Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * fs/isofs/export.c
0004  *
0005  *  (C) 2004  Paul Serice - The new inode scheme requires switching
0006  *                          from iget() to iget5_locked() which means
0007  *                          the NFS export operations have to be hand
0008  *                          coded because the default routines rely on
0009  *                          iget().
0010  *
0011  * The following files are helpful:
0012  *
0013  *     Documentation/filesystems/nfs/exporting.rst
0014  *     fs/exportfs/expfs.c.
0015  */
0016 
0017 #include "isofs.h"
0018 
0019 static struct dentry *
0020 isofs_export_iget(struct super_block *sb,
0021           unsigned long block,
0022           unsigned long offset,
0023           __u32 generation)
0024 {
0025     struct inode *inode;
0026 
0027     if (block == 0)
0028         return ERR_PTR(-ESTALE);
0029     inode = isofs_iget(sb, block, offset);
0030     if (IS_ERR(inode))
0031         return ERR_CAST(inode);
0032     if (generation && inode->i_generation != generation) {
0033         iput(inode);
0034         return ERR_PTR(-ESTALE);
0035     }
0036     return d_obtain_alias(inode);
0037 }
0038 
0039 /* This function is surprisingly simple.  The trick is understanding
0040  * that "child" is always a directory. So, to find its parent, you
0041  * simply need to find its ".." entry, normalize its block and offset,
0042  * and return the underlying inode.  See the comments for
0043  * isofs_normalize_block_and_offset(). */
0044 static struct dentry *isofs_export_get_parent(struct dentry *child)
0045 {
0046     unsigned long parent_block = 0;
0047     unsigned long parent_offset = 0;
0048     struct inode *child_inode = d_inode(child);
0049     struct iso_inode_info *e_child_inode = ISOFS_I(child_inode);
0050     struct iso_directory_record *de = NULL;
0051     struct buffer_head * bh = NULL;
0052     struct dentry *rv = NULL;
0053 
0054     /* "child" must always be a directory. */
0055     if (!S_ISDIR(child_inode->i_mode)) {
0056         printk(KERN_ERR "isofs: isofs_export_get_parent(): "
0057                "child is not a directory!\n");
0058         rv = ERR_PTR(-EACCES);
0059         goto out;
0060     }
0061 
0062     /* It is an invariant that the directory offset is zero.  If
0063      * it is not zero, it means the directory failed to be
0064      * normalized for some reason. */
0065     if (e_child_inode->i_iget5_offset != 0) {
0066         printk(KERN_ERR "isofs: isofs_export_get_parent(): "
0067                "child directory not normalized!\n");
0068         rv = ERR_PTR(-EACCES);
0069         goto out;
0070     }
0071 
0072     /* The child inode has been normalized such that its
0073      * i_iget5_block value points to the "." entry.  Fortunately,
0074      * the ".." entry is located in the same block. */
0075     parent_block = e_child_inode->i_iget5_block;
0076 
0077     /* Get the block in question. */
0078     bh = sb_bread(child_inode->i_sb, parent_block);
0079     if (bh == NULL) {
0080         rv = ERR_PTR(-EACCES);
0081         goto out;
0082     }
0083 
0084     /* This is the "." entry. */
0085     de = (struct iso_directory_record*)bh->b_data;
0086 
0087     /* The ".." entry is always the second entry. */
0088     parent_offset = (unsigned long)isonum_711(de->length);
0089     de = (struct iso_directory_record*)(bh->b_data + parent_offset);
0090 
0091     /* Verify it is in fact the ".." entry. */
0092     if ((isonum_711(de->name_len) != 1) || (de->name[0] != 1)) {
0093         printk(KERN_ERR "isofs: Unable to find the \"..\" "
0094                "directory for NFS.\n");
0095         rv = ERR_PTR(-EACCES);
0096         goto out;
0097     }
0098 
0099     /* Normalize */
0100     isofs_normalize_block_and_offset(de, &parent_block, &parent_offset);
0101 
0102     rv = d_obtain_alias(isofs_iget(child_inode->i_sb, parent_block,
0103                      parent_offset));
0104  out:
0105     if (bh)
0106         brelse(bh);
0107     return rv;
0108 }
0109 
0110 static int
0111 isofs_export_encode_fh(struct inode *inode,
0112                __u32 *fh32,
0113                int *max_len,
0114                struct inode *parent)
0115 {
0116     struct iso_inode_info * ei = ISOFS_I(inode);
0117     int len = *max_len;
0118     int type = 1;
0119     __u16 *fh16 = (__u16*)fh32;
0120 
0121     /*
0122      * WARNING: max_len is 5 for NFSv2.  Because of this
0123      * limitation, we use the lower 16 bits of fh32[1] to hold the
0124      * offset of the inode and the upper 16 bits of fh32[1] to
0125      * hold the offset of the parent.
0126      */
0127     if (parent && (len < 5)) {
0128         *max_len = 5;
0129         return FILEID_INVALID;
0130     } else if (len < 3) {
0131         *max_len = 3;
0132         return FILEID_INVALID;
0133     }
0134 
0135     len = 3;
0136     fh32[0] = ei->i_iget5_block;
0137     fh16[2] = (__u16)ei->i_iget5_offset;  /* fh16 [sic] */
0138     fh16[3] = 0;  /* avoid leaking uninitialized data */
0139     fh32[2] = inode->i_generation;
0140     if (parent) {
0141         struct iso_inode_info *eparent;
0142         eparent = ISOFS_I(parent);
0143         fh32[3] = eparent->i_iget5_block;
0144         fh16[3] = (__u16)eparent->i_iget5_offset;  /* fh16 [sic] */
0145         fh32[4] = parent->i_generation;
0146         len = 5;
0147         type = 2;
0148     }
0149     *max_len = len;
0150     return type;
0151 }
0152 
0153 struct isofs_fid {
0154     u32 block;
0155     u16 offset;
0156     u16 parent_offset;
0157     u32 generation;
0158     u32 parent_block;
0159     u32 parent_generation;
0160 };
0161 
0162 static struct dentry *isofs_fh_to_dentry(struct super_block *sb,
0163     struct fid *fid, int fh_len, int fh_type)
0164 {
0165     struct isofs_fid *ifid = (struct isofs_fid *)fid;
0166 
0167     if (fh_len < 3 || fh_type > 2)
0168         return NULL;
0169 
0170     return isofs_export_iget(sb, ifid->block, ifid->offset,
0171             ifid->generation);
0172 }
0173 
0174 static struct dentry *isofs_fh_to_parent(struct super_block *sb,
0175         struct fid *fid, int fh_len, int fh_type)
0176 {
0177     struct isofs_fid *ifid = (struct isofs_fid *)fid;
0178 
0179     if (fh_len < 2 || fh_type != 2)
0180         return NULL;
0181 
0182     return isofs_export_iget(sb,
0183             fh_len > 2 ? ifid->parent_block : 0,
0184             ifid->parent_offset,
0185             fh_len > 4 ? ifid->parent_generation : 0);
0186 }
0187 
0188 const struct export_operations isofs_export_ops = {
0189     .encode_fh  = isofs_export_encode_fh,
0190     .fh_to_dentry   = isofs_fh_to_dentry,
0191     .fh_to_parent   = isofs_fh_to_parent,
0192     .get_parent     = isofs_export_get_parent,
0193 };