summaryrefslogtreecommitdiffstats
path: root/sys/nfs/nfsnode.h
diff options
context:
space:
mode:
authordillon <dillon@FreeBSD.org>1999-12-14 19:07:54 +0000
committerdillon <dillon@FreeBSD.org>1999-12-14 19:07:54 +0000
commit3968ced3f8a2f899bd9f39b2b067f2236d485ce5 (patch)
tree6751051d6eb810f743e91024499cb430268b96e2 /sys/nfs/nfsnode.h
parent4c83e2cd181003d28cb3352704faaa4cd1acdeff (diff)
downloadFreeBSD-src-3968ced3f8a2f899bd9f39b2b067f2236d485ce5.zip
FreeBSD-src-3968ced3f8a2f899bd9f39b2b067f2236d485ce5.tar.gz
Fix two problems: First, fix the append seek position race that can
occur due to np->n_size potentially changing if nfs_getcacheblk() blocks in nfs_write(). Second, under -current we must supply the proper bufsize when obtaining buffers that straddle the EOF, but due to the fact that np->n_size can change out from under us it is possible that we may specify the wrong buffer size and wind up truncating dirty data written by another process. Both problems are solved by implementing nfs_rslock(), which allows us to lock around sensitive buffer cache operations such as those that occur when appending to a file. It is believed that this race is responsible for causing dirtyoff/dirtyend and (in stable) validoff/validend to exceed the buffer size. Therefore we have now added a warning printf for the dirtyoff/end case in current. However, we have introduced a new problem which we need to fix at some point, and that is that soft or intr NFS mounts may become uninterruptable from the point of view of process A which is stuck waiting on rslock while process B is stuck doing the rpc. To unstick process A, process B would have to be interrupted first. Reviewed by: Alfred Perlstein <bright@wintelcom.net>
Diffstat (limited to 'sys/nfs/nfsnode.h')
-rw-r--r--sys/nfs/nfsnode.h26
1 files changed, 26 insertions, 0 deletions
diff --git a/sys/nfs/nfsnode.h b/sys/nfs/nfsnode.h
index 3bc818f..1ca4529 100644
--- a/sys/nfs/nfsnode.h
+++ b/sys/nfs/nfsnode.h
@@ -118,6 +118,7 @@ struct nfsnode {
short n_fhsize; /* size in bytes, of fh */
short n_flag; /* Flag for locking.. */
nfsfh_t n_fh; /* Small File Handle */
+ struct lock n_rslock;
};
#define n_atim n_un1.nf_atim
@@ -157,6 +158,31 @@ extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
extern struct nfsmount *nfs_iodmount[NFS_MAXASYNCDAEMON];
#if defined(KERNEL) || defined(_KERNEL)
+
+/*
+ * nfs_rslock - Attempt to obtain lock on nfsnode
+ *
+ * Attempt to obtain a lock on the passed nfsnode, returning ENOLCK
+ * if the lock could not be obtained due to our having to sleep. This
+ * function is generally used to lock around code that modifies an
+ * NFS file's size. In order to avoid deadlocks the lock
+ * should not be obtained while other locks are being held.
+ */
+
+static __inline
+int
+nfs_rslock(struct nfsnode *np, struct proc *p)
+{
+ return(lockmgr(&np->n_rslock, LK_EXCLUSIVE | LK_CANRECURSE | LK_SLEEPFAIL, NULL, p));
+}
+
+static __inline
+void
+nfs_rsunlock(struct nfsnode *np, struct proc *p)
+{
+ (void)lockmgr(&np->n_rslock, LK_RELEASE, NULL, p);
+}
+
extern vop_t **fifo_nfsv2nodeop_p;
extern vop_t **nfsv2_vnodeop_p;
extern vop_t **spec_nfsv2nodeop_p;
OpenPOWER on IntegriCloud