diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/client.c | 12 | ||||
-rw-r--r-- | fs/nfs/filelayout/filelayout.c | 5 | ||||
-rw-r--r-- | fs/nfs/nfs3acl.c | 5 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 13 | ||||
-rw-r--r-- | fs/nfs/nfs4client.c | 38 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 50 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 24 | ||||
-rw-r--r-- | fs/nfs/pagelist.c | 84 | ||||
-rw-r--r-- | fs/nfs/write.c | 21 |
9 files changed, 149 insertions, 103 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 1c5ff6d58385..6a4f3666e273 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -1412,24 +1412,18 @@ int nfs_fs_proc_net_init(struct net *net) | |||
1412 | p = proc_create("volumes", S_IFREG|S_IRUGO, | 1412 | p = proc_create("volumes", S_IFREG|S_IRUGO, |
1413 | nn->proc_nfsfs, &nfs_volume_list_fops); | 1413 | nn->proc_nfsfs, &nfs_volume_list_fops); |
1414 | if (!p) | 1414 | if (!p) |
1415 | goto error_2; | 1415 | goto error_1; |
1416 | return 0; | 1416 | return 0; |
1417 | 1417 | ||
1418 | error_2: | ||
1419 | remove_proc_entry("servers", nn->proc_nfsfs); | ||
1420 | error_1: | 1418 | error_1: |
1421 | remove_proc_entry("fs/nfsfs", NULL); | 1419 | remove_proc_subtree("nfsfs", net->proc_net); |
1422 | error_0: | 1420 | error_0: |
1423 | return -ENOMEM; | 1421 | return -ENOMEM; |
1424 | } | 1422 | } |
1425 | 1423 | ||
1426 | void nfs_fs_proc_net_exit(struct net *net) | 1424 | void nfs_fs_proc_net_exit(struct net *net) |
1427 | { | 1425 | { |
1428 | struct nfs_net *nn = net_generic(net, nfs_net_id); | 1426 | remove_proc_subtree("nfsfs", net->proc_net); |
1429 | |||
1430 | remove_proc_entry("volumes", nn->proc_nfsfs); | ||
1431 | remove_proc_entry("servers", nn->proc_nfsfs); | ||
1432 | remove_proc_entry("fs/nfsfs", NULL); | ||
1433 | } | 1427 | } |
1434 | 1428 | ||
1435 | /* | 1429 | /* |
diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c index 1359c4a27393..90978075f730 100644 --- a/fs/nfs/filelayout/filelayout.c +++ b/fs/nfs/filelayout/filelayout.c | |||
@@ -1269,11 +1269,12 @@ filelayout_search_commit_reqs(struct nfs_commit_info *cinfo, struct page *page) | |||
1269 | static void filelayout_retry_commit(struct nfs_commit_info *cinfo, int idx) | 1269 | static void filelayout_retry_commit(struct nfs_commit_info *cinfo, int idx) |
1270 | { | 1270 | { |
1271 | struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds; | 1271 | struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds; |
1272 | struct pnfs_commit_bucket *bucket = fl_cinfo->buckets; | 1272 | struct pnfs_commit_bucket *bucket; |
1273 | struct pnfs_layout_segment *freeme; | 1273 | struct pnfs_layout_segment *freeme; |
1274 | int i; | 1274 | int i; |
1275 | 1275 | ||
1276 | for (i = idx; i < fl_cinfo->nbuckets; i++, bucket++) { | 1276 | for (i = idx; i < fl_cinfo->nbuckets; i++) { |
1277 | bucket = &fl_cinfo->buckets[i]; | ||
1277 | if (list_empty(&bucket->committing)) | 1278 | if (list_empty(&bucket->committing)) |
1278 | continue; | 1279 | continue; |
1279 | nfs_retry_commit(&bucket->committing, bucket->clseg, cinfo); | 1280 | nfs_retry_commit(&bucket->committing, bucket->clseg, cinfo); |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index d0fec260132a..24c6898159cc 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
@@ -129,7 +129,10 @@ static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
129 | .rpc_argp = &args, | 129 | .rpc_argp = &args, |
130 | .rpc_resp = &fattr, | 130 | .rpc_resp = &fattr, |
131 | }; | 131 | }; |
132 | int status; | 132 | int status = 0; |
133 | |||
134 | if (acl == NULL && (!S_ISDIR(inode->i_mode) || dfacl == NULL)) | ||
135 | goto out; | ||
133 | 136 | ||
134 | status = -EOPNOTSUPP; | 137 | status = -EOPNOTSUPP; |
135 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) | 138 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 92193eddb41d..a8b855ab4e22 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -130,16 +130,15 @@ enum { | |||
130 | */ | 130 | */ |
131 | 131 | ||
132 | struct nfs4_lock_state { | 132 | struct nfs4_lock_state { |
133 | struct list_head ls_locks; /* Other lock stateids */ | 133 | struct list_head ls_locks; /* Other lock stateids */ |
134 | struct nfs4_state * ls_state; /* Pointer to open state */ | 134 | struct nfs4_state * ls_state; /* Pointer to open state */ |
135 | #define NFS_LOCK_INITIALIZED 0 | 135 | #define NFS_LOCK_INITIALIZED 0 |
136 | #define NFS_LOCK_LOST 1 | 136 | #define NFS_LOCK_LOST 1 |
137 | unsigned long ls_flags; | 137 | unsigned long ls_flags; |
138 | struct nfs_seqid_counter ls_seqid; | 138 | struct nfs_seqid_counter ls_seqid; |
139 | nfs4_stateid ls_stateid; | 139 | nfs4_stateid ls_stateid; |
140 | atomic_t ls_count; | 140 | atomic_t ls_count; |
141 | fl_owner_t ls_owner; | 141 | fl_owner_t ls_owner; |
142 | struct work_struct ls_release; | ||
143 | }; | 142 | }; |
144 | 143 | ||
145 | /* bits for nfs4_state->flags */ | 144 | /* bits for nfs4_state->flags */ |
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 53e435a95260..ffdb28d86cf8 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
@@ -482,6 +482,16 @@ int nfs40_walk_client_list(struct nfs_client *new, | |||
482 | 482 | ||
483 | spin_lock(&nn->nfs_client_lock); | 483 | spin_lock(&nn->nfs_client_lock); |
484 | list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { | 484 | list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { |
485 | |||
486 | if (pos->rpc_ops != new->rpc_ops) | ||
487 | continue; | ||
488 | |||
489 | if (pos->cl_proto != new->cl_proto) | ||
490 | continue; | ||
491 | |||
492 | if (pos->cl_minorversion != new->cl_minorversion) | ||
493 | continue; | ||
494 | |||
485 | /* If "pos" isn't marked ready, we can't trust the | 495 | /* If "pos" isn't marked ready, we can't trust the |
486 | * remaining fields in "pos" */ | 496 | * remaining fields in "pos" */ |
487 | if (pos->cl_cons_state > NFS_CS_READY) { | 497 | if (pos->cl_cons_state > NFS_CS_READY) { |
@@ -501,15 +511,6 @@ int nfs40_walk_client_list(struct nfs_client *new, | |||
501 | if (pos->cl_cons_state != NFS_CS_READY) | 511 | if (pos->cl_cons_state != NFS_CS_READY) |
502 | continue; | 512 | continue; |
503 | 513 | ||
504 | if (pos->rpc_ops != new->rpc_ops) | ||
505 | continue; | ||
506 | |||
507 | if (pos->cl_proto != new->cl_proto) | ||
508 | continue; | ||
509 | |||
510 | if (pos->cl_minorversion != new->cl_minorversion) | ||
511 | continue; | ||
512 | |||
513 | if (pos->cl_clientid != new->cl_clientid) | 514 | if (pos->cl_clientid != new->cl_clientid) |
514 | continue; | 515 | continue; |
515 | 516 | ||
@@ -622,6 +623,16 @@ int nfs41_walk_client_list(struct nfs_client *new, | |||
622 | 623 | ||
623 | spin_lock(&nn->nfs_client_lock); | 624 | spin_lock(&nn->nfs_client_lock); |
624 | list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { | 625 | list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { |
626 | |||
627 | if (pos->rpc_ops != new->rpc_ops) | ||
628 | continue; | ||
629 | |||
630 | if (pos->cl_proto != new->cl_proto) | ||
631 | continue; | ||
632 | |||
633 | if (pos->cl_minorversion != new->cl_minorversion) | ||
634 | continue; | ||
635 | |||
625 | /* If "pos" isn't marked ready, we can't trust the | 636 | /* If "pos" isn't marked ready, we can't trust the |
626 | * remaining fields in "pos", especially the client | 637 | * remaining fields in "pos", especially the client |
627 | * ID and serverowner fields. Wait for CREATE_SESSION | 638 | * ID and serverowner fields. Wait for CREATE_SESSION |
@@ -647,15 +658,6 @@ int nfs41_walk_client_list(struct nfs_client *new, | |||
647 | if (pos->cl_cons_state != NFS_CS_READY) | 658 | if (pos->cl_cons_state != NFS_CS_READY) |
648 | continue; | 659 | continue; |
649 | 660 | ||
650 | if (pos->rpc_ops != new->rpc_ops) | ||
651 | continue; | ||
652 | |||
653 | if (pos->cl_proto != new->cl_proto) | ||
654 | continue; | ||
655 | |||
656 | if (pos->cl_minorversion != new->cl_minorversion) | ||
657 | continue; | ||
658 | |||
659 | if (!nfs4_match_clientids(pos, new)) | 661 | if (!nfs4_match_clientids(pos, new)) |
660 | continue; | 662 | continue; |
661 | 663 | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 75ae8d22f067..6ca0c8e7a945 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -2226,9 +2226,13 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, | |||
2226 | ret = _nfs4_proc_open(opendata); | 2226 | ret = _nfs4_proc_open(opendata); |
2227 | if (ret != 0) { | 2227 | if (ret != 0) { |
2228 | if (ret == -ENOENT) { | 2228 | if (ret == -ENOENT) { |
2229 | d_drop(opendata->dentry); | 2229 | dentry = opendata->dentry; |
2230 | d_add(opendata->dentry, NULL); | 2230 | if (dentry->d_inode) |
2231 | nfs_set_verifier(opendata->dentry, | 2231 | d_delete(dentry); |
2232 | else if (d_unhashed(dentry)) | ||
2233 | d_add(dentry, NULL); | ||
2234 | |||
2235 | nfs_set_verifier(dentry, | ||
2232 | nfs_save_change_attribute(opendata->dir->d_inode)); | 2236 | nfs_save_change_attribute(opendata->dir->d_inode)); |
2233 | } | 2237 | } |
2234 | goto out; | 2238 | goto out; |
@@ -2560,6 +2564,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
2560 | struct nfs4_closedata *calldata = data; | 2564 | struct nfs4_closedata *calldata = data; |
2561 | struct nfs4_state *state = calldata->state; | 2565 | struct nfs4_state *state = calldata->state; |
2562 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 2566 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
2567 | nfs4_stateid *res_stateid = NULL; | ||
2563 | 2568 | ||
2564 | dprintk("%s: begin!\n", __func__); | 2569 | dprintk("%s: begin!\n", __func__); |
2565 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) | 2570 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) |
@@ -2570,12 +2575,12 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
2570 | */ | 2575 | */ |
2571 | switch (task->tk_status) { | 2576 | switch (task->tk_status) { |
2572 | case 0: | 2577 | case 0: |
2573 | if (calldata->roc) | 2578 | res_stateid = &calldata->res.stateid; |
2579 | if (calldata->arg.fmode == 0 && calldata->roc) | ||
2574 | pnfs_roc_set_barrier(state->inode, | 2580 | pnfs_roc_set_barrier(state->inode, |
2575 | calldata->roc_barrier); | 2581 | calldata->roc_barrier); |
2576 | nfs_clear_open_stateid(state, &calldata->res.stateid, 0); | ||
2577 | renew_lease(server, calldata->timestamp); | 2582 | renew_lease(server, calldata->timestamp); |
2578 | goto out_release; | 2583 | break; |
2579 | case -NFS4ERR_ADMIN_REVOKED: | 2584 | case -NFS4ERR_ADMIN_REVOKED: |
2580 | case -NFS4ERR_STALE_STATEID: | 2585 | case -NFS4ERR_STALE_STATEID: |
2581 | case -NFS4ERR_OLD_STATEID: | 2586 | case -NFS4ERR_OLD_STATEID: |
@@ -2589,7 +2594,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
2589 | goto out_release; | 2594 | goto out_release; |
2590 | } | 2595 | } |
2591 | } | 2596 | } |
2592 | nfs_clear_open_stateid(state, NULL, calldata->arg.fmode); | 2597 | nfs_clear_open_stateid(state, res_stateid, calldata->arg.fmode); |
2593 | out_release: | 2598 | out_release: |
2594 | nfs_release_seqid(calldata->arg.seqid); | 2599 | nfs_release_seqid(calldata->arg.seqid); |
2595 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 2600 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
@@ -2601,6 +2606,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
2601 | struct nfs4_closedata *calldata = data; | 2606 | struct nfs4_closedata *calldata = data; |
2602 | struct nfs4_state *state = calldata->state; | 2607 | struct nfs4_state *state = calldata->state; |
2603 | struct inode *inode = calldata->inode; | 2608 | struct inode *inode = calldata->inode; |
2609 | bool is_rdonly, is_wronly, is_rdwr; | ||
2604 | int call_close = 0; | 2610 | int call_close = 0; |
2605 | 2611 | ||
2606 | dprintk("%s: begin!\n", __func__); | 2612 | dprintk("%s: begin!\n", __func__); |
@@ -2608,21 +2614,27 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
2608 | goto out_wait; | 2614 | goto out_wait; |
2609 | 2615 | ||
2610 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 2616 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
2611 | calldata->arg.fmode = FMODE_READ|FMODE_WRITE; | ||
2612 | spin_lock(&state->owner->so_lock); | 2617 | spin_lock(&state->owner->so_lock); |
2618 | is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags); | ||
2619 | is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
2620 | is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
2613 | /* Calculate the change in open mode */ | 2621 | /* Calculate the change in open mode */ |
2622 | calldata->arg.fmode = 0; | ||
2614 | if (state->n_rdwr == 0) { | 2623 | if (state->n_rdwr == 0) { |
2615 | if (state->n_rdonly == 0) { | 2624 | if (state->n_rdonly == 0) |
2616 | call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags); | 2625 | call_close |= is_rdonly; |
2617 | call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); | 2626 | else if (is_rdonly) |
2618 | calldata->arg.fmode &= ~FMODE_READ; | 2627 | calldata->arg.fmode |= FMODE_READ; |
2619 | } | 2628 | if (state->n_wronly == 0) |
2620 | if (state->n_wronly == 0) { | 2629 | call_close |= is_wronly; |
2621 | call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags); | 2630 | else if (is_wronly) |
2622 | call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); | 2631 | calldata->arg.fmode |= FMODE_WRITE; |
2623 | calldata->arg.fmode &= ~FMODE_WRITE; | 2632 | } else if (is_rdwr) |
2624 | } | 2633 | calldata->arg.fmode |= FMODE_READ|FMODE_WRITE; |
2625 | } | 2634 | |
2635 | if (calldata->arg.fmode == 0) | ||
2636 | call_close |= is_rdwr; | ||
2637 | |||
2626 | if (!nfs4_valid_open_stateid(state)) | 2638 | if (!nfs4_valid_open_stateid(state)) |
2627 | call_close = 0; | 2639 | call_close = 0; |
2628 | spin_unlock(&state->owner->so_lock); | 2640 | spin_unlock(&state->owner->so_lock); |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index a043f618cd5a..22fe35104c0c 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -799,18 +799,6 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | |||
799 | return NULL; | 799 | return NULL; |
800 | } | 800 | } |
801 | 801 | ||
802 | static void | ||
803 | free_lock_state_work(struct work_struct *work) | ||
804 | { | ||
805 | struct nfs4_lock_state *lsp = container_of(work, | ||
806 | struct nfs4_lock_state, ls_release); | ||
807 | struct nfs4_state *state = lsp->ls_state; | ||
808 | struct nfs_server *server = state->owner->so_server; | ||
809 | struct nfs_client *clp = server->nfs_client; | ||
810 | |||
811 | clp->cl_mvops->free_lock_state(server, lsp); | ||
812 | } | ||
813 | |||
814 | /* | 802 | /* |
815 | * Return a compatible lock_state. If no initialized lock_state structure | 803 | * Return a compatible lock_state. If no initialized lock_state structure |
816 | * exists, return an uninitialized one. | 804 | * exists, return an uninitialized one. |
@@ -832,7 +820,6 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
832 | if (lsp->ls_seqid.owner_id < 0) | 820 | if (lsp->ls_seqid.owner_id < 0) |
833 | goto out_free; | 821 | goto out_free; |
834 | INIT_LIST_HEAD(&lsp->ls_locks); | 822 | INIT_LIST_HEAD(&lsp->ls_locks); |
835 | INIT_WORK(&lsp->ls_release, free_lock_state_work); | ||
836 | return lsp; | 823 | return lsp; |
837 | out_free: | 824 | out_free: |
838 | kfree(lsp); | 825 | kfree(lsp); |
@@ -896,12 +883,13 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp) | |||
896 | if (list_empty(&state->lock_states)) | 883 | if (list_empty(&state->lock_states)) |
897 | clear_bit(LK_STATE_IN_USE, &state->flags); | 884 | clear_bit(LK_STATE_IN_USE, &state->flags); |
898 | spin_unlock(&state->state_lock); | 885 | spin_unlock(&state->state_lock); |
899 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) | 886 | server = state->owner->so_server; |
900 | queue_work(nfsiod_workqueue, &lsp->ls_release); | 887 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { |
901 | else { | 888 | struct nfs_client *clp = server->nfs_client; |
902 | server = state->owner->so_server; | 889 | |
890 | clp->cl_mvops->free_lock_state(server, lsp); | ||
891 | } else | ||
903 | nfs4_free_lock_state(server, lsp); | 892 | nfs4_free_lock_state(server, lsp); |
904 | } | ||
905 | } | 893 | } |
906 | 894 | ||
907 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) | 895 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index ba491926df5f..be7cbce6e4c7 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -116,7 +116,7 @@ __nfs_iocounter_wait(struct nfs_io_counter *c) | |||
116 | if (atomic_read(&c->io_count) == 0) | 116 | if (atomic_read(&c->io_count) == 0) |
117 | break; | 117 | break; |
118 | ret = nfs_wait_bit_killable(&q.key); | 118 | ret = nfs_wait_bit_killable(&q.key); |
119 | } while (atomic_read(&c->io_count) != 0); | 119 | } while (atomic_read(&c->io_count) != 0 && !ret); |
120 | finish_wait(wq, &q.wait); | 120 | finish_wait(wq, &q.wait); |
121 | return ret; | 121 | return ret; |
122 | } | 122 | } |
@@ -139,26 +139,49 @@ nfs_iocounter_wait(struct nfs_io_counter *c) | |||
139 | /* | 139 | /* |
140 | * nfs_page_group_lock - lock the head of the page group | 140 | * nfs_page_group_lock - lock the head of the page group |
141 | * @req - request in group that is to be locked | 141 | * @req - request in group that is to be locked |
142 | * @nonblock - if true don't block waiting for lock | ||
142 | * | 143 | * |
143 | * this lock must be held if modifying the page group list | 144 | * this lock must be held if modifying the page group list |
144 | * | 145 | * |
145 | * returns result from wait_on_bit_lock: 0 on success, < 0 on error | 146 | * return 0 on success, < 0 on error: -EDELAY if nonblocking or the |
147 | * result from wait_on_bit_lock | ||
148 | * | ||
149 | * NOTE: calling with nonblock=false should always have set the | ||
150 | * lock bit (see fs/buffer.c and other uses of wait_on_bit_lock | ||
151 | * with TASK_UNINTERRUPTIBLE), so there is no need to check the result. | ||
146 | */ | 152 | */ |
147 | int | 153 | int |
148 | nfs_page_group_lock(struct nfs_page *req, bool wait) | 154 | nfs_page_group_lock(struct nfs_page *req, bool nonblock) |
149 | { | 155 | { |
150 | struct nfs_page *head = req->wb_head; | 156 | struct nfs_page *head = req->wb_head; |
151 | int ret; | ||
152 | 157 | ||
153 | WARN_ON_ONCE(head != head->wb_head); | 158 | WARN_ON_ONCE(head != head->wb_head); |
154 | 159 | ||
155 | do { | 160 | if (!test_and_set_bit(PG_HEADLOCK, &head->wb_flags)) |
156 | ret = wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, | 161 | return 0; |
157 | TASK_UNINTERRUPTIBLE); | ||
158 | } while (wait && ret != 0); | ||
159 | 162 | ||
160 | WARN_ON_ONCE(ret > 0); | 163 | if (!nonblock) |
161 | return ret; | 164 | return wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, |
165 | TASK_UNINTERRUPTIBLE); | ||
166 | |||
167 | return -EAGAIN; | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * nfs_page_group_lock_wait - wait for the lock to clear, but don't grab it | ||
172 | * @req - a request in the group | ||
173 | * | ||
174 | * This is a blocking call to wait for the group lock to be cleared. | ||
175 | */ | ||
176 | void | ||
177 | nfs_page_group_lock_wait(struct nfs_page *req) | ||
178 | { | ||
179 | struct nfs_page *head = req->wb_head; | ||
180 | |||
181 | WARN_ON_ONCE(head != head->wb_head); | ||
182 | |||
183 | wait_on_bit(&head->wb_flags, PG_HEADLOCK, | ||
184 | TASK_UNINTERRUPTIBLE); | ||
162 | } | 185 | } |
163 | 186 | ||
164 | /* | 187 | /* |
@@ -219,7 +242,7 @@ bool nfs_page_group_sync_on_bit(struct nfs_page *req, unsigned int bit) | |||
219 | { | 242 | { |
220 | bool ret; | 243 | bool ret; |
221 | 244 | ||
222 | nfs_page_group_lock(req, true); | 245 | nfs_page_group_lock(req, false); |
223 | ret = nfs_page_group_sync_on_bit_locked(req, bit); | 246 | ret = nfs_page_group_sync_on_bit_locked(req, bit); |
224 | nfs_page_group_unlock(req); | 247 | nfs_page_group_unlock(req); |
225 | 248 | ||
@@ -701,10 +724,11 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, | |||
701 | struct nfs_pgio_header *hdr) | 724 | struct nfs_pgio_header *hdr) |
702 | { | 725 | { |
703 | struct nfs_page *req; | 726 | struct nfs_page *req; |
704 | struct page **pages; | 727 | struct page **pages, |
728 | *last_page; | ||
705 | struct list_head *head = &desc->pg_list; | 729 | struct list_head *head = &desc->pg_list; |
706 | struct nfs_commit_info cinfo; | 730 | struct nfs_commit_info cinfo; |
707 | unsigned int pagecount; | 731 | unsigned int pagecount, pageused; |
708 | 732 | ||
709 | pagecount = nfs_page_array_len(desc->pg_base, desc->pg_count); | 733 | pagecount = nfs_page_array_len(desc->pg_base, desc->pg_count); |
710 | if (!nfs_pgarray_set(&hdr->page_array, pagecount)) | 734 | if (!nfs_pgarray_set(&hdr->page_array, pagecount)) |
@@ -712,12 +736,23 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, | |||
712 | 736 | ||
713 | nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); | 737 | nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); |
714 | pages = hdr->page_array.pagevec; | 738 | pages = hdr->page_array.pagevec; |
739 | last_page = NULL; | ||
740 | pageused = 0; | ||
715 | while (!list_empty(head)) { | 741 | while (!list_empty(head)) { |
716 | req = nfs_list_entry(head->next); | 742 | req = nfs_list_entry(head->next); |
717 | nfs_list_remove_request(req); | 743 | nfs_list_remove_request(req); |
718 | nfs_list_add_request(req, &hdr->pages); | 744 | nfs_list_add_request(req, &hdr->pages); |
719 | *pages++ = req->wb_page; | 745 | |
746 | if (WARN_ON_ONCE(pageused >= pagecount)) | ||
747 | return nfs_pgio_error(desc, hdr); | ||
748 | |||
749 | if (!last_page || last_page != req->wb_page) { | ||
750 | *pages++ = last_page = req->wb_page; | ||
751 | pageused++; | ||
752 | } | ||
720 | } | 753 | } |
754 | if (WARN_ON_ONCE(pageused != pagecount)) | ||
755 | return nfs_pgio_error(desc, hdr); | ||
721 | 756 | ||
722 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && | 757 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && |
723 | (desc->pg_moreio || nfs_reqs_to_commit(&cinfo))) | 758 | (desc->pg_moreio || nfs_reqs_to_commit(&cinfo))) |
@@ -788,6 +823,14 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev, | |||
788 | return false; | 823 | return false; |
789 | if (req_offset(req) != req_offset(prev) + prev->wb_bytes) | 824 | if (req_offset(req) != req_offset(prev) + prev->wb_bytes) |
790 | return false; | 825 | return false; |
826 | if (req->wb_page == prev->wb_page) { | ||
827 | if (req->wb_pgbase != prev->wb_pgbase + prev->wb_bytes) | ||
828 | return false; | ||
829 | } else { | ||
830 | if (req->wb_pgbase != 0 || | ||
831 | prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE) | ||
832 | return false; | ||
833 | } | ||
791 | } | 834 | } |
792 | size = pgio->pg_ops->pg_test(pgio, prev, req); | 835 | size = pgio->pg_ops->pg_test(pgio, prev, req); |
793 | WARN_ON_ONCE(size > req->wb_bytes); | 836 | WARN_ON_ONCE(size > req->wb_bytes); |
@@ -858,13 +901,8 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
858 | struct nfs_page *subreq; | 901 | struct nfs_page *subreq; |
859 | unsigned int bytes_left = 0; | 902 | unsigned int bytes_left = 0; |
860 | unsigned int offset, pgbase; | 903 | unsigned int offset, pgbase; |
861 | int ret; | ||
862 | 904 | ||
863 | ret = nfs_page_group_lock(req, false); | 905 | nfs_page_group_lock(req, false); |
864 | if (ret < 0) { | ||
865 | desc->pg_error = ret; | ||
866 | return 0; | ||
867 | } | ||
868 | 906 | ||
869 | subreq = req; | 907 | subreq = req; |
870 | bytes_left = subreq->wb_bytes; | 908 | bytes_left = subreq->wb_bytes; |
@@ -886,11 +924,7 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
886 | if (desc->pg_recoalesce) | 924 | if (desc->pg_recoalesce) |
887 | return 0; | 925 | return 0; |
888 | /* retry add_request for this subreq */ | 926 | /* retry add_request for this subreq */ |
889 | ret = nfs_page_group_lock(req, false); | 927 | nfs_page_group_lock(req, false); |
890 | if (ret < 0) { | ||
891 | desc->pg_error = ret; | ||
892 | return 0; | ||
893 | } | ||
894 | continue; | 928 | continue; |
895 | } | 929 | } |
896 | 930 | ||
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e3b5cf28bdc5..175d5d073ccf 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -241,7 +241,7 @@ static bool nfs_page_group_covers_page(struct nfs_page *req) | |||
241 | unsigned int pos = 0; | 241 | unsigned int pos = 0; |
242 | unsigned int len = nfs_page_length(req->wb_page); | 242 | unsigned int len = nfs_page_length(req->wb_page); |
243 | 243 | ||
244 | nfs_page_group_lock(req, true); | 244 | nfs_page_group_lock(req, false); |
245 | 245 | ||
246 | do { | 246 | do { |
247 | tmp = nfs_page_group_search_locked(req->wb_head, pos); | 247 | tmp = nfs_page_group_search_locked(req->wb_head, pos); |
@@ -478,10 +478,23 @@ try_again: | |||
478 | return NULL; | 478 | return NULL; |
479 | } | 479 | } |
480 | 480 | ||
481 | /* lock each request in the page group */ | 481 | /* holding inode lock, so always make a non-blocking call to try the |
482 | ret = nfs_page_group_lock(head, false); | 482 | * page group lock */ |
483 | if (ret < 0) | 483 | ret = nfs_page_group_lock(head, true); |
484 | if (ret < 0) { | ||
485 | spin_unlock(&inode->i_lock); | ||
486 | |||
487 | if (!nonblock && ret == -EAGAIN) { | ||
488 | nfs_page_group_lock_wait(head); | ||
489 | nfs_release_request(head); | ||
490 | goto try_again; | ||
491 | } | ||
492 | |||
493 | nfs_release_request(head); | ||
484 | return ERR_PTR(ret); | 494 | return ERR_PTR(ret); |
495 | } | ||
496 | |||
497 | /* lock each request in the page group */ | ||
485 | subreq = head; | 498 | subreq = head; |
486 | do { | 499 | do { |
487 | /* | 500 | /* |