Skip to content

Commit 510de83

Browse files
Hongbo Lihsiangkao
authored andcommitted
erofs: fix file handle encoding for 64-bit NIDs
EROFS uses NID to indicate the on-disk inode offset, which can exceed 32 bits. However, the default encode_fh uses the ino32, thus it doesn't work if the image is larger than 128GiB. Let's introduce our own helpers to encode file handles. It's easy to reproduce: 1. prepare an erofs image with nid bigger than U32_MAX 2. mount -t erofs foo.img /mnt/erofs 3. set exportfs with configuration: /mnt/erofs *(rw,sync, no_root_squash) 4. mount -t nfs $IP:/mnt/erofs /mnt/nfs 5. md5sum /mnt/nfs/foo # foo is the file which nid bigger than U32_MAX. # you will get ESTALE error. In the case of overlayfs, the underlying filesystem's file handle is encoded in ovl_fb.fid, which is similar to NFS's case. If the NID of file is larger than U32_MAX, the overlay will get -ESTALE error when calls exportfs_decode_fh. Fixes: 3e917cc ("erofs: make filesystem exportable") Signed-off-by: Hongbo Li <[email protected]> Reviewed-by: Gao Xiang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Gao Xiang <[email protected]>
1 parent 82f2b0b commit 510de83

File tree

1 file changed

+36
-8
lines changed

1 file changed

+36
-8
lines changed

fs/erofs/super.c

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -510,24 +510,52 @@ static int erofs_fc_parse_param(struct fs_context *fc,
510510
return 0;
511511
}
512512

513-
static struct inode *erofs_nfs_get_inode(struct super_block *sb,
514-
u64 ino, u32 generation)
513+
static int erofs_encode_fh(struct inode *inode, u32 *fh, int *max_len,
514+
struct inode *parent)
515515
{
516-
return erofs_iget(sb, ino);
516+
erofs_nid_t nid = EROFS_I(inode)->nid;
517+
int len = parent ? 6 : 3;
518+
519+
if (*max_len < len) {
520+
*max_len = len;
521+
return FILEID_INVALID;
522+
}
523+
524+
fh[0] = (u32)(nid >> 32);
525+
fh[1] = (u32)(nid & 0xffffffff);
526+
fh[2] = inode->i_generation;
527+
528+
if (parent) {
529+
nid = EROFS_I(parent)->nid;
530+
531+
fh[3] = (u32)(nid >> 32);
532+
fh[4] = (u32)(nid & 0xffffffff);
533+
fh[5] = parent->i_generation;
534+
}
535+
536+
*max_len = len;
537+
return parent ? FILEID_INO64_GEN_PARENT : FILEID_INO64_GEN;
517538
}
518539

519540
static struct dentry *erofs_fh_to_dentry(struct super_block *sb,
520541
struct fid *fid, int fh_len, int fh_type)
521542
{
522-
return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
523-
erofs_nfs_get_inode);
543+
if ((fh_type != FILEID_INO64_GEN &&
544+
fh_type != FILEID_INO64_GEN_PARENT) || fh_len < 3)
545+
return NULL;
546+
547+
return d_obtain_alias(erofs_iget(sb,
548+
((u64)fid->raw[0] << 32) | fid->raw[1]));
524549
}
525550

526551
static struct dentry *erofs_fh_to_parent(struct super_block *sb,
527552
struct fid *fid, int fh_len, int fh_type)
528553
{
529-
return generic_fh_to_parent(sb, fid, fh_len, fh_type,
530-
erofs_nfs_get_inode);
554+
if (fh_type != FILEID_INO64_GEN_PARENT || fh_len < 6)
555+
return NULL;
556+
557+
return d_obtain_alias(erofs_iget(sb,
558+
((u64)fid->raw[3] << 32) | fid->raw[4]));
531559
}
532560

533561
static struct dentry *erofs_get_parent(struct dentry *child)
@@ -543,7 +571,7 @@ static struct dentry *erofs_get_parent(struct dentry *child)
543571
}
544572

545573
static const struct export_operations erofs_export_ops = {
546-
.encode_fh = generic_encode_ino32_fh,
574+
.encode_fh = erofs_encode_fh,
547575
.fh_to_dentry = erofs_fh_to_dentry,
548576
.fh_to_parent = erofs_fh_to_parent,
549577
.get_parent = erofs_get_parent,

0 commit comments

Comments
 (0)