Skip to content

Commit

Permalink
NFSv4: Fix open_to_lock_owner sequenceid allocation...
Browse files Browse the repository at this point in the history
NFSv4 file locking is currently completely broken since it doesn't respect
the OPEN sequencing when it is given an unconfirmed lock_owner and needs to
do an open_to_lock_owner. Worse: it breaks the sunrpc rules by doing a
GFP_KERNEL allocation inside an rpciod callback.

Fix is to preallocate the open seqid structure in nfs4_alloc_lockdata if we
see that the lock_owner is unconfirmed.
Then, in nfs4_lock_prepare() we wait for either the open_seqid, if
the lock_owner is still unconfirmed, or else fall back to waiting on the
standard lock_seqid.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed Jan 3, 2008
1 parent bb22629 commit e6e2197
Showing 1 changed file with 19 additions and 11 deletions.
30 changes: 19 additions & 11 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3331,6 +3331,12 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,

p->arg.fh = NFS_FH(inode);
p->arg.fl = &p->fl;
if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) {
p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid);
if (p->arg.open_seqid == NULL)
goto out_free;

}
p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid);
if (p->arg.lock_seqid == NULL)
goto out_free;
Expand All @@ -3343,6 +3349,8 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
memcpy(&p->fl, fl, sizeof(p->fl));
return p;
out_free:
if (p->arg.open_seqid != NULL)
nfs_free_seqid(p->arg.open_seqid);
kfree(p);
return NULL;
}
Expand All @@ -3359,23 +3367,23 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
.rpc_cred = sp->so_cred,
};

if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
return;
dprintk("%s: begin!\n", __FUNCTION__);
/* Do we need to do an open_to_lock_owner? */
if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
data->arg.open_seqid = nfs_alloc_seqid(&sp->so_seqid);
if (data->arg.open_seqid == NULL) {
data->rpc_status = -ENOMEM;
task->tk_action = NULL;
goto out;
}
if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0)
return;
data->arg.open_stateid = &state->stateid;
data->arg.new_lock_owner = 1;
/* Retest in case we raced... */
if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED))
goto do_rpc;
}
if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
return;
data->arg.new_lock_owner = 0;
do_rpc:
data->timestamp = jiffies;
rpc_call_setup(task, &msg, 0);
out:
dprintk("%s: done!, ret = %d\n", __FUNCTION__, data->rpc_status);
}

Expand Down Expand Up @@ -3411,8 +3419,6 @@ static void nfs4_lock_release(void *calldata)
struct nfs4_lockdata *data = calldata;

dprintk("%s: begin!\n", __FUNCTION__);
if (data->arg.open_seqid != NULL)
nfs_free_seqid(data->arg.open_seqid);
if (data->cancelled != 0) {
struct rpc_task *task;
task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
Expand All @@ -3422,6 +3428,8 @@ static void nfs4_lock_release(void *calldata)
dprintk("%s: cancelling lock!\n", __FUNCTION__);
} else
nfs_free_seqid(data->arg.lock_seqid);
if (data->arg.open_seqid != NULL)
nfs_free_seqid(data->arg.open_seqid);
nfs4_put_lock_state(data->lsp);
put_nfs_open_context(data->ctx);
kfree(data);
Expand Down

0 comments on commit e6e2197

Please sign in to comment.