1 /* fs/fat/nfs.c 2 * 3 * This software is licensed under the terms of the GNU General Public 4 * License version 2, as published by the Free Software Foundation, and 5 * may be copied, distributed, and modified under those terms. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 */ 13 14 #include <linux/exportfs.h> 15 #include "fat.h" 16 17 /** 18 * Look up a directory inode given its starting cluster. 19 */ 20 static struct inode *fat_dget(struct super_block *sb, int i_logstart) 21 { 22 struct msdos_sb_info *sbi = MSDOS_SB(sb); 23 struct hlist_head *head; 24 struct hlist_node *_p; 25 struct msdos_inode_info *i; 26 struct inode *inode = NULL; 27 28 head = sbi->dir_hashtable + fat_dir_hash(i_logstart); 29 spin_lock(&sbi->dir_hash_lock); 30 hlist_for_each_entry(i, _p, head, i_dir_hash) { 31 BUG_ON(i->vfs_inode.i_sb != sb); 32 if (i->i_logstart != i_logstart) 33 continue; 34 inode = igrab(&i->vfs_inode); 35 if (inode) 36 break; 37 } 38 spin_unlock(&sbi->dir_hash_lock); 39 return inode; 40 } 41 42 static struct inode *fat_nfs_get_inode(struct super_block *sb, 43 u64 ino, u32 generation) 44 { 45 struct inode *inode; 46 47 if ((ino < MSDOS_ROOT_INO) || (ino == MSDOS_FSINFO_INO)) 48 return NULL; 49 50 inode = ilookup(sb, ino); 51 if (inode && generation && (inode->i_generation != generation)) { 52 iput(inode); 53 inode = NULL; 54 } 55 56 return inode; 57 } 58 59 /** 60 * Map a NFS file handle to a corresponding dentry. 61 * The dentry may or may not be connected to the filesystem root. 62 */ 63 struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, 64 int fh_len, int fh_type) 65 { 66 return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 67 fat_nfs_get_inode); 68 } 69 70 /* 71 * Find the parent for a file specified by NFS handle. 72 * This requires that the handle contain the i_ino of the parent. 73 */ 74 struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid, 75 int fh_len, int fh_type) 76 { 77 return generic_fh_to_parent(sb, fid, fh_len, fh_type, 78 fat_nfs_get_inode); 79 } 80 81 /* 82 * Find the parent for a directory that is not currently connected to 83 * the filesystem root. 84 * 85 * On entry, the caller holds child_dir->d_inode->i_mutex. 86 */ 87 struct dentry *fat_get_parent(struct dentry *child_dir) 88 { 89 struct super_block *sb = child_dir->d_sb; 90 struct buffer_head *bh = NULL; 91 struct msdos_dir_entry *de; 92 struct inode *parent_inode = NULL; 93 94 if (!fat_get_dotdot_entry(child_dir->d_inode, &bh, &de)) { 95 int parent_logstart = fat_get_start(MSDOS_SB(sb), de); 96 parent_inode = fat_dget(sb, parent_logstart); 97 } 98 brelse(bh); 99 100 return d_obtain_alias(parent_inode); 101 } 102