diff options
-rw-r--r-- | fs/nfs/inode.c | 6 | ||||
-rw-r--r-- | fs/nfs/internal.h | 12 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 119 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.h | 14 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 72 | ||||
-rw-r--r-- | fs/nfs/write.c | 158 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 5 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 27 |
8 files changed, 248 insertions, 165 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index e8bbfa5b3500..59a12c6a8df6 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -1547,7 +1547,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi) | |||
1547 | nfsi->delegation_state = 0; | 1547 | nfsi->delegation_state = 0; |
1548 | init_rwsem(&nfsi->rwsem); | 1548 | init_rwsem(&nfsi->rwsem); |
1549 | nfsi->layout = NULL; | 1549 | nfsi->layout = NULL; |
1550 | atomic_set(&nfsi->commits_outstanding, 0); | 1550 | atomic_set(&nfsi->commit_info.rpcs_out, 0); |
1551 | #endif | 1551 | #endif |
1552 | } | 1552 | } |
1553 | 1553 | ||
@@ -1559,9 +1559,9 @@ static void init_once(void *foo) | |||
1559 | INIT_LIST_HEAD(&nfsi->open_files); | 1559 | INIT_LIST_HEAD(&nfsi->open_files); |
1560 | INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); | 1560 | INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); |
1561 | INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); | 1561 | INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); |
1562 | INIT_LIST_HEAD(&nfsi->commit_list); | 1562 | INIT_LIST_HEAD(&nfsi->commit_info.list); |
1563 | nfsi->npages = 0; | 1563 | nfsi->npages = 0; |
1564 | nfsi->ncommit = 0; | 1564 | nfsi->commit_info.ncommit = 0; |
1565 | atomic_set(&nfsi->silly_count, 1); | 1565 | atomic_set(&nfsi->silly_count, 1); |
1566 | INIT_HLIST_HEAD(&nfsi->silly_list); | 1566 | INIT_HLIST_HEAD(&nfsi->silly_list); |
1567 | init_waitqueue_head(&nfsi->waitqueue); | 1567 | init_waitqueue_head(&nfsi->waitqueue); |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index cd5d4a300bc9..145e9e7dc8ce 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -346,12 +346,18 @@ extern void nfs_init_commit(struct nfs_commit_data *data, | |||
346 | struct list_head *head, | 346 | struct list_head *head, |
347 | struct pnfs_layout_segment *lseg); | 347 | struct pnfs_layout_segment *lseg); |
348 | void nfs_retry_commit(struct list_head *page_list, | 348 | void nfs_retry_commit(struct list_head *page_list, |
349 | struct pnfs_layout_segment *lseg); | 349 | struct pnfs_layout_segment *lseg, |
350 | struct nfs_commit_info *cinfo); | ||
350 | void nfs_commit_clear_lock(struct nfs_inode *nfsi); | 351 | void nfs_commit_clear_lock(struct nfs_inode *nfsi); |
351 | void nfs_commitdata_release(struct nfs_commit_data *data); | 352 | void nfs_commitdata_release(struct nfs_commit_data *data); |
352 | void nfs_commit_release_pages(struct nfs_commit_data *data); | 353 | void nfs_commit_release_pages(struct nfs_commit_data *data); |
353 | void nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head); | 354 | void nfs_request_add_commit_list(struct nfs_page *req, struct list_head *dst, |
354 | void nfs_request_remove_commit_list(struct nfs_page *req); | 355 | struct nfs_commit_info *cinfo); |
356 | void nfs_request_remove_commit_list(struct nfs_page *req, | ||
357 | struct nfs_commit_info *cinfo); | ||
358 | void nfs_init_cinfo(struct nfs_commit_info *cinfo, | ||
359 | struct inode *inode, | ||
360 | struct nfs_direct_req *dreq); | ||
355 | 361 | ||
356 | #ifdef CONFIG_MIGRATION | 362 | #ifdef CONFIG_MIGRATION |
357 | extern int nfs_migrate_page(struct address_space *, | 363 | extern int nfs_migrate_page(struct address_space *, |
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index e40523f2fe26..fe2cb55ca6b1 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -347,9 +347,11 @@ static void filelayout_commit_count_stats(struct rpc_task *task, void *data) | |||
347 | static void filelayout_commit_release(void *calldata) | 347 | static void filelayout_commit_release(void *calldata) |
348 | { | 348 | { |
349 | struct nfs_commit_data *data = calldata; | 349 | struct nfs_commit_data *data = calldata; |
350 | struct nfs_commit_info cinfo; | ||
350 | 351 | ||
351 | nfs_commit_release_pages(data); | 352 | nfs_commit_release_pages(data); |
352 | if (atomic_dec_and_test(&NFS_I(data->inode)->commits_outstanding)) | 353 | nfs_init_cinfo(&cinfo, data->inode, data->dreq); |
354 | if (atomic_dec_and_test(&cinfo.mds->rpcs_out)) | ||
353 | nfs_commit_clear_lock(NFS_I(data->inode)); | 355 | nfs_commit_clear_lock(NFS_I(data->inode)); |
354 | put_lseg(data->lseg); | 356 | put_lseg(data->lseg); |
355 | nfs_commitdata_release(data); | 357 | nfs_commitdata_release(data); |
@@ -695,17 +697,16 @@ filelayout_free_lseg(struct pnfs_layout_segment *lseg) | |||
695 | 697 | ||
696 | static int | 698 | static int |
697 | filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg, | 699 | filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg, |
700 | struct nfs_commit_info *cinfo, | ||
698 | gfp_t gfp_flags) | 701 | gfp_t gfp_flags) |
699 | { | 702 | { |
700 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); | 703 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); |
701 | struct nfs4_filelayout *flo = FILELAYOUT_FROM_HDR(lseg->pls_layout); | 704 | struct pnfs_commit_bucket *buckets; |
702 | |||
703 | struct nfs4_fl_commit_bucket *buckets; | ||
704 | int size; | 705 | int size; |
705 | 706 | ||
706 | if (fl->commit_through_mds) | 707 | if (fl->commit_through_mds) |
707 | return 0; | 708 | return 0; |
708 | if (flo->commit_info.nbuckets != 0) { | 709 | if (cinfo->ds->nbuckets != 0) { |
709 | /* This assumes there is only one IOMODE_RW lseg. What | 710 | /* This assumes there is only one IOMODE_RW lseg. What |
710 | * we really want to do is have a layout_hdr level | 711 | * we really want to do is have a layout_hdr level |
711 | * dictionary of <multipath_list4, fh> keys, each | 712 | * dictionary of <multipath_list4, fh> keys, each |
@@ -718,25 +719,25 @@ filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg, | |||
718 | size = (fl->stripe_type == STRIPE_SPARSE) ? | 719 | size = (fl->stripe_type == STRIPE_SPARSE) ? |
719 | fl->dsaddr->ds_num : fl->dsaddr->stripe_count; | 720 | fl->dsaddr->ds_num : fl->dsaddr->stripe_count; |
720 | 721 | ||
721 | buckets = kcalloc(size, sizeof(struct nfs4_fl_commit_bucket), | 722 | buckets = kcalloc(size, sizeof(struct pnfs_commit_bucket), |
722 | gfp_flags); | 723 | gfp_flags); |
723 | if (!buckets) | 724 | if (!buckets) |
724 | return -ENOMEM; | 725 | return -ENOMEM; |
725 | else { | 726 | else { |
726 | int i; | 727 | int i; |
727 | 728 | ||
728 | spin_lock(&lseg->pls_layout->plh_inode->i_lock); | 729 | spin_lock(cinfo->lock); |
729 | if (flo->commit_info.nbuckets != 0) | 730 | if (cinfo->ds->nbuckets != 0) |
730 | kfree(buckets); | 731 | kfree(buckets); |
731 | else { | 732 | else { |
732 | flo->commit_info.buckets = buckets; | 733 | cinfo->ds->buckets = buckets; |
733 | flo->commit_info.nbuckets = size; | 734 | cinfo->ds->nbuckets = size; |
734 | for (i = 0; i < size; i++) { | 735 | for (i = 0; i < size; i++) { |
735 | INIT_LIST_HEAD(&buckets[i].written); | 736 | INIT_LIST_HEAD(&buckets[i].written); |
736 | INIT_LIST_HEAD(&buckets[i].committing); | 737 | INIT_LIST_HEAD(&buckets[i].committing); |
737 | } | 738 | } |
738 | } | 739 | } |
739 | spin_unlock(&lseg->pls_layout->plh_inode->i_lock); | 740 | spin_unlock(cinfo->lock); |
740 | return 0; | 741 | return 0; |
741 | } | 742 | } |
742 | } | 743 | } |
@@ -821,6 +822,7 @@ static void | |||
821 | filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, | 822 | filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, |
822 | struct nfs_page *req) | 823 | struct nfs_page *req) |
823 | { | 824 | { |
825 | struct nfs_commit_info cinfo; | ||
824 | int status; | 826 | int status; |
825 | 827 | ||
826 | BUG_ON(pgio->pg_lseg != NULL); | 828 | BUG_ON(pgio->pg_lseg != NULL); |
@@ -836,7 +838,8 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, | |||
836 | /* If no lseg, fall back to write through mds */ | 838 | /* If no lseg, fall back to write through mds */ |
837 | if (pgio->pg_lseg == NULL) | 839 | if (pgio->pg_lseg == NULL) |
838 | goto out_mds; | 840 | goto out_mds; |
839 | status = filelayout_alloc_commit_info(pgio->pg_lseg, GFP_NOFS); | 841 | nfs_init_cinfo(&cinfo, pgio->pg_inode, pgio->pg_dreq); |
842 | status = filelayout_alloc_commit_info(pgio->pg_lseg, &cinfo, GFP_NOFS); | ||
840 | if (status < 0) { | 843 | if (status < 0) { |
841 | put_lseg(pgio->pg_lseg); | 844 | put_lseg(pgio->pg_lseg); |
842 | pgio->pg_lseg = NULL; | 845 | pgio->pg_lseg = NULL; |
@@ -871,40 +874,42 @@ static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) | |||
871 | * If this will make the bucket empty, it will need to put the lseg reference. | 874 | * If this will make the bucket empty, it will need to put the lseg reference. |
872 | */ | 875 | */ |
873 | static void | 876 | static void |
874 | filelayout_clear_request_commit(struct nfs_page *req) | 877 | filelayout_clear_request_commit(struct nfs_page *req, |
878 | struct nfs_commit_info *cinfo) | ||
875 | { | 879 | { |
876 | struct pnfs_layout_segment *freeme = NULL; | 880 | struct pnfs_layout_segment *freeme = NULL; |
877 | struct inode *inode = req->wb_context->dentry->d_inode; | ||
878 | 881 | ||
879 | spin_lock(&inode->i_lock); | 882 | spin_lock(cinfo->lock); |
880 | if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags)) | 883 | if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags)) |
881 | goto out; | 884 | goto out; |
885 | cinfo->ds->nwritten--; | ||
882 | if (list_is_singular(&req->wb_list)) { | 886 | if (list_is_singular(&req->wb_list)) { |
883 | struct nfs4_fl_commit_bucket *bucket; | 887 | struct pnfs_commit_bucket *bucket; |
884 | 888 | ||
885 | bucket = list_first_entry(&req->wb_list, | 889 | bucket = list_first_entry(&req->wb_list, |
886 | struct nfs4_fl_commit_bucket, | 890 | struct pnfs_commit_bucket, |
887 | written); | 891 | written); |
888 | freeme = bucket->wlseg; | 892 | freeme = bucket->wlseg; |
889 | bucket->wlseg = NULL; | 893 | bucket->wlseg = NULL; |
890 | } | 894 | } |
891 | out: | 895 | out: |
892 | nfs_request_remove_commit_list(req); | 896 | nfs_request_remove_commit_list(req, cinfo); |
893 | spin_unlock(&inode->i_lock); | 897 | spin_unlock(cinfo->lock); |
894 | put_lseg(freeme); | 898 | put_lseg(freeme); |
895 | } | 899 | } |
896 | 900 | ||
897 | static struct list_head * | 901 | static struct list_head * |
898 | filelayout_choose_commit_list(struct nfs_page *req, | 902 | filelayout_choose_commit_list(struct nfs_page *req, |
899 | struct pnfs_layout_segment *lseg) | 903 | struct pnfs_layout_segment *lseg, |
904 | struct nfs_commit_info *cinfo) | ||
900 | { | 905 | { |
901 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); | 906 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); |
902 | u32 i, j; | 907 | u32 i, j; |
903 | struct list_head *list; | 908 | struct list_head *list; |
904 | struct nfs4_fl_commit_bucket *buckets; | 909 | struct pnfs_commit_bucket *buckets; |
905 | 910 | ||
906 | if (fl->commit_through_mds) | 911 | if (fl->commit_through_mds) |
907 | return &NFS_I(req->wb_context->dentry->d_inode)->commit_list; | 912 | return &cinfo->mds->list; |
908 | 913 | ||
909 | /* Note that we are calling nfs4_fl_calc_j_index on each page | 914 | /* Note that we are calling nfs4_fl_calc_j_index on each page |
910 | * that ends up being committed to a data server. An attractive | 915 | * that ends up being committed to a data server. An attractive |
@@ -914,7 +919,7 @@ filelayout_choose_commit_list(struct nfs_page *req, | |||
914 | */ | 919 | */ |
915 | j = nfs4_fl_calc_j_index(lseg, req_offset(req)); | 920 | j = nfs4_fl_calc_j_index(lseg, req_offset(req)); |
916 | i = select_bucket_index(fl, j); | 921 | i = select_bucket_index(fl, j); |
917 | buckets = FILELAYOUT_FROM_HDR(lseg->pls_layout)->commit_info.buckets; | 922 | buckets = cinfo->ds->buckets; |
918 | list = &buckets[i].written; | 923 | list = &buckets[i].written; |
919 | if (list_empty(list)) { | 924 | if (list_empty(list)) { |
920 | /* Non-empty buckets hold a reference on the lseg. That ref | 925 | /* Non-empty buckets hold a reference on the lseg. That ref |
@@ -926,17 +931,19 @@ filelayout_choose_commit_list(struct nfs_page *req, | |||
926 | buckets[i].wlseg = get_lseg(lseg); | 931 | buckets[i].wlseg = get_lseg(lseg); |
927 | } | 932 | } |
928 | set_bit(PG_COMMIT_TO_DS, &req->wb_flags); | 933 | set_bit(PG_COMMIT_TO_DS, &req->wb_flags); |
934 | cinfo->ds->nwritten++; | ||
929 | return list; | 935 | return list; |
930 | } | 936 | } |
931 | 937 | ||
932 | static void | 938 | static void |
933 | filelayout_mark_request_commit(struct nfs_page *req, | 939 | filelayout_mark_request_commit(struct nfs_page *req, |
934 | struct pnfs_layout_segment *lseg) | 940 | struct pnfs_layout_segment *lseg, |
941 | struct nfs_commit_info *cinfo) | ||
935 | { | 942 | { |
936 | struct list_head *list; | 943 | struct list_head *list; |
937 | 944 | ||
938 | list = filelayout_choose_commit_list(req, lseg); | 945 | list = filelayout_choose_commit_list(req, lseg, cinfo); |
939 | nfs_request_add_commit_list(req, list); | 946 | nfs_request_add_commit_list(req, list, cinfo); |
940 | } | 947 | } |
941 | 948 | ||
942 | static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) | 949 | static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) |
@@ -993,8 +1000,9 @@ static int filelayout_initiate_commit(struct nfs_commit_data *data, int how) | |||
993 | } | 1000 | } |
994 | 1001 | ||
995 | static int | 1002 | static int |
996 | filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max, | 1003 | filelayout_scan_ds_commit_list(struct pnfs_commit_bucket *bucket, |
997 | spinlock_t *lock) | 1004 | struct nfs_commit_info *cinfo, |
1005 | int max) | ||
998 | { | 1006 | { |
999 | struct list_head *src = &bucket->written; | 1007 | struct list_head *src = &bucket->written; |
1000 | struct list_head *dst = &bucket->committing; | 1008 | struct list_head *dst = &bucket->committing; |
@@ -1004,9 +1012,9 @@ filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max, | |||
1004 | list_for_each_entry_safe(req, tmp, src, wb_list) { | 1012 | list_for_each_entry_safe(req, tmp, src, wb_list) { |
1005 | if (!nfs_lock_request(req)) | 1013 | if (!nfs_lock_request(req)) |
1006 | continue; | 1014 | continue; |
1007 | if (cond_resched_lock(lock)) | 1015 | if (cond_resched_lock(cinfo->lock)) |
1008 | list_safe_reset_next(req, tmp, wb_list); | 1016 | list_safe_reset_next(req, tmp, wb_list); |
1009 | nfs_request_remove_commit_list(req); | 1017 | nfs_request_remove_commit_list(req, cinfo); |
1010 | clear_bit(PG_COMMIT_TO_DS, &req->wb_flags); | 1018 | clear_bit(PG_COMMIT_TO_DS, &req->wb_flags); |
1011 | nfs_list_add_request(req, dst); | 1019 | nfs_list_add_request(req, dst); |
1012 | ret++; | 1020 | ret++; |
@@ -1014,6 +1022,8 @@ filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max, | |||
1014 | break; | 1022 | break; |
1015 | } | 1023 | } |
1016 | if (ret) { | 1024 | if (ret) { |
1025 | cinfo->ds->nwritten -= ret; | ||
1026 | cinfo->ds->ncommitting += ret; | ||
1017 | bucket->clseg = bucket->wlseg; | 1027 | bucket->clseg = bucket->wlseg; |
1018 | if (list_empty(src)) | 1028 | if (list_empty(src)) |
1019 | bucket->wlseg = NULL; | 1029 | bucket->wlseg = NULL; |
@@ -1024,37 +1034,32 @@ filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max, | |||
1024 | } | 1034 | } |
1025 | 1035 | ||
1026 | /* Move reqs from written to committing lists, returning count of number moved. | 1036 | /* Move reqs from written to committing lists, returning count of number moved. |
1027 | * Note called with i_lock held. | 1037 | * Note called with cinfo->lock held. |
1028 | */ | 1038 | */ |
1029 | static int filelayout_scan_commit_lists(struct inode *inode, int max, | 1039 | static int filelayout_scan_commit_lists(struct nfs_commit_info *cinfo, |
1030 | spinlock_t *lock) | 1040 | int max) |
1031 | { | 1041 | { |
1032 | struct nfs4_fl_commit_info *fl_cinfo; | ||
1033 | int i, rv = 0, cnt; | 1042 | int i, rv = 0, cnt; |
1034 | 1043 | ||
1035 | fl_cinfo = &FILELAYOUT_FROM_HDR(NFS_I(inode)->layout)->commit_info; | 1044 | for (i = 0; i < cinfo->ds->nbuckets && max != 0; i++) { |
1036 | if (fl_cinfo->nbuckets == 0) | 1045 | cnt = filelayout_scan_ds_commit_list(&cinfo->ds->buckets[i], |
1037 | goto out_done; | 1046 | cinfo, max); |
1038 | for (i = 0; i < fl_cinfo->nbuckets && max != 0; i++) { | ||
1039 | cnt = filelayout_scan_ds_commit_list(&fl_cinfo->buckets[i], | ||
1040 | max, lock); | ||
1041 | max -= cnt; | 1047 | max -= cnt; |
1042 | rv += cnt; | 1048 | rv += cnt; |
1043 | } | 1049 | } |
1044 | out_done: | ||
1045 | return rv; | 1050 | return rv; |
1046 | } | 1051 | } |
1047 | 1052 | ||
1048 | static unsigned int | 1053 | static unsigned int |
1049 | alloc_ds_commits(struct inode *inode, struct list_head *list) | 1054 | alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list) |
1050 | { | 1055 | { |
1051 | struct nfs4_fl_commit_info *fl_cinfo; | 1056 | struct pnfs_ds_commit_info *fl_cinfo; |
1052 | struct nfs4_fl_commit_bucket *bucket; | 1057 | struct pnfs_commit_bucket *bucket; |
1053 | struct nfs_commit_data *data; | 1058 | struct nfs_commit_data *data; |
1054 | int i, j; | 1059 | int i, j; |
1055 | unsigned int nreq = 0; | 1060 | unsigned int nreq = 0; |
1056 | 1061 | ||
1057 | fl_cinfo = &FILELAYOUT_FROM_HDR(NFS_I(inode)->layout)->commit_info; | 1062 | fl_cinfo = cinfo->ds; |
1058 | bucket = fl_cinfo->buckets; | 1063 | bucket = fl_cinfo->buckets; |
1059 | for (i = 0; i < fl_cinfo->nbuckets; i++, bucket++) { | 1064 | for (i = 0; i < fl_cinfo->nbuckets; i++, bucket++) { |
1060 | if (list_empty(&bucket->committing)) | 1065 | if (list_empty(&bucket->committing)) |
@@ -1073,7 +1078,7 @@ alloc_ds_commits(struct inode *inode, struct list_head *list) | |||
1073 | for (j = i; j < fl_cinfo->nbuckets; j++, bucket++) { | 1078 | for (j = i; j < fl_cinfo->nbuckets; j++, bucket++) { |
1074 | if (list_empty(&bucket->committing)) | 1079 | if (list_empty(&bucket->committing)) |
1075 | continue; | 1080 | continue; |
1076 | nfs_retry_commit(&bucket->committing, bucket->clseg); | 1081 | nfs_retry_commit(&bucket->committing, bucket->clseg, cinfo); |
1077 | put_lseg(bucket->clseg); | 1082 | put_lseg(bucket->clseg); |
1078 | bucket->clseg = NULL; | 1083 | bucket->clseg = NULL; |
1079 | } | 1084 | } |
@@ -1084,7 +1089,7 @@ alloc_ds_commits(struct inode *inode, struct list_head *list) | |||
1084 | /* This follows nfs_commit_list pretty closely */ | 1089 | /* This follows nfs_commit_list pretty closely */ |
1085 | static int | 1090 | static int |
1086 | filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages, | 1091 | filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages, |
1087 | int how) | 1092 | int how, struct nfs_commit_info *cinfo) |
1088 | { | 1093 | { |
1089 | struct nfs_commit_data *data, *tmp; | 1094 | struct nfs_commit_data *data, *tmp; |
1090 | LIST_HEAD(list); | 1095 | LIST_HEAD(list); |
@@ -1097,17 +1102,17 @@ filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages, | |||
1097 | list_add(&data->pages, &list); | 1102 | list_add(&data->pages, &list); |
1098 | nreq++; | 1103 | nreq++; |
1099 | } else | 1104 | } else |
1100 | nfs_retry_commit(mds_pages, NULL); | 1105 | nfs_retry_commit(mds_pages, NULL, cinfo); |
1101 | } | 1106 | } |
1102 | 1107 | ||
1103 | nreq += alloc_ds_commits(inode, &list); | 1108 | nreq += alloc_ds_commits(cinfo, &list); |
1104 | 1109 | ||
1105 | if (nreq == 0) { | 1110 | if (nreq == 0) { |
1106 | nfs_commit_clear_lock(NFS_I(inode)); | 1111 | nfs_commit_clear_lock(NFS_I(inode)); |
1107 | goto out; | 1112 | goto out; |
1108 | } | 1113 | } |
1109 | 1114 | ||
1110 | atomic_add(nreq, &NFS_I(inode)->commits_outstanding); | 1115 | atomic_add(nreq, &cinfo->mds->rpcs_out); |
1111 | 1116 | ||
1112 | list_for_each_entry_safe(data, tmp, &list, pages) { | 1117 | list_for_each_entry_safe(data, tmp, &list, pages) { |
1113 | list_del_init(&data->pages); | 1118 | list_del_init(&data->pages); |
@@ -1116,14 +1121,15 @@ filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages, | |||
1116 | nfs_initiate_commit(NFS_CLIENT(inode), data, | 1121 | nfs_initiate_commit(NFS_CLIENT(inode), data, |
1117 | data->mds_ops, how); | 1122 | data->mds_ops, how); |
1118 | } else { | 1123 | } else { |
1119 | struct nfs4_fl_commit_info *fl_cinfo; | 1124 | struct pnfs_commit_bucket *buckets; |
1120 | 1125 | ||
1121 | fl_cinfo = &FILELAYOUT_FROM_HDR(data->lseg->pls_layout)->commit_info; | 1126 | buckets = cinfo->ds->buckets; |
1122 | nfs_init_commit(data, &fl_cinfo->buckets[data->ds_commit_index].committing, data->lseg); | 1127 | nfs_init_commit(data, &buckets[data->ds_commit_index].committing, data->lseg); |
1123 | filelayout_initiate_commit(data, how); | 1128 | filelayout_initiate_commit(data, how); |
1124 | } | 1129 | } |
1125 | } | 1130 | } |
1126 | out: | 1131 | out: |
1132 | cinfo->ds->ncommitting = 0; | ||
1127 | return PNFS_ATTEMPTED; | 1133 | return PNFS_ATTEMPTED; |
1128 | } | 1134 | } |
1129 | 1135 | ||
@@ -1148,6 +1154,12 @@ filelayout_free_layout_hdr(struct pnfs_layout_hdr *lo) | |||
1148 | kfree(FILELAYOUT_FROM_HDR(lo)); | 1154 | kfree(FILELAYOUT_FROM_HDR(lo)); |
1149 | } | 1155 | } |
1150 | 1156 | ||
1157 | static struct pnfs_ds_commit_info * | ||
1158 | filelayout_get_ds_info(struct inode *inode) | ||
1159 | { | ||
1160 | return &FILELAYOUT_FROM_HDR(NFS_I(inode)->layout)->commit_info; | ||
1161 | } | ||
1162 | |||
1151 | static struct pnfs_layoutdriver_type filelayout_type = { | 1163 | static struct pnfs_layoutdriver_type filelayout_type = { |
1152 | .id = LAYOUT_NFSV4_1_FILES, | 1164 | .id = LAYOUT_NFSV4_1_FILES, |
1153 | .name = "LAYOUT_NFSV4_1_FILES", | 1165 | .name = "LAYOUT_NFSV4_1_FILES", |
@@ -1158,6 +1170,7 @@ static struct pnfs_layoutdriver_type filelayout_type = { | |||
1158 | .free_lseg = filelayout_free_lseg, | 1170 | .free_lseg = filelayout_free_lseg, |
1159 | .pg_read_ops = &filelayout_pg_read_ops, | 1171 | .pg_read_ops = &filelayout_pg_read_ops, |
1160 | .pg_write_ops = &filelayout_pg_write_ops, | 1172 | .pg_write_ops = &filelayout_pg_write_ops, |
1173 | .get_ds_info = &filelayout_get_ds_info, | ||
1161 | .mark_request_commit = filelayout_mark_request_commit, | 1174 | .mark_request_commit = filelayout_mark_request_commit, |
1162 | .clear_request_commit = filelayout_clear_request_commit, | 1175 | .clear_request_commit = filelayout_clear_request_commit, |
1163 | .scan_commit_lists = filelayout_scan_commit_lists, | 1176 | .scan_commit_lists = filelayout_scan_commit_lists, |
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h index 333a3ac97606..96b89bbddf4f 100644 --- a/fs/nfs/nfs4filelayout.h +++ b/fs/nfs/nfs4filelayout.h | |||
@@ -74,18 +74,6 @@ struct nfs4_file_layout_dsaddr { | |||
74 | struct nfs4_pnfs_ds *ds_list[1]; | 74 | struct nfs4_pnfs_ds *ds_list[1]; |
75 | }; | 75 | }; |
76 | 76 | ||
77 | struct nfs4_fl_commit_bucket { | ||
78 | struct list_head written; | ||
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; | ||
87 | }; | ||
88 | |||
89 | struct nfs4_filelayout_segment { | 77 | struct nfs4_filelayout_segment { |
90 | struct pnfs_layout_segment generic_hdr; | 78 | struct pnfs_layout_segment generic_hdr; |
91 | u32 stripe_type; | 79 | u32 stripe_type; |
@@ -100,7 +88,7 @@ struct nfs4_filelayout_segment { | |||
100 | 88 | ||
101 | struct nfs4_filelayout { | 89 | struct nfs4_filelayout { |
102 | struct pnfs_layout_hdr generic_hdr; | 90 | struct pnfs_layout_hdr generic_hdr; |
103 | struct nfs4_fl_commit_info commit_info; | 91 | struct pnfs_ds_commit_info commit_info; |
104 | }; | 92 | }; |
105 | 93 | ||
106 | static inline struct nfs4_filelayout * | 94 | static inline struct nfs4_filelayout * |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 734e4eff7fb0..4cd8760c2f89 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -94,11 +94,18 @@ struct pnfs_layoutdriver_type { | |||
94 | const struct nfs_pageio_ops *pg_read_ops; | 94 | const struct nfs_pageio_ops *pg_read_ops; |
95 | const struct nfs_pageio_ops *pg_write_ops; | 95 | const struct nfs_pageio_ops *pg_write_ops; |
96 | 96 | ||
97 | struct pnfs_ds_commit_info *(*get_ds_info) (struct inode *inode); | ||
97 | void (*mark_request_commit) (struct nfs_page *req, | 98 | void (*mark_request_commit) (struct nfs_page *req, |
98 | struct pnfs_layout_segment *lseg); | 99 | struct pnfs_layout_segment *lseg, |
99 | void (*clear_request_commit) (struct nfs_page *req); | 100 | struct nfs_commit_info *cinfo); |
100 | int (*scan_commit_lists) (struct inode *inode, int max, spinlock_t *lock); | 101 | void (*clear_request_commit) (struct nfs_page *req, |
101 | int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how); | 102 | struct nfs_commit_info *cinfo); |
103 | int (*scan_commit_lists) (struct nfs_commit_info *cinfo, | ||
104 | int max); | ||
105 | int (*commit_pagelist)(struct inode *inode, | ||
106 | struct list_head *mds_pages, | ||
107 | int how, | ||
108 | struct nfs_commit_info *cinfo); | ||
102 | 109 | ||
103 | /* | 110 | /* |
104 | * Return PNFS_ATTEMPTED to indicate the layout code has attempted | 111 | * Return PNFS_ATTEMPTED to indicate the layout code has attempted |
@@ -263,49 +270,57 @@ static inline int pnfs_enabled_sb(struct nfs_server *nfss) | |||
263 | } | 270 | } |
264 | 271 | ||
265 | static inline int | 272 | static inline int |
266 | pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how) | 273 | pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how, |
274 | struct nfs_commit_info *cinfo) | ||
267 | { | 275 | { |
268 | if (!test_and_clear_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags)) | 276 | if (cinfo->ds == NULL || cinfo->ds->ncommitting == 0) |
269 | return PNFS_NOT_ATTEMPTED; | 277 | return PNFS_NOT_ATTEMPTED; |
270 | return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how); | 278 | return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how, cinfo); |
279 | } | ||
280 | |||
281 | static inline struct pnfs_ds_commit_info * | ||
282 | pnfs_get_ds_info(struct inode *inode) | ||
283 | { | ||
284 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; | ||
285 | |||
286 | if (ld == NULL || ld->get_ds_info == NULL) | ||
287 | return NULL; | ||
288 | return ld->get_ds_info(inode); | ||
271 | } | 289 | } |
272 | 290 | ||
273 | static inline bool | 291 | static inline bool |
274 | pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | 292 | pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg, |
293 | struct nfs_commit_info *cinfo) | ||
275 | { | 294 | { |
276 | struct inode *inode = req->wb_context->dentry->d_inode; | 295 | struct inode *inode = req->wb_context->dentry->d_inode; |
277 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; | 296 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; |
278 | 297 | ||
279 | if (lseg == NULL || ld->mark_request_commit == NULL) | 298 | if (lseg == NULL || ld->mark_request_commit == NULL) |
280 | return false; | 299 | return false; |
281 | ld->mark_request_commit(req, lseg); | 300 | ld->mark_request_commit(req, lseg, cinfo); |
282 | return true; | 301 | return true; |
283 | } | 302 | } |
284 | 303 | ||
285 | static inline bool | 304 | static inline bool |
286 | pnfs_clear_request_commit(struct nfs_page *req) | 305 | pnfs_clear_request_commit(struct nfs_page *req, struct nfs_commit_info *cinfo) |
287 | { | 306 | { |
288 | struct inode *inode = req->wb_context->dentry->d_inode; | 307 | struct inode *inode = req->wb_context->dentry->d_inode; |
289 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; | 308 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; |
290 | 309 | ||
291 | if (ld == NULL || ld->clear_request_commit == NULL) | 310 | if (ld == NULL || ld->clear_request_commit == NULL) |
292 | return false; | 311 | return false; |
293 | ld->clear_request_commit(req); | 312 | ld->clear_request_commit(req, cinfo); |
294 | return true; | 313 | return true; |
295 | } | 314 | } |
296 | 315 | ||
297 | static inline int | 316 | static inline int |
298 | pnfs_scan_commit_lists(struct inode *inode, int max, spinlock_t *lock) | 317 | pnfs_scan_commit_lists(struct inode *inode, struct nfs_commit_info *cinfo, |
318 | int max) | ||
299 | { | 319 | { |
300 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; | 320 | if (cinfo->ds == NULL || cinfo->ds->nwritten == 0) |
301 | int ret; | ||
302 | |||
303 | if (ld == NULL || ld->scan_commit_lists == NULL) | ||
304 | return 0; | 321 | return 0; |
305 | ret = ld->scan_commit_lists(inode, max, lock); | 322 | else |
306 | if (ret != 0) | 323 | return NFS_SERVER(inode)->pnfs_curr_ld->scan_commit_lists(cinfo, max); |
307 | set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags); | ||
308 | return ret; | ||
309 | } | 324 | } |
310 | 325 | ||
311 | /* Should the pNFS client commit and return the layout upon a setattr */ | 326 | /* Should the pNFS client commit and return the layout upon a setattr */ |
@@ -409,25 +424,34 @@ static inline bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, st | |||
409 | } | 424 | } |
410 | 425 | ||
411 | static inline int | 426 | static inline int |
412 | pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how) | 427 | pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how, |
428 | struct nfs_commit_info *cinfo) | ||
413 | { | 429 | { |
414 | return PNFS_NOT_ATTEMPTED; | 430 | return PNFS_NOT_ATTEMPTED; |
415 | } | 431 | } |
416 | 432 | ||
433 | static inline struct pnfs_ds_commit_info * | ||
434 | pnfs_get_ds_info(struct inode *inode) | ||
435 | { | ||
436 | return NULL; | ||
437 | } | ||
438 | |||
417 | static inline bool | 439 | static inline bool |
418 | pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | 440 | pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg, |
441 | struct nfs_commit_info *cinfo) | ||
419 | { | 442 | { |
420 | return false; | 443 | return false; |
421 | } | 444 | } |
422 | 445 | ||
423 | static inline bool | 446 | static inline bool |
424 | pnfs_clear_request_commit(struct nfs_page *req) | 447 | pnfs_clear_request_commit(struct nfs_page *req, struct nfs_commit_info *cinfo) |
425 | { | 448 | { |
426 | return false; | 449 | return false; |
427 | } | 450 | } |
428 | 451 | ||
429 | static inline int | 452 | static inline int |
430 | pnfs_scan_commit_lists(struct inode *inode, int max, spinlock_t *lock) | 453 | pnfs_scan_commit_lists(struct inode *inode, struct nfs_commit_info *cinfo, |
454 | int max) | ||
431 | { | 455 | { |
432 | return 0; | 456 | return 0; |
433 | } | 457 | } |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 2500f1cf1996..18bf70055272 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -452,65 +452,79 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
452 | /** | 452 | /** |
453 | * nfs_request_add_commit_list - add request to a commit list | 453 | * nfs_request_add_commit_list - add request to a commit list |
454 | * @req: pointer to a struct nfs_page | 454 | * @req: pointer to a struct nfs_page |
455 | * @head: commit list head | 455 | * @dst: commit list head |
456 | * @cinfo: holds list lock and accounting info | ||
456 | * | 457 | * |
457 | * This sets the PG_CLEAN bit, updates the inode global count of | 458 | * This sets the PG_CLEAN bit, updates the cinfo count of |
458 | * number of outstanding requests requiring a commit as well as | 459 | * number of outstanding requests requiring a commit as well as |
459 | * the MM page stats. | 460 | * the MM page stats. |
460 | * | 461 | * |
461 | * The caller must _not_ hold the inode->i_lock, but must be | 462 | * The caller must _not_ hold the cinfo->lock, but must be |
462 | * holding the nfs_page lock. | 463 | * holding the nfs_page lock. |
463 | */ | 464 | */ |
464 | void | 465 | void |
465 | nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head) | 466 | nfs_request_add_commit_list(struct nfs_page *req, struct list_head *dst, |
467 | struct nfs_commit_info *cinfo) | ||
466 | { | 468 | { |
467 | struct inode *inode = req->wb_context->dentry->d_inode; | ||
468 | |||
469 | set_bit(PG_CLEAN, &(req)->wb_flags); | 469 | set_bit(PG_CLEAN, &(req)->wb_flags); |
470 | spin_lock(&inode->i_lock); | 470 | spin_lock(cinfo->lock); |
471 | nfs_list_add_request(req, head); | 471 | nfs_list_add_request(req, dst); |
472 | NFS_I(inode)->ncommit++; | 472 | cinfo->mds->ncommit++; |
473 | spin_unlock(&inode->i_lock); | 473 | spin_unlock(cinfo->lock); |
474 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 474 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
475 | inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); | 475 | inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); |
476 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | 476 | __mark_inode_dirty(req->wb_context->dentry->d_inode, I_DIRTY_DATASYNC); |
477 | } | 477 | } |
478 | EXPORT_SYMBOL_GPL(nfs_request_add_commit_list); | 478 | EXPORT_SYMBOL_GPL(nfs_request_add_commit_list); |
479 | 479 | ||
480 | /** | 480 | /** |
481 | * nfs_request_remove_commit_list - Remove request from a commit list | 481 | * nfs_request_remove_commit_list - Remove request from a commit list |
482 | * @req: pointer to a nfs_page | 482 | * @req: pointer to a nfs_page |
483 | * @cinfo: holds list lock and accounting info | ||
483 | * | 484 | * |
484 | * This clears the PG_CLEAN bit, and updates the inode global count of | 485 | * This clears the PG_CLEAN bit, and updates the cinfo's count of |
485 | * number of outstanding requests requiring a commit | 486 | * number of outstanding requests requiring a commit |
486 | * It does not update the MM page stats. | 487 | * It does not update the MM page stats. |
487 | * | 488 | * |
488 | * The caller _must_ hold the inode->i_lock and the nfs_page lock. | 489 | * The caller _must_ hold the cinfo->lock and the nfs_page lock. |
489 | */ | 490 | */ |
490 | void | 491 | void |
491 | nfs_request_remove_commit_list(struct nfs_page *req) | 492 | nfs_request_remove_commit_list(struct nfs_page *req, |
493 | struct nfs_commit_info *cinfo) | ||
492 | { | 494 | { |
493 | struct inode *inode = req->wb_context->dentry->d_inode; | ||
494 | |||
495 | if (!test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) | 495 | if (!test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) |
496 | return; | 496 | return; |
497 | nfs_list_remove_request(req); | 497 | nfs_list_remove_request(req); |
498 | NFS_I(inode)->ncommit--; | 498 | cinfo->mds->ncommit--; |
499 | } | 499 | } |
500 | EXPORT_SYMBOL_GPL(nfs_request_remove_commit_list); | 500 | EXPORT_SYMBOL_GPL(nfs_request_remove_commit_list); |
501 | 501 | ||
502 | static void nfs_init_cinfo_from_inode(struct nfs_commit_info *cinfo, | ||
503 | struct inode *inode) | ||
504 | { | ||
505 | cinfo->lock = &inode->i_lock; | ||
506 | cinfo->mds = &NFS_I(inode)->commit_info; | ||
507 | cinfo->ds = pnfs_get_ds_info(inode); | ||
508 | } | ||
509 | |||
510 | void nfs_init_cinfo(struct nfs_commit_info *cinfo, | ||
511 | struct inode *inode, | ||
512 | struct nfs_direct_req *dreq) | ||
513 | { | ||
514 | nfs_init_cinfo_from_inode(cinfo, inode); | ||
515 | } | ||
516 | EXPORT_SYMBOL_GPL(nfs_init_cinfo); | ||
502 | 517 | ||
503 | /* | 518 | /* |
504 | * Add a request to the inode's commit list. | 519 | * Add a request to the inode's commit list. |
505 | */ | 520 | */ |
506 | static void | 521 | static void |
507 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | 522 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg, |
523 | struct nfs_commit_info *cinfo) | ||
508 | { | 524 | { |
509 | struct inode *inode = req->wb_context->dentry->d_inode; | 525 | if (pnfs_mark_request_commit(req, lseg, cinfo)) |
510 | |||
511 | if (pnfs_mark_request_commit(req, lseg)) | ||
512 | return; | 526 | return; |
513 | nfs_request_add_commit_list(req, &NFS_I(inode)->commit_list); | 527 | nfs_request_add_commit_list(req, &cinfo->mds->list, cinfo); |
514 | } | 528 | } |
515 | 529 | ||
516 | static void | 530 | static void |
@@ -525,11 +539,13 @@ nfs_clear_request_commit(struct nfs_page *req) | |||
525 | { | 539 | { |
526 | if (test_bit(PG_CLEAN, &req->wb_flags)) { | 540 | if (test_bit(PG_CLEAN, &req->wb_flags)) { |
527 | struct inode *inode = req->wb_context->dentry->d_inode; | 541 | struct inode *inode = req->wb_context->dentry->d_inode; |
542 | struct nfs_commit_info cinfo; | ||
528 | 543 | ||
529 | if (!pnfs_clear_request_commit(req)) { | 544 | nfs_init_cinfo_from_inode(&cinfo, inode); |
530 | spin_lock(&inode->i_lock); | 545 | if (!pnfs_clear_request_commit(req, &cinfo)) { |
531 | nfs_request_remove_commit_list(req); | 546 | spin_lock(cinfo.lock); |
532 | spin_unlock(&inode->i_lock); | 547 | nfs_request_remove_commit_list(req, &cinfo); |
548 | spin_unlock(cinfo.lock); | ||
533 | } | 549 | } |
534 | nfs_clear_page_commit(req->wb_page); | 550 | nfs_clear_page_commit(req->wb_page); |
535 | } | 551 | } |
@@ -545,7 +561,8 @@ int nfs_write_need_commit(struct nfs_write_data *data) | |||
545 | 561 | ||
546 | #else | 562 | #else |
547 | static void | 563 | static void |
548 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | 564 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg, |
565 | struct nfs_commit_info *cinfo) | ||
549 | { | 566 | { |
550 | } | 567 | } |
551 | 568 | ||
@@ -564,10 +581,12 @@ int nfs_write_need_commit(struct nfs_write_data *data) | |||
564 | 581 | ||
565 | static void nfs_write_completion(struct nfs_pgio_header *hdr) | 582 | static void nfs_write_completion(struct nfs_pgio_header *hdr) |
566 | { | 583 | { |
584 | struct nfs_commit_info cinfo; | ||
567 | unsigned long bytes = 0; | 585 | unsigned long bytes = 0; |
568 | 586 | ||
569 | if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) | 587 | if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) |
570 | goto out; | 588 | goto out; |
589 | nfs_init_cinfo_from_inode(&cinfo, hdr->inode); | ||
571 | while (!list_empty(&hdr->pages)) { | 590 | while (!list_empty(&hdr->pages)) { |
572 | struct nfs_page *req = nfs_list_entry(hdr->pages.next); | 591 | struct nfs_page *req = nfs_list_entry(hdr->pages.next); |
573 | struct page *page = req->wb_page; | 592 | struct page *page = req->wb_page; |
@@ -585,7 +604,7 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr) | |||
585 | goto next; | 604 | goto next; |
586 | } | 605 | } |
587 | if (test_bit(NFS_IOHDR_NEED_COMMIT, &hdr->flags)) { | 606 | if (test_bit(NFS_IOHDR_NEED_COMMIT, &hdr->flags)) { |
588 | nfs_mark_request_commit(req, hdr->lseg); | 607 | nfs_mark_request_commit(req, hdr->lseg, &cinfo); |
589 | goto next; | 608 | goto next; |
590 | } | 609 | } |
591 | remove_req: | 610 | remove_req: |
@@ -599,16 +618,16 @@ out: | |||
599 | } | 618 | } |
600 | 619 | ||
601 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 620 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
602 | static int | 621 | static unsigned long |
603 | nfs_need_commit(struct nfs_inode *nfsi) | 622 | nfs_reqs_to_commit(struct nfs_commit_info *cinfo) |
604 | { | 623 | { |
605 | return nfsi->ncommit > 0; | 624 | return cinfo->mds->ncommit; |
606 | } | 625 | } |
607 | 626 | ||
608 | /* i_lock held by caller */ | 627 | /* cinfo->lock held by caller */ |
609 | static int | 628 | static int |
610 | nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max, | 629 | nfs_scan_commit_list(struct list_head *src, struct list_head *dst, |
611 | spinlock_t *lock) | 630 | struct nfs_commit_info *cinfo, int max) |
612 | { | 631 | { |
613 | struct nfs_page *req, *tmp; | 632 | struct nfs_page *req, *tmp; |
614 | int ret = 0; | 633 | int ret = 0; |
@@ -616,9 +635,9 @@ nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max, | |||
616 | list_for_each_entry_safe(req, tmp, src, wb_list) { | 635 | list_for_each_entry_safe(req, tmp, src, wb_list) { |
617 | if (!nfs_lock_request(req)) | 636 | if (!nfs_lock_request(req)) |
618 | continue; | 637 | continue; |
619 | if (cond_resched_lock(lock)) | 638 | if (cond_resched_lock(cinfo->lock)) |
620 | list_safe_reset_next(req, tmp, wb_list); | 639 | list_safe_reset_next(req, tmp, wb_list); |
621 | nfs_request_remove_commit_list(req); | 640 | nfs_request_remove_commit_list(req, cinfo); |
622 | nfs_list_add_request(req, dst); | 641 | nfs_list_add_request(req, dst); |
623 | ret++; | 642 | ret++; |
624 | if (ret == max) | 643 | if (ret == max) |
@@ -630,37 +649,38 @@ nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max, | |||
630 | /* | 649 | /* |
631 | * nfs_scan_commit - Scan an inode for commit requests | 650 | * nfs_scan_commit - Scan an inode for commit requests |
632 | * @inode: NFS inode to scan | 651 | * @inode: NFS inode to scan |
633 | * @dst: destination list | 652 | * @dst: mds destination list |
653 | * @cinfo: mds and ds lists of reqs ready to commit | ||
634 | * | 654 | * |
635 | * Moves requests from the inode's 'commit' request list. | 655 | * Moves requests from the inode's 'commit' request list. |
636 | * The requests are *not* checked to ensure that they form a contiguous set. | 656 | * The requests are *not* checked to ensure that they form a contiguous set. |
637 | */ | 657 | */ |
638 | static int | 658 | static int |
639 | nfs_scan_commit(struct inode *inode, struct list_head *dst) | 659 | nfs_scan_commit(struct inode *inode, struct list_head *dst, |
660 | struct nfs_commit_info *cinfo) | ||
640 | { | 661 | { |
641 | struct nfs_inode *nfsi = NFS_I(inode); | ||
642 | int ret = 0; | 662 | int ret = 0; |
643 | 663 | ||
644 | spin_lock(&inode->i_lock); | 664 | spin_lock(cinfo->lock); |
645 | if (nfsi->ncommit > 0) { | 665 | if (cinfo->mds->ncommit > 0) { |
646 | const int max = INT_MAX; | 666 | const int max = INT_MAX; |
647 | 667 | ||
648 | ret = nfs_scan_commit_list(&nfsi->commit_list, dst, max, | 668 | ret = nfs_scan_commit_list(&cinfo->mds->list, dst, |
649 | &inode->i_lock); | 669 | cinfo, max); |
650 | ret += pnfs_scan_commit_lists(inode, max - ret, | 670 | ret += pnfs_scan_commit_lists(inode, cinfo, max - ret); |
651 | &inode->i_lock); | ||
652 | } | 671 | } |
653 | spin_unlock(&inode->i_lock); | 672 | spin_unlock(cinfo->lock); |
654 | return ret; | 673 | return ret; |
655 | } | 674 | } |
656 | 675 | ||
657 | #else | 676 | #else |
658 | static inline int nfs_need_commit(struct nfs_inode *nfsi) | 677 | static unsigned long nfs_reqs_to_commit(struct nfs_commit_info *cinfo) |
659 | { | 678 | { |
660 | return 0; | 679 | return 0; |
661 | } | 680 | } |
662 | 681 | ||
663 | static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst) | 682 | static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, |
683 | struct nfs_commit_info *cinfo) | ||
664 | { | 684 | { |
665 | return 0; | 685 | return 0; |
666 | } | 686 | } |
@@ -929,7 +949,7 @@ EXPORT_SYMBOL_GPL(nfs_initiate_write); | |||
929 | */ | 949 | */ |
930 | static void nfs_write_rpcsetup(struct nfs_write_data *data, | 950 | static void nfs_write_rpcsetup(struct nfs_write_data *data, |
931 | unsigned int count, unsigned int offset, | 951 | unsigned int count, unsigned int offset, |
932 | int how) | 952 | int how, struct nfs_commit_info *cinfo) |
933 | { | 953 | { |
934 | struct nfs_page *req = data->header->req; | 954 | struct nfs_page *req = data->header->req; |
935 | 955 | ||
@@ -950,7 +970,7 @@ static void nfs_write_rpcsetup(struct nfs_write_data *data, | |||
950 | case 0: | 970 | case 0: |
951 | break; | 971 | break; |
952 | case FLUSH_COND_STABLE: | 972 | case FLUSH_COND_STABLE: |
953 | if (nfs_need_commit(NFS_I(data->header->inode))) | 973 | if (nfs_reqs_to_commit(cinfo)) |
954 | break; | 974 | break; |
955 | default: | 975 | default: |
956 | data->args.stable = NFS_FILE_SYNC; | 976 | data->args.stable = NFS_FILE_SYNC; |
@@ -1034,12 +1054,14 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, | |||
1034 | unsigned int offset; | 1054 | unsigned int offset; |
1035 | int requests = 0; | 1055 | int requests = 0; |
1036 | int ret = 0; | 1056 | int ret = 0; |
1057 | struct nfs_commit_info cinfo; | ||
1037 | 1058 | ||
1059 | nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); | ||
1038 | nfs_list_remove_request(req); | 1060 | nfs_list_remove_request(req); |
1039 | nfs_list_add_request(req, &hdr->pages); | 1061 | nfs_list_add_request(req, &hdr->pages); |
1040 | 1062 | ||
1041 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && | 1063 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && |
1042 | (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit || | 1064 | (desc->pg_moreio || nfs_reqs_to_commit(&cinfo) || |
1043 | desc->pg_count > wsize)) | 1065 | desc->pg_count > wsize)) |
1044 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | 1066 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; |
1045 | 1067 | ||
@@ -1053,7 +1075,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, | |||
1053 | if (!data) | 1075 | if (!data) |
1054 | goto out_bad; | 1076 | goto out_bad; |
1055 | data->pages.pagevec[0] = page; | 1077 | data->pages.pagevec[0] = page; |
1056 | nfs_write_rpcsetup(data, len, offset, desc->pg_ioflags); | 1078 | nfs_write_rpcsetup(data, len, offset, desc->pg_ioflags, &cinfo); |
1057 | list_add(&data->list, &hdr->rpc_list); | 1079 | list_add(&data->list, &hdr->rpc_list); |
1058 | requests++; | 1080 | requests++; |
1059 | nbytes -= len; | 1081 | nbytes -= len; |
@@ -1088,6 +1110,7 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc, | |||
1088 | struct nfs_write_data *data; | 1110 | struct nfs_write_data *data; |
1089 | struct list_head *head = &desc->pg_list; | 1111 | struct list_head *head = &desc->pg_list; |
1090 | int ret = 0; | 1112 | int ret = 0; |
1113 | struct nfs_commit_info cinfo; | ||
1091 | 1114 | ||
1092 | data = nfs_writedata_alloc(hdr, nfs_page_array_len(desc->pg_base, | 1115 | data = nfs_writedata_alloc(hdr, nfs_page_array_len(desc->pg_base, |
1093 | desc->pg_count)); | 1116 | desc->pg_count)); |
@@ -1097,6 +1120,7 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc, | |||
1097 | goto out; | 1120 | goto out; |
1098 | } | 1121 | } |
1099 | 1122 | ||
1123 | nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); | ||
1100 | pages = data->pages.pagevec; | 1124 | pages = data->pages.pagevec; |
1101 | while (!list_empty(head)) { | 1125 | while (!list_empty(head)) { |
1102 | req = nfs_list_entry(head->next); | 1126 | req = nfs_list_entry(head->next); |
@@ -1106,11 +1130,11 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc, | |||
1106 | } | 1130 | } |
1107 | 1131 | ||
1108 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && | 1132 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && |
1109 | (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit)) | 1133 | (desc->pg_moreio || nfs_reqs_to_commit(&cinfo))) |
1110 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | 1134 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; |
1111 | 1135 | ||
1112 | /* Set up the argument struct */ | 1136 | /* Set up the argument struct */ |
1113 | nfs_write_rpcsetup(data, desc->pg_count, 0, desc->pg_ioflags); | 1137 | nfs_write_rpcsetup(data, desc->pg_count, 0, desc->pg_ioflags, &cinfo); |
1114 | list_add(&data->list, &hdr->rpc_list); | 1138 | list_add(&data->list, &hdr->rpc_list); |
1115 | desc->pg_rpc_callops = &nfs_write_common_ops; | 1139 | desc->pg_rpc_callops = &nfs_write_common_ops; |
1116 | out: | 1140 | out: |
@@ -1417,14 +1441,15 @@ void nfs_init_commit(struct nfs_commit_data *data, | |||
1417 | EXPORT_SYMBOL_GPL(nfs_init_commit); | 1441 | EXPORT_SYMBOL_GPL(nfs_init_commit); |
1418 | 1442 | ||
1419 | void nfs_retry_commit(struct list_head *page_list, | 1443 | void nfs_retry_commit(struct list_head *page_list, |
1420 | struct pnfs_layout_segment *lseg) | 1444 | struct pnfs_layout_segment *lseg, |
1445 | struct nfs_commit_info *cinfo) | ||
1421 | { | 1446 | { |
1422 | struct nfs_page *req; | 1447 | struct nfs_page *req; |
1423 | 1448 | ||
1424 | while (!list_empty(page_list)) { | 1449 | while (!list_empty(page_list)) { |
1425 | req = nfs_list_entry(page_list->next); | 1450 | req = nfs_list_entry(page_list->next); |
1426 | nfs_list_remove_request(req); | 1451 | nfs_list_remove_request(req); |
1427 | nfs_mark_request_commit(req, lseg); | 1452 | nfs_mark_request_commit(req, lseg, cinfo); |
1428 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 1453 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
1429 | dec_bdi_stat(req->wb_page->mapping->backing_dev_info, | 1454 | dec_bdi_stat(req->wb_page->mapping->backing_dev_info, |
1430 | BDI_RECLAIMABLE); | 1455 | BDI_RECLAIMABLE); |
@@ -1437,7 +1462,8 @@ EXPORT_SYMBOL_GPL(nfs_retry_commit); | |||
1437 | * Commit dirty pages | 1462 | * Commit dirty pages |
1438 | */ | 1463 | */ |
1439 | static int | 1464 | static int |
1440 | nfs_commit_list(struct inode *inode, struct list_head *head, int how) | 1465 | nfs_commit_list(struct inode *inode, struct list_head *head, int how, |
1466 | struct nfs_commit_info *cinfo) | ||
1441 | { | 1467 | { |
1442 | struct nfs_commit_data *data; | 1468 | struct nfs_commit_data *data; |
1443 | 1469 | ||
@@ -1450,7 +1476,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1450 | nfs_init_commit(data, head, NULL); | 1476 | nfs_init_commit(data, head, NULL); |
1451 | return nfs_initiate_commit(NFS_CLIENT(inode), data, data->mds_ops, how); | 1477 | return nfs_initiate_commit(NFS_CLIENT(inode), data, data->mds_ops, how); |
1452 | out_bad: | 1478 | out_bad: |
1453 | nfs_retry_commit(head, NULL); | 1479 | nfs_retry_commit(head, NULL, cinfo); |
1454 | nfs_commit_clear_lock(NFS_I(inode)); | 1480 | nfs_commit_clear_lock(NFS_I(inode)); |
1455 | return -ENOMEM; | 1481 | return -ENOMEM; |
1456 | } | 1482 | } |
@@ -1524,30 +1550,32 @@ static const struct rpc_call_ops nfs_commit_ops = { | |||
1524 | }; | 1550 | }; |
1525 | 1551 | ||
1526 | static int nfs_generic_commit_list(struct inode *inode, struct list_head *head, | 1552 | static int nfs_generic_commit_list(struct inode *inode, struct list_head *head, |
1527 | int how) | 1553 | int how, struct nfs_commit_info *cinfo) |
1528 | { | 1554 | { |
1529 | int status; | 1555 | int status; |
1530 | 1556 | ||
1531 | status = pnfs_commit_list(inode, head, how); | 1557 | status = pnfs_commit_list(inode, head, how, cinfo); |
1532 | if (status == PNFS_NOT_ATTEMPTED) | 1558 | if (status == PNFS_NOT_ATTEMPTED) |
1533 | status = nfs_commit_list(inode, head, how); | 1559 | status = nfs_commit_list(inode, head, how, cinfo); |
1534 | return status; | 1560 | return status; |
1535 | } | 1561 | } |
1536 | 1562 | ||
1537 | int nfs_commit_inode(struct inode *inode, int how) | 1563 | int nfs_commit_inode(struct inode *inode, int how) |
1538 | { | 1564 | { |
1539 | LIST_HEAD(head); | 1565 | LIST_HEAD(head); |
1566 | struct nfs_commit_info cinfo; | ||
1540 | int may_wait = how & FLUSH_SYNC; | 1567 | int may_wait = how & FLUSH_SYNC; |
1541 | int res; | 1568 | int res; |
1542 | 1569 | ||
1543 | res = nfs_commit_set_lock(NFS_I(inode), may_wait); | 1570 | res = nfs_commit_set_lock(NFS_I(inode), may_wait); |
1544 | if (res <= 0) | 1571 | if (res <= 0) |
1545 | goto out_mark_dirty; | 1572 | goto out_mark_dirty; |
1546 | res = nfs_scan_commit(inode, &head); | 1573 | nfs_init_cinfo_from_inode(&cinfo, inode); |
1574 | res = nfs_scan_commit(inode, &head, &cinfo); | ||
1547 | if (res) { | 1575 | if (res) { |
1548 | int error; | 1576 | int error; |
1549 | 1577 | ||
1550 | error = nfs_generic_commit_list(inode, &head, how); | 1578 | error = nfs_generic_commit_list(inode, &head, how, &cinfo); |
1551 | if (error < 0) | 1579 | if (error < 0) |
1552 | return error; | 1580 | return error; |
1553 | if (!may_wait) | 1581 | if (!may_wait) |
@@ -1578,14 +1606,14 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr | |||
1578 | int ret = 0; | 1606 | int ret = 0; |
1579 | 1607 | ||
1580 | /* no commits means nothing needs to be done */ | 1608 | /* no commits means nothing needs to be done */ |
1581 | if (!nfsi->ncommit) | 1609 | if (!nfsi->commit_info.ncommit) |
1582 | return ret; | 1610 | return ret; |
1583 | 1611 | ||
1584 | if (wbc->sync_mode == WB_SYNC_NONE) { | 1612 | if (wbc->sync_mode == WB_SYNC_NONE) { |
1585 | /* Don't commit yet if this is a non-blocking flush and there | 1613 | /* Don't commit yet if this is a non-blocking flush and there |
1586 | * are a lot of outstanding writes for this mapping. | 1614 | * are a lot of outstanding writes for this mapping. |
1587 | */ | 1615 | */ |
1588 | if (nfsi->ncommit <= (nfsi->npages >> 1)) | 1616 | if (nfsi->commit_info.ncommit <= (nfsi->npages >> 1)) |
1589 | goto out_mark_dirty; | 1617 | goto out_mark_dirty; |
1590 | 1618 | ||
1591 | /* don't wait for the COMMIT response */ | 1619 | /* don't wait for the COMMIT response */ |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 8d3a2b804201..8a88c16662c5 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -179,8 +179,7 @@ struct nfs_inode { | |||
179 | __be32 cookieverf[2]; | 179 | __be32 cookieverf[2]; |
180 | 180 | ||
181 | unsigned long npages; | 181 | unsigned long npages; |
182 | unsigned long ncommit; | 182 | struct nfs_mds_commit_info commit_info; |
183 | struct list_head commit_list; | ||
184 | 183 | ||
185 | /* Open contexts for shared mmap writes */ | 184 | /* Open contexts for shared mmap writes */ |
186 | struct list_head open_files; | 185 | struct list_head open_files; |
@@ -201,7 +200,6 @@ struct nfs_inode { | |||
201 | 200 | ||
202 | /* pNFS layout information */ | 201 | /* pNFS layout information */ |
203 | struct pnfs_layout_hdr *layout; | 202 | struct pnfs_layout_hdr *layout; |
204 | atomic_t commits_outstanding; | ||
205 | #endif /* CONFIG_NFS_V4*/ | 203 | #endif /* CONFIG_NFS_V4*/ |
206 | #ifdef CONFIG_NFS_FSCACHE | 204 | #ifdef CONFIG_NFS_FSCACHE |
207 | struct fscache_cookie *fscache; | 205 | struct fscache_cookie *fscache; |
@@ -230,7 +228,6 @@ struct nfs_inode { | |||
230 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ | 228 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ |
231 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ | 229 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ |
232 | #define NFS_INO_COMMIT (7) /* inode is committing unstable writes */ | 230 | #define NFS_INO_COMMIT (7) /* inode is committing unstable writes */ |
233 | #define NFS_INO_PNFS_COMMIT (8) /* use pnfs code for commit */ | ||
234 | #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ | 231 | #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ |
235 | #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ | 232 | #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ |
236 | 233 | ||
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 38687b87ca9b..224e1e82670c 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -1079,6 +1079,21 @@ struct nfstime4 { | |||
1079 | }; | 1079 | }; |
1080 | 1080 | ||
1081 | #ifdef CONFIG_NFS_V4_1 | 1081 | #ifdef CONFIG_NFS_V4_1 |
1082 | |||
1083 | struct pnfs_commit_bucket { | ||
1084 | struct list_head written; | ||
1085 | struct list_head committing; | ||
1086 | struct pnfs_layout_segment *wlseg; | ||
1087 | struct pnfs_layout_segment *clseg; | ||
1088 | }; | ||
1089 | |||
1090 | struct pnfs_ds_commit_info { | ||
1091 | int nwritten; | ||
1092 | int ncommitting; | ||
1093 | int nbuckets; | ||
1094 | struct pnfs_commit_bucket *buckets; | ||
1095 | }; | ||
1096 | |||
1082 | #define NFS4_EXCHANGE_ID_LEN (48) | 1097 | #define NFS4_EXCHANGE_ID_LEN (48) |
1083 | struct nfs41_exchange_id_args { | 1098 | struct nfs41_exchange_id_args { |
1084 | struct nfs_client *client; | 1099 | struct nfs_client *client; |
@@ -1242,6 +1257,18 @@ struct nfs_write_header { | |||
1242 | struct nfs_write_data rpc_data; | 1257 | struct nfs_write_data rpc_data; |
1243 | }; | 1258 | }; |
1244 | 1259 | ||
1260 | struct nfs_mds_commit_info { | ||
1261 | atomic_t rpcs_out; | ||
1262 | unsigned long ncommit; | ||
1263 | struct list_head list; | ||
1264 | }; | ||
1265 | |||
1266 | struct nfs_commit_info { | ||
1267 | spinlock_t *lock; | ||
1268 | struct nfs_mds_commit_info *mds; | ||
1269 | struct pnfs_ds_commit_info *ds; | ||
1270 | }; | ||
1271 | |||
1245 | struct nfs_commit_data { | 1272 | struct nfs_commit_data { |
1246 | struct rpc_task task; | 1273 | struct rpc_task task; |
1247 | struct inode *inode; | 1274 | struct inode *inode; |