FreeBSD/sys/fs/nfsclient/nfs_clvnops.c
/*
 * NFS advisory byte-level locks.
 */
NFS advisory byte-level locks.
NFS advisory byte - level locks .
static int
nfs_advlock(struct vop_advlock_args *ap)
{
	struct vnode *vp = ap->a_vp;
	struct ucred *cred;
	struct nfsnode *np = VTONFS(ap->a_vp);
	struct proc *p = (struct proc *)ap->a_id;
	struct thread *td = curthread;	
	struct vattr va;
	int ret, error = EOPNOTSUPP;
	u_quad_t size;
	if (NFS_ISV4(vp) && (ap->a_flags & (F_POSIX | F_FLOCK)) != 0) {
		if (vp->v_type != VREG)
			return (EINVAL);
		if ((ap->a_flags & F_POSIX) != 0)
			cred = p->p_ucred;
		else
			cred = td->td_ucred;
		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
		if (vp->v_iflag & VI_DOOMED) {
			NFSVOPUNLOCK(vp, 0);
			return (EBADF);
		}
		if (ap->a_op == F_UNLCK &&
		    nfscl_checkwritelocked(vp, ap->a_fl, cred, td, ap->a_id,
		    ap->a_flags))
			(void) ncl_flush(vp, MNT_WAIT, cred, td, 1, 0);
		do {
			ret = nfsrpc_advlock(vp, np->n_size, ap->a_op,
			    ap->a_fl, 0, cred, td, ap->a_id, ap->a_flags);
			if (ret == NFSERR_DENIED && (ap->a_flags & F_WAIT) &&
			    ap->a_op == F_SETLK) {
				NFSVOPUNLOCK(vp, 0);
				error = nfs_catnap(PZERO | PCATCH, ret,
				    "ncladvl");
				if (error)
					return (EINTR);
				NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
				if (vp->v_iflag & VI_DOOMED) {
					NFSVOPUNLOCK(vp, 0);
					return (EBADF);
				}
			}
		} while (ret == NFSERR_DENIED && (ap->a_flags & F_WAIT) &&
		     ap->a_op == F_SETLK);
		if (ret == NFSERR_DENIED) {
			NFSVOPUNLOCK(vp, 0);
			return (EAGAIN);
		} else if (ret == EINVAL || ret == EBADF || ret == EINTR) {
			NFSVOPUNLOCK(vp, 0);
			return (ret);
		} else if (ret != 0) {
			NFSVOPUNLOCK(vp, 0);
			return (EACCES);
		}
		if (ap->a_op == F_SETLK) {
			if ((np->n_flag & NMODIFIED) == 0) {
				np->n_attrstamp = 0;
				KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
				ret = VOP_GETATTR(vp, &va, cred);
			}
			if ((np->n_flag & NMODIFIED) || ret ||
			    np->n_change != va.va_filerev) {
				(void) ncl_vinvalbuf(vp, V_SAVE, td, 1);
				np->n_attrstamp = 0;
				KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
				ret = VOP_GETATTR(vp, &va, cred);
				if (!ret) {
					np->n_mtime = va.va_mtime;
					np->n_change = va.va_filerev;
				}
			}
			mtx_lock(&np->n_mtx);
			np->n_flag |= NHASBEENLOCKED;
			mtx_unlock(&np->n_mtx);
		}
		NFSVOPUNLOCK(vp, 0);
		return (0);
	} else if (!NFS_ISV4(vp)) {
		error = NFSVOPLOCK(vp, LK_SHARED);
		if (error)
			return (error);
		if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) {
			size = VTONFS(vp)->n_size;
			NFSVOPUNLOCK(vp, 0);
			error = lf_advlock(ap, &(vp->v_lockf), size);
		} else {
			if (nfs_advlock_p != NULL)
				error = nfs_advlock_p(ap);
			else {
				NFSVOPUNLOCK(vp, 0);
				error = ENOLCK;
			}
		}
		if (error == 0 && ap->a_op == F_SETLK) {
			error = NFSVOPLOCK(vp, LK_SHARED);
			if (error == 0) {
				mtx_lock(&np->n_mtx);
				np->n_flag |= NHASBEENLOCKED;
				mtx_unlock(&np->n_mtx);
				NFSVOPUNLOCK(vp, 0);
			}
		}
	}
	return (error);
}
static int nfs_advlock ( struct vop_advlock_args * ap ) { struct vnode * vp = ap -> a_vp ; struct ucred * cred ; struct nfsnode * np = VTONFS ( ap -> a_vp ) ; struct proc * p = ( struct proc * ) ap -> a_id ; struct thread * td = curthread ; struct vattr va ; int ret , error = EOPNOTSUPP ; u_quad_t size ; if ( NFS_ISV4 ( vp ) && ( ap -> a_flags & ( F_POSIX | F_FLOCK ) ) != 0 ) { if ( vp -> v_type != VREG ) return ( EINVAL ) ; if ( ( ap -> a_flags & F_POSIX ) != 0 ) cred = p -> p_ucred ; else cred = td -> td_ucred ; NFSVOPLOCK ( vp , LK_EXCLUSIVE | LK_RETRY ) ; if ( vp -> v_iflag & VI_DOOMED ) { NFSVOPUNLOCK ( vp , 0 ) ; return ( EBADF ) ; } if ( ap -> a_op == F_UNLCK && nfscl_checkwritelocked ( vp , ap -> a_fl , cred , td , ap -> a_id , ap -> a_flags ) ) ( void ) ncl_flush ( vp , MNT_WAIT , cred , td , 1 , 0 ) ; do { ret = nfsrpc_advlock ( vp , np -> n_size , ap -> a_op , ap -> a_fl , 0 , cred , td , ap -> a_id , ap -> a_flags ) ; if ( ret == NFSERR_DENIED && ( ap -> a_flags & F_WAIT ) && ap -> a_op == F_SETLK ) { NFSVOPUNLOCK ( vp , 0 ) ; error = nfs_catnap ( PZERO | PCATCH , ret , " " ) ; if ( error ) return ( EINTR ) ; NFSVOPLOCK ( vp , LK_EXCLUSIVE | LK_RETRY ) ; if ( vp -> v_iflag & VI_DOOMED ) { NFSVOPUNLOCK ( vp , 0 ) ; return ( EBADF ) ; } } } while ( ret == NFSERR_DENIED && ( ap -> a_flags & F_WAIT ) && ap -> a_op == F_SETLK ) ; if ( ret == NFSERR_DENIED ) { NFSVOPUNLOCK ( vp , 0 ) ; return ( EAGAIN ) ; } else if ( ret == EINVAL || ret == EBADF || ret == EINTR ) { NFSVOPUNLOCK ( vp , 0 ) ; return ( ret ) ; } else if ( ret != 0 ) { NFSVOPUNLOCK ( vp , 0 ) ; return ( EACCES ) ; } if ( ap -> a_op == F_SETLK ) { if ( ( np -> n_flag & NMODIFIED ) == 0 ) { np -> n_attrstamp = 0 ; KDTRACE_NFS_ATTRCACHE_FLUSH_DONE ( vp ) ; ret = VOP_GETATTR ( vp , & va , cred ) ; } if ( ( np -> n_flag & NMODIFIED ) || ret || np -> n_change != va . va_filerev ) { ( void ) ncl_vinvalbuf ( vp , V_SAVE , td , 1 ) ; np -> n_attrstamp = 0 ; KDTRACE_NFS_ATTRCACHE_FLUSH_DONE ( vp ) ; ret = VOP_GETATTR ( vp , & va , cred ) ; if ( ! ret ) { np -> n_mtime = va . va_mtime ; np -> n_change = va . va_filerev ; } } mtx_lock ( & np -> n_mtx ) ; np -> n_flag |= NHASBEENLOCKED ; mtx_unlock ( & np -> n_mtx ) ; } NFSVOPUNLOCK ( vp , 0 ) ; return ( 0 ) ; } else if ( ! NFS_ISV4 ( vp ) ) { error = NFSVOPLOCK ( vp , LK_SHARED ) ; if ( error ) return ( error ) ; if ( ( VFSTONFS ( vp -> v_mount ) -> nm_flag & NFSMNT_NOLOCKD ) != 0 ) { size = VTONFS ( vp ) -> n_size ; NFSVOPUNLOCK ( vp , 0 ) ; error = lf_advlock ( ap , & ( vp -> v_lockf ) , size ) ; } else { if ( nfs_advlock_p != NULL ) error = nfs_advlock_p ( ap ) ; else { NFSVOPUNLOCK ( vp , 0 ) ; error = ENOLCK ; } } if ( error == 0 && ap -> a_op == F_SETLK ) { error = NFSVOPLOCK ( vp , LK_SHARED ) ; if ( error == 0 ) { mtx_lock ( & np -> n_mtx ) ; np -> n_flag |= NHASBEENLOCKED ; mtx_unlock ( & np -> n_mtx ) ; NFSVOPUNLOCK ( vp , 0 ) ; } } } return ( error ) ; }
NFS advisory byte-level locks.
NFS advisory byte - level locks .
/* XXX */ /*
		 * If this is unlocking a write locked region, flush and
		 * commit them before unlocking. This is required by
		 * RFC3530 Sec. 9.3.2.
		 */ /*
		 * Loop around doing the lock op, while a blocking lock
		 * must wait for the lock op to succeed.
		 */ /*
		 * Now, if we just got a lock, invalidate data in the buffer
		 * cache, as required, so that the coherency conforms with
		 * RFC3530 Sec. 9.3.2.
		 */ /* Mark that a file lock has been acquired. */ /* Mark that a file lock has been acquired. */