diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 735 |
1 files changed, 468 insertions, 267 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9701ca8c9428..933e13b383f8 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/nfs_page.h> | 47 | #include <linux/nfs_page.h> |
48 | #include <linux/smp_lock.h> | 48 | #include <linux/smp_lock.h> |
49 | #include <linux/namei.h> | 49 | #include <linux/namei.h> |
50 | #include <linux/mount.h> | ||
50 | 51 | ||
51 | #include "nfs4_fs.h" | 52 | #include "nfs4_fs.h" |
52 | #include "delegation.h" | 53 | #include "delegation.h" |
@@ -56,10 +57,11 @@ | |||
56 | #define NFS4_POLL_RETRY_MIN (1*HZ) | 57 | #define NFS4_POLL_RETRY_MIN (1*HZ) |
57 | #define NFS4_POLL_RETRY_MAX (15*HZ) | 58 | #define NFS4_POLL_RETRY_MAX (15*HZ) |
58 | 59 | ||
60 | static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid); | ||
59 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 61 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
60 | static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *); | 62 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); |
61 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); | 63 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); |
62 | static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | 64 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); |
63 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | 65 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); |
64 | extern struct rpc_procinfo nfs4_procedures[]; | 66 | extern struct rpc_procinfo nfs4_procedures[]; |
65 | 67 | ||
@@ -185,8 +187,26 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf | |||
185 | { | 187 | { |
186 | struct nfs_inode *nfsi = NFS_I(inode); | 188 | struct nfs_inode *nfsi = NFS_I(inode); |
187 | 189 | ||
190 | spin_lock(&inode->i_lock); | ||
191 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | ||
188 | if (cinfo->before == nfsi->change_attr && cinfo->atomic) | 192 | if (cinfo->before == nfsi->change_attr && cinfo->atomic) |
189 | nfsi->change_attr = cinfo->after; | 193 | nfsi->change_attr = cinfo->after; |
194 | spin_unlock(&inode->i_lock); | ||
195 | } | ||
196 | |||
197 | /* Helper for asynchronous RPC calls */ | ||
198 | static int nfs4_call_async(struct rpc_clnt *clnt, rpc_action tk_begin, | ||
199 | rpc_action tk_exit, void *calldata) | ||
200 | { | ||
201 | struct rpc_task *task; | ||
202 | |||
203 | if (!(task = rpc_new_task(clnt, tk_exit, RPC_TASK_ASYNC))) | ||
204 | return -ENOMEM; | ||
205 | |||
206 | task->tk_calldata = calldata; | ||
207 | task->tk_action = tk_begin; | ||
208 | rpc_execute(task); | ||
209 | return 0; | ||
190 | } | 210 | } |
191 | 211 | ||
192 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 212 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) |
@@ -195,6 +215,7 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, | |||
195 | 215 | ||
196 | open_flags &= (FMODE_READ|FMODE_WRITE); | 216 | open_flags &= (FMODE_READ|FMODE_WRITE); |
197 | /* Protect against nfs4_find_state() */ | 217 | /* Protect against nfs4_find_state() */ |
218 | spin_lock(&state->owner->so_lock); | ||
198 | spin_lock(&inode->i_lock); | 219 | spin_lock(&inode->i_lock); |
199 | state->state |= open_flags; | 220 | state->state |= open_flags; |
200 | /* NB! List reordering - see the reclaim code for why. */ | 221 | /* NB! List reordering - see the reclaim code for why. */ |
@@ -204,12 +225,12 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, | |||
204 | state->nreaders++; | 225 | state->nreaders++; |
205 | memcpy(&state->stateid, stateid, sizeof(state->stateid)); | 226 | memcpy(&state->stateid, stateid, sizeof(state->stateid)); |
206 | spin_unlock(&inode->i_lock); | 227 | spin_unlock(&inode->i_lock); |
228 | spin_unlock(&state->owner->so_lock); | ||
207 | } | 229 | } |
208 | 230 | ||
209 | /* | 231 | /* |
210 | * OPEN_RECLAIM: | 232 | * OPEN_RECLAIM: |
211 | * reclaim state on the server after a reboot. | 233 | * reclaim state on the server after a reboot. |
212 | * Assumes caller is holding the sp->so_sem | ||
213 | */ | 234 | */ |
214 | static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) | 235 | static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) |
215 | { | 236 | { |
@@ -218,7 +239,6 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
218 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; | 239 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; |
219 | struct nfs_openargs o_arg = { | 240 | struct nfs_openargs o_arg = { |
220 | .fh = NFS_FH(inode), | 241 | .fh = NFS_FH(inode), |
221 | .seqid = sp->so_seqid, | ||
222 | .id = sp->so_id, | 242 | .id = sp->so_id, |
223 | .open_flags = state->state, | 243 | .open_flags = state->state, |
224 | .clientid = server->nfs4_state->cl_clientid, | 244 | .clientid = server->nfs4_state->cl_clientid, |
@@ -245,8 +265,13 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
245 | } | 265 | } |
246 | o_arg.u.delegation_type = delegation->type; | 266 | o_arg.u.delegation_type = delegation->type; |
247 | } | 267 | } |
268 | o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | ||
269 | if (o_arg.seqid == NULL) | ||
270 | return -ENOMEM; | ||
248 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 271 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
249 | nfs4_increment_seqid(status, sp); | 272 | /* Confirm the sequence as being established */ |
273 | nfs_confirm_seqid(&sp->so_seqid, status); | ||
274 | nfs_increment_open_seqid(status, o_arg.seqid); | ||
250 | if (status == 0) { | 275 | if (status == 0) { |
251 | memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); | 276 | memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); |
252 | if (o_res.delegation_type != 0) { | 277 | if (o_res.delegation_type != 0) { |
@@ -256,6 +281,7 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
256 | nfs_async_inode_return_delegation(inode, &o_res.stateid); | 281 | nfs_async_inode_return_delegation(inode, &o_res.stateid); |
257 | } | 282 | } |
258 | } | 283 | } |
284 | nfs_free_seqid(o_arg.seqid); | ||
259 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 285 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
260 | /* Ensure we update the inode attributes */ | 286 | /* Ensure we update the inode attributes */ |
261 | NFS_CACHEINV(inode); | 287 | NFS_CACHEINV(inode); |
@@ -302,23 +328,35 @@ static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state | |||
302 | }; | 328 | }; |
303 | int status = 0; | 329 | int status = 0; |
304 | 330 | ||
305 | down(&sp->so_sema); | ||
306 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | 331 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) |
307 | goto out; | 332 | goto out; |
308 | if (state->state == 0) | 333 | if (state->state == 0) |
309 | goto out; | 334 | goto out; |
310 | arg.seqid = sp->so_seqid; | 335 | arg.seqid = nfs_alloc_seqid(&sp->so_seqid); |
336 | status = -ENOMEM; | ||
337 | if (arg.seqid == NULL) | ||
338 | goto out; | ||
311 | arg.open_flags = state->state; | 339 | arg.open_flags = state->state; |
312 | memcpy(arg.u.delegation.data, state->stateid.data, sizeof(arg.u.delegation.data)); | 340 | memcpy(arg.u.delegation.data, state->stateid.data, sizeof(arg.u.delegation.data)); |
313 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 341 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
314 | nfs4_increment_seqid(status, sp); | 342 | nfs_increment_open_seqid(status, arg.seqid); |
343 | if (status != 0) | ||
344 | goto out_free; | ||
345 | if(res.rflags & NFS4_OPEN_RESULT_CONFIRM) { | ||
346 | status = _nfs4_proc_open_confirm(server->client, NFS_FH(inode), | ||
347 | sp, &res.stateid, arg.seqid); | ||
348 | if (status != 0) | ||
349 | goto out_free; | ||
350 | } | ||
351 | nfs_confirm_seqid(&sp->so_seqid, 0); | ||
315 | if (status >= 0) { | 352 | if (status >= 0) { |
316 | memcpy(state->stateid.data, res.stateid.data, | 353 | memcpy(state->stateid.data, res.stateid.data, |
317 | sizeof(state->stateid.data)); | 354 | sizeof(state->stateid.data)); |
318 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 355 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
319 | } | 356 | } |
357 | out_free: | ||
358 | nfs_free_seqid(arg.seqid); | ||
320 | out: | 359 | out: |
321 | up(&sp->so_sema); | ||
322 | dput(parent); | 360 | dput(parent); |
323 | return status; | 361 | return status; |
324 | } | 362 | } |
@@ -345,11 +383,11 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | |||
345 | return err; | 383 | return err; |
346 | } | 384 | } |
347 | 385 | ||
348 | static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid) | 386 | static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid) |
349 | { | 387 | { |
350 | struct nfs_open_confirmargs arg = { | 388 | struct nfs_open_confirmargs arg = { |
351 | .fh = fh, | 389 | .fh = fh, |
352 | .seqid = sp->so_seqid, | 390 | .seqid = seqid, |
353 | .stateid = *stateid, | 391 | .stateid = *stateid, |
354 | }; | 392 | }; |
355 | struct nfs_open_confirmres res; | 393 | struct nfs_open_confirmres res; |
@@ -362,7 +400,9 @@ static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nf | |||
362 | int status; | 400 | int status; |
363 | 401 | ||
364 | status = rpc_call_sync(clnt, &msg, RPC_TASK_NOINTR); | 402 | status = rpc_call_sync(clnt, &msg, RPC_TASK_NOINTR); |
365 | nfs4_increment_seqid(status, sp); | 403 | /* Confirm the sequence as being established */ |
404 | nfs_confirm_seqid(&sp->so_seqid, status); | ||
405 | nfs_increment_open_seqid(status, seqid); | ||
366 | if (status >= 0) | 406 | if (status >= 0) |
367 | memcpy(stateid, &res.stateid, sizeof(*stateid)); | 407 | memcpy(stateid, &res.stateid, sizeof(*stateid)); |
368 | return status; | 408 | return status; |
@@ -380,21 +420,41 @@ static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, stru | |||
380 | int status; | 420 | int status; |
381 | 421 | ||
382 | /* Update sequence id. The caller must serialize! */ | 422 | /* Update sequence id. The caller must serialize! */ |
383 | o_arg->seqid = sp->so_seqid; | ||
384 | o_arg->id = sp->so_id; | 423 | o_arg->id = sp->so_id; |
385 | o_arg->clientid = sp->so_client->cl_clientid; | 424 | o_arg->clientid = sp->so_client->cl_clientid; |
386 | 425 | ||
387 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 426 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
388 | nfs4_increment_seqid(status, sp); | 427 | if (status == 0) { |
428 | /* OPEN on anything except a regular file is disallowed in NFSv4 */ | ||
429 | switch (o_res->f_attr->mode & S_IFMT) { | ||
430 | case S_IFREG: | ||
431 | break; | ||
432 | case S_IFLNK: | ||
433 | status = -ELOOP; | ||
434 | break; | ||
435 | case S_IFDIR: | ||
436 | status = -EISDIR; | ||
437 | break; | ||
438 | default: | ||
439 | status = -ENOTDIR; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | nfs_increment_open_seqid(status, o_arg->seqid); | ||
389 | if (status != 0) | 444 | if (status != 0) |
390 | goto out; | 445 | goto out; |
391 | update_changeattr(dir, &o_res->cinfo); | 446 | if (o_arg->open_flags & O_CREAT) { |
447 | update_changeattr(dir, &o_res->cinfo); | ||
448 | nfs_post_op_update_inode(dir, o_res->dir_attr); | ||
449 | } else | ||
450 | nfs_refresh_inode(dir, o_res->dir_attr); | ||
392 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | 451 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { |
393 | status = _nfs4_proc_open_confirm(server->client, &o_res->fh, | 452 | status = _nfs4_proc_open_confirm(server->client, &o_res->fh, |
394 | sp, &o_res->stateid); | 453 | sp, &o_res->stateid, o_arg->seqid); |
395 | if (status != 0) | 454 | if (status != 0) |
396 | goto out; | 455 | goto out; |
397 | } | 456 | } |
457 | nfs_confirm_seqid(&sp->so_seqid, 0); | ||
398 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) | 458 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) |
399 | status = server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); | 459 | status = server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); |
400 | out: | 460 | out: |
@@ -441,9 +501,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
441 | struct inode *inode = state->inode; | 501 | struct inode *inode = state->inode; |
442 | struct nfs_server *server = NFS_SERVER(dir); | 502 | struct nfs_server *server = NFS_SERVER(dir); |
443 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; | 503 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; |
444 | struct nfs_fattr f_attr = { | 504 | struct nfs_fattr f_attr, dir_attr; |
445 | .valid = 0, | ||
446 | }; | ||
447 | struct nfs_openargs o_arg = { | 505 | struct nfs_openargs o_arg = { |
448 | .fh = NFS_FH(dir), | 506 | .fh = NFS_FH(dir), |
449 | .open_flags = state->state, | 507 | .open_flags = state->state, |
@@ -453,6 +511,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
453 | }; | 511 | }; |
454 | struct nfs_openres o_res = { | 512 | struct nfs_openres o_res = { |
455 | .f_attr = &f_attr, | 513 | .f_attr = &f_attr, |
514 | .dir_attr = &dir_attr, | ||
456 | .server = server, | 515 | .server = server, |
457 | }; | 516 | }; |
458 | int status = 0; | 517 | int status = 0; |
@@ -465,6 +524,12 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
465 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 524 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
466 | goto out; | 525 | goto out; |
467 | } | 526 | } |
527 | o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | ||
528 | status = -ENOMEM; | ||
529 | if (o_arg.seqid == NULL) | ||
530 | goto out; | ||
531 | nfs_fattr_init(&f_attr); | ||
532 | nfs_fattr_init(&dir_attr); | ||
468 | status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); | 533 | status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); |
469 | if (status != 0) | 534 | if (status != 0) |
470 | goto out_nodeleg; | 535 | goto out_nodeleg; |
@@ -490,6 +555,7 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
490 | nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res); | 555 | nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res); |
491 | } | 556 | } |
492 | out_nodeleg: | 557 | out_nodeleg: |
558 | nfs_free_seqid(o_arg.seqid); | ||
493 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 559 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
494 | out: | 560 | out: |
495 | dput(parent); | 561 | dput(parent); |
@@ -564,7 +630,6 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
564 | dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__); | 630 | dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__); |
565 | goto out_err; | 631 | goto out_err; |
566 | } | 632 | } |
567 | down(&sp->so_sema); | ||
568 | state = nfs4_get_open_state(inode, sp); | 633 | state = nfs4_get_open_state(inode, sp); |
569 | if (state == NULL) | 634 | if (state == NULL) |
570 | goto out_err; | 635 | goto out_err; |
@@ -589,7 +654,6 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
589 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 654 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
590 | update_open_stateid(state, &delegation->stateid, open_flags); | 655 | update_open_stateid(state, &delegation->stateid, open_flags); |
591 | out_ok: | 656 | out_ok: |
592 | up(&sp->so_sema); | ||
593 | nfs4_put_state_owner(sp); | 657 | nfs4_put_state_owner(sp); |
594 | up_read(&nfsi->rwsem); | 658 | up_read(&nfsi->rwsem); |
595 | up_read(&clp->cl_sem); | 659 | up_read(&clp->cl_sem); |
@@ -600,11 +664,12 @@ out_err: | |||
600 | if (sp != NULL) { | 664 | if (sp != NULL) { |
601 | if (state != NULL) | 665 | if (state != NULL) |
602 | nfs4_put_open_state(state); | 666 | nfs4_put_open_state(state); |
603 | up(&sp->so_sema); | ||
604 | nfs4_put_state_owner(sp); | 667 | nfs4_put_state_owner(sp); |
605 | } | 668 | } |
606 | up_read(&nfsi->rwsem); | 669 | up_read(&nfsi->rwsem); |
607 | up_read(&clp->cl_sem); | 670 | up_read(&clp->cl_sem); |
671 | if (err != -EACCES) | ||
672 | nfs_inode_return_delegation(inode); | ||
608 | return err; | 673 | return err; |
609 | } | 674 | } |
610 | 675 | ||
@@ -635,9 +700,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
635 | struct nfs4_client *clp = server->nfs4_state; | 700 | struct nfs4_client *clp = server->nfs4_state; |
636 | struct inode *inode = NULL; | 701 | struct inode *inode = NULL; |
637 | int status; | 702 | int status; |
638 | struct nfs_fattr f_attr = { | 703 | struct nfs_fattr f_attr, dir_attr; |
639 | .valid = 0, | ||
640 | }; | ||
641 | struct nfs_openargs o_arg = { | 704 | struct nfs_openargs o_arg = { |
642 | .fh = NFS_FH(dir), | 705 | .fh = NFS_FH(dir), |
643 | .open_flags = flags, | 706 | .open_flags = flags, |
@@ -648,6 +711,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
648 | }; | 711 | }; |
649 | struct nfs_openres o_res = { | 712 | struct nfs_openres o_res = { |
650 | .f_attr = &f_attr, | 713 | .f_attr = &f_attr, |
714 | .dir_attr = &dir_attr, | ||
651 | .server = server, | 715 | .server = server, |
652 | }; | 716 | }; |
653 | 717 | ||
@@ -665,8 +729,12 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
665 | } else | 729 | } else |
666 | o_arg.u.attrs = sattr; | 730 | o_arg.u.attrs = sattr; |
667 | /* Serialization for the sequence id */ | 731 | /* Serialization for the sequence id */ |
668 | down(&sp->so_sema); | ||
669 | 732 | ||
733 | o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | ||
734 | if (o_arg.seqid == NULL) | ||
735 | return -ENOMEM; | ||
736 | nfs_fattr_init(&f_attr); | ||
737 | nfs_fattr_init(&dir_attr); | ||
670 | status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); | 738 | status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); |
671 | if (status != 0) | 739 | if (status != 0) |
672 | goto out_err; | 740 | goto out_err; |
@@ -681,7 +749,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
681 | update_open_stateid(state, &o_res.stateid, flags); | 749 | update_open_stateid(state, &o_res.stateid, flags); |
682 | if (o_res.delegation_type != 0) | 750 | if (o_res.delegation_type != 0) |
683 | nfs_inode_set_delegation(inode, cred, &o_res); | 751 | nfs_inode_set_delegation(inode, cred, &o_res); |
684 | up(&sp->so_sema); | 752 | nfs_free_seqid(o_arg.seqid); |
685 | nfs4_put_state_owner(sp); | 753 | nfs4_put_state_owner(sp); |
686 | up_read(&clp->cl_sem); | 754 | up_read(&clp->cl_sem); |
687 | *res = state; | 755 | *res = state; |
@@ -690,7 +758,7 @@ out_err: | |||
690 | if (sp != NULL) { | 758 | if (sp != NULL) { |
691 | if (state != NULL) | 759 | if (state != NULL) |
692 | nfs4_put_open_state(state); | 760 | nfs4_put_open_state(state); |
693 | up(&sp->so_sema); | 761 | nfs_free_seqid(o_arg.seqid); |
694 | nfs4_put_state_owner(sp); | 762 | nfs4_put_state_owner(sp); |
695 | } | 763 | } |
696 | /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */ | 764 | /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */ |
@@ -718,7 +786,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, | |||
718 | * It is actually a sign of a bug on the client or on the server. | 786 | * It is actually a sign of a bug on the client or on the server. |
719 | * | 787 | * |
720 | * If we receive a BAD_SEQID error in the particular case of | 788 | * If we receive a BAD_SEQID error in the particular case of |
721 | * doing an OPEN, we assume that nfs4_increment_seqid() will | 789 | * doing an OPEN, we assume that nfs_increment_open_seqid() will |
722 | * have unhashed the old state_owner for us, and that we can | 790 | * have unhashed the old state_owner for us, and that we can |
723 | * therefore safely retry using a new one. We should still warn | 791 | * therefore safely retry using a new one. We should still warn |
724 | * the user though... | 792 | * the user though... |
@@ -728,6 +796,16 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, | |||
728 | exception.retry = 1; | 796 | exception.retry = 1; |
729 | continue; | 797 | continue; |
730 | } | 798 | } |
799 | /* | ||
800 | * BAD_STATEID on OPEN means that the server cancelled our | ||
801 | * state before it received the OPEN_CONFIRM. | ||
802 | * Recover by retrying the request as per the discussion | ||
803 | * on Page 181 of RFC3530. | ||
804 | */ | ||
805 | if (status == -NFS4ERR_BAD_STATEID) { | ||
806 | exception.retry = 1; | ||
807 | continue; | ||
808 | } | ||
731 | res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir), | 809 | res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir), |
732 | status, &exception)); | 810 | status, &exception)); |
733 | } while (exception.retry); | 811 | } while (exception.retry); |
@@ -755,7 +833,7 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
755 | }; | 833 | }; |
756 | int status; | 834 | int status; |
757 | 835 | ||
758 | fattr->valid = 0; | 836 | nfs_fattr_init(fattr); |
759 | 837 | ||
760 | if (state != NULL) { | 838 | if (state != NULL) { |
761 | msg.rpc_cred = state->owner->so_cred; | 839 | msg.rpc_cred = state->owner->so_cred; |
@@ -787,19 +865,30 @@ struct nfs4_closedata { | |||
787 | struct nfs4_state *state; | 865 | struct nfs4_state *state; |
788 | struct nfs_closeargs arg; | 866 | struct nfs_closeargs arg; |
789 | struct nfs_closeres res; | 867 | struct nfs_closeres res; |
868 | struct nfs_fattr fattr; | ||
790 | }; | 869 | }; |
791 | 870 | ||
871 | static void nfs4_free_closedata(struct nfs4_closedata *calldata) | ||
872 | { | ||
873 | struct nfs4_state *state = calldata->state; | ||
874 | struct nfs4_state_owner *sp = state->owner; | ||
875 | |||
876 | nfs4_put_open_state(calldata->state); | ||
877 | nfs_free_seqid(calldata->arg.seqid); | ||
878 | nfs4_put_state_owner(sp); | ||
879 | kfree(calldata); | ||
880 | } | ||
881 | |||
792 | static void nfs4_close_done(struct rpc_task *task) | 882 | static void nfs4_close_done(struct rpc_task *task) |
793 | { | 883 | { |
794 | struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; | 884 | struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; |
795 | struct nfs4_state *state = calldata->state; | 885 | struct nfs4_state *state = calldata->state; |
796 | struct nfs4_state_owner *sp = state->owner; | ||
797 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 886 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
798 | 887 | ||
799 | /* hmm. we are done with the inode, and in the process of freeing | 888 | /* hmm. we are done with the inode, and in the process of freeing |
800 | * the state_owner. we keep this around to process errors | 889 | * the state_owner. we keep this around to process errors |
801 | */ | 890 | */ |
802 | nfs4_increment_seqid(task->tk_status, sp); | 891 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); |
803 | switch (task->tk_status) { | 892 | switch (task->tk_status) { |
804 | case 0: | 893 | case 0: |
805 | memcpy(&state->stateid, &calldata->res.stateid, | 894 | memcpy(&state->stateid, &calldata->res.stateid, |
@@ -816,25 +905,49 @@ static void nfs4_close_done(struct rpc_task *task) | |||
816 | return; | 905 | return; |
817 | } | 906 | } |
818 | } | 907 | } |
908 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | ||
819 | state->state = calldata->arg.open_flags; | 909 | state->state = calldata->arg.open_flags; |
820 | nfs4_put_open_state(state); | 910 | nfs4_free_closedata(calldata); |
821 | up(&sp->so_sema); | ||
822 | nfs4_put_state_owner(sp); | ||
823 | up_read(&server->nfs4_state->cl_sem); | ||
824 | kfree(calldata); | ||
825 | } | 911 | } |
826 | 912 | ||
827 | static inline int nfs4_close_call(struct rpc_clnt *clnt, struct nfs4_closedata *calldata) | 913 | static void nfs4_close_begin(struct rpc_task *task) |
828 | { | 914 | { |
915 | struct nfs4_closedata *calldata = (struct nfs4_closedata *)task->tk_calldata; | ||
916 | struct nfs4_state *state = calldata->state; | ||
829 | struct rpc_message msg = { | 917 | struct rpc_message msg = { |
830 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], | 918 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], |
831 | .rpc_argp = &calldata->arg, | 919 | .rpc_argp = &calldata->arg, |
832 | .rpc_resp = &calldata->res, | 920 | .rpc_resp = &calldata->res, |
833 | .rpc_cred = calldata->state->owner->so_cred, | 921 | .rpc_cred = state->owner->so_cred, |
834 | }; | 922 | }; |
835 | if (calldata->arg.open_flags != 0) | 923 | int mode = 0; |
924 | int status; | ||
925 | |||
926 | status = nfs_wait_on_sequence(calldata->arg.seqid, task); | ||
927 | if (status != 0) | ||
928 | return; | ||
929 | /* Don't reorder reads */ | ||
930 | smp_rmb(); | ||
931 | /* Recalculate the new open mode in case someone reopened the file | ||
932 | * while we were waiting in line to be scheduled. | ||
933 | */ | ||
934 | if (state->nreaders != 0) | ||
935 | mode |= FMODE_READ; | ||
936 | if (state->nwriters != 0) | ||
937 | mode |= FMODE_WRITE; | ||
938 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | ||
939 | state->state = mode; | ||
940 | if (mode == state->state) { | ||
941 | nfs4_free_closedata(calldata); | ||
942 | task->tk_exit = NULL; | ||
943 | rpc_exit(task, 0); | ||
944 | return; | ||
945 | } | ||
946 | nfs_fattr_init(calldata->res.fattr); | ||
947 | if (mode != 0) | ||
836 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 948 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
837 | return rpc_call_async(clnt, &msg, 0, nfs4_close_done, calldata); | 949 | calldata->arg.open_flags = mode; |
950 | rpc_call_setup(task, &msg, 0); | ||
838 | } | 951 | } |
839 | 952 | ||
840 | /* | 953 | /* |
@@ -850,40 +963,57 @@ static inline int nfs4_close_call(struct rpc_clnt *clnt, struct nfs4_closedata * | |||
850 | */ | 963 | */ |
851 | int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode) | 964 | int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode) |
852 | { | 965 | { |
966 | struct nfs_server *server = NFS_SERVER(inode); | ||
853 | struct nfs4_closedata *calldata; | 967 | struct nfs4_closedata *calldata; |
854 | int status; | 968 | int status = -ENOMEM; |
855 | 969 | ||
856 | /* Tell caller we're done */ | 970 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); |
857 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | ||
858 | state->state = mode; | ||
859 | return 0; | ||
860 | } | ||
861 | calldata = (struct nfs4_closedata *)kmalloc(sizeof(*calldata), GFP_KERNEL); | ||
862 | if (calldata == NULL) | 971 | if (calldata == NULL) |
863 | return -ENOMEM; | 972 | goto out; |
864 | calldata->inode = inode; | 973 | calldata->inode = inode; |
865 | calldata->state = state; | 974 | calldata->state = state; |
866 | calldata->arg.fh = NFS_FH(inode); | 975 | calldata->arg.fh = NFS_FH(inode); |
976 | calldata->arg.stateid = &state->stateid; | ||
867 | /* Serialization for the sequence id */ | 977 | /* Serialization for the sequence id */ |
868 | calldata->arg.seqid = state->owner->so_seqid; | 978 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
869 | calldata->arg.open_flags = mode; | 979 | if (calldata->arg.seqid == NULL) |
870 | memcpy(&calldata->arg.stateid, &state->stateid, | 980 | goto out_free_calldata; |
871 | sizeof(calldata->arg.stateid)); | 981 | calldata->arg.bitmask = server->attr_bitmask; |
872 | status = nfs4_close_call(NFS_SERVER(inode)->client, calldata); | 982 | calldata->res.fattr = &calldata->fattr; |
873 | /* | 983 | calldata->res.server = server; |
874 | * Return -EINPROGRESS on success in order to indicate to the | 984 | |
875 | * caller that an asynchronous RPC call has been launched, and | 985 | status = nfs4_call_async(server->client, nfs4_close_begin, |
876 | * that it will release the semaphores on completion. | 986 | nfs4_close_done, calldata); |
877 | */ | 987 | if (status == 0) |
878 | return (status == 0) ? -EINPROGRESS : status; | 988 | goto out; |
989 | |||
990 | nfs_free_seqid(calldata->arg.seqid); | ||
991 | out_free_calldata: | ||
992 | kfree(calldata); | ||
993 | out: | ||
994 | return status; | ||
879 | } | 995 | } |
880 | 996 | ||
881 | struct inode * | 997 | static void nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, struct nfs4_state *state) |
998 | { | ||
999 | struct file *filp; | ||
1000 | |||
1001 | filp = lookup_instantiate_filp(nd, dentry, NULL); | ||
1002 | if (!IS_ERR(filp)) { | ||
1003 | struct nfs_open_context *ctx; | ||
1004 | ctx = (struct nfs_open_context *)filp->private_data; | ||
1005 | ctx->state = state; | ||
1006 | } else | ||
1007 | nfs4_close_state(state, nd->intent.open.flags); | ||
1008 | } | ||
1009 | |||
1010 | struct dentry * | ||
882 | nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 1011 | nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
883 | { | 1012 | { |
884 | struct iattr attr; | 1013 | struct iattr attr; |
885 | struct rpc_cred *cred; | 1014 | struct rpc_cred *cred; |
886 | struct nfs4_state *state; | 1015 | struct nfs4_state *state; |
1016 | struct dentry *res; | ||
887 | 1017 | ||
888 | if (nd->flags & LOOKUP_CREATE) { | 1018 | if (nd->flags & LOOKUP_CREATE) { |
889 | attr.ia_mode = nd->intent.open.create_mode; | 1019 | attr.ia_mode = nd->intent.open.create_mode; |
@@ -897,16 +1027,23 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
897 | 1027 | ||
898 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); | 1028 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); |
899 | if (IS_ERR(cred)) | 1029 | if (IS_ERR(cred)) |
900 | return (struct inode *)cred; | 1030 | return (struct dentry *)cred; |
901 | state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); | 1031 | state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); |
902 | put_rpccred(cred); | 1032 | put_rpccred(cred); |
903 | if (IS_ERR(state)) | 1033 | if (IS_ERR(state)) { |
904 | return (struct inode *)state; | 1034 | if (PTR_ERR(state) == -ENOENT) |
905 | return state->inode; | 1035 | d_add(dentry, NULL); |
1036 | return (struct dentry *)state; | ||
1037 | } | ||
1038 | res = d_add_unique(dentry, state->inode); | ||
1039 | if (res != NULL) | ||
1040 | dentry = res; | ||
1041 | nfs4_intent_set_file(nd, dentry, state); | ||
1042 | return res; | ||
906 | } | 1043 | } |
907 | 1044 | ||
908 | int | 1045 | int |
909 | nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags) | 1046 | nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) |
910 | { | 1047 | { |
911 | struct rpc_cred *cred; | 1048 | struct rpc_cred *cred; |
912 | struct nfs4_state *state; | 1049 | struct nfs4_state *state; |
@@ -919,18 +1056,30 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags) | |||
919 | if (IS_ERR(state)) | 1056 | if (IS_ERR(state)) |
920 | state = nfs4_do_open(dir, dentry, openflags, NULL, cred); | 1057 | state = nfs4_do_open(dir, dentry, openflags, NULL, cred); |
921 | put_rpccred(cred); | 1058 | put_rpccred(cred); |
922 | if (state == ERR_PTR(-ENOENT) && dentry->d_inode == 0) | 1059 | if (IS_ERR(state)) { |
923 | return 1; | 1060 | switch (PTR_ERR(state)) { |
924 | if (IS_ERR(state)) | 1061 | case -EPERM: |
925 | return 0; | 1062 | case -EACCES: |
1063 | case -EDQUOT: | ||
1064 | case -ENOSPC: | ||
1065 | case -EROFS: | ||
1066 | lookup_instantiate_filp(nd, (struct dentry *)state, NULL); | ||
1067 | return 1; | ||
1068 | case -ENOENT: | ||
1069 | if (dentry->d_inode == NULL) | ||
1070 | return 1; | ||
1071 | } | ||
1072 | goto out_drop; | ||
1073 | } | ||
926 | inode = state->inode; | 1074 | inode = state->inode; |
1075 | iput(inode); | ||
927 | if (inode == dentry->d_inode) { | 1076 | if (inode == dentry->d_inode) { |
928 | iput(inode); | 1077 | nfs4_intent_set_file(nd, dentry, state); |
929 | return 1; | 1078 | return 1; |
930 | } | 1079 | } |
931 | d_drop(dentry); | ||
932 | nfs4_close_state(state, openflags); | 1080 | nfs4_close_state(state, openflags); |
933 | iput(inode); | 1081 | out_drop: |
1082 | d_drop(dentry); | ||
934 | return 0; | 1083 | return 0; |
935 | } | 1084 | } |
936 | 1085 | ||
@@ -974,13 +1123,12 @@ static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh | |||
974 | static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | 1123 | static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, |
975 | struct nfs_fsinfo *info) | 1124 | struct nfs_fsinfo *info) |
976 | { | 1125 | { |
977 | struct nfs_fattr * fattr = info->fattr; | ||
978 | struct nfs4_lookup_root_arg args = { | 1126 | struct nfs4_lookup_root_arg args = { |
979 | .bitmask = nfs4_fattr_bitmap, | 1127 | .bitmask = nfs4_fattr_bitmap, |
980 | }; | 1128 | }; |
981 | struct nfs4_lookup_res res = { | 1129 | struct nfs4_lookup_res res = { |
982 | .server = server, | 1130 | .server = server, |
983 | .fattr = fattr, | 1131 | .fattr = info->fattr, |
984 | .fh = fhandle, | 1132 | .fh = fhandle, |
985 | }; | 1133 | }; |
986 | struct rpc_message msg = { | 1134 | struct rpc_message msg = { |
@@ -988,7 +1136,7 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
988 | .rpc_argp = &args, | 1136 | .rpc_argp = &args, |
989 | .rpc_resp = &res, | 1137 | .rpc_resp = &res, |
990 | }; | 1138 | }; |
991 | fattr->valid = 0; | 1139 | nfs_fattr_init(info->fattr); |
992 | return rpc_call_sync(server->client, &msg, 0); | 1140 | return rpc_call_sync(server->client, &msg, 0); |
993 | } | 1141 | } |
994 | 1142 | ||
@@ -1051,7 +1199,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1051 | q.len = p - q.name; | 1199 | q.len = p - q.name; |
1052 | 1200 | ||
1053 | do { | 1201 | do { |
1054 | fattr->valid = 0; | 1202 | nfs_fattr_init(fattr); |
1055 | status = nfs4_handle_exception(server, | 1203 | status = nfs4_handle_exception(server, |
1056 | rpc_call_sync(server->client, &msg, 0), | 1204 | rpc_call_sync(server->client, &msg, 0), |
1057 | &exception); | 1205 | &exception); |
@@ -1088,7 +1236,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1088 | .rpc_resp = &res, | 1236 | .rpc_resp = &res, |
1089 | }; | 1237 | }; |
1090 | 1238 | ||
1091 | fattr->valid = 0; | 1239 | nfs_fattr_init(fattr); |
1092 | return rpc_call_sync(server->client, &msg, 0); | 1240 | return rpc_call_sync(server->client, &msg, 0); |
1093 | } | 1241 | } |
1094 | 1242 | ||
@@ -1130,7 +1278,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
1130 | struct nfs4_state *state; | 1278 | struct nfs4_state *state; |
1131 | int status; | 1279 | int status; |
1132 | 1280 | ||
1133 | fattr->valid = 0; | 1281 | nfs_fattr_init(fattr); |
1134 | 1282 | ||
1135 | cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); | 1283 | cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); |
1136 | if (IS_ERR(cred)) | 1284 | if (IS_ERR(cred)) |
@@ -1176,7 +1324,7 @@ static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, | |||
1176 | .rpc_resp = &res, | 1324 | .rpc_resp = &res, |
1177 | }; | 1325 | }; |
1178 | 1326 | ||
1179 | fattr->valid = 0; | 1327 | nfs_fattr_init(fattr); |
1180 | 1328 | ||
1181 | dprintk("NFS call lookup %s\n", name->name); | 1329 | dprintk("NFS call lookup %s\n", name->name); |
1182 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 1330 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
@@ -1325,7 +1473,7 @@ static int _nfs4_proc_read(struct nfs_read_data *rdata) | |||
1325 | dprintk("NFS call read %d @ %Ld\n", rdata->args.count, | 1473 | dprintk("NFS call read %d @ %Ld\n", rdata->args.count, |
1326 | (long long) rdata->args.offset); | 1474 | (long long) rdata->args.offset); |
1327 | 1475 | ||
1328 | fattr->valid = 0; | 1476 | nfs_fattr_init(fattr); |
1329 | status = rpc_call_sync(server->client, &msg, flags); | 1477 | status = rpc_call_sync(server->client, &msg, flags); |
1330 | if (!status) | 1478 | if (!status) |
1331 | renew_lease(server, timestamp); | 1479 | renew_lease(server, timestamp); |
@@ -1362,7 +1510,7 @@ static int _nfs4_proc_write(struct nfs_write_data *wdata) | |||
1362 | dprintk("NFS call write %d @ %Ld\n", wdata->args.count, | 1510 | dprintk("NFS call write %d @ %Ld\n", wdata->args.count, |
1363 | (long long) wdata->args.offset); | 1511 | (long long) wdata->args.offset); |
1364 | 1512 | ||
1365 | fattr->valid = 0; | 1513 | nfs_fattr_init(fattr); |
1366 | status = rpc_call_sync(server->client, &msg, rpcflags); | 1514 | status = rpc_call_sync(server->client, &msg, rpcflags); |
1367 | dprintk("NFS reply write: %d\n", status); | 1515 | dprintk("NFS reply write: %d\n", status); |
1368 | return status; | 1516 | return status; |
@@ -1396,7 +1544,7 @@ static int _nfs4_proc_commit(struct nfs_write_data *cdata) | |||
1396 | dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, | 1544 | dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, |
1397 | (long long) cdata->args.offset); | 1545 | (long long) cdata->args.offset); |
1398 | 1546 | ||
1399 | fattr->valid = 0; | 1547 | nfs_fattr_init(fattr); |
1400 | status = rpc_call_sync(server->client, &msg, 0); | 1548 | status = rpc_call_sync(server->client, &msg, 0); |
1401 | dprintk("NFS reply commit: %d\n", status); | 1549 | dprintk("NFS reply commit: %d\n", status); |
1402 | return status; | 1550 | return status; |
@@ -1431,7 +1579,7 @@ static int nfs4_proc_commit(struct nfs_write_data *cdata) | |||
1431 | 1579 | ||
1432 | static int | 1580 | static int |
1433 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 1581 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
1434 | int flags) | 1582 | int flags, struct nameidata *nd) |
1435 | { | 1583 | { |
1436 | struct nfs4_state *state; | 1584 | struct nfs4_state *state; |
1437 | struct rpc_cred *cred; | 1585 | struct rpc_cred *cred; |
@@ -1453,24 +1601,30 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1453 | struct nfs_fattr fattr; | 1601 | struct nfs_fattr fattr; |
1454 | status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, | 1602 | status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, |
1455 | NFS_FH(state->inode), sattr, state); | 1603 | NFS_FH(state->inode), sattr, state); |
1456 | if (status == 0) { | 1604 | if (status == 0) |
1457 | nfs_setattr_update_inode(state->inode, sattr); | 1605 | nfs_setattr_update_inode(state->inode, sattr); |
1458 | goto out; | 1606 | } |
1459 | } | 1607 | if (status == 0 && nd != NULL && (nd->flags & LOOKUP_OPEN)) |
1460 | } else if (flags != 0) | 1608 | nfs4_intent_set_file(nd, dentry, state); |
1461 | goto out; | 1609 | else |
1462 | nfs4_close_state(state, flags); | 1610 | nfs4_close_state(state, flags); |
1463 | out: | 1611 | out: |
1464 | return status; | 1612 | return status; |
1465 | } | 1613 | } |
1466 | 1614 | ||
1467 | static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | 1615 | static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) |
1468 | { | 1616 | { |
1617 | struct nfs_server *server = NFS_SERVER(dir); | ||
1469 | struct nfs4_remove_arg args = { | 1618 | struct nfs4_remove_arg args = { |
1470 | .fh = NFS_FH(dir), | 1619 | .fh = NFS_FH(dir), |
1471 | .name = name, | 1620 | .name = name, |
1621 | .bitmask = server->attr_bitmask, | ||
1622 | }; | ||
1623 | struct nfs_fattr dir_attr; | ||
1624 | struct nfs4_remove_res res = { | ||
1625 | .server = server, | ||
1626 | .dir_attr = &dir_attr, | ||
1472 | }; | 1627 | }; |
1473 | struct nfs4_change_info res; | ||
1474 | struct rpc_message msg = { | 1628 | struct rpc_message msg = { |
1475 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE], | 1629 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE], |
1476 | .rpc_argp = &args, | 1630 | .rpc_argp = &args, |
@@ -1478,9 +1632,12 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
1478 | }; | 1632 | }; |
1479 | int status; | 1633 | int status; |
1480 | 1634 | ||
1481 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 1635 | nfs_fattr_init(res.dir_attr); |
1482 | if (status == 0) | 1636 | status = rpc_call_sync(server->client, &msg, 0); |
1483 | update_changeattr(dir, &res); | 1637 | if (status == 0) { |
1638 | update_changeattr(dir, &res.cinfo); | ||
1639 | nfs_post_op_update_inode(dir, res.dir_attr); | ||
1640 | } | ||
1484 | return status; | 1641 | return status; |
1485 | } | 1642 | } |
1486 | 1643 | ||
@@ -1498,12 +1655,14 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
1498 | 1655 | ||
1499 | struct unlink_desc { | 1656 | struct unlink_desc { |
1500 | struct nfs4_remove_arg args; | 1657 | struct nfs4_remove_arg args; |
1501 | struct nfs4_change_info res; | 1658 | struct nfs4_remove_res res; |
1659 | struct nfs_fattr dir_attr; | ||
1502 | }; | 1660 | }; |
1503 | 1661 | ||
1504 | static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, | 1662 | static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, |
1505 | struct qstr *name) | 1663 | struct qstr *name) |
1506 | { | 1664 | { |
1665 | struct nfs_server *server = NFS_SERVER(dir->d_inode); | ||
1507 | struct unlink_desc *up; | 1666 | struct unlink_desc *up; |
1508 | 1667 | ||
1509 | up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL); | 1668 | up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL); |
@@ -1512,6 +1671,9 @@ static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, | |||
1512 | 1671 | ||
1513 | up->args.fh = NFS_FH(dir->d_inode); | 1672 | up->args.fh = NFS_FH(dir->d_inode); |
1514 | up->args.name = name; | 1673 | up->args.name = name; |
1674 | up->args.bitmask = server->attr_bitmask; | ||
1675 | up->res.server = server; | ||
1676 | up->res.dir_attr = &up->dir_attr; | ||
1515 | 1677 | ||
1516 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; | 1678 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; |
1517 | msg->rpc_argp = &up->args; | 1679 | msg->rpc_argp = &up->args; |
@@ -1526,7 +1688,8 @@ static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) | |||
1526 | 1688 | ||
1527 | if (msg->rpc_resp != NULL) { | 1689 | if (msg->rpc_resp != NULL) { |
1528 | up = container_of(msg->rpc_resp, struct unlink_desc, res); | 1690 | up = container_of(msg->rpc_resp, struct unlink_desc, res); |
1529 | update_changeattr(dir->d_inode, &up->res); | 1691 | update_changeattr(dir->d_inode, &up->res.cinfo); |
1692 | nfs_post_op_update_inode(dir->d_inode, up->res.dir_attr); | ||
1530 | kfree(up); | 1693 | kfree(up); |
1531 | msg->rpc_resp = NULL; | 1694 | msg->rpc_resp = NULL; |
1532 | msg->rpc_argp = NULL; | 1695 | msg->rpc_argp = NULL; |
@@ -1537,13 +1700,20 @@ static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) | |||
1537 | static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | 1700 | static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, |
1538 | struct inode *new_dir, struct qstr *new_name) | 1701 | struct inode *new_dir, struct qstr *new_name) |
1539 | { | 1702 | { |
1703 | struct nfs_server *server = NFS_SERVER(old_dir); | ||
1540 | struct nfs4_rename_arg arg = { | 1704 | struct nfs4_rename_arg arg = { |
1541 | .old_dir = NFS_FH(old_dir), | 1705 | .old_dir = NFS_FH(old_dir), |
1542 | .new_dir = NFS_FH(new_dir), | 1706 | .new_dir = NFS_FH(new_dir), |
1543 | .old_name = old_name, | 1707 | .old_name = old_name, |
1544 | .new_name = new_name, | 1708 | .new_name = new_name, |
1709 | .bitmask = server->attr_bitmask, | ||
1710 | }; | ||
1711 | struct nfs_fattr old_fattr, new_fattr; | ||
1712 | struct nfs4_rename_res res = { | ||
1713 | .server = server, | ||
1714 | .old_fattr = &old_fattr, | ||
1715 | .new_fattr = &new_fattr, | ||
1545 | }; | 1716 | }; |
1546 | struct nfs4_rename_res res = { }; | ||
1547 | struct rpc_message msg = { | 1717 | struct rpc_message msg = { |
1548 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], | 1718 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], |
1549 | .rpc_argp = &arg, | 1719 | .rpc_argp = &arg, |
@@ -1551,11 +1721,15 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
1551 | }; | 1721 | }; |
1552 | int status; | 1722 | int status; |
1553 | 1723 | ||
1554 | status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); | 1724 | nfs_fattr_init(res.old_fattr); |
1725 | nfs_fattr_init(res.new_fattr); | ||
1726 | status = rpc_call_sync(server->client, &msg, 0); | ||
1555 | 1727 | ||
1556 | if (!status) { | 1728 | if (!status) { |
1557 | update_changeattr(old_dir, &res.old_cinfo); | 1729 | update_changeattr(old_dir, &res.old_cinfo); |
1730 | nfs_post_op_update_inode(old_dir, res.old_fattr); | ||
1558 | update_changeattr(new_dir, &res.new_cinfo); | 1731 | update_changeattr(new_dir, &res.new_cinfo); |
1732 | nfs_post_op_update_inode(new_dir, res.new_fattr); | ||
1559 | } | 1733 | } |
1560 | return status; | 1734 | return status; |
1561 | } | 1735 | } |
@@ -1576,22 +1750,34 @@ static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
1576 | 1750 | ||
1577 | static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | 1751 | static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) |
1578 | { | 1752 | { |
1753 | struct nfs_server *server = NFS_SERVER(inode); | ||
1579 | struct nfs4_link_arg arg = { | 1754 | struct nfs4_link_arg arg = { |
1580 | .fh = NFS_FH(inode), | 1755 | .fh = NFS_FH(inode), |
1581 | .dir_fh = NFS_FH(dir), | 1756 | .dir_fh = NFS_FH(dir), |
1582 | .name = name, | 1757 | .name = name, |
1758 | .bitmask = server->attr_bitmask, | ||
1759 | }; | ||
1760 | struct nfs_fattr fattr, dir_attr; | ||
1761 | struct nfs4_link_res res = { | ||
1762 | .server = server, | ||
1763 | .fattr = &fattr, | ||
1764 | .dir_attr = &dir_attr, | ||
1583 | }; | 1765 | }; |
1584 | struct nfs4_change_info cinfo = { }; | ||
1585 | struct rpc_message msg = { | 1766 | struct rpc_message msg = { |
1586 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], | 1767 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], |
1587 | .rpc_argp = &arg, | 1768 | .rpc_argp = &arg, |
1588 | .rpc_resp = &cinfo, | 1769 | .rpc_resp = &res, |
1589 | }; | 1770 | }; |
1590 | int status; | 1771 | int status; |
1591 | 1772 | ||
1592 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 1773 | nfs_fattr_init(res.fattr); |
1593 | if (!status) | 1774 | nfs_fattr_init(res.dir_attr); |
1594 | update_changeattr(dir, &cinfo); | 1775 | status = rpc_call_sync(server->client, &msg, 0); |
1776 | if (!status) { | ||
1777 | update_changeattr(dir, &res.cinfo); | ||
1778 | nfs_post_op_update_inode(dir, res.dir_attr); | ||
1779 | nfs_refresh_inode(inode, res.fattr); | ||
1780 | } | ||
1595 | 1781 | ||
1596 | return status; | 1782 | return status; |
1597 | } | 1783 | } |
@@ -1613,6 +1799,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, | |||
1613 | struct nfs_fattr *fattr) | 1799 | struct nfs_fattr *fattr) |
1614 | { | 1800 | { |
1615 | struct nfs_server *server = NFS_SERVER(dir); | 1801 | struct nfs_server *server = NFS_SERVER(dir); |
1802 | struct nfs_fattr dir_fattr; | ||
1616 | struct nfs4_create_arg arg = { | 1803 | struct nfs4_create_arg arg = { |
1617 | .dir_fh = NFS_FH(dir), | 1804 | .dir_fh = NFS_FH(dir), |
1618 | .server = server, | 1805 | .server = server, |
@@ -1625,6 +1812,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, | |||
1625 | .server = server, | 1812 | .server = server, |
1626 | .fh = fhandle, | 1813 | .fh = fhandle, |
1627 | .fattr = fattr, | 1814 | .fattr = fattr, |
1815 | .dir_fattr = &dir_fattr, | ||
1628 | }; | 1816 | }; |
1629 | struct rpc_message msg = { | 1817 | struct rpc_message msg = { |
1630 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK], | 1818 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK], |
@@ -1636,11 +1824,13 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, | |||
1636 | if (path->len > NFS4_MAXPATHLEN) | 1824 | if (path->len > NFS4_MAXPATHLEN) |
1637 | return -ENAMETOOLONG; | 1825 | return -ENAMETOOLONG; |
1638 | arg.u.symlink = path; | 1826 | arg.u.symlink = path; |
1639 | fattr->valid = 0; | 1827 | nfs_fattr_init(fattr); |
1828 | nfs_fattr_init(&dir_fattr); | ||
1640 | 1829 | ||
1641 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 1830 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
1642 | if (!status) | 1831 | if (!status) |
1643 | update_changeattr(dir, &res.dir_cinfo); | 1832 | update_changeattr(dir, &res.dir_cinfo); |
1833 | nfs_post_op_update_inode(dir, res.dir_fattr); | ||
1644 | return status; | 1834 | return status; |
1645 | } | 1835 | } |
1646 | 1836 | ||
@@ -1664,7 +1854,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, | |||
1664 | { | 1854 | { |
1665 | struct nfs_server *server = NFS_SERVER(dir); | 1855 | struct nfs_server *server = NFS_SERVER(dir); |
1666 | struct nfs_fh fhandle; | 1856 | struct nfs_fh fhandle; |
1667 | struct nfs_fattr fattr; | 1857 | struct nfs_fattr fattr, dir_fattr; |
1668 | struct nfs4_create_arg arg = { | 1858 | struct nfs4_create_arg arg = { |
1669 | .dir_fh = NFS_FH(dir), | 1859 | .dir_fh = NFS_FH(dir), |
1670 | .server = server, | 1860 | .server = server, |
@@ -1677,6 +1867,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, | |||
1677 | .server = server, | 1867 | .server = server, |
1678 | .fh = &fhandle, | 1868 | .fh = &fhandle, |
1679 | .fattr = &fattr, | 1869 | .fattr = &fattr, |
1870 | .dir_fattr = &dir_fattr, | ||
1680 | }; | 1871 | }; |
1681 | struct rpc_message msg = { | 1872 | struct rpc_message msg = { |
1682 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], | 1873 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], |
@@ -1685,11 +1876,13 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, | |||
1685 | }; | 1876 | }; |
1686 | int status; | 1877 | int status; |
1687 | 1878 | ||
1688 | fattr.valid = 0; | 1879 | nfs_fattr_init(&fattr); |
1880 | nfs_fattr_init(&dir_fattr); | ||
1689 | 1881 | ||
1690 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 1882 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
1691 | if (!status) { | 1883 | if (!status) { |
1692 | update_changeattr(dir, &res.dir_cinfo); | 1884 | update_changeattr(dir, &res.dir_cinfo); |
1885 | nfs_post_op_update_inode(dir, res.dir_fattr); | ||
1693 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 1886 | status = nfs_instantiate(dentry, &fhandle, &fattr); |
1694 | } | 1887 | } |
1695 | return status; | 1888 | return status; |
@@ -1762,7 +1955,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, | |||
1762 | { | 1955 | { |
1763 | struct nfs_server *server = NFS_SERVER(dir); | 1956 | struct nfs_server *server = NFS_SERVER(dir); |
1764 | struct nfs_fh fh; | 1957 | struct nfs_fh fh; |
1765 | struct nfs_fattr fattr; | 1958 | struct nfs_fattr fattr, dir_fattr; |
1766 | struct nfs4_create_arg arg = { | 1959 | struct nfs4_create_arg arg = { |
1767 | .dir_fh = NFS_FH(dir), | 1960 | .dir_fh = NFS_FH(dir), |
1768 | .server = server, | 1961 | .server = server, |
@@ -1774,6 +1967,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, | |||
1774 | .server = server, | 1967 | .server = server, |
1775 | .fh = &fh, | 1968 | .fh = &fh, |
1776 | .fattr = &fattr, | 1969 | .fattr = &fattr, |
1970 | .dir_fattr = &dir_fattr, | ||
1777 | }; | 1971 | }; |
1778 | struct rpc_message msg = { | 1972 | struct rpc_message msg = { |
1779 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], | 1973 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], |
@@ -1783,7 +1977,8 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, | |||
1783 | int status; | 1977 | int status; |
1784 | int mode = sattr->ia_mode; | 1978 | int mode = sattr->ia_mode; |
1785 | 1979 | ||
1786 | fattr.valid = 0; | 1980 | nfs_fattr_init(&fattr); |
1981 | nfs_fattr_init(&dir_fattr); | ||
1787 | 1982 | ||
1788 | BUG_ON(!(sattr->ia_valid & ATTR_MODE)); | 1983 | BUG_ON(!(sattr->ia_valid & ATTR_MODE)); |
1789 | BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode)); | 1984 | BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode)); |
@@ -1805,6 +2000,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, | |||
1805 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 2000 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
1806 | if (status == 0) { | 2001 | if (status == 0) { |
1807 | update_changeattr(dir, &res.dir_cinfo); | 2002 | update_changeattr(dir, &res.dir_cinfo); |
2003 | nfs_post_op_update_inode(dir, res.dir_fattr); | ||
1808 | status = nfs_instantiate(dentry, &fh, &fattr); | 2004 | status = nfs_instantiate(dentry, &fh, &fattr); |
1809 | } | 2005 | } |
1810 | return status; | 2006 | return status; |
@@ -1836,7 +2032,7 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1836 | .rpc_resp = fsstat, | 2032 | .rpc_resp = fsstat, |
1837 | }; | 2033 | }; |
1838 | 2034 | ||
1839 | fsstat->fattr->valid = 0; | 2035 | nfs_fattr_init(fsstat->fattr); |
1840 | return rpc_call_sync(server->client, &msg, 0); | 2036 | return rpc_call_sync(server->client, &msg, 0); |
1841 | } | 2037 | } |
1842 | 2038 | ||
@@ -1883,7 +2079,7 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, str | |||
1883 | 2079 | ||
1884 | static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 2080 | static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) |
1885 | { | 2081 | { |
1886 | fsinfo->fattr->valid = 0; | 2082 | nfs_fattr_init(fsinfo->fattr); |
1887 | return nfs4_do_fsinfo(server, fhandle, fsinfo); | 2083 | return nfs4_do_fsinfo(server, fhandle, fsinfo); |
1888 | } | 2084 | } |
1889 | 2085 | ||
@@ -1906,7 +2102,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
1906 | return 0; | 2102 | return 0; |
1907 | } | 2103 | } |
1908 | 2104 | ||
1909 | pathconf->fattr->valid = 0; | 2105 | nfs_fattr_init(pathconf->fattr); |
1910 | return rpc_call_sync(server->client, &msg, 0); | 2106 | return rpc_call_sync(server->client, &msg, 0); |
1911 | } | 2107 | } |
1912 | 2108 | ||
@@ -1973,8 +2169,10 @@ nfs4_write_done(struct rpc_task *task) | |||
1973 | rpc_restart_call(task); | 2169 | rpc_restart_call(task); |
1974 | return; | 2170 | return; |
1975 | } | 2171 | } |
1976 | if (task->tk_status >= 0) | 2172 | if (task->tk_status >= 0) { |
1977 | renew_lease(NFS_SERVER(inode), data->timestamp); | 2173 | renew_lease(NFS_SERVER(inode), data->timestamp); |
2174 | nfs_post_op_update_inode(inode, data->res.fattr); | ||
2175 | } | ||
1978 | /* Call back common NFS writeback processing */ | 2176 | /* Call back common NFS writeback processing */ |
1979 | nfs_writeback_done(task); | 2177 | nfs_writeback_done(task); |
1980 | } | 2178 | } |
@@ -1990,6 +2188,7 @@ nfs4_proc_write_setup(struct nfs_write_data *data, int how) | |||
1990 | .rpc_cred = data->cred, | 2188 | .rpc_cred = data->cred, |
1991 | }; | 2189 | }; |
1992 | struct inode *inode = data->inode; | 2190 | struct inode *inode = data->inode; |
2191 | struct nfs_server *server = NFS_SERVER(inode); | ||
1993 | int stable; | 2192 | int stable; |
1994 | int flags; | 2193 | int flags; |
1995 | 2194 | ||
@@ -2001,6 +2200,8 @@ nfs4_proc_write_setup(struct nfs_write_data *data, int how) | |||
2001 | } else | 2200 | } else |
2002 | stable = NFS_UNSTABLE; | 2201 | stable = NFS_UNSTABLE; |
2003 | data->args.stable = stable; | 2202 | data->args.stable = stable; |
2203 | data->args.bitmask = server->attr_bitmask; | ||
2204 | data->res.server = server; | ||
2004 | 2205 | ||
2005 | data->timestamp = jiffies; | 2206 | data->timestamp = jiffies; |
2006 | 2207 | ||
@@ -2022,6 +2223,8 @@ nfs4_commit_done(struct rpc_task *task) | |||
2022 | rpc_restart_call(task); | 2223 | rpc_restart_call(task); |
2023 | return; | 2224 | return; |
2024 | } | 2225 | } |
2226 | if (task->tk_status >= 0) | ||
2227 | nfs_post_op_update_inode(inode, data->res.fattr); | ||
2025 | /* Call back common NFS writeback processing */ | 2228 | /* Call back common NFS writeback processing */ |
2026 | nfs_commit_done(task); | 2229 | nfs_commit_done(task); |
2027 | } | 2230 | } |
@@ -2037,8 +2240,12 @@ nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | |||
2037 | .rpc_cred = data->cred, | 2240 | .rpc_cred = data->cred, |
2038 | }; | 2241 | }; |
2039 | struct inode *inode = data->inode; | 2242 | struct inode *inode = data->inode; |
2243 | struct nfs_server *server = NFS_SERVER(inode); | ||
2040 | int flags; | 2244 | int flags; |
2041 | 2245 | ||
2246 | data->args.bitmask = server->attr_bitmask; | ||
2247 | data->res.server = server; | ||
2248 | |||
2042 | /* Set the initial flags for the task. */ | 2249 | /* Set the initial flags for the task. */ |
2043 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 2250 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
2044 | 2251 | ||
@@ -2106,65 +2313,6 @@ nfs4_proc_renew(struct nfs4_client *clp) | |||
2106 | return 0; | 2313 | return 0; |
2107 | } | 2314 | } |
2108 | 2315 | ||
2109 | /* | ||
2110 | * We will need to arrange for the VFS layer to provide an atomic open. | ||
2111 | * Until then, this open method is prone to inefficiency and race conditions | ||
2112 | * due to the lookup, potential create, and open VFS calls from sys_open() | ||
2113 | * placed on the wire. | ||
2114 | */ | ||
2115 | static int | ||
2116 | nfs4_proc_file_open(struct inode *inode, struct file *filp) | ||
2117 | { | ||
2118 | struct dentry *dentry = filp->f_dentry; | ||
2119 | struct nfs_open_context *ctx; | ||
2120 | struct nfs4_state *state = NULL; | ||
2121 | struct rpc_cred *cred; | ||
2122 | int status = -ENOMEM; | ||
2123 | |||
2124 | dprintk("nfs4_proc_file_open: starting on (%.*s/%.*s)\n", | ||
2125 | (int)dentry->d_parent->d_name.len, | ||
2126 | dentry->d_parent->d_name.name, | ||
2127 | (int)dentry->d_name.len, dentry->d_name.name); | ||
2128 | |||
2129 | |||
2130 | /* Find our open stateid */ | ||
2131 | cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); | ||
2132 | if (IS_ERR(cred)) | ||
2133 | return PTR_ERR(cred); | ||
2134 | ctx = alloc_nfs_open_context(dentry, cred); | ||
2135 | put_rpccred(cred); | ||
2136 | if (unlikely(ctx == NULL)) | ||
2137 | return -ENOMEM; | ||
2138 | status = -EIO; /* ERACE actually */ | ||
2139 | state = nfs4_find_state(inode, cred, filp->f_mode); | ||
2140 | if (unlikely(state == NULL)) | ||
2141 | goto no_state; | ||
2142 | ctx->state = state; | ||
2143 | nfs4_close_state(state, filp->f_mode); | ||
2144 | ctx->mode = filp->f_mode; | ||
2145 | nfs_file_set_open_context(filp, ctx); | ||
2146 | put_nfs_open_context(ctx); | ||
2147 | if (filp->f_mode & FMODE_WRITE) | ||
2148 | nfs_begin_data_update(inode); | ||
2149 | return 0; | ||
2150 | no_state: | ||
2151 | printk(KERN_WARNING "NFS: v4 raced in function %s\n", __FUNCTION__); | ||
2152 | put_nfs_open_context(ctx); | ||
2153 | return status; | ||
2154 | } | ||
2155 | |||
2156 | /* | ||
2157 | * Release our state | ||
2158 | */ | ||
2159 | static int | ||
2160 | nfs4_proc_file_release(struct inode *inode, struct file *filp) | ||
2161 | { | ||
2162 | if (filp->f_mode & FMODE_WRITE) | ||
2163 | nfs_end_data_update(inode); | ||
2164 | nfs_file_clear_open_context(filp); | ||
2165 | return 0; | ||
2166 | } | ||
2167 | |||
2168 | static inline int nfs4_server_supports_acls(struct nfs_server *server) | 2316 | static inline int nfs4_server_supports_acls(struct nfs_server *server) |
2169 | { | 2317 | { |
2170 | return (server->caps & NFS_CAP_ACLS) | 2318 | return (server->caps & NFS_CAP_ACLS) |
@@ -2285,7 +2433,7 @@ static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size | |||
2285 | return -ENOMEM; | 2433 | return -ENOMEM; |
2286 | args.acl_pages[0] = localpage; | 2434 | args.acl_pages[0] = localpage; |
2287 | args.acl_pgbase = 0; | 2435 | args.acl_pgbase = 0; |
2288 | args.acl_len = PAGE_SIZE; | 2436 | resp_len = args.acl_len = PAGE_SIZE; |
2289 | } else { | 2437 | } else { |
2290 | resp_buf = buf; | 2438 | resp_buf = buf; |
2291 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | 2439 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); |
@@ -2345,6 +2493,7 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
2345 | 2493 | ||
2346 | if (!nfs4_server_supports_acls(server)) | 2494 | if (!nfs4_server_supports_acls(server)) |
2347 | return -EOPNOTSUPP; | 2495 | return -EOPNOTSUPP; |
2496 | nfs_inode_return_delegation(inode); | ||
2348 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 2497 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
2349 | ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); | 2498 | ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); |
2350 | if (ret == 0) | 2499 | if (ret == 0) |
@@ -2353,7 +2502,7 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
2353 | } | 2502 | } |
2354 | 2503 | ||
2355 | static int | 2504 | static int |
2356 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) | 2505 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) |
2357 | { | 2506 | { |
2358 | struct nfs4_client *clp = server->nfs4_state; | 2507 | struct nfs4_client *clp = server->nfs4_state; |
2359 | 2508 | ||
@@ -2431,7 +2580,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | |||
2431 | /* This is the error handling routine for processes that are allowed | 2580 | /* This is the error handling routine for processes that are allowed |
2432 | * to sleep. | 2581 | * to sleep. |
2433 | */ | 2582 | */ |
2434 | int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | 2583 | int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) |
2435 | { | 2584 | { |
2436 | struct nfs4_client *clp = server->nfs4_state; | 2585 | struct nfs4_client *clp = server->nfs4_state; |
2437 | int ret = errorcode; | 2586 | int ret = errorcode; |
@@ -2632,7 +2781,6 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2632 | 2781 | ||
2633 | down_read(&clp->cl_sem); | 2782 | down_read(&clp->cl_sem); |
2634 | nlo.clientid = clp->cl_clientid; | 2783 | nlo.clientid = clp->cl_clientid; |
2635 | down(&state->lock_sema); | ||
2636 | status = nfs4_set_lock_state(state, request); | 2784 | status = nfs4_set_lock_state(state, request); |
2637 | if (status != 0) | 2785 | if (status != 0) |
2638 | goto out; | 2786 | goto out; |
@@ -2659,7 +2807,6 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2659 | status = 0; | 2807 | status = 0; |
2660 | } | 2808 | } |
2661 | out: | 2809 | out: |
2662 | up(&state->lock_sema); | ||
2663 | up_read(&clp->cl_sem); | 2810 | up_read(&clp->cl_sem); |
2664 | return status; | 2811 | return status; |
2665 | } | 2812 | } |
@@ -2696,79 +2843,149 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) | |||
2696 | return res; | 2843 | return res; |
2697 | } | 2844 | } |
2698 | 2845 | ||
2699 | static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | 2846 | struct nfs4_unlockdata { |
2847 | struct nfs_lockargs arg; | ||
2848 | struct nfs_locku_opargs luargs; | ||
2849 | struct nfs_lockres res; | ||
2850 | struct nfs4_lock_state *lsp; | ||
2851 | struct nfs_open_context *ctx; | ||
2852 | atomic_t refcount; | ||
2853 | struct completion completion; | ||
2854 | }; | ||
2855 | |||
2856 | static void nfs4_locku_release_calldata(struct nfs4_unlockdata *calldata) | ||
2700 | { | 2857 | { |
2701 | struct inode *inode = state->inode; | 2858 | if (atomic_dec_and_test(&calldata->refcount)) { |
2702 | struct nfs_server *server = NFS_SERVER(inode); | 2859 | nfs_free_seqid(calldata->luargs.seqid); |
2703 | struct nfs4_client *clp = server->nfs4_state; | 2860 | nfs4_put_lock_state(calldata->lsp); |
2704 | struct nfs_lockargs arg = { | 2861 | put_nfs_open_context(calldata->ctx); |
2705 | .fh = NFS_FH(inode), | 2862 | kfree(calldata); |
2706 | .type = nfs4_lck_type(cmd, request), | 2863 | } |
2707 | .offset = request->fl_start, | 2864 | } |
2708 | .length = nfs4_lck_length(request), | 2865 | |
2709 | }; | 2866 | static void nfs4_locku_complete(struct nfs4_unlockdata *calldata) |
2710 | struct nfs_lockres res = { | 2867 | { |
2711 | .server = server, | 2868 | complete(&calldata->completion); |
2712 | }; | 2869 | nfs4_locku_release_calldata(calldata); |
2870 | } | ||
2871 | |||
2872 | static void nfs4_locku_done(struct rpc_task *task) | ||
2873 | { | ||
2874 | struct nfs4_unlockdata *calldata = (struct nfs4_unlockdata *)task->tk_calldata; | ||
2875 | |||
2876 | nfs_increment_lock_seqid(task->tk_status, calldata->luargs.seqid); | ||
2877 | switch (task->tk_status) { | ||
2878 | case 0: | ||
2879 | memcpy(calldata->lsp->ls_stateid.data, | ||
2880 | calldata->res.u.stateid.data, | ||
2881 | sizeof(calldata->lsp->ls_stateid.data)); | ||
2882 | break; | ||
2883 | case -NFS4ERR_STALE_STATEID: | ||
2884 | case -NFS4ERR_EXPIRED: | ||
2885 | nfs4_schedule_state_recovery(calldata->res.server->nfs4_state); | ||
2886 | break; | ||
2887 | default: | ||
2888 | if (nfs4_async_handle_error(task, calldata->res.server) == -EAGAIN) { | ||
2889 | rpc_restart_call(task); | ||
2890 | return; | ||
2891 | } | ||
2892 | } | ||
2893 | nfs4_locku_complete(calldata); | ||
2894 | } | ||
2895 | |||
2896 | static void nfs4_locku_begin(struct rpc_task *task) | ||
2897 | { | ||
2898 | struct nfs4_unlockdata *calldata = (struct nfs4_unlockdata *)task->tk_calldata; | ||
2713 | struct rpc_message msg = { | 2899 | struct rpc_message msg = { |
2714 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], | 2900 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], |
2715 | .rpc_argp = &arg, | 2901 | .rpc_argp = &calldata->arg, |
2716 | .rpc_resp = &res, | 2902 | .rpc_resp = &calldata->res, |
2717 | .rpc_cred = state->owner->so_cred, | 2903 | .rpc_cred = calldata->lsp->ls_state->owner->so_cred, |
2718 | }; | 2904 | }; |
2905 | int status; | ||
2906 | |||
2907 | status = nfs_wait_on_sequence(calldata->luargs.seqid, task); | ||
2908 | if (status != 0) | ||
2909 | return; | ||
2910 | if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) { | ||
2911 | nfs4_locku_complete(calldata); | ||
2912 | task->tk_exit = NULL; | ||
2913 | rpc_exit(task, 0); | ||
2914 | return; | ||
2915 | } | ||
2916 | rpc_call_setup(task, &msg, 0); | ||
2917 | } | ||
2918 | |||
2919 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | ||
2920 | { | ||
2921 | struct nfs4_unlockdata *calldata; | ||
2922 | struct inode *inode = state->inode; | ||
2923 | struct nfs_server *server = NFS_SERVER(inode); | ||
2719 | struct nfs4_lock_state *lsp; | 2924 | struct nfs4_lock_state *lsp; |
2720 | struct nfs_locku_opargs luargs; | ||
2721 | int status; | 2925 | int status; |
2722 | 2926 | ||
2723 | down_read(&clp->cl_sem); | ||
2724 | down(&state->lock_sema); | ||
2725 | status = nfs4_set_lock_state(state, request); | 2927 | status = nfs4_set_lock_state(state, request); |
2726 | if (status != 0) | 2928 | if (status != 0) |
2727 | goto out; | 2929 | return status; |
2728 | lsp = request->fl_u.nfs4_fl.owner; | 2930 | lsp = request->fl_u.nfs4_fl.owner; |
2729 | /* We might have lost the locks! */ | 2931 | /* We might have lost the locks! */ |
2730 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) | 2932 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) |
2731 | goto out; | 2933 | return 0; |
2732 | luargs.seqid = lsp->ls_seqid; | 2934 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); |
2733 | memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); | 2935 | if (calldata == NULL) |
2734 | arg.u.locku = &luargs; | 2936 | return -ENOMEM; |
2735 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 2937 | calldata->luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
2736 | nfs4_increment_lock_seqid(status, lsp); | 2938 | if (calldata->luargs.seqid == NULL) { |
2737 | 2939 | kfree(calldata); | |
2738 | if (status == 0) | 2940 | return -ENOMEM; |
2739 | memcpy(&lsp->ls_stateid, &res.u.stateid, | 2941 | } |
2740 | sizeof(lsp->ls_stateid)); | 2942 | calldata->luargs.stateid = &lsp->ls_stateid; |
2741 | out: | 2943 | calldata->arg.fh = NFS_FH(inode); |
2742 | up(&state->lock_sema); | 2944 | calldata->arg.type = nfs4_lck_type(cmd, request); |
2945 | calldata->arg.offset = request->fl_start; | ||
2946 | calldata->arg.length = nfs4_lck_length(request); | ||
2947 | calldata->arg.u.locku = &calldata->luargs; | ||
2948 | calldata->res.server = server; | ||
2949 | calldata->lsp = lsp; | ||
2950 | atomic_inc(&lsp->ls_count); | ||
2951 | |||
2952 | /* Ensure we don't close file until we're done freeing locks! */ | ||
2953 | calldata->ctx = get_nfs_open_context((struct nfs_open_context*)request->fl_file->private_data); | ||
2954 | |||
2955 | atomic_set(&calldata->refcount, 2); | ||
2956 | init_completion(&calldata->completion); | ||
2957 | |||
2958 | status = nfs4_call_async(NFS_SERVER(inode)->client, nfs4_locku_begin, | ||
2959 | nfs4_locku_done, calldata); | ||
2743 | if (status == 0) | 2960 | if (status == 0) |
2744 | do_vfs_lock(request->fl_file, request); | 2961 | wait_for_completion_interruptible(&calldata->completion); |
2745 | up_read(&clp->cl_sem); | 2962 | do_vfs_lock(request->fl_file, request); |
2963 | nfs4_locku_release_calldata(calldata); | ||
2746 | return status; | 2964 | return status; |
2747 | } | 2965 | } |
2748 | 2966 | ||
2749 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | ||
2750 | { | ||
2751 | struct nfs4_exception exception = { }; | ||
2752 | int err; | ||
2753 | |||
2754 | do { | ||
2755 | err = nfs4_handle_exception(NFS_SERVER(state->inode), | ||
2756 | _nfs4_proc_unlck(state, cmd, request), | ||
2757 | &exception); | ||
2758 | } while (exception.retry); | ||
2759 | return err; | ||
2760 | } | ||
2761 | |||
2762 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim) | 2967 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim) |
2763 | { | 2968 | { |
2764 | struct inode *inode = state->inode; | 2969 | struct inode *inode = state->inode; |
2765 | struct nfs_server *server = NFS_SERVER(inode); | 2970 | struct nfs_server *server = NFS_SERVER(inode); |
2766 | struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; | 2971 | struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; |
2972 | struct nfs_lock_opargs largs = { | ||
2973 | .lock_stateid = &lsp->ls_stateid, | ||
2974 | .open_stateid = &state->stateid, | ||
2975 | .lock_owner = { | ||
2976 | .clientid = server->nfs4_state->cl_clientid, | ||
2977 | .id = lsp->ls_id, | ||
2978 | }, | ||
2979 | .reclaim = reclaim, | ||
2980 | }; | ||
2767 | struct nfs_lockargs arg = { | 2981 | struct nfs_lockargs arg = { |
2768 | .fh = NFS_FH(inode), | 2982 | .fh = NFS_FH(inode), |
2769 | .type = nfs4_lck_type(cmd, request), | 2983 | .type = nfs4_lck_type(cmd, request), |
2770 | .offset = request->fl_start, | 2984 | .offset = request->fl_start, |
2771 | .length = nfs4_lck_length(request), | 2985 | .length = nfs4_lck_length(request), |
2986 | .u = { | ||
2987 | .lock = &largs, | ||
2988 | }, | ||
2772 | }; | 2989 | }; |
2773 | struct nfs_lockres res = { | 2990 | struct nfs_lockres res = { |
2774 | .server = server, | 2991 | .server = server, |
@@ -2779,53 +2996,39 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2779 | .rpc_resp = &res, | 2996 | .rpc_resp = &res, |
2780 | .rpc_cred = state->owner->so_cred, | 2997 | .rpc_cred = state->owner->so_cred, |
2781 | }; | 2998 | }; |
2782 | struct nfs_lock_opargs largs = { | 2999 | int status = -ENOMEM; |
2783 | .reclaim = reclaim, | ||
2784 | .new_lock_owner = 0, | ||
2785 | }; | ||
2786 | int status; | ||
2787 | 3000 | ||
2788 | if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) { | 3001 | largs.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
3002 | if (largs.lock_seqid == NULL) | ||
3003 | return -ENOMEM; | ||
3004 | if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) { | ||
2789 | struct nfs4_state_owner *owner = state->owner; | 3005 | struct nfs4_state_owner *owner = state->owner; |
2790 | struct nfs_open_to_lock otl = { | 3006 | |
2791 | .lock_owner = { | 3007 | largs.open_seqid = nfs_alloc_seqid(&owner->so_seqid); |
2792 | .clientid = server->nfs4_state->cl_clientid, | 3008 | if (largs.open_seqid == NULL) |
2793 | }, | 3009 | goto out; |
2794 | }; | ||
2795 | |||
2796 | otl.lock_seqid = lsp->ls_seqid; | ||
2797 | otl.lock_owner.id = lsp->ls_id; | ||
2798 | memcpy(&otl.open_stateid, &state->stateid, sizeof(otl.open_stateid)); | ||
2799 | largs.u.open_lock = &otl; | ||
2800 | largs.new_lock_owner = 1; | 3010 | largs.new_lock_owner = 1; |
2801 | arg.u.lock = &largs; | ||
2802 | down(&owner->so_sema); | ||
2803 | otl.open_seqid = owner->so_seqid; | ||
2804 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 3011 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
2805 | /* increment open_owner seqid on success, and | 3012 | /* increment open seqid on success, and seqid mutating errors */ |
2806 | * seqid mutating errors */ | 3013 | if (largs.new_lock_owner != 0) { |
2807 | nfs4_increment_seqid(status, owner); | 3014 | nfs_increment_open_seqid(status, largs.open_seqid); |
2808 | up(&owner->so_sema); | 3015 | if (status == 0) |
2809 | if (status == 0) { | 3016 | nfs_confirm_seqid(&lsp->ls_seqid, 0); |
2810 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | ||
2811 | lsp->ls_seqid++; | ||
2812 | } | 3017 | } |
2813 | } else { | 3018 | nfs_free_seqid(largs.open_seqid); |
2814 | struct nfs_exist_lock el = { | 3019 | } else |
2815 | .seqid = lsp->ls_seqid, | ||
2816 | }; | ||
2817 | memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); | ||
2818 | largs.u.exist_lock = ⪙ | ||
2819 | arg.u.lock = &largs; | ||
2820 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 3020 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
2821 | /* increment seqid on success, and * seqid mutating errors*/ | 3021 | /* increment lock seqid on success, and seqid mutating errors*/ |
2822 | nfs4_increment_lock_seqid(status, lsp); | 3022 | nfs_increment_lock_seqid(status, largs.lock_seqid); |
2823 | } | ||
2824 | /* save the returned stateid. */ | 3023 | /* save the returned stateid. */ |
2825 | if (status == 0) | 3024 | if (status == 0) { |
2826 | memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); | 3025 | memcpy(lsp->ls_stateid.data, res.u.stateid.data, |
2827 | else if (status == -NFS4ERR_DENIED) | 3026 | sizeof(lsp->ls_stateid.data)); |
3027 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | ||
3028 | } else if (status == -NFS4ERR_DENIED) | ||
2828 | status = -EAGAIN; | 3029 | status = -EAGAIN; |
3030 | out: | ||
3031 | nfs_free_seqid(largs.lock_seqid); | ||
2829 | return status; | 3032 | return status; |
2830 | } | 3033 | } |
2831 | 3034 | ||
@@ -2865,11 +3068,9 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2865 | int status; | 3068 | int status; |
2866 | 3069 | ||
2867 | down_read(&clp->cl_sem); | 3070 | down_read(&clp->cl_sem); |
2868 | down(&state->lock_sema); | ||
2869 | status = nfs4_set_lock_state(state, request); | 3071 | status = nfs4_set_lock_state(state, request); |
2870 | if (status == 0) | 3072 | if (status == 0) |
2871 | status = _nfs4_do_setlk(state, cmd, request, 0); | 3073 | status = _nfs4_do_setlk(state, cmd, request, 0); |
2872 | up(&state->lock_sema); | ||
2873 | if (status == 0) { | 3074 | if (status == 0) { |
2874 | /* Note: we always want to sleep here! */ | 3075 | /* Note: we always want to sleep here! */ |
2875 | request->fl_flags |= FL_SLEEP; | 3076 | request->fl_flags |= FL_SLEEP; |
@@ -3024,8 +3225,8 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
3024 | .read_setup = nfs4_proc_read_setup, | 3225 | .read_setup = nfs4_proc_read_setup, |
3025 | .write_setup = nfs4_proc_write_setup, | 3226 | .write_setup = nfs4_proc_write_setup, |
3026 | .commit_setup = nfs4_proc_commit_setup, | 3227 | .commit_setup = nfs4_proc_commit_setup, |
3027 | .file_open = nfs4_proc_file_open, | 3228 | .file_open = nfs_open, |
3028 | .file_release = nfs4_proc_file_release, | 3229 | .file_release = nfs_release, |
3029 | .lock = nfs4_proc_lock, | 3230 | .lock = nfs4_proc_lock, |
3030 | .clear_acl_cache = nfs4_zap_acl_attr, | 3231 | .clear_acl_cache = nfs4_zap_acl_attr, |
3031 | }; | 3232 | }; |