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
;
139 * Map a NFS file handle to a corresponding dentry.
140 * The dentry may or may not be connected to the filesystem root.
142 static struct dentry
*fat_fh_to_dentry(struct super_block
*sb
, struct fid
*fid
,
143 int fh_len
, int fh_type
)
145 return generic_fh_to_dentry(sb
, fid
, fh_len
, fh_type
,
149 static struct dentry
*fat_fh_to_dentry_nostale(struct super_block
*sb
,
150 struct fid
*fh
, int fh_len
,
153 struct inode
*inode
= NULL
;
154 struct fat_fid
*fid
= (struct fat_fid
*)fh
;
158 case FILEID_FAT_WITHOUT_PARENT
:
159 if (fh_len
< FAT_FID_SIZE_WITHOUT_PARENT
)
162 case FILEID_FAT_WITH_PARENT
:
163 if (fh_len
< FAT_FID_SIZE_WITH_PARENT
)
169 i_pos
= fid
->i_pos_hi
;
170 i_pos
= (i_pos
<< 32) | (fid
->i_pos_low
);
171 inode
= __fat_nfs_get_inode(sb
, 0, fid
->i_gen
, i_pos
);
173 return d_obtain_alias(inode
);
177 * Find the parent for a file specified by NFS handle.
178 * This requires that the handle contain the i_ino of the parent.
180 static struct dentry
*fat_fh_to_parent(struct super_block
*sb
, struct fid
*fid
,
181 int fh_len
, int fh_type
)
183 return generic_fh_to_parent(sb
, fid
, fh_len
, fh_type
,
187 static struct dentry
*fat_fh_to_parent_nostale(struct super_block
*sb
,
188 struct fid
*fh
, int fh_len
,
191 struct inode
*inode
= NULL
;
192 struct fat_fid
*fid
= (struct fat_fid
*)fh
;
195 if (fh_len
< FAT_FID_SIZE_WITH_PARENT
)
199 case FILEID_FAT_WITH_PARENT
:
200 i_pos
= fid
->parent_i_pos_hi
;
201 i_pos
= (i_pos
<< 32) | (fid
->parent_i_pos_low
);
202 inode
= __fat_nfs_get_inode(sb
, 0, fid
->parent_i_gen
, i_pos
);
206 return d_obtain_alias(inode
);
210 * Rebuild the parent for a directory that is not connected
211 * to the filesystem root
214 struct inode
*fat_rebuild_parent(struct super_block
*sb
, int parent_logstart
)
216 int search_clus
, clus_to_match
;
217 struct msdos_dir_entry
*de
;
218 struct inode
*parent
= NULL
;
219 struct inode
*dummy_grand_parent
= NULL
;
220 struct fat_slot_info sinfo
;
221 struct msdos_sb_info
*sbi
= MSDOS_SB(sb
);
222 sector_t blknr
= fat_clus_to_blknr(sbi
, parent_logstart
);
223 struct buffer_head
*parent_bh
= sb_bread(sb
, blknr
);
225 fat_msg(sb
, KERN_ERR
,
226 "unable to read cluster of parent directory");
230 de
= (struct msdos_dir_entry
*) parent_bh
->b_data
;
231 clus_to_match
= fat_get_start(sbi
, &de
[0]);
232 search_clus
= fat_get_start(sbi
, &de
[1]);
234 dummy_grand_parent
= fat_dget(sb
, search_clus
);
235 if (!dummy_grand_parent
) {
236 dummy_grand_parent
= new_inode(sb
);
237 if (!dummy_grand_parent
) {
242 dummy_grand_parent
->i_ino
= iunique(sb
, MSDOS_ROOT_INO
);
243 fat_fill_inode(dummy_grand_parent
, &de
[1]);
244 MSDOS_I(dummy_grand_parent
)->i_pos
= -1;
247 if (!fat_scan_logstart(dummy_grand_parent
, clus_to_match
, &sinfo
))
248 parent
= fat_build_inode(sb
, sinfo
.de
, sinfo
.i_pos
);
251 iput(dummy_grand_parent
);
257 * Find the parent for a directory that is not currently connected to
258 * the filesystem root.
260 * On entry, the caller holds d_inode(child_dir)->i_mutex.
262 static struct dentry
*fat_get_parent(struct dentry
*child_dir
)
264 struct super_block
*sb
= child_dir
->d_sb
;
265 struct buffer_head
*bh
= NULL
;
266 struct msdos_dir_entry
*de
;
267 struct inode
*parent_inode
= NULL
;
268 struct msdos_sb_info
*sbi
= MSDOS_SB(sb
);
270 if (!fat_get_dotdot_entry(d_inode(child_dir
), &bh
, &de
)) {
271 int parent_logstart
= fat_get_start(sbi
, de
);
272 parent_inode
= fat_dget(sb
, parent_logstart
);
273 if (!parent_inode
&& sbi
->options
.nfs
== FAT_NFS_NOSTALE_RO
)
274 parent_inode
= fat_rebuild_parent(sb
, parent_logstart
);
278 return d_obtain_alias(parent_inode
);
281 const struct export_operations fat_export_ops
= {
282 .fh_to_dentry
= fat_fh_to_dentry
,
283 .fh_to_parent
= fat_fh_to_parent
,
284 .get_parent
= fat_get_parent
,
287 const struct export_operations fat_export_ops_nostale
= {
288 .encode_fh
= fat_encode_fh_nostale
,
289 .fh_to_dentry
= fat_fh_to_dentry_nostale
,
290 .fh_to_parent
= fat_fh_to_parent_nostale
,
291 .get_parent
= fat_get_parent
,