From 65589a29f4f530aff3ccecf285077efc2d00d656 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Wed, 16 Jul 2014 14:04:46 +0000 Subject: [PATCH] Check for the cross-device cross-link attempt in the VFS, instead of forcing filesystem VOP_LINK() methods to repeat the code. In tmpfs_link(), remove redundand check for the type of the source, already done by VFS. Note that NFS server already performs this check before calling VOP_LINK(). Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks --- sys/fs/ext2fs/ext2_vnops.c | 4 ---- sys/fs/nandfs/nandfs_vnops.c | 3 --- sys/fs/nfsclient/nfs_clvnops.c | 4 ---- sys/fs/nullfs/null_vnops.c | 10 ---------- sys/fs/tmpfs/tmpfs_vnops.c | 15 --------------- sys/kern/vfs_syscalls.c | 10 +++++++++- sys/ufs/ufs/ufs_vnops.c | 4 ---- 7 files changed, 9 insertions(+), 41 deletions(-) diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c index 523e3c742179..2046e33a5d39 100644 --- a/sys/fs/ext2fs/ext2_vnops.c +++ b/sys/fs/ext2fs/ext2_vnops.c @@ -666,10 +666,6 @@ ext2_link(struct vop_link_args *ap) if ((cnp->cn_flags & HASBUF) == 0) panic("ext2_link: no name"); #endif - if (tdvp->v_mount != vp->v_mount) { - error = EXDEV; - goto out; - } ip = VTOI(vp); if ((nlink_t)ip->i_nlink >= EXT2_LINK_MAX) { error = EMLINK; diff --git a/sys/fs/nandfs/nandfs_vnops.c b/sys/fs/nandfs/nandfs_vnops.c index 056ca901c2b9..0f26b19ee6af 100644 --- a/sys/fs/nandfs/nandfs_vnops.c +++ b/sys/fs/nandfs/nandfs_vnops.c @@ -1355,9 +1355,6 @@ nandfs_link(struct vop_link_args *ap) struct nandfs_inode *inode = &node->nn_inode; int error; - if (tdvp->v_mount != vp->v_mount) - return (EXDEV); - if (inode->i_links_count >= LINK_MAX) return (EMLINK); diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index 2d13b06b6db7..9570b70092ac 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -1976,10 +1976,6 @@ nfs_link(struct vop_link_args *ap) struct nfsvattr nfsva, dnfsva; int error = 0, attrflag, dattrflag; - if (vp->v_mount != tdvp->v_mount) { - return (EXDEV); - } - /* * Push all writes to the server, so that the attribute cache * doesn't get "out of sync" with the server. diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c index cf3762eda39d..70402e35f1db 100644 --- a/sys/fs/nullfs/null_vnops.c +++ b/sys/fs/nullfs/null_vnops.c @@ -858,15 +858,6 @@ null_vptocnp(struct vop_vptocnp_args *ap) return (error); } -static int -null_link(struct vop_link_args *ap) -{ - - if (ap->a_tdvp->v_mount != ap->a_vp->v_mount) - return (EXDEV); - return (null_bypass((struct vop_generic_args *)ap)); -} - /* * Global vfs data structures */ @@ -880,7 +871,6 @@ struct vop_vector null_vnodeops = { .vop_getwritemount = null_getwritemount, .vop_inactive = null_inactive, .vop_islocked = vop_stdislocked, - .vop_link = null_link, .vop_lock1 = null_lock, .vop_lookup = null_lookup, .vop_open = null_open, diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index cb35a69ecc92..c11fe31e7d4b 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -571,21 +571,6 @@ tmpfs_link(struct vop_link_args *v) MPASS(VOP_ISLOCKED(dvp)); MPASS(cnp->cn_flags & HASBUF); MPASS(dvp != vp); /* XXX When can this be false? */ - - /* XXX: Why aren't the following two tests done by the caller? */ - - /* Hard links of directories are forbidden. */ - if (vp->v_type == VDIR) { - error = EPERM; - goto out; - } - - /* Cannot create cross-device links. */ - if (dvp->v_mount != vp->v_mount) { - error = EXDEV; - goto out; - } - node = VP_TO_TMPFS_NODE(vp); /* Ensure that we do not overflow the maximum number of links imposed diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 9d5380ae6011..1406e0f8bc5f 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1578,7 +1578,15 @@ kern_linkat(struct thread *td, int fd1, int fd2, char *path1, char *path2, vrele(nd.ni_vp); error = EEXIST; } else if ((error = vn_lock(vp, LK_EXCLUSIVE)) == 0) { - error = can_hardlink(vp, td->td_ucred); + /* + * Check for cross-device links. No need to + * recheck vp->v_type, since it cannot change + * for non-doomed vnode. + */ + if (nd.ni_dvp->v_mount != vp->v_mount) + error = EXDEV; + else + error = can_hardlink(vp, td->td_ucred); if (error == 0) #ifdef MAC error = mac_vnode_check_link(td->td_ucred, diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index 3504f0eb156d..3379b134e8ca 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -968,10 +968,6 @@ ufs_link(ap) if ((cnp->cn_flags & HASBUF) == 0) panic("ufs_link: no name"); #endif - if (tdvp->v_mount != vp->v_mount) { - error = EXDEV; - goto out; - } if (VTOI(tdvp)->i_effnlink < 2) panic("ufs_link: Bad link count %d on parent", VTOI(tdvp)->i_effnlink);