aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-03-16 13:52:45 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-03-17 11:17:42 -0400
commit9390f42546339cf111edd23c16d6cf74ca41974c (patch)
treef281aa1e7bed7fbf41c441eab605d6d7a1a9050b /fs/nfs
parent8dd3775889345850ecddd689b5c200cdd91bd8c9 (diff)
NFSv4.1: Fix a few issues in filelayout_commit_pagelist
- Fix a race in which NFS_I(inode)->commits_outstanding could potentially go to zero (triggering a call to nfs_commit_clear_lock()) before we're done sending out all the commit RPC calls. - If nfs_commitdata_alloc fails, there is no reason why we shouldn't try to send off all the commits-to-ds. - Simplify the error handling. - Change pnfs_commit_list() to always return either PNFS_ATTEMPTED or PNFS_NOT_ATTEMPTED. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: Fred Isaman <iisaman@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4filelayout.c47
1 files changed, 24 insertions, 23 deletions
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index c24e077c2820..e0bdbf4fe454 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -980,12 +980,14 @@ out_done:
980 return rv; 980 return rv;
981} 981}
982 982
983static int alloc_ds_commits(struct inode *inode, struct list_head *list) 983static unsigned int
984alloc_ds_commits(struct inode *inode, struct list_head *list)
984{ 985{
985 struct pnfs_layout_segment *lseg; 986 struct pnfs_layout_segment *lseg;
986 struct nfs4_filelayout_segment *fl; 987 struct nfs4_filelayout_segment *fl;
987 struct nfs_write_data *data; 988 struct nfs_write_data *data;
988 int i, j; 989 int i, j;
990 unsigned int nreq = 0;
989 991
990 /* Won't need this when non-whole file layout segments are supported 992 /* Won't need this when non-whole file layout segments are supported
991 * instead we will use a pnfs_layout_hdr structure */ 993 * instead we will use a pnfs_layout_hdr structure */
@@ -998,15 +1000,14 @@ static int alloc_ds_commits(struct inode *inode, struct list_head *list)
998 continue; 1000 continue;
999 data = nfs_commitdata_alloc(); 1001 data = nfs_commitdata_alloc();
1000 if (!data) 1002 if (!data)
1001 goto out_bad; 1003 break;
1002 data->ds_commit_index = i; 1004 data->ds_commit_index = i;
1003 data->lseg = lseg; 1005 data->lseg = lseg;
1004 list_add(&data->pages, list); 1006 list_add(&data->pages, list);
1007 nreq++;
1005 } 1008 }
1006 put_lseg(lseg);
1007 return 0;
1008 1009
1009out_bad: 1010 /* Clean up on error */
1010 for (j = i; j < fl->number_of_buckets; j++) { 1011 for (j = i; j < fl->number_of_buckets; j++) {
1011 if (list_empty(&fl->commit_buckets[i].committing)) 1012 if (list_empty(&fl->commit_buckets[i].committing))
1012 continue; 1013 continue;
@@ -1015,7 +1016,7 @@ out_bad:
1015 } 1016 }
1016 put_lseg(lseg); 1017 put_lseg(lseg);
1017 /* Caller will clean up entries put on list */ 1018 /* Caller will clean up entries put on list */
1018 return -ENOMEM; 1019 return nreq;
1019} 1020}
1020 1021
1021/* This follows nfs_commit_list pretty closely */ 1022/* This follows nfs_commit_list pretty closely */
@@ -1025,21 +1026,29 @@ filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
1025{ 1026{
1026 struct nfs_write_data *data, *tmp; 1027 struct nfs_write_data *data, *tmp;
1027 LIST_HEAD(list); 1028 LIST_HEAD(list);
1029 unsigned int nreq = 0;
1028 1030
1029 if (!list_empty(mds_pages)) { 1031 if (!list_empty(mds_pages)) {
1030 data = nfs_commitdata_alloc(); 1032 data = nfs_commitdata_alloc();
1031 if (!data) 1033 if (data != NULL) {
1032 goto out_bad; 1034 data->lseg = NULL;
1033 data->lseg = NULL; 1035 list_add(&data->pages, &list);
1034 list_add(&data->pages, &list); 1036 nreq++;
1037 } else
1038 nfs_retry_commit(mds_pages, NULL);
1035 } 1039 }
1036 1040
1037 if (alloc_ds_commits(inode, &list)) 1041 nreq += alloc_ds_commits(inode, &list);
1038 goto out_bad; 1042
1043 if (nreq == 0) {
1044 nfs_commit_clear_lock(NFS_I(inode));
1045 goto out;
1046 }
1047
1048 atomic_add(nreq, &NFS_I(inode)->commits_outstanding);
1039 1049
1040 list_for_each_entry_safe(data, tmp, &list, pages) { 1050 list_for_each_entry_safe(data, tmp, &list, pages) {
1041 list_del_init(&data->pages); 1051 list_del_init(&data->pages);
1042 atomic_inc(&NFS_I(inode)->commits_outstanding);
1043 if (!data->lseg) { 1052 if (!data->lseg) {
1044 nfs_init_commit(data, mds_pages, NULL); 1053 nfs_init_commit(data, mds_pages, NULL);
1045 nfs_initiate_commit(data, NFS_CLIENT(inode), 1054 nfs_initiate_commit(data, NFS_CLIENT(inode),
@@ -1049,16 +1058,8 @@ filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
1049 filelayout_initiate_commit(data, how); 1058 filelayout_initiate_commit(data, how);
1050 } 1059 }
1051 } 1060 }
1052 return 0; 1061out:
1053 out_bad: 1062 return PNFS_ATTEMPTED;
1054 list_for_each_entry_safe(data, tmp, &list, pages) {
1055 nfs_retry_commit(&data->pages, data->lseg);
1056 list_del_init(&data->pages);
1057 nfs_commit_free(data);
1058 }
1059 nfs_retry_commit(mds_pages, NULL);
1060 nfs_commit_clear_lock(NFS_I(inode));
1061 return -ENOMEM;
1062} 1063}
1063 1064
1064static void 1065static void