aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-05 18:07:55 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-10 23:40:41 -0400
commit003707c7225dbd4bf879b6c204743554de0a08d6 (patch)
treeb5ca79744badf011d15111d819f629cfc69452ba /fs/nfs
parent0f9f95e0ad1f9d07d77832c5b60f7d30440602ee (diff)
NFSv4: Always use the delegation if we have one
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4_fs.h14
-rw-r--r--fs/nfs/nfs4proc.c88
-rw-r--r--fs/nfs/nfs4state.c28
3 files changed, 94 insertions, 36 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 44b56c915f72..4a1c4d80a577 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -122,7 +122,10 @@ struct nfs4_lock_state {
122/* bits for nfs4_state->flags */ 122/* bits for nfs4_state->flags */
123enum { 123enum {
124 LK_STATE_IN_USE, 124 LK_STATE_IN_USE,
125 NFS_DELEGATED_STATE, 125 NFS_DELEGATED_STATE, /* Current stateid is delegation */
126 NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */
127 NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */
128 NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */
126}; 129};
127 130
128struct nfs4_state { 131struct nfs4_state {
@@ -136,11 +139,12 @@ struct nfs4_state {
136 unsigned long flags; /* Do we hold any locks? */ 139 unsigned long flags; /* Do we hold any locks? */
137 spinlock_t state_lock; /* Protects the lock_states list */ 140 spinlock_t state_lock; /* Protects the lock_states list */
138 141
139 nfs4_stateid stateid; 142 nfs4_stateid stateid; /* Current stateid: may be delegation */
143 nfs4_stateid open_stateid; /* OPEN stateid */
140 144
141 unsigned int n_rdonly; 145 unsigned int n_rdonly; /* Number of read-only references */
142 unsigned int n_wronly; 146 unsigned int n_wronly; /* Number of write-only references */
143 unsigned int n_rdwr; 147 unsigned int n_rdwr; /* Number of read/write references */
144 int state; /* State on the server (R,W, or RW) */ 148 int state; /* State on the server (R,W, or RW) */
145 atomic_t count; 149 atomic_t count;
146}; 150};
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 61ba32af4d2f..128fe23d3f1e 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -319,7 +319,7 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task)
319 return ret; 319 return ret;
320} 320}
321 321
322static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) 322static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags)
323{ 323{
324 switch (open_flags) { 324 switch (open_flags) {
325 case FMODE_WRITE: 325 case FMODE_WRITE:
@@ -331,9 +331,36 @@ static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_
331 case FMODE_READ|FMODE_WRITE: 331 case FMODE_READ|FMODE_WRITE:
332 state->n_rdwr++; 332 state->n_rdwr++;
333 } 333 }
334 nfs4_state_set_mode_locked(state, state->state | open_flags);
335}
336
337static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
338{
339 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
340 memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data));
341 memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data));
342 switch (open_flags) {
343 case FMODE_READ:
344 set_bit(NFS_O_RDONLY_STATE, &state->flags);
345 break;
346 case FMODE_WRITE:
347 set_bit(NFS_O_WRONLY_STATE, &state->flags);
348 break;
349 case FMODE_READ|FMODE_WRITE:
350 set_bit(NFS_O_RDWR_STATE, &state->flags);
351 }
334} 352}
335 353
336static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) 354static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
355{
356 spin_lock(&state->owner->so_lock);
357 spin_lock(&state->inode->i_lock);
358 nfs_set_open_stateid_locked(state, stateid, open_flags);
359 spin_unlock(&state->inode->i_lock);
360 spin_unlock(&state->owner->so_lock);
361}
362
363static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags)
337{ 364{
338 struct inode *inode = state->inode; 365 struct inode *inode = state->inode;
339 366
@@ -341,9 +368,13 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid,
341 /* Protect against nfs4_find_state_byowner() */ 368 /* Protect against nfs4_find_state_byowner() */
342 spin_lock(&state->owner->so_lock); 369 spin_lock(&state->owner->so_lock);
343 spin_lock(&inode->i_lock); 370 spin_lock(&inode->i_lock);
344 memcpy(&state->stateid, stateid, sizeof(state->stateid)); 371 if (deleg_stateid != NULL) {
372 memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data));
373 set_bit(NFS_DELEGATED_STATE, &state->flags);
374 }
375 if (open_stateid != NULL)
376 nfs_set_open_stateid_locked(state, open_stateid, open_flags);
345 update_open_stateflags(state, open_flags); 377 update_open_stateflags(state, open_flags);
346 nfs4_state_set_mode_locked(state, state->state | open_flags);
347 spin_unlock(&inode->i_lock); 378 spin_unlock(&inode->i_lock);
348 spin_unlock(&state->owner->so_lock); 379 spin_unlock(&state->owner->so_lock);
349} 380}
@@ -352,6 +383,8 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
352{ 383{
353 struct inode *inode; 384 struct inode *inode;
354 struct nfs4_state *state = NULL; 385 struct nfs4_state *state = NULL;
386 struct nfs_delegation *delegation;
387 nfs4_stateid *deleg_stateid = NULL;
355 388
356 if (!(data->f_attr.valid & NFS_ATTR_FATTR)) 389 if (!(data->f_attr.valid & NFS_ATTR_FATTR))
357 goto out; 390 goto out;
@@ -361,13 +394,14 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
361 state = nfs4_get_open_state(inode, data->owner); 394 state = nfs4_get_open_state(inode, data->owner);
362 if (state == NULL) 395 if (state == NULL)
363 goto put_inode; 396 goto put_inode;
364 update_open_stateid(state, &data->o_res.stateid, data->o_arg.open_flags);
365 if (data->o_res.delegation_type != 0) { 397 if (data->o_res.delegation_type != 0) {
366 struct nfs_inode *nfsi = NFS_I(inode);
367 int delegation_flags = 0; 398 int delegation_flags = 0;
368 399
369 if (nfsi->delegation) 400 rcu_read_lock();
370 delegation_flags = nfsi->delegation->flags; 401 delegation = rcu_dereference(NFS_I(inode)->delegation);
402 if (delegation)
403 delegation_flags = delegation->flags;
404 rcu_read_unlock();
371 if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) 405 if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM))
372 nfs_inode_set_delegation(state->inode, 406 nfs_inode_set_delegation(state->inode,
373 data->owner->so_cred, 407 data->owner->so_cred,
@@ -377,6 +411,12 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
377 data->owner->so_cred, 411 data->owner->so_cred,
378 &data->o_res); 412 &data->o_res);
379 } 413 }
414 rcu_read_lock();
415 delegation = rcu_dereference(NFS_I(inode)->delegation);
416 if (delegation != NULL)
417 deleg_stateid = &delegation->stateid;
418 update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags);
419 rcu_read_unlock();
380put_inode: 420put_inode:
381 iput(inode); 421 iput(inode);
382out: 422out:
@@ -911,8 +951,7 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred
911 unlock_kernel(); 951 unlock_kernel();
912 if (err != 0) 952 if (err != 0)
913 goto out_put_open_state; 953 goto out_put_open_state;
914 set_bit(NFS_DELEGATED_STATE, &state->flags); 954 update_open_stateid(state, NULL, &delegation->stateid, open_flags);
915 update_open_stateid(state, &delegation->stateid, open_flags);
916out_ok: 955out_ok:
917 nfs4_put_state_owner(sp); 956 nfs4_put_state_owner(sp);
918 up_read(&nfsi->rwsem); 957 up_read(&nfsi->rwsem);
@@ -1149,8 +1188,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
1149 nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); 1188 nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid);
1150 switch (task->tk_status) { 1189 switch (task->tk_status) {
1151 case 0: 1190 case 0:
1152 memcpy(&state->stateid, &calldata->res.stateid, 1191 nfs_set_open_stateid(state, &calldata->res.stateid, calldata->arg.open_flags);
1153 sizeof(state->stateid));
1154 renew_lease(server, calldata->timestamp); 1192 renew_lease(server, calldata->timestamp);
1155 break; 1193 break;
1156 case -NFS4ERR_STALE_STATEID: 1194 case -NFS4ERR_STALE_STATEID:
@@ -1175,26 +1213,32 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
1175 .rpc_resp = &calldata->res, 1213 .rpc_resp = &calldata->res,
1176 .rpc_cred = state->owner->so_cred, 1214 .rpc_cred = state->owner->so_cred,
1177 }; 1215 };
1178 int mode = 0, old_mode; 1216 int clear_rd, clear_wr, clear_rdwr;
1217 int mode;
1179 1218
1180 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) 1219 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
1181 return; 1220 return;
1182 /* Recalculate the new open mode in case someone reopened the file 1221
1183 * while we were waiting in line to be scheduled. 1222 mode = FMODE_READ|FMODE_WRITE;
1184 */ 1223 clear_rd = clear_wr = clear_rdwr = 0;
1185 spin_lock(&state->owner->so_lock); 1224 spin_lock(&state->owner->so_lock);
1186 spin_lock(&calldata->inode->i_lock); 1225 spin_lock(&calldata->inode->i_lock);
1187 mode = old_mode = state->state; 1226 /* Calculate the change in open mode */
1188 if (state->n_rdwr == 0) { 1227 if (state->n_rdwr == 0) {
1189 if (state->n_rdonly == 0) 1228 if (state->n_rdonly == 0) {
1190 mode &= ~FMODE_READ; 1229 mode &= ~FMODE_READ;
1191 if (state->n_wronly == 0) 1230 clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags);
1231 clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);
1232 }
1233 if (state->n_wronly == 0) {
1192 mode &= ~FMODE_WRITE; 1234 mode &= ~FMODE_WRITE;
1235 clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags);
1236 clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);
1237 }
1193 } 1238 }
1194 nfs4_state_set_mode_locked(state, mode);
1195 spin_unlock(&calldata->inode->i_lock); 1239 spin_unlock(&calldata->inode->i_lock);
1196 spin_unlock(&state->owner->so_lock); 1240 spin_unlock(&state->owner->so_lock);
1197 if (mode == old_mode || test_bit(NFS_DELEGATED_STATE, &state->flags)) { 1241 if (!clear_rd && !clear_wr && !clear_rdwr) {
1198 /* Note: exit _without_ calling nfs4_close_done */ 1242 /* Note: exit _without_ calling nfs4_close_done */
1199 task->tk_action = NULL; 1243 task->tk_action = NULL;
1200 return; 1244 return;
@@ -1238,7 +1282,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state)
1238 calldata->inode = state->inode; 1282 calldata->inode = state->inode;
1239 calldata->state = state; 1283 calldata->state = state;
1240 calldata->arg.fh = NFS_FH(state->inode); 1284 calldata->arg.fh = NFS_FH(state->inode);
1241 calldata->arg.stateid = &state->stateid; 1285 calldata->arg.stateid = &state->open_stateid;
1242 /* Serialization for the sequence id */ 1286 /* Serialization for the sequence id */
1243 calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); 1287 calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid);
1244 if (calldata->arg.seqid == NULL) 1288 if (calldata->arg.seqid == NULL)
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index ac816b303f3a..4f78c0d1eab5 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -412,7 +412,8 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
412{ 412{
413 struct inode *inode = state->inode; 413 struct inode *inode = state->inode;
414 struct nfs4_state_owner *owner = state->owner; 414 struct nfs4_state_owner *owner = state->owner;
415 int oldstate, newstate = 0; 415 int call_close = 0;
416 int newstate;
416 417
417 atomic_inc(&owner->so_count); 418 atomic_inc(&owner->so_count);
418 /* Protect against nfs4_find_state() */ 419 /* Protect against nfs4_find_state() */
@@ -428,21 +429,26 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
428 case FMODE_READ|FMODE_WRITE: 429 case FMODE_READ|FMODE_WRITE:
429 state->n_rdwr--; 430 state->n_rdwr--;
430 } 431 }
431 oldstate = newstate = state->state; 432 newstate = FMODE_READ|FMODE_WRITE;
432 if (state->n_rdwr == 0) { 433 if (state->n_rdwr == 0) {
433 if (state->n_rdonly == 0) 434 if (state->n_rdonly == 0) {
434 newstate &= ~FMODE_READ; 435 newstate &= ~FMODE_READ;
435 if (state->n_wronly == 0) 436 call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
437 call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
438 }
439 if (state->n_wronly == 0) {
436 newstate &= ~FMODE_WRITE; 440 newstate &= ~FMODE_WRITE;
441 call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
442 call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
443 }
444 if (newstate == 0)
445 clear_bit(NFS_DELEGATED_STATE, &state->flags);
437 } 446 }
438 if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { 447 nfs4_state_set_mode_locked(state, newstate);
439 nfs4_state_set_mode_locked(state, newstate);
440 oldstate = newstate;
441 }
442 spin_unlock(&inode->i_lock); 448 spin_unlock(&inode->i_lock);
443 spin_unlock(&owner->so_lock); 449 spin_unlock(&owner->so_lock);
444 450
445 if (oldstate == newstate) { 451 if (!call_close) {
446 nfs4_put_open_state(state); 452 nfs4_put_open_state(state);
447 nfs4_put_state_owner(owner); 453 nfs4_put_state_owner(owner);
448 } else 454 } else
@@ -838,6 +844,10 @@ static void nfs4_state_mark_reclaim(struct nfs_client *clp)
838 sp->so_seqid.flags = 0; 844 sp->so_seqid.flags = 0;
839 spin_lock(&sp->so_lock); 845 spin_lock(&sp->so_lock);
840 list_for_each_entry(state, &sp->so_states, open_states) { 846 list_for_each_entry(state, &sp->so_states, open_states) {
847 clear_bit(NFS_DELEGATED_STATE, &state->flags);
848 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
849 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
850 clear_bit(NFS_O_RDWR_STATE, &state->flags);
841 list_for_each_entry(lock, &state->lock_states, ls_locks) { 851 list_for_each_entry(lock, &state->lock_states, ls_locks) {
842 lock->ls_seqid.counter = 0; 852 lock->ls_seqid.counter = 0;
843 lock->ls_seqid.flags = 0; 853 lock->ls_seqid.flags = 0;