diff options
author | Richard Yao <[email protected]> | 2013-10-02 11:22:53 -0400 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2013-10-29 09:51:59 -0700 |
commit | c12e3a594a49ed10b7870d950c1f336f78f136cb (patch) | |
tree | f44342977c62b07bffa357b53a2afb804fd91ffc /module/zfs | |
parent | d65e73810938e5619b72591d3438063b00949e77 (diff) |
Restructure zfs_readdir() to fix regressions
This does the following:
1. It creates a uint8_t type value, which is initialized to DT_DIR on
dot directories and ZFS_DIRENT_TYPE(zap.za_first_integer) otherwise.
This resolves a regression where we return unintialized values as the
directory entry type on dot directories. This was accidentally
introduced by commit 8170d281263e52ff33d7fba93ab625196844df36.
2. It restructures zfs_readdir() code to use `uint64_t offset` like
Illumos instead of `loff_t *pos`. This resolves a regression where
negative ZAP cursors were treated as if they were dot directories.
3. It restructures the function to more closely match the structure of
zfs_readdir() on Illumos and removes the unused variable outcount, which
was only used on Illumos.
Signed-off-by: Richard Yao <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #1750
Diffstat (limited to 'module/zfs')
-rw-r--r-- | module/zfs/zfs_vnops.c | 37 |
1 files changed, 22 insertions, 15 deletions
diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index 876d44b35..436a25eaf 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -2004,12 +2004,12 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr) objset_t *os; zap_cursor_t zc; zap_attribute_t zap; - int outcount; int error; uint8_t prefetch; + uint8_t type; int done = 0; uint64_t parent; - loff_t *pos = &(ctx->pos); + uint64_t offset; /* must be unsigned; checks for < 1 */ ZFS_ENTER(zsb); ZFS_VERIFY_ZP(zp); @@ -2021,17 +2021,18 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr) /* * Quit if directory has been removed (posix) */ - error = 0; if (zp->z_unlinked) goto out; + error = 0; os = zsb->z_os; + offset = ctx->pos; prefetch = zp->z_zn_prefetch; /* * Initialize the iterator cursor. */ - if (*pos <= 3) { + if (offset <= 3) { /* * Start iteration from the beginning of the directory. */ @@ -2040,31 +2041,32 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr) /* * The offset is a serialized cursor. */ - zap_cursor_init_serialized(&zc, os, zp->z_id, *pos); + zap_cursor_init_serialized(&zc, os, zp->z_id, offset); } /* * Transform to file-system independent format */ - outcount = 0; - while (!done) { uint64_t objnum; /* * Special case `.', `..', and `.zfs'. */ - if (*pos == 0) { + if (offset == 0) { (void) strcpy(zap.za_name, "."); zap.za_normalization_conflict = 0; objnum = zp->z_id; - } else if (*pos == 1) { + type = DT_DIR; + } else if (offset == 1) { (void) strcpy(zap.za_name, ".."); zap.za_normalization_conflict = 0; objnum = parent; - } else if (*pos == 2 && zfs_show_ctldir(zp)) { + type = DT_DIR; + } else if (offset == 2 && zfs_show_ctldir(zp)) { (void) strcpy(zap.za_name, ZFS_CTLDIR_NAME); zap.za_normalization_conflict = 0; objnum = ZFSCTL_INO_ROOT; + type = DT_DIR; } else { /* * Grab next entry. @@ -2089,7 +2091,7 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr) "entry, obj = %lld, offset = %lld, " "length = %d, num = %lld\n", (u_longlong_t)zp->z_id, - (u_longlong_t)*pos, + (u_longlong_t)offset, zap.za_integer_length, (u_longlong_t)zap.za_num_integers); error = ENXIO; @@ -2097,10 +2099,11 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr) } objnum = ZFS_DIRENT_OBJ(zap.za_first_integer); + type = ZFS_DIRENT_TYPE(zap.za_first_integer); } done = !dir_emit(ctx, zap.za_name, strlen(zap.za_name), - objnum, ZFS_DIRENT_TYPE(zap.za_first_integer)); + objnum, type); if (done) break; @@ -2109,12 +2112,16 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr) dmu_prefetch(os, objnum, 0, 0); } - if (*pos > 2 || (*pos == 2 && !zfs_show_ctldir(zp))) { + /* + * Move to the next entry, fill in the previous offset. + */ + if (offset > 2 || (offset == 2 && !zfs_show_ctldir(zp))) { zap_cursor_advance(&zc); - *pos = zap_cursor_serialize(&zc); + offset = zap_cursor_serialize(&zc); } else { - (*pos)++; + offset += 1; } + ctx->pos = offset; } zp->z_zn_prefetch = B_FALSE; /* a lookup will re-enable pre-fetching */ |