aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFred Isaman <iisaman@netapp.com>2012-04-20 14:47:38 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-04-27 14:10:36 -0400
commit799ba8d53d32c84bd2a867ca2689538a48176140 (patch)
treee17ad842898a2c9b63183f7a435c984191336859
parent1acbbb4e16209e85c35ff6cacad61d802c07289b (diff)
NFS4.1: Add lseg to struct nfs4_fl_commit_bucket
Also create a commit_info structure to hold the bucket array and push it up from the lseg to the layout where it really belongs. While we are at it, fix a refcounting bug due to an (incorrect) implicit assumption that filelayout_scan_ds_commit_list always completely emptied the src list. This clarifies refcounting, removes the ugly find_only_write_lseg functions, and pushes the file layout commit code along on the path to supporting multiple lsegs. Signed-off-by: Fred Isaman <iisaman@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/nfs4filelayout.c216
-rw-r--r--fs/nfs/nfs4filelayout.h20
2 files changed, 144 insertions, 92 deletions
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 5acfd9ea8a31..15aeba20d57d 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -650,10 +650,66 @@ filelayout_free_lseg(struct pnfs_layout_segment *lseg)
650 650
651 dprintk("--> %s\n", __func__); 651 dprintk("--> %s\n", __func__);
652 nfs4_fl_put_deviceid(fl->dsaddr); 652 nfs4_fl_put_deviceid(fl->dsaddr);
653 kfree(fl->commit_buckets); 653 /* This assumes a single RW lseg */
654 if (lseg->pls_range.iomode == IOMODE_RW) {
655 struct nfs4_filelayout *flo;
656
657 flo = FILELAYOUT_FROM_HDR(lseg->pls_layout);
658 flo->commit_info.nbuckets = 0;
659 kfree(flo->commit_info.buckets);
660 flo->commit_info.buckets = NULL;
661 }
654 _filelayout_free_lseg(fl); 662 _filelayout_free_lseg(fl);
655} 663}
656 664
665static int
666filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg,
667 gfp_t gfp_flags)
668{
669 struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
670 struct nfs4_filelayout *flo = FILELAYOUT_FROM_HDR(lseg->pls_layout);
671
672 struct nfs4_fl_commit_bucket *buckets;
673 int size;
674
675 if (fl->commit_through_mds)
676 return 0;
677 if (flo->commit_info.nbuckets != 0) {
678 /* This assumes there is only one IOMODE_RW lseg. What
679 * we really want to do is have a layout_hdr level
680 * dictionary of <multipath_list4, fh> keys, each
681 * associated with a struct list_head, populated by calls
682 * to filelayout_write_pagelist().
683 * */
684 return 0;
685 }
686
687 size = (fl->stripe_type == STRIPE_SPARSE) ?
688 fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
689
690 buckets = kcalloc(size, sizeof(struct nfs4_fl_commit_bucket),
691 gfp_flags);
692 if (!buckets)
693 return -ENOMEM;
694 else {
695 int i;
696
697 spin_lock(&lseg->pls_layout->plh_inode->i_lock);
698 if (flo->commit_info.nbuckets != 0)
699 kfree(buckets);
700 else {
701 flo->commit_info.buckets = buckets;
702 flo->commit_info.nbuckets = size;
703 for (i = 0; i < size; i++) {
704 INIT_LIST_HEAD(&buckets[i].written);
705 INIT_LIST_HEAD(&buckets[i].committing);
706 }
707 }
708 spin_unlock(&lseg->pls_layout->plh_inode->i_lock);
709 return 0;
710 }
711}
712
657static struct pnfs_layout_segment * 713static struct pnfs_layout_segment *
658filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid, 714filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
659 struct nfs4_layoutget_res *lgr, 715 struct nfs4_layoutget_res *lgr,
@@ -673,29 +729,6 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
673 _filelayout_free_lseg(fl); 729 _filelayout_free_lseg(fl);
674 return NULL; 730 return NULL;
675 } 731 }
676
677 /* This assumes there is only one IOMODE_RW lseg. What
678 * we really want to do is have a layout_hdr level
679 * dictionary of <multipath_list4, fh> keys, each
680 * associated with a struct list_head, populated by calls
681 * to filelayout_write_pagelist().
682 * */
683 if ((!fl->commit_through_mds) && (lgr->range.iomode == IOMODE_RW)) {
684 int i;
685 int size = (fl->stripe_type == STRIPE_SPARSE) ?
686 fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
687
688 fl->commit_buckets = kcalloc(size, sizeof(struct nfs4_fl_commit_bucket), gfp_flags);
689 if (!fl->commit_buckets) {
690 filelayout_free_lseg(&fl->generic_hdr);
691 return NULL;
692 }
693 fl->number_of_buckets = size;
694 for (i = 0; i < size; i++) {
695 INIT_LIST_HEAD(&fl->commit_buckets[i].written);
696 INIT_LIST_HEAD(&fl->commit_buckets[i].committing);
697 }
698 }
699 return &fl->generic_hdr; 732 return &fl->generic_hdr;
700} 733}
701 734
@@ -747,6 +780,8 @@ static void
747filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, 780filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
748 struct nfs_page *req) 781 struct nfs_page *req)
749{ 782{
783 int status;
784
750 BUG_ON(pgio->pg_lseg != NULL); 785 BUG_ON(pgio->pg_lseg != NULL);
751 786
752 pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, 787 pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
@@ -757,7 +792,16 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
757 GFP_NOFS); 792 GFP_NOFS);
758 /* If no lseg, fall back to write through mds */ 793 /* If no lseg, fall back to write through mds */
759 if (pgio->pg_lseg == NULL) 794 if (pgio->pg_lseg == NULL)
760 nfs_pageio_reset_write_mds(pgio); 795 goto out_mds;
796 status = filelayout_alloc_commit_info(pgio->pg_lseg, GFP_NOFS);
797 if (status < 0) {
798 put_lseg(pgio->pg_lseg);
799 pgio->pg_lseg = NULL;
800 goto out_mds;
801 }
802 return;
803out_mds:
804 nfs_pageio_reset_write_mds(pgio);
761} 805}
762 806
763static const struct nfs_pageio_ops filelayout_pg_read_ops = { 807static const struct nfs_pageio_ops filelayout_pg_read_ops = {
@@ -793,17 +837,13 @@ filelayout_clear_request_commit(struct nfs_page *req)
793 if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags)) 837 if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags))
794 goto out; 838 goto out;
795 if (list_is_singular(&req->wb_list)) { 839 if (list_is_singular(&req->wb_list)) {
796 struct pnfs_layout_segment *lseg; 840 struct nfs4_fl_commit_bucket *bucket;
797 841
798 /* From here we can find the bucket, but for the moment, 842 bucket = list_first_entry(&req->wb_list,
799 * since there is only one relevant lseg... 843 struct nfs4_fl_commit_bucket,
800 */ 844 written);
801 list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) { 845 freeme = bucket->wlseg;
802 if (lseg->pls_range.iomode == IOMODE_RW) { 846 bucket->wlseg = NULL;
803 freeme = lseg;
804 break;
805 }
806 }
807 } 847 }
808out: 848out:
809 nfs_request_remove_commit_list(req); 849 nfs_request_remove_commit_list(req);
@@ -818,6 +858,7 @@ filelayout_choose_commit_list(struct nfs_page *req,
818 struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); 858 struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
819 u32 i, j; 859 u32 i, j;
820 struct list_head *list; 860 struct list_head *list;
861 struct nfs4_fl_commit_bucket *buckets;
821 862
822 if (fl->commit_through_mds) 863 if (fl->commit_through_mds)
823 return &NFS_I(req->wb_context->dentry->d_inode)->commit_list; 864 return &NFS_I(req->wb_context->dentry->d_inode)->commit_list;
@@ -831,15 +872,16 @@ filelayout_choose_commit_list(struct nfs_page *req,
831 j = nfs4_fl_calc_j_index(lseg, 872 j = nfs4_fl_calc_j_index(lseg,
832 (loff_t)req->wb_index << PAGE_CACHE_SHIFT); 873 (loff_t)req->wb_index << PAGE_CACHE_SHIFT);
833 i = select_bucket_index(fl, j); 874 i = select_bucket_index(fl, j);
834 list = &fl->commit_buckets[i].written; 875 buckets = FILELAYOUT_FROM_HDR(lseg->pls_layout)->commit_info.buckets;
876 list = &buckets[i].written;
835 if (list_empty(list)) { 877 if (list_empty(list)) {
836 /* Non-empty buckets hold a reference on the lseg. That ref 878 /* Non-empty buckets hold a reference on the lseg. That ref
837 * is normally transferred to the COMMIT call and released 879 * is normally transferred to the COMMIT call and released
838 * there. It could also be released if the last req is pulled 880 * there. It could also be released if the last req is pulled
839 * off due to a rewrite, in which case it will be done in 881 * off due to a rewrite, in which case it will be done in
840 * filelayout_remove_commit_req 882 * filelayout_clear_request_commit
841 */ 883 */
842 get_lseg(lseg); 884 buckets[i].wlseg = get_lseg(lseg);
843 } 885 }
844 set_bit(PG_COMMIT_TO_DS, &req->wb_flags); 886 set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
845 return list; 887 return list;
@@ -908,32 +950,6 @@ static int filelayout_initiate_commit(struct nfs_write_data *data, int how)
908 &filelayout_commit_call_ops, how); 950 &filelayout_commit_call_ops, how);
909} 951}
910 952
911/*
912 * This is only useful while we are using whole file layouts.
913 */
914static struct pnfs_layout_segment *
915find_only_write_lseg_locked(struct inode *inode)
916{
917 struct pnfs_layout_segment *lseg;
918
919 list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list)
920 if (lseg->pls_range.iomode == IOMODE_RW)
921 return lseg;
922 return NULL;
923}
924
925static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode)
926{
927 struct pnfs_layout_segment *rv;
928
929 spin_lock(&inode->i_lock);
930 rv = find_only_write_lseg_locked(inode);
931 if (rv)
932 get_lseg(rv);
933 spin_unlock(&inode->i_lock);
934 return rv;
935}
936
937static int 953static int
938filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max, 954filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max,
939 spinlock_t *lock) 955 spinlock_t *lock)
@@ -955,6 +971,13 @@ filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max,
955 if (ret == max) 971 if (ret == max)
956 break; 972 break;
957 } 973 }
974 if (ret) {
975 bucket->clseg = bucket->wlseg;
976 if (list_empty(src))
977 bucket->wlseg = NULL;
978 else
979 get_lseg(bucket->clseg);
980 }
958 return ret; 981 return ret;
959} 982}
960 983
@@ -964,18 +987,14 @@ filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max,
964static int filelayout_scan_commit_lists(struct inode *inode, int max, 987static int filelayout_scan_commit_lists(struct inode *inode, int max,
965 spinlock_t *lock) 988 spinlock_t *lock)
966{ 989{
967 struct pnfs_layout_segment *lseg; 990 struct nfs4_fl_commit_info *fl_cinfo;
968 struct nfs4_filelayout_segment *fl;
969 int i, rv = 0, cnt; 991 int i, rv = 0, cnt;
970 992
971 lseg = find_only_write_lseg_locked(inode); 993 fl_cinfo = &FILELAYOUT_FROM_HDR(NFS_I(inode)->layout)->commit_info;
972 if (!lseg) 994 if (fl_cinfo->nbuckets == 0)
973 goto out_done;
974 fl = FILELAYOUT_LSEG(lseg);
975 if (fl->commit_through_mds)
976 goto out_done; 995 goto out_done;
977 for (i = 0; i < fl->number_of_buckets && max != 0; i++) { 996 for (i = 0; i < fl_cinfo->nbuckets && max != 0; i++) {
978 cnt = filelayout_scan_ds_commit_list(&fl->commit_buckets[i], 997 cnt = filelayout_scan_ds_commit_list(&fl_cinfo->buckets[i],
979 max, lock); 998 max, lock);
980 max -= cnt; 999 max -= cnt;
981 rv += cnt; 1000 rv += cnt;
@@ -987,38 +1006,35 @@ out_done:
987static unsigned int 1006static unsigned int
988alloc_ds_commits(struct inode *inode, struct list_head *list) 1007alloc_ds_commits(struct inode *inode, struct list_head *list)
989{ 1008{
990 struct pnfs_layout_segment *lseg; 1009 struct nfs4_fl_commit_info *fl_cinfo;
991 struct nfs4_filelayout_segment *fl; 1010 struct nfs4_fl_commit_bucket *bucket;
992 struct nfs_write_data *data; 1011 struct nfs_write_data *data;
993 int i, j; 1012 int i, j;
994 unsigned int nreq = 0; 1013 unsigned int nreq = 0;
995 1014
996 /* Won't need this when non-whole file layout segments are supported 1015 fl_cinfo = &FILELAYOUT_FROM_HDR(NFS_I(inode)->layout)->commit_info;
997 * instead we will use a pnfs_layout_hdr structure */ 1016 bucket = fl_cinfo->buckets;
998 lseg = find_only_write_lseg(inode); 1017 for (i = 0; i < fl_cinfo->nbuckets; i++, bucket++) {
999 if (!lseg) 1018 if (list_empty(&bucket->committing))
1000 return 0;
1001 fl = FILELAYOUT_LSEG(lseg);
1002 for (i = 0; i < fl->number_of_buckets; i++) {
1003 if (list_empty(&fl->commit_buckets[i].committing))
1004 continue; 1019 continue;
1005 data = nfs_commitdata_alloc(); 1020 data = nfs_commitdata_alloc();
1006 if (!data) 1021 if (!data)
1007 break; 1022 break;
1008 data->ds_commit_index = i; 1023 data->ds_commit_index = i;
1009 data->lseg = lseg; 1024 data->lseg = bucket->clseg;
1025 bucket->clseg = NULL;
1010 list_add(&data->pages, list); 1026 list_add(&data->pages, list);
1011 nreq++; 1027 nreq++;
1012 } 1028 }
1013 1029
1014 /* Clean up on error */ 1030 /* Clean up on error */
1015 for (j = i; j < fl->number_of_buckets; j++) { 1031 for (j = i; j < fl_cinfo->nbuckets; j++, bucket++) {
1016 if (list_empty(&fl->commit_buckets[i].committing)) 1032 if (list_empty(&bucket->committing))
1017 continue; 1033 continue;
1018 nfs_retry_commit(&fl->commit_buckets[i].committing, lseg); 1034 nfs_retry_commit(&bucket->committing, bucket->clseg);
1019 put_lseg(lseg); /* associated with emptying bucket */ 1035 put_lseg(bucket->clseg);
1036 bucket->clseg = NULL;
1020 } 1037 }
1021 put_lseg(lseg);
1022 /* Caller will clean up entries put on list */ 1038 /* Caller will clean up entries put on list */
1023 return nreq; 1039 return nreq;
1024} 1040}
@@ -1058,7 +1074,10 @@ filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
1058 nfs_initiate_commit(data, NFS_CLIENT(inode), 1074 nfs_initiate_commit(data, NFS_CLIENT(inode),
1059 data->mds_ops, how); 1075 data->mds_ops, how);
1060 } else { 1076 } else {
1061 nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index].committing, data->lseg); 1077 struct nfs4_fl_commit_info *fl_cinfo;
1078
1079 fl_cinfo = &FILELAYOUT_FROM_HDR(data->lseg->pls_layout)->commit_info;
1080 nfs_init_commit(data, &fl_cinfo->buckets[data->ds_commit_index].committing, data->lseg);
1062 filelayout_initiate_commit(data, how); 1081 filelayout_initiate_commit(data, how);
1063 } 1082 }
1064 } 1083 }
@@ -1072,10 +1091,27 @@ filelayout_free_deveiceid_node(struct nfs4_deviceid_node *d)
1072 nfs4_fl_free_deviceid(container_of(d, struct nfs4_file_layout_dsaddr, id_node)); 1091 nfs4_fl_free_deviceid(container_of(d, struct nfs4_file_layout_dsaddr, id_node));
1073} 1092}
1074 1093
1094static struct pnfs_layout_hdr *
1095filelayout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags)
1096{
1097 struct nfs4_filelayout *flo;
1098
1099 flo = kzalloc(sizeof(*flo), gfp_flags);
1100 return &flo->generic_hdr;
1101}
1102
1103static void
1104filelayout_free_layout_hdr(struct pnfs_layout_hdr *lo)
1105{
1106 kfree(FILELAYOUT_FROM_HDR(lo));
1107}
1108
1075static struct pnfs_layoutdriver_type filelayout_type = { 1109static struct pnfs_layoutdriver_type filelayout_type = {
1076 .id = LAYOUT_NFSV4_1_FILES, 1110 .id = LAYOUT_NFSV4_1_FILES,
1077 .name = "LAYOUT_NFSV4_1_FILES", 1111 .name = "LAYOUT_NFSV4_1_FILES",
1078 .owner = THIS_MODULE, 1112 .owner = THIS_MODULE,
1113 .alloc_layout_hdr = filelayout_alloc_layout_hdr,
1114 .free_layout_hdr = filelayout_free_layout_hdr,
1079 .alloc_lseg = filelayout_alloc_lseg, 1115 .alloc_lseg = filelayout_alloc_lseg,
1080 .free_lseg = filelayout_free_lseg, 1116 .free_lseg = filelayout_free_lseg,
1081 .pg_read_ops = &filelayout_pg_read_ops, 1117 .pg_read_ops = &filelayout_pg_read_ops,
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h
index 21190bb1f5e3..333a3ac97606 100644
--- a/fs/nfs/nfs4filelayout.h
+++ b/fs/nfs/nfs4filelayout.h
@@ -77,6 +77,13 @@ struct nfs4_file_layout_dsaddr {
77struct nfs4_fl_commit_bucket { 77struct nfs4_fl_commit_bucket {
78 struct list_head written; 78 struct list_head written;
79 struct list_head committing; 79 struct list_head committing;
80 struct pnfs_layout_segment *wlseg;
81 struct pnfs_layout_segment *clseg;
82};
83
84struct nfs4_fl_commit_info {
85 int nbuckets;
86 struct nfs4_fl_commit_bucket *buckets;
80}; 87};
81 88
82struct nfs4_filelayout_segment { 89struct nfs4_filelayout_segment {
@@ -89,10 +96,19 @@ struct nfs4_filelayout_segment {
89 struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */ 96 struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */
90 unsigned int num_fh; 97 unsigned int num_fh;
91 struct nfs_fh **fh_array; 98 struct nfs_fh **fh_array;
92 struct nfs4_fl_commit_bucket *commit_buckets; /* Sort commits to ds */
93 int number_of_buckets;
94}; 99};
95 100
101struct nfs4_filelayout {
102 struct pnfs_layout_hdr generic_hdr;
103 struct nfs4_fl_commit_info commit_info;
104};
105
106static inline struct nfs4_filelayout *
107FILELAYOUT_FROM_HDR(struct pnfs_layout_hdr *lo)
108{
109 return container_of(lo, struct nfs4_filelayout, generic_hdr);
110}
111
96static inline struct nfs4_filelayout_segment * 112static inline struct nfs4_filelayout_segment *
97FILELAYOUT_LSEG(struct pnfs_layout_segment *lseg) 113FILELAYOUT_LSEG(struct pnfs_layout_segment *lseg)
98{ 114{