1 // SPDX-License-Identifier: GPL-2.0-only
5 #include <linux/exportfs.h>
17 #define FAT_FID_SIZE_WITHOUT_PARENT 3
18 #define FAT_FID_SIZE_WITH_PARENT (sizeof(struct fat_fid)/sizeof(u32))
21 * Look up a directory inode given its starting cluster.
23 static struct inode
*fat_dget(struct super_block
*sb
, int i_logstart
)
25 struct msdos_sb_info
*sbi
= MSDOS_SB(sb
);
26 struct hlist_head
*head
;
27 struct msdos_inode_info
*i
;
28 struct inode
*inode
= NULL
;
30 head
= sbi
->dir_hashtable
+ fat_dir_hash(i_logstart
);
31 spin_lock(&sbi
->dir_hash_lock
);
32 hlist_for_each_entry(i
, head
, i_dir_hash
) {
33 BUG_ON(i
->vfs_inode
.i_sb
!= sb
);
34 if (i
->i_logstart
!= i_logstart
)
36 inode
= igrab(&i
->vfs_inode
);
40 spin_unlock(&sbi
->dir_hash_lock
);
44 static struct inode
*fat_ilookup(struct super_block
*sb
, u64 ino
, loff_t i_pos
)
46 if (MSDOS_SB(sb
)->options
.nfs
== FAT_NFS_NOSTALE_RO
)
47 return fat_iget(sb
, i_pos
);
50 if ((ino
< MSDOS_ROOT_INO
) || (ino
== MSDOS_FSINFO_INO
))
52 return ilookup(sb
, ino
);
56 static struct inode
*__fat_nfs_get_inode(struct super_block
*sb
,
57 u64 ino
, u32 generation
, loff_t i_pos
)
59 struct inode
*inode
= fat_ilookup(sb
, ino
, i_pos
);
61 if (inode
&& generation
&& (inode
->i_generation
!= generation
)) {
65 if (inode
== NULL
&& MSDOS_SB(sb
)->options
.nfs
== FAT_NFS_NOSTALE_RO
) {
66 struct buffer_head
*bh
= NULL
;
67 struct msdos_dir_entry
*de
;
70 fat_get_blknr_offset(MSDOS_SB(sb
), i_pos
, &blocknr
, &offset
);
71 bh
= sb_bread(sb
, blocknr
);
74 "unable to read block(%llu) for building NFS inode",
78 de
= (struct msdos_dir_entry
*)bh
->b_data
;
79 /* If a file is deleted on server and client is not updated
80 * yet, we must not build the inode upon a lookup call.
82 if (IS_FREE(de
[offset
].name
))
85 inode
= fat_build_inode(sb
, &de
[offset
], i_pos
);
92 static struct inode
*fat_nfs_get_inode(struct super_block
*sb
,
93 u64 ino
, u32 generation
)
96 return __fat_nfs_get_inode(sb
, ino
, generation
, 0);
100 fat_encode_fh_nostale(struct inode
*inode
, __u32
*fh
, int *lenp
,
101 struct inode
*parent
)
104 struct msdos_sb_info
*sbi
= MSDOS_SB(inode
->i_sb
);
105 struct fat_fid
*fid
= (struct fat_fid
*) fh
;
107 int type
= FILEID_FAT_WITHOUT_PARENT
;
110 if (len
< FAT_FID_SIZE_WITH_PARENT
) {
111 *lenp
= FAT_FID_SIZE_WITH_PARENT
;
112 return FILEID_INVALID
;
115 if (len
< FAT_FID_SIZE_WITHOUT_PARENT
) {
116 *lenp
= FAT_FID_SIZE_WITHOUT_PARENT
;
117 return FILEID_INVALID
;
121 i_pos
= fat_i_pos_read(sbi
, inode
);
122 *lenp
= FAT_FID_SIZE_WITHOUT_PARENT
;
123 fid
->i_gen
= inode
->i_generation
;
124 fid
->i_pos_low
= i_pos
& 0xFFFFFFFF;
125 fid
->i_pos_hi
= (i_pos
>> 32) & 0xFFFF;
127 i_pos
= fat_i_pos_read(sbi
, parent
);
128 fid
->parent_i_pos_hi
= (i_pos
>> 32) & 0xFFFF;
129 fid
->parent_i_pos_low
= i_pos
& 0xFFFFFFFF;
130 fid
->parent_i_gen
= parent
->i_generation
;
131 type
= FILEID_FAT_WITH_PARENT
;
132 *lenp
= FAT_FID_SIZE_WITH_PARENT
;
135 * We need to initialize this field because the fh is actually
138 fid
->parent_i_pos_hi
= 0;
145 * Map a NFS file handle to a corresponding dentry.
146 * The dentry may or may not be connected to the filesystem root.
148 static struct dentry
*fat_fh_to_dentry(struct super_block
*sb
, struct fid
*fid
,
149 int fh_len
, int fh_type
)
151 return generic_fh_to_dentry(sb
, fid
, fh_len
, fh_type
,
155 static struct dentry
*fat_fh_to_dentry_nostale(struct super_block
*sb
,
156 struct fid
*fh
, int fh_len
,
159 struct inode
*inode
= NULL
;
160 struct fat_fid
*fid
= (struct fat_fid
*)fh
;
164 case FILEID_FAT_WITHOUT_PARENT
:
165 if (fh_len
< FAT_FID_SIZE_WITHOUT_PARENT
)
168 case FILEID_FAT_WITH_PARENT
:
169 if (fh_len
< FAT_FID_SIZE_WITH_PARENT
)
175 i_pos
= fid
->i_pos_hi
;
176 i_pos
= (i_pos
<< 32) | (fid
->i_pos_low
);
177 inode
= __fat_nfs_get_inode(sb
, 0, fid
->i_gen
, i_pos
);
179 return d_obtain_alias(inode
);
183 * Find the parent for a file specified by NFS handle.
184 * This requires that the handle contain the i_ino of the parent.
186 static struct dentry
*fat_fh_to_parent(struct super_block
*sb
, struct fid
*fid
,
187 int fh_len
, int fh_type
)
189 return generic_fh_to_parent(sb
, fid
, fh_len
, fh_type
,
193 static struct dentry
*fat_fh_to_parent_nostale(struct super_block
*sb
,
194 struct fid
*fh
, int fh_len
,
197 struct inode
*inode
= NULL
;
198 struct fat_fid
*fid
= (struct fat_fid
*)fh
;
201 if (fh_len
< FAT_FID_SIZE_WITH_PARENT
)
205 case FILEID_FAT_WITH_PARENT
:
206 i_pos
= fid
->parent_i_pos_hi
;
207 i_pos
= (i_pos
<< 32) | (fid
->parent_i_pos_low
);
208 inode
= __fat_nfs_get_inode(sb
, 0, fid
->parent_i_gen
, i_pos
);
212 return d_obtain_alias(inode
);
216 * Rebuild the parent for a directory that is not connected
217 * to the filesystem root
220 struct inode
*fat_rebuild_parent(struct super_block
*sb
, int parent_logstart
)
222 int search_clus
, clus_to_match
;
223 struct msdos_dir_entry
*de
;
224 struct inode
*parent
= NULL
;
225 struct inode
*dummy_grand_parent
= NULL
;
226 struct fat_slot_info sinfo
;
227 struct msdos_sb_info
*sbi
= MSDOS_SB(sb
);
228 sector_t blknr
= fat_clus_to_blknr(sbi
, parent_logstart
);
229 struct buffer_head
*parent_bh
= sb_bread(sb
, blknr
);
231 fat_msg(sb
, KERN_ERR
,
232 "unable to read cluster of parent directory");
236 de
= (struct msdos_dir_entry
*) parent_bh
->b_data
;
237 clus_to_match
= fat_get_start(sbi
, &de
[0]);
238 search_clus
= fat_get_start(sbi
, &de
[1]);
240 dummy_grand_parent
= fat_dget(sb
, search_clus
);
241 if (!dummy_grand_parent
) {
242 dummy_grand_parent
= new_inode(sb
);
243 if (!dummy_grand_parent
) {
248 dummy_grand_parent
->i_ino
= iunique(sb
, MSDOS_ROOT_INO
);
249 fat_fill_inode(dummy_grand_parent
, &de
[1]);
250 MSDOS_I(dummy_grand_parent
)->i_pos
= -1;
253 if (!fat_scan_logstart(dummy_grand_parent
, clus_to_match
, &sinfo
))
254 parent
= fat_build_inode(sb
, sinfo
.de
, sinfo
.i_pos
);
257 iput(dummy_grand_parent
);
263 * Find the parent for a directory that is not currently connected to
264 * the filesystem root.
266 * On entry, the caller holds d_inode(child_dir)->i_mutex.
268 static struct dentry
*fat_get_parent(struct dentry
*child_dir
)
270 struct super_block
*sb
= child_dir
->d_sb
;
271 struct buffer_head
*bh
= NULL
;
272 struct msdos_dir_entry
*de
;
273 struct inode
*parent_inode
= NULL
;
274 struct msdos_sb_info
*sbi
= MSDOS_SB(sb
);
276 if (!fat_get_dotdot_entry(d_inode(child_dir
), &bh
, &de
)) {
277 int parent_logstart
= fat_get_start(sbi
, de
);
278 parent_inode
= fat_dget(sb
, parent_logstart
);
279 if (!parent_inode
&& sbi
->options
.nfs
== FAT_NFS_NOSTALE_RO
)
280 parent_inode
= fat_rebuild_parent(sb
, parent_logstart
);
284 return d_obtain_alias(parent_inode
);
287 const struct export_operations fat_export_ops
= {
288 .encode_fh
= generic_encode_ino32_fh
,
289 .fh_to_dentry
= fat_fh_to_dentry
,
290 .fh_to_parent
= fat_fh_to_parent
,
291 .get_parent
= fat_get_parent
,
294 const struct export_operations fat_export_ops_nostale
= {
295 .encode_fh
= fat_encode_fh_nostale
,
296 .fh_to_dentry
= fat_fh_to_dentry_nostale
,
297 .fh_to_parent
= fat_fh_to_parent_nostale
,
298 .get_parent
= fat_get_parent
,