Work-around READDIRPLUS problem with .zfs/ and .zfs/snapshot/ directories

by just returning EOPNOTSUPP. This will allow NFS server to fall back to
regular READDIR.

Note that converting inode number to snapshot's vnode is expensive operation.
Snapshots are stored in AVL tree, but based on their names, not inode numbers,
so to convert inode to snapshot vnode we have to interate over all snalshots.

This is not a problem in OpenSolaris, because in their READDIRPLUS
implementation they use VOP_LOOKUP() on d_name, instead of VFS_VGET() on
d_fileno as we do.

PR:		kern/125149
Reported by:	Weldon Godfrey <wgodfrey@ena.com>
Analysis by:	Jaakko Heinonen <jh@saunalahti.fi>
MFC after:	3 days
This commit is contained in:
Pawel Jakub Dawidek 2009-09-13 16:05:20 +00:00
parent 4c68dee0fb
commit 7746b6461d

View File

@ -1114,6 +1114,20 @@ zfs_vget(vfs_t *vfsp, ino_t ino, int flags, vnode_t **vpp)
znode_t *zp;
int err;
/*
* XXXPJD: zfs_zget() can't operate on virtual entires like .zfs/ or
* .zfs/snapshot/ directories, so for now just return EOPNOTSUPP.
* This will make NFS to fall back to using READDIR instead of
* READDIRPLUS.
* Also snapshots are stored in AVL tree, but based on their names,
* not inode numbers, so it will be very inefficient to iterate
* over all snapshots to find the right one.
* Note that OpenSolaris READDIRPLUS implementation does LOOKUP on
* d_name, and not VGET on d_fileno as we do.
*/
if (ino == ZFSCTL_INO_ROOT || ino == ZFSCTL_INO_SNAPDIR)
return (EOPNOTSUPP);
ZFS_ENTER(zfsvfs);
err = zfs_zget(zfsvfs, ino, &zp);
if (err == 0 && zp->z_unlinked) {