Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8bda4e4c authored by Trond Myklebust's avatar Trond Myklebust
Browse files

NFSv4: Fix up stateid locking...



We really don't need to grab both the state->so_owner and the
inode->i_lock.

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 1ac7e2fd
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -139,9 +139,11 @@ struct nfs4_state {
	unsigned long flags;		/* Do we hold any locks? */
	spinlock_t state_lock;		/* Protects the lock_states list */

	seqlock_t seqlock;		/* Protects the stateid/open_stateid */
	nfs4_stateid stateid;		/* Current stateid: may be delegation */
	nfs4_stateid open_stateid;	/* OPEN stateid */

	/* The following 3 fields are protected by owner->so_lock */
	unsigned int n_rdonly;		/* Number of read-only references */
	unsigned int n_wronly;		/* Number of write-only references */
	unsigned int n_rdwr;		/* Number of read/write references */
+11 −16
Original line number Diff line number Diff line
@@ -385,29 +385,28 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *

static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
{
	spin_lock(&state->owner->so_lock);
	spin_lock(&state->inode->i_lock);
	write_seqlock(&state->seqlock);
	nfs_set_open_stateid_locked(state, stateid, open_flags);
	spin_unlock(&state->inode->i_lock);
	spin_unlock(&state->owner->so_lock);
	write_sequnlock(&state->seqlock);
}

static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags)
{
	struct inode *inode = state->inode;

	open_flags &= (FMODE_READ|FMODE_WRITE);
	/* Protect against nfs4_find_state_byowner() */
	spin_lock(&state->owner->so_lock);
	spin_lock(&inode->i_lock);
	/*
	 * Protect the call to nfs4_state_set_mode_locked and
	 * serialise the stateid update
	 */
	write_seqlock(&state->seqlock);
	if (deleg_stateid != NULL) {
		memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data));
		set_bit(NFS_DELEGATED_STATE, &state->flags);
	}
	if (open_stateid != NULL)
		nfs_set_open_stateid_locked(state, open_stateid, open_flags);
	write_sequnlock(&state->seqlock);
	spin_lock(&state->owner->so_lock);
	update_open_stateflags(state, open_flags);
	spin_unlock(&inode->i_lock);
	spin_unlock(&state->owner->so_lock);
}

@@ -608,12 +607,10 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
	 */
	if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 &&
	    memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) {
		spin_lock(&state->owner->so_lock);
		spin_lock(&state->inode->i_lock);
		write_seqlock(&state->seqlock);
		if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
			memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data));
		spin_unlock(&state->inode->i_lock);
		spin_unlock(&state->owner->so_lock);
		write_sequnlock(&state->seqlock);
	}
	return 0;
}
@@ -1280,7 +1277,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
	mode = FMODE_READ|FMODE_WRITE;
	clear_rd = clear_wr = clear_rdwr = 0;
	spin_lock(&state->owner->so_lock);
	spin_lock(&calldata->inode->i_lock);
	/* Calculate the change in open mode */
	if (state->n_rdwr == 0) {
		if (state->n_rdonly == 0) {
@@ -1294,7 +1290,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
			clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);
		}
	}
	spin_unlock(&calldata->inode->i_lock);
	spin_unlock(&state->owner->so_lock);
	if (!clear_rd && !clear_wr && !clear_rdwr) {
		/* Note: exit _without_ calling nfs4_close_done */
+6 −4
Original line number Diff line number Diff line
@@ -307,6 +307,7 @@ nfs4_alloc_open_state(void)
	atomic_set(&state->count, 1);
	INIT_LIST_HEAD(&state->lock_states);
	spin_lock_init(&state->state_lock);
	seqlock_init(&state->seqlock);
	return state;
}

@@ -411,7 +412,6 @@ void nfs4_put_open_state(struct nfs4_state *state)
 */
void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
{
	struct inode *inode = state->inode;
	struct nfs4_state_owner *owner = state->owner;
	int call_close = 0;
	int newstate;
@@ -419,7 +419,6 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
	atomic_inc(&owner->so_count);
	/* Protect against nfs4_find_state() */
	spin_lock(&owner->so_lock);
	spin_lock(&inode->i_lock);
	switch (mode & (FMODE_READ | FMODE_WRITE)) {
		case FMODE_READ:
			state->n_rdonly--;
@@ -446,7 +445,6 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
			clear_bit(NFS_DELEGATED_STATE, &state->flags);
	}
	nfs4_state_set_mode_locked(state, newstate);
	spin_unlock(&inode->i_lock);
	spin_unlock(&owner->so_lock);

	if (!call_close) {
@@ -599,8 +597,12 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner)
{
	struct nfs4_lock_state *lsp;
	int seq;

	do {
		seq = read_seqbegin(&state->seqlock);
		memcpy(dst, &state->stateid, sizeof(*dst));
	} while (read_seqretry(&state->seqlock, seq));
	if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
		return;