linux-nfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] nfs4: file locking fixes and cleanups
@ 2014-04-23 18:24 Jeff Layton
  2014-04-23 18:24 ` [PATCH 1/3] nfs4: treat lock owners as opaque values Jeff Layton
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Jeff Layton @ 2014-04-23 18:24 UTC (permalink / raw)
  To: trond.myklebust; +Cc: linux-nfs

The impetus for this set was a bug report in Fedora about "sleeping in
atomic context" warning that patch #2 fixes. While looking at that, I
noticed that a LOCKU wasn't being sent in the reproducer provided so I
tracked down and fixed that bug as well.

These are only lightly tested, and could probably use some soak time in
linux-next. Also, I'm not 100% thrilled with queueing the
free_lock_state job submission to a workqueue, but I don't see a better
way to handle it so far.

Jeff Layton (3):
  nfs4: treat lock owners as opaque values
  nfs4: queue free_lock_state job submission to nfsiod
  nfs4: turn free_lock_state into a void return operation

 fs/nfs/nfs4_fs.h   | 26 +++++++--------------
 fs/nfs/nfs4proc.c  | 14 ++++++------
 fs/nfs/nfs4state.c | 67 ++++++++++++++++++++++--------------------------------
 3 files changed, 42 insertions(+), 65 deletions(-)

-- 
1.9.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/3] nfs4: treat lock owners as opaque values
  2014-04-23 18:24 [PATCH 0/3] nfs4: file locking fixes and cleanups Jeff Layton
@ 2014-04-23 18:24 ` Jeff Layton
  2014-04-23 18:48   ` Trond Myklebust
  2014-04-23 18:24 ` [PATCH 2/3] nfs4: queue free_lock_state job submission to nfsiod Jeff Layton
  2014-04-23 18:25 ` [PATCH 3/3] nfs4: turn free_lock_state into a void return operation Jeff Layton
  2 siblings, 1 reply; 7+ messages in thread
From: Jeff Layton @ 2014-04-23 18:24 UTC (permalink / raw)
  To: trond.myklebust; +Cc: linux-nfs

Do the following set of ops with a file on a NFSv4 mount:

    exec 3>>$1
    flock -x 3
    exec 3>&-

You'll see the LOCK request go across the wire, but no LOCKU when the
file is closed. This leads to

What happens is that the fd is passed across a fork, and the final close
is done in a different process than the opener. That makes
__nfs4_find_lock_state miss finding the correct lock state because it
uses the fl_pid as a search key. A new one is created, and the locking
code treats it as a delegation stateid (because NFS_LOCK_INITIALIZED
isn't set).

The root cause of this breakage seems to be commit 77041ed9b49a9e
(NFSv4: Ensure the lockowners are labelled using the fl_owner and/or
fl_pid).

That changed it so that flock lockowners are allocated based on the
fl_pid. I think this is incorrect. flock locks should be "owned" by the
struct file, and that is already accounted for in the fl_owner field of
the lock request when the vfs layer passes it down.

This patch basically reverts the above commit and with it, a LOCKU is
sent in the above reproducer.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/nfs/nfs4_fs.h   | 13 +------------
 fs/nfs/nfs4state.c | 43 +++++++++----------------------------------
 2 files changed, 10 insertions(+), 46 deletions(-)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index e1d1badbe53c..3888dd0b43a1 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -129,17 +129,6 @@ enum {
  * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN)
  */
 
-struct nfs4_lock_owner {
-	unsigned int lo_type;
-#define NFS4_ANY_LOCK_TYPE	(0U)
-#define NFS4_FLOCK_LOCK_TYPE	(1U << 0)
-#define NFS4_POSIX_LOCK_TYPE	(1U << 1)
-	union {
-		fl_owner_t posix_owner;
-		pid_t flock_owner;
-	} lo_u;
-};
-
 struct nfs4_lock_state {
 	struct list_head	ls_locks;	/* Other lock stateids */
 	struct nfs4_state *	ls_state;	/* Pointer to open state */
@@ -149,7 +138,7 @@ struct nfs4_lock_state {
 	struct nfs_seqid_counter	ls_seqid;
 	nfs4_stateid		ls_stateid;
 	atomic_t		ls_count;
-	struct nfs4_lock_owner	ls_owner;
+	fl_owner_t		ls_owner;
 };
 
 /* bits for nfs4_state->flags */
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 2349518eef2c..102cd4b4f07e 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -787,21 +787,12 @@ void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
  * that is compatible with current->files
  */
 static struct nfs4_lock_state *
-__nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type)
+__nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid)
 {
 	struct nfs4_lock_state *pos;
 	list_for_each_entry(pos, &state->lock_states, ls_locks) {
-		if (type != NFS4_ANY_LOCK_TYPE && pos->ls_owner.lo_type != type)
+		if (pos->ls_owner != fl_owner)
 			continue;
-		switch (pos->ls_owner.lo_type) {
-		case NFS4_POSIX_LOCK_TYPE:
-			if (pos->ls_owner.lo_u.posix_owner != fl_owner)
-				continue;
-			break;
-		case NFS4_FLOCK_LOCK_TYPE:
-			if (pos->ls_owner.lo_u.flock_owner != fl_pid)
-				continue;
-		}
 		atomic_inc(&pos->ls_count);
 		return pos;
 	}
@@ -813,7 +804,7 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_p
  * exists, return an uninitialized one.
  *
  */
-static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type)
+static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid)
 {
 	struct nfs4_lock_state *lsp;
 	struct nfs_server *server = state->owner->so_server;
@@ -824,17 +815,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
 	nfs4_init_seqid_counter(&lsp->ls_seqid);
 	atomic_set(&lsp->ls_count, 1);
 	lsp->ls_state = state;
-	lsp->ls_owner.lo_type = type;
-	switch (lsp->ls_owner.lo_type) {
-	case NFS4_FLOCK_LOCK_TYPE:
-		lsp->ls_owner.lo_u.flock_owner = fl_pid;
-		break;
-	case NFS4_POSIX_LOCK_TYPE:
-		lsp->ls_owner.lo_u.posix_owner = fl_owner;
-		break;
-	default:
-		goto out_free;
-	}
+	lsp->ls_owner = fl_owner;
 	lsp->ls_seqid.owner_id = ida_simple_get(&server->lockowner_id, 0, 0, GFP_NOFS);
 	if (lsp->ls_seqid.owner_id < 0)
 		goto out_free;
@@ -857,13 +838,13 @@ void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp
  * exists, return an uninitialized one.
  *
  */
-static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner, pid_t pid, unsigned int type)
+static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner, pid_t pid)
 {
 	struct nfs4_lock_state *lsp, *new = NULL;
 	
 	for(;;) {
 		spin_lock(&state->state_lock);
-		lsp = __nfs4_find_lock_state(state, owner, pid, type);
+		lsp = __nfs4_find_lock_state(state, owner, pid);
 		if (lsp != NULL)
 			break;
 		if (new != NULL) {
@@ -874,7 +855,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_
 			break;
 		}
 		spin_unlock(&state->state_lock);
-		new = nfs4_alloc_lock_state(state, owner, pid, type);
+		new = nfs4_alloc_lock_state(state, owner, pid);
 		if (new == NULL)
 			return NULL;
 	}
@@ -935,13 +916,7 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
 
 	if (fl->fl_ops != NULL)
 		return 0;
-	if (fl->fl_flags & FL_POSIX)
-		lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE);
-	else if (fl->fl_flags & FL_FLOCK)
-		lsp = nfs4_get_lock_state(state, NULL, fl->fl_pid,
-				NFS4_FLOCK_LOCK_TYPE);
-	else
-		return -EINVAL;
+	lsp = nfs4_get_lock_state(state, fl->fl_owner, 0);
 	if (lsp == NULL)
 		return -ENOMEM;
 	fl->fl_u.nfs4_fl.owner = lsp;
@@ -968,7 +943,7 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
 	fl_owner = lockowner->l_owner;
 	fl_pid = lockowner->l_pid;
 	spin_lock(&state->state_lock);
-	lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
+	lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid);
 	if (lsp && test_bit(NFS_LOCK_LOST, &lsp->ls_flags))
 		ret = -EIO;
 	else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/3] nfs4: queue free_lock_state job submission to nfsiod
  2014-04-23 18:24 [PATCH 0/3] nfs4: file locking fixes and cleanups Jeff Layton
  2014-04-23 18:24 ` [PATCH 1/3] nfs4: treat lock owners as opaque values Jeff Layton
@ 2014-04-23 18:24 ` Jeff Layton
  2014-04-23 18:25 ` [PATCH 3/3] nfs4: turn free_lock_state into a void return operation Jeff Layton
  2 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2014-04-23 18:24 UTC (permalink / raw)
  To: trond.myklebust; +Cc: linux-nfs

We got a report of the following warning in Fedora:

BUG: sleeping function called from invalid context at mm/slub.c:969
in_atomic(): 1, irqs_disabled(): 0, pid: 533, name: bash
3 locks held by bash/533:
 #0:  (&sp->so_delegreturn_mutex){+.+...}, at: [<ffffffffa033da62>] nfs4_proc_lock+0x262/0x910 [nfsv4]
 #1:  (&nfsi->rwsem){.+.+.+}, at: [<ffffffffa033da6a>] nfs4_proc_lock+0x26a/0x910 [nfsv4]
 #2:  (&sb->s_type->i_lock_key#23){+.+...}, at: [<ffffffff812998dc>] flock_lock_file_wait+0x8c/0x3a0
CPU: 0 PID: 533 Comm: bash Not tainted 3.15.0-0.rc1.git1.1.fc21.x86_64 #1
Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
 0000000000000000 00000000d664ff3c ffff880078b69a70 ffffffff817e82e0
 0000000000000000 ffff880078b69a98 ffffffff810cf1a4 0000000000000050
 0000000000000050 ffff88007cc01a00 ffff880078b69ad8 ffffffff8121449e
Call Trace:
 [<ffffffff817e82e0>] dump_stack+0x4d/0x66
 [<ffffffff810cf1a4>] __might_sleep+0x184/0x240
 [<ffffffff8121449e>] kmem_cache_alloc_trace+0x4e/0x330
 [<ffffffffa0331124>] ? nfs4_release_lockowner+0x74/0x110 [nfsv4]
 [<ffffffffa0331124>] nfs4_release_lockowner+0x74/0x110 [nfsv4]
 [<ffffffffa0352340>] nfs4_put_lock_state+0x90/0xb0 [nfsv4]
 [<ffffffffa0352375>] nfs4_fl_release_lock+0x15/0x20 [nfsv4]
 [<ffffffff81297515>] locks_free_lock+0x45/0x90
 [<ffffffff8129996c>] flock_lock_file_wait+0x11c/0x3a0
 [<ffffffffa033da6a>] ? nfs4_proc_lock+0x26a/0x910 [nfsv4]
 [<ffffffffa033301e>] do_vfs_lock+0x1e/0x30 [nfsv4]
 [<ffffffffa033da79>] nfs4_proc_lock+0x279/0x910 [nfsv4]
 [<ffffffff810dbb26>] ? local_clock+0x16/0x30
 [<ffffffff810f5a3f>] ? lock_release_holdtime.part.28+0xf/0x200
 [<ffffffffa02f820c>] do_unlk+0x8c/0xc0 [nfs]
 [<ffffffffa02f85c5>] nfs_flock+0xa5/0xf0 [nfs]
 [<ffffffff8129a6f6>] locks_remove_file+0xb6/0x1e0
 [<ffffffff812159d8>] ? kfree+0xd8/0x2d0
 [<ffffffff8123bc63>] __fput+0xd3/0x210
 [<ffffffff8123bdee>] ____fput+0xe/0x10
 [<ffffffff810bfb6d>] task_work_run+0xcd/0xf0
 [<ffffffff81019cd1>] do_notify_resume+0x61/0x90
 [<ffffffff817fbea2>] int_signal+0x12/0x17

The problem is that NFSv4 is trying to do an allocation from
fl_release_private (in order to send a RELEASE_LOCKOWNER call). That
function can be called while holding the inode->i_lock, and it's
currently set up to do __GFP_WAIT allocations. v4.1 code has a
similar problem.

This patch adds a work_struct to the nfs4_lock_state and has the code
queue the free_lock_state operation to nfsiod.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/nfs/nfs4_fs.h   | 13 +++++++------
 fs/nfs/nfs4state.c | 24 ++++++++++++++++++------
 2 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 3888dd0b43a1..75aadf8c0429 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -130,15 +130,16 @@ enum {
  */
 
 struct nfs4_lock_state {
-	struct list_head	ls_locks;	/* Other lock stateids */
-	struct nfs4_state *	ls_state;	/* Pointer to open state */
+	struct list_head		ls_locks;   /* Other lock stateids */
+	struct nfs4_state *		ls_state;   /* Pointer to open state */
 #define NFS_LOCK_INITIALIZED 0
 #define NFS_LOCK_LOST        1
-	unsigned long		ls_flags;
+	unsigned long			ls_flags;
 	struct nfs_seqid_counter	ls_seqid;
-	nfs4_stateid		ls_stateid;
-	atomic_t		ls_count;
-	fl_owner_t		ls_owner;
+	nfs4_stateid			ls_stateid;
+	atomic_t			ls_count;
+	fl_owner_t			ls_owner;
+	struct work_struct		ls_release;
 };
 
 /* bits for nfs4_state->flags */
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 102cd4b4f07e..7b0b113e3c37 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -799,6 +799,18 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_p
 	return NULL;
 }
 
+static void
+free_lock_state_work(struct work_struct *work)
+{
+	struct nfs4_lock_state *lsp = container_of(work,
+					struct nfs4_lock_state, ls_release);
+	struct nfs4_state *state = lsp->ls_state;
+	struct nfs_server *server = state->owner->so_server;
+	struct nfs_client *clp = server->nfs_client;
+
+	clp->cl_mvops->free_lock_state(server, lsp);
+}
+
 /*
  * Return a compatible lock_state. If no initialized lock_state structure
  * exists, return an uninitialized one.
@@ -820,6 +832,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
 	if (lsp->ls_seqid.owner_id < 0)
 		goto out_free;
 	INIT_LIST_HEAD(&lsp->ls_locks);
+	INIT_WORK(&lsp->ls_release, free_lock_state_work);
 	return lsp;
 out_free:
 	kfree(lsp);
@@ -883,13 +896,12 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
 	if (list_empty(&state->lock_states))
 		clear_bit(LK_STATE_IN_USE, &state->flags);
 	spin_unlock(&state->state_lock);
-	server = state->owner->so_server;
-	if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
-		struct nfs_client *clp = server->nfs_client;
-
-		clp->cl_mvops->free_lock_state(server, lsp);
-	} else
+	if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags))
+		queue_work(nfsiod_workqueue, &lsp->ls_release);
+	else {
+		server = state->owner->so_server;
 		nfs4_free_lock_state(server, lsp);
+	}
 }
 
 static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/3] nfs4: turn free_lock_state into a void return operation
  2014-04-23 18:24 [PATCH 0/3] nfs4: file locking fixes and cleanups Jeff Layton
  2014-04-23 18:24 ` [PATCH 1/3] nfs4: treat lock owners as opaque values Jeff Layton
  2014-04-23 18:24 ` [PATCH 2/3] nfs4: queue free_lock_state job submission to nfsiod Jeff Layton
@ 2014-04-23 18:25 ` Jeff Layton
  2 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2014-04-23 18:25 UTC (permalink / raw)
  To: trond.myklebust; +Cc: linux-nfs

Nothing checks its return value, and these calls are generally
best-effort anyway.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/nfs/nfs4_fs.h  |  2 +-
 fs/nfs/nfs4proc.c | 14 +++++++-------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 75aadf8c0429..f495ff306c4f 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -54,7 +54,7 @@ struct nfs4_minor_version_ops {
 			const nfs4_stateid *);
 	int	(*find_root_sec)(struct nfs_server *, struct nfs_fh *,
 			struct nfs_fsinfo *);
-	int	(*free_lock_state)(struct nfs_server *,
+	void	(*free_lock_state)(struct nfs_server *,
 			struct nfs4_lock_state *);
 	const struct rpc_call_ops *call_sync_ops;
 	const struct nfs4_state_recovery_ops *reboot_recovery_ops;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index cc6c3fe3e060..06c1e9e777ab 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -5915,7 +5915,8 @@ static const struct rpc_call_ops nfs4_release_lockowner_ops = {
 	.rpc_release = nfs4_release_lockowner_release,
 };
 
-static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp)
+static void
+nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp)
 {
 	struct nfs_release_lockowner_data *data;
 	struct rpc_message msg = {
@@ -5923,11 +5924,11 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
 	};
 
 	if (server->nfs_client->cl_mvops->minor_version != 0)
-		return -EINVAL;
+		return;
 
 	data = kmalloc(sizeof(*data), GFP_NOFS);
 	if (!data)
-		return -ENOMEM;
+		return;
 	data->lsp = lsp;
 	data->server = server;
 	data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
@@ -5938,7 +5939,6 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
 	msg.rpc_resp = &data->res;
 	nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
 	rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
-	return 0;
 }
 
 #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
@@ -8225,7 +8225,8 @@ static int nfs41_free_stateid(struct nfs_server *server,
 	return ret;
 }
 
-static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
+static void
+nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
 {
 	struct rpc_task *task;
 	struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
@@ -8233,9 +8234,8 @@ static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_sta
 	task = _nfs41_free_stateid(server, &lsp->ls_stateid, cred, false);
 	nfs4_free_lock_state(server, lsp);
 	if (IS_ERR(task))
-		return PTR_ERR(task);
+		return;
 	rpc_put_task(task);
-	return 0;
 }
 
 static bool nfs41_match_stateid(const nfs4_stateid *s1,
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] nfs4: treat lock owners as opaque values
  2014-04-23 18:24 ` [PATCH 1/3] nfs4: treat lock owners as opaque values Jeff Layton
@ 2014-04-23 18:48   ` Trond Myklebust
  2014-04-23 19:00     ` Jeff Layton
  0 siblings, 1 reply; 7+ messages in thread
From: Trond Myklebust @ 2014-04-23 18:48 UTC (permalink / raw)
  To: Layton Jeff; +Cc: linux-nfs


On Apr 23, 2014, at 14:24, Jeff Layton <jlayton@redhat.com> wrote:

> Do the following set of ops with a file on a NFSv4 mount:
> 
>    exec 3>>$1
>    flock -x 3
>    exec 3>&-
> 
> You'll see the LOCK request go across the wire, but no LOCKU when the
> file is closed. This leads to
> 
> What happens is that the fd is passed across a fork, and the final close
> is done in a different process than the opener. That makes
> __nfs4_find_lock_state miss finding the correct lock state because it
> uses the fl_pid as a search key. A new one is created, and the locking
> code treats it as a delegation stateid (because NFS_LOCK_INITIALIZED
> isn't set).
> 
> The root cause of this breakage seems to be commit 77041ed9b49a9e
> (NFSv4: Ensure the lockowners are labelled using the fl_owner and/or
> fl_pid).
> 
> That changed it so that flock lockowners are allocated based on the
> fl_pid. I think this is incorrect. flock locks should be "owned" by the
> struct file, and that is already accounted for in the fl_owner field of
> the lock request when the vfs layer passes it down.

NACKed for now.

I'll grant you that there are several nice potential cleanups here, but as far as I can tell, flock_make_lock() never sets fl_owner, and neither does anything else in sys_flock().

_________________________________
Trond Myklebust
Linux NFS client maintainer, PrimaryData
trond.myklebust@primarydata.com


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] nfs4: treat lock owners as opaque values
  2014-04-23 18:48   ` Trond Myklebust
@ 2014-04-23 19:00     ` Jeff Layton
  2014-04-24 14:25       ` Jeff Layton
  0 siblings, 1 reply; 7+ messages in thread
From: Jeff Layton @ 2014-04-23 19:00 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Wed, 23 Apr 2014 14:48:08 -0400
Trond Myklebust <trond.myklebust@primarydata.com> wrote:

> 
> On Apr 23, 2014, at 14:24, Jeff Layton <jlayton@redhat.com> wrote:
> 
> > Do the following set of ops with a file on a NFSv4 mount:
> > 
> >    exec 3>>$1
> >    flock -x 3
> >    exec 3>&-
> > 
> > You'll see the LOCK request go across the wire, but no LOCKU when the
> > file is closed. This leads to
> > 
> > What happens is that the fd is passed across a fork, and the final close
> > is done in a different process than the opener. That makes
> > __nfs4_find_lock_state miss finding the correct lock state because it
> > uses the fl_pid as a search key. A new one is created, and the locking
> > code treats it as a delegation stateid (because NFS_LOCK_INITIALIZED
> > isn't set).
> > 
> > The root cause of this breakage seems to be commit 77041ed9b49a9e
> > (NFSv4: Ensure the lockowners are labelled using the fl_owner and/or
> > fl_pid).
> > 
> > That changed it so that flock lockowners are allocated based on the
> > fl_pid. I think this is incorrect. flock locks should be "owned" by the
> > struct file, and that is already accounted for in the fl_owner field of
> > the lock request when the vfs layer passes it down.
> 
> NACKed for now.
> 
> I'll grant you that there are several nice potential cleanups here, but as far as I can tell, flock_make_lock() never sets fl_owner, and neither does anything else in sys_flock().
> 

Ahh right...nfs_flock is what sets that currently. So this patch *does*
work, but I think you're right that we ought to have the generic flock
codepath universally set fl_owner instead.

I'll see if I can make that a bit more consistent for v3.16 and then we
can revisit this one.

Thanks,
-- 
Jeff Layton <jlayton@redhat.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] nfs4: treat lock owners as opaque values
  2014-04-23 19:00     ` Jeff Layton
@ 2014-04-24 14:25       ` Jeff Layton
  0 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2014-04-24 14:25 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Wed, 23 Apr 2014 15:00:23 -0400
Jeff Layton <jlayton@redhat.com> wrote:

> On Wed, 23 Apr 2014 14:48:08 -0400
> Trond Myklebust <trond.myklebust@primarydata.com> wrote:
> 
> > 
> > On Apr 23, 2014, at 14:24, Jeff Layton <jlayton@redhat.com> wrote:
> > 
> > > Do the following set of ops with a file on a NFSv4 mount:
> > > 
> > >    exec 3>>$1
> > >    flock -x 3
> > >    exec 3>&-
> > > 
> > > You'll see the LOCK request go across the wire, but no LOCKU when the
> > > file is closed. This leads to
> > > 
> > > What happens is that the fd is passed across a fork, and the final close
> > > is done in a different process than the opener. That makes
> > > __nfs4_find_lock_state miss finding the correct lock state because it
> > > uses the fl_pid as a search key. A new one is created, and the locking
> > > code treats it as a delegation stateid (because NFS_LOCK_INITIALIZED
> > > isn't set).
> > > 
> > > The root cause of this breakage seems to be commit 77041ed9b49a9e
> > > (NFSv4: Ensure the lockowners are labelled using the fl_owner and/or
> > > fl_pid).
> > > 
> > > That changed it so that flock lockowners are allocated based on the
> > > fl_pid. I think this is incorrect. flock locks should be "owned" by the
> > > struct file, and that is already accounted for in the fl_owner field of
> > > the lock request when the vfs layer passes it down.
> > 
> > NACKed for now.
> > 
> > I'll grant you that there are several nice potential cleanups here, but as far as I can tell, flock_make_lock() never sets fl_owner, and neither does anything else in sys_flock().
> > 
> 
> Ahh right...nfs_flock is what sets that currently. So this patch *does*
> work, but I think you're right that we ought to have the generic flock
> codepath universally set fl_owner instead.
> 
> I'll see if I can make that a bit more consistent for v3.16 and then we
> can revisit this one.
> 

BTW, any thoughts on the second patch in this series? It's not really
dependent on the first, and it does fix a bug where we're trying to do
a __GFP_WAIT allocation under a spinlock.

Thanks,
-- 
Jeff Layton <jlayton@poochiereds.net>

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2014-04-24 14:33 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-04-23 18:24 [PATCH 0/3] nfs4: file locking fixes and cleanups Jeff Layton
2014-04-23 18:24 ` [PATCH 1/3] nfs4: treat lock owners as opaque values Jeff Layton
2014-04-23 18:48   ` Trond Myklebust
2014-04-23 19:00     ` Jeff Layton
2014-04-24 14:25       ` Jeff Layton
2014-04-23 18:24 ` [PATCH 2/3] nfs4: queue free_lock_state job submission to nfsiod Jeff Layton
2014-04-23 18:25 ` [PATCH 3/3] nfs4: turn free_lock_state into a void return operation Jeff Layton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).