diff options
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r-- | fs/nfs/pnfs.c | 330 |
1 files changed, 156 insertions, 174 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 1b1bc1a0fb0a..f38813a0a295 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/nfs_fs.h> | 30 | #include <linux/nfs_fs.h> |
31 | #include "internal.h" | 31 | #include "internal.h" |
32 | #include "pnfs.h" | 32 | #include "pnfs.h" |
33 | #include "iostat.h" | ||
33 | 34 | ||
34 | #define NFSDBG_FACILITY NFSDBG_PNFS | 35 | #define NFSDBG_FACILITY NFSDBG_PNFS |
35 | 36 | ||
@@ -74,10 +75,8 @@ find_pnfs_driver(u32 id) | |||
74 | void | 75 | void |
75 | unset_pnfs_layoutdriver(struct nfs_server *nfss) | 76 | unset_pnfs_layoutdriver(struct nfs_server *nfss) |
76 | { | 77 | { |
77 | if (nfss->pnfs_curr_ld) { | 78 | if (nfss->pnfs_curr_ld) |
78 | nfss->pnfs_curr_ld->clear_layoutdriver(nfss); | ||
79 | module_put(nfss->pnfs_curr_ld->owner); | 79 | module_put(nfss->pnfs_curr_ld->owner); |
80 | } | ||
81 | nfss->pnfs_curr_ld = NULL; | 80 | nfss->pnfs_curr_ld = NULL; |
82 | } | 81 | } |
83 | 82 | ||
@@ -115,13 +114,7 @@ set_pnfs_layoutdriver(struct nfs_server *server, u32 id) | |||
115 | goto out_no_driver; | 114 | goto out_no_driver; |
116 | } | 115 | } |
117 | server->pnfs_curr_ld = ld_type; | 116 | server->pnfs_curr_ld = ld_type; |
118 | if (ld_type->set_layoutdriver(server)) { | 117 | |
119 | printk(KERN_ERR | ||
120 | "%s: Error initializing mount point for layout driver %u.\n", | ||
121 | __func__, id); | ||
122 | module_put(ld_type->owner); | ||
123 | goto out_no_driver; | ||
124 | } | ||
125 | dprintk("%s: pNFS module for %u set\n", __func__, id); | 118 | dprintk("%s: pNFS module for %u set\n", __func__, id); |
126 | return; | 119 | return; |
127 | 120 | ||
@@ -230,37 +223,41 @@ static void free_lseg(struct pnfs_layout_segment *lseg) | |||
230 | put_layout_hdr(NFS_I(ino)->layout); | 223 | put_layout_hdr(NFS_I(ino)->layout); |
231 | } | 224 | } |
232 | 225 | ||
233 | /* The use of tmp_list is necessary because pnfs_curr_ld->free_lseg | 226 | static void |
234 | * could sleep, so must be called outside of the lock. | 227 | put_lseg_common(struct pnfs_layout_segment *lseg) |
235 | * Returns 1 if object was removed, otherwise return 0. | 228 | { |
236 | */ | 229 | struct inode *inode = lseg->pls_layout->plh_inode; |
237 | static int | 230 | |
238 | put_lseg_locked(struct pnfs_layout_segment *lseg, | 231 | BUG_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); |
239 | struct list_head *tmp_list) | 232 | list_del_init(&lseg->pls_list); |
233 | if (list_empty(&lseg->pls_layout->plh_segs)) { | ||
234 | set_bit(NFS_LAYOUT_DESTROYED, &lseg->pls_layout->plh_flags); | ||
235 | /* Matched by initial refcount set in alloc_init_layout_hdr */ | ||
236 | put_layout_hdr_locked(lseg->pls_layout); | ||
237 | } | ||
238 | rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq); | ||
239 | } | ||
240 | |||
241 | void | ||
242 | put_lseg(struct pnfs_layout_segment *lseg) | ||
240 | { | 243 | { |
244 | struct inode *inode; | ||
245 | |||
246 | if (!lseg) | ||
247 | return; | ||
248 | |||
241 | dprintk("%s: lseg %p ref %d valid %d\n", __func__, lseg, | 249 | dprintk("%s: lseg %p ref %d valid %d\n", __func__, lseg, |
242 | atomic_read(&lseg->pls_refcount), | 250 | atomic_read(&lseg->pls_refcount), |
243 | test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); | 251 | test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); |
244 | if (atomic_dec_and_test(&lseg->pls_refcount)) { | 252 | inode = lseg->pls_layout->plh_inode; |
245 | struct inode *ino = lseg->pls_layout->plh_inode; | 253 | if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) { |
254 | LIST_HEAD(free_me); | ||
246 | 255 | ||
247 | BUG_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); | 256 | put_lseg_common(lseg); |
248 | list_del(&lseg->pls_list); | 257 | list_add(&lseg->pls_list, &free_me); |
249 | if (list_empty(&lseg->pls_layout->plh_segs)) { | 258 | spin_unlock(&inode->i_lock); |
250 | struct nfs_client *clp; | 259 | pnfs_free_lseg_list(&free_me); |
251 | |||
252 | clp = NFS_SERVER(ino)->nfs_client; | ||
253 | spin_lock(&clp->cl_lock); | ||
254 | /* List does not take a reference, so no need for put here */ | ||
255 | list_del_init(&lseg->pls_layout->plh_layouts); | ||
256 | spin_unlock(&clp->cl_lock); | ||
257 | clear_bit(NFS_LAYOUT_BULK_RECALL, &lseg->pls_layout->plh_flags); | ||
258 | } | ||
259 | rpc_wake_up(&NFS_SERVER(ino)->roc_rpcwaitq); | ||
260 | list_add(&lseg->pls_list, tmp_list); | ||
261 | return 1; | ||
262 | } | 260 | } |
263 | return 0; | ||
264 | } | 261 | } |
265 | 262 | ||
266 | static bool | 263 | static bool |
@@ -281,7 +278,13 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, | |||
281 | * list. It will now be removed when all | 278 | * list. It will now be removed when all |
282 | * outstanding io is finished. | 279 | * outstanding io is finished. |
283 | */ | 280 | */ |
284 | rv = put_lseg_locked(lseg, tmp_list); | 281 | dprintk("%s: lseg %p ref %d\n", __func__, lseg, |
282 | atomic_read(&lseg->pls_refcount)); | ||
283 | if (atomic_dec_and_test(&lseg->pls_refcount)) { | ||
284 | put_lseg_common(lseg); | ||
285 | list_add(&lseg->pls_list, tmp_list); | ||
286 | rv = 1; | ||
287 | } | ||
285 | } | 288 | } |
286 | return rv; | 289 | return rv; |
287 | } | 290 | } |
@@ -299,6 +302,11 @@ mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, | |||
299 | 302 | ||
300 | dprintk("%s:Begin lo %p\n", __func__, lo); | 303 | dprintk("%s:Begin lo %p\n", __func__, lo); |
301 | 304 | ||
305 | if (list_empty(&lo->plh_segs)) { | ||
306 | if (!test_and_set_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags)) | ||
307 | put_layout_hdr_locked(lo); | ||
308 | return 0; | ||
309 | } | ||
302 | list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) | 310 | list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) |
303 | if (should_free_lseg(lseg->pls_range.iomode, iomode)) { | 311 | if (should_free_lseg(lseg->pls_range.iomode, iomode)) { |
304 | dprintk("%s: freeing lseg %p iomode %d " | 312 | dprintk("%s: freeing lseg %p iomode %d " |
@@ -312,11 +320,27 @@ mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, | |||
312 | return invalid - removed; | 320 | return invalid - removed; |
313 | } | 321 | } |
314 | 322 | ||
323 | /* note free_me must contain lsegs from a single layout_hdr */ | ||
315 | void | 324 | void |
316 | pnfs_free_lseg_list(struct list_head *free_me) | 325 | pnfs_free_lseg_list(struct list_head *free_me) |
317 | { | 326 | { |
318 | struct pnfs_layout_segment *lseg, *tmp; | 327 | struct pnfs_layout_segment *lseg, *tmp; |
328 | struct pnfs_layout_hdr *lo; | ||
329 | |||
330 | if (list_empty(free_me)) | ||
331 | return; | ||
319 | 332 | ||
333 | lo = list_first_entry(free_me, struct pnfs_layout_segment, | ||
334 | pls_list)->pls_layout; | ||
335 | |||
336 | if (test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags)) { | ||
337 | struct nfs_client *clp; | ||
338 | |||
339 | clp = NFS_SERVER(lo->plh_inode)->nfs_client; | ||
340 | spin_lock(&clp->cl_lock); | ||
341 | list_del_init(&lo->plh_layouts); | ||
342 | spin_unlock(&clp->cl_lock); | ||
343 | } | ||
320 | list_for_each_entry_safe(lseg, tmp, free_me, pls_list) { | 344 | list_for_each_entry_safe(lseg, tmp, free_me, pls_list) { |
321 | list_del(&lseg->pls_list); | 345 | list_del(&lseg->pls_list); |
322 | free_lseg(lseg); | 346 | free_lseg(lseg); |
@@ -332,10 +356,8 @@ pnfs_destroy_layout(struct nfs_inode *nfsi) | |||
332 | spin_lock(&nfsi->vfs_inode.i_lock); | 356 | spin_lock(&nfsi->vfs_inode.i_lock); |
333 | lo = nfsi->layout; | 357 | lo = nfsi->layout; |
334 | if (lo) { | 358 | if (lo) { |
335 | set_bit(NFS_LAYOUT_DESTROYED, &nfsi->layout->plh_flags); | 359 | lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */ |
336 | mark_matching_lsegs_invalid(lo, &tmp_list, IOMODE_ANY); | 360 | mark_matching_lsegs_invalid(lo, &tmp_list, IOMODE_ANY); |
337 | /* Matched by refcount set to 1 in alloc_init_layout_hdr */ | ||
338 | put_layout_hdr_locked(lo); | ||
339 | } | 361 | } |
340 | spin_unlock(&nfsi->vfs_inode.i_lock); | 362 | spin_unlock(&nfsi->vfs_inode.i_lock); |
341 | pnfs_free_lseg_list(&tmp_list); | 363 | pnfs_free_lseg_list(&tmp_list); |
@@ -403,6 +425,7 @@ pnfs_layoutgets_blocked(struct pnfs_layout_hdr *lo, nfs4_stateid *stateid, | |||
403 | (int)(lo->plh_barrier - be32_to_cpu(stateid->stateid.seqid)) >= 0) | 425 | (int)(lo->plh_barrier - be32_to_cpu(stateid->stateid.seqid)) >= 0) |
404 | return true; | 426 | return true; |
405 | return lo->plh_block_lgets || | 427 | return lo->plh_block_lgets || |
428 | test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) || | ||
406 | test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) || | 429 | test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) || |
407 | (list_empty(&lo->plh_segs) && | 430 | (list_empty(&lo->plh_segs) && |
408 | (atomic_read(&lo->plh_outstanding) > lget)); | 431 | (atomic_read(&lo->plh_outstanding) > lget)); |
@@ -674,7 +697,7 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, u32 iomode) | |||
674 | list_for_each_entry(lseg, &lo->plh_segs, pls_list) { | 697 | list_for_each_entry(lseg, &lo->plh_segs, pls_list) { |
675 | if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) && | 698 | if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) && |
676 | is_matching_lseg(lseg, iomode)) { | 699 | is_matching_lseg(lseg, iomode)) { |
677 | ret = lseg; | 700 | ret = get_lseg(lseg); |
678 | break; | 701 | break; |
679 | } | 702 | } |
680 | if (cmp_layout(iomode, lseg->pls_range.iomode) > 0) | 703 | if (cmp_layout(iomode, lseg->pls_range.iomode) > 0) |
@@ -699,6 +722,7 @@ pnfs_update_layout(struct inode *ino, | |||
699 | struct nfs_client *clp = NFS_SERVER(ino)->nfs_client; | 722 | struct nfs_client *clp = NFS_SERVER(ino)->nfs_client; |
700 | struct pnfs_layout_hdr *lo; | 723 | struct pnfs_layout_hdr *lo; |
701 | struct pnfs_layout_segment *lseg = NULL; | 724 | struct pnfs_layout_segment *lseg = NULL; |
725 | bool first = false; | ||
702 | 726 | ||
703 | if (!pnfs_enabled_sb(NFS_SERVER(ino))) | 727 | if (!pnfs_enabled_sb(NFS_SERVER(ino))) |
704 | return NULL; | 728 | return NULL; |
@@ -715,21 +739,25 @@ pnfs_update_layout(struct inode *ino, | |||
715 | dprintk("%s matches recall, use MDS\n", __func__); | 739 | dprintk("%s matches recall, use MDS\n", __func__); |
716 | goto out_unlock; | 740 | goto out_unlock; |
717 | } | 741 | } |
718 | /* Check to see if the layout for the given range already exists */ | ||
719 | lseg = pnfs_find_lseg(lo, iomode); | ||
720 | if (lseg) | ||
721 | goto out_unlock; | ||
722 | 742 | ||
723 | /* if LAYOUTGET already failed once we don't try again */ | 743 | /* if LAYOUTGET already failed once we don't try again */ |
724 | if (test_bit(lo_fail_bit(iomode), &nfsi->layout->plh_flags)) | 744 | if (test_bit(lo_fail_bit(iomode), &nfsi->layout->plh_flags)) |
725 | goto out_unlock; | 745 | goto out_unlock; |
726 | 746 | ||
747 | /* Check to see if the layout for the given range already exists */ | ||
748 | lseg = pnfs_find_lseg(lo, iomode); | ||
749 | if (lseg) | ||
750 | goto out_unlock; | ||
751 | |||
727 | if (pnfs_layoutgets_blocked(lo, NULL, 0)) | 752 | if (pnfs_layoutgets_blocked(lo, NULL, 0)) |
728 | goto out_unlock; | 753 | goto out_unlock; |
729 | atomic_inc(&lo->plh_outstanding); | 754 | atomic_inc(&lo->plh_outstanding); |
730 | 755 | ||
731 | get_layout_hdr(lo); | 756 | get_layout_hdr(lo); |
732 | if (list_empty(&lo->plh_segs)) { | 757 | if (list_empty(&lo->plh_segs)) |
758 | first = true; | ||
759 | spin_unlock(&ino->i_lock); | ||
760 | if (first) { | ||
733 | /* The lo must be on the clp list if there is any | 761 | /* The lo must be on the clp list if there is any |
734 | * chance of a CB_LAYOUTRECALL(FILE) coming in. | 762 | * chance of a CB_LAYOUTRECALL(FILE) coming in. |
735 | */ | 763 | */ |
@@ -738,24 +766,18 @@ pnfs_update_layout(struct inode *ino, | |||
738 | list_add_tail(&lo->plh_layouts, &clp->cl_layouts); | 766 | list_add_tail(&lo->plh_layouts, &clp->cl_layouts); |
739 | spin_unlock(&clp->cl_lock); | 767 | spin_unlock(&clp->cl_lock); |
740 | } | 768 | } |
741 | spin_unlock(&ino->i_lock); | ||
742 | 769 | ||
743 | lseg = send_layoutget(lo, ctx, iomode); | 770 | lseg = send_layoutget(lo, ctx, iomode); |
744 | if (!lseg) { | 771 | if (!lseg && first) { |
745 | spin_lock(&ino->i_lock); | 772 | spin_lock(&clp->cl_lock); |
746 | if (list_empty(&lo->plh_segs)) { | 773 | list_del_init(&lo->plh_layouts); |
747 | spin_lock(&clp->cl_lock); | 774 | spin_unlock(&clp->cl_lock); |
748 | list_del_init(&lo->plh_layouts); | ||
749 | spin_unlock(&clp->cl_lock); | ||
750 | clear_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags); | ||
751 | } | ||
752 | spin_unlock(&ino->i_lock); | ||
753 | } | 775 | } |
754 | atomic_dec(&lo->plh_outstanding); | 776 | atomic_dec(&lo->plh_outstanding); |
755 | put_layout_hdr(lo); | 777 | put_layout_hdr(lo); |
756 | out: | 778 | out: |
757 | dprintk("%s end, state 0x%lx lseg %p\n", __func__, | 779 | dprintk("%s end, state 0x%lx lseg %p\n", __func__, |
758 | nfsi->layout->plh_flags, lseg); | 780 | nfsi->layout ? nfsi->layout->plh_flags : -1, lseg); |
759 | return lseg; | 781 | return lseg; |
760 | out_unlock: | 782 | out_unlock: |
761 | spin_unlock(&ino->i_lock); | 783 | spin_unlock(&ino->i_lock); |
@@ -808,7 +830,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) | |||
808 | } | 830 | } |
809 | init_lseg(lo, lseg); | 831 | init_lseg(lo, lseg); |
810 | lseg->pls_range = res->range; | 832 | lseg->pls_range = res->range; |
811 | *lgp->lsegpp = lseg; | 833 | *lgp->lsegpp = get_lseg(lseg); |
812 | pnfs_insert_layout(lo, lseg); | 834 | pnfs_insert_layout(lo, lseg); |
813 | 835 | ||
814 | if (res->return_on_close) { | 836 | if (res->return_on_close) { |
@@ -829,137 +851,97 @@ out_forget_reply: | |||
829 | goto out; | 851 | goto out; |
830 | } | 852 | } |
831 | 853 | ||
832 | /* | 854 | static int pnfs_read_pg_test(struct nfs_pageio_descriptor *pgio, |
833 | * Device ID cache. Currently supports one layout type per struct nfs_client. | 855 | struct nfs_page *prev, |
834 | * Add layout type to the lookup key to expand to support multiple types. | 856 | struct nfs_page *req) |
835 | */ | ||
836 | int | ||
837 | pnfs_alloc_init_deviceid_cache(struct nfs_client *clp, | ||
838 | void (*free_callback)(struct pnfs_deviceid_node *)) | ||
839 | { | 857 | { |
840 | struct pnfs_deviceid_cache *c; | 858 | if (pgio->pg_count == prev->wb_bytes) { |
841 | 859 | /* This is first coelesce call for a series of nfs_pages */ | |
842 | c = kzalloc(sizeof(struct pnfs_deviceid_cache), GFP_KERNEL); | 860 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, |
843 | if (!c) | 861 | prev->wb_context, |
844 | return -ENOMEM; | 862 | IOMODE_READ); |
845 | spin_lock(&clp->cl_lock); | ||
846 | if (clp->cl_devid_cache != NULL) { | ||
847 | atomic_inc(&clp->cl_devid_cache->dc_ref); | ||
848 | dprintk("%s [kref [%d]]\n", __func__, | ||
849 | atomic_read(&clp->cl_devid_cache->dc_ref)); | ||
850 | kfree(c); | ||
851 | } else { | ||
852 | /* kzalloc initializes hlists */ | ||
853 | spin_lock_init(&c->dc_lock); | ||
854 | atomic_set(&c->dc_ref, 1); | ||
855 | c->dc_free_callback = free_callback; | ||
856 | clp->cl_devid_cache = c; | ||
857 | dprintk("%s [new]\n", __func__); | ||
858 | } | 863 | } |
859 | spin_unlock(&clp->cl_lock); | 864 | return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req); |
860 | return 0; | ||
861 | } | 865 | } |
862 | EXPORT_SYMBOL_GPL(pnfs_alloc_init_deviceid_cache); | ||
863 | 866 | ||
864 | /* | ||
865 | * Called from pnfs_layoutdriver_type->free_lseg | ||
866 | * last layout segment reference frees deviceid | ||
867 | */ | ||
868 | void | 867 | void |
869 | pnfs_put_deviceid(struct pnfs_deviceid_cache *c, | 868 | pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode) |
870 | struct pnfs_deviceid_node *devid) | ||
871 | { | 869 | { |
872 | struct nfs4_deviceid *id = &devid->de_id; | 870 | struct pnfs_layoutdriver_type *ld; |
873 | struct pnfs_deviceid_node *d; | ||
874 | struct hlist_node *n; | ||
875 | long h = nfs4_deviceid_hash(id); | ||
876 | 871 | ||
877 | dprintk("%s [%d]\n", __func__, atomic_read(&devid->de_ref)); | 872 | ld = NFS_SERVER(inode)->pnfs_curr_ld; |
878 | if (!atomic_dec_and_lock(&devid->de_ref, &c->dc_lock)) | 873 | pgio->pg_test = (ld && ld->pg_test) ? pnfs_read_pg_test : NULL; |
879 | return; | 874 | } |
880 | 875 | ||
881 | hlist_for_each_entry_rcu(d, n, &c->dc_deviceids[h], de_node) | 876 | static int pnfs_write_pg_test(struct nfs_pageio_descriptor *pgio, |
882 | if (!memcmp(&d->de_id, id, sizeof(*id))) { | 877 | struct nfs_page *prev, |
883 | hlist_del_rcu(&d->de_node); | 878 | struct nfs_page *req) |
884 | spin_unlock(&c->dc_lock); | 879 | { |
885 | synchronize_rcu(); | 880 | if (pgio->pg_count == prev->wb_bytes) { |
886 | c->dc_free_callback(devid); | 881 | /* This is first coelesce call for a series of nfs_pages */ |
887 | return; | 882 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, |
888 | } | 883 | prev->wb_context, |
889 | spin_unlock(&c->dc_lock); | 884 | IOMODE_RW); |
890 | /* Why wasn't it found in the list? */ | ||
891 | BUG(); | ||
892 | } | ||
893 | EXPORT_SYMBOL_GPL(pnfs_put_deviceid); | ||
894 | |||
895 | /* Find and reference a deviceid */ | ||
896 | struct pnfs_deviceid_node * | ||
897 | pnfs_find_get_deviceid(struct pnfs_deviceid_cache *c, struct nfs4_deviceid *id) | ||
898 | { | ||
899 | struct pnfs_deviceid_node *d; | ||
900 | struct hlist_node *n; | ||
901 | long hash = nfs4_deviceid_hash(id); | ||
902 | |||
903 | dprintk("--> %s hash %ld\n", __func__, hash); | ||
904 | rcu_read_lock(); | ||
905 | hlist_for_each_entry_rcu(d, n, &c->dc_deviceids[hash], de_node) { | ||
906 | if (!memcmp(&d->de_id, id, sizeof(*id))) { | ||
907 | if (!atomic_inc_not_zero(&d->de_ref)) { | ||
908 | goto fail; | ||
909 | } else { | ||
910 | rcu_read_unlock(); | ||
911 | return d; | ||
912 | } | ||
913 | } | ||
914 | } | 885 | } |
915 | fail: | 886 | return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req); |
916 | rcu_read_unlock(); | 887 | } |
917 | return NULL; | 888 | |
889 | void | ||
890 | pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode) | ||
891 | { | ||
892 | struct pnfs_layoutdriver_type *ld; | ||
893 | |||
894 | ld = NFS_SERVER(inode)->pnfs_curr_ld; | ||
895 | pgio->pg_test = (ld && ld->pg_test) ? pnfs_write_pg_test : NULL; | ||
896 | } | ||
897 | |||
898 | enum pnfs_try_status | ||
899 | pnfs_try_to_write_data(struct nfs_write_data *wdata, | ||
900 | const struct rpc_call_ops *call_ops, int how) | ||
901 | { | ||
902 | struct inode *inode = wdata->inode; | ||
903 | enum pnfs_try_status trypnfs; | ||
904 | struct nfs_server *nfss = NFS_SERVER(inode); | ||
905 | |||
906 | wdata->mds_ops = call_ops; | ||
907 | |||
908 | dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__, | ||
909 | inode->i_ino, wdata->args.count, wdata->args.offset, how); | ||
910 | |||
911 | trypnfs = nfss->pnfs_curr_ld->write_pagelist(wdata, how); | ||
912 | if (trypnfs == PNFS_NOT_ATTEMPTED) { | ||
913 | put_lseg(wdata->lseg); | ||
914 | wdata->lseg = NULL; | ||
915 | } else | ||
916 | nfs_inc_stats(inode, NFSIOS_PNFS_WRITE); | ||
917 | |||
918 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); | ||
919 | return trypnfs; | ||
918 | } | 920 | } |
919 | EXPORT_SYMBOL_GPL(pnfs_find_get_deviceid); | ||
920 | 921 | ||
921 | /* | 922 | /* |
922 | * Add a deviceid to the cache. | 923 | * Call the appropriate parallel I/O subsystem read function. |
923 | * GETDEVICEINFOs for same deviceid can race. If deviceid is found, discard new | ||
924 | */ | 924 | */ |
925 | struct pnfs_deviceid_node * | 925 | enum pnfs_try_status |
926 | pnfs_add_deviceid(struct pnfs_deviceid_cache *c, struct pnfs_deviceid_node *new) | 926 | pnfs_try_to_read_data(struct nfs_read_data *rdata, |
927 | { | 927 | const struct rpc_call_ops *call_ops) |
928 | struct pnfs_deviceid_node *d; | ||
929 | long hash = nfs4_deviceid_hash(&new->de_id); | ||
930 | |||
931 | dprintk("--> %s hash %ld\n", __func__, hash); | ||
932 | spin_lock(&c->dc_lock); | ||
933 | d = pnfs_find_get_deviceid(c, &new->de_id); | ||
934 | if (d) { | ||
935 | spin_unlock(&c->dc_lock); | ||
936 | dprintk("%s [discard]\n", __func__); | ||
937 | c->dc_free_callback(new); | ||
938 | return d; | ||
939 | } | ||
940 | INIT_HLIST_NODE(&new->de_node); | ||
941 | atomic_set(&new->de_ref, 1); | ||
942 | hlist_add_head_rcu(&new->de_node, &c->dc_deviceids[hash]); | ||
943 | spin_unlock(&c->dc_lock); | ||
944 | dprintk("%s [new]\n", __func__); | ||
945 | return new; | ||
946 | } | ||
947 | EXPORT_SYMBOL_GPL(pnfs_add_deviceid); | ||
948 | |||
949 | void | ||
950 | pnfs_put_deviceid_cache(struct nfs_client *clp) | ||
951 | { | 928 | { |
952 | struct pnfs_deviceid_cache *local = clp->cl_devid_cache; | 929 | struct inode *inode = rdata->inode; |
930 | struct nfs_server *nfss = NFS_SERVER(inode); | ||
931 | enum pnfs_try_status trypnfs; | ||
953 | 932 | ||
954 | dprintk("--> %s ({%d})\n", __func__, atomic_read(&local->dc_ref)); | 933 | rdata->mds_ops = call_ops; |
955 | if (atomic_dec_and_lock(&local->dc_ref, &clp->cl_lock)) { | 934 | |
956 | int i; | 935 | dprintk("%s: Reading ino:%lu %u@%llu\n", |
957 | /* Verify cache is empty */ | 936 | __func__, inode->i_ino, rdata->args.count, rdata->args.offset); |
958 | for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i++) | 937 | |
959 | BUG_ON(!hlist_empty(&local->dc_deviceids[i])); | 938 | trypnfs = nfss->pnfs_curr_ld->read_pagelist(rdata); |
960 | clp->cl_devid_cache = NULL; | 939 | if (trypnfs == PNFS_NOT_ATTEMPTED) { |
961 | spin_unlock(&clp->cl_lock); | 940 | put_lseg(rdata->lseg); |
962 | kfree(local); | 941 | rdata->lseg = NULL; |
942 | } else { | ||
943 | nfs_inc_stats(inode, NFSIOS_PNFS_READ); | ||
963 | } | 944 | } |
945 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); | ||
946 | return trypnfs; | ||
964 | } | 947 | } |
965 | EXPORT_SYMBOL_GPL(pnfs_put_deviceid_cache); | ||