mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 03:09:34 +03:00
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 8170d28126
.
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 <ryao@gentoo.org>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #1750
This commit is contained in:
parent
d65e738109
commit
c12e3a594a
@ -2004,12 +2004,12 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
|
|||||||
objset_t *os;
|
objset_t *os;
|
||||||
zap_cursor_t zc;
|
zap_cursor_t zc;
|
||||||
zap_attribute_t zap;
|
zap_attribute_t zap;
|
||||||
int outcount;
|
|
||||||
int error;
|
int error;
|
||||||
uint8_t prefetch;
|
uint8_t prefetch;
|
||||||
|
uint8_t type;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
uint64_t parent;
|
uint64_t parent;
|
||||||
loff_t *pos = &(ctx->pos);
|
uint64_t offset; /* must be unsigned; checks for < 1 */
|
||||||
|
|
||||||
ZFS_ENTER(zsb);
|
ZFS_ENTER(zsb);
|
||||||
ZFS_VERIFY_ZP(zp);
|
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)
|
* Quit if directory has been removed (posix)
|
||||||
*/
|
*/
|
||||||
error = 0;
|
|
||||||
if (zp->z_unlinked)
|
if (zp->z_unlinked)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
error = 0;
|
||||||
os = zsb->z_os;
|
os = zsb->z_os;
|
||||||
|
offset = ctx->pos;
|
||||||
prefetch = zp->z_zn_prefetch;
|
prefetch = zp->z_zn_prefetch;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the iterator cursor.
|
* Initialize the iterator cursor.
|
||||||
*/
|
*/
|
||||||
if (*pos <= 3) {
|
if (offset <= 3) {
|
||||||
/*
|
/*
|
||||||
* Start iteration from the beginning of the directory.
|
* 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.
|
* 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
|
* Transform to file-system independent format
|
||||||
*/
|
*/
|
||||||
outcount = 0;
|
|
||||||
|
|
||||||
while (!done) {
|
while (!done) {
|
||||||
uint64_t objnum;
|
uint64_t objnum;
|
||||||
/*
|
/*
|
||||||
* Special case `.', `..', and `.zfs'.
|
* Special case `.', `..', and `.zfs'.
|
||||||
*/
|
*/
|
||||||
if (*pos == 0) {
|
if (offset == 0) {
|
||||||
(void) strcpy(zap.za_name, ".");
|
(void) strcpy(zap.za_name, ".");
|
||||||
zap.za_normalization_conflict = 0;
|
zap.za_normalization_conflict = 0;
|
||||||
objnum = zp->z_id;
|
objnum = zp->z_id;
|
||||||
} else if (*pos == 1) {
|
type = DT_DIR;
|
||||||
|
} else if (offset == 1) {
|
||||||
(void) strcpy(zap.za_name, "..");
|
(void) strcpy(zap.za_name, "..");
|
||||||
zap.za_normalization_conflict = 0;
|
zap.za_normalization_conflict = 0;
|
||||||
objnum = parent;
|
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);
|
(void) strcpy(zap.za_name, ZFS_CTLDIR_NAME);
|
||||||
zap.za_normalization_conflict = 0;
|
zap.za_normalization_conflict = 0;
|
||||||
objnum = ZFSCTL_INO_ROOT;
|
objnum = ZFSCTL_INO_ROOT;
|
||||||
|
type = DT_DIR;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Grab next entry.
|
* Grab next entry.
|
||||||
@ -2089,7 +2091,7 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
|
|||||||
"entry, obj = %lld, offset = %lld, "
|
"entry, obj = %lld, offset = %lld, "
|
||||||
"length = %d, num = %lld\n",
|
"length = %d, num = %lld\n",
|
||||||
(u_longlong_t)zp->z_id,
|
(u_longlong_t)zp->z_id,
|
||||||
(u_longlong_t)*pos,
|
(u_longlong_t)offset,
|
||||||
zap.za_integer_length,
|
zap.za_integer_length,
|
||||||
(u_longlong_t)zap.za_num_integers);
|
(u_longlong_t)zap.za_num_integers);
|
||||||
error = ENXIO;
|
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);
|
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),
|
done = !dir_emit(ctx, zap.za_name, strlen(zap.za_name),
|
||||||
objnum, ZFS_DIRENT_TYPE(zap.za_first_integer));
|
objnum, type);
|
||||||
if (done)
|
if (done)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2109,12 +2112,16 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
|
|||||||
dmu_prefetch(os, objnum, 0, 0);
|
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);
|
zap_cursor_advance(&zc);
|
||||||
*pos = zap_cursor_serialize(&zc);
|
offset = zap_cursor_serialize(&zc);
|
||||||
} else {
|
} else {
|
||||||
(*pos)++;
|
offset += 1;
|
||||||
}
|
}
|
||||||
|
ctx->pos = offset;
|
||||||
}
|
}
|
||||||
zp->z_zn_prefetch = B_FALSE; /* a lookup will re-enable pre-fetching */
|
zp->z_zn_prefetch = B_FALSE; /* a lookup will re-enable pre-fetching */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user