diff options
author | Fred Isaman <iisaman@netapp.com> | 2012-04-20 14:47:38 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-04-27 14:10:36 -0400 |
commit | 799ba8d53d32c84bd2a867ca2689538a48176140 (patch) | |
tree | e17ad842898a2c9b63183f7a435c984191336859 | |
parent | 1acbbb4e16209e85c35ff6cacad61d802c07289b (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.c | 216 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.h | 20 |
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 | ||
665 | static int | ||
666 | filelayout_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 | |||
657 | static struct pnfs_layout_segment * | 713 | static struct pnfs_layout_segment * |
658 | filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid, | 714 | filelayout_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 | |||
747 | filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, | 780 | filelayout_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; | ||
803 | out_mds: | ||
804 | nfs_pageio_reset_write_mds(pgio); | ||
761 | } | 805 | } |
762 | 806 | ||
763 | static const struct nfs_pageio_ops filelayout_pg_read_ops = { | 807 | static 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 | } |
808 | out: | 848 | out: |
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 | */ | ||
914 | static struct pnfs_layout_segment * | ||
915 | find_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 | |||
925 | static 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 | |||
937 | static int | 953 | static int |
938 | filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max, | 954 | filelayout_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, | |||
964 | static int filelayout_scan_commit_lists(struct inode *inode, int max, | 987 | static 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: | |||
987 | static unsigned int | 1006 | static unsigned int |
988 | alloc_ds_commits(struct inode *inode, struct list_head *list) | 1007 | alloc_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 | ||
1094 | static struct pnfs_layout_hdr * | ||
1095 | filelayout_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 | |||
1103 | static void | ||
1104 | filelayout_free_layout_hdr(struct pnfs_layout_hdr *lo) | ||
1105 | { | ||
1106 | kfree(FILELAYOUT_FROM_HDR(lo)); | ||
1107 | } | ||
1108 | |||
1075 | static struct pnfs_layoutdriver_type filelayout_type = { | 1109 | static 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 { | |||
77 | struct nfs4_fl_commit_bucket { | 77 | struct 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 | |||
84 | struct nfs4_fl_commit_info { | ||
85 | int nbuckets; | ||
86 | struct nfs4_fl_commit_bucket *buckets; | ||
80 | }; | 87 | }; |
81 | 88 | ||
82 | struct nfs4_filelayout_segment { | 89 | struct 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 | ||
101 | struct nfs4_filelayout { | ||
102 | struct pnfs_layout_hdr generic_hdr; | ||
103 | struct nfs4_fl_commit_info commit_info; | ||
104 | }; | ||
105 | |||
106 | static inline struct nfs4_filelayout * | ||
107 | FILELAYOUT_FROM_HDR(struct pnfs_layout_hdr *lo) | ||
108 | { | ||
109 | return container_of(lo, struct nfs4_filelayout, generic_hdr); | ||
110 | } | ||
111 | |||
96 | static inline struct nfs4_filelayout_segment * | 112 | static inline struct nfs4_filelayout_segment * |
97 | FILELAYOUT_LSEG(struct pnfs_layout_segment *lseg) | 113 | FILELAYOUT_LSEG(struct pnfs_layout_segment *lseg) |
98 | { | 114 | { |