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.
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.
14 #include <linux/exportfs.h>
26 #define FAT_FID_SIZE_WITHOUT_PARENT 3
27 #define FAT_FID_SIZE_WITH_PARENT (sizeof(struct fat_fid)/sizeof(u32))
30 * Look up a directory inode given its starting cluster.
32 static struct inode
*fat_dget(struct super_block
*sb
, int i_logstart
)
34 struct msdos_sb_info
*sbi
= MSDOS_SB(sb
);
35 struct hlist_head
*head
;
36 struct msdos_inode_info
*i
;
37 struct inode
*inode
= NULL
;
39 head
= sbi
->dir_hashtable
+ fat_dir_hash(i_logstart
);
40 spin_lock(&sbi
->dir_hash_lock
);
41 hlist_for_each_entry(i
, head
, i_dir_hash
) {
42 BUG_ON(i
->vfs_inode
.i_sb
!= sb
);
43 if (i
->i_logstart
!= i_logstart
)
45 inode
= igrab(&i
->vfs_inode
);
49 spin_unlock(&sbi
->dir_hash_lock
);
53 static struct inode
*fat_ilookup(struct super_block
*sb
, u64 ino
, loff_t i_pos
)
55 if (MSDOS_SB(sb
)->options
.nfs
== FAT_NFS_NOSTALE_RO
)
56 return fat_iget(sb
, i_pos
);
59 if ((ino
< MSDOS_ROOT_INO
) || (ino
== MSDOS_FSINFO_INO
))
61 return ilookup(sb
, ino
);
65 static struct inode
*__fat_nfs_get_inode(struct super_block
*sb
,
66 u64 ino
, u32 generation
, loff_t i_pos
)
68 struct inode
*inode
= fat_ilookup(sb
, ino
, i_pos
);
70 if (inode
&& generation
&& (inode
->i_generation
!= generation
)) {
74 if (inode
== NULL
&& MSDOS_SB(sb
)->options
.nfs
== FAT_NFS_NOSTALE_RO
) {
75 struct buffer_head
*bh
= NULL
;
76 struct msdos_dir_entry
*de
;
79 fat_get_blknr_offset(MSDOS_SB(sb
), i_pos
, &blocknr
, &offset
);
80 bh
= sb_bread(sb
, blocknr
);
83 "unable to read block(%llu) for building NFS inode",
87 de
= (struct msdos_dir_entry
*)bh
->b_data
;
88 /* If a file is deleted on server and client is not updated
89 * yet, we must not build the inode upon a lookup call.
91 if (IS_FREE(de
[offset
].name
))
94 inode
= fat_build_inode(sb
, &de
[offset
], i_pos
);
101 static struct inode
*fat_nfs_get_inode(struct super_block
*sb
,
102 u64 ino
, u32 generation
)
105 return __fat_nfs_get_inode(sb
, ino
, generation
, 0);
109 fat_encode_fh_nostale(struct inode
*inode
, __u32
*fh
, int *lenp
,
110 struct inode
*parent
)
113 struct msdos_sb_info
*sbi
= MSDOS_SB(inode
->i_sb
);
114 struct fat_fid
*fid
= (struct fat_fid
*) fh
;
116 int type
= FILEID_FAT_WITHOUT_PARENT
;
119 if (len
< FAT_FID_SIZE_WITH_PARENT
) {
120 *lenp
= FAT_FID_SIZE_WITH_PARENT
;
121 return FILEID_INVALID
;
124 if (len
< FAT_FID_SIZE_WITHOUT_PARENT
) {
125 *lenp
= FAT_FID_SIZE_WITHOUT_PARENT
;
126 return FILEID_INVALID
;
130 i_pos
= fat_i_pos_read(sbi
, inode
);
131 *lenp
= FAT_FID_SIZE_WITHOUT_PARENT
;
132 fid
->i_gen
= inode
->i_generation
;
133 fid
->i_pos_low
= i_pos
& 0xFFFFFFFF;
134 fid
->i_pos_hi
= (i_pos
>> 32) & 0xFFFF;
136 i_pos
= fat_i_pos_read(sbi
, parent
);
137 fid
->parent_i_pos_hi
= (i_pos
>> 32) & 0xFFFF;
138 fid
->parent_i_pos_low
= i_pos
& 0xFFFFFFFF;
139 fid
->parent_i_gen
= parent
->i_generation
;
140 type
= FILEID_FAT_WITH_PARENT
;
141 *lenp
= FAT_FID_SIZE_WITH_PARENT
;
148 * Map a NFS file handle to a corresponding dentry.
149 * The dentry may or may not be connected to the filesystem root.
151 static struct dentry
*fat_fh_to_dentry(struct super_block
*sb
, struct fid
*fid
,
152 int fh_len
, int fh_type
)
154 return generic_fh_to_dentry(sb
, fid
, fh_len
, fh_type
,
158 static struct dentry
*fat_fh_to_dentry_nostale(struct super_block
*sb
,
159 struct fid
*fh
, int fh_len
,
162 struct inode
*inode
= NULL
;
163 struct fat_fid
*fid
= (struct fat_fid
*)fh
;
167 case FILEID_FAT_WITHOUT_PARENT
:
168 if (fh_len
< FAT_FID_SIZE_WITHOUT_PARENT
)
171 case FILEID_FAT_WITH_PARENT
:
172 if (fh_len
< FAT_FID_SIZE_WITH_PARENT
)
178 i_pos
= fid
->i_pos_hi
;
179 i_pos
= (i_pos
<< 32) | (fid
->i_pos_low
);
180 inode
= __fat_nfs_get_inode(sb
, 0, fid
->i_gen
, i_pos
);
182 return d_obtain_alias(inode
);
186 * Find the parent for a file specified by NFS handle.
187 * This requires that the handle contain the i_ino of the parent.
189 static struct dentry
*fat_fh_to_parent(struct super_block
*sb
, struct fid
*fid
,
190 int fh_len
, int fh_type
)
192 return generic_fh_to_parent(sb
, fid
, fh_len
, fh_type
,
196 static struct dentry
*fat_fh_to_parent_nostale(struct super_block
*sb
,
197 struct fid
*fh
, int fh_len
,
200 struct inode
*inode
= NULL
;
201 struct fat_fid
*fid
= (struct fat_fid
*)fh
;
204 if (fh_len
< FAT_FID_SIZE_WITH_PARENT
)
208 case FILEID_FAT_WITH_PARENT
:
209 i_pos
= fid
->parent_i_pos_hi
;
210 i_pos
= (i_pos
<< 32) | (fid
->parent_i_pos_low
);
211 inode
= __fat_nfs_get_inode(sb
, 0, fid
->parent_i_gen
, i_pos
);
215 return d_obtain_alias(inode
);
219 * Rebuild the parent for a directory that is not connected
220 * to the filesystem root
223 struct inode
*fat_rebuild_parent(struct super_block
*sb
, int parent_logstart
)
225 int search_clus
, clus_to_match
;
226 struct msdos_dir_entry
*de
;
227 struct inode
*parent
= NULL
;
228 struct inode
*dummy_grand_parent
= NULL
;
229 struct fat_slot_info sinfo
;
230 struct msdos_sb_info
*sbi
= MSDOS_SB(sb
);
231 sector_t blknr
= fat_clus_to_blknr(sbi
, parent_logstart
);
232 struct buffer_head
*parent_bh
= sb_bread(sb
, blknr
);
234 fat_msg(sb
, KERN_ERR
,
235 "unable to read cluster of parent directory");
239 de
= (struct msdos_dir_entry
*) parent_bh
->b_data
;
240 clus_to_match
= fat_get_start(sbi
, &de
[0]);
241 search_clus
= fat_get_start(sbi
, &de
[1]);
243 dummy_grand_parent
= fat_dget(sb
, search_clus
);
244 if (!dummy_grand_parent
) {
245 dummy_grand_parent
= new_inode(sb
);
246 if (!dummy_grand_parent
) {
251 dummy_grand_parent
->i_ino
= iunique(sb
, MSDOS_ROOT_INO
);
252 fat_fill_inode(dummy_grand_parent
, &de
[1]);
253 MSDOS_I(dummy_grand_parent
)->i_pos
= -1;
256 if (!fat_scan_logstart(dummy_grand_parent
, clus_to_match
, &sinfo
))
257 parent
= fat_build_inode(sb
, sinfo
.de
, sinfo
.i_pos
);
260 iput(dummy_grand_parent
);
266 * Find the parent for a directory that is not currently connected to
267 * the filesystem root.
269 * On entry, the caller holds d_inode(child_dir)->i_mutex.
271 static struct dentry
*fat_get_parent(struct dentry
*child_dir
)
273 struct super_block
*sb
= child_dir
->d_sb
;
274 struct buffer_head
*bh
= NULL
;
275 struct msdos_dir_entry
*de
;
276 struct inode
*parent_inode
= NULL
;
277 struct msdos_sb_info
*sbi
= MSDOS_SB(sb
);
279 if (!fat_get_dotdot_entry(d_inode(child_dir
), &bh
, &de
)) {
280 int parent_logstart
= fat_get_start(sbi
, de
);
281 parent_inode
= fat_dget(sb
, parent_logstart
);
282 if (!parent_inode
&& sbi
->options
.nfs
== FAT_NFS_NOSTALE_RO
)
283 parent_inode
= fat_rebuild_parent(sb
, parent_logstart
);
287 return d_obtain_alias(parent_inode
);
290 const struct export_operations fat_export_ops
= {
291 .fh_to_dentry
= fat_fh_to_dentry
,
292 .fh_to_parent
= fat_fh_to_parent
,
293 .get_parent
= fat_get_parent
,
296 const struct export_operations fat_export_ops_nostale
= {
297 .encode_fh
= fat_encode_fh_nostale
,
298 .fh_to_dentry
= fat_fh_to_dentry_nostale
,
299 .fh_to_parent
= fat_fh_to_parent_nostale
,
300 .get_parent
= fat_get_parent
,