Fix a LOR in the NFS client which could cause a deadlock.
This was reported to the mailing list freebsd-net@freebsd.org on July 21, 2011 under the subject "LOR with nfsclient sillyrename". The LOR occurred when nfs_inactive() called vrele(sp->s_dvp) while holding the vnode lock on the file in s_dvp. This patch modifies the client so that it performs the vrele(sp->s_dvp) as a separate task to avoid the LOR. This fix was discussed with jhb@ and kib@, who both proposed variations of it. Tested by: pho, jlott at averesystems.com Submitted by: jhb (earlier version) Reviewed by: kib Approved by: re (kib) MFC after: 2 weeks
This commit is contained in:
parent
df6f430410
commit
e498ea9037
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=224604
@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/proc.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/taskqueue.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <vm/uma.h>
|
||||
@ -59,6 +60,8 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
static uma_zone_t nfsnode_zone;
|
||||
|
||||
static void nfs_freesillyrename(void *arg, __unused int pending);
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
@ -185,6 +188,20 @@ nfs_nget(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp, int
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the vrele(sp->s_dvp) as a separate task in order to avoid a
|
||||
* deadlock because of a LOR when vrele() locks the directory vnode.
|
||||
*/
|
||||
static void
|
||||
nfs_freesillyrename(void *arg, __unused int pending)
|
||||
{
|
||||
struct sillyrename *sp;
|
||||
|
||||
sp = arg;
|
||||
vrele(sp->s_dvp);
|
||||
free(sp, M_NFSREQ);
|
||||
}
|
||||
|
||||
int
|
||||
nfs_inactive(struct vop_inactive_args *ap)
|
||||
{
|
||||
@ -207,8 +224,8 @@ nfs_inactive(struct vop_inactive_args *ap)
|
||||
*/
|
||||
(sp->s_removeit)(sp);
|
||||
crfree(sp->s_cred);
|
||||
vrele(sp->s_dvp);
|
||||
free((caddr_t)sp, M_NFSREQ);
|
||||
TASK_INIT(&sp->s_task, 0, nfs_freesillyrename, sp);
|
||||
taskqueue_enqueue(taskqueue_thread, &sp->s_task);
|
||||
mtx_lock(&np->n_mtx);
|
||||
}
|
||||
np->n_flag &= NMODIFIED;
|
||||
|
@ -36,6 +36,7 @@
|
||||
#ifndef _NFSCLIENT_NFSNODE_H_
|
||||
#define _NFSCLIENT_NFSNODE_H_
|
||||
|
||||
#include <sys/_task.h>
|
||||
#if !defined(_NFSCLIENT_NFS_H_) && !defined(_KERNEL)
|
||||
#include <nfs/nfs.h>
|
||||
#endif
|
||||
@ -45,6 +46,7 @@
|
||||
* can be removed by nfs_inactive()
|
||||
*/
|
||||
struct sillyrename {
|
||||
struct task s_task;
|
||||
struct ucred *s_cred;
|
||||
struct vnode *s_dvp;
|
||||
int (*s_removeit)(struct sillyrename *sp);
|
||||
|
Loading…
Reference in New Issue
Block a user