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); | ||
