root/fs/isofs/export.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. isofs_export_iget
  2. isofs_export_get_parent
  3. isofs_export_encode_fh
  4. isofs_fh_to_dentry
  5. isofs_fh_to_parent

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * fs/isofs/export.c
   4  *
   5  *  (C) 2004  Paul Serice - The new inode scheme requires switching
   6  *                          from iget() to iget5_locked() which means
   7  *                          the NFS export operations have to be hand
   8  *                          coded because the default routines rely on
   9  *                          iget().
  10  *
  11  * The following files are helpful:
  12  *
  13  *     Documentation/filesystems/nfs/exporting.rst
  14  *     fs/exportfs/expfs.c.
  15  */
  16 
  17 #include "isofs.h"
  18 
  19 static struct dentry *
  20 isofs_export_iget(struct super_block *sb,
  21                   unsigned long block,
  22                   unsigned long offset,
  23                   __u32 generation)
  24 {
  25         struct inode *inode;
  26 
  27         if (block == 0)
  28                 return ERR_PTR(-ESTALE);
  29         inode = isofs_iget(sb, block, offset);
  30         if (IS_ERR(inode))
  31                 return ERR_CAST(inode);
  32         if (generation && inode->i_generation != generation) {
  33                 iput(inode);
  34                 return ERR_PTR(-ESTALE);
  35         }
  36         return d_obtain_alias(inode);
  37 }
  38 
  39 /* This function is surprisingly simple.  The trick is understanding
  40  * that "child" is always a directory. So, to find its parent, you
  41  * simply need to find its ".." entry, normalize its block and offset,
  42  * and return the underlying inode.  See the comments for
  43  * isofs_normalize_block_and_offset(). */
  44 static struct dentry *isofs_export_get_parent(struct dentry *child)
  45 {
  46         unsigned long parent_block = 0;
  47         unsigned long parent_offset = 0;
  48         struct inode *child_inode = d_inode(child);
  49         struct iso_inode_info *e_child_inode = ISOFS_I(child_inode);
  50         struct iso_directory_record *de = NULL;
  51         struct buffer_head * bh = NULL;
  52         struct dentry *rv = NULL;
  53 
  54         /* "child" must always be a directory. */
  55         if (!S_ISDIR(child_inode->i_mode)) {
  56                 printk(KERN_ERR "isofs: isofs_export_get_parent(): "
  57                        "child is not a directory!\n");
  58                 rv = ERR_PTR(-EACCES);
  59                 goto out;
  60         }
  61 
  62         /* It is an invariant that the directory offset is zero.  If
  63          * it is not zero, it means the directory failed to be
  64          * normalized for some reason. */
  65         if (e_child_inode->i_iget5_offset != 0) {
  66                 printk(KERN_ERR "isofs: isofs_export_get_parent(): "
  67                        "child directory not normalized!\n");
  68                 rv = ERR_PTR(-EACCES);
  69                 goto out;
  70         }
  71 
  72         /* The child inode has been normalized such that its
  73          * i_iget5_block value points to the "." entry.  Fortunately,
  74          * the ".." entry is located in the same block. */
  75         parent_block = e_child_inode->i_iget5_block;
  76 
  77         /* Get the block in question. */
  78         bh = sb_bread(child_inode->i_sb, parent_block);
  79         if (bh == NULL) {
  80                 rv = ERR_PTR(-EACCES);
  81                 goto out;
  82         }
  83 
  84         /* This is the "." entry. */
  85         de = (struct iso_directory_record*)bh->b_data;
  86 
  87         /* The ".." entry is always the second entry. */
  88         parent_offset = (unsigned long)isonum_711(de->length);
  89         de = (struct iso_directory_record*)(bh->b_data + parent_offset);
  90 
  91         /* Verify it is in fact the ".." entry. */
  92         if ((isonum_711(de->name_len) != 1) || (de->name[0] != 1)) {
  93                 printk(KERN_ERR "isofs: Unable to find the \"..\" "
  94                        "directory for NFS.\n");
  95                 rv = ERR_PTR(-EACCES);
  96                 goto out;
  97         }
  98 
  99         /* Normalize */
 100         isofs_normalize_block_and_offset(de, &parent_block, &parent_offset);
 101 
 102         rv = d_obtain_alias(isofs_iget(child_inode->i_sb, parent_block,
 103                                      parent_offset));
 104  out:
 105         if (bh)
 106                 brelse(bh);
 107         return rv;
 108 }
 109 
 110 static int
 111 isofs_export_encode_fh(struct inode *inode,
 112                        __u32 *fh32,
 113                        int *max_len,
 114                        struct inode *parent)
 115 {
 116         struct iso_inode_info * ei = ISOFS_I(inode);
 117         int len = *max_len;
 118         int type = 1;
 119         __u16 *fh16 = (__u16*)fh32;
 120 
 121         /*
 122          * WARNING: max_len is 5 for NFSv2.  Because of this
 123          * limitation, we use the lower 16 bits of fh32[1] to hold the
 124          * offset of the inode and the upper 16 bits of fh32[1] to
 125          * hold the offset of the parent.
 126          */
 127         if (parent && (len < 5)) {
 128                 *max_len = 5;
 129                 return FILEID_INVALID;
 130         } else if (len < 3) {
 131                 *max_len = 3;
 132                 return FILEID_INVALID;
 133         }
 134 
 135         len = 3;
 136         fh32[0] = ei->i_iget5_block;
 137         fh16[2] = (__u16)ei->i_iget5_offset;  /* fh16 [sic] */
 138         fh16[3] = 0;  /* avoid leaking uninitialized data */
 139         fh32[2] = inode->i_generation;
 140         if (parent) {
 141                 struct iso_inode_info *eparent;
 142                 eparent = ISOFS_I(parent);
 143                 fh32[3] = eparent->i_iget5_block;
 144                 fh16[3] = (__u16)eparent->i_iget5_offset;  /* fh16 [sic] */
 145                 fh32[4] = parent->i_generation;
 146                 len = 5;
 147                 type = 2;
 148         }
 149         *max_len = len;
 150         return type;
 151 }
 152 
 153 struct isofs_fid {
 154         u32 block;
 155         u16 offset;
 156         u16 parent_offset;
 157         u32 generation;
 158         u32 parent_block;
 159         u32 parent_generation;
 160 };
 161 
 162 static struct dentry *isofs_fh_to_dentry(struct super_block *sb,
 163         struct fid *fid, int fh_len, int fh_type)
 164 {
 165         struct isofs_fid *ifid = (struct isofs_fid *)fid;
 166 
 167         if (fh_len < 3 || fh_type > 2)
 168                 return NULL;
 169 
 170         return isofs_export_iget(sb, ifid->block, ifid->offset,
 171                         ifid->generation);
 172 }
 173 
 174 static struct dentry *isofs_fh_to_parent(struct super_block *sb,
 175                 struct fid *fid, int fh_len, int fh_type)
 176 {
 177         struct isofs_fid *ifid = (struct isofs_fid *)fid;
 178 
 179         if (fh_len < 2 || fh_type != 2)
 180                 return NULL;
 181 
 182         return isofs_export_iget(sb,
 183                         fh_len > 2 ? ifid->parent_block : 0,
 184                         ifid->parent_offset,
 185                         fh_len > 4 ? ifid->parent_generation : 0);
 186 }
 187 
 188 const struct export_operations isofs_export_ops = {
 189         .encode_fh      = isofs_export_encode_fh,
 190         .fh_to_dentry   = isofs_fh_to_dentry,
 191         .fh_to_parent   = isofs_fh_to_parent,
 192         .get_parent     = isofs_export_get_parent,
 193 };

/* [<][>][^][v][top][bottom][index][help] */