Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/nfsclient/nfs_clvnops.c
Show First 20 Lines • Show All 641 Lines • ▼ Show 20 Lines | nfs_open(struct vop_open_args *ap) | ||||
/* | /* | ||||
* Now, if this Open will be doing reading, re-validate/flush the | * Now, if this Open will be doing reading, re-validate/flush the | ||||
* cache, so that Close/Open coherency is maintained. | * cache, so that Close/Open coherency is maintained. | ||||
*/ | */ | ||||
NFSLOCKNODE(np); | NFSLOCKNODE(np); | ||||
if (np->n_flag & NMODIFIED) { | if (np->n_flag & NMODIFIED) { | ||||
NFSUNLOCKNODE(np); | NFSUNLOCKNODE(np); | ||||
if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { | |||||
NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); | |||||
if (VN_IS_DOOMED(vp)) | |||||
return (EBADF); | |||||
} | |||||
error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); | error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); | ||||
if (error == EINTR || error == EIO) { | if (error == EINTR || error == EIO) { | ||||
if (NFS_ISV4(vp)) | if (NFS_ISV4(vp)) | ||||
(void) nfsrpc_close(vp, 0, ap->a_td); | (void) nfsrpc_close(vp, 0, ap->a_td); | ||||
return (error); | return (error); | ||||
} | } | ||||
NFSLOCKNODE(np); | NFSLOCKNODE(np); | ||||
np->n_attrstamp = 0; | np->n_attrstamp = 0; | ||||
Show All 20 Lines | if (error) { | ||||
return (error); | return (error); | ||||
} | } | ||||
NFSLOCKNODE(np); | NFSLOCKNODE(np); | ||||
if ((NFS_ISV4(vp) && np->n_change != vattr.va_filerev) || | if ((NFS_ISV4(vp) && np->n_change != vattr.va_filerev) || | ||||
NFS_TIMESPEC_COMPARE(&np->n_mtime, &vattr.va_mtime)) { | NFS_TIMESPEC_COMPARE(&np->n_mtime, &vattr.va_mtime)) { | ||||
if (vp->v_type == VDIR) | if (vp->v_type == VDIR) | ||||
np->n_direofoffset = 0; | np->n_direofoffset = 0; | ||||
NFSUNLOCKNODE(np); | NFSUNLOCKNODE(np); | ||||
if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { | |||||
NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); | |||||
if (VN_IS_DOOMED(vp)) | |||||
return (EBADF); | |||||
} | |||||
error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); | error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); | ||||
if (error == EINTR || error == EIO) { | if (error == EINTR || error == EIO) { | ||||
if (NFS_ISV4(vp)) | if (NFS_ISV4(vp)) | ||||
(void) nfsrpc_close(vp, 0, ap->a_td); | (void) nfsrpc_close(vp, 0, ap->a_td); | ||||
return (error); | return (error); | ||||
} | } | ||||
NFSLOCKNODE(np); | NFSLOCKNODE(np); | ||||
np->n_mtime = vattr.va_mtime; | np->n_mtime = vattr.va_mtime; | ||||
if (NFS_ISV4(vp)) | if (NFS_ISV4(vp)) | ||||
np->n_change = vattr.va_filerev; | np->n_change = vattr.va_filerev; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* If the object has >= 1 O_DIRECT active opens, we disable caching. | * If the object has >= 1 O_DIRECT active opens, we disable caching. | ||||
*/ | */ | ||||
if (newnfs_directio_enable && (fmode & O_DIRECT) && | if (newnfs_directio_enable && (fmode & O_DIRECT) && | ||||
(vp->v_type == VREG)) { | (vp->v_type == VREG)) { | ||||
if (np->n_directio_opens == 0) { | if (np->n_directio_opens == 0) { | ||||
NFSUNLOCKNODE(np); | NFSUNLOCKNODE(np); | ||||
if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { | |||||
NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); | |||||
if (VN_IS_DOOMED(vp)) | |||||
return (EBADF); | |||||
} | |||||
error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); | error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); | ||||
if (error) { | if (error) { | ||||
if (NFS_ISV4(vp)) | if (NFS_ISV4(vp)) | ||||
(void) nfsrpc_close(vp, 0, ap->a_td); | (void) nfsrpc_close(vp, 0, ap->a_td); | ||||
return (error); | return (error); | ||||
} | } | ||||
NFSLOCKNODE(np); | NFSLOCKNODE(np); | ||||
np->n_flag |= NNONCACHE; | np->n_flag |= NNONCACHE; | ||||
Show All 29 Lines | nfs_open(struct vop_open_args *ap) | ||||
* Make sure all writes are pushed to the NFS server. If this is not | * Make sure all writes are pushed to the NFS server. If this is not | ||||
* done, the modify time of the file can change while the text | * done, the modify time of the file can change while the text | ||||
* file is being executed. This will cause the process that is | * file is being executed. This will cause the process that is | ||||
* executing the text file to be terminated. | * executing the text file to be terminated. | ||||
*/ | */ | ||||
if (vp->v_writecount <= -1) { | if (vp->v_writecount <= -1) { | ||||
if ((obj = vp->v_object) != NULL && | if ((obj = vp->v_object) != NULL && | ||||
vm_object_mightbedirty(obj)) { | vm_object_mightbedirty(obj)) { | ||||
if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { | |||||
NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); | |||||
if (VN_IS_DOOMED(vp)) | |||||
return (EBADF); | |||||
} | |||||
VM_OBJECT_WLOCK(obj); | VM_OBJECT_WLOCK(obj); | ||||
vm_object_page_clean(obj, 0, 0, OBJPC_SYNC); | vm_object_page_clean(obj, 0, 0, OBJPC_SYNC); | ||||
VM_OBJECT_WUNLOCK(obj); | VM_OBJECT_WUNLOCK(obj); | ||||
} | } | ||||
/* Now, flush the buffer cache. */ | /* Now, flush the buffer cache. */ | ||||
ncl_flush(vp, MNT_WAIT, curthread, 0, 0); | ncl_flush(vp, MNT_WAIT, curthread, 0, 0); | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | if (vp->v_type == VREG) { | ||||
/* | /* | ||||
* Examine and clean dirty pages, regardless of NMODIFIED. | * Examine and clean dirty pages, regardless of NMODIFIED. | ||||
* This closes a major hole in close-to-open consistency. | * This closes a major hole in close-to-open consistency. | ||||
* We want to push out all dirty pages (and buffers) on | * We want to push out all dirty pages (and buffers) on | ||||
* close, regardless of whether they were dirtied by | * close, regardless of whether they were dirtied by | ||||
* mmap'ed writes or via write(). | * mmap'ed writes or via write(). | ||||
*/ | */ | ||||
if (nfs_clean_pages_on_close && vp->v_object) { | if (nfs_clean_pages_on_close && vp->v_object) { | ||||
if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { | |||||
NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); | |||||
if (VN_IS_DOOMED(vp) && ap->a_fflag != FNONBLOCK) | |||||
return (EBADF); | |||||
} | |||||
VM_OBJECT_WLOCK(vp->v_object); | VM_OBJECT_WLOCK(vp->v_object); | ||||
vm_object_page_clean(vp->v_object, 0, 0, 0); | vm_object_page_clean(vp->v_object, 0, 0, 0); | ||||
VM_OBJECT_WUNLOCK(vp->v_object); | VM_OBJECT_WUNLOCK(vp->v_object); | ||||
} | } | ||||
NFSLOCKNODE(np); | NFSLOCKNODE(np); | ||||
if (np->n_flag & NMODIFIED) { | if (np->n_flag & NMODIFIED) { | ||||
NFSUNLOCKNODE(np); | NFSUNLOCKNODE(np); | ||||
if (NFS_ISV3(vp)) { | if (NFS_ISV3(vp)) { | ||||
/* | /* | ||||
* Under NFSv3 we have dirty buffers to dispose of. We | * Under NFSv3 we have dirty buffers to dispose of. We | ||||
* must flush them to the NFS server. We have the option | * must flush them to the NFS server. We have the option | ||||
* of waiting all the way through the commit rpc or just | * of waiting all the way through the commit rpc or just | ||||
* waiting for the initial write. The default is to only | * waiting for the initial write. The default is to only | ||||
* wait through the initial write so the data is in the | * wait through the initial write so the data is in the | ||||
* server's cache, which is roughly similar to the state | * server's cache, which is roughly similar to the state | ||||
* a standard disk subsystem leaves the file in on close(). | * a standard disk subsystem leaves the file in on close(). | ||||
* | * | ||||
* We cannot clear the NMODIFIED bit in np->n_flag due to | * We cannot clear the NMODIFIED bit in np->n_flag due to | ||||
* potential races with other processes, and certainly | * potential races with other processes, and certainly | ||||
* cannot clear it if we don't commit. | * cannot clear it if we don't commit. | ||||
* These races occur when there is no longer the old | * These races occur when there is no longer the old | ||||
* traditional vnode locking implemented for Vnode Ops. | * traditional vnode locking implemented for Vnode Ops. | ||||
*/ | */ | ||||
int cm = newnfs_commit_on_close ? 1 : 0; | int cm = newnfs_commit_on_close ? 1 : 0; | ||||
if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { | |||||
NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); | |||||
if (VN_IS_DOOMED(vp) && ap->a_fflag != FNONBLOCK) | |||||
return (EBADF); | |||||
} | |||||
error = ncl_flush(vp, MNT_WAIT, ap->a_td, cm, 0); | error = ncl_flush(vp, MNT_WAIT, ap->a_td, cm, 0); | ||||
/* np->n_flag &= ~NMODIFIED; */ | /* np->n_flag &= ~NMODIFIED; */ | ||||
} else if (NFS_ISV4(vp)) { | } else if (NFS_ISV4(vp)) { | ||||
if (nfscl_mustflush(vp) != 0) { | if (nfscl_mustflush(vp) != 0) { | ||||
int cm = newnfs_commit_on_close ? 1 : 0; | int cm = newnfs_commit_on_close ? 1 : 0; | ||||
if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { | |||||
NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); | |||||
if (VN_IS_DOOMED(vp) && ap->a_fflag != | |||||
FNONBLOCK) | |||||
return (EBADF); | |||||
} | |||||
error = ncl_flush(vp, MNT_WAIT, ap->a_td, | error = ncl_flush(vp, MNT_WAIT, ap->a_td, | ||||
cm, 0); | cm, 0); | ||||
/* | /* | ||||
* as above w.r.t races when clearing | * as above w.r.t races when clearing | ||||
* NMODIFIED. | * NMODIFIED. | ||||
* np->n_flag &= ~NMODIFIED; | * np->n_flag &= ~NMODIFIED; | ||||
*/ | */ | ||||
} | } | ||||
} else { | } else { | ||||
if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { | |||||
NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY); | |||||
if (VN_IS_DOOMED(vp) && ap->a_fflag != | |||||
FNONBLOCK) | |||||
return (EBADF); | |||||
} | |||||
error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); | error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); | ||||
} | } | ||||
NFSLOCKNODE(np); | NFSLOCKNODE(np); | ||||
} | } | ||||
/* | /* | ||||
* Invalidate the attribute cache in all cases. | * Invalidate the attribute cache in all cases. | ||||
* An open is going to fetch fresh attrs any way, other procs | * An open is going to fetch fresh attrs any way, other procs | ||||
* on this node that have file open will be forced to do an | * on this node that have file open will be forced to do an | ||||
▲ Show 20 Lines • Show All 3,645 Lines • Show Last 20 Lines |