diff options
Diffstat (limited to 'fs')
143 files changed, 7121 insertions, 2504 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index d78e950402c1..a97263be6a91 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -236,10 +236,12 @@ source "fs/nfsd/Kconfig" | |||
236 | 236 | ||
237 | config LOCKD | 237 | config LOCKD |
238 | tristate | 238 | tristate |
239 | depends on FILE_LOCKING | ||
239 | 240 | ||
240 | config LOCKD_V4 | 241 | config LOCKD_V4 |
241 | bool | 242 | bool |
242 | depends on NFSD_V3 || NFS_V3 | 243 | depends on NFSD_V3 || NFS_V3 |
244 | depends on FILE_LOCKING | ||
243 | default y | 245 | default y |
244 | 246 | ||
245 | config EXPORTFS | 247 | config EXPORTFS |
diff --git a/fs/afs/flock.c b/fs/afs/flock.c index 210acafe4a9b..3ff8bdd18fb3 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c | |||
@@ -432,7 +432,6 @@ vfs_rejected_lock: | |||
432 | list_del_init(&fl->fl_u.afs.link); | 432 | list_del_init(&fl->fl_u.afs.link); |
433 | if (list_empty(&vnode->granted_locks)) | 433 | if (list_empty(&vnode->granted_locks)) |
434 | afs_defer_unlock(vnode, key); | 434 | afs_defer_unlock(vnode, key); |
435 | spin_unlock(&vnode->lock); | ||
436 | goto abort_attempt; | 435 | goto abort_attempt; |
437 | } | 436 | } |
438 | 437 | ||
@@ -485,6 +485,8 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req) | |||
485 | { | 485 | { |
486 | assert_spin_locked(&ctx->ctx_lock); | 486 | assert_spin_locked(&ctx->ctx_lock); |
487 | 487 | ||
488 | if (req->ki_eventfd != NULL) | ||
489 | eventfd_ctx_put(req->ki_eventfd); | ||
488 | if (req->ki_dtor) | 490 | if (req->ki_dtor) |
489 | req->ki_dtor(req); | 491 | req->ki_dtor(req); |
490 | if (req->ki_iovec != &req->ki_inline_vec) | 492 | if (req->ki_iovec != &req->ki_inline_vec) |
@@ -509,8 +511,6 @@ static void aio_fput_routine(struct work_struct *data) | |||
509 | /* Complete the fput(s) */ | 511 | /* Complete the fput(s) */ |
510 | if (req->ki_filp != NULL) | 512 | if (req->ki_filp != NULL) |
511 | __fput(req->ki_filp); | 513 | __fput(req->ki_filp); |
512 | if (req->ki_eventfd != NULL) | ||
513 | __fput(req->ki_eventfd); | ||
514 | 514 | ||
515 | /* Link the iocb into the context's free list */ | 515 | /* Link the iocb into the context's free list */ |
516 | spin_lock_irq(&ctx->ctx_lock); | 516 | spin_lock_irq(&ctx->ctx_lock); |
@@ -528,8 +528,6 @@ static void aio_fput_routine(struct work_struct *data) | |||
528 | */ | 528 | */ |
529 | static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) | 529 | static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) |
530 | { | 530 | { |
531 | int schedule_putreq = 0; | ||
532 | |||
533 | dprintk(KERN_DEBUG "aio_put(%p): f_count=%ld\n", | 531 | dprintk(KERN_DEBUG "aio_put(%p): f_count=%ld\n", |
534 | req, atomic_long_read(&req->ki_filp->f_count)); | 532 | req, atomic_long_read(&req->ki_filp->f_count)); |
535 | 533 | ||
@@ -549,24 +547,16 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) | |||
549 | * we would not be holding the last reference to the file*, so | 547 | * we would not be holding the last reference to the file*, so |
550 | * this function will be executed w/out any aio kthread wakeup. | 548 | * this function will be executed w/out any aio kthread wakeup. |
551 | */ | 549 | */ |
552 | if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) | 550 | if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) { |
553 | schedule_putreq++; | ||
554 | else | ||
555 | req->ki_filp = NULL; | ||
556 | if (req->ki_eventfd != NULL) { | ||
557 | if (unlikely(atomic_long_dec_and_test(&req->ki_eventfd->f_count))) | ||
558 | schedule_putreq++; | ||
559 | else | ||
560 | req->ki_eventfd = NULL; | ||
561 | } | ||
562 | if (unlikely(schedule_putreq)) { | ||
563 | get_ioctx(ctx); | 551 | get_ioctx(ctx); |
564 | spin_lock(&fput_lock); | 552 | spin_lock(&fput_lock); |
565 | list_add(&req->ki_list, &fput_head); | 553 | list_add(&req->ki_list, &fput_head); |
566 | spin_unlock(&fput_lock); | 554 | spin_unlock(&fput_lock); |
567 | queue_work(aio_wq, &fput_work); | 555 | queue_work(aio_wq, &fput_work); |
568 | } else | 556 | } else { |
557 | req->ki_filp = NULL; | ||
569 | really_put_req(ctx, req); | 558 | really_put_req(ctx, req); |
559 | } | ||
570 | return 1; | 560 | return 1; |
571 | } | 561 | } |
572 | 562 | ||
@@ -1622,7 +1612,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1622 | * an eventfd() fd, and will be signaled for each completed | 1612 | * an eventfd() fd, and will be signaled for each completed |
1623 | * event using the eventfd_signal() function. | 1613 | * event using the eventfd_signal() function. |
1624 | */ | 1614 | */ |
1625 | req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd); | 1615 | req->ki_eventfd = eventfd_ctx_fdget((int) iocb->aio_resfd); |
1626 | if (IS_ERR(req->ki_eventfd)) { | 1616 | if (IS_ERR(req->ki_eventfd)) { |
1627 | ret = PTR_ERR(req->ki_eventfd); | 1617 | ret = PTR_ERR(req->ki_eventfd); |
1628 | req->ki_eventfd = NULL; | 1618 | req->ki_eventfd = NULL; |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 9fa212b014a5..b7c1603cd4bd 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -1522,11 +1522,11 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
1522 | info->thread = NULL; | 1522 | info->thread = NULL; |
1523 | 1523 | ||
1524 | psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); | 1524 | psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); |
1525 | fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); | ||
1526 | |||
1527 | if (psinfo == NULL) | 1525 | if (psinfo == NULL) |
1528 | return 0; | 1526 | return 0; |
1529 | 1527 | ||
1528 | fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); | ||
1529 | |||
1530 | /* | 1530 | /* |
1531 | * Figure out how many notes we're going to need for each thread. | 1531 | * Figure out how many notes we're going to need for each thread. |
1532 | */ | 1532 | */ |
@@ -1929,7 +1929,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un | |||
1929 | elf = kmalloc(sizeof(*elf), GFP_KERNEL); | 1929 | elf = kmalloc(sizeof(*elf), GFP_KERNEL); |
1930 | if (!elf) | 1930 | if (!elf) |
1931 | goto out; | 1931 | goto out; |
1932 | 1932 | /* | |
1933 | * The number of segs are recored into ELF header as 16bit value. | ||
1934 | * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. | ||
1935 | */ | ||
1933 | segs = current->mm->map_count; | 1936 | segs = current->mm->map_count; |
1934 | #ifdef ELF_CORE_EXTRA_PHDRS | 1937 | #ifdef ELF_CORE_EXTRA_PHDRS |
1935 | segs += ELF_CORE_EXTRA_PHDRS; | 1938 | segs += ELF_CORE_EXTRA_PHDRS; |
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index 31c46a241bac..49a34e7f7306 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * bio-integrity.c - bio data integrity extensions | 2 | * bio-integrity.c - bio data integrity extensions |
3 | * | 3 | * |
4 | * Copyright (C) 2007, 2008 Oracle Corporation | 4 | * Copyright (C) 2007, 2008, 2009 Oracle Corporation |
5 | * Written by: Martin K. Petersen <martin.petersen@oracle.com> | 5 | * Written by: Martin K. Petersen <martin.petersen@oracle.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
@@ -25,63 +25,121 @@ | |||
25 | #include <linux/bio.h> | 25 | #include <linux/bio.h> |
26 | #include <linux/workqueue.h> | 26 | #include <linux/workqueue.h> |
27 | 27 | ||
28 | static struct kmem_cache *bio_integrity_slab __read_mostly; | 28 | struct integrity_slab { |
29 | static mempool_t *bio_integrity_pool; | 29 | struct kmem_cache *slab; |
30 | static struct bio_set *integrity_bio_set; | 30 | unsigned short nr_vecs; |
31 | char name[8]; | ||
32 | }; | ||
33 | |||
34 | #define IS(x) { .nr_vecs = x, .name = "bip-"__stringify(x) } | ||
35 | struct integrity_slab bip_slab[BIOVEC_NR_POOLS] __read_mostly = { | ||
36 | IS(1), IS(4), IS(16), IS(64), IS(128), IS(BIO_MAX_PAGES), | ||
37 | }; | ||
38 | #undef IS | ||
39 | |||
31 | static struct workqueue_struct *kintegrityd_wq; | 40 | static struct workqueue_struct *kintegrityd_wq; |
32 | 41 | ||
42 | static inline unsigned int vecs_to_idx(unsigned int nr) | ||
43 | { | ||
44 | switch (nr) { | ||
45 | case 1: | ||
46 | return 0; | ||
47 | case 2 ... 4: | ||
48 | return 1; | ||
49 | case 5 ... 16: | ||
50 | return 2; | ||
51 | case 17 ... 64: | ||
52 | return 3; | ||
53 | case 65 ... 128: | ||
54 | return 4; | ||
55 | case 129 ... BIO_MAX_PAGES: | ||
56 | return 5; | ||
57 | default: | ||
58 | BUG(); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | static inline int use_bip_pool(unsigned int idx) | ||
63 | { | ||
64 | if (idx == BIOVEC_NR_POOLS) | ||
65 | return 1; | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
33 | /** | 70 | /** |
34 | * bio_integrity_alloc - Allocate integrity payload and attach it to bio | 71 | * bio_integrity_alloc_bioset - Allocate integrity payload and attach it to bio |
35 | * @bio: bio to attach integrity metadata to | 72 | * @bio: bio to attach integrity metadata to |
36 | * @gfp_mask: Memory allocation mask | 73 | * @gfp_mask: Memory allocation mask |
37 | * @nr_vecs: Number of integrity metadata scatter-gather elements | 74 | * @nr_vecs: Number of integrity metadata scatter-gather elements |
75 | * @bs: bio_set to allocate from | ||
38 | * | 76 | * |
39 | * Description: This function prepares a bio for attaching integrity | 77 | * Description: This function prepares a bio for attaching integrity |
40 | * metadata. nr_vecs specifies the maximum number of pages containing | 78 | * metadata. nr_vecs specifies the maximum number of pages containing |
41 | * integrity metadata that can be attached. | 79 | * integrity metadata that can be attached. |
42 | */ | 80 | */ |
43 | struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, | 81 | struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio, |
44 | gfp_t gfp_mask, | 82 | gfp_t gfp_mask, |
45 | unsigned int nr_vecs) | 83 | unsigned int nr_vecs, |
84 | struct bio_set *bs) | ||
46 | { | 85 | { |
47 | struct bio_integrity_payload *bip; | 86 | struct bio_integrity_payload *bip; |
48 | struct bio_vec *iv; | 87 | unsigned int idx = vecs_to_idx(nr_vecs); |
49 | unsigned long idx; | ||
50 | 88 | ||
51 | BUG_ON(bio == NULL); | 89 | BUG_ON(bio == NULL); |
90 | bip = NULL; | ||
52 | 91 | ||
53 | bip = mempool_alloc(bio_integrity_pool, gfp_mask); | 92 | /* Lower order allocations come straight from slab */ |
54 | if (unlikely(bip == NULL)) { | 93 | if (!use_bip_pool(idx)) |
55 | printk(KERN_ERR "%s: could not alloc bip\n", __func__); | 94 | bip = kmem_cache_alloc(bip_slab[idx].slab, gfp_mask); |
56 | return NULL; | ||
57 | } | ||
58 | 95 | ||
59 | memset(bip, 0, sizeof(*bip)); | 96 | /* Use mempool if lower order alloc failed or max vecs were requested */ |
97 | if (bip == NULL) { | ||
98 | bip = mempool_alloc(bs->bio_integrity_pool, gfp_mask); | ||
60 | 99 | ||
61 | iv = bvec_alloc_bs(gfp_mask, nr_vecs, &idx, integrity_bio_set); | 100 | if (unlikely(bip == NULL)) { |
62 | if (unlikely(iv == NULL)) { | 101 | printk(KERN_ERR "%s: could not alloc bip\n", __func__); |
63 | printk(KERN_ERR "%s: could not alloc bip_vec\n", __func__); | 102 | return NULL; |
64 | mempool_free(bip, bio_integrity_pool); | 103 | } |
65 | return NULL; | ||
66 | } | 104 | } |
67 | 105 | ||
68 | bip->bip_pool = idx; | 106 | memset(bip, 0, sizeof(*bip)); |
69 | bip->bip_vec = iv; | 107 | |
108 | bip->bip_slab = idx; | ||
70 | bip->bip_bio = bio; | 109 | bip->bip_bio = bio; |
71 | bio->bi_integrity = bip; | 110 | bio->bi_integrity = bip; |
72 | 111 | ||
73 | return bip; | 112 | return bip; |
74 | } | 113 | } |
114 | EXPORT_SYMBOL(bio_integrity_alloc_bioset); | ||
115 | |||
116 | /** | ||
117 | * bio_integrity_alloc - Allocate integrity payload and attach it to bio | ||
118 | * @bio: bio to attach integrity metadata to | ||
119 | * @gfp_mask: Memory allocation mask | ||
120 | * @nr_vecs: Number of integrity metadata scatter-gather elements | ||
121 | * | ||
122 | * Description: This function prepares a bio for attaching integrity | ||
123 | * metadata. nr_vecs specifies the maximum number of pages containing | ||
124 | * integrity metadata that can be attached. | ||
125 | */ | ||
126 | struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, | ||
127 | gfp_t gfp_mask, | ||
128 | unsigned int nr_vecs) | ||
129 | { | ||
130 | return bio_integrity_alloc_bioset(bio, gfp_mask, nr_vecs, fs_bio_set); | ||
131 | } | ||
75 | EXPORT_SYMBOL(bio_integrity_alloc); | 132 | EXPORT_SYMBOL(bio_integrity_alloc); |
76 | 133 | ||
77 | /** | 134 | /** |
78 | * bio_integrity_free - Free bio integrity payload | 135 | * bio_integrity_free - Free bio integrity payload |
79 | * @bio: bio containing bip to be freed | 136 | * @bio: bio containing bip to be freed |
137 | * @bs: bio_set this bio was allocated from | ||
80 | * | 138 | * |
81 | * Description: Used to free the integrity portion of a bio. Usually | 139 | * Description: Used to free the integrity portion of a bio. Usually |
82 | * called from bio_free(). | 140 | * called from bio_free(). |
83 | */ | 141 | */ |
84 | void bio_integrity_free(struct bio *bio) | 142 | void bio_integrity_free(struct bio *bio, struct bio_set *bs) |
85 | { | 143 | { |
86 | struct bio_integrity_payload *bip = bio->bi_integrity; | 144 | struct bio_integrity_payload *bip = bio->bi_integrity; |
87 | 145 | ||
@@ -92,8 +150,10 @@ void bio_integrity_free(struct bio *bio) | |||
92 | && bip->bip_buf != NULL) | 150 | && bip->bip_buf != NULL) |
93 | kfree(bip->bip_buf); | 151 | kfree(bip->bip_buf); |
94 | 152 | ||
95 | bvec_free_bs(integrity_bio_set, bip->bip_vec, bip->bip_pool); | 153 | if (use_bip_pool(bip->bip_slab)) |
96 | mempool_free(bip, bio_integrity_pool); | 154 | mempool_free(bip, bs->bio_integrity_pool); |
155 | else | ||
156 | kmem_cache_free(bip_slab[bip->bip_slab].slab, bip); | ||
97 | 157 | ||
98 | bio->bi_integrity = NULL; | 158 | bio->bi_integrity = NULL; |
99 | } | 159 | } |
@@ -114,7 +174,7 @@ int bio_integrity_add_page(struct bio *bio, struct page *page, | |||
114 | struct bio_integrity_payload *bip = bio->bi_integrity; | 174 | struct bio_integrity_payload *bip = bio->bi_integrity; |
115 | struct bio_vec *iv; | 175 | struct bio_vec *iv; |
116 | 176 | ||
117 | if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_pool)) { | 177 | if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_slab)) { |
118 | printk(KERN_ERR "%s: bip_vec full\n", __func__); | 178 | printk(KERN_ERR "%s: bip_vec full\n", __func__); |
119 | return 0; | 179 | return 0; |
120 | } | 180 | } |
@@ -647,8 +707,8 @@ void bio_integrity_split(struct bio *bio, struct bio_pair *bp, int sectors) | |||
647 | bp->iv1 = bip->bip_vec[0]; | 707 | bp->iv1 = bip->bip_vec[0]; |
648 | bp->iv2 = bip->bip_vec[0]; | 708 | bp->iv2 = bip->bip_vec[0]; |
649 | 709 | ||
650 | bp->bip1.bip_vec = &bp->iv1; | 710 | bp->bip1.bip_vec[0] = bp->iv1; |
651 | bp->bip2.bip_vec = &bp->iv2; | 711 | bp->bip2.bip_vec[0] = bp->iv2; |
652 | 712 | ||
653 | bp->iv1.bv_len = sectors * bi->tuple_size; | 713 | bp->iv1.bv_len = sectors * bi->tuple_size; |
654 | bp->iv2.bv_offset += sectors * bi->tuple_size; | 714 | bp->iv2.bv_offset += sectors * bi->tuple_size; |
@@ -667,17 +727,19 @@ EXPORT_SYMBOL(bio_integrity_split); | |||
667 | * @bio: New bio | 727 | * @bio: New bio |
668 | * @bio_src: Original bio | 728 | * @bio_src: Original bio |
669 | * @gfp_mask: Memory allocation mask | 729 | * @gfp_mask: Memory allocation mask |
730 | * @bs: bio_set to allocate bip from | ||
670 | * | 731 | * |
671 | * Description: Called to allocate a bip when cloning a bio | 732 | * Description: Called to allocate a bip when cloning a bio |
672 | */ | 733 | */ |
673 | int bio_integrity_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp_mask) | 734 | int bio_integrity_clone(struct bio *bio, struct bio *bio_src, |
735 | gfp_t gfp_mask, struct bio_set *bs) | ||
674 | { | 736 | { |
675 | struct bio_integrity_payload *bip_src = bio_src->bi_integrity; | 737 | struct bio_integrity_payload *bip_src = bio_src->bi_integrity; |
676 | struct bio_integrity_payload *bip; | 738 | struct bio_integrity_payload *bip; |
677 | 739 | ||
678 | BUG_ON(bip_src == NULL); | 740 | BUG_ON(bip_src == NULL); |
679 | 741 | ||
680 | bip = bio_integrity_alloc(bio, gfp_mask, bip_src->bip_vcnt); | 742 | bip = bio_integrity_alloc_bioset(bio, gfp_mask, bip_src->bip_vcnt, bs); |
681 | 743 | ||
682 | if (bip == NULL) | 744 | if (bip == NULL) |
683 | return -EIO; | 745 | return -EIO; |
@@ -693,25 +755,43 @@ int bio_integrity_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp_mask) | |||
693 | } | 755 | } |
694 | EXPORT_SYMBOL(bio_integrity_clone); | 756 | EXPORT_SYMBOL(bio_integrity_clone); |
695 | 757 | ||
696 | static int __init bio_integrity_init(void) | 758 | int bioset_integrity_create(struct bio_set *bs, int pool_size) |
697 | { | 759 | { |
698 | kintegrityd_wq = create_workqueue("kintegrityd"); | 760 | unsigned int max_slab = vecs_to_idx(BIO_MAX_PAGES); |
761 | |||
762 | bs->bio_integrity_pool = | ||
763 | mempool_create_slab_pool(pool_size, bip_slab[max_slab].slab); | ||
699 | 764 | ||
765 | if (!bs->bio_integrity_pool) | ||
766 | return -1; | ||
767 | |||
768 | return 0; | ||
769 | } | ||
770 | EXPORT_SYMBOL(bioset_integrity_create); | ||
771 | |||
772 | void bioset_integrity_free(struct bio_set *bs) | ||
773 | { | ||
774 | if (bs->bio_integrity_pool) | ||
775 | mempool_destroy(bs->bio_integrity_pool); | ||
776 | } | ||
777 | EXPORT_SYMBOL(bioset_integrity_free); | ||
778 | |||
779 | void __init bio_integrity_init(void) | ||
780 | { | ||
781 | unsigned int i; | ||
782 | |||
783 | kintegrityd_wq = create_workqueue("kintegrityd"); | ||
700 | if (!kintegrityd_wq) | 784 | if (!kintegrityd_wq) |
701 | panic("Failed to create kintegrityd\n"); | 785 | panic("Failed to create kintegrityd\n"); |
702 | 786 | ||
703 | bio_integrity_slab = KMEM_CACHE(bio_integrity_payload, | 787 | for (i = 0 ; i < BIOVEC_NR_POOLS ; i++) { |
704 | SLAB_HWCACHE_ALIGN|SLAB_PANIC); | 788 | unsigned int size; |
705 | 789 | ||
706 | bio_integrity_pool = mempool_create_slab_pool(BIO_POOL_SIZE, | 790 | size = sizeof(struct bio_integrity_payload) |
707 | bio_integrity_slab); | 791 | + bip_slab[i].nr_vecs * sizeof(struct bio_vec); |
708 | if (!bio_integrity_pool) | ||
709 | panic("bio_integrity: can't allocate bip pool\n"); | ||
710 | 792 | ||
711 | integrity_bio_set = bioset_create(BIO_POOL_SIZE, 0); | 793 | bip_slab[i].slab = |
712 | if (!integrity_bio_set) | 794 | kmem_cache_create(bip_slab[i].name, size, 0, |
713 | panic("bio_integrity: can't allocate bio_set\n"); | 795 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); |
714 | 796 | } | |
715 | return 0; | ||
716 | } | 797 | } |
717 | subsys_initcall(bio_integrity_init); | ||
@@ -238,7 +238,7 @@ void bio_free(struct bio *bio, struct bio_set *bs) | |||
238 | bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio)); | 238 | bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio)); |
239 | 239 | ||
240 | if (bio_integrity(bio)) | 240 | if (bio_integrity(bio)) |
241 | bio_integrity_free(bio); | 241 | bio_integrity_free(bio, bs); |
242 | 242 | ||
243 | /* | 243 | /* |
244 | * If we have front padding, adjust the bio pointer before freeing | 244 | * If we have front padding, adjust the bio pointer before freeing |
@@ -341,7 +341,7 @@ struct bio *bio_alloc(gfp_t gfp_mask, int nr_iovecs) | |||
341 | static void bio_kmalloc_destructor(struct bio *bio) | 341 | static void bio_kmalloc_destructor(struct bio *bio) |
342 | { | 342 | { |
343 | if (bio_integrity(bio)) | 343 | if (bio_integrity(bio)) |
344 | bio_integrity_free(bio); | 344 | bio_integrity_free(bio, fs_bio_set); |
345 | kfree(bio); | 345 | kfree(bio); |
346 | } | 346 | } |
347 | 347 | ||
@@ -472,7 +472,7 @@ struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask) | |||
472 | if (bio_integrity(bio)) { | 472 | if (bio_integrity(bio)) { |
473 | int ret; | 473 | int ret; |
474 | 474 | ||
475 | ret = bio_integrity_clone(b, bio, gfp_mask); | 475 | ret = bio_integrity_clone(b, bio, gfp_mask, fs_bio_set); |
476 | 476 | ||
477 | if (ret < 0) { | 477 | if (ret < 0) { |
478 | bio_put(b); | 478 | bio_put(b); |
@@ -1539,6 +1539,7 @@ void bioset_free(struct bio_set *bs) | |||
1539 | if (bs->bio_pool) | 1539 | if (bs->bio_pool) |
1540 | mempool_destroy(bs->bio_pool); | 1540 | mempool_destroy(bs->bio_pool); |
1541 | 1541 | ||
1542 | bioset_integrity_free(bs); | ||
1542 | biovec_free_pools(bs); | 1543 | biovec_free_pools(bs); |
1543 | bio_put_slab(bs); | 1544 | bio_put_slab(bs); |
1544 | 1545 | ||
@@ -1579,6 +1580,9 @@ struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad) | |||
1579 | if (!bs->bio_pool) | 1580 | if (!bs->bio_pool) |
1580 | goto bad; | 1581 | goto bad; |
1581 | 1582 | ||
1583 | if (bioset_integrity_create(bs, pool_size)) | ||
1584 | goto bad; | ||
1585 | |||
1582 | if (!biovec_create_pools(bs, pool_size)) | 1586 | if (!biovec_create_pools(bs, pool_size)) |
1583 | return bs; | 1587 | return bs; |
1584 | 1588 | ||
@@ -1616,6 +1620,7 @@ static int __init init_bio(void) | |||
1616 | if (!bio_slabs) | 1620 | if (!bio_slabs) |
1617 | panic("bio: can't allocate bios\n"); | 1621 | panic("bio: can't allocate bios\n"); |
1618 | 1622 | ||
1623 | bio_integrity_init(); | ||
1619 | biovec_init_slabs(); | 1624 | biovec_init_slabs(); |
1620 | 1625 | ||
1621 | fs_bio_set = bioset_create(BIO_POOL_SIZE, 0); | 1626 | fs_bio_set = bioset_create(BIO_POOL_SIZE, 0); |
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 603972576f0f..f128427b995b 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c | |||
@@ -29,51 +29,28 @@ | |||
29 | 29 | ||
30 | #ifdef CONFIG_FS_POSIX_ACL | 30 | #ifdef CONFIG_FS_POSIX_ACL |
31 | 31 | ||
32 | static void btrfs_update_cached_acl(struct inode *inode, | ||
33 | struct posix_acl **p_acl, | ||
34 | struct posix_acl *acl) | ||
35 | { | ||
36 | spin_lock(&inode->i_lock); | ||
37 | if (*p_acl && *p_acl != BTRFS_ACL_NOT_CACHED) | ||
38 | posix_acl_release(*p_acl); | ||
39 | *p_acl = posix_acl_dup(acl); | ||
40 | spin_unlock(&inode->i_lock); | ||
41 | } | ||
42 | |||
43 | static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) | 32 | static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) |
44 | { | 33 | { |
45 | int size; | 34 | int size; |
46 | const char *name; | 35 | const char *name; |
47 | char *value = NULL; | 36 | char *value = NULL; |
48 | struct posix_acl *acl = NULL, **p_acl; | 37 | struct posix_acl *acl; |
38 | |||
39 | acl = get_cached_acl(inode, type); | ||
40 | if (acl != ACL_NOT_CACHED) | ||
41 | return acl; | ||
49 | 42 | ||
50 | switch (type) { | 43 | switch (type) { |
51 | case ACL_TYPE_ACCESS: | 44 | case ACL_TYPE_ACCESS: |
52 | name = POSIX_ACL_XATTR_ACCESS; | 45 | name = POSIX_ACL_XATTR_ACCESS; |
53 | p_acl = &BTRFS_I(inode)->i_acl; | ||
54 | break; | 46 | break; |
55 | case ACL_TYPE_DEFAULT: | 47 | case ACL_TYPE_DEFAULT: |
56 | name = POSIX_ACL_XATTR_DEFAULT; | 48 | name = POSIX_ACL_XATTR_DEFAULT; |
57 | p_acl = &BTRFS_I(inode)->i_default_acl; | ||
58 | break; | 49 | break; |
59 | default: | 50 | default: |
60 | return ERR_PTR(-EINVAL); | 51 | BUG(); |
61 | } | 52 | } |
62 | 53 | ||
63 | /* Handle the cached NULL acl case without locking */ | ||
64 | acl = ACCESS_ONCE(*p_acl); | ||
65 | if (!acl) | ||
66 | return acl; | ||
67 | |||
68 | spin_lock(&inode->i_lock); | ||
69 | acl = *p_acl; | ||
70 | if (acl != BTRFS_ACL_NOT_CACHED) | ||
71 | acl = posix_acl_dup(acl); | ||
72 | spin_unlock(&inode->i_lock); | ||
73 | |||
74 | if (acl != BTRFS_ACL_NOT_CACHED) | ||
75 | return acl; | ||
76 | |||
77 | size = __btrfs_getxattr(inode, name, "", 0); | 54 | size = __btrfs_getxattr(inode, name, "", 0); |
78 | if (size > 0) { | 55 | if (size > 0) { |
79 | value = kzalloc(size, GFP_NOFS); | 56 | value = kzalloc(size, GFP_NOFS); |
@@ -82,13 +59,13 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) | |||
82 | size = __btrfs_getxattr(inode, name, value, size); | 59 | size = __btrfs_getxattr(inode, name, value, size); |
83 | if (size > 0) { | 60 | if (size > 0) { |
84 | acl = posix_acl_from_xattr(value, size); | 61 | acl = posix_acl_from_xattr(value, size); |
85 | btrfs_update_cached_acl(inode, p_acl, acl); | 62 | set_cached_acl(inode, type, acl); |
86 | } | 63 | } |
87 | kfree(value); | 64 | kfree(value); |
88 | } else if (size == -ENOENT || size == -ENODATA || size == 0) { | 65 | } else if (size == -ENOENT || size == -ENODATA || size == 0) { |
89 | /* FIXME, who returns -ENOENT? I think nobody */ | 66 | /* FIXME, who returns -ENOENT? I think nobody */ |
90 | acl = NULL; | 67 | acl = NULL; |
91 | btrfs_update_cached_acl(inode, p_acl, acl); | 68 | set_cached_acl(inode, type, acl); |
92 | } else { | 69 | } else { |
93 | acl = ERR_PTR(-EIO); | 70 | acl = ERR_PTR(-EIO); |
94 | } | 71 | } |
@@ -121,7 +98,6 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) | |||
121 | { | 98 | { |
122 | int ret, size = 0; | 99 | int ret, size = 0; |
123 | const char *name; | 100 | const char *name; |
124 | struct posix_acl **p_acl; | ||
125 | char *value = NULL; | 101 | char *value = NULL; |
126 | mode_t mode; | 102 | mode_t mode; |
127 | 103 | ||
@@ -141,13 +117,11 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) | |||
141 | ret = 0; | 117 | ret = 0; |
142 | inode->i_mode = mode; | 118 | inode->i_mode = mode; |
143 | name = POSIX_ACL_XATTR_ACCESS; | 119 | name = POSIX_ACL_XATTR_ACCESS; |
144 | p_acl = &BTRFS_I(inode)->i_acl; | ||
145 | break; | 120 | break; |
146 | case ACL_TYPE_DEFAULT: | 121 | case ACL_TYPE_DEFAULT: |
147 | if (!S_ISDIR(inode->i_mode)) | 122 | if (!S_ISDIR(inode->i_mode)) |
148 | return acl ? -EINVAL : 0; | 123 | return acl ? -EINVAL : 0; |
149 | name = POSIX_ACL_XATTR_DEFAULT; | 124 | name = POSIX_ACL_XATTR_DEFAULT; |
150 | p_acl = &BTRFS_I(inode)->i_default_acl; | ||
151 | break; | 125 | break; |
152 | default: | 126 | default: |
153 | return -EINVAL; | 127 | return -EINVAL; |
@@ -172,7 +146,7 @@ out: | |||
172 | kfree(value); | 146 | kfree(value); |
173 | 147 | ||
174 | if (!ret) | 148 | if (!ret) |
175 | btrfs_update_cached_acl(inode, p_acl, acl); | 149 | set_cached_acl(inode, type, acl); |
176 | 150 | ||
177 | return ret; | 151 | return ret; |
178 | } | 152 | } |
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 7f88628a1a72..6e4f6c50a120 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c | |||
@@ -299,8 +299,8 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) | |||
299 | "btrfs-%s-%d", workers->name, | 299 | "btrfs-%s-%d", workers->name, |
300 | workers->num_workers + i); | 300 | workers->num_workers + i); |
301 | if (IS_ERR(worker->task)) { | 301 | if (IS_ERR(worker->task)) { |
302 | kfree(worker); | ||
303 | ret = PTR_ERR(worker->task); | 302 | ret = PTR_ERR(worker->task); |
303 | kfree(worker); | ||
304 | goto fail; | 304 | goto fail; |
305 | } | 305 | } |
306 | 306 | ||
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index acb4f3517582..ea1ea0af8c0e 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h | |||
@@ -53,10 +53,6 @@ struct btrfs_inode { | |||
53 | /* used to order data wrt metadata */ | 53 | /* used to order data wrt metadata */ |
54 | struct btrfs_ordered_inode_tree ordered_tree; | 54 | struct btrfs_ordered_inode_tree ordered_tree; |
55 | 55 | ||
56 | /* standard acl pointers */ | ||
57 | struct posix_acl *i_acl; | ||
58 | struct posix_acl *i_default_acl; | ||
59 | |||
60 | /* for keeping track of orphaned inodes */ | 56 | /* for keeping track of orphaned inodes */ |
61 | struct list_head i_orphan; | 57 | struct list_head i_orphan; |
62 | 58 | ||
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 03441a99ea38..98a873838717 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -41,8 +41,6 @@ struct btrfs_ordered_sum; | |||
41 | 41 | ||
42 | #define BTRFS_MAGIC "_BHRfS_M" | 42 | #define BTRFS_MAGIC "_BHRfS_M" |
43 | 43 | ||
44 | #define BTRFS_ACL_NOT_CACHED ((void *)-1) | ||
45 | |||
46 | #define BTRFS_MAX_LEVEL 8 | 44 | #define BTRFS_MAX_LEVEL 8 |
47 | 45 | ||
48 | #define BTRFS_COMPAT_EXTENT_TREE_V0 | 46 | #define BTRFS_COMPAT_EXTENT_TREE_V0 |
@@ -2076,8 +2074,7 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, | |||
2076 | int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); | 2074 | int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); |
2077 | int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path); | 2075 | int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path); |
2078 | int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf); | 2076 | int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf); |
2079 | int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | 2077 | int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref); |
2080 | *root); | ||
2081 | int btrfs_drop_subtree(struct btrfs_trans_handle *trans, | 2078 | int btrfs_drop_subtree(struct btrfs_trans_handle *trans, |
2082 | struct btrfs_root *root, | 2079 | struct btrfs_root *root, |
2083 | struct extent_buffer *node, | 2080 | struct extent_buffer *node, |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index edc7d208c5ce..a5aca3997d42 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -990,15 +990,13 @@ static inline int extent_ref_type(u64 parent, u64 owner) | |||
990 | return type; | 990 | return type; |
991 | } | 991 | } |
992 | 992 | ||
993 | static int find_next_key(struct btrfs_path *path, struct btrfs_key *key) | 993 | static int find_next_key(struct btrfs_path *path, int level, |
994 | struct btrfs_key *key) | ||
994 | 995 | ||
995 | { | 996 | { |
996 | int level; | 997 | for (; level < BTRFS_MAX_LEVEL; level++) { |
997 | BUG_ON(!path->keep_locks); | ||
998 | for (level = 0; level < BTRFS_MAX_LEVEL; level++) { | ||
999 | if (!path->nodes[level]) | 998 | if (!path->nodes[level]) |
1000 | break; | 999 | break; |
1001 | btrfs_assert_tree_locked(path->nodes[level]); | ||
1002 | if (path->slots[level] + 1 >= | 1000 | if (path->slots[level] + 1 >= |
1003 | btrfs_header_nritems(path->nodes[level])) | 1001 | btrfs_header_nritems(path->nodes[level])) |
1004 | continue; | 1002 | continue; |
@@ -1158,7 +1156,8 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, | |||
1158 | * For simplicity, we just do not add new inline back | 1156 | * For simplicity, we just do not add new inline back |
1159 | * ref if there is any kind of item for this block | 1157 | * ref if there is any kind of item for this block |
1160 | */ | 1158 | */ |
1161 | if (find_next_key(path, &key) == 0 && key.objectid == bytenr && | 1159 | if (find_next_key(path, 0, &key) == 0 && |
1160 | key.objectid == bytenr && | ||
1162 | key.type < BTRFS_BLOCK_GROUP_ITEM_KEY) { | 1161 | key.type < BTRFS_BLOCK_GROUP_ITEM_KEY) { |
1163 | err = -EAGAIN; | 1162 | err = -EAGAIN; |
1164 | goto out; | 1163 | goto out; |
@@ -2697,7 +2696,7 @@ again: | |||
2697 | 2696 | ||
2698 | printk(KERN_ERR "no space left, need %llu, %llu delalloc bytes" | 2697 | printk(KERN_ERR "no space left, need %llu, %llu delalloc bytes" |
2699 | ", %llu bytes_used, %llu bytes_reserved, " | 2698 | ", %llu bytes_used, %llu bytes_reserved, " |
2700 | "%llu bytes_pinned, %llu bytes_readonly, %llu may use" | 2699 | "%llu bytes_pinned, %llu bytes_readonly, %llu may use " |
2701 | "%llu total\n", (unsigned long long)bytes, | 2700 | "%llu total\n", (unsigned long long)bytes, |
2702 | (unsigned long long)data_sinfo->bytes_delalloc, | 2701 | (unsigned long long)data_sinfo->bytes_delalloc, |
2703 | (unsigned long long)data_sinfo->bytes_used, | 2702 | (unsigned long long)data_sinfo->bytes_used, |
@@ -4128,6 +4127,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
4128 | return buf; | 4127 | return buf; |
4129 | } | 4128 | } |
4130 | 4129 | ||
4130 | #if 0 | ||
4131 | int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, | 4131 | int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, |
4132 | struct btrfs_root *root, struct extent_buffer *leaf) | 4132 | struct btrfs_root *root, struct extent_buffer *leaf) |
4133 | { | 4133 | { |
@@ -4171,8 +4171,6 @@ int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, | |||
4171 | return 0; | 4171 | return 0; |
4172 | } | 4172 | } |
4173 | 4173 | ||
4174 | #if 0 | ||
4175 | |||
4176 | static noinline int cache_drop_leaf_ref(struct btrfs_trans_handle *trans, | 4174 | static noinline int cache_drop_leaf_ref(struct btrfs_trans_handle *trans, |
4177 | struct btrfs_root *root, | 4175 | struct btrfs_root *root, |
4178 | struct btrfs_leaf_ref *ref) | 4176 | struct btrfs_leaf_ref *ref) |
@@ -4553,262 +4551,471 @@ out: | |||
4553 | } | 4551 | } |
4554 | #endif | 4552 | #endif |
4555 | 4553 | ||
4554 | struct walk_control { | ||
4555 | u64 refs[BTRFS_MAX_LEVEL]; | ||
4556 | u64 flags[BTRFS_MAX_LEVEL]; | ||
4557 | struct btrfs_key update_progress; | ||
4558 | int stage; | ||
4559 | int level; | ||
4560 | int shared_level; | ||
4561 | int update_ref; | ||
4562 | int keep_locks; | ||
4563 | }; | ||
4564 | |||
4565 | #define DROP_REFERENCE 1 | ||
4566 | #define UPDATE_BACKREF 2 | ||
4567 | |||
4556 | /* | 4568 | /* |
4557 | * helper function for drop_subtree, this function is similar to | 4569 | * hepler to process tree block while walking down the tree. |
4558 | * walk_down_tree. The main difference is that it checks reference | 4570 | * |
4559 | * counts while tree blocks are locked. | 4571 | * when wc->stage == DROP_REFERENCE, this function checks |
4572 | * reference count of the block. if the block is shared and | ||
4573 | * we need update back refs for the subtree rooted at the | ||
4574 | * block, this function changes wc->stage to UPDATE_BACKREF | ||
4575 | * | ||
4576 | * when wc->stage == UPDATE_BACKREF, this function updates | ||
4577 | * back refs for pointers in the block. | ||
4578 | * | ||
4579 | * NOTE: return value 1 means we should stop walking down. | ||
4560 | */ | 4580 | */ |
4561 | static noinline int walk_down_tree(struct btrfs_trans_handle *trans, | 4581 | static noinline int walk_down_proc(struct btrfs_trans_handle *trans, |
4562 | struct btrfs_root *root, | 4582 | struct btrfs_root *root, |
4563 | struct btrfs_path *path, int *level) | 4583 | struct btrfs_path *path, |
4584 | struct walk_control *wc) | ||
4564 | { | 4585 | { |
4565 | struct extent_buffer *next; | 4586 | int level = wc->level; |
4566 | struct extent_buffer *cur; | 4587 | struct extent_buffer *eb = path->nodes[level]; |
4567 | struct extent_buffer *parent; | 4588 | struct btrfs_key key; |
4568 | u64 bytenr; | 4589 | u64 flag = BTRFS_BLOCK_FLAG_FULL_BACKREF; |
4569 | u64 ptr_gen; | ||
4570 | u64 refs; | ||
4571 | u64 flags; | ||
4572 | u32 blocksize; | ||
4573 | int ret; | 4590 | int ret; |
4574 | 4591 | ||
4575 | cur = path->nodes[*level]; | 4592 | if (wc->stage == UPDATE_BACKREF && |
4576 | ret = btrfs_lookup_extent_info(trans, root, cur->start, cur->len, | 4593 | btrfs_header_owner(eb) != root->root_key.objectid) |
4577 | &refs, &flags); | 4594 | return 1; |
4578 | BUG_ON(ret); | ||
4579 | if (refs > 1) | ||
4580 | goto out; | ||
4581 | 4595 | ||
4582 | BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)); | 4596 | /* |
4597 | * when reference count of tree block is 1, it won't increase | ||
4598 | * again. once full backref flag is set, we never clear it. | ||
4599 | */ | ||
4600 | if ((wc->stage == DROP_REFERENCE && wc->refs[level] != 1) || | ||
4601 | (wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag))) { | ||
4602 | BUG_ON(!path->locks[level]); | ||
4603 | ret = btrfs_lookup_extent_info(trans, root, | ||
4604 | eb->start, eb->len, | ||
4605 | &wc->refs[level], | ||
4606 | &wc->flags[level]); | ||
4607 | BUG_ON(ret); | ||
4608 | BUG_ON(wc->refs[level] == 0); | ||
4609 | } | ||
4583 | 4610 | ||
4584 | while (*level >= 0) { | 4611 | if (wc->stage == DROP_REFERENCE && |
4585 | cur = path->nodes[*level]; | 4612 | wc->update_ref && wc->refs[level] > 1) { |
4586 | if (*level == 0) { | 4613 | BUG_ON(eb == root->node); |
4587 | ret = btrfs_drop_leaf_ref(trans, root, cur); | 4614 | BUG_ON(path->slots[level] > 0); |
4588 | BUG_ON(ret); | 4615 | if (level == 0) |
4589 | clean_tree_block(trans, root, cur); | 4616 | btrfs_item_key_to_cpu(eb, &key, path->slots[level]); |
4590 | break; | 4617 | else |
4591 | } | 4618 | btrfs_node_key_to_cpu(eb, &key, path->slots[level]); |
4592 | if (path->slots[*level] >= btrfs_header_nritems(cur)) { | 4619 | if (btrfs_header_owner(eb) == root->root_key.objectid && |
4593 | clean_tree_block(trans, root, cur); | 4620 | btrfs_comp_cpu_keys(&key, &wc->update_progress) >= 0) { |
4594 | break; | 4621 | wc->stage = UPDATE_BACKREF; |
4622 | wc->shared_level = level; | ||
4595 | } | 4623 | } |
4624 | } | ||
4596 | 4625 | ||
4597 | bytenr = btrfs_node_blockptr(cur, path->slots[*level]); | 4626 | if (wc->stage == DROP_REFERENCE) { |
4598 | blocksize = btrfs_level_size(root, *level - 1); | 4627 | if (wc->refs[level] > 1) |
4599 | ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]); | 4628 | return 1; |
4600 | 4629 | ||
4601 | next = read_tree_block(root, bytenr, blocksize, ptr_gen); | 4630 | if (path->locks[level] && !wc->keep_locks) { |
4602 | btrfs_tree_lock(next); | 4631 | btrfs_tree_unlock(eb); |
4603 | btrfs_set_lock_blocking(next); | 4632 | path->locks[level] = 0; |
4633 | } | ||
4634 | return 0; | ||
4635 | } | ||
4604 | 4636 | ||
4605 | ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize, | 4637 | /* wc->stage == UPDATE_BACKREF */ |
4606 | &refs, &flags); | 4638 | if (!(wc->flags[level] & flag)) { |
4639 | BUG_ON(!path->locks[level]); | ||
4640 | ret = btrfs_inc_ref(trans, root, eb, 1); | ||
4607 | BUG_ON(ret); | 4641 | BUG_ON(ret); |
4608 | if (refs > 1) { | 4642 | ret = btrfs_dec_ref(trans, root, eb, 0); |
4609 | parent = path->nodes[*level]; | 4643 | BUG_ON(ret); |
4610 | ret = btrfs_free_extent(trans, root, bytenr, | 4644 | ret = btrfs_set_disk_extent_flags(trans, root, eb->start, |
4611 | blocksize, parent->start, | 4645 | eb->len, flag, 0); |
4612 | btrfs_header_owner(parent), | 4646 | BUG_ON(ret); |
4613 | *level - 1, 0); | 4647 | wc->flags[level] |= flag; |
4648 | } | ||
4649 | |||
4650 | /* | ||
4651 | * the block is shared by multiple trees, so it's not good to | ||
4652 | * keep the tree lock | ||
4653 | */ | ||
4654 | if (path->locks[level] && level > 0) { | ||
4655 | btrfs_tree_unlock(eb); | ||
4656 | path->locks[level] = 0; | ||
4657 | } | ||
4658 | return 0; | ||
4659 | } | ||
4660 | |||
4661 | /* | ||
4662 | * hepler to process tree block while walking up the tree. | ||
4663 | * | ||
4664 | * when wc->stage == DROP_REFERENCE, this function drops | ||
4665 | * reference count on the block. | ||
4666 | * | ||
4667 | * when wc->stage == UPDATE_BACKREF, this function changes | ||
4668 | * wc->stage back to DROP_REFERENCE if we changed wc->stage | ||
4669 | * to UPDATE_BACKREF previously while processing the block. | ||
4670 | * | ||
4671 | * NOTE: return value 1 means we should stop walking up. | ||
4672 | */ | ||
4673 | static noinline int walk_up_proc(struct btrfs_trans_handle *trans, | ||
4674 | struct btrfs_root *root, | ||
4675 | struct btrfs_path *path, | ||
4676 | struct walk_control *wc) | ||
4677 | { | ||
4678 | int ret = 0; | ||
4679 | int level = wc->level; | ||
4680 | struct extent_buffer *eb = path->nodes[level]; | ||
4681 | u64 parent = 0; | ||
4682 | |||
4683 | if (wc->stage == UPDATE_BACKREF) { | ||
4684 | BUG_ON(wc->shared_level < level); | ||
4685 | if (level < wc->shared_level) | ||
4686 | goto out; | ||
4687 | |||
4688 | BUG_ON(wc->refs[level] <= 1); | ||
4689 | ret = find_next_key(path, level + 1, &wc->update_progress); | ||
4690 | if (ret > 0) | ||
4691 | wc->update_ref = 0; | ||
4692 | |||
4693 | wc->stage = DROP_REFERENCE; | ||
4694 | wc->shared_level = -1; | ||
4695 | path->slots[level] = 0; | ||
4696 | |||
4697 | /* | ||
4698 | * check reference count again if the block isn't locked. | ||
4699 | * we should start walking down the tree again if reference | ||
4700 | * count is one. | ||
4701 | */ | ||
4702 | if (!path->locks[level]) { | ||
4703 | BUG_ON(level == 0); | ||
4704 | btrfs_tree_lock(eb); | ||
4705 | btrfs_set_lock_blocking(eb); | ||
4706 | path->locks[level] = 1; | ||
4707 | |||
4708 | ret = btrfs_lookup_extent_info(trans, root, | ||
4709 | eb->start, eb->len, | ||
4710 | &wc->refs[level], | ||
4711 | &wc->flags[level]); | ||
4614 | BUG_ON(ret); | 4712 | BUG_ON(ret); |
4615 | path->slots[*level]++; | 4713 | BUG_ON(wc->refs[level] == 0); |
4616 | btrfs_tree_unlock(next); | 4714 | if (wc->refs[level] == 1) { |
4617 | free_extent_buffer(next); | 4715 | btrfs_tree_unlock(eb); |
4618 | continue; | 4716 | path->locks[level] = 0; |
4717 | return 1; | ||
4718 | } | ||
4719 | } else { | ||
4720 | BUG_ON(level != 0); | ||
4619 | } | 4721 | } |
4722 | } | ||
4620 | 4723 | ||
4621 | BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)); | 4724 | /* wc->stage == DROP_REFERENCE */ |
4725 | BUG_ON(wc->refs[level] > 1 && !path->locks[level]); | ||
4622 | 4726 | ||
4623 | *level = btrfs_header_level(next); | 4727 | if (wc->refs[level] == 1) { |
4624 | path->nodes[*level] = next; | 4728 | if (level == 0) { |
4625 | path->slots[*level] = 0; | 4729 | if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) |
4626 | path->locks[*level] = 1; | 4730 | ret = btrfs_dec_ref(trans, root, eb, 1); |
4627 | cond_resched(); | 4731 | else |
4732 | ret = btrfs_dec_ref(trans, root, eb, 0); | ||
4733 | BUG_ON(ret); | ||
4734 | } | ||
4735 | /* make block locked assertion in clean_tree_block happy */ | ||
4736 | if (!path->locks[level] && | ||
4737 | btrfs_header_generation(eb) == trans->transid) { | ||
4738 | btrfs_tree_lock(eb); | ||
4739 | btrfs_set_lock_blocking(eb); | ||
4740 | path->locks[level] = 1; | ||
4741 | } | ||
4742 | clean_tree_block(trans, root, eb); | ||
4743 | } | ||
4744 | |||
4745 | if (eb == root->node) { | ||
4746 | if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) | ||
4747 | parent = eb->start; | ||
4748 | else | ||
4749 | BUG_ON(root->root_key.objectid != | ||
4750 | btrfs_header_owner(eb)); | ||
4751 | } else { | ||
4752 | if (wc->flags[level + 1] & BTRFS_BLOCK_FLAG_FULL_BACKREF) | ||
4753 | parent = path->nodes[level + 1]->start; | ||
4754 | else | ||
4755 | BUG_ON(root->root_key.objectid != | ||
4756 | btrfs_header_owner(path->nodes[level + 1])); | ||
4628 | } | 4757 | } |
4629 | out: | ||
4630 | if (path->nodes[*level] == root->node) | ||
4631 | parent = path->nodes[*level]; | ||
4632 | else | ||
4633 | parent = path->nodes[*level + 1]; | ||
4634 | bytenr = path->nodes[*level]->start; | ||
4635 | blocksize = path->nodes[*level]->len; | ||
4636 | 4758 | ||
4637 | ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent->start, | 4759 | ret = btrfs_free_extent(trans, root, eb->start, eb->len, parent, |
4638 | btrfs_header_owner(parent), *level, 0); | 4760 | root->root_key.objectid, level, 0); |
4639 | BUG_ON(ret); | 4761 | BUG_ON(ret); |
4762 | out: | ||
4763 | wc->refs[level] = 0; | ||
4764 | wc->flags[level] = 0; | ||
4765 | return ret; | ||
4766 | } | ||
4767 | |||
4768 | static noinline int walk_down_tree(struct btrfs_trans_handle *trans, | ||
4769 | struct btrfs_root *root, | ||
4770 | struct btrfs_path *path, | ||
4771 | struct walk_control *wc) | ||
4772 | { | ||
4773 | struct extent_buffer *next; | ||
4774 | struct extent_buffer *cur; | ||
4775 | u64 bytenr; | ||
4776 | u64 ptr_gen; | ||
4777 | u32 blocksize; | ||
4778 | int level = wc->level; | ||
4779 | int ret; | ||
4780 | |||
4781 | while (level >= 0) { | ||
4782 | cur = path->nodes[level]; | ||
4783 | BUG_ON(path->slots[level] >= btrfs_header_nritems(cur)); | ||
4640 | 4784 | ||
4641 | if (path->locks[*level]) { | 4785 | ret = walk_down_proc(trans, root, path, wc); |
4642 | btrfs_tree_unlock(path->nodes[*level]); | 4786 | if (ret > 0) |
4643 | path->locks[*level] = 0; | 4787 | break; |
4788 | |||
4789 | if (level == 0) | ||
4790 | break; | ||
4791 | |||
4792 | bytenr = btrfs_node_blockptr(cur, path->slots[level]); | ||
4793 | blocksize = btrfs_level_size(root, level - 1); | ||
4794 | ptr_gen = btrfs_node_ptr_generation(cur, path->slots[level]); | ||
4795 | |||
4796 | next = read_tree_block(root, bytenr, blocksize, ptr_gen); | ||
4797 | btrfs_tree_lock(next); | ||
4798 | btrfs_set_lock_blocking(next); | ||
4799 | |||
4800 | level--; | ||
4801 | BUG_ON(level != btrfs_header_level(next)); | ||
4802 | path->nodes[level] = next; | ||
4803 | path->slots[level] = 0; | ||
4804 | path->locks[level] = 1; | ||
4805 | wc->level = level; | ||
4644 | } | 4806 | } |
4645 | free_extent_buffer(path->nodes[*level]); | ||
4646 | path->nodes[*level] = NULL; | ||
4647 | *level += 1; | ||
4648 | cond_resched(); | ||
4649 | return 0; | 4807 | return 0; |
4650 | } | 4808 | } |
4651 | 4809 | ||
4652 | /* | ||
4653 | * helper for dropping snapshots. This walks back up the tree in the path | ||
4654 | * to find the first node higher up where we haven't yet gone through | ||
4655 | * all the slots | ||
4656 | */ | ||
4657 | static noinline int walk_up_tree(struct btrfs_trans_handle *trans, | 4810 | static noinline int walk_up_tree(struct btrfs_trans_handle *trans, |
4658 | struct btrfs_root *root, | 4811 | struct btrfs_root *root, |
4659 | struct btrfs_path *path, | 4812 | struct btrfs_path *path, |
4660 | int *level, int max_level) | 4813 | struct walk_control *wc, int max_level) |
4661 | { | 4814 | { |
4662 | struct btrfs_root_item *root_item = &root->root_item; | 4815 | int level = wc->level; |
4663 | int i; | ||
4664 | int slot; | ||
4665 | int ret; | 4816 | int ret; |
4666 | 4817 | ||
4667 | for (i = *level; i < max_level && path->nodes[i]; i++) { | 4818 | path->slots[level] = btrfs_header_nritems(path->nodes[level]); |
4668 | slot = path->slots[i]; | 4819 | while (level < max_level && path->nodes[level]) { |
4669 | if (slot + 1 < btrfs_header_nritems(path->nodes[i])) { | 4820 | wc->level = level; |
4670 | /* | 4821 | if (path->slots[level] + 1 < |
4671 | * there is more work to do in this level. | 4822 | btrfs_header_nritems(path->nodes[level])) { |
4672 | * Update the drop_progress marker to reflect | 4823 | path->slots[level]++; |
4673 | * the work we've done so far, and then bump | ||
4674 | * the slot number | ||
4675 | */ | ||
4676 | path->slots[i]++; | ||
4677 | WARN_ON(*level == 0); | ||
4678 | if (max_level == BTRFS_MAX_LEVEL) { | ||
4679 | btrfs_node_key(path->nodes[i], | ||
4680 | &root_item->drop_progress, | ||
4681 | path->slots[i]); | ||
4682 | root_item->drop_level = i; | ||
4683 | } | ||
4684 | *level = i; | ||
4685 | return 0; | 4824 | return 0; |
4686 | } else { | 4825 | } else { |
4687 | struct extent_buffer *parent; | 4826 | ret = walk_up_proc(trans, root, path, wc); |
4688 | 4827 | if (ret > 0) | |
4689 | /* | 4828 | return 0; |
4690 | * this whole node is done, free our reference | ||
4691 | * on it and go up one level | ||
4692 | */ | ||
4693 | if (path->nodes[*level] == root->node) | ||
4694 | parent = path->nodes[*level]; | ||
4695 | else | ||
4696 | parent = path->nodes[*level + 1]; | ||
4697 | 4829 | ||
4698 | clean_tree_block(trans, root, path->nodes[i]); | 4830 | if (path->locks[level]) { |
4699 | ret = btrfs_free_extent(trans, root, | 4831 | btrfs_tree_unlock(path->nodes[level]); |
4700 | path->nodes[i]->start, | 4832 | path->locks[level] = 0; |
4701 | path->nodes[i]->len, | ||
4702 | parent->start, | ||
4703 | btrfs_header_owner(parent), | ||
4704 | *level, 0); | ||
4705 | BUG_ON(ret); | ||
4706 | if (path->locks[*level]) { | ||
4707 | btrfs_tree_unlock(path->nodes[i]); | ||
4708 | path->locks[i] = 0; | ||
4709 | } | 4833 | } |
4710 | free_extent_buffer(path->nodes[i]); | 4834 | free_extent_buffer(path->nodes[level]); |
4711 | path->nodes[i] = NULL; | 4835 | path->nodes[level] = NULL; |
4712 | *level = i + 1; | 4836 | level++; |
4713 | } | 4837 | } |
4714 | } | 4838 | } |
4715 | return 1; | 4839 | return 1; |
4716 | } | 4840 | } |
4717 | 4841 | ||
4718 | /* | 4842 | /* |
4719 | * drop the reference count on the tree rooted at 'snap'. This traverses | 4843 | * drop a subvolume tree. |
4720 | * the tree freeing any blocks that have a ref count of zero after being | 4844 | * |
4721 | * decremented. | 4845 | * this function traverses the tree freeing any blocks that only |
4846 | * referenced by the tree. | ||
4847 | * | ||
4848 | * when a shared tree block is found. this function decreases its | ||
4849 | * reference count by one. if update_ref is true, this function | ||
4850 | * also make sure backrefs for the shared block and all lower level | ||
4851 | * blocks are properly updated. | ||
4722 | */ | 4852 | */ |
4723 | int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | 4853 | int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref) |
4724 | *root) | ||
4725 | { | 4854 | { |
4726 | int ret = 0; | ||
4727 | int wret; | ||
4728 | int level; | ||
4729 | struct btrfs_path *path; | 4855 | struct btrfs_path *path; |
4730 | int update_count; | 4856 | struct btrfs_trans_handle *trans; |
4857 | struct btrfs_root *tree_root = root->fs_info->tree_root; | ||
4731 | struct btrfs_root_item *root_item = &root->root_item; | 4858 | struct btrfs_root_item *root_item = &root->root_item; |
4859 | struct walk_control *wc; | ||
4860 | struct btrfs_key key; | ||
4861 | int err = 0; | ||
4862 | int ret; | ||
4863 | int level; | ||
4732 | 4864 | ||
4733 | path = btrfs_alloc_path(); | 4865 | path = btrfs_alloc_path(); |
4734 | BUG_ON(!path); | 4866 | BUG_ON(!path); |
4735 | 4867 | ||
4736 | level = btrfs_header_level(root->node); | 4868 | wc = kzalloc(sizeof(*wc), GFP_NOFS); |
4869 | BUG_ON(!wc); | ||
4870 | |||
4871 | trans = btrfs_start_transaction(tree_root, 1); | ||
4872 | |||
4737 | if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) { | 4873 | if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) { |
4874 | level = btrfs_header_level(root->node); | ||
4738 | path->nodes[level] = btrfs_lock_root_node(root); | 4875 | path->nodes[level] = btrfs_lock_root_node(root); |
4739 | btrfs_set_lock_blocking(path->nodes[level]); | 4876 | btrfs_set_lock_blocking(path->nodes[level]); |
4740 | path->slots[level] = 0; | 4877 | path->slots[level] = 0; |
4741 | path->locks[level] = 1; | 4878 | path->locks[level] = 1; |
4879 | memset(&wc->update_progress, 0, | ||
4880 | sizeof(wc->update_progress)); | ||
4742 | } else { | 4881 | } else { |
4743 | struct btrfs_key key; | ||
4744 | struct btrfs_disk_key found_key; | ||
4745 | struct extent_buffer *node; | ||
4746 | |||
4747 | btrfs_disk_key_to_cpu(&key, &root_item->drop_progress); | 4882 | btrfs_disk_key_to_cpu(&key, &root_item->drop_progress); |
4883 | memcpy(&wc->update_progress, &key, | ||
4884 | sizeof(wc->update_progress)); | ||
4885 | |||
4748 | level = root_item->drop_level; | 4886 | level = root_item->drop_level; |
4887 | BUG_ON(level == 0); | ||
4749 | path->lowest_level = level; | 4888 | path->lowest_level = level; |
4750 | wret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 4889 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
4751 | if (wret < 0) { | 4890 | path->lowest_level = 0; |
4752 | ret = wret; | 4891 | if (ret < 0) { |
4892 | err = ret; | ||
4753 | goto out; | 4893 | goto out; |
4754 | } | 4894 | } |
4755 | node = path->nodes[level]; | 4895 | btrfs_node_key_to_cpu(path->nodes[level], &key, |
4756 | btrfs_node_key(node, &found_key, path->slots[level]); | 4896 | path->slots[level]); |
4757 | WARN_ON(memcmp(&found_key, &root_item->drop_progress, | 4897 | WARN_ON(memcmp(&key, &wc->update_progress, sizeof(key))); |
4758 | sizeof(found_key))); | 4898 | |
4759 | /* | 4899 | /* |
4760 | * unlock our path, this is safe because only this | 4900 | * unlock our path, this is safe because only this |
4761 | * function is allowed to delete this snapshot | 4901 | * function is allowed to delete this snapshot |
4762 | */ | 4902 | */ |
4763 | btrfs_unlock_up_safe(path, 0); | 4903 | btrfs_unlock_up_safe(path, 0); |
4904 | |||
4905 | level = btrfs_header_level(root->node); | ||
4906 | while (1) { | ||
4907 | btrfs_tree_lock(path->nodes[level]); | ||
4908 | btrfs_set_lock_blocking(path->nodes[level]); | ||
4909 | |||
4910 | ret = btrfs_lookup_extent_info(trans, root, | ||
4911 | path->nodes[level]->start, | ||
4912 | path->nodes[level]->len, | ||
4913 | &wc->refs[level], | ||
4914 | &wc->flags[level]); | ||
4915 | BUG_ON(ret); | ||
4916 | BUG_ON(wc->refs[level] == 0); | ||
4917 | |||
4918 | if (level == root_item->drop_level) | ||
4919 | break; | ||
4920 | |||
4921 | btrfs_tree_unlock(path->nodes[level]); | ||
4922 | WARN_ON(wc->refs[level] != 1); | ||
4923 | level--; | ||
4924 | } | ||
4764 | } | 4925 | } |
4926 | |||
4927 | wc->level = level; | ||
4928 | wc->shared_level = -1; | ||
4929 | wc->stage = DROP_REFERENCE; | ||
4930 | wc->update_ref = update_ref; | ||
4931 | wc->keep_locks = 0; | ||
4932 | |||
4765 | while (1) { | 4933 | while (1) { |
4766 | unsigned long update; | 4934 | ret = walk_down_tree(trans, root, path, wc); |
4767 | wret = walk_down_tree(trans, root, path, &level); | 4935 | if (ret < 0) { |
4768 | if (wret > 0) | 4936 | err = ret; |
4769 | break; | 4937 | break; |
4770 | if (wret < 0) | 4938 | } |
4771 | ret = wret; | ||
4772 | 4939 | ||
4773 | wret = walk_up_tree(trans, root, path, &level, | 4940 | ret = walk_up_tree(trans, root, path, wc, BTRFS_MAX_LEVEL); |
4774 | BTRFS_MAX_LEVEL); | 4941 | if (ret < 0) { |
4775 | if (wret > 0) | 4942 | err = ret; |
4776 | break; | 4943 | break; |
4777 | if (wret < 0) | 4944 | } |
4778 | ret = wret; | 4945 | |
4779 | if (trans->transaction->in_commit || | 4946 | if (ret > 0) { |
4780 | trans->transaction->delayed_refs.flushing) { | 4947 | BUG_ON(wc->stage != DROP_REFERENCE); |
4781 | ret = -EAGAIN; | ||
4782 | break; | 4948 | break; |
4783 | } | 4949 | } |
4784 | for (update_count = 0; update_count < 16; update_count++) { | 4950 | |
4951 | if (wc->stage == DROP_REFERENCE) { | ||
4952 | level = wc->level; | ||
4953 | btrfs_node_key(path->nodes[level], | ||
4954 | &root_item->drop_progress, | ||
4955 | path->slots[level]); | ||
4956 | root_item->drop_level = level; | ||
4957 | } | ||
4958 | |||
4959 | BUG_ON(wc->level == 0); | ||
4960 | if (trans->transaction->in_commit || | ||
4961 | trans->transaction->delayed_refs.flushing) { | ||
4962 | ret = btrfs_update_root(trans, tree_root, | ||
4963 | &root->root_key, | ||
4964 | root_item); | ||
4965 | BUG_ON(ret); | ||
4966 | |||
4967 | btrfs_end_transaction(trans, tree_root); | ||
4968 | trans = btrfs_start_transaction(tree_root, 1); | ||
4969 | } else { | ||
4970 | unsigned long update; | ||
4785 | update = trans->delayed_ref_updates; | 4971 | update = trans->delayed_ref_updates; |
4786 | trans->delayed_ref_updates = 0; | 4972 | trans->delayed_ref_updates = 0; |
4787 | if (update) | 4973 | if (update) |
4788 | btrfs_run_delayed_refs(trans, root, update); | 4974 | btrfs_run_delayed_refs(trans, tree_root, |
4789 | else | 4975 | update); |
4790 | break; | ||
4791 | } | 4976 | } |
4792 | } | 4977 | } |
4978 | btrfs_release_path(root, path); | ||
4979 | BUG_ON(err); | ||
4980 | |||
4981 | ret = btrfs_del_root(trans, tree_root, &root->root_key); | ||
4982 | BUG_ON(ret); | ||
4983 | |||
4984 | free_extent_buffer(root->node); | ||
4985 | free_extent_buffer(root->commit_root); | ||
4986 | kfree(root); | ||
4793 | out: | 4987 | out: |
4988 | btrfs_end_transaction(trans, tree_root); | ||
4989 | kfree(wc); | ||
4794 | btrfs_free_path(path); | 4990 | btrfs_free_path(path); |
4795 | return ret; | 4991 | return err; |
4796 | } | 4992 | } |
4797 | 4993 | ||
4994 | /* | ||
4995 | * drop subtree rooted at tree block 'node'. | ||
4996 | * | ||
4997 | * NOTE: this function will unlock and release tree block 'node' | ||
4998 | */ | ||
4798 | int btrfs_drop_subtree(struct btrfs_trans_handle *trans, | 4999 | int btrfs_drop_subtree(struct btrfs_trans_handle *trans, |
4799 | struct btrfs_root *root, | 5000 | struct btrfs_root *root, |
4800 | struct extent_buffer *node, | 5001 | struct extent_buffer *node, |
4801 | struct extent_buffer *parent) | 5002 | struct extent_buffer *parent) |
4802 | { | 5003 | { |
4803 | struct btrfs_path *path; | 5004 | struct btrfs_path *path; |
5005 | struct walk_control *wc; | ||
4804 | int level; | 5006 | int level; |
4805 | int parent_level; | 5007 | int parent_level; |
4806 | int ret = 0; | 5008 | int ret = 0; |
4807 | int wret; | 5009 | int wret; |
4808 | 5010 | ||
5011 | BUG_ON(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID); | ||
5012 | |||
4809 | path = btrfs_alloc_path(); | 5013 | path = btrfs_alloc_path(); |
4810 | BUG_ON(!path); | 5014 | BUG_ON(!path); |
4811 | 5015 | ||
5016 | wc = kzalloc(sizeof(*wc), GFP_NOFS); | ||
5017 | BUG_ON(!wc); | ||
5018 | |||
4812 | btrfs_assert_tree_locked(parent); | 5019 | btrfs_assert_tree_locked(parent); |
4813 | parent_level = btrfs_header_level(parent); | 5020 | parent_level = btrfs_header_level(parent); |
4814 | extent_buffer_get(parent); | 5021 | extent_buffer_get(parent); |
@@ -4817,24 +5024,33 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans, | |||
4817 | 5024 | ||
4818 | btrfs_assert_tree_locked(node); | 5025 | btrfs_assert_tree_locked(node); |
4819 | level = btrfs_header_level(node); | 5026 | level = btrfs_header_level(node); |
4820 | extent_buffer_get(node); | ||
4821 | path->nodes[level] = node; | 5027 | path->nodes[level] = node; |
4822 | path->slots[level] = 0; | 5028 | path->slots[level] = 0; |
5029 | path->locks[level] = 1; | ||
5030 | |||
5031 | wc->refs[parent_level] = 1; | ||
5032 | wc->flags[parent_level] = BTRFS_BLOCK_FLAG_FULL_BACKREF; | ||
5033 | wc->level = level; | ||
5034 | wc->shared_level = -1; | ||
5035 | wc->stage = DROP_REFERENCE; | ||
5036 | wc->update_ref = 0; | ||
5037 | wc->keep_locks = 1; | ||
4823 | 5038 | ||
4824 | while (1) { | 5039 | while (1) { |
4825 | wret = walk_down_tree(trans, root, path, &level); | 5040 | wret = walk_down_tree(trans, root, path, wc); |
4826 | if (wret < 0) | 5041 | if (wret < 0) { |
4827 | ret = wret; | 5042 | ret = wret; |
4828 | if (wret != 0) | ||
4829 | break; | 5043 | break; |
5044 | } | ||
4830 | 5045 | ||
4831 | wret = walk_up_tree(trans, root, path, &level, parent_level); | 5046 | wret = walk_up_tree(trans, root, path, wc, parent_level); |
4832 | if (wret < 0) | 5047 | if (wret < 0) |
4833 | ret = wret; | 5048 | ret = wret; |
4834 | if (wret != 0) | 5049 | if (wret != 0) |
4835 | break; | 5050 | break; |
4836 | } | 5051 | } |
4837 | 5052 | ||
5053 | kfree(wc); | ||
4838 | btrfs_free_path(path); | 5054 | btrfs_free_path(path); |
4839 | return ret; | 5055 | return ret; |
4840 | } | 5056 | } |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 126477eaecf5..7c3cd248d8d6 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -151,7 +151,10 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
151 | } | 151 | } |
152 | if (end_pos > isize) { | 152 | if (end_pos > isize) { |
153 | i_size_write(inode, end_pos); | 153 | i_size_write(inode, end_pos); |
154 | btrfs_update_inode(trans, root, inode); | 154 | /* we've only changed i_size in ram, and we haven't updated |
155 | * the disk i_size. There is no need to log the inode | ||
156 | * at this time. | ||
157 | */ | ||
155 | } | 158 | } |
156 | err = btrfs_end_transaction(trans, root); | 159 | err = btrfs_end_transaction(trans, root); |
157 | out_unlock: | 160 | out_unlock: |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8612b3a09811..7ffa3d34ea19 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2122,10 +2122,8 @@ static void btrfs_read_locked_inode(struct inode *inode) | |||
2122 | * any xattrs or acls | 2122 | * any xattrs or acls |
2123 | */ | 2123 | */ |
2124 | maybe_acls = acls_after_inode_item(leaf, path->slots[0], inode->i_ino); | 2124 | maybe_acls = acls_after_inode_item(leaf, path->slots[0], inode->i_ino); |
2125 | if (!maybe_acls) { | 2125 | if (!maybe_acls) |
2126 | BTRFS_I(inode)->i_acl = NULL; | 2126 | cache_no_acl(inode); |
2127 | BTRFS_I(inode)->i_default_acl = NULL; | ||
2128 | } | ||
2129 | 2127 | ||
2130 | BTRFS_I(inode)->block_group = btrfs_find_block_group(root, 0, | 2128 | BTRFS_I(inode)->block_group = btrfs_find_block_group(root, 0, |
2131 | alloc_group_block, 0); | 2129 | alloc_group_block, 0); |
@@ -3141,9 +3139,6 @@ static noinline void init_btrfs_i(struct inode *inode) | |||
3141 | { | 3139 | { |
3142 | struct btrfs_inode *bi = BTRFS_I(inode); | 3140 | struct btrfs_inode *bi = BTRFS_I(inode); |
3143 | 3141 | ||
3144 | bi->i_acl = BTRFS_ACL_NOT_CACHED; | ||
3145 | bi->i_default_acl = BTRFS_ACL_NOT_CACHED; | ||
3146 | |||
3147 | bi->generation = 0; | 3142 | bi->generation = 0; |
3148 | bi->sequence = 0; | 3143 | bi->sequence = 0; |
3149 | bi->last_trans = 0; | 3144 | bi->last_trans = 0; |
@@ -3585,12 +3580,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
3585 | owner = 1; | 3580 | owner = 1; |
3586 | BTRFS_I(inode)->block_group = | 3581 | BTRFS_I(inode)->block_group = |
3587 | btrfs_find_block_group(root, 0, alloc_hint, owner); | 3582 | btrfs_find_block_group(root, 0, alloc_hint, owner); |
3588 | if ((mode & S_IFREG)) { | ||
3589 | if (btrfs_test_opt(root, NODATASUM)) | ||
3590 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; | ||
3591 | if (btrfs_test_opt(root, NODATACOW)) | ||
3592 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; | ||
3593 | } | ||
3594 | 3583 | ||
3595 | key[0].objectid = objectid; | 3584 | key[0].objectid = objectid; |
3596 | btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY); | 3585 | btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY); |
@@ -3645,6 +3634,13 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
3645 | 3634 | ||
3646 | btrfs_inherit_iflags(inode, dir); | 3635 | btrfs_inherit_iflags(inode, dir); |
3647 | 3636 | ||
3637 | if ((mode & S_IFREG)) { | ||
3638 | if (btrfs_test_opt(root, NODATASUM)) | ||
3639 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; | ||
3640 | if (btrfs_test_opt(root, NODATACOW)) | ||
3641 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; | ||
3642 | } | ||
3643 | |||
3648 | insert_inode_hash(inode); | 3644 | insert_inode_hash(inode); |
3649 | inode_tree_add(inode); | 3645 | inode_tree_add(inode); |
3650 | return inode; | 3646 | return inode; |
@@ -4640,8 +4636,6 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) | |||
4640 | ei->last_trans = 0; | 4636 | ei->last_trans = 0; |
4641 | ei->logged_trans = 0; | 4637 | ei->logged_trans = 0; |
4642 | btrfs_ordered_inode_tree_init(&ei->ordered_tree); | 4638 | btrfs_ordered_inode_tree_init(&ei->ordered_tree); |
4643 | ei->i_acl = BTRFS_ACL_NOT_CACHED; | ||
4644 | ei->i_default_acl = BTRFS_ACL_NOT_CACHED; | ||
4645 | INIT_LIST_HEAD(&ei->i_orphan); | 4639 | INIT_LIST_HEAD(&ei->i_orphan); |
4646 | INIT_LIST_HEAD(&ei->ordered_operations); | 4640 | INIT_LIST_HEAD(&ei->ordered_operations); |
4647 | return &ei->vfs_inode; | 4641 | return &ei->vfs_inode; |
@@ -4655,13 +4649,6 @@ void btrfs_destroy_inode(struct inode *inode) | |||
4655 | WARN_ON(!list_empty(&inode->i_dentry)); | 4649 | WARN_ON(!list_empty(&inode->i_dentry)); |
4656 | WARN_ON(inode->i_data.nrpages); | 4650 | WARN_ON(inode->i_data.nrpages); |
4657 | 4651 | ||
4658 | if (BTRFS_I(inode)->i_acl && | ||
4659 | BTRFS_I(inode)->i_acl != BTRFS_ACL_NOT_CACHED) | ||
4660 | posix_acl_release(BTRFS_I(inode)->i_acl); | ||
4661 | if (BTRFS_I(inode)->i_default_acl && | ||
4662 | BTRFS_I(inode)->i_default_acl != BTRFS_ACL_NOT_CACHED) | ||
4663 | posix_acl_release(BTRFS_I(inode)->i_default_acl); | ||
4664 | |||
4665 | /* | 4652 | /* |
4666 | * Make sure we're properly removed from the ordered operation | 4653 | * Make sure we're properly removed from the ordered operation |
4667 | * lists. | 4654 | * lists. |
@@ -5096,6 +5083,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5096 | u64 mask = BTRFS_I(inode)->root->sectorsize - 1; | 5083 | u64 mask = BTRFS_I(inode)->root->sectorsize - 1; |
5097 | struct extent_map *em; | 5084 | struct extent_map *em; |
5098 | struct btrfs_trans_handle *trans; | 5085 | struct btrfs_trans_handle *trans; |
5086 | struct btrfs_root *root; | ||
5099 | int ret; | 5087 | int ret; |
5100 | 5088 | ||
5101 | alloc_start = offset & ~mask; | 5089 | alloc_start = offset & ~mask; |
@@ -5114,6 +5102,13 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5114 | goto out; | 5102 | goto out; |
5115 | } | 5103 | } |
5116 | 5104 | ||
5105 | root = BTRFS_I(inode)->root; | ||
5106 | |||
5107 | ret = btrfs_check_data_free_space(root, inode, | ||
5108 | alloc_end - alloc_start); | ||
5109 | if (ret) | ||
5110 | goto out; | ||
5111 | |||
5117 | locked_end = alloc_end - 1; | 5112 | locked_end = alloc_end - 1; |
5118 | while (1) { | 5113 | while (1) { |
5119 | struct btrfs_ordered_extent *ordered; | 5114 | struct btrfs_ordered_extent *ordered; |
@@ -5121,7 +5116,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5121 | trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1); | 5116 | trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1); |
5122 | if (!trans) { | 5117 | if (!trans) { |
5123 | ret = -EIO; | 5118 | ret = -EIO; |
5124 | goto out; | 5119 | goto out_free; |
5125 | } | 5120 | } |
5126 | 5121 | ||
5127 | /* the extent lock is ordered inside the running | 5122 | /* the extent lock is ordered inside the running |
@@ -5182,6 +5177,8 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5182 | GFP_NOFS); | 5177 | GFP_NOFS); |
5183 | 5178 | ||
5184 | btrfs_end_transaction(trans, BTRFS_I(inode)->root); | 5179 | btrfs_end_transaction(trans, BTRFS_I(inode)->root); |
5180 | out_free: | ||
5181 | btrfs_free_reserved_data_space(root, inode, alloc_end - alloc_start); | ||
5185 | out: | 5182 | out: |
5186 | mutex_unlock(&inode->i_mutex); | 5183 | mutex_unlock(&inode->i_mutex); |
5187 | return ret; | 5184 | return ret; |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index eff18f5b5362..9f4db848db10 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -1028,7 +1028,8 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1028 | struct btrfs_file_extent_item); | 1028 | struct btrfs_file_extent_item); |
1029 | comp = btrfs_file_extent_compression(leaf, extent); | 1029 | comp = btrfs_file_extent_compression(leaf, extent); |
1030 | type = btrfs_file_extent_type(leaf, extent); | 1030 | type = btrfs_file_extent_type(leaf, extent); |
1031 | if (type == BTRFS_FILE_EXTENT_REG) { | 1031 | if (type == BTRFS_FILE_EXTENT_REG || |
1032 | type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
1032 | disko = btrfs_file_extent_disk_bytenr(leaf, | 1033 | disko = btrfs_file_extent_disk_bytenr(leaf, |
1033 | extent); | 1034 | extent); |
1034 | diskl = btrfs_file_extent_disk_num_bytes(leaf, | 1035 | diskl = btrfs_file_extent_disk_num_bytes(leaf, |
@@ -1051,7 +1052,8 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1051 | new_key.objectid = inode->i_ino; | 1052 | new_key.objectid = inode->i_ino; |
1052 | new_key.offset = key.offset + destoff - off; | 1053 | new_key.offset = key.offset + destoff - off; |
1053 | 1054 | ||
1054 | if (type == BTRFS_FILE_EXTENT_REG) { | 1055 | if (type == BTRFS_FILE_EXTENT_REG || |
1056 | type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
1055 | ret = btrfs_insert_empty_item(trans, root, path, | 1057 | ret = btrfs_insert_empty_item(trans, root, path, |
1056 | &new_key, size); | 1058 | &new_key, size); |
1057 | if (ret) | 1059 | if (ret) |
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index b23dc209ae10..008397934778 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -1788,7 +1788,7 @@ static void merge_func(struct btrfs_work *work) | |||
1788 | btrfs_end_transaction(trans, root); | 1788 | btrfs_end_transaction(trans, root); |
1789 | } | 1789 | } |
1790 | 1790 | ||
1791 | btrfs_drop_dead_root(reloc_root); | 1791 | btrfs_drop_snapshot(reloc_root, 0); |
1792 | 1792 | ||
1793 | if (atomic_dec_and_test(async->num_pending)) | 1793 | if (atomic_dec_and_test(async->num_pending)) |
1794 | complete(async->done); | 1794 | complete(async->done); |
@@ -2075,9 +2075,6 @@ static int do_relocation(struct btrfs_trans_handle *trans, | |||
2075 | 2075 | ||
2076 | ret = btrfs_drop_subtree(trans, root, eb, upper->eb); | 2076 | ret = btrfs_drop_subtree(trans, root, eb, upper->eb); |
2077 | BUG_ON(ret); | 2077 | BUG_ON(ret); |
2078 | |||
2079 | btrfs_tree_unlock(eb); | ||
2080 | free_extent_buffer(eb); | ||
2081 | } | 2078 | } |
2082 | if (!lowest) { | 2079 | if (!lowest) { |
2083 | btrfs_tree_unlock(upper->eb); | 2080 | btrfs_tree_unlock(upper->eb); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 4e83457ea253..2dbf1c1f56ee 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -593,6 +593,7 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) | |||
593 | return 0; | 593 | return 0; |
594 | } | 594 | } |
595 | 595 | ||
596 | #if 0 | ||
596 | /* | 597 | /* |
597 | * when dropping snapshots, we generate a ton of delayed refs, and it makes | 598 | * when dropping snapshots, we generate a ton of delayed refs, and it makes |
598 | * sense not to join the transaction while it is trying to flush the current | 599 | * sense not to join the transaction while it is trying to flush the current |
@@ -681,6 +682,7 @@ int btrfs_drop_dead_root(struct btrfs_root *root) | |||
681 | btrfs_btree_balance_dirty(tree_root, nr); | 682 | btrfs_btree_balance_dirty(tree_root, nr); |
682 | return ret; | 683 | return ret; |
683 | } | 684 | } |
685 | #endif | ||
684 | 686 | ||
685 | /* | 687 | /* |
686 | * new snapshots need to be created at a very specific time in the | 688 | * new snapshots need to be created at a very specific time in the |
@@ -1081,7 +1083,7 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root) | |||
1081 | while (!list_empty(&list)) { | 1083 | while (!list_empty(&list)) { |
1082 | root = list_entry(list.next, struct btrfs_root, root_list); | 1084 | root = list_entry(list.next, struct btrfs_root, root_list); |
1083 | list_del_init(&root->root_list); | 1085 | list_del_init(&root->root_list); |
1084 | btrfs_drop_dead_root(root); | 1086 | btrfs_drop_snapshot(root, 0); |
1085 | } | 1087 | } |
1086 | return 0; | 1088 | return 0; |
1087 | } | 1089 | } |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index b48689839428..3a9b7a58a51d 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -5,7 +5,7 @@ client generated ones by default (mount option "serverino" turned | |||
5 | on by default if server supports it). Add forceuid and forcegid | 5 | on by default if server supports it). Add forceuid and forcegid |
6 | mount options (so that when negotiating unix extensions specifying | 6 | mount options (so that when negotiating unix extensions specifying |
7 | which uid mounted does not immediately force the server's reported | 7 | which uid mounted does not immediately force the server's reported |
8 | uids to be overridden). | 8 | uids to be overridden). Add support for scope moutn parm. |
9 | 9 | ||
10 | Version 1.58 | 10 | Version 1.58 |
11 | ------------ | 11 | ------------ |
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 1b09f1670061..20692fbfdb24 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #define ASN1_OJI 6 /* Object Identifier */ | 49 | #define ASN1_OJI 6 /* Object Identifier */ |
50 | #define ASN1_OJD 7 /* Object Description */ | 50 | #define ASN1_OJD 7 /* Object Description */ |
51 | #define ASN1_EXT 8 /* External */ | 51 | #define ASN1_EXT 8 /* External */ |
52 | #define ASN1_ENUM 10 /* Enumerated */ | ||
52 | #define ASN1_SEQ 16 /* Sequence */ | 53 | #define ASN1_SEQ 16 /* Sequence */ |
53 | #define ASN1_SET 17 /* Set */ | 54 | #define ASN1_SET 17 /* Set */ |
54 | #define ASN1_NUMSTR 18 /* Numerical String */ | 55 | #define ASN1_NUMSTR 18 /* Numerical String */ |
@@ -78,10 +79,12 @@ | |||
78 | #define SPNEGO_OID_LEN 7 | 79 | #define SPNEGO_OID_LEN 7 |
79 | #define NTLMSSP_OID_LEN 10 | 80 | #define NTLMSSP_OID_LEN 10 |
80 | #define KRB5_OID_LEN 7 | 81 | #define KRB5_OID_LEN 7 |
82 | #define KRB5U2U_OID_LEN 8 | ||
81 | #define MSKRB5_OID_LEN 7 | 83 | #define MSKRB5_OID_LEN 7 |
82 | static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; | 84 | static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; |
83 | static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; | 85 | static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; |
84 | static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 }; | 86 | static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 }; |
87 | static unsigned long KRB5U2U_OID[8] = { 1, 2, 840, 113554, 1, 2, 2, 3 }; | ||
85 | static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 }; | 88 | static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 }; |
86 | 89 | ||
87 | /* | 90 | /* |
@@ -122,6 +125,28 @@ asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch) | |||
122 | return 1; | 125 | return 1; |
123 | } | 126 | } |
124 | 127 | ||
128 | #if 0 /* will be needed later by spnego decoding/encoding of ntlmssp */ | ||
129 | static unsigned char | ||
130 | asn1_enum_decode(struct asn1_ctx *ctx, __le32 *val) | ||
131 | { | ||
132 | unsigned char ch; | ||
133 | |||
134 | if (ctx->pointer >= ctx->end) { | ||
135 | ctx->error = ASN1_ERR_DEC_EMPTY; | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | ch = *(ctx->pointer)++; /* ch has 0xa, ptr points to lenght octet */ | ||
140 | if ((ch) == ASN1_ENUM) /* if ch value is ENUM, 0xa */ | ||
141 | *val = *(++(ctx->pointer)); /* value has enum value */ | ||
142 | else | ||
143 | return 0; | ||
144 | |||
145 | ctx->pointer++; | ||
146 | return 1; | ||
147 | } | ||
148 | #endif | ||
149 | |||
125 | static unsigned char | 150 | static unsigned char |
126 | asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) | 151 | asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) |
127 | { | 152 | { |
@@ -476,10 +501,9 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
476 | unsigned int cls, con, tag, oidlen, rc; | 501 | unsigned int cls, con, tag, oidlen, rc; |
477 | bool use_ntlmssp = false; | 502 | bool use_ntlmssp = false; |
478 | bool use_kerberos = false; | 503 | bool use_kerberos = false; |
504 | bool use_kerberosu2u = false; | ||
479 | bool use_mskerberos = false; | 505 | bool use_mskerberos = false; |
480 | 506 | ||
481 | *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/ | ||
482 | |||
483 | /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */ | 507 | /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */ |
484 | 508 | ||
485 | asn1_open(&ctx, security_blob, length); | 509 | asn1_open(&ctx, security_blob, length); |
@@ -515,6 +539,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
515 | return 0; | 539 | return 0; |
516 | } | 540 | } |
517 | 541 | ||
542 | /* SPNEGO */ | ||
518 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 543 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
519 | cFYI(1, ("Error decoding negTokenInit")); | 544 | cFYI(1, ("Error decoding negTokenInit")); |
520 | return 0; | 545 | return 0; |
@@ -526,6 +551,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
526 | return 0; | 551 | return 0; |
527 | } | 552 | } |
528 | 553 | ||
554 | /* negTokenInit */ | ||
529 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 555 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
530 | cFYI(1, ("Error decoding negTokenInit")); | 556 | cFYI(1, ("Error decoding negTokenInit")); |
531 | return 0; | 557 | return 0; |
@@ -537,6 +563,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
537 | return 0; | 563 | return 0; |
538 | } | 564 | } |
539 | 565 | ||
566 | /* sequence */ | ||
540 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 567 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
541 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); | 568 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); |
542 | return 0; | 569 | return 0; |
@@ -548,6 +575,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
548 | return 0; | 575 | return 0; |
549 | } | 576 | } |
550 | 577 | ||
578 | /* sequence of */ | ||
551 | if (asn1_header_decode | 579 | if (asn1_header_decode |
552 | (&ctx, &sequence_end, &cls, &con, &tag) == 0) { | 580 | (&ctx, &sequence_end, &cls, &con, &tag) == 0) { |
553 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); | 581 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); |
@@ -560,6 +588,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
560 | return 0; | 588 | return 0; |
561 | } | 589 | } |
562 | 590 | ||
591 | /* list of security mechanisms */ | ||
563 | while (!asn1_eoc_decode(&ctx, sequence_end)) { | 592 | while (!asn1_eoc_decode(&ctx, sequence_end)) { |
564 | rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); | 593 | rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); |
565 | if (!rc) { | 594 | if (!rc) { |
@@ -576,11 +605,15 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
576 | 605 | ||
577 | if (compare_oid(oid, oidlen, MSKRB5_OID, | 606 | if (compare_oid(oid, oidlen, MSKRB5_OID, |
578 | MSKRB5_OID_LEN) && | 607 | MSKRB5_OID_LEN) && |
579 | !use_kerberos) | 608 | !use_mskerberos) |
580 | use_mskerberos = true; | 609 | use_mskerberos = true; |
610 | else if (compare_oid(oid, oidlen, KRB5U2U_OID, | ||
611 | KRB5U2U_OID_LEN) && | ||
612 | !use_kerberosu2u) | ||
613 | use_kerberosu2u = true; | ||
581 | else if (compare_oid(oid, oidlen, KRB5_OID, | 614 | else if (compare_oid(oid, oidlen, KRB5_OID, |
582 | KRB5_OID_LEN) && | 615 | KRB5_OID_LEN) && |
583 | !use_mskerberos) | 616 | !use_kerberos) |
584 | use_kerberos = true; | 617 | use_kerberos = true; |
585 | else if (compare_oid(oid, oidlen, NTLMSSP_OID, | 618 | else if (compare_oid(oid, oidlen, NTLMSSP_OID, |
586 | NTLMSSP_OID_LEN)) | 619 | NTLMSSP_OID_LEN)) |
@@ -593,7 +626,12 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
593 | } | 626 | } |
594 | } | 627 | } |
595 | 628 | ||
629 | /* mechlistMIC */ | ||
596 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 630 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
631 | /* Check if we have reached the end of the blob, but with | ||
632 | no mechListMic (e.g. NTLMSSP instead of KRB5) */ | ||
633 | if (ctx.error == ASN1_ERR_DEC_EMPTY) | ||
634 | goto decode_negtoken_exit; | ||
597 | cFYI(1, ("Error decoding last part negTokenInit exit3")); | 635 | cFYI(1, ("Error decoding last part negTokenInit exit3")); |
598 | return 0; | 636 | return 0; |
599 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { | 637 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { |
@@ -602,6 +640,8 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
602 | cls, con, tag, end, *end)); | 640 | cls, con, tag, end, *end)); |
603 | return 0; | 641 | return 0; |
604 | } | 642 | } |
643 | |||
644 | /* sequence */ | ||
605 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 645 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
606 | cFYI(1, ("Error decoding last part negTokenInit exit5")); | 646 | cFYI(1, ("Error decoding last part negTokenInit exit5")); |
607 | return 0; | 647 | return 0; |
@@ -611,6 +651,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
611 | cls, con, tag, end, *end)); | 651 | cls, con, tag, end, *end)); |
612 | } | 652 | } |
613 | 653 | ||
654 | /* sequence of */ | ||
614 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 655 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
615 | cFYI(1, ("Error decoding last part negTokenInit exit 7")); | 656 | cFYI(1, ("Error decoding last part negTokenInit exit 7")); |
616 | return 0; | 657 | return 0; |
@@ -619,6 +660,8 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
619 | cls, con, tag, end, *end)); | 660 | cls, con, tag, end, *end)); |
620 | return 0; | 661 | return 0; |
621 | } | 662 | } |
663 | |||
664 | /* general string */ | ||
622 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 665 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
623 | cFYI(1, ("Error decoding last part negTokenInit exit9")); | 666 | cFYI(1, ("Error decoding last part negTokenInit exit9")); |
624 | return 0; | 667 | return 0; |
@@ -630,13 +673,13 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
630 | } | 673 | } |
631 | cFYI(1, ("Need to call asn1_octets_decode() function for %s", | 674 | cFYI(1, ("Need to call asn1_octets_decode() function for %s", |
632 | ctx.pointer)); /* is this UTF-8 or ASCII? */ | 675 | ctx.pointer)); /* is this UTF-8 or ASCII? */ |
633 | 676 | decode_negtoken_exit: | |
634 | if (use_kerberos) | 677 | if (use_kerberos) |
635 | *secType = Kerberos; | 678 | *secType = Kerberos; |
636 | else if (use_mskerberos) | 679 | else if (use_mskerberos) |
637 | *secType = MSKerberos; | 680 | *secType = MSKerberos; |
638 | else if (use_ntlmssp) | 681 | else if (use_ntlmssp) |
639 | *secType = NTLMSSP; | 682 | *secType = RawNTLMSSP; |
640 | 683 | ||
641 | return 1; | 684 | return 1; |
642 | } | 685 | } |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0d92114195ab..9f669f982c4d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -333,6 +333,27 @@ cifs_destroy_inode(struct inode *inode) | |||
333 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); | 333 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); |
334 | } | 334 | } |
335 | 335 | ||
336 | static void | ||
337 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) | ||
338 | { | ||
339 | seq_printf(s, ",addr="); | ||
340 | |||
341 | switch (server->addr.sockAddr.sin_family) { | ||
342 | case AF_INET: | ||
343 | seq_printf(s, "%pI4", &server->addr.sockAddr.sin_addr.s_addr); | ||
344 | break; | ||
345 | case AF_INET6: | ||
346 | seq_printf(s, "%pI6", | ||
347 | &server->addr.sockAddr6.sin6_addr.s6_addr); | ||
348 | if (server->addr.sockAddr6.sin6_scope_id) | ||
349 | seq_printf(s, "%%%u", | ||
350 | server->addr.sockAddr6.sin6_scope_id); | ||
351 | break; | ||
352 | default: | ||
353 | seq_printf(s, "(unknown)"); | ||
354 | } | ||
355 | } | ||
356 | |||
336 | /* | 357 | /* |
337 | * cifs_show_options() is for displaying mount options in /proc/mounts. | 358 | * cifs_show_options() is for displaying mount options in /proc/mounts. |
338 | * Not all settable options are displayed but most of the important | 359 | * Not all settable options are displayed but most of the important |
@@ -343,83 +364,64 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) | |||
343 | { | 364 | { |
344 | struct cifs_sb_info *cifs_sb; | 365 | struct cifs_sb_info *cifs_sb; |
345 | struct cifsTconInfo *tcon; | 366 | struct cifsTconInfo *tcon; |
346 | struct TCP_Server_Info *server; | ||
347 | 367 | ||
348 | cifs_sb = CIFS_SB(m->mnt_sb); | 368 | cifs_sb = CIFS_SB(m->mnt_sb); |
369 | tcon = cifs_sb->tcon; | ||
349 | 370 | ||
350 | if (cifs_sb) { | 371 | seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); |
351 | tcon = cifs_sb->tcon; | 372 | if (tcon->ses->userName) |
352 | if (tcon) { | 373 | seq_printf(s, ",username=%s", tcon->ses->userName); |
353 | seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); | 374 | if (tcon->ses->domainName) |
354 | if (tcon->ses) { | 375 | seq_printf(s, ",domain=%s", tcon->ses->domainName); |
355 | if (tcon->ses->userName) | 376 | |
356 | seq_printf(s, ",username=%s", | 377 | seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); |
357 | tcon->ses->userName); | 378 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) |
358 | if (tcon->ses->domainName) | 379 | seq_printf(s, ",forceuid"); |
359 | seq_printf(s, ",domain=%s", | 380 | |
360 | tcon->ses->domainName); | 381 | seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); |
361 | server = tcon->ses->server; | 382 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) |
362 | if (server) { | 383 | seq_printf(s, ",forcegid"); |
363 | seq_printf(s, ",addr="); | 384 | |
364 | switch (server->addr.sockAddr6. | 385 | cifs_show_address(s, tcon->ses->server); |
365 | sin6_family) { | 386 | |
366 | case AF_INET6: | 387 | if (!tcon->unix_ext) |
367 | seq_printf(s, "%pI6", | 388 | seq_printf(s, ",file_mode=0%o,dir_mode=0%o", |
368 | &server->addr.sockAddr6.sin6_addr); | ||
369 | break; | ||
370 | case AF_INET: | ||
371 | seq_printf(s, "%pI4", | ||
372 | &server->addr.sockAddr.sin_addr.s_addr); | ||
373 | break; | ||
374 | } | ||
375 | } | ||
376 | } | ||
377 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) || | ||
378 | !(tcon->unix_ext)) | ||
379 | seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); | ||
380 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || | ||
381 | !(tcon->unix_ext)) | ||
382 | seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); | ||
383 | if (!tcon->unix_ext) { | ||
384 | seq_printf(s, ",file_mode=0%o,dir_mode=0%o", | ||
385 | cifs_sb->mnt_file_mode, | 389 | cifs_sb->mnt_file_mode, |
386 | cifs_sb->mnt_dir_mode); | 390 | cifs_sb->mnt_dir_mode); |
387 | } | 391 | if (tcon->seal) |
388 | if (tcon->seal) | 392 | seq_printf(s, ",seal"); |
389 | seq_printf(s, ",seal"); | 393 | if (tcon->nocase) |
390 | if (tcon->nocase) | 394 | seq_printf(s, ",nocase"); |
391 | seq_printf(s, ",nocase"); | 395 | if (tcon->retry) |
392 | if (tcon->retry) | 396 | seq_printf(s, ",hard"); |
393 | seq_printf(s, ",hard"); | 397 | if (cifs_sb->prepath) |
394 | } | 398 | seq_printf(s, ",prepath=%s", cifs_sb->prepath); |
395 | if (cifs_sb->prepath) | 399 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) |
396 | seq_printf(s, ",prepath=%s", cifs_sb->prepath); | 400 | seq_printf(s, ",posixpaths"); |
397 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) | 401 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) |
398 | seq_printf(s, ",posixpaths"); | 402 | seq_printf(s, ",setuids"); |
399 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) | 403 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) |
400 | seq_printf(s, ",setuids"); | 404 | seq_printf(s, ",serverino"); |
401 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) | 405 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) |
402 | seq_printf(s, ",serverino"); | 406 | seq_printf(s, ",directio"); |
403 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | 407 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) |
404 | seq_printf(s, ",directio"); | 408 | seq_printf(s, ",nouser_xattr"); |
405 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | 409 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) |
406 | seq_printf(s, ",nouser_xattr"); | 410 | seq_printf(s, ",mapchars"); |
407 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) | 411 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) |
408 | seq_printf(s, ",mapchars"); | 412 | seq_printf(s, ",sfu"); |
409 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) | 413 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) |
410 | seq_printf(s, ",sfu"); | 414 | seq_printf(s, ",nobrl"); |
411 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 415 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) |
412 | seq_printf(s, ",nobrl"); | 416 | seq_printf(s, ",cifsacl"); |
413 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) | 417 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) |
414 | seq_printf(s, ",cifsacl"); | 418 | seq_printf(s, ",dynperm"); |
415 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) | 419 | if (m->mnt_sb->s_flags & MS_POSIXACL) |
416 | seq_printf(s, ",dynperm"); | 420 | seq_printf(s, ",acl"); |
417 | if (m->mnt_sb->s_flags & MS_POSIXACL) | 421 | |
418 | seq_printf(s, ",acl"); | 422 | seq_printf(s, ",rsize=%d", cifs_sb->rsize); |
419 | 423 | seq_printf(s, ",wsize=%d", cifs_sb->wsize); | |
420 | seq_printf(s, ",rsize=%d", cifs_sb->rsize); | 424 | |
421 | seq_printf(s, ",wsize=%d", cifs_sb->wsize); | ||
422 | } | ||
423 | return 0; | 425 | return 0; |
424 | } | 426 | } |
425 | 427 | ||
@@ -535,9 +537,14 @@ static void cifs_umount_begin(struct super_block *sb) | |||
535 | if (tcon == NULL) | 537 | if (tcon == NULL) |
536 | return; | 538 | return; |
537 | 539 | ||
538 | lock_kernel(); | ||
539 | read_lock(&cifs_tcp_ses_lock); | 540 | read_lock(&cifs_tcp_ses_lock); |
540 | if (tcon->tc_count == 1) | 541 | if ((tcon->tc_count > 1) || (tcon->tidStatus == CifsExiting)) { |
542 | /* we have other mounts to same share or we have | ||
543 | already tried to force umount this and woken up | ||
544 | all waiting network requests, nothing to do */ | ||
545 | read_unlock(&cifs_tcp_ses_lock); | ||
546 | return; | ||
547 | } else if (tcon->tc_count == 1) | ||
541 | tcon->tidStatus = CifsExiting; | 548 | tcon->tidStatus = CifsExiting; |
542 | read_unlock(&cifs_tcp_ses_lock); | 549 | read_unlock(&cifs_tcp_ses_lock); |
543 | 550 | ||
@@ -552,9 +559,7 @@ static void cifs_umount_begin(struct super_block *sb) | |||
552 | wake_up_all(&tcon->ses->server->response_q); | 559 | wake_up_all(&tcon->ses->server->response_q); |
553 | msleep(1); | 560 | msleep(1); |
554 | } | 561 | } |
555 | /* BB FIXME - finish add checks for tidStatus BB */ | ||
556 | 562 | ||
557 | unlock_kernel(); | ||
558 | return; | 563 | return; |
559 | } | 564 | } |
560 | 565 | ||
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a61ab772c6f6..e1225e6ded2f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -83,7 +83,7 @@ enum securityEnum { | |||
83 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ | 83 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ |
84 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ | 84 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ |
85 | RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ | 85 | RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ |
86 | NTLMSSP, /* NTLMSSP via SPNEGO, NTLMv2 hash */ | 86 | /* NTLMSSP, */ /* can use rawNTLMSSP instead of NTLMSSP via SPNEGO */ |
87 | Kerberos, /* Kerberos via SPNEGO */ | 87 | Kerberos, /* Kerberos via SPNEGO */ |
88 | MSKerberos, /* MS Kerberos via SPNEGO */ | 88 | MSKerberos, /* MS Kerberos via SPNEGO */ |
89 | }; | 89 | }; |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index f9452329bcce..c419416a42ee 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -74,7 +74,7 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr); | |||
74 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); | 74 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); |
75 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 75 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
76 | enum securityEnum *secType); | 76 | enum securityEnum *secType); |
77 | extern int cifs_inet_pton(const int, const char *source, void *dst); | 77 | extern int cifs_convert_address(char *src, void *dst); |
78 | extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); | 78 | extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); |
79 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 79 | extern void header_assemble(struct smb_hdr *, char /* command */ , |
80 | const struct cifsTconInfo *, int /* length of | 80 | const struct cifsTconInfo *, int /* length of |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b84c61d5bca4..61007c627497 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -594,7 +594,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
594 | else if (secFlags & CIFSSEC_MAY_KRB5) | 594 | else if (secFlags & CIFSSEC_MAY_KRB5) |
595 | server->secType = Kerberos; | 595 | server->secType = Kerberos; |
596 | else if (secFlags & CIFSSEC_MAY_NTLMSSP) | 596 | else if (secFlags & CIFSSEC_MAY_NTLMSSP) |
597 | server->secType = NTLMSSP; | 597 | server->secType = RawNTLMSSP; |
598 | else if (secFlags & CIFSSEC_MAY_LANMAN) | 598 | else if (secFlags & CIFSSEC_MAY_LANMAN) |
599 | server->secType = LANMAN; | 599 | server->secType = LANMAN; |
600 | /* #ifdef CONFIG_CIFS_EXPERIMENTAL | 600 | /* #ifdef CONFIG_CIFS_EXPERIMENTAL |
@@ -729,7 +729,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | |||
729 | * the tcon is no longer on the list, so no need to take lock before | 729 | * the tcon is no longer on the list, so no need to take lock before |
730 | * checking this. | 730 | * checking this. |
731 | */ | 731 | */ |
732 | if (tcon->need_reconnect) | 732 | if ((tcon->need_reconnect) || (tcon->ses->need_reconnect)) |
733 | return 0; | 733 | return 0; |
734 | 734 | ||
735 | rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, | 735 | rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 97f4311b9a8e..e16d7592116a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -70,7 +70,6 @@ struct smb_vol { | |||
70 | mode_t file_mode; | 70 | mode_t file_mode; |
71 | mode_t dir_mode; | 71 | mode_t dir_mode; |
72 | unsigned secFlg; | 72 | unsigned secFlg; |
73 | bool rw:1; | ||
74 | bool retry:1; | 73 | bool retry:1; |
75 | bool intr:1; | 74 | bool intr:1; |
76 | bool setuids:1; | 75 | bool setuids:1; |
@@ -832,7 +831,6 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
832 | vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR; | 831 | vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR; |
833 | 832 | ||
834 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ | 833 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ |
835 | vol->rw = true; | ||
836 | /* default is always to request posix paths. */ | 834 | /* default is always to request posix paths. */ |
837 | vol->posix_paths = 1; | 835 | vol->posix_paths = 1; |
838 | /* default to using server inode numbers where available */ | 836 | /* default to using server inode numbers where available */ |
@@ -1199,7 +1197,9 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1199 | } else if (strnicmp(data, "guest", 5) == 0) { | 1197 | } else if (strnicmp(data, "guest", 5) == 0) { |
1200 | /* ignore */ | 1198 | /* ignore */ |
1201 | } else if (strnicmp(data, "rw", 2) == 0) { | 1199 | } else if (strnicmp(data, "rw", 2) == 0) { |
1202 | vol->rw = true; | 1200 | /* ignore */ |
1201 | } else if (strnicmp(data, "ro", 2) == 0) { | ||
1202 | /* ignore */ | ||
1203 | } else if (strnicmp(data, "noblocksend", 11) == 0) { | 1203 | } else if (strnicmp(data, "noblocksend", 11) == 0) { |
1204 | vol->noblocksnd = 1; | 1204 | vol->noblocksnd = 1; |
1205 | } else if (strnicmp(data, "noautotune", 10) == 0) { | 1205 | } else if (strnicmp(data, "noautotune", 10) == 0) { |
@@ -1218,8 +1218,6 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1218 | parse these options again and set anything and it | 1218 | parse these options again and set anything and it |
1219 | is ok to just ignore them */ | 1219 | is ok to just ignore them */ |
1220 | continue; | 1220 | continue; |
1221 | } else if (strnicmp(data, "ro", 2) == 0) { | ||
1222 | vol->rw = false; | ||
1223 | } else if (strnicmp(data, "hard", 4) == 0) { | 1221 | } else if (strnicmp(data, "hard", 4) == 0) { |
1224 | vol->retry = 1; | 1222 | vol->retry = 1; |
1225 | } else if (strnicmp(data, "soft", 4) == 0) { | 1223 | } else if (strnicmp(data, "soft", 4) == 0) { |
@@ -1386,8 +1384,10 @@ cifs_find_tcp_session(struct sockaddr_storage *addr) | |||
1386 | server->addr.sockAddr.sin_addr.s_addr)) | 1384 | server->addr.sockAddr.sin_addr.s_addr)) |
1387 | continue; | 1385 | continue; |
1388 | else if (addr->ss_family == AF_INET6 && | 1386 | else if (addr->ss_family == AF_INET6 && |
1389 | !ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr, | 1387 | (!ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr, |
1390 | &addr6->sin6_addr)) | 1388 | &addr6->sin6_addr) || |
1389 | server->addr.sockAddr6.sin6_scope_id != | ||
1390 | addr6->sin6_scope_id)) | ||
1391 | continue; | 1391 | continue; |
1392 | 1392 | ||
1393 | ++server->srv_count; | 1393 | ++server->srv_count; |
@@ -1433,28 +1433,15 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1433 | 1433 | ||
1434 | memset(&addr, 0, sizeof(struct sockaddr_storage)); | 1434 | memset(&addr, 0, sizeof(struct sockaddr_storage)); |
1435 | 1435 | ||
1436 | if (volume_info->UNCip && volume_info->UNC) { | 1436 | cFYI(1, ("UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip)); |
1437 | rc = cifs_inet_pton(AF_INET, volume_info->UNCip, | ||
1438 | &sin_server->sin_addr.s_addr); | ||
1439 | |||
1440 | if (rc <= 0) { | ||
1441 | /* not ipv4 address, try ipv6 */ | ||
1442 | rc = cifs_inet_pton(AF_INET6, volume_info->UNCip, | ||
1443 | &sin_server6->sin6_addr.in6_u); | ||
1444 | if (rc > 0) | ||
1445 | addr.ss_family = AF_INET6; | ||
1446 | } else { | ||
1447 | addr.ss_family = AF_INET; | ||
1448 | } | ||
1449 | 1437 | ||
1450 | if (rc <= 0) { | 1438 | if (volume_info->UNCip && volume_info->UNC) { |
1439 | rc = cifs_convert_address(volume_info->UNCip, &addr); | ||
1440 | if (!rc) { | ||
1451 | /* we failed translating address */ | 1441 | /* we failed translating address */ |
1452 | rc = -EINVAL; | 1442 | rc = -EINVAL; |
1453 | goto out_err; | 1443 | goto out_err; |
1454 | } | 1444 | } |
1455 | |||
1456 | cFYI(1, ("UNC: %s ip: %s", volume_info->UNC, | ||
1457 | volume_info->UNCip)); | ||
1458 | } else if (volume_info->UNCip) { | 1445 | } else if (volume_info->UNCip) { |
1459 | /* BB using ip addr as tcp_ses name to connect to the | 1446 | /* BB using ip addr as tcp_ses name to connect to the |
1460 | DFS root below */ | 1447 | DFS root below */ |
@@ -1513,14 +1500,14 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1513 | cFYI(1, ("attempting ipv6 connect")); | 1500 | cFYI(1, ("attempting ipv6 connect")); |
1514 | /* BB should we allow ipv6 on port 139? */ | 1501 | /* BB should we allow ipv6 on port 139? */ |
1515 | /* other OS never observed in Wild doing 139 with v6 */ | 1502 | /* other OS never observed in Wild doing 139 with v6 */ |
1503 | sin_server6->sin6_port = htons(volume_info->port); | ||
1516 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, | 1504 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, |
1517 | sizeof(struct sockaddr_in6)); | 1505 | sizeof(struct sockaddr_in6)); |
1518 | sin_server6->sin6_port = htons(volume_info->port); | ||
1519 | rc = ipv6_connect(tcp_ses); | 1506 | rc = ipv6_connect(tcp_ses); |
1520 | } else { | 1507 | } else { |
1508 | sin_server->sin_port = htons(volume_info->port); | ||
1521 | memcpy(&tcp_ses->addr.sockAddr, sin_server, | 1509 | memcpy(&tcp_ses->addr.sockAddr, sin_server, |
1522 | sizeof(struct sockaddr_in)); | 1510 | sizeof(struct sockaddr_in)); |
1523 | sin_server->sin_port = htons(volume_info->port); | ||
1524 | rc = ipv4_connect(tcp_ses); | 1511 | rc = ipv4_connect(tcp_ses); |
1525 | } | 1512 | } |
1526 | if (rc < 0) { | 1513 | if (rc < 0) { |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 3758965d73d5..7dc6b74f9def 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -307,8 +307,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
307 | 307 | ||
308 | full_path = build_path_from_dentry(direntry); | 308 | full_path = build_path_from_dentry(direntry); |
309 | if (full_path == NULL) { | 309 | if (full_path == NULL) { |
310 | rc = -ENOMEM; | ||
310 | FreeXid(xid); | 311 | FreeXid(xid); |
311 | return -ENOMEM; | 312 | return rc; |
312 | } | 313 | } |
313 | 314 | ||
314 | if (oplockEnabled) | 315 | if (oplockEnabled) |
@@ -540,8 +541,9 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
540 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | 541 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
541 | if (buf == NULL) { | 542 | if (buf == NULL) { |
542 | kfree(full_path); | 543 | kfree(full_path); |
544 | rc = -ENOMEM; | ||
543 | FreeXid(xid); | 545 | FreeXid(xid); |
544 | return -ENOMEM; | 546 | return rc; |
545 | } | 547 | } |
546 | 548 | ||
547 | rc = CIFSSMBOpen(xid, pTcon, full_path, | 549 | rc = CIFSSMBOpen(xid, pTcon, full_path, |
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index df4a306f697e..87948147d7ec 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c | |||
@@ -35,26 +35,11 @@ | |||
35 | * 0 - name is not IP | 35 | * 0 - name is not IP |
36 | */ | 36 | */ |
37 | static int | 37 | static int |
38 | is_ip(const char *name) | 38 | is_ip(char *name) |
39 | { | 39 | { |
40 | int rc; | 40 | struct sockaddr_storage ss; |
41 | struct sockaddr_in sin_server; | 41 | |
42 | struct sockaddr_in6 sin_server6; | 42 | return cifs_convert_address(name, &ss); |
43 | |||
44 | rc = cifs_inet_pton(AF_INET, name, | ||
45 | &sin_server.sin_addr.s_addr); | ||
46 | |||
47 | if (rc <= 0) { | ||
48 | /* not ipv4 address, try ipv6 */ | ||
49 | rc = cifs_inet_pton(AF_INET6, name, | ||
50 | &sin_server6.sin6_addr.in6_u); | ||
51 | if (rc > 0) | ||
52 | return 1; | ||
53 | } else { | ||
54 | return 1; | ||
55 | } | ||
56 | /* we failed translating address */ | ||
57 | return 0; | ||
58 | } | 43 | } |
59 | 44 | ||
60 | static int | 45 | static int |
@@ -72,7 +57,7 @@ dns_resolver_instantiate(struct key *key, const void *data, | |||
72 | ip[datalen] = '\0'; | 57 | ip[datalen] = '\0'; |
73 | 58 | ||
74 | /* make sure this looks like an address */ | 59 | /* make sure this looks like an address */ |
75 | if (!is_ip((const char *) ip)) { | 60 | if (!is_ip(ip)) { |
76 | kfree(ip); | 61 | kfree(ip); |
77 | return -EINVAL; | 62 | return -EINVAL; |
78 | } | 63 | } |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 06866841b97f..97ce4bf89d15 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -300,14 +300,16 @@ int cifs_open(struct inode *inode, struct file *file) | |||
300 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | 300 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); |
301 | pCifsFile = cifs_fill_filedata(file); | 301 | pCifsFile = cifs_fill_filedata(file); |
302 | if (pCifsFile) { | 302 | if (pCifsFile) { |
303 | rc = 0; | ||
303 | FreeXid(xid); | 304 | FreeXid(xid); |
304 | return 0; | 305 | return rc; |
305 | } | 306 | } |
306 | 307 | ||
307 | full_path = build_path_from_dentry(file->f_path.dentry); | 308 | full_path = build_path_from_dentry(file->f_path.dentry); |
308 | if (full_path == NULL) { | 309 | if (full_path == NULL) { |
310 | rc = -ENOMEM; | ||
309 | FreeXid(xid); | 311 | FreeXid(xid); |
310 | return -ENOMEM; | 312 | return rc; |
311 | } | 313 | } |
312 | 314 | ||
313 | cFYI(1, ("inode = 0x%p file flags are 0x%x for %s", | 315 | cFYI(1, ("inode = 0x%p file flags are 0x%x for %s", |
@@ -491,11 +493,12 @@ static int cifs_reopen_file(struct file *file, bool can_flush) | |||
491 | return -EBADF; | 493 | return -EBADF; |
492 | 494 | ||
493 | xid = GetXid(); | 495 | xid = GetXid(); |
494 | mutex_unlock(&pCifsFile->fh_mutex); | 496 | mutex_lock(&pCifsFile->fh_mutex); |
495 | if (!pCifsFile->invalidHandle) { | 497 | if (!pCifsFile->invalidHandle) { |
496 | mutex_lock(&pCifsFile->fh_mutex); | 498 | mutex_unlock(&pCifsFile->fh_mutex); |
499 | rc = 0; | ||
497 | FreeXid(xid); | 500 | FreeXid(xid); |
498 | return 0; | 501 | return rc; |
499 | } | 502 | } |
500 | 503 | ||
501 | if (file->f_path.dentry == NULL) { | 504 | if (file->f_path.dentry == NULL) { |
@@ -524,7 +527,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush) | |||
524 | if (full_path == NULL) { | 527 | if (full_path == NULL) { |
525 | rc = -ENOMEM; | 528 | rc = -ENOMEM; |
526 | reopen_error_exit: | 529 | reopen_error_exit: |
527 | mutex_lock(&pCifsFile->fh_mutex); | 530 | mutex_unlock(&pCifsFile->fh_mutex); |
528 | FreeXid(xid); | 531 | FreeXid(xid); |
529 | return rc; | 532 | return rc; |
530 | } | 533 | } |
@@ -566,14 +569,14 @@ reopen_error_exit: | |||
566 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 569 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
567 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 570 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
568 | if (rc) { | 571 | if (rc) { |
569 | mutex_lock(&pCifsFile->fh_mutex); | 572 | mutex_unlock(&pCifsFile->fh_mutex); |
570 | cFYI(1, ("cifs_open returned 0x%x", rc)); | 573 | cFYI(1, ("cifs_open returned 0x%x", rc)); |
571 | cFYI(1, ("oplock: %d", oplock)); | 574 | cFYI(1, ("oplock: %d", oplock)); |
572 | } else { | 575 | } else { |
573 | reopen_success: | 576 | reopen_success: |
574 | pCifsFile->netfid = netfid; | 577 | pCifsFile->netfid = netfid; |
575 | pCifsFile->invalidHandle = false; | 578 | pCifsFile->invalidHandle = false; |
576 | mutex_lock(&pCifsFile->fh_mutex); | 579 | mutex_unlock(&pCifsFile->fh_mutex); |
577 | pCifsInode = CIFS_I(inode); | 580 | pCifsInode = CIFS_I(inode); |
578 | if (pCifsInode) { | 581 | if (pCifsInode) { |
579 | if (can_flush) { | 582 | if (can_flush) { |
@@ -845,8 +848,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
845 | tcon = cifs_sb->tcon; | 848 | tcon = cifs_sb->tcon; |
846 | 849 | ||
847 | if (file->private_data == NULL) { | 850 | if (file->private_data == NULL) { |
851 | rc = -EBADF; | ||
848 | FreeXid(xid); | 852 | FreeXid(xid); |
849 | return -EBADF; | 853 | return rc; |
850 | } | 854 | } |
851 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; | 855 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; |
852 | 856 | ||
@@ -1805,8 +1809,9 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1805 | pTcon = cifs_sb->tcon; | 1809 | pTcon = cifs_sb->tcon; |
1806 | 1810 | ||
1807 | if (file->private_data == NULL) { | 1811 | if (file->private_data == NULL) { |
1812 | rc = -EBADF; | ||
1808 | FreeXid(xid); | 1813 | FreeXid(xid); |
1809 | return -EBADF; | 1814 | return rc; |
1810 | } | 1815 | } |
1811 | open_file = (struct cifsFileInfo *)file->private_data; | 1816 | open_file = (struct cifsFileInfo *)file->private_data; |
1812 | 1817 | ||
@@ -1885,8 +1890,9 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1885 | pTcon = cifs_sb->tcon; | 1890 | pTcon = cifs_sb->tcon; |
1886 | 1891 | ||
1887 | if (file->private_data == NULL) { | 1892 | if (file->private_data == NULL) { |
1893 | rc = -EBADF; | ||
1888 | FreeXid(xid); | 1894 | FreeXid(xid); |
1889 | return -EBADF; | 1895 | return rc; |
1890 | } | 1896 | } |
1891 | open_file = (struct cifsFileInfo *)file->private_data; | 1897 | open_file = (struct cifsFileInfo *)file->private_data; |
1892 | 1898 | ||
@@ -2019,8 +2025,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2019 | 2025 | ||
2020 | xid = GetXid(); | 2026 | xid = GetXid(); |
2021 | if (file->private_data == NULL) { | 2027 | if (file->private_data == NULL) { |
2028 | rc = -EBADF; | ||
2022 | FreeXid(xid); | 2029 | FreeXid(xid); |
2023 | return -EBADF; | 2030 | return rc; |
2024 | } | 2031 | } |
2025 | open_file = (struct cifsFileInfo *)file->private_data; | 2032 | open_file = (struct cifsFileInfo *)file->private_data; |
2026 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 2033 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
@@ -2185,8 +2192,9 @@ static int cifs_readpage(struct file *file, struct page *page) | |||
2185 | xid = GetXid(); | 2192 | xid = GetXid(); |
2186 | 2193 | ||
2187 | if (file->private_data == NULL) { | 2194 | if (file->private_data == NULL) { |
2195 | rc = -EBADF; | ||
2188 | FreeXid(xid); | 2196 | FreeXid(xid); |
2189 | return -EBADF; | 2197 | return rc; |
2190 | } | 2198 | } |
2191 | 2199 | ||
2192 | cFYI(1, ("readpage %p at offset %d 0x%x\n", | 2200 | cFYI(1, ("readpage %p at offset %d 0x%x\n", |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index fad882b075ba..155c9e785d0c 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -988,8 +988,9 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) | |||
988 | * sb->s_vfs_rename_mutex here */ | 988 | * sb->s_vfs_rename_mutex here */ |
989 | full_path = build_path_from_dentry(dentry); | 989 | full_path = build_path_from_dentry(dentry); |
990 | if (full_path == NULL) { | 990 | if (full_path == NULL) { |
991 | rc = -ENOMEM; | ||
991 | FreeXid(xid); | 992 | FreeXid(xid); |
992 | return -ENOMEM; | 993 | return rc; |
993 | } | 994 | } |
994 | 995 | ||
995 | if ((tcon->ses->capabilities & CAP_UNIX) && | 996 | if ((tcon->ses->capabilities & CAP_UNIX) && |
@@ -1118,8 +1119,9 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
1118 | 1119 | ||
1119 | full_path = build_path_from_dentry(direntry); | 1120 | full_path = build_path_from_dentry(direntry); |
1120 | if (full_path == NULL) { | 1121 | if (full_path == NULL) { |
1122 | rc = -ENOMEM; | ||
1121 | FreeXid(xid); | 1123 | FreeXid(xid); |
1122 | return -ENOMEM; | 1124 | return rc; |
1123 | } | 1125 | } |
1124 | 1126 | ||
1125 | if ((pTcon->ses->capabilities & CAP_UNIX) && | 1127 | if ((pTcon->ses->capabilities & CAP_UNIX) && |
@@ -1303,8 +1305,9 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) | |||
1303 | 1305 | ||
1304 | full_path = build_path_from_dentry(direntry); | 1306 | full_path = build_path_from_dentry(direntry); |
1305 | if (full_path == NULL) { | 1307 | if (full_path == NULL) { |
1308 | rc = -ENOMEM; | ||
1306 | FreeXid(xid); | 1309 | FreeXid(xid); |
1307 | return -ENOMEM; | 1310 | return rc; |
1308 | } | 1311 | } |
1309 | 1312 | ||
1310 | rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, | 1313 | rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, |
@@ -1508,8 +1511,9 @@ int cifs_revalidate(struct dentry *direntry) | |||
1508 | since that would deadlock */ | 1511 | since that would deadlock */ |
1509 | full_path = build_path_from_dentry(direntry); | 1512 | full_path = build_path_from_dentry(direntry); |
1510 | if (full_path == NULL) { | 1513 | if (full_path == NULL) { |
1514 | rc = -ENOMEM; | ||
1511 | FreeXid(xid); | 1515 | FreeXid(xid); |
1512 | return -ENOMEM; | 1516 | return rc; |
1513 | } | 1517 | } |
1514 | cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld " | 1518 | cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld " |
1515 | "jiffies %ld", full_path, direntry->d_inode, | 1519 | "jiffies %ld", full_path, direntry->d_inode, |
@@ -1911,8 +1915,9 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
1911 | 1915 | ||
1912 | full_path = build_path_from_dentry(direntry); | 1916 | full_path = build_path_from_dentry(direntry); |
1913 | if (full_path == NULL) { | 1917 | if (full_path == NULL) { |
1918 | rc = -ENOMEM; | ||
1914 | FreeXid(xid); | 1919 | FreeXid(xid); |
1915 | return -ENOMEM; | 1920 | return rc; |
1916 | } | 1921 | } |
1917 | 1922 | ||
1918 | /* | 1923 | /* |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index cd83c53fcbb5..fc1e0487eaee 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -172,8 +172,9 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
172 | full_path = build_path_from_dentry(direntry); | 172 | full_path = build_path_from_dentry(direntry); |
173 | 173 | ||
174 | if (full_path == NULL) { | 174 | if (full_path == NULL) { |
175 | rc = -ENOMEM; | ||
175 | FreeXid(xid); | 176 | FreeXid(xid); |
176 | return -ENOMEM; | 177 | return rc; |
177 | } | 178 | } |
178 | 179 | ||
179 | cFYI(1, ("Full path: %s", full_path)); | 180 | cFYI(1, ("Full path: %s", full_path)); |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 32d6baa0a54f..bd6d6895730d 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
@@ -133,10 +133,12 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = { | |||
133 | {0, 0} | 133 | {0, 0} |
134 | }; | 134 | }; |
135 | 135 | ||
136 | /* Convert string containing dotted ip address to binary form */ | 136 | /* |
137 | /* returns 0 if invalid address */ | 137 | * Convert a string containing text IPv4 or IPv6 address to binary form. |
138 | 138 | * | |
139 | int | 139 | * Returns 0 on failure. |
140 | */ | ||
141 | static int | ||
140 | cifs_inet_pton(const int address_family, const char *cp, void *dst) | 142 | cifs_inet_pton(const int address_family, const char *cp, void *dst) |
141 | { | 143 | { |
142 | int ret = 0; | 144 | int ret = 0; |
@@ -153,6 +155,52 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst) | |||
153 | return ret; | 155 | return ret; |
154 | } | 156 | } |
155 | 157 | ||
158 | /* | ||
159 | * Try to convert a string to an IPv4 address and then attempt to convert | ||
160 | * it to an IPv6 address if that fails. Set the family field if either | ||
161 | * succeeds. If it's an IPv6 address and it has a '%' sign in it, try to | ||
162 | * treat the part following it as a numeric sin6_scope_id. | ||
163 | * | ||
164 | * Returns 0 on failure. | ||
165 | */ | ||
166 | int | ||
167 | cifs_convert_address(char *src, void *dst) | ||
168 | { | ||
169 | int rc; | ||
170 | char *pct, *endp; | ||
171 | struct sockaddr_in *s4 = (struct sockaddr_in *) dst; | ||
172 | struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst; | ||
173 | |||
174 | /* IPv4 address */ | ||
175 | if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) { | ||
176 | s4->sin_family = AF_INET; | ||
177 | return 1; | ||
178 | } | ||
179 | |||
180 | /* temporarily terminate string */ | ||
181 | pct = strchr(src, '%'); | ||
182 | if (pct) | ||
183 | *pct = '\0'; | ||
184 | |||
185 | rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr); | ||
186 | |||
187 | /* repair temp termination (if any) and make pct point to scopeid */ | ||
188 | if (pct) | ||
189 | *pct++ = '%'; | ||
190 | |||
191 | if (!rc) | ||
192 | return rc; | ||
193 | |||
194 | s6->sin6_family = AF_INET6; | ||
195 | if (pct) { | ||
196 | s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0); | ||
197 | if (!*pct || *endp) | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | return rc; | ||
202 | } | ||
203 | |||
156 | /***************************************************************************** | 204 | /***************************************************************************** |
157 | convert a NT status code to a dos class/code | 205 | convert a NT status code to a dos class/code |
158 | *****************************************************************************/ | 206 | *****************************************************************************/ |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 897a052270f9..7085a6275c4c 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -802,7 +802,7 @@ ssetup_ntlmssp_authenticate: | |||
802 | #endif /* CONFIG_CIFS_UPCALL */ | 802 | #endif /* CONFIG_CIFS_UPCALL */ |
803 | } else { | 803 | } else { |
804 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 804 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
805 | if ((experimEnabled > 1) && (type == RawNTLMSSP)) { | 805 | if (type == RawNTLMSSP) { |
806 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | 806 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { |
807 | cERROR(1, ("NTLMSSP requires Unicode support")); | 807 | cERROR(1, ("NTLMSSP requires Unicode support")); |
808 | rc = -ENOSYS; | 808 | rc = -ENOSYS; |
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index e9527eedc639..a75afa3dd9e1 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c | |||
@@ -64,8 +64,9 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) | |||
64 | 64 | ||
65 | full_path = build_path_from_dentry(direntry); | 65 | full_path = build_path_from_dentry(direntry); |
66 | if (full_path == NULL) { | 66 | if (full_path == NULL) { |
67 | rc = -ENOMEM; | ||
67 | FreeXid(xid); | 68 | FreeXid(xid); |
68 | return -ENOMEM; | 69 | return rc; |
69 | } | 70 | } |
70 | if (ea_name == NULL) { | 71 | if (ea_name == NULL) { |
71 | cFYI(1, ("Null xattr names not supported")); | 72 | cFYI(1, ("Null xattr names not supported")); |
@@ -118,8 +119,9 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
118 | 119 | ||
119 | full_path = build_path_from_dentry(direntry); | 120 | full_path = build_path_from_dentry(direntry); |
120 | if (full_path == NULL) { | 121 | if (full_path == NULL) { |
122 | rc = -ENOMEM; | ||
121 | FreeXid(xid); | 123 | FreeXid(xid); |
122 | return -ENOMEM; | 124 | return rc; |
123 | } | 125 | } |
124 | /* return dos attributes as pseudo xattr */ | 126 | /* return dos attributes as pseudo xattr */ |
125 | /* return alt name if available as pseudo attr */ | 127 | /* return alt name if available as pseudo attr */ |
@@ -225,8 +227,9 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, | |||
225 | 227 | ||
226 | full_path = build_path_from_dentry(direntry); | 228 | full_path = build_path_from_dentry(direntry); |
227 | if (full_path == NULL) { | 229 | if (full_path == NULL) { |
230 | rc = -ENOMEM; | ||
228 | FreeXid(xid); | 231 | FreeXid(xid); |
229 | return -ENOMEM; | 232 | return rc; |
230 | } | 233 | } |
231 | /* return dos attributes as pseudo xattr */ | 234 | /* return dos attributes as pseudo xattr */ |
232 | /* return alt name if available as pseudo attr */ | 235 | /* return alt name if available as pseudo attr */ |
@@ -351,8 +354,9 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) | |||
351 | 354 | ||
352 | full_path = build_path_from_dentry(direntry); | 355 | full_path = build_path_from_dentry(direntry); |
353 | if (full_path == NULL) { | 356 | if (full_path == NULL) { |
357 | rc = -ENOMEM; | ||
354 | FreeXid(xid); | 358 | FreeXid(xid); |
355 | return -ENOMEM; | 359 | return rc; |
356 | } | 360 | } |
357 | /* return dos attributes as pseudo xattr */ | 361 | /* return dos attributes as pseudo xattr */ |
358 | /* return alt name if available as pseudo attr */ | 362 | /* return alt name if available as pseudo attr */ |
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index c5ded5ff72b5..626c7483b4de 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/skbuff.h> | 31 | #include <linux/skbuff.h> |
32 | #include <linux/netlink.h> | 32 | #include <linux/netlink.h> |
33 | #include <linux/vt.h> | 33 | #include <linux/vt.h> |
34 | #include <linux/falloc.h> | ||
34 | #include <linux/fs.h> | 35 | #include <linux/fs.h> |
35 | #include <linux/file.h> | 36 | #include <linux/file.h> |
36 | #include <linux/ppp_defs.h> | 37 | #include <linux/ppp_defs.h> |
@@ -94,7 +95,6 @@ | |||
94 | #include <linux/atm_tcp.h> | 95 | #include <linux/atm_tcp.h> |
95 | #include <linux/sonet.h> | 96 | #include <linux/sonet.h> |
96 | #include <linux/atm_suni.h> | 97 | #include <linux/atm_suni.h> |
97 | #include <linux/mtd/mtd.h> | ||
98 | 98 | ||
99 | #include <linux/usb.h> | 99 | #include <linux/usb.h> |
100 | #include <linux/usbdevice_fs.h> | 100 | #include <linux/usbdevice_fs.h> |
@@ -1405,46 +1405,6 @@ static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
1405 | #define HIDPGETCONNLIST _IOR('H', 210, int) | 1405 | #define HIDPGETCONNLIST _IOR('H', 210, int) |
1406 | #define HIDPGETCONNINFO _IOR('H', 211, int) | 1406 | #define HIDPGETCONNINFO _IOR('H', 211, int) |
1407 | 1407 | ||
1408 | struct mtd_oob_buf32 { | ||
1409 | u_int32_t start; | ||
1410 | u_int32_t length; | ||
1411 | compat_caddr_t ptr; /* unsigned char* */ | ||
1412 | }; | ||
1413 | |||
1414 | #define MEMWRITEOOB32 _IOWR('M',3,struct mtd_oob_buf32) | ||
1415 | #define MEMREADOOB32 _IOWR('M',4,struct mtd_oob_buf32) | ||
1416 | |||
1417 | static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
1418 | { | ||
1419 | struct mtd_oob_buf __user *buf = compat_alloc_user_space(sizeof(*buf)); | ||
1420 | struct mtd_oob_buf32 __user *buf32 = compat_ptr(arg); | ||
1421 | u32 data; | ||
1422 | char __user *datap; | ||
1423 | unsigned int real_cmd; | ||
1424 | int err; | ||
1425 | |||
1426 | real_cmd = (cmd == MEMREADOOB32) ? | ||
1427 | MEMREADOOB : MEMWRITEOOB; | ||
1428 | |||
1429 | if (copy_in_user(&buf->start, &buf32->start, | ||
1430 | 2 * sizeof(u32)) || | ||
1431 | get_user(data, &buf32->ptr)) | ||
1432 | return -EFAULT; | ||
1433 | datap = compat_ptr(data); | ||
1434 | if (put_user(datap, &buf->ptr)) | ||
1435 | return -EFAULT; | ||
1436 | |||
1437 | err = sys_ioctl(fd, real_cmd, (unsigned long) buf); | ||
1438 | |||
1439 | if (!err) { | ||
1440 | if (copy_in_user(&buf32->start, &buf->start, | ||
1441 | 2 * sizeof(u32))) | ||
1442 | err = -EFAULT; | ||
1443 | } | ||
1444 | |||
1445 | return err; | ||
1446 | } | ||
1447 | |||
1448 | #ifdef CONFIG_BLOCK | 1408 | #ifdef CONFIG_BLOCK |
1449 | struct raw32_config_request | 1409 | struct raw32_config_request |
1450 | { | 1410 | { |
@@ -1820,6 +1780,41 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
1820 | return sys_ioctl(fd, cmd, (unsigned long)tn); | 1780 | return sys_ioctl(fd, cmd, (unsigned long)tn); |
1821 | } | 1781 | } |
1822 | 1782 | ||
1783 | /* on ia32 l_start is on a 32-bit boundary */ | ||
1784 | #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) | ||
1785 | struct space_resv_32 { | ||
1786 | __s16 l_type; | ||
1787 | __s16 l_whence; | ||
1788 | __s64 l_start __attribute__((packed)); | ||
1789 | /* len == 0 means until end of file */ | ||
1790 | __s64 l_len __attribute__((packed)); | ||
1791 | __s32 l_sysid; | ||
1792 | __u32 l_pid; | ||
1793 | __s32 l_pad[4]; /* reserve area */ | ||
1794 | }; | ||
1795 | |||
1796 | #define FS_IOC_RESVSP_32 _IOW ('X', 40, struct space_resv_32) | ||
1797 | #define FS_IOC_RESVSP64_32 _IOW ('X', 42, struct space_resv_32) | ||
1798 | |||
1799 | /* just account for different alignment */ | ||
1800 | static int compat_ioctl_preallocate(struct file *file, unsigned long arg) | ||
1801 | { | ||
1802 | struct space_resv_32 __user *p32 = (void __user *)arg; | ||
1803 | struct space_resv __user *p = compat_alloc_user_space(sizeof(*p)); | ||
1804 | |||
1805 | if (copy_in_user(&p->l_type, &p32->l_type, sizeof(s16)) || | ||
1806 | copy_in_user(&p->l_whence, &p32->l_whence, sizeof(s16)) || | ||
1807 | copy_in_user(&p->l_start, &p32->l_start, sizeof(s64)) || | ||
1808 | copy_in_user(&p->l_len, &p32->l_len, sizeof(s64)) || | ||
1809 | copy_in_user(&p->l_sysid, &p32->l_sysid, sizeof(s32)) || | ||
1810 | copy_in_user(&p->l_pid, &p32->l_pid, sizeof(u32)) || | ||
1811 | copy_in_user(&p->l_pad, &p32->l_pad, 4*sizeof(u32))) | ||
1812 | return -EFAULT; | ||
1813 | |||
1814 | return ioctl_preallocate(file, p); | ||
1815 | } | ||
1816 | #endif | ||
1817 | |||
1823 | 1818 | ||
1824 | typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, | 1819 | typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, |
1825 | unsigned long, struct file *); | 1820 | unsigned long, struct file *); |
@@ -2426,15 +2421,6 @@ COMPATIBLE_IOCTL(USBDEVFS_SUBMITURB32) | |||
2426 | COMPATIBLE_IOCTL(USBDEVFS_REAPURB32) | 2421 | COMPATIBLE_IOCTL(USBDEVFS_REAPURB32) |
2427 | COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32) | 2422 | COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32) |
2428 | COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT) | 2423 | COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT) |
2429 | /* MTD */ | ||
2430 | COMPATIBLE_IOCTL(MEMGETINFO) | ||
2431 | COMPATIBLE_IOCTL(MEMERASE) | ||
2432 | COMPATIBLE_IOCTL(MEMLOCK) | ||
2433 | COMPATIBLE_IOCTL(MEMUNLOCK) | ||
2434 | COMPATIBLE_IOCTL(MEMGETREGIONCOUNT) | ||
2435 | COMPATIBLE_IOCTL(MEMGETREGIONINFO) | ||
2436 | COMPATIBLE_IOCTL(MEMGETBADBLOCK) | ||
2437 | COMPATIBLE_IOCTL(MEMSETBADBLOCK) | ||
2438 | /* NBD */ | 2424 | /* NBD */ |
2439 | ULONG_IOCTL(NBD_SET_SOCK) | 2425 | ULONG_IOCTL(NBD_SET_SOCK) |
2440 | ULONG_IOCTL(NBD_SET_BLKSIZE) | 2426 | ULONG_IOCTL(NBD_SET_BLKSIZE) |
@@ -2544,8 +2530,6 @@ COMPATIBLE_IOCTL(JSIOCGBUTTONS) | |||
2544 | COMPATIBLE_IOCTL(JSIOCGNAME(0)) | 2530 | COMPATIBLE_IOCTL(JSIOCGNAME(0)) |
2545 | 2531 | ||
2546 | /* now things that need handlers */ | 2532 | /* now things that need handlers */ |
2547 | HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob) | ||
2548 | HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob) | ||
2549 | #ifdef CONFIG_NET | 2533 | #ifdef CONFIG_NET |
2550 | HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) | 2534 | HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) |
2551 | HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) | 2535 | HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) |
@@ -2808,6 +2792,18 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, | |||
2808 | case FIOQSIZE: | 2792 | case FIOQSIZE: |
2809 | break; | 2793 | break; |
2810 | 2794 | ||
2795 | #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) | ||
2796 | case FS_IOC_RESVSP_32: | ||
2797 | case FS_IOC_RESVSP64_32: | ||
2798 | error = compat_ioctl_preallocate(filp, arg); | ||
2799 | goto out_fput; | ||
2800 | #else | ||
2801 | case FS_IOC_RESVSP: | ||
2802 | case FS_IOC_RESVSP64: | ||
2803 | error = ioctl_preallocate(filp, (void __user *)arg); | ||
2804 | goto out_fput; | ||
2805 | #endif | ||
2806 | |||
2811 | case FIBMAP: | 2807 | case FIBMAP: |
2812 | case FIGETBSZ: | 2808 | case FIGETBSZ: |
2813 | case FIONREAD: | 2809 | case FIONREAD: |
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 9b1d285f9fe6..75efb028974b 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c | |||
@@ -423,7 +423,6 @@ static void devpts_kill_sb(struct super_block *sb) | |||
423 | } | 423 | } |
424 | 424 | ||
425 | static struct file_system_type devpts_fs_type = { | 425 | static struct file_system_type devpts_fs_type = { |
426 | .owner = THIS_MODULE, | ||
427 | .name = "devpts", | 426 | .name = "devpts", |
428 | .get_sb = devpts_get_sb, | 427 | .get_sb = devpts_get_sb, |
429 | .kill_sb = devpts_kill_sb, | 428 | .kill_sb = devpts_kill_sb, |
@@ -564,13 +563,4 @@ static int __init init_devpts_fs(void) | |||
564 | } | 563 | } |
565 | return err; | 564 | return err; |
566 | } | 565 | } |
567 | |||
568 | static void __exit exit_devpts_fs(void) | ||
569 | { | ||
570 | unregister_filesystem(&devpts_fs_type); | ||
571 | mntput(devpts_mnt); | ||
572 | } | ||
573 | |||
574 | module_init(init_devpts_fs) | 566 | module_init(init_devpts_fs) |
575 | module_exit(exit_devpts_fs) | ||
576 | MODULE_LICENSE("GPL"); | ||
diff --git a/fs/eventfd.c b/fs/eventfd.c index 3f0e1974abdc..31d12de83a2a 100644 --- a/fs/eventfd.c +++ b/fs/eventfd.c | |||
@@ -14,35 +14,44 @@ | |||
14 | #include <linux/list.h> | 14 | #include <linux/list.h> |
15 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
16 | #include <linux/anon_inodes.h> | 16 | #include <linux/anon_inodes.h> |
17 | #include <linux/eventfd.h> | ||
18 | #include <linux/syscalls.h> | 17 | #include <linux/syscalls.h> |
19 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/kref.h> | ||
20 | #include <linux/eventfd.h> | ||
20 | 21 | ||
21 | struct eventfd_ctx { | 22 | struct eventfd_ctx { |
23 | struct kref kref; | ||
22 | wait_queue_head_t wqh; | 24 | wait_queue_head_t wqh; |
23 | /* | 25 | /* |
24 | * Every time that a write(2) is performed on an eventfd, the | 26 | * Every time that a write(2) is performed on an eventfd, the |
25 | * value of the __u64 being written is added to "count" and a | 27 | * value of the __u64 being written is added to "count" and a |
26 | * wakeup is performed on "wqh". A read(2) will return the "count" | 28 | * wakeup is performed on "wqh". A read(2) will return the "count" |
27 | * value to userspace, and will reset "count" to zero. The kernel | 29 | * value to userspace, and will reset "count" to zero. The kernel |
28 | * size eventfd_signal() also, adds to the "count" counter and | 30 | * side eventfd_signal() also, adds to the "count" counter and |
29 | * issue a wakeup. | 31 | * issue a wakeup. |
30 | */ | 32 | */ |
31 | __u64 count; | 33 | __u64 count; |
32 | unsigned int flags; | 34 | unsigned int flags; |
33 | }; | 35 | }; |
34 | 36 | ||
35 | /* | 37 | /** |
36 | * Adds "n" to the eventfd counter "count". Returns "n" in case of | 38 | * eventfd_signal - Adds @n to the eventfd counter. |
37 | * success, or a value lower then "n" in case of coutner overflow. | 39 | * @ctx: [in] Pointer to the eventfd context. |
38 | * This function is supposed to be called by the kernel in paths | 40 | * @n: [in] Value of the counter to be added to the eventfd internal counter. |
39 | * that do not allow sleeping. In this function we allow the counter | 41 | * The value cannot be negative. |
40 | * to reach the ULLONG_MAX value, and we signal this as overflow | 42 | * |
41 | * condition by returining a POLLERR to poll(2). | 43 | * This function is supposed to be called by the kernel in paths that do not |
44 | * allow sleeping. In this function we allow the counter to reach the ULLONG_MAX | ||
45 | * value, and we signal this as overflow condition by returining a POLLERR | ||
46 | * to poll(2). | ||
47 | * | ||
48 | * Returns @n in case of success, a non-negative number lower than @n in case | ||
49 | * of overflow, or the following error codes: | ||
50 | * | ||
51 | * -EINVAL : The value of @n is negative. | ||
42 | */ | 52 | */ |
43 | int eventfd_signal(struct file *file, int n) | 53 | int eventfd_signal(struct eventfd_ctx *ctx, int n) |
44 | { | 54 | { |
45 | struct eventfd_ctx *ctx = file->private_data; | ||
46 | unsigned long flags; | 55 | unsigned long flags; |
47 | 56 | ||
48 | if (n < 0) | 57 | if (n < 0) |
@@ -59,9 +68,45 @@ int eventfd_signal(struct file *file, int n) | |||
59 | } | 68 | } |
60 | EXPORT_SYMBOL_GPL(eventfd_signal); | 69 | EXPORT_SYMBOL_GPL(eventfd_signal); |
61 | 70 | ||
71 | static void eventfd_free(struct kref *kref) | ||
72 | { | ||
73 | struct eventfd_ctx *ctx = container_of(kref, struct eventfd_ctx, kref); | ||
74 | |||
75 | kfree(ctx); | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * eventfd_ctx_get - Acquires a reference to the internal eventfd context. | ||
80 | * @ctx: [in] Pointer to the eventfd context. | ||
81 | * | ||
82 | * Returns: In case of success, returns a pointer to the eventfd context. | ||
83 | */ | ||
84 | struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx) | ||
85 | { | ||
86 | kref_get(&ctx->kref); | ||
87 | return ctx; | ||
88 | } | ||
89 | EXPORT_SYMBOL_GPL(eventfd_ctx_get); | ||
90 | |||
91 | /** | ||
92 | * eventfd_ctx_put - Releases a reference to the internal eventfd context. | ||
93 | * @ctx: [in] Pointer to eventfd context. | ||
94 | * | ||
95 | * The eventfd context reference must have been previously acquired either | ||
96 | * with eventfd_ctx_get() or eventfd_ctx_fdget()). | ||
97 | */ | ||
98 | void eventfd_ctx_put(struct eventfd_ctx *ctx) | ||
99 | { | ||
100 | kref_put(&ctx->kref, eventfd_free); | ||
101 | } | ||
102 | EXPORT_SYMBOL_GPL(eventfd_ctx_put); | ||
103 | |||
62 | static int eventfd_release(struct inode *inode, struct file *file) | 104 | static int eventfd_release(struct inode *inode, struct file *file) |
63 | { | 105 | { |
64 | kfree(file->private_data); | 106 | struct eventfd_ctx *ctx = file->private_data; |
107 | |||
108 | wake_up_poll(&ctx->wqh, POLLHUP); | ||
109 | eventfd_ctx_put(ctx); | ||
65 | return 0; | 110 | return 0; |
66 | } | 111 | } |
67 | 112 | ||
@@ -185,6 +230,16 @@ static const struct file_operations eventfd_fops = { | |||
185 | .write = eventfd_write, | 230 | .write = eventfd_write, |
186 | }; | 231 | }; |
187 | 232 | ||
233 | /** | ||
234 | * eventfd_fget - Acquire a reference of an eventfd file descriptor. | ||
235 | * @fd: [in] Eventfd file descriptor. | ||
236 | * | ||
237 | * Returns a pointer to the eventfd file structure in case of success, or the | ||
238 | * following error pointer: | ||
239 | * | ||
240 | * -EBADF : Invalid @fd file descriptor. | ||
241 | * -EINVAL : The @fd file descriptor is not an eventfd file. | ||
242 | */ | ||
188 | struct file *eventfd_fget(int fd) | 243 | struct file *eventfd_fget(int fd) |
189 | { | 244 | { |
190 | struct file *file; | 245 | struct file *file; |
@@ -201,6 +256,48 @@ struct file *eventfd_fget(int fd) | |||
201 | } | 256 | } |
202 | EXPORT_SYMBOL_GPL(eventfd_fget); | 257 | EXPORT_SYMBOL_GPL(eventfd_fget); |
203 | 258 | ||
259 | /** | ||
260 | * eventfd_ctx_fdget - Acquires a reference to the internal eventfd context. | ||
261 | * @fd: [in] Eventfd file descriptor. | ||
262 | * | ||
263 | * Returns a pointer to the internal eventfd context, otherwise the error | ||
264 | * pointers returned by the following functions: | ||
265 | * | ||
266 | * eventfd_fget | ||
267 | */ | ||
268 | struct eventfd_ctx *eventfd_ctx_fdget(int fd) | ||
269 | { | ||
270 | struct file *file; | ||
271 | struct eventfd_ctx *ctx; | ||
272 | |||
273 | file = eventfd_fget(fd); | ||
274 | if (IS_ERR(file)) | ||
275 | return (struct eventfd_ctx *) file; | ||
276 | ctx = eventfd_ctx_get(file->private_data); | ||
277 | fput(file); | ||
278 | |||
279 | return ctx; | ||
280 | } | ||
281 | EXPORT_SYMBOL_GPL(eventfd_ctx_fdget); | ||
282 | |||
283 | /** | ||
284 | * eventfd_ctx_fileget - Acquires a reference to the internal eventfd context. | ||
285 | * @file: [in] Eventfd file pointer. | ||
286 | * | ||
287 | * Returns a pointer to the internal eventfd context, otherwise the error | ||
288 | * pointer: | ||
289 | * | ||
290 | * -EINVAL : The @fd file descriptor is not an eventfd file. | ||
291 | */ | ||
292 | struct eventfd_ctx *eventfd_ctx_fileget(struct file *file) | ||
293 | { | ||
294 | if (file->f_op != &eventfd_fops) | ||
295 | return ERR_PTR(-EINVAL); | ||
296 | |||
297 | return eventfd_ctx_get(file->private_data); | ||
298 | } | ||
299 | EXPORT_SYMBOL_GPL(eventfd_ctx_fileget); | ||
300 | |||
204 | SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) | 301 | SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) |
205 | { | 302 | { |
206 | int fd; | 303 | int fd; |
@@ -217,6 +314,7 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) | |||
217 | if (!ctx) | 314 | if (!ctx) |
218 | return -ENOMEM; | 315 | return -ENOMEM; |
219 | 316 | ||
317 | kref_init(&ctx->kref); | ||
220 | init_waitqueue_head(&ctx->wqh); | 318 | init_waitqueue_head(&ctx->wqh); |
221 | ctx->count = count; | 319 | ctx->count = count; |
222 | ctx->flags = flags; | 320 | ctx->flags = flags; |
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index d46e38cb85c5..d636e1297cad 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c | |||
@@ -125,37 +125,12 @@ fail: | |||
125 | return ERR_PTR(-EINVAL); | 125 | return ERR_PTR(-EINVAL); |
126 | } | 126 | } |
127 | 127 | ||
128 | static inline struct posix_acl * | ||
129 | ext2_iget_acl(struct inode *inode, struct posix_acl **i_acl) | ||
130 | { | ||
131 | struct posix_acl *acl = EXT2_ACL_NOT_CACHED; | ||
132 | |||
133 | spin_lock(&inode->i_lock); | ||
134 | if (*i_acl != EXT2_ACL_NOT_CACHED) | ||
135 | acl = posix_acl_dup(*i_acl); | ||
136 | spin_unlock(&inode->i_lock); | ||
137 | |||
138 | return acl; | ||
139 | } | ||
140 | |||
141 | static inline void | ||
142 | ext2_iset_acl(struct inode *inode, struct posix_acl **i_acl, | ||
143 | struct posix_acl *acl) | ||
144 | { | ||
145 | spin_lock(&inode->i_lock); | ||
146 | if (*i_acl != EXT2_ACL_NOT_CACHED) | ||
147 | posix_acl_release(*i_acl); | ||
148 | *i_acl = posix_acl_dup(acl); | ||
149 | spin_unlock(&inode->i_lock); | ||
150 | } | ||
151 | |||
152 | /* | 128 | /* |
153 | * inode->i_mutex: don't care | 129 | * inode->i_mutex: don't care |
154 | */ | 130 | */ |
155 | static struct posix_acl * | 131 | static struct posix_acl * |
156 | ext2_get_acl(struct inode *inode, int type) | 132 | ext2_get_acl(struct inode *inode, int type) |
157 | { | 133 | { |
158 | struct ext2_inode_info *ei = EXT2_I(inode); | ||
159 | int name_index; | 134 | int name_index; |
160 | char *value = NULL; | 135 | char *value = NULL; |
161 | struct posix_acl *acl; | 136 | struct posix_acl *acl; |
@@ -164,23 +139,19 @@ ext2_get_acl(struct inode *inode, int type) | |||
164 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 139 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
165 | return NULL; | 140 | return NULL; |
166 | 141 | ||
167 | switch(type) { | 142 | acl = get_cached_acl(inode, type); |
168 | case ACL_TYPE_ACCESS: | 143 | if (acl != ACL_NOT_CACHED) |
169 | acl = ext2_iget_acl(inode, &ei->i_acl); | 144 | return acl; |
170 | if (acl != EXT2_ACL_NOT_CACHED) | 145 | |
171 | return acl; | 146 | switch (type) { |
172 | name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; | 147 | case ACL_TYPE_ACCESS: |
173 | break; | 148 | name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; |
174 | 149 | break; | |
175 | case ACL_TYPE_DEFAULT: | 150 | case ACL_TYPE_DEFAULT: |
176 | acl = ext2_iget_acl(inode, &ei->i_default_acl); | 151 | name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; |
177 | if (acl != EXT2_ACL_NOT_CACHED) | 152 | break; |
178 | return acl; | 153 | default: |
179 | name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; | 154 | BUG(); |
180 | break; | ||
181 | |||
182 | default: | ||
183 | return ERR_PTR(-EINVAL); | ||
184 | } | 155 | } |
185 | retval = ext2_xattr_get(inode, name_index, "", NULL, 0); | 156 | retval = ext2_xattr_get(inode, name_index, "", NULL, 0); |
186 | if (retval > 0) { | 157 | if (retval > 0) { |
@@ -197,17 +168,9 @@ ext2_get_acl(struct inode *inode, int type) | |||
197 | acl = ERR_PTR(retval); | 168 | acl = ERR_PTR(retval); |
198 | kfree(value); | 169 | kfree(value); |
199 | 170 | ||
200 | if (!IS_ERR(acl)) { | 171 | if (!IS_ERR(acl)) |
201 | switch(type) { | 172 | set_cached_acl(inode, type, acl); |
202 | case ACL_TYPE_ACCESS: | ||
203 | ext2_iset_acl(inode, &ei->i_acl, acl); | ||
204 | break; | ||
205 | 173 | ||
206 | case ACL_TYPE_DEFAULT: | ||
207 | ext2_iset_acl(inode, &ei->i_default_acl, acl); | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | return acl; | 174 | return acl; |
212 | } | 175 | } |
213 | 176 | ||
@@ -217,7 +180,6 @@ ext2_get_acl(struct inode *inode, int type) | |||
217 | static int | 180 | static int |
218 | ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | 181 | ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) |
219 | { | 182 | { |
220 | struct ext2_inode_info *ei = EXT2_I(inode); | ||
221 | int name_index; | 183 | int name_index; |
222 | void *value = NULL; | 184 | void *value = NULL; |
223 | size_t size = 0; | 185 | size_t size = 0; |
@@ -263,17 +225,8 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
263 | error = ext2_xattr_set(inode, name_index, "", value, size, 0); | 225 | error = ext2_xattr_set(inode, name_index, "", value, size, 0); |
264 | 226 | ||
265 | kfree(value); | 227 | kfree(value); |
266 | if (!error) { | 228 | if (!error) |
267 | switch(type) { | 229 | set_cached_acl(inode, type, acl); |
268 | case ACL_TYPE_ACCESS: | ||
269 | ext2_iset_acl(inode, &ei->i_acl, acl); | ||
270 | break; | ||
271 | |||
272 | case ACL_TYPE_DEFAULT: | ||
273 | ext2_iset_acl(inode, &ei->i_default_acl, acl); | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | return error; | 230 | return error; |
278 | } | 231 | } |
279 | 232 | ||
diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h index b42cf578554b..ecefe478898f 100644 --- a/fs/ext2/acl.h +++ b/fs/ext2/acl.h | |||
@@ -53,10 +53,6 @@ static inline int ext2_acl_count(size_t size) | |||
53 | 53 | ||
54 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | 54 | #ifdef CONFIG_EXT2_FS_POSIX_ACL |
55 | 55 | ||
56 | /* Value for inode->u.ext2_i.i_acl and inode->u.ext2_i.i_default_acl | ||
57 | if the ACL has not been cached */ | ||
58 | #define EXT2_ACL_NOT_CACHED ((void *)-1) | ||
59 | |||
60 | /* acl.c */ | 56 | /* acl.c */ |
61 | extern int ext2_permission (struct inode *, int); | 57 | extern int ext2_permission (struct inode *, int); |
62 | extern int ext2_acl_chmod (struct inode *); | 58 | extern int ext2_acl_chmod (struct inode *); |
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index d988a718aedb..9a8a8e27a063 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
@@ -47,10 +47,6 @@ struct ext2_inode_info { | |||
47 | */ | 47 | */ |
48 | struct rw_semaphore xattr_sem; | 48 | struct rw_semaphore xattr_sem; |
49 | #endif | 49 | #endif |
50 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | ||
51 | struct posix_acl *i_acl; | ||
52 | struct posix_acl *i_default_acl; | ||
53 | #endif | ||
54 | rwlock_t i_meta_lock; | 50 | rwlock_t i_meta_lock; |
55 | 51 | ||
56 | /* | 52 | /* |
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 29ed682061f6..e27130341d4f 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
@@ -1224,10 +1224,6 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino) | |||
1224 | return inode; | 1224 | return inode; |
1225 | 1225 | ||
1226 | ei = EXT2_I(inode); | 1226 | ei = EXT2_I(inode); |
1227 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | ||
1228 | ei->i_acl = EXT2_ACL_NOT_CACHED; | ||
1229 | ei->i_default_acl = EXT2_ACL_NOT_CACHED; | ||
1230 | #endif | ||
1231 | ei->i_block_alloc_info = NULL; | 1227 | ei->i_block_alloc_info = NULL; |
1232 | 1228 | ||
1233 | raw_inode = ext2_get_inode(inode->i_sb, ino, &bh); | 1229 | raw_inode = ext2_get_inode(inode->i_sb, ino, &bh); |
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 6524ecaebb7a..e1dedb0f7873 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c | |||
@@ -66,8 +66,16 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str | |||
66 | inode = NULL; | 66 | inode = NULL; |
67 | if (ino) { | 67 | if (ino) { |
68 | inode = ext2_iget(dir->i_sb, ino); | 68 | inode = ext2_iget(dir->i_sb, ino); |
69 | if (IS_ERR(inode)) | 69 | if (unlikely(IS_ERR(inode))) { |
70 | return ERR_CAST(inode); | 70 | if (PTR_ERR(inode) == -ESTALE) { |
71 | ext2_error(dir->i_sb, __func__, | ||
72 | "deleted inode referenced: %lu", | ||
73 | ino); | ||
74 | return ERR_PTR(-EIO); | ||
75 | } else { | ||
76 | return ERR_CAST(inode); | ||
77 | } | ||
78 | } | ||
71 | } | 79 | } |
72 | return d_splice_alias(inode, dentry); | 80 | return d_splice_alias(inode, dentry); |
73 | } | 81 | } |
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 458999638c3d..1a9ffee47d56 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
@@ -152,10 +152,6 @@ static struct inode *ext2_alloc_inode(struct super_block *sb) | |||
152 | ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, GFP_KERNEL); | 152 | ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, GFP_KERNEL); |
153 | if (!ei) | 153 | if (!ei) |
154 | return NULL; | 154 | return NULL; |
155 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | ||
156 | ei->i_acl = EXT2_ACL_NOT_CACHED; | ||
157 | ei->i_default_acl = EXT2_ACL_NOT_CACHED; | ||
158 | #endif | ||
159 | ei->i_block_alloc_info = NULL; | 155 | ei->i_block_alloc_info = NULL; |
160 | ei->vfs_inode.i_version = 1; | 156 | ei->vfs_inode.i_version = 1; |
161 | return &ei->vfs_inode; | 157 | return &ei->vfs_inode; |
@@ -198,18 +194,6 @@ static void destroy_inodecache(void) | |||
198 | static void ext2_clear_inode(struct inode *inode) | 194 | static void ext2_clear_inode(struct inode *inode) |
199 | { | 195 | { |
200 | struct ext2_block_alloc_info *rsv = EXT2_I(inode)->i_block_alloc_info; | 196 | struct ext2_block_alloc_info *rsv = EXT2_I(inode)->i_block_alloc_info; |
201 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | ||
202 | struct ext2_inode_info *ei = EXT2_I(inode); | ||
203 | |||
204 | if (ei->i_acl && ei->i_acl != EXT2_ACL_NOT_CACHED) { | ||
205 | posix_acl_release(ei->i_acl); | ||
206 | ei->i_acl = EXT2_ACL_NOT_CACHED; | ||
207 | } | ||
208 | if (ei->i_default_acl && ei->i_default_acl != EXT2_ACL_NOT_CACHED) { | ||
209 | posix_acl_release(ei->i_default_acl); | ||
210 | ei->i_default_acl = EXT2_ACL_NOT_CACHED; | ||
211 | } | ||
212 | #endif | ||
213 | ext2_discard_reservation(inode); | 197 | ext2_discard_reservation(inode); |
214 | EXT2_I(inode)->i_block_alloc_info = NULL; | 198 | EXT2_I(inode)->i_block_alloc_info = NULL; |
215 | if (unlikely(rsv)) | 199 | if (unlikely(rsv)) |
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index e0c745451715..e167bae37ef0 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c | |||
@@ -126,33 +126,6 @@ fail: | |||
126 | return ERR_PTR(-EINVAL); | 126 | return ERR_PTR(-EINVAL); |
127 | } | 127 | } |
128 | 128 | ||
129 | static inline struct posix_acl * | ||
130 | ext3_iget_acl(struct inode *inode, struct posix_acl **i_acl) | ||
131 | { | ||
132 | struct posix_acl *acl = ACCESS_ONCE(*i_acl); | ||
133 | |||
134 | if (acl) { | ||
135 | spin_lock(&inode->i_lock); | ||
136 | acl = *i_acl; | ||
137 | if (acl != EXT3_ACL_NOT_CACHED) | ||
138 | acl = posix_acl_dup(acl); | ||
139 | spin_unlock(&inode->i_lock); | ||
140 | } | ||
141 | |||
142 | return acl; | ||
143 | } | ||
144 | |||
145 | static inline void | ||
146 | ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl, | ||
147 | struct posix_acl *acl) | ||
148 | { | ||
149 | spin_lock(&inode->i_lock); | ||
150 | if (*i_acl != EXT3_ACL_NOT_CACHED) | ||
151 | posix_acl_release(*i_acl); | ||
152 | *i_acl = posix_acl_dup(acl); | ||
153 | spin_unlock(&inode->i_lock); | ||
154 | } | ||
155 | |||
156 | /* | 129 | /* |
157 | * Inode operation get_posix_acl(). | 130 | * Inode operation get_posix_acl(). |
158 | * | 131 | * |
@@ -161,7 +134,6 @@ ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl, | |||
161 | static struct posix_acl * | 134 | static struct posix_acl * |
162 | ext3_get_acl(struct inode *inode, int type) | 135 | ext3_get_acl(struct inode *inode, int type) |
163 | { | 136 | { |
164 | struct ext3_inode_info *ei = EXT3_I(inode); | ||
165 | int name_index; | 137 | int name_index; |
166 | char *value = NULL; | 138 | char *value = NULL; |
167 | struct posix_acl *acl; | 139 | struct posix_acl *acl; |
@@ -170,24 +142,21 @@ ext3_get_acl(struct inode *inode, int type) | |||
170 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 142 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
171 | return NULL; | 143 | return NULL; |
172 | 144 | ||
173 | switch(type) { | 145 | acl = get_cached_acl(inode, type); |
174 | case ACL_TYPE_ACCESS: | 146 | if (acl != ACL_NOT_CACHED) |
175 | acl = ext3_iget_acl(inode, &ei->i_acl); | 147 | return acl; |
176 | if (acl != EXT3_ACL_NOT_CACHED) | 148 | |
177 | return acl; | 149 | switch (type) { |
178 | name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; | 150 | case ACL_TYPE_ACCESS: |
179 | break; | 151 | name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; |
180 | 152 | break; | |
181 | case ACL_TYPE_DEFAULT: | 153 | case ACL_TYPE_DEFAULT: |
182 | acl = ext3_iget_acl(inode, &ei->i_default_acl); | 154 | name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; |
183 | if (acl != EXT3_ACL_NOT_CACHED) | 155 | break; |
184 | return acl; | 156 | default: |
185 | name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; | 157 | BUG(); |
186 | break; | ||
187 | |||
188 | default: | ||
189 | return ERR_PTR(-EINVAL); | ||
190 | } | 158 | } |
159 | |||
191 | retval = ext3_xattr_get(inode, name_index, "", NULL, 0); | 160 | retval = ext3_xattr_get(inode, name_index, "", NULL, 0); |
192 | if (retval > 0) { | 161 | if (retval > 0) { |
193 | value = kmalloc(retval, GFP_NOFS); | 162 | value = kmalloc(retval, GFP_NOFS); |
@@ -203,17 +172,9 @@ ext3_get_acl(struct inode *inode, int type) | |||
203 | acl = ERR_PTR(retval); | 172 | acl = ERR_PTR(retval); |
204 | kfree(value); | 173 | kfree(value); |
205 | 174 | ||
206 | if (!IS_ERR(acl)) { | 175 | if (!IS_ERR(acl)) |
207 | switch(type) { | 176 | set_cached_acl(inode, type, acl); |
208 | case ACL_TYPE_ACCESS: | ||
209 | ext3_iset_acl(inode, &ei->i_acl, acl); | ||
210 | break; | ||
211 | 177 | ||
212 | case ACL_TYPE_DEFAULT: | ||
213 | ext3_iset_acl(inode, &ei->i_default_acl, acl); | ||
214 | break; | ||
215 | } | ||
216 | } | ||
217 | return acl; | 178 | return acl; |
218 | } | 179 | } |
219 | 180 | ||
@@ -226,7 +187,6 @@ static int | |||
226 | ext3_set_acl(handle_t *handle, struct inode *inode, int type, | 187 | ext3_set_acl(handle_t *handle, struct inode *inode, int type, |
227 | struct posix_acl *acl) | 188 | struct posix_acl *acl) |
228 | { | 189 | { |
229 | struct ext3_inode_info *ei = EXT3_I(inode); | ||
230 | int name_index; | 190 | int name_index; |
231 | void *value = NULL; | 191 | void *value = NULL; |
232 | size_t size = 0; | 192 | size_t size = 0; |
@@ -271,17 +231,10 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, | |||
271 | value, size, 0); | 231 | value, size, 0); |
272 | 232 | ||
273 | kfree(value); | 233 | kfree(value); |
274 | if (!error) { | ||
275 | switch(type) { | ||
276 | case ACL_TYPE_ACCESS: | ||
277 | ext3_iset_acl(inode, &ei->i_acl, acl); | ||
278 | break; | ||
279 | 234 | ||
280 | case ACL_TYPE_DEFAULT: | 235 | if (!error) |
281 | ext3_iset_acl(inode, &ei->i_default_acl, acl); | 236 | set_cached_acl(inode, type, acl); |
282 | break; | 237 | |
283 | } | ||
284 | } | ||
285 | return error; | 238 | return error; |
286 | } | 239 | } |
287 | 240 | ||
diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h index 42da16b8cac0..07d15a3a5969 100644 --- a/fs/ext3/acl.h +++ b/fs/ext3/acl.h | |||
@@ -53,10 +53,6 @@ static inline int ext3_acl_count(size_t size) | |||
53 | 53 | ||
54 | #ifdef CONFIG_EXT3_FS_POSIX_ACL | 54 | #ifdef CONFIG_EXT3_FS_POSIX_ACL |
55 | 55 | ||
56 | /* Value for inode->u.ext3_i.i_acl and inode->u.ext3_i.i_default_acl | ||
57 | if the ACL has not been cached */ | ||
58 | #define EXT3_ACL_NOT_CACHED ((void *)-1) | ||
59 | |||
60 | /* acl.c */ | 56 | /* acl.c */ |
61 | extern int ext3_permission (struct inode *, int); | 57 | extern int ext3_permission (struct inode *, int); |
62 | extern int ext3_acl_chmod (struct inode *); | 58 | extern int ext3_acl_chmod (struct inode *); |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 05dea8132fc0..5f51fed5c750 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -2752,10 +2752,6 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino) | |||
2752 | return inode; | 2752 | return inode; |
2753 | 2753 | ||
2754 | ei = EXT3_I(inode); | 2754 | ei = EXT3_I(inode); |
2755 | #ifdef CONFIG_EXT3_FS_POSIX_ACL | ||
2756 | ei->i_acl = EXT3_ACL_NOT_CACHED; | ||
2757 | ei->i_default_acl = EXT3_ACL_NOT_CACHED; | ||
2758 | #endif | ||
2759 | ei->i_block_alloc_info = NULL; | 2755 | ei->i_block_alloc_info = NULL; |
2760 | 2756 | ||
2761 | ret = __ext3_get_inode_loc(inode, &iloc, 0); | 2757 | ret = __ext3_get_inode_loc(inode, &iloc, 0); |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 601e881e6105..524b349c6299 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -464,10 +464,6 @@ static struct inode *ext3_alloc_inode(struct super_block *sb) | |||
464 | ei = kmem_cache_alloc(ext3_inode_cachep, GFP_NOFS); | 464 | ei = kmem_cache_alloc(ext3_inode_cachep, GFP_NOFS); |
465 | if (!ei) | 465 | if (!ei) |
466 | return NULL; | 466 | return NULL; |
467 | #ifdef CONFIG_EXT3_FS_POSIX_ACL | ||
468 | ei->i_acl = EXT3_ACL_NOT_CACHED; | ||
469 | ei->i_default_acl = EXT3_ACL_NOT_CACHED; | ||
470 | #endif | ||
471 | ei->i_block_alloc_info = NULL; | 467 | ei->i_block_alloc_info = NULL; |
472 | ei->vfs_inode.i_version = 1; | 468 | ei->vfs_inode.i_version = 1; |
473 | return &ei->vfs_inode; | 469 | return &ei->vfs_inode; |
@@ -518,18 +514,6 @@ static void destroy_inodecache(void) | |||
518 | static void ext3_clear_inode(struct inode *inode) | 514 | static void ext3_clear_inode(struct inode *inode) |
519 | { | 515 | { |
520 | struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info; | 516 | struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info; |
521 | #ifdef CONFIG_EXT3_FS_POSIX_ACL | ||
522 | if (EXT3_I(inode)->i_acl && | ||
523 | EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) { | ||
524 | posix_acl_release(EXT3_I(inode)->i_acl); | ||
525 | EXT3_I(inode)->i_acl = EXT3_ACL_NOT_CACHED; | ||
526 | } | ||
527 | if (EXT3_I(inode)->i_default_acl && | ||
528 | EXT3_I(inode)->i_default_acl != EXT3_ACL_NOT_CACHED) { | ||
529 | posix_acl_release(EXT3_I(inode)->i_default_acl); | ||
530 | EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED; | ||
531 | } | ||
532 | #endif | ||
533 | ext3_discard_reservation(inode); | 517 | ext3_discard_reservation(inode); |
534 | EXT3_I(inode)->i_block_alloc_info = NULL; | 518 | EXT3_I(inode)->i_block_alloc_info = NULL; |
535 | if (unlikely(rsv)) | 519 | if (unlikely(rsv)) |
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 605aeed96d68..f6d8967149ca 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c | |||
@@ -126,33 +126,6 @@ fail: | |||
126 | return ERR_PTR(-EINVAL); | 126 | return ERR_PTR(-EINVAL); |
127 | } | 127 | } |
128 | 128 | ||
129 | static inline struct posix_acl * | ||
130 | ext4_iget_acl(struct inode *inode, struct posix_acl **i_acl) | ||
131 | { | ||
132 | struct posix_acl *acl = ACCESS_ONCE(*i_acl); | ||
133 | |||
134 | if (acl) { | ||
135 | spin_lock(&inode->i_lock); | ||
136 | acl = *i_acl; | ||
137 | if (acl != EXT4_ACL_NOT_CACHED) | ||
138 | acl = posix_acl_dup(acl); | ||
139 | spin_unlock(&inode->i_lock); | ||
140 | } | ||
141 | |||
142 | return acl; | ||
143 | } | ||
144 | |||
145 | static inline void | ||
146 | ext4_iset_acl(struct inode *inode, struct posix_acl **i_acl, | ||
147 | struct posix_acl *acl) | ||
148 | { | ||
149 | spin_lock(&inode->i_lock); | ||
150 | if (*i_acl != EXT4_ACL_NOT_CACHED) | ||
151 | posix_acl_release(*i_acl); | ||
152 | *i_acl = posix_acl_dup(acl); | ||
153 | spin_unlock(&inode->i_lock); | ||
154 | } | ||
155 | |||
156 | /* | 129 | /* |
157 | * Inode operation get_posix_acl(). | 130 | * Inode operation get_posix_acl(). |
158 | * | 131 | * |
@@ -161,7 +134,6 @@ ext4_iset_acl(struct inode *inode, struct posix_acl **i_acl, | |||
161 | static struct posix_acl * | 134 | static struct posix_acl * |
162 | ext4_get_acl(struct inode *inode, int type) | 135 | ext4_get_acl(struct inode *inode, int type) |
163 | { | 136 | { |
164 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
165 | int name_index; | 137 | int name_index; |
166 | char *value = NULL; | 138 | char *value = NULL; |
167 | struct posix_acl *acl; | 139 | struct posix_acl *acl; |
@@ -170,23 +142,19 @@ ext4_get_acl(struct inode *inode, int type) | |||
170 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 142 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
171 | return NULL; | 143 | return NULL; |
172 | 144 | ||
145 | acl = get_cached_acl(inode, type); | ||
146 | if (acl != ACL_NOT_CACHED) | ||
147 | return acl; | ||
148 | |||
173 | switch (type) { | 149 | switch (type) { |
174 | case ACL_TYPE_ACCESS: | 150 | case ACL_TYPE_ACCESS: |
175 | acl = ext4_iget_acl(inode, &ei->i_acl); | ||
176 | if (acl != EXT4_ACL_NOT_CACHED) | ||
177 | return acl; | ||
178 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; | 151 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; |
179 | break; | 152 | break; |
180 | |||
181 | case ACL_TYPE_DEFAULT: | 153 | case ACL_TYPE_DEFAULT: |
182 | acl = ext4_iget_acl(inode, &ei->i_default_acl); | ||
183 | if (acl != EXT4_ACL_NOT_CACHED) | ||
184 | return acl; | ||
185 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT; | 154 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT; |
186 | break; | 155 | break; |
187 | |||
188 | default: | 156 | default: |
189 | return ERR_PTR(-EINVAL); | 157 | BUG(); |
190 | } | 158 | } |
191 | retval = ext4_xattr_get(inode, name_index, "", NULL, 0); | 159 | retval = ext4_xattr_get(inode, name_index, "", NULL, 0); |
192 | if (retval > 0) { | 160 | if (retval > 0) { |
@@ -203,17 +171,9 @@ ext4_get_acl(struct inode *inode, int type) | |||
203 | acl = ERR_PTR(retval); | 171 | acl = ERR_PTR(retval); |
204 | kfree(value); | 172 | kfree(value); |
205 | 173 | ||
206 | if (!IS_ERR(acl)) { | 174 | if (!IS_ERR(acl)) |
207 | switch (type) { | 175 | set_cached_acl(inode, type, acl); |
208 | case ACL_TYPE_ACCESS: | ||
209 | ext4_iset_acl(inode, &ei->i_acl, acl); | ||
210 | break; | ||
211 | 176 | ||
212 | case ACL_TYPE_DEFAULT: | ||
213 | ext4_iset_acl(inode, &ei->i_default_acl, acl); | ||
214 | break; | ||
215 | } | ||
216 | } | ||
217 | return acl; | 177 | return acl; |
218 | } | 178 | } |
219 | 179 | ||
@@ -226,7 +186,6 @@ static int | |||
226 | ext4_set_acl(handle_t *handle, struct inode *inode, int type, | 186 | ext4_set_acl(handle_t *handle, struct inode *inode, int type, |
227 | struct posix_acl *acl) | 187 | struct posix_acl *acl) |
228 | { | 188 | { |
229 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
230 | int name_index; | 189 | int name_index; |
231 | void *value = NULL; | 190 | void *value = NULL; |
232 | size_t size = 0; | 191 | size_t size = 0; |
@@ -271,17 +230,9 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, | |||
271 | value, size, 0); | 230 | value, size, 0); |
272 | 231 | ||
273 | kfree(value); | 232 | kfree(value); |
274 | if (!error) { | 233 | if (!error) |
275 | switch (type) { | 234 | set_cached_acl(inode, type, acl); |
276 | case ACL_TYPE_ACCESS: | ||
277 | ext4_iset_acl(inode, &ei->i_acl, acl); | ||
278 | break; | ||
279 | 235 | ||
280 | case ACL_TYPE_DEFAULT: | ||
281 | ext4_iset_acl(inode, &ei->i_default_acl, acl); | ||
282 | break; | ||
283 | } | ||
284 | } | ||
285 | return error; | 236 | return error; |
286 | } | 237 | } |
287 | 238 | ||
diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h index cb45257a246e..949789d2bba6 100644 --- a/fs/ext4/acl.h +++ b/fs/ext4/acl.h | |||
@@ -53,10 +53,6 @@ static inline int ext4_acl_count(size_t size) | |||
53 | 53 | ||
54 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | 54 | #ifdef CONFIG_EXT4_FS_POSIX_ACL |
55 | 55 | ||
56 | /* Value for inode->u.ext4_i.i_acl and inode->u.ext4_i.i_default_acl | ||
57 | if the ACL has not been cached */ | ||
58 | #define EXT4_ACL_NOT_CACHED ((void *)-1) | ||
59 | |||
60 | /* acl.c */ | 56 | /* acl.c */ |
61 | extern int ext4_permission(struct inode *, int); | 57 | extern int ext4_permission(struct inode *, int); |
62 | extern int ext4_acl_chmod(struct inode *); | 58 | extern int ext4_acl_chmod(struct inode *); |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 17b9998680e3..0ddf7e55abe1 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -595,10 +595,6 @@ struct ext4_inode_info { | |||
595 | */ | 595 | */ |
596 | struct rw_semaphore xattr_sem; | 596 | struct rw_semaphore xattr_sem; |
597 | #endif | 597 | #endif |
598 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | ||
599 | struct posix_acl *i_acl; | ||
600 | struct posix_acl *i_default_acl; | ||
601 | #endif | ||
602 | 598 | ||
603 | struct list_head i_orphan; /* unlinked but open inodes */ | 599 | struct list_head i_orphan; /* unlinked but open inodes */ |
604 | 600 | ||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 7c17ae275af4..60a26f3a6f8b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -4453,10 +4453,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4453 | return inode; | 4453 | return inode; |
4454 | 4454 | ||
4455 | ei = EXT4_I(inode); | 4455 | ei = EXT4_I(inode); |
4456 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | ||
4457 | ei->i_acl = EXT4_ACL_NOT_CACHED; | ||
4458 | ei->i_default_acl = EXT4_ACL_NOT_CACHED; | ||
4459 | #endif | ||
4460 | 4456 | ||
4461 | ret = __ext4_get_inode_loc(inode, &iloc, 0); | 4457 | ret = __ext4_get_inode_loc(inode, &iloc, 0); |
4462 | if (ret < 0) | 4458 | if (ret < 0) |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 8bb9e2d3e4b8..8f4f079e6b9a 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -666,10 +666,6 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) | |||
666 | if (!ei) | 666 | if (!ei) |
667 | return NULL; | 667 | return NULL; |
668 | 668 | ||
669 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | ||
670 | ei->i_acl = EXT4_ACL_NOT_CACHED; | ||
671 | ei->i_default_acl = EXT4_ACL_NOT_CACHED; | ||
672 | #endif | ||
673 | ei->vfs_inode.i_version = 1; | 669 | ei->vfs_inode.i_version = 1; |
674 | ei->vfs_inode.i_data.writeback_index = 0; | 670 | ei->vfs_inode.i_data.writeback_index = 0; |
675 | memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache)); | 671 | memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache)); |
@@ -735,18 +731,6 @@ static void destroy_inodecache(void) | |||
735 | 731 | ||
736 | static void ext4_clear_inode(struct inode *inode) | 732 | static void ext4_clear_inode(struct inode *inode) |
737 | { | 733 | { |
738 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | ||
739 | if (EXT4_I(inode)->i_acl && | ||
740 | EXT4_I(inode)->i_acl != EXT4_ACL_NOT_CACHED) { | ||
741 | posix_acl_release(EXT4_I(inode)->i_acl); | ||
742 | EXT4_I(inode)->i_acl = EXT4_ACL_NOT_CACHED; | ||
743 | } | ||
744 | if (EXT4_I(inode)->i_default_acl && | ||
745 | EXT4_I(inode)->i_default_acl != EXT4_ACL_NOT_CACHED) { | ||
746 | posix_acl_release(EXT4_I(inode)->i_default_acl); | ||
747 | EXT4_I(inode)->i_default_acl = EXT4_ACL_NOT_CACHED; | ||
748 | } | ||
749 | #endif | ||
750 | ext4_discard_preallocations(inode); | 734 | ext4_discard_preallocations(inode); |
751 | if (EXT4_JOURNAL(inode)) | 735 | if (EXT4_JOURNAL(inode)) |
752 | jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal, | 736 | jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal, |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index caf049146ca2..c54226be5294 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -278,7 +278,26 @@ int sb_has_dirty_inodes(struct super_block *sb) | |||
278 | EXPORT_SYMBOL(sb_has_dirty_inodes); | 278 | EXPORT_SYMBOL(sb_has_dirty_inodes); |
279 | 279 | ||
280 | /* | 280 | /* |
281 | * Write a single inode's dirty pages and inode data out to disk. | 281 | * Wait for writeback on an inode to complete. |
282 | */ | ||
283 | static void inode_wait_for_writeback(struct inode *inode) | ||
284 | { | ||
285 | DEFINE_WAIT_BIT(wq, &inode->i_state, __I_SYNC); | ||
286 | wait_queue_head_t *wqh; | ||
287 | |||
288 | wqh = bit_waitqueue(&inode->i_state, __I_SYNC); | ||
289 | do { | ||
290 | spin_unlock(&inode_lock); | ||
291 | __wait_on_bit(wqh, &wq, inode_wait, TASK_UNINTERRUPTIBLE); | ||
292 | spin_lock(&inode_lock); | ||
293 | } while (inode->i_state & I_SYNC); | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * Write out an inode's dirty pages. Called under inode_lock. Either the | ||
298 | * caller has ref on the inode (either via __iget or via syscall against an fd) | ||
299 | * or the inode has I_WILL_FREE set (via generic_forget_inode) | ||
300 | * | ||
282 | * If `wait' is set, wait on the writeout. | 301 | * If `wait' is set, wait on the writeout. |
283 | * | 302 | * |
284 | * The whole writeout design is quite complex and fragile. We want to avoid | 303 | * The whole writeout design is quite complex and fragile. We want to avoid |
@@ -288,13 +307,38 @@ EXPORT_SYMBOL(sb_has_dirty_inodes); | |||
288 | * Called under inode_lock. | 307 | * Called under inode_lock. |
289 | */ | 308 | */ |
290 | static int | 309 | static int |
291 | __sync_single_inode(struct inode *inode, struct writeback_control *wbc) | 310 | writeback_single_inode(struct inode *inode, struct writeback_control *wbc) |
292 | { | 311 | { |
293 | unsigned dirty; | ||
294 | struct address_space *mapping = inode->i_mapping; | 312 | struct address_space *mapping = inode->i_mapping; |
295 | int wait = wbc->sync_mode == WB_SYNC_ALL; | 313 | int wait = wbc->sync_mode == WB_SYNC_ALL; |
314 | unsigned dirty; | ||
296 | int ret; | 315 | int ret; |
297 | 316 | ||
317 | if (!atomic_read(&inode->i_count)) | ||
318 | WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING))); | ||
319 | else | ||
320 | WARN_ON(inode->i_state & I_WILL_FREE); | ||
321 | |||
322 | if (inode->i_state & I_SYNC) { | ||
323 | /* | ||
324 | * If this inode is locked for writeback and we are not doing | ||
325 | * writeback-for-data-integrity, move it to s_more_io so that | ||
326 | * writeback can proceed with the other inodes on s_io. | ||
327 | * | ||
328 | * We'll have another go at writing back this inode when we | ||
329 | * completed a full scan of s_io. | ||
330 | */ | ||
331 | if (!wait) { | ||
332 | requeue_io(inode); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | /* | ||
337 | * It's a data-integrity sync. We must wait. | ||
338 | */ | ||
339 | inode_wait_for_writeback(inode); | ||
340 | } | ||
341 | |||
298 | BUG_ON(inode->i_state & I_SYNC); | 342 | BUG_ON(inode->i_state & I_SYNC); |
299 | 343 | ||
300 | /* Set I_SYNC, reset I_DIRTY */ | 344 | /* Set I_SYNC, reset I_DIRTY */ |
@@ -390,50 +434,6 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
390 | } | 434 | } |
391 | 435 | ||
392 | /* | 436 | /* |
393 | * Write out an inode's dirty pages. Called under inode_lock. Either the | ||
394 | * caller has ref on the inode (either via __iget or via syscall against an fd) | ||
395 | * or the inode has I_WILL_FREE set (via generic_forget_inode) | ||
396 | */ | ||
397 | static int | ||
398 | __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | ||
399 | { | ||
400 | wait_queue_head_t *wqh; | ||
401 | |||
402 | if (!atomic_read(&inode->i_count)) | ||
403 | WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING))); | ||
404 | else | ||
405 | WARN_ON(inode->i_state & I_WILL_FREE); | ||
406 | |||
407 | if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_SYNC)) { | ||
408 | /* | ||
409 | * We're skipping this inode because it's locked, and we're not | ||
410 | * doing writeback-for-data-integrity. Move it to s_more_io so | ||
411 | * that writeback can proceed with the other inodes on s_io. | ||
412 | * We'll have another go at writing back this inode when we | ||
413 | * completed a full scan of s_io. | ||
414 | */ | ||
415 | requeue_io(inode); | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | /* | ||
420 | * It's a data-integrity sync. We must wait. | ||
421 | */ | ||
422 | if (inode->i_state & I_SYNC) { | ||
423 | DEFINE_WAIT_BIT(wq, &inode->i_state, __I_SYNC); | ||
424 | |||
425 | wqh = bit_waitqueue(&inode->i_state, __I_SYNC); | ||
426 | do { | ||
427 | spin_unlock(&inode_lock); | ||
428 | __wait_on_bit(wqh, &wq, inode_wait, | ||
429 | TASK_UNINTERRUPTIBLE); | ||
430 | spin_lock(&inode_lock); | ||
431 | } while (inode->i_state & I_SYNC); | ||
432 | } | ||
433 | return __sync_single_inode(inode, wbc); | ||
434 | } | ||
435 | |||
436 | /* | ||
437 | * Write out a superblock's list of dirty inodes. A wait will be performed | 437 | * Write out a superblock's list of dirty inodes. A wait will be performed |
438 | * upon no inodes, all inodes or the final one, depending upon sync_mode. | 438 | * upon no inodes, all inodes or the final one, depending upon sync_mode. |
439 | * | 439 | * |
@@ -526,7 +526,7 @@ void generic_sync_sb_inodes(struct super_block *sb, | |||
526 | BUG_ON(inode->i_state & (I_FREEING | I_CLEAR)); | 526 | BUG_ON(inode->i_state & (I_FREEING | I_CLEAR)); |
527 | __iget(inode); | 527 | __iget(inode); |
528 | pages_skipped = wbc->pages_skipped; | 528 | pages_skipped = wbc->pages_skipped; |
529 | __writeback_single_inode(inode, wbc); | 529 | writeback_single_inode(inode, wbc); |
530 | if (current_is_pdflush()) | 530 | if (current_is_pdflush()) |
531 | writeback_release(bdi); | 531 | writeback_release(bdi); |
532 | if (wbc->pages_skipped != pages_skipped) { | 532 | if (wbc->pages_skipped != pages_skipped) { |
@@ -708,7 +708,7 @@ int write_inode_now(struct inode *inode, int sync) | |||
708 | 708 | ||
709 | might_sleep(); | 709 | might_sleep(); |
710 | spin_lock(&inode_lock); | 710 | spin_lock(&inode_lock); |
711 | ret = __writeback_single_inode(inode, &wbc); | 711 | ret = writeback_single_inode(inode, &wbc); |
712 | spin_unlock(&inode_lock); | 712 | spin_unlock(&inode_lock); |
713 | if (sync) | 713 | if (sync) |
714 | inode_sync_wait(inode); | 714 | inode_sync_wait(inode); |
@@ -732,7 +732,7 @@ int sync_inode(struct inode *inode, struct writeback_control *wbc) | |||
732 | int ret; | 732 | int ret; |
733 | 733 | ||
734 | spin_lock(&inode_lock); | 734 | spin_lock(&inode_lock); |
735 | ret = __writeback_single_inode(inode, wbc); | 735 | ret = writeback_single_inode(inode, wbc); |
736 | spin_unlock(&inode_lock); | 736 | spin_unlock(&inode_lock); |
737 | return ret; | 737 | return ret; |
738 | } | 738 | } |
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 8fed2ed12f38..f58ecbc416c8 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -849,6 +849,81 @@ err: | |||
849 | return err; | 849 | return err; |
850 | } | 850 | } |
851 | 851 | ||
852 | static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size, | ||
853 | struct fuse_copy_state *cs) | ||
854 | { | ||
855 | struct fuse_notify_inval_inode_out outarg; | ||
856 | int err = -EINVAL; | ||
857 | |||
858 | if (size != sizeof(outarg)) | ||
859 | goto err; | ||
860 | |||
861 | err = fuse_copy_one(cs, &outarg, sizeof(outarg)); | ||
862 | if (err) | ||
863 | goto err; | ||
864 | fuse_copy_finish(cs); | ||
865 | |||
866 | down_read(&fc->killsb); | ||
867 | err = -ENOENT; | ||
868 | if (!fc->sb) | ||
869 | goto err_unlock; | ||
870 | |||
871 | err = fuse_reverse_inval_inode(fc->sb, outarg.ino, | ||
872 | outarg.off, outarg.len); | ||
873 | |||
874 | err_unlock: | ||
875 | up_read(&fc->killsb); | ||
876 | return err; | ||
877 | |||
878 | err: | ||
879 | fuse_copy_finish(cs); | ||
880 | return err; | ||
881 | } | ||
882 | |||
883 | static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, | ||
884 | struct fuse_copy_state *cs) | ||
885 | { | ||
886 | struct fuse_notify_inval_entry_out outarg; | ||
887 | int err = -EINVAL; | ||
888 | char buf[FUSE_NAME_MAX+1]; | ||
889 | struct qstr name; | ||
890 | |||
891 | if (size < sizeof(outarg)) | ||
892 | goto err; | ||
893 | |||
894 | err = fuse_copy_one(cs, &outarg, sizeof(outarg)); | ||
895 | if (err) | ||
896 | goto err; | ||
897 | |||
898 | err = -ENAMETOOLONG; | ||
899 | if (outarg.namelen > FUSE_NAME_MAX) | ||
900 | goto err; | ||
901 | |||
902 | name.name = buf; | ||
903 | name.len = outarg.namelen; | ||
904 | err = fuse_copy_one(cs, buf, outarg.namelen + 1); | ||
905 | if (err) | ||
906 | goto err; | ||
907 | fuse_copy_finish(cs); | ||
908 | buf[outarg.namelen] = 0; | ||
909 | name.hash = full_name_hash(name.name, name.len); | ||
910 | |||
911 | down_read(&fc->killsb); | ||
912 | err = -ENOENT; | ||
913 | if (!fc->sb) | ||
914 | goto err_unlock; | ||
915 | |||
916 | err = fuse_reverse_inval_entry(fc->sb, outarg.parent, &name); | ||
917 | |||
918 | err_unlock: | ||
919 | up_read(&fc->killsb); | ||
920 | return err; | ||
921 | |||
922 | err: | ||
923 | fuse_copy_finish(cs); | ||
924 | return err; | ||
925 | } | ||
926 | |||
852 | static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, | 927 | static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, |
853 | unsigned int size, struct fuse_copy_state *cs) | 928 | unsigned int size, struct fuse_copy_state *cs) |
854 | { | 929 | { |
@@ -856,6 +931,12 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, | |||
856 | case FUSE_NOTIFY_POLL: | 931 | case FUSE_NOTIFY_POLL: |
857 | return fuse_notify_poll(fc, size, cs); | 932 | return fuse_notify_poll(fc, size, cs); |
858 | 933 | ||
934 | case FUSE_NOTIFY_INVAL_INODE: | ||
935 | return fuse_notify_inval_inode(fc, size, cs); | ||
936 | |||
937 | case FUSE_NOTIFY_INVAL_ENTRY: | ||
938 | return fuse_notify_inval_entry(fc, size, cs); | ||
939 | |||
859 | default: | 940 | default: |
860 | fuse_copy_finish(cs); | 941 | fuse_copy_finish(cs); |
861 | return -EINVAL; | 942 | return -EINVAL; |
@@ -910,7 +991,7 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov, | |||
910 | unsigned long nr_segs, loff_t pos) | 991 | unsigned long nr_segs, loff_t pos) |
911 | { | 992 | { |
912 | int err; | 993 | int err; |
913 | unsigned nbytes = iov_length(iov, nr_segs); | 994 | size_t nbytes = iov_length(iov, nr_segs); |
914 | struct fuse_req *req; | 995 | struct fuse_req *req; |
915 | struct fuse_out_header oh; | 996 | struct fuse_out_header oh; |
916 | struct fuse_copy_state cs; | 997 | struct fuse_copy_state cs; |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index b3089a083d30..e703654e7f40 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -375,7 +375,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
375 | struct fuse_conn *fc = get_fuse_conn(dir); | 375 | struct fuse_conn *fc = get_fuse_conn(dir); |
376 | struct fuse_req *req; | 376 | struct fuse_req *req; |
377 | struct fuse_req *forget_req; | 377 | struct fuse_req *forget_req; |
378 | struct fuse_open_in inarg; | 378 | struct fuse_create_in inarg; |
379 | struct fuse_open_out outopen; | 379 | struct fuse_open_out outopen; |
380 | struct fuse_entry_out outentry; | 380 | struct fuse_entry_out outentry; |
381 | struct fuse_file *ff; | 381 | struct fuse_file *ff; |
@@ -399,15 +399,20 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
399 | if (!ff) | 399 | if (!ff) |
400 | goto out_put_request; | 400 | goto out_put_request; |
401 | 401 | ||
402 | if (!fc->dont_mask) | ||
403 | mode &= ~current_umask(); | ||
404 | |||
402 | flags &= ~O_NOCTTY; | 405 | flags &= ~O_NOCTTY; |
403 | memset(&inarg, 0, sizeof(inarg)); | 406 | memset(&inarg, 0, sizeof(inarg)); |
404 | memset(&outentry, 0, sizeof(outentry)); | 407 | memset(&outentry, 0, sizeof(outentry)); |
405 | inarg.flags = flags; | 408 | inarg.flags = flags; |
406 | inarg.mode = mode; | 409 | inarg.mode = mode; |
410 | inarg.umask = current_umask(); | ||
407 | req->in.h.opcode = FUSE_CREATE; | 411 | req->in.h.opcode = FUSE_CREATE; |
408 | req->in.h.nodeid = get_node_id(dir); | 412 | req->in.h.nodeid = get_node_id(dir); |
409 | req->in.numargs = 2; | 413 | req->in.numargs = 2; |
410 | req->in.args[0].size = sizeof(inarg); | 414 | req->in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) : |
415 | sizeof(inarg); | ||
411 | req->in.args[0].value = &inarg; | 416 | req->in.args[0].value = &inarg; |
412 | req->in.args[1].size = entry->d_name.len + 1; | 417 | req->in.args[1].size = entry->d_name.len + 1; |
413 | req->in.args[1].value = entry->d_name.name; | 418 | req->in.args[1].value = entry->d_name.name; |
@@ -546,12 +551,17 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, | |||
546 | if (IS_ERR(req)) | 551 | if (IS_ERR(req)) |
547 | return PTR_ERR(req); | 552 | return PTR_ERR(req); |
548 | 553 | ||
554 | if (!fc->dont_mask) | ||
555 | mode &= ~current_umask(); | ||
556 | |||
549 | memset(&inarg, 0, sizeof(inarg)); | 557 | memset(&inarg, 0, sizeof(inarg)); |
550 | inarg.mode = mode; | 558 | inarg.mode = mode; |
551 | inarg.rdev = new_encode_dev(rdev); | 559 | inarg.rdev = new_encode_dev(rdev); |
560 | inarg.umask = current_umask(); | ||
552 | req->in.h.opcode = FUSE_MKNOD; | 561 | req->in.h.opcode = FUSE_MKNOD; |
553 | req->in.numargs = 2; | 562 | req->in.numargs = 2; |
554 | req->in.args[0].size = sizeof(inarg); | 563 | req->in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE : |
564 | sizeof(inarg); | ||
555 | req->in.args[0].value = &inarg; | 565 | req->in.args[0].value = &inarg; |
556 | req->in.args[1].size = entry->d_name.len + 1; | 566 | req->in.args[1].size = entry->d_name.len + 1; |
557 | req->in.args[1].value = entry->d_name.name; | 567 | req->in.args[1].value = entry->d_name.name; |
@@ -578,8 +588,12 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) | |||
578 | if (IS_ERR(req)) | 588 | if (IS_ERR(req)) |
579 | return PTR_ERR(req); | 589 | return PTR_ERR(req); |
580 | 590 | ||
591 | if (!fc->dont_mask) | ||
592 | mode &= ~current_umask(); | ||
593 | |||
581 | memset(&inarg, 0, sizeof(inarg)); | 594 | memset(&inarg, 0, sizeof(inarg)); |
582 | inarg.mode = mode; | 595 | inarg.mode = mode; |
596 | inarg.umask = current_umask(); | ||
583 | req->in.h.opcode = FUSE_MKDIR; | 597 | req->in.h.opcode = FUSE_MKDIR; |
584 | req->in.numargs = 2; | 598 | req->in.numargs = 2; |
585 | req->in.args[0].size = sizeof(inarg); | 599 | req->in.args[0].size = sizeof(inarg); |
@@ -845,6 +859,43 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat, | |||
845 | return err; | 859 | return err; |
846 | } | 860 | } |
847 | 861 | ||
862 | int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, | ||
863 | struct qstr *name) | ||
864 | { | ||
865 | int err = -ENOTDIR; | ||
866 | struct inode *parent; | ||
867 | struct dentry *dir; | ||
868 | struct dentry *entry; | ||
869 | |||
870 | parent = ilookup5(sb, parent_nodeid, fuse_inode_eq, &parent_nodeid); | ||
871 | if (!parent) | ||
872 | return -ENOENT; | ||
873 | |||
874 | mutex_lock(&parent->i_mutex); | ||
875 | if (!S_ISDIR(parent->i_mode)) | ||
876 | goto unlock; | ||
877 | |||
878 | err = -ENOENT; | ||
879 | dir = d_find_alias(parent); | ||
880 | if (!dir) | ||
881 | goto unlock; | ||
882 | |||
883 | entry = d_lookup(dir, name); | ||
884 | dput(dir); | ||
885 | if (!entry) | ||
886 | goto unlock; | ||
887 | |||
888 | fuse_invalidate_attr(parent); | ||
889 | fuse_invalidate_entry(entry); | ||
890 | dput(entry); | ||
891 | err = 0; | ||
892 | |||
893 | unlock: | ||
894 | mutex_unlock(&parent->i_mutex); | ||
895 | iput(parent); | ||
896 | return err; | ||
897 | } | ||
898 | |||
848 | /* | 899 | /* |
849 | * Calling into a user-controlled filesystem gives the filesystem | 900 | * Calling into a user-controlled filesystem gives the filesystem |
850 | * daemon ptrace-like capabilities over the requester process. This | 901 | * daemon ptrace-like capabilities over the requester process. This |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index fce6ce694fde..cbc464043b6f 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -1922,7 +1922,7 @@ unsigned fuse_file_poll(struct file *file, poll_table *wait) | |||
1922 | 1922 | ||
1923 | req = fuse_get_req(fc); | 1923 | req = fuse_get_req(fc); |
1924 | if (IS_ERR(req)) | 1924 | if (IS_ERR(req)) |
1925 | return PTR_ERR(req); | 1925 | return POLLERR; |
1926 | 1926 | ||
1927 | req->in.h.opcode = FUSE_POLL; | 1927 | req->in.h.opcode = FUSE_POLL; |
1928 | req->in.h.nodeid = ff->nodeid; | 1928 | req->in.h.nodeid = ff->nodeid; |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index aaf2f9ff970e..52b641fc0faf 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -446,6 +446,9 @@ struct fuse_conn { | |||
446 | /** Do multi-page cached writes */ | 446 | /** Do multi-page cached writes */ |
447 | unsigned big_writes:1; | 447 | unsigned big_writes:1; |
448 | 448 | ||
449 | /** Don't apply umask to creation modes */ | ||
450 | unsigned dont_mask:1; | ||
451 | |||
449 | /** The number of requests waiting for completion */ | 452 | /** The number of requests waiting for completion */ |
450 | atomic_t num_waiting; | 453 | atomic_t num_waiting; |
451 | 454 | ||
@@ -481,6 +484,12 @@ struct fuse_conn { | |||
481 | 484 | ||
482 | /** Called on final put */ | 485 | /** Called on final put */ |
483 | void (*release)(struct fuse_conn *); | 486 | void (*release)(struct fuse_conn *); |
487 | |||
488 | /** Super block for this connection. */ | ||
489 | struct super_block *sb; | ||
490 | |||
491 | /** Read/write semaphore to hold when accessing sb. */ | ||
492 | struct rw_semaphore killsb; | ||
484 | }; | 493 | }; |
485 | 494 | ||
486 | static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) | 495 | static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) |
@@ -509,6 +518,11 @@ extern const struct file_operations fuse_dev_operations; | |||
509 | extern const struct dentry_operations fuse_dentry_operations; | 518 | extern const struct dentry_operations fuse_dentry_operations; |
510 | 519 | ||
511 | /** | 520 | /** |
521 | * Inode to nodeid comparison. | ||
522 | */ | ||
523 | int fuse_inode_eq(struct inode *inode, void *_nodeidp); | ||
524 | |||
525 | /** | ||
512 | * Get a filled in inode | 526 | * Get a filled in inode |
513 | */ | 527 | */ |
514 | struct inode *fuse_iget(struct super_block *sb, u64 nodeid, | 528 | struct inode *fuse_iget(struct super_block *sb, u64 nodeid, |
@@ -708,6 +722,19 @@ void fuse_release_nowrite(struct inode *inode); | |||
708 | 722 | ||
709 | u64 fuse_get_attr_version(struct fuse_conn *fc); | 723 | u64 fuse_get_attr_version(struct fuse_conn *fc); |
710 | 724 | ||
725 | /** | ||
726 | * File-system tells the kernel to invalidate cache for the given node id. | ||
727 | */ | ||
728 | int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid, | ||
729 | loff_t offset, loff_t len); | ||
730 | |||
731 | /** | ||
732 | * File-system tells the kernel to invalidate parent attributes and | ||
733 | * the dentry matching parent/name. | ||
734 | */ | ||
735 | int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, | ||
736 | struct qstr *name); | ||
737 | |||
711 | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | 738 | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, |
712 | bool isdir); | 739 | bool isdir); |
713 | ssize_t fuse_direct_io(struct file *file, const char __user *buf, | 740 | ssize_t fuse_direct_io(struct file *file, const char __user *buf, |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index d8673ccf90b7..f91ccc4a189d 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -206,7 +206,7 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) | |||
206 | BUG(); | 206 | BUG(); |
207 | } | 207 | } |
208 | 208 | ||
209 | static int fuse_inode_eq(struct inode *inode, void *_nodeidp) | 209 | int fuse_inode_eq(struct inode *inode, void *_nodeidp) |
210 | { | 210 | { |
211 | u64 nodeid = *(u64 *) _nodeidp; | 211 | u64 nodeid = *(u64 *) _nodeidp; |
212 | if (get_node_id(inode) == nodeid) | 212 | if (get_node_id(inode) == nodeid) |
@@ -257,6 +257,31 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, | |||
257 | return inode; | 257 | return inode; |
258 | } | 258 | } |
259 | 259 | ||
260 | int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid, | ||
261 | loff_t offset, loff_t len) | ||
262 | { | ||
263 | struct inode *inode; | ||
264 | pgoff_t pg_start; | ||
265 | pgoff_t pg_end; | ||
266 | |||
267 | inode = ilookup5(sb, nodeid, fuse_inode_eq, &nodeid); | ||
268 | if (!inode) | ||
269 | return -ENOENT; | ||
270 | |||
271 | fuse_invalidate_attr(inode); | ||
272 | if (offset >= 0) { | ||
273 | pg_start = offset >> PAGE_CACHE_SHIFT; | ||
274 | if (len <= 0) | ||
275 | pg_end = -1; | ||
276 | else | ||
277 | pg_end = (offset + len - 1) >> PAGE_CACHE_SHIFT; | ||
278 | invalidate_inode_pages2_range(inode->i_mapping, | ||
279 | pg_start, pg_end); | ||
280 | } | ||
281 | iput(inode); | ||
282 | return 0; | ||
283 | } | ||
284 | |||
260 | static void fuse_umount_begin(struct super_block *sb) | 285 | static void fuse_umount_begin(struct super_block *sb) |
261 | { | 286 | { |
262 | fuse_abort_conn(get_fuse_conn_super(sb)); | 287 | fuse_abort_conn(get_fuse_conn_super(sb)); |
@@ -480,6 +505,7 @@ void fuse_conn_init(struct fuse_conn *fc) | |||
480 | memset(fc, 0, sizeof(*fc)); | 505 | memset(fc, 0, sizeof(*fc)); |
481 | spin_lock_init(&fc->lock); | 506 | spin_lock_init(&fc->lock); |
482 | mutex_init(&fc->inst_mutex); | 507 | mutex_init(&fc->inst_mutex); |
508 | init_rwsem(&fc->killsb); | ||
483 | atomic_set(&fc->count, 1); | 509 | atomic_set(&fc->count, 1); |
484 | init_waitqueue_head(&fc->waitq); | 510 | init_waitqueue_head(&fc->waitq); |
485 | init_waitqueue_head(&fc->blocked_waitq); | 511 | init_waitqueue_head(&fc->blocked_waitq); |
@@ -725,6 +751,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
725 | } | 751 | } |
726 | if (arg->flags & FUSE_BIG_WRITES) | 752 | if (arg->flags & FUSE_BIG_WRITES) |
727 | fc->big_writes = 1; | 753 | fc->big_writes = 1; |
754 | if (arg->flags & FUSE_DONT_MASK) | ||
755 | fc->dont_mask = 1; | ||
728 | } else { | 756 | } else { |
729 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; | 757 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; |
730 | fc->no_lock = 1; | 758 | fc->no_lock = 1; |
@@ -748,7 +776,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) | |||
748 | arg->minor = FUSE_KERNEL_MINOR_VERSION; | 776 | arg->minor = FUSE_KERNEL_MINOR_VERSION; |
749 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; | 777 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; |
750 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | | 778 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | |
751 | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES; | 779 | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK; |
752 | req->in.h.opcode = FUSE_INIT; | 780 | req->in.h.opcode = FUSE_INIT; |
753 | req->in.numargs = 1; | 781 | req->in.numargs = 1; |
754 | req->in.args[0].size = sizeof(*arg); | 782 | req->in.args[0].size = sizeof(*arg); |
@@ -860,10 +888,16 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
860 | fuse_conn_init(fc); | 888 | fuse_conn_init(fc); |
861 | 889 | ||
862 | fc->dev = sb->s_dev; | 890 | fc->dev = sb->s_dev; |
891 | fc->sb = sb; | ||
863 | err = fuse_bdi_init(fc, sb); | 892 | err = fuse_bdi_init(fc, sb); |
864 | if (err) | 893 | if (err) |
865 | goto err_put_conn; | 894 | goto err_put_conn; |
866 | 895 | ||
896 | /* Handle umasking inside the fuse code */ | ||
897 | if (sb->s_flags & MS_POSIXACL) | ||
898 | fc->dont_mask = 1; | ||
899 | sb->s_flags |= MS_POSIXACL; | ||
900 | |||
867 | fc->release = fuse_free_conn; | 901 | fc->release = fuse_free_conn; |
868 | fc->flags = d.flags; | 902 | fc->flags = d.flags; |
869 | fc->user_id = d.user_id; | 903 | fc->user_id = d.user_id; |
@@ -941,12 +975,25 @@ static int fuse_get_sb(struct file_system_type *fs_type, | |||
941 | return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt); | 975 | return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt); |
942 | } | 976 | } |
943 | 977 | ||
978 | static void fuse_kill_sb_anon(struct super_block *sb) | ||
979 | { | ||
980 | struct fuse_conn *fc = get_fuse_conn_super(sb); | ||
981 | |||
982 | if (fc) { | ||
983 | down_write(&fc->killsb); | ||
984 | fc->sb = NULL; | ||
985 | up_write(&fc->killsb); | ||
986 | } | ||
987 | |||
988 | kill_anon_super(sb); | ||
989 | } | ||
990 | |||
944 | static struct file_system_type fuse_fs_type = { | 991 | static struct file_system_type fuse_fs_type = { |
945 | .owner = THIS_MODULE, | 992 | .owner = THIS_MODULE, |
946 | .name = "fuse", | 993 | .name = "fuse", |
947 | .fs_flags = FS_HAS_SUBTYPE, | 994 | .fs_flags = FS_HAS_SUBTYPE, |
948 | .get_sb = fuse_get_sb, | 995 | .get_sb = fuse_get_sb, |
949 | .kill_sb = kill_anon_super, | 996 | .kill_sb = fuse_kill_sb_anon, |
950 | }; | 997 | }; |
951 | 998 | ||
952 | #ifdef CONFIG_BLOCK | 999 | #ifdef CONFIG_BLOCK |
@@ -958,11 +1005,24 @@ static int fuse_get_sb_blk(struct file_system_type *fs_type, | |||
958 | mnt); | 1005 | mnt); |
959 | } | 1006 | } |
960 | 1007 | ||
1008 | static void fuse_kill_sb_blk(struct super_block *sb) | ||
1009 | { | ||
1010 | struct fuse_conn *fc = get_fuse_conn_super(sb); | ||
1011 | |||
1012 | if (fc) { | ||
1013 | down_write(&fc->killsb); | ||
1014 | fc->sb = NULL; | ||
1015 | up_write(&fc->killsb); | ||
1016 | } | ||
1017 | |||
1018 | kill_block_super(sb); | ||
1019 | } | ||
1020 | |||
961 | static struct file_system_type fuseblk_fs_type = { | 1021 | static struct file_system_type fuseblk_fs_type = { |
962 | .owner = THIS_MODULE, | 1022 | .owner = THIS_MODULE, |
963 | .name = "fuseblk", | 1023 | .name = "fuseblk", |
964 | .get_sb = fuse_get_sb_blk, | 1024 | .get_sb = fuse_get_sb_blk, |
965 | .kill_sb = kill_block_super, | 1025 | .kill_sb = fuse_kill_sb_blk, |
966 | .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE, | 1026 | .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE, |
967 | }; | 1027 | }; |
968 | 1028 | ||
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index fe02ad4740e7..032604e5ef2c 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c | |||
@@ -972,6 +972,7 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) | |||
972 | sb->s_blocksize_bits = 10; | 972 | sb->s_blocksize_bits = 10; |
973 | sb->s_magic = HOSTFS_SUPER_MAGIC; | 973 | sb->s_magic = HOSTFS_SUPER_MAGIC; |
974 | sb->s_op = &hostfs_sbops; | 974 | sb->s_op = &hostfs_sbops; |
975 | sb->s_maxbytes = MAX_LFS_FILESIZE; | ||
975 | 976 | ||
976 | /* NULL is printed as <NULL> by sprintf: avoid that. */ | 977 | /* NULL is printed as <NULL> by sprintf: avoid that. */ |
977 | if (req_root == NULL) | 978 | if (req_root == NULL) |
diff --git a/fs/inode.c b/fs/inode.c index f643be565df8..901bad1e5f12 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/fsnotify.h> | 25 | #include <linux/fsnotify.h> |
26 | #include <linux/mount.h> | 26 | #include <linux/mount.h> |
27 | #include <linux/async.h> | 27 | #include <linux/async.h> |
28 | #include <linux/posix_acl.h> | ||
28 | 29 | ||
29 | /* | 30 | /* |
30 | * This is needed for the following functions: | 31 | * This is needed for the following functions: |
@@ -189,6 +190,9 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode) | |||
189 | } | 190 | } |
190 | inode->i_private = NULL; | 191 | inode->i_private = NULL; |
191 | inode->i_mapping = mapping; | 192 | inode->i_mapping = mapping; |
193 | #ifdef CONFIG_FS_POSIX_ACL | ||
194 | inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED; | ||
195 | #endif | ||
192 | 196 | ||
193 | #ifdef CONFIG_FSNOTIFY | 197 | #ifdef CONFIG_FSNOTIFY |
194 | inode->i_fsnotify_mask = 0; | 198 | inode->i_fsnotify_mask = 0; |
@@ -227,6 +231,12 @@ void destroy_inode(struct inode *inode) | |||
227 | ima_inode_free(inode); | 231 | ima_inode_free(inode); |
228 | security_inode_free(inode); | 232 | security_inode_free(inode); |
229 | fsnotify_inode_delete(inode); | 233 | fsnotify_inode_delete(inode); |
234 | #ifdef CONFIG_FS_POSIX_ACL | ||
235 | if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED) | ||
236 | posix_acl_release(inode->i_acl); | ||
237 | if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED) | ||
238 | posix_acl_release(inode->i_default_acl); | ||
239 | #endif | ||
230 | if (inode->i_sb->s_op->destroy_inode) | 240 | if (inode->i_sb->s_op->destroy_inode) |
231 | inode->i_sb->s_op->destroy_inode(inode); | 241 | inode->i_sb->s_op->destroy_inode(inode); |
232 | else | 242 | else |
@@ -665,12 +675,17 @@ void unlock_new_inode(struct inode *inode) | |||
665 | if (inode->i_mode & S_IFDIR) { | 675 | if (inode->i_mode & S_IFDIR) { |
666 | struct file_system_type *type = inode->i_sb->s_type; | 676 | struct file_system_type *type = inode->i_sb->s_type; |
667 | 677 | ||
668 | /* | 678 | /* Set new key only if filesystem hasn't already changed it */ |
669 | * ensure nobody is actually holding i_mutex | 679 | if (!lockdep_match_class(&inode->i_mutex, |
670 | */ | 680 | &type->i_mutex_key)) { |
671 | mutex_destroy(&inode->i_mutex); | 681 | /* |
672 | mutex_init(&inode->i_mutex); | 682 | * ensure nobody is actually holding i_mutex |
673 | lockdep_set_class(&inode->i_mutex, &type->i_mutex_dir_key); | 683 | */ |
684 | mutex_destroy(&inode->i_mutex); | ||
685 | mutex_init(&inode->i_mutex); | ||
686 | lockdep_set_class(&inode->i_mutex, | ||
687 | &type->i_mutex_dir_key); | ||
688 | } | ||
674 | } | 689 | } |
675 | #endif | 690 | #endif |
676 | /* | 691 | /* |
diff --git a/fs/ioctl.c b/fs/ioctl.c index 001f8d3118f2..5612880fcbe7 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/uaccess.h> | 15 | #include <linux/uaccess.h> |
16 | #include <linux/writeback.h> | 16 | #include <linux/writeback.h> |
17 | #include <linux/buffer_head.h> | 17 | #include <linux/buffer_head.h> |
18 | #include <linux/falloc.h> | ||
18 | 19 | ||
19 | #include <asm/ioctls.h> | 20 | #include <asm/ioctls.h> |
20 | 21 | ||
@@ -403,6 +404,37 @@ EXPORT_SYMBOL(generic_block_fiemap); | |||
403 | 404 | ||
404 | #endif /* CONFIG_BLOCK */ | 405 | #endif /* CONFIG_BLOCK */ |
405 | 406 | ||
407 | /* | ||
408 | * This provides compatibility with legacy XFS pre-allocation ioctls | ||
409 | * which predate the fallocate syscall. | ||
410 | * | ||
411 | * Only the l_start, l_len and l_whence fields of the 'struct space_resv' | ||
412 | * are used here, rest are ignored. | ||
413 | */ | ||
414 | int ioctl_preallocate(struct file *filp, void __user *argp) | ||
415 | { | ||
416 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
417 | struct space_resv sr; | ||
418 | |||
419 | if (copy_from_user(&sr, argp, sizeof(sr))) | ||
420 | return -EFAULT; | ||
421 | |||
422 | switch (sr.l_whence) { | ||
423 | case SEEK_SET: | ||
424 | break; | ||
425 | case SEEK_CUR: | ||
426 | sr.l_start += filp->f_pos; | ||
427 | break; | ||
428 | case SEEK_END: | ||
429 | sr.l_start += i_size_read(inode); | ||
430 | break; | ||
431 | default: | ||
432 | return -EINVAL; | ||
433 | } | ||
434 | |||
435 | return do_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len); | ||
436 | } | ||
437 | |||
406 | static int file_ioctl(struct file *filp, unsigned int cmd, | 438 | static int file_ioctl(struct file *filp, unsigned int cmd, |
407 | unsigned long arg) | 439 | unsigned long arg) |
408 | { | 440 | { |
@@ -414,6 +446,9 @@ static int file_ioctl(struct file *filp, unsigned int cmd, | |||
414 | return ioctl_fibmap(filp, p); | 446 | return ioctl_fibmap(filp, p); |
415 | case FIONREAD: | 447 | case FIONREAD: |
416 | return put_user(i_size_read(inode) - filp->f_pos, p); | 448 | return put_user(i_size_read(inode) - filp->f_pos, p); |
449 | case FS_IOC_RESVSP: | ||
450 | case FS_IOC_RESVSP64: | ||
451 | return ioctl_preallocate(filp, p); | ||
417 | } | 452 | } |
418 | 453 | ||
419 | return vfs_ioctl(filp, cmd, arg); | 454 | return vfs_ioctl(filp, cmd, arg); |
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 043740dde20c..8fcb6239218e 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c | |||
@@ -156,48 +156,25 @@ static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size) | |||
156 | return ERR_PTR(-EINVAL); | 156 | return ERR_PTR(-EINVAL); |
157 | } | 157 | } |
158 | 158 | ||
159 | static struct posix_acl *jffs2_iget_acl(struct inode *inode, struct posix_acl **i_acl) | ||
160 | { | ||
161 | struct posix_acl *acl = JFFS2_ACL_NOT_CACHED; | ||
162 | |||
163 | spin_lock(&inode->i_lock); | ||
164 | if (*i_acl != JFFS2_ACL_NOT_CACHED) | ||
165 | acl = posix_acl_dup(*i_acl); | ||
166 | spin_unlock(&inode->i_lock); | ||
167 | return acl; | ||
168 | } | ||
169 | |||
170 | static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct posix_acl *acl) | ||
171 | { | ||
172 | spin_lock(&inode->i_lock); | ||
173 | if (*i_acl != JFFS2_ACL_NOT_CACHED) | ||
174 | posix_acl_release(*i_acl); | ||
175 | *i_acl = posix_acl_dup(acl); | ||
176 | spin_unlock(&inode->i_lock); | ||
177 | } | ||
178 | |||
179 | static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) | 159 | static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) |
180 | { | 160 | { |
181 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | ||
182 | struct posix_acl *acl; | 161 | struct posix_acl *acl; |
183 | char *value = NULL; | 162 | char *value = NULL; |
184 | int rc, xprefix; | 163 | int rc, xprefix; |
185 | 164 | ||
165 | acl = get_cached_acl(inode, type); | ||
166 | if (acl != ACL_NOT_CACHED) | ||
167 | return acl; | ||
168 | |||
186 | switch (type) { | 169 | switch (type) { |
187 | case ACL_TYPE_ACCESS: | 170 | case ACL_TYPE_ACCESS: |
188 | acl = jffs2_iget_acl(inode, &f->i_acl_access); | ||
189 | if (acl != JFFS2_ACL_NOT_CACHED) | ||
190 | return acl; | ||
191 | xprefix = JFFS2_XPREFIX_ACL_ACCESS; | 171 | xprefix = JFFS2_XPREFIX_ACL_ACCESS; |
192 | break; | 172 | break; |
193 | case ACL_TYPE_DEFAULT: | 173 | case ACL_TYPE_DEFAULT: |
194 | acl = jffs2_iget_acl(inode, &f->i_acl_default); | ||
195 | if (acl != JFFS2_ACL_NOT_CACHED) | ||
196 | return acl; | ||
197 | xprefix = JFFS2_XPREFIX_ACL_DEFAULT; | 174 | xprefix = JFFS2_XPREFIX_ACL_DEFAULT; |
198 | break; | 175 | break; |
199 | default: | 176 | default: |
200 | return ERR_PTR(-EINVAL); | 177 | BUG(); |
201 | } | 178 | } |
202 | rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0); | 179 | rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0); |
203 | if (rc > 0) { | 180 | if (rc > 0) { |
@@ -215,16 +192,8 @@ static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) | |||
215 | } | 192 | } |
216 | if (value) | 193 | if (value) |
217 | kfree(value); | 194 | kfree(value); |
218 | if (!IS_ERR(acl)) { | 195 | if (!IS_ERR(acl)) |
219 | switch (type) { | 196 | set_cached_acl(inode, type, acl); |
220 | case ACL_TYPE_ACCESS: | ||
221 | jffs2_iset_acl(inode, &f->i_acl_access, acl); | ||
222 | break; | ||
223 | case ACL_TYPE_DEFAULT: | ||
224 | jffs2_iset_acl(inode, &f->i_acl_default, acl); | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | return acl; | 197 | return acl; |
229 | } | 198 | } |
230 | 199 | ||
@@ -249,7 +218,6 @@ static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *a | |||
249 | 218 | ||
250 | static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | 219 | static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) |
251 | { | 220 | { |
252 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | ||
253 | int rc, xprefix; | 221 | int rc, xprefix; |
254 | 222 | ||
255 | if (S_ISLNK(inode->i_mode)) | 223 | if (S_ISLNK(inode->i_mode)) |
@@ -285,16 +253,8 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
285 | return -EINVAL; | 253 | return -EINVAL; |
286 | } | 254 | } |
287 | rc = __jffs2_set_acl(inode, xprefix, acl); | 255 | rc = __jffs2_set_acl(inode, xprefix, acl); |
288 | if (!rc) { | 256 | if (!rc) |
289 | switch(type) { | 257 | set_cached_acl(inode, type, acl); |
290 | case ACL_TYPE_ACCESS: | ||
291 | jffs2_iset_acl(inode, &f->i_acl_access, acl); | ||
292 | break; | ||
293 | case ACL_TYPE_DEFAULT: | ||
294 | jffs2_iset_acl(inode, &f->i_acl_default, acl); | ||
295 | break; | ||
296 | } | ||
297 | } | ||
298 | return rc; | 258 | return rc; |
299 | } | 259 | } |
300 | 260 | ||
@@ -321,12 +281,10 @@ int jffs2_permission(struct inode *inode, int mask) | |||
321 | 281 | ||
322 | int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) | 282 | int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) |
323 | { | 283 | { |
324 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | ||
325 | struct posix_acl *acl, *clone; | 284 | struct posix_acl *acl, *clone; |
326 | int rc; | 285 | int rc; |
327 | 286 | ||
328 | f->i_acl_default = NULL; | 287 | cache_no_acl(inode); |
329 | f->i_acl_access = NULL; | ||
330 | 288 | ||
331 | if (S_ISLNK(*i_mode)) | 289 | if (S_ISLNK(*i_mode)) |
332 | return 0; /* Symlink always has no-ACL */ | 290 | return 0; /* Symlink always has no-ACL */ |
@@ -339,7 +297,7 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) | |||
339 | *i_mode &= ~current_umask(); | 297 | *i_mode &= ~current_umask(); |
340 | } else { | 298 | } else { |
341 | if (S_ISDIR(*i_mode)) | 299 | if (S_ISDIR(*i_mode)) |
342 | jffs2_iset_acl(inode, &f->i_acl_default, acl); | 300 | set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); |
343 | 301 | ||
344 | clone = posix_acl_clone(acl, GFP_KERNEL); | 302 | clone = posix_acl_clone(acl, GFP_KERNEL); |
345 | if (!clone) | 303 | if (!clone) |
@@ -350,7 +308,7 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) | |||
350 | return rc; | 308 | return rc; |
351 | } | 309 | } |
352 | if (rc > 0) | 310 | if (rc > 0) |
353 | jffs2_iset_acl(inode, &f->i_acl_access, clone); | 311 | set_cached_acl(inode, ACL_TYPE_ACCESS, clone); |
354 | 312 | ||
355 | posix_acl_release(clone); | 313 | posix_acl_release(clone); |
356 | } | 314 | } |
@@ -359,17 +317,16 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) | |||
359 | 317 | ||
360 | int jffs2_init_acl_post(struct inode *inode) | 318 | int jffs2_init_acl_post(struct inode *inode) |
361 | { | 319 | { |
362 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | ||
363 | int rc; | 320 | int rc; |
364 | 321 | ||
365 | if (f->i_acl_default) { | 322 | if (inode->i_default_acl) { |
366 | rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, f->i_acl_default); | 323 | rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, inode->i_default_acl); |
367 | if (rc) | 324 | if (rc) |
368 | return rc; | 325 | return rc; |
369 | } | 326 | } |
370 | 327 | ||
371 | if (f->i_acl_access) { | 328 | if (inode->i_acl) { |
372 | rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, f->i_acl_access); | 329 | rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, inode->i_acl); |
373 | if (rc) | 330 | if (rc) |
374 | return rc; | 331 | return rc; |
375 | } | 332 | } |
@@ -377,18 +334,6 @@ int jffs2_init_acl_post(struct inode *inode) | |||
377 | return 0; | 334 | return 0; |
378 | } | 335 | } |
379 | 336 | ||
380 | void jffs2_clear_acl(struct jffs2_inode_info *f) | ||
381 | { | ||
382 | if (f->i_acl_access && f->i_acl_access != JFFS2_ACL_NOT_CACHED) { | ||
383 | posix_acl_release(f->i_acl_access); | ||
384 | f->i_acl_access = JFFS2_ACL_NOT_CACHED; | ||
385 | } | ||
386 | if (f->i_acl_default && f->i_acl_default != JFFS2_ACL_NOT_CACHED) { | ||
387 | posix_acl_release(f->i_acl_default); | ||
388 | f->i_acl_default = JFFS2_ACL_NOT_CACHED; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | int jffs2_acl_chmod(struct inode *inode) | 337 | int jffs2_acl_chmod(struct inode *inode) |
393 | { | 338 | { |
394 | struct posix_acl *acl, *clone; | 339 | struct posix_acl *acl, *clone; |
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index 8ca058aed384..fc929f2a14f6 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h | |||
@@ -26,13 +26,10 @@ struct jffs2_acl_header { | |||
26 | 26 | ||
27 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL | 27 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL |
28 | 28 | ||
29 | #define JFFS2_ACL_NOT_CACHED ((void *)-1) | ||
30 | |||
31 | extern int jffs2_permission(struct inode *, int); | 29 | extern int jffs2_permission(struct inode *, int); |
32 | extern int jffs2_acl_chmod(struct inode *); | 30 | extern int jffs2_acl_chmod(struct inode *); |
33 | extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); | 31 | extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); |
34 | extern int jffs2_init_acl_post(struct inode *); | 32 | extern int jffs2_init_acl_post(struct inode *); |
35 | extern void jffs2_clear_acl(struct jffs2_inode_info *); | ||
36 | 33 | ||
37 | extern struct xattr_handler jffs2_acl_access_xattr_handler; | 34 | extern struct xattr_handler jffs2_acl_access_xattr_handler; |
38 | extern struct xattr_handler jffs2_acl_default_xattr_handler; | 35 | extern struct xattr_handler jffs2_acl_default_xattr_handler; |
@@ -43,6 +40,5 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler; | |||
43 | #define jffs2_acl_chmod(inode) (0) | 40 | #define jffs2_acl_chmod(inode) (0) |
44 | #define jffs2_init_acl_pre(dir_i,inode,mode) (0) | 41 | #define jffs2_init_acl_pre(dir_i,inode,mode) (0) |
45 | #define jffs2_init_acl_post(inode) (0) | 42 | #define jffs2_init_acl_post(inode) (0) |
46 | #define jffs2_clear_acl(f) | ||
47 | 43 | ||
48 | #endif /* CONFIG_JFFS2_FS_POSIX_ACL */ | 44 | #endif /* CONFIG_JFFS2_FS_POSIX_ACL */ |
diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h index 4c41db91eaa4..c6923da98263 100644 --- a/fs/jffs2/jffs2_fs_i.h +++ b/fs/jffs2/jffs2_fs_i.h | |||
@@ -50,10 +50,6 @@ struct jffs2_inode_info { | |||
50 | uint16_t flags; | 50 | uint16_t flags; |
51 | uint8_t usercompr; | 51 | uint8_t usercompr; |
52 | struct inode vfs_inode; | 52 | struct inode vfs_inode; |
53 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL | ||
54 | struct posix_acl *i_acl_access; | ||
55 | struct posix_acl *i_acl_default; | ||
56 | #endif | ||
57 | }; | 53 | }; |
58 | 54 | ||
59 | #endif /* _JFFS2_FS_I */ | 55 | #endif /* _JFFS2_FS_I */ |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 2228380c47b9..a7f03b7ebcb3 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
@@ -56,10 +56,6 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | |||
56 | f->target = NULL; | 56 | f->target = NULL; |
57 | f->flags = 0; | 57 | f->flags = 0; |
58 | f->usercompr = 0; | 58 | f->usercompr = 0; |
59 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL | ||
60 | f->i_acl_access = JFFS2_ACL_NOT_CACHED; | ||
61 | f->i_acl_default = JFFS2_ACL_NOT_CACHED; | ||
62 | #endif | ||
63 | } | 59 | } |
64 | 60 | ||
65 | 61 | ||
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 1fc1e92356ee..1a80301004b8 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -1424,7 +1424,6 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
1424 | struct jffs2_full_dirent *fd, *fds; | 1424 | struct jffs2_full_dirent *fd, *fds; |
1425 | int deleted; | 1425 | int deleted; |
1426 | 1426 | ||
1427 | jffs2_clear_acl(f); | ||
1428 | jffs2_xattr_delete_inode(c, f->inocache); | 1427 | jffs2_xattr_delete_inode(c, f->inocache); |
1429 | mutex_lock(&f->sem); | 1428 | mutex_lock(&f->sem); |
1430 | deleted = f->inocache && !f->inocache->pino_nlink; | 1429 | deleted = f->inocache && !f->inocache->pino_nlink; |
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 1d437de1e9a8..696686cc206e 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -130,9 +130,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
130 | if (jffs2_sum_active()) { | 130 | if (jffs2_sum_active()) { |
131 | s = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL); | 131 | s = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL); |
132 | if (!s) { | 132 | if (!s) { |
133 | kfree(flashbuf); | ||
134 | JFFS2_WARNING("Can't allocate memory for summary\n"); | 133 | JFFS2_WARNING("Can't allocate memory for summary\n"); |
135 | return -ENOMEM; | 134 | ret = -ENOMEM; |
135 | goto out; | ||
136 | } | 136 | } |
137 | } | 137 | } |
138 | 138 | ||
@@ -196,7 +196,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
196 | if (c->nextblock) { | 196 | if (c->nextblock) { |
197 | ret = file_dirty(c, c->nextblock); | 197 | ret = file_dirty(c, c->nextblock); |
198 | if (ret) | 198 | if (ret) |
199 | return ret; | 199 | goto out; |
200 | /* deleting summary information of the old nextblock */ | 200 | /* deleting summary information of the old nextblock */ |
201 | jffs2_sum_reset_collected(c->summary); | 201 | jffs2_sum_reset_collected(c->summary); |
202 | } | 202 | } |
@@ -207,7 +207,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
207 | } else { | 207 | } else { |
208 | ret = file_dirty(c, jeb); | 208 | ret = file_dirty(c, jeb); |
209 | if (ret) | 209 | if (ret) |
210 | return ret; | 210 | goto out; |
211 | } | 211 | } |
212 | break; | 212 | break; |
213 | 213 | ||
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 06ca1b8d2054..91fa3ad6e8c2 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c | |||
@@ -31,27 +31,24 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type) | |||
31 | { | 31 | { |
32 | struct posix_acl *acl; | 32 | struct posix_acl *acl; |
33 | char *ea_name; | 33 | char *ea_name; |
34 | struct jfs_inode_info *ji = JFS_IP(inode); | ||
35 | struct posix_acl **p_acl; | ||
36 | int size; | 34 | int size; |
37 | char *value = NULL; | 35 | char *value = NULL; |
38 | 36 | ||
37 | acl = get_cached_acl(inode, type); | ||
38 | if (acl != ACL_NOT_CACHED) | ||
39 | return acl; | ||
40 | |||
39 | switch(type) { | 41 | switch(type) { |
40 | case ACL_TYPE_ACCESS: | 42 | case ACL_TYPE_ACCESS: |
41 | ea_name = POSIX_ACL_XATTR_ACCESS; | 43 | ea_name = POSIX_ACL_XATTR_ACCESS; |
42 | p_acl = &ji->i_acl; | ||
43 | break; | 44 | break; |
44 | case ACL_TYPE_DEFAULT: | 45 | case ACL_TYPE_DEFAULT: |
45 | ea_name = POSIX_ACL_XATTR_DEFAULT; | 46 | ea_name = POSIX_ACL_XATTR_DEFAULT; |
46 | p_acl = &ji->i_default_acl; | ||
47 | break; | 47 | break; |
48 | default: | 48 | default: |
49 | return ERR_PTR(-EINVAL); | 49 | return ERR_PTR(-EINVAL); |
50 | } | 50 | } |
51 | 51 | ||
52 | if (*p_acl != JFS_ACL_NOT_CACHED) | ||
53 | return posix_acl_dup(*p_acl); | ||
54 | |||
55 | size = __jfs_getxattr(inode, ea_name, NULL, 0); | 52 | size = __jfs_getxattr(inode, ea_name, NULL, 0); |
56 | 53 | ||
57 | if (size > 0) { | 54 | if (size > 0) { |
@@ -62,17 +59,18 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type) | |||
62 | } | 59 | } |
63 | 60 | ||
64 | if (size < 0) { | 61 | if (size < 0) { |
65 | if (size == -ENODATA) { | 62 | if (size == -ENODATA) |
66 | *p_acl = NULL; | ||
67 | acl = NULL; | 63 | acl = NULL; |
68 | } else | 64 | else |
69 | acl = ERR_PTR(size); | 65 | acl = ERR_PTR(size); |
70 | } else { | 66 | } else { |
71 | acl = posix_acl_from_xattr(value, size); | 67 | acl = posix_acl_from_xattr(value, size); |
72 | if (!IS_ERR(acl)) | ||
73 | *p_acl = posix_acl_dup(acl); | ||
74 | } | 68 | } |
75 | kfree(value); | 69 | kfree(value); |
70 | if (!IS_ERR(acl)) { | ||
71 | set_cached_acl(inode, type, acl); | ||
72 | posix_acl_release(acl); | ||
73 | } | ||
76 | return acl; | 74 | return acl; |
77 | } | 75 | } |
78 | 76 | ||
@@ -80,8 +78,6 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type, | |||
80 | struct posix_acl *acl) | 78 | struct posix_acl *acl) |
81 | { | 79 | { |
82 | char *ea_name; | 80 | char *ea_name; |
83 | struct jfs_inode_info *ji = JFS_IP(inode); | ||
84 | struct posix_acl **p_acl; | ||
85 | int rc; | 81 | int rc; |
86 | int size = 0; | 82 | int size = 0; |
87 | char *value = NULL; | 83 | char *value = NULL; |
@@ -92,11 +88,9 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type, | |||
92 | switch(type) { | 88 | switch(type) { |
93 | case ACL_TYPE_ACCESS: | 89 | case ACL_TYPE_ACCESS: |
94 | ea_name = POSIX_ACL_XATTR_ACCESS; | 90 | ea_name = POSIX_ACL_XATTR_ACCESS; |
95 | p_acl = &ji->i_acl; | ||
96 | break; | 91 | break; |
97 | case ACL_TYPE_DEFAULT: | 92 | case ACL_TYPE_DEFAULT: |
98 | ea_name = POSIX_ACL_XATTR_DEFAULT; | 93 | ea_name = POSIX_ACL_XATTR_DEFAULT; |
99 | p_acl = &ji->i_default_acl; | ||
100 | if (!S_ISDIR(inode->i_mode)) | 94 | if (!S_ISDIR(inode->i_mode)) |
101 | return acl ? -EACCES : 0; | 95 | return acl ? -EACCES : 0; |
102 | break; | 96 | break; |
@@ -116,27 +110,24 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type, | |||
116 | out: | 110 | out: |
117 | kfree(value); | 111 | kfree(value); |
118 | 112 | ||
119 | if (!rc) { | 113 | if (!rc) |
120 | if (*p_acl && (*p_acl != JFS_ACL_NOT_CACHED)) | 114 | set_cached_acl(inode, type, acl); |
121 | posix_acl_release(*p_acl); | 115 | |
122 | *p_acl = posix_acl_dup(acl); | ||
123 | } | ||
124 | return rc; | 116 | return rc; |
125 | } | 117 | } |
126 | 118 | ||
127 | static int jfs_check_acl(struct inode *inode, int mask) | 119 | static int jfs_check_acl(struct inode *inode, int mask) |
128 | { | 120 | { |
129 | struct jfs_inode_info *ji = JFS_IP(inode); | 121 | struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); |
130 | 122 | ||
131 | if (ji->i_acl == JFS_ACL_NOT_CACHED) { | 123 | if (IS_ERR(acl)) |
132 | struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); | 124 | return PTR_ERR(acl); |
133 | if (IS_ERR(acl)) | 125 | if (acl) { |
134 | return PTR_ERR(acl); | 126 | int error = posix_acl_permission(inode, acl, mask); |
135 | posix_acl_release(acl); | 127 | posix_acl_release(acl); |
128 | return error; | ||
136 | } | 129 | } |
137 | 130 | ||
138 | if (ji->i_acl) | ||
139 | return posix_acl_permission(inode, ji->i_acl, mask); | ||
140 | return -EAGAIN; | 131 | return -EAGAIN; |
141 | } | 132 | } |
142 | 133 | ||
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index 439901d205fe..1439f119ec83 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h | |||
@@ -74,10 +74,6 @@ struct jfs_inode_info { | |||
74 | /* xattr_sem allows us to access the xattrs without taking i_mutex */ | 74 | /* xattr_sem allows us to access the xattrs without taking i_mutex */ |
75 | struct rw_semaphore xattr_sem; | 75 | struct rw_semaphore xattr_sem; |
76 | lid_t xtlid; /* lid of xtree lock on directory */ | 76 | lid_t xtlid; /* lid of xtree lock on directory */ |
77 | #ifdef CONFIG_JFS_POSIX_ACL | ||
78 | struct posix_acl *i_acl; | ||
79 | struct posix_acl *i_default_acl; | ||
80 | #endif | ||
81 | union { | 77 | union { |
82 | struct { | 78 | struct { |
83 | xtpage_t _xtroot; /* 288: xtree root */ | 79 | xtpage_t _xtroot; /* 288: xtree root */ |
@@ -107,8 +103,6 @@ struct jfs_inode_info { | |||
107 | #define i_inline u.link._inline | 103 | #define i_inline u.link._inline |
108 | #define i_inline_ea u.link._inline_ea | 104 | #define i_inline_ea u.link._inline_ea |
109 | 105 | ||
110 | #define JFS_ACL_NOT_CACHED ((void *)-1) | ||
111 | |||
112 | #define IREAD_LOCK(ip, subclass) \ | 106 | #define IREAD_LOCK(ip, subclass) \ |
113 | down_read_nested(&JFS_IP(ip)->rdwrlock, subclass) | 107 | down_read_nested(&JFS_IP(ip)->rdwrlock, subclass) |
114 | #define IREAD_UNLOCK(ip) up_read(&JFS_IP(ip)->rdwrlock) | 108 | #define IREAD_UNLOCK(ip) up_read(&JFS_IP(ip)->rdwrlock) |
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 09b1b6ee2186..37e6dcda8fc8 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
@@ -128,18 +128,6 @@ static void jfs_destroy_inode(struct inode *inode) | |||
128 | ji->active_ag = -1; | 128 | ji->active_ag = -1; |
129 | } | 129 | } |
130 | spin_unlock_irq(&ji->ag_lock); | 130 | spin_unlock_irq(&ji->ag_lock); |
131 | |||
132 | #ifdef CONFIG_JFS_POSIX_ACL | ||
133 | if (ji->i_acl != JFS_ACL_NOT_CACHED) { | ||
134 | posix_acl_release(ji->i_acl); | ||
135 | ji->i_acl = JFS_ACL_NOT_CACHED; | ||
136 | } | ||
137 | if (ji->i_default_acl != JFS_ACL_NOT_CACHED) { | ||
138 | posix_acl_release(ji->i_default_acl); | ||
139 | ji->i_default_acl = JFS_ACL_NOT_CACHED; | ||
140 | } | ||
141 | #endif | ||
142 | |||
143 | kmem_cache_free(jfs_inode_cachep, ji); | 131 | kmem_cache_free(jfs_inode_cachep, ji); |
144 | } | 132 | } |
145 | 133 | ||
@@ -798,10 +786,6 @@ static void init_once(void *foo) | |||
798 | init_rwsem(&jfs_ip->xattr_sem); | 786 | init_rwsem(&jfs_ip->xattr_sem); |
799 | spin_lock_init(&jfs_ip->ag_lock); | 787 | spin_lock_init(&jfs_ip->ag_lock); |
800 | jfs_ip->active_ag = -1; | 788 | jfs_ip->active_ag = -1; |
801 | #ifdef CONFIG_JFS_POSIX_ACL | ||
802 | jfs_ip->i_acl = JFS_ACL_NOT_CACHED; | ||
803 | jfs_ip->i_default_acl = JFS_ACL_NOT_CACHED; | ||
804 | #endif | ||
805 | inode_init_once(&jfs_ip->vfs_inode); | 789 | inode_init_once(&jfs_ip->vfs_inode); |
806 | } | 790 | } |
807 | 791 | ||
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index 61dfa8173ebc..fad364548bc9 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c | |||
@@ -727,10 +727,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name, | |||
727 | /* | 727 | /* |
728 | * We're changing the ACL. Get rid of the cached one | 728 | * We're changing the ACL. Get rid of the cached one |
729 | */ | 729 | */ |
730 | acl =JFS_IP(inode)->i_acl; | 730 | forget_cached_acl(inode, ACL_TYPE_ACCESS); |
731 | if (acl != JFS_ACL_NOT_CACHED) | ||
732 | posix_acl_release(acl); | ||
733 | JFS_IP(inode)->i_acl = JFS_ACL_NOT_CACHED; | ||
734 | 731 | ||
735 | return 0; | 732 | return 0; |
736 | } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { | 733 | } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { |
@@ -746,10 +743,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name, | |||
746 | /* | 743 | /* |
747 | * We're changing the default ACL. Get rid of the cached one | 744 | * We're changing the default ACL. Get rid of the cached one |
748 | */ | 745 | */ |
749 | acl =JFS_IP(inode)->i_default_acl; | 746 | forget_cached_acl(inode, ACL_TYPE_DEFAULT); |
750 | if (acl && (acl != JFS_ACL_NOT_CACHED)) | ||
751 | posix_acl_release(acl); | ||
752 | JFS_IP(inode)->i_default_acl = JFS_ACL_NOT_CACHED; | ||
753 | 747 | ||
754 | return 0; | 748 | return 0; |
755 | } | 749 | } |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index dd7957064a8c..f2fdcbce143e 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -126,7 +126,6 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) | |||
126 | struct nlm_lock *lock = &argp->lock; | 126 | struct nlm_lock *lock = &argp->lock; |
127 | 127 | ||
128 | nlmclnt_next_cookie(&argp->cookie); | 128 | nlmclnt_next_cookie(&argp->cookie); |
129 | argp->state = nsm_local_state; | ||
130 | memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh)); | 129 | memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh)); |
131 | lock->caller = utsname()->nodename; | 130 | lock->caller = utsname()->nodename; |
132 | lock->oh.data = req->a_owner; | 131 | lock->oh.data = req->a_owner; |
@@ -165,6 +164,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
165 | /* Set up the argument struct */ | 164 | /* Set up the argument struct */ |
166 | nlmclnt_setlockargs(call, fl); | 165 | nlmclnt_setlockargs(call, fl); |
167 | 166 | ||
167 | lock_kernel(); | ||
168 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { | 168 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { |
169 | if (fl->fl_type != F_UNLCK) { | 169 | if (fl->fl_type != F_UNLCK) { |
170 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; | 170 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; |
@@ -178,6 +178,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
178 | 178 | ||
179 | fl->fl_ops->fl_release_private(fl); | 179 | fl->fl_ops->fl_release_private(fl); |
180 | fl->fl_ops = NULL; | 180 | fl->fl_ops = NULL; |
181 | unlock_kernel(); | ||
181 | 182 | ||
182 | dprintk("lockd: clnt proc returns %d\n", status); | 183 | dprintk("lockd: clnt proc returns %d\n", status); |
183 | return status; | 184 | return status; |
@@ -519,6 +520,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
519 | 520 | ||
520 | if (nsm_monitor(host) < 0) | 521 | if (nsm_monitor(host) < 0) |
521 | goto out; | 522 | goto out; |
523 | req->a_args.state = nsm_local_state; | ||
522 | 524 | ||
523 | fl->fl_flags |= FL_ACCESS; | 525 | fl->fl_flags |= FL_ACCESS; |
524 | status = do_vfs_lock(fl); | 526 | status = do_vfs_lock(fl); |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 6d5d4a4169e5..7fce1b525849 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -53,7 +53,7 @@ static DEFINE_SPINLOCK(nsm_lock); | |||
53 | /* | 53 | /* |
54 | * Local NSM state | 54 | * Local NSM state |
55 | */ | 55 | */ |
56 | int __read_mostly nsm_local_state; | 56 | u32 __read_mostly nsm_local_state; |
57 | int __read_mostly nsm_use_hostnames; | 57 | int __read_mostly nsm_use_hostnames; |
58 | 58 | ||
59 | static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) | 59 | static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) |
@@ -112,6 +112,7 @@ static struct rpc_clnt *nsm_create(void) | |||
112 | .program = &nsm_program, | 112 | .program = &nsm_program, |
113 | .version = NSM_VERSION, | 113 | .version = NSM_VERSION, |
114 | .authflavor = RPC_AUTH_NULL, | 114 | .authflavor = RPC_AUTH_NULL, |
115 | .flags = RPC_CLNT_CREATE_NOPING, | ||
115 | }; | 116 | }; |
116 | 117 | ||
117 | return rpc_create(&args); | 118 | return rpc_create(&args); |
@@ -184,13 +185,19 @@ int nsm_monitor(const struct nlm_host *host) | |||
184 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; | 185 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; |
185 | 186 | ||
186 | status = nsm_mon_unmon(nsm, NSMPROC_MON, &res); | 187 | status = nsm_mon_unmon(nsm, NSMPROC_MON, &res); |
187 | if (res.status != 0) | 188 | if (unlikely(res.status != 0)) |
188 | status = -EIO; | 189 | status = -EIO; |
189 | if (status < 0) | 190 | if (unlikely(status < 0)) { |
190 | printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name); | 191 | printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name); |
191 | else | 192 | return status; |
192 | nsm->sm_monitored = 1; | 193 | } |
193 | return status; | 194 | |
195 | nsm->sm_monitored = 1; | ||
196 | if (unlikely(nsm_local_state != res.state)) { | ||
197 | nsm_local_state = res.state; | ||
198 | dprintk("lockd: NSM state changed to %d\n", nsm_local_state); | ||
199 | } | ||
200 | return 0; | ||
194 | } | 201 | } |
195 | 202 | ||
196 | /** | 203 | /** |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 83ee34203bd7..e577a78d7bac 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -326,6 +326,8 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call) | |||
326 | { | 326 | { |
327 | if (call->a_args.lock.oh.data != call->a_owner) | 327 | if (call->a_args.lock.oh.data != call->a_owner) |
328 | kfree(call->a_args.lock.oh.data); | 328 | kfree(call->a_args.lock.oh.data); |
329 | |||
330 | locks_release_private(&call->a_args.lock.fl); | ||
329 | } | 331 | } |
330 | 332 | ||
331 | /* | 333 | /* |
diff --git a/fs/locks.c b/fs/locks.c index ec3deea29e37..b6440f52178f 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -151,7 +151,7 @@ static struct file_lock *locks_alloc_lock(void) | |||
151 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); | 151 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); |
152 | } | 152 | } |
153 | 153 | ||
154 | static void locks_release_private(struct file_lock *fl) | 154 | void locks_release_private(struct file_lock *fl) |
155 | { | 155 | { |
156 | if (fl->fl_ops) { | 156 | if (fl->fl_ops) { |
157 | if (fl->fl_ops->fl_release_private) | 157 | if (fl->fl_ops->fl_release_private) |
@@ -165,6 +165,7 @@ static void locks_release_private(struct file_lock *fl) | |||
165 | } | 165 | } |
166 | 166 | ||
167 | } | 167 | } |
168 | EXPORT_SYMBOL_GPL(locks_release_private); | ||
168 | 169 | ||
169 | /* Free a lock which is not in use. */ | 170 | /* Free a lock which is not in use. */ |
170 | static void locks_free_lock(struct file_lock *fl) | 171 | static void locks_free_lock(struct file_lock *fl) |
diff --git a/fs/minix/minix.h b/fs/minix/minix.h index cb7fdd11f9a5..9dcf95b42116 100644 --- a/fs/minix/minix.h +++ b/fs/minix/minix.h | |||
@@ -1,3 +1,6 @@ | |||
1 | #ifndef FS_MINIX_H | ||
2 | #define FS_MINIX_H | ||
3 | |||
1 | #include <linux/fs.h> | 4 | #include <linux/fs.h> |
2 | #include <linux/pagemap.h> | 5 | #include <linux/pagemap.h> |
3 | #include <linux/minix_fs.h> | 6 | #include <linux/minix_fs.h> |
@@ -86,3 +89,5 @@ static inline struct minix_inode_info *minix_i(struct inode *inode) | |||
86 | { | 89 | { |
87 | return list_entry(inode, struct minix_inode_info, vfs_inode); | 90 | return list_entry(inode, struct minix_inode_info, vfs_inode); |
88 | } | 91 | } |
92 | |||
93 | #endif /* FS_MINIX_H */ | ||
diff --git a/fs/namei.c b/fs/namei.c index 527119afb6a5..f3c5b278895a 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1698,8 +1698,11 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1698 | if (error) | 1698 | if (error) |
1699 | return ERR_PTR(error); | 1699 | return ERR_PTR(error); |
1700 | error = path_walk(pathname, &nd); | 1700 | error = path_walk(pathname, &nd); |
1701 | if (error) | 1701 | if (error) { |
1702 | if (nd.root.mnt) | ||
1703 | path_put(&nd.root); | ||
1702 | return ERR_PTR(error); | 1704 | return ERR_PTR(error); |
1705 | } | ||
1703 | if (unlikely(!audit_dummy_context())) | 1706 | if (unlikely(!audit_dummy_context())) |
1704 | audit_inode(pathname, nd.path.dentry); | 1707 | audit_inode(pathname, nd.path.dentry); |
1705 | 1708 | ||
@@ -1758,7 +1761,13 @@ do_last: | |||
1758 | goto exit; | 1761 | goto exit; |
1759 | } | 1762 | } |
1760 | filp = nameidata_to_filp(&nd, open_flag); | 1763 | filp = nameidata_to_filp(&nd, open_flag); |
1764 | if (IS_ERR(filp)) | ||
1765 | ima_counts_put(&nd.path, | ||
1766 | acc_mode & (MAY_READ | MAY_WRITE | | ||
1767 | MAY_EXEC)); | ||
1761 | mnt_drop_write(nd.path.mnt); | 1768 | mnt_drop_write(nd.path.mnt); |
1769 | if (nd.root.mnt) | ||
1770 | path_put(&nd.root); | ||
1762 | return filp; | 1771 | return filp; |
1763 | } | 1772 | } |
1764 | 1773 | ||
@@ -1812,6 +1821,9 @@ ok: | |||
1812 | goto exit; | 1821 | goto exit; |
1813 | } | 1822 | } |
1814 | filp = nameidata_to_filp(&nd, open_flag); | 1823 | filp = nameidata_to_filp(&nd, open_flag); |
1824 | if (IS_ERR(filp)) | ||
1825 | ima_counts_put(&nd.path, | ||
1826 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC)); | ||
1815 | /* | 1827 | /* |
1816 | * It is now safe to drop the mnt write | 1828 | * It is now safe to drop the mnt write |
1817 | * because the filp has had a write taken | 1829 | * because the filp has had a write taken |
@@ -1819,6 +1831,8 @@ ok: | |||
1819 | */ | 1831 | */ |
1820 | if (will_write) | 1832 | if (will_write) |
1821 | mnt_drop_write(nd.path.mnt); | 1833 | mnt_drop_write(nd.path.mnt); |
1834 | if (nd.root.mnt) | ||
1835 | path_put(&nd.root); | ||
1822 | return filp; | 1836 | return filp; |
1823 | 1837 | ||
1824 | exit_mutex_unlock: | 1838 | exit_mutex_unlock: |
@@ -1859,6 +1873,8 @@ do_link: | |||
1859 | * with "intent.open". | 1873 | * with "intent.open". |
1860 | */ | 1874 | */ |
1861 | release_open_intent(&nd); | 1875 | release_open_intent(&nd); |
1876 | if (nd.root.mnt) | ||
1877 | path_put(&nd.root); | ||
1862 | return ERR_PTR(error); | 1878 | return ERR_PTR(error); |
1863 | } | 1879 | } |
1864 | nd.flags &= ~LOOKUP_PARENT; | 1880 | nd.flags &= ~LOOKUP_PARENT; |
diff --git a/fs/namespace.c b/fs/namespace.c index 2dd333b0fe7f..3dc283fd4716 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -42,6 +42,8 @@ __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); | |||
42 | static int event; | 42 | static int event; |
43 | static DEFINE_IDA(mnt_id_ida); | 43 | static DEFINE_IDA(mnt_id_ida); |
44 | static DEFINE_IDA(mnt_group_ida); | 44 | static DEFINE_IDA(mnt_group_ida); |
45 | static int mnt_id_start = 0; | ||
46 | static int mnt_group_start = 1; | ||
45 | 47 | ||
46 | static struct list_head *mount_hashtable __read_mostly; | 48 | static struct list_head *mount_hashtable __read_mostly; |
47 | static struct kmem_cache *mnt_cache __read_mostly; | 49 | static struct kmem_cache *mnt_cache __read_mostly; |
@@ -69,7 +71,9 @@ static int mnt_alloc_id(struct vfsmount *mnt) | |||
69 | retry: | 71 | retry: |
70 | ida_pre_get(&mnt_id_ida, GFP_KERNEL); | 72 | ida_pre_get(&mnt_id_ida, GFP_KERNEL); |
71 | spin_lock(&vfsmount_lock); | 73 | spin_lock(&vfsmount_lock); |
72 | res = ida_get_new(&mnt_id_ida, &mnt->mnt_id); | 74 | res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id); |
75 | if (!res) | ||
76 | mnt_id_start = mnt->mnt_id + 1; | ||
73 | spin_unlock(&vfsmount_lock); | 77 | spin_unlock(&vfsmount_lock); |
74 | if (res == -EAGAIN) | 78 | if (res == -EAGAIN) |
75 | goto retry; | 79 | goto retry; |
@@ -79,8 +83,11 @@ retry: | |||
79 | 83 | ||
80 | static void mnt_free_id(struct vfsmount *mnt) | 84 | static void mnt_free_id(struct vfsmount *mnt) |
81 | { | 85 | { |
86 | int id = mnt->mnt_id; | ||
82 | spin_lock(&vfsmount_lock); | 87 | spin_lock(&vfsmount_lock); |
83 | ida_remove(&mnt_id_ida, mnt->mnt_id); | 88 | ida_remove(&mnt_id_ida, id); |
89 | if (mnt_id_start > id) | ||
90 | mnt_id_start = id; | ||
84 | spin_unlock(&vfsmount_lock); | 91 | spin_unlock(&vfsmount_lock); |
85 | } | 92 | } |
86 | 93 | ||
@@ -91,10 +98,18 @@ static void mnt_free_id(struct vfsmount *mnt) | |||
91 | */ | 98 | */ |
92 | static int mnt_alloc_group_id(struct vfsmount *mnt) | 99 | static int mnt_alloc_group_id(struct vfsmount *mnt) |
93 | { | 100 | { |
101 | int res; | ||
102 | |||
94 | if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL)) | 103 | if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL)) |
95 | return -ENOMEM; | 104 | return -ENOMEM; |
96 | 105 | ||
97 | return ida_get_new_above(&mnt_group_ida, 1, &mnt->mnt_group_id); | 106 | res = ida_get_new_above(&mnt_group_ida, |
107 | mnt_group_start, | ||
108 | &mnt->mnt_group_id); | ||
109 | if (!res) | ||
110 | mnt_group_start = mnt->mnt_group_id + 1; | ||
111 | |||
112 | return res; | ||
98 | } | 113 | } |
99 | 114 | ||
100 | /* | 115 | /* |
@@ -102,7 +117,10 @@ static int mnt_alloc_group_id(struct vfsmount *mnt) | |||
102 | */ | 117 | */ |
103 | void mnt_release_group_id(struct vfsmount *mnt) | 118 | void mnt_release_group_id(struct vfsmount *mnt) |
104 | { | 119 | { |
105 | ida_remove(&mnt_group_ida, mnt->mnt_group_id); | 120 | int id = mnt->mnt_group_id; |
121 | ida_remove(&mnt_group_ida, id); | ||
122 | if (mnt_group_start > id) | ||
123 | mnt_group_start = id; | ||
106 | mnt->mnt_group_id = 0; | 124 | mnt->mnt_group_id = 0; |
107 | } | 125 | } |
108 | 126 | ||
@@ -1937,6 +1955,21 @@ dput_out: | |||
1937 | return retval; | 1955 | return retval; |
1938 | } | 1956 | } |
1939 | 1957 | ||
1958 | static struct mnt_namespace *alloc_mnt_ns(void) | ||
1959 | { | ||
1960 | struct mnt_namespace *new_ns; | ||
1961 | |||
1962 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); | ||
1963 | if (!new_ns) | ||
1964 | return ERR_PTR(-ENOMEM); | ||
1965 | atomic_set(&new_ns->count, 1); | ||
1966 | new_ns->root = NULL; | ||
1967 | INIT_LIST_HEAD(&new_ns->list); | ||
1968 | init_waitqueue_head(&new_ns->poll); | ||
1969 | new_ns->event = 0; | ||
1970 | return new_ns; | ||
1971 | } | ||
1972 | |||
1940 | /* | 1973 | /* |
1941 | * Allocate a new namespace structure and populate it with contents | 1974 | * Allocate a new namespace structure and populate it with contents |
1942 | * copied from the namespace of the passed in task structure. | 1975 | * copied from the namespace of the passed in task structure. |
@@ -1948,14 +1981,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
1948 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; | 1981 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; |
1949 | struct vfsmount *p, *q; | 1982 | struct vfsmount *p, *q; |
1950 | 1983 | ||
1951 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); | 1984 | new_ns = alloc_mnt_ns(); |
1952 | if (!new_ns) | 1985 | if (IS_ERR(new_ns)) |
1953 | return ERR_PTR(-ENOMEM); | 1986 | return new_ns; |
1954 | |||
1955 | atomic_set(&new_ns->count, 1); | ||
1956 | INIT_LIST_HEAD(&new_ns->list); | ||
1957 | init_waitqueue_head(&new_ns->poll); | ||
1958 | new_ns->event = 0; | ||
1959 | 1987 | ||
1960 | down_write(&namespace_sem); | 1988 | down_write(&namespace_sem); |
1961 | /* First pass: copy the tree topology */ | 1989 | /* First pass: copy the tree topology */ |
@@ -2019,6 +2047,24 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, | |||
2019 | return new_ns; | 2047 | return new_ns; |
2020 | } | 2048 | } |
2021 | 2049 | ||
2050 | /** | ||
2051 | * create_mnt_ns - creates a private namespace and adds a root filesystem | ||
2052 | * @mnt: pointer to the new root filesystem mountpoint | ||
2053 | */ | ||
2054 | struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt) | ||
2055 | { | ||
2056 | struct mnt_namespace *new_ns; | ||
2057 | |||
2058 | new_ns = alloc_mnt_ns(); | ||
2059 | if (!IS_ERR(new_ns)) { | ||
2060 | mnt->mnt_ns = new_ns; | ||
2061 | new_ns->root = mnt; | ||
2062 | list_add(&new_ns->list, &new_ns->root->mnt_list); | ||
2063 | } | ||
2064 | return new_ns; | ||
2065 | } | ||
2066 | EXPORT_SYMBOL(create_mnt_ns); | ||
2067 | |||
2022 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, | 2068 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, |
2023 | char __user *, type, unsigned long, flags, void __user *, data) | 2069 | char __user *, type, unsigned long, flags, void __user *, data) |
2024 | { | 2070 | { |
@@ -2194,16 +2240,9 @@ static void __init init_mount_tree(void) | |||
2194 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); | 2240 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); |
2195 | if (IS_ERR(mnt)) | 2241 | if (IS_ERR(mnt)) |
2196 | panic("Can't create rootfs"); | 2242 | panic("Can't create rootfs"); |
2197 | ns = kmalloc(sizeof(*ns), GFP_KERNEL); | 2243 | ns = create_mnt_ns(mnt); |
2198 | if (!ns) | 2244 | if (IS_ERR(ns)) |
2199 | panic("Can't allocate initial namespace"); | 2245 | panic("Can't allocate initial namespace"); |
2200 | atomic_set(&ns->count, 1); | ||
2201 | INIT_LIST_HEAD(&ns->list); | ||
2202 | init_waitqueue_head(&ns->poll); | ||
2203 | ns->event = 0; | ||
2204 | list_add(&mnt->mnt_list, &ns->list); | ||
2205 | ns->root = mnt; | ||
2206 | mnt->mnt_ns = ns; | ||
2207 | 2246 | ||
2208 | init_task.nsproxy->mnt_ns = ns; | 2247 | init_task.nsproxy->mnt_ns = ns; |
2209 | get_mnt_ns(ns); | 2248 | get_mnt_ns(ns); |
@@ -2246,10 +2285,14 @@ void __init mnt_init(void) | |||
2246 | init_mount_tree(); | 2285 | init_mount_tree(); |
2247 | } | 2286 | } |
2248 | 2287 | ||
2249 | void __put_mnt_ns(struct mnt_namespace *ns) | 2288 | void put_mnt_ns(struct mnt_namespace *ns) |
2250 | { | 2289 | { |
2251 | struct vfsmount *root = ns->root; | 2290 | struct vfsmount *root; |
2252 | LIST_HEAD(umount_list); | 2291 | LIST_HEAD(umount_list); |
2292 | |||
2293 | if (!atomic_dec_and_lock(&ns->count, &vfsmount_lock)) | ||
2294 | return; | ||
2295 | root = ns->root; | ||
2253 | ns->root = NULL; | 2296 | ns->root = NULL; |
2254 | spin_unlock(&vfsmount_lock); | 2297 | spin_unlock(&vfsmount_lock); |
2255 | down_write(&namespace_sem); | 2298 | down_write(&namespace_sem); |
@@ -2260,3 +2303,4 @@ void __put_mnt_ns(struct mnt_namespace *ns) | |||
2260 | release_mounts(&umount_list); | 2303 | release_mounts(&umount_list); |
2261 | kfree(ns); | 2304 | kfree(ns); |
2262 | } | 2305 | } |
2306 | EXPORT_SYMBOL(put_mnt_ns); | ||
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index e67f3ec07736..2a77bc25d5af 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config NFS_FS | 1 | config NFS_FS |
2 | tristate "NFS client support" | 2 | tristate "NFS client support" |
3 | depends on INET | 3 | depends on INET && FILE_LOCKING |
4 | select LOCKD | 4 | select LOCKD |
5 | select SUNRPC | 5 | select SUNRPC |
6 | select NFS_ACL_SUPPORT if NFS_V3_ACL | 6 | select NFS_ACL_SUPPORT if NFS_V3_ACL |
@@ -74,6 +74,15 @@ config NFS_V4 | |||
74 | 74 | ||
75 | If unsure, say N. | 75 | If unsure, say N. |
76 | 76 | ||
77 | config NFS_V4_1 | ||
78 | bool "NFS client support for NFSv4.1 (DEVELOPER ONLY)" | ||
79 | depends on NFS_V4 && EXPERIMENTAL | ||
80 | help | ||
81 | This option enables support for minor version 1 of the NFSv4 protocol | ||
82 | (draft-ietf-nfsv4-minorversion1) in the kernel's NFS client. | ||
83 | |||
84 | Unless you're an NFS developer, say N. | ||
85 | |||
77 | config ROOT_NFS | 86 | config ROOT_NFS |
78 | bool "Root file system on NFS" | 87 | bool "Root file system on NFS" |
79 | depends on NFS_FS=y && IP_PNP | 88 | depends on NFS_FS=y && IP_PNP |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index a886e692ddd0..7f604c7941fb 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -17,6 +17,9 @@ | |||
17 | #include <linux/freezer.h> | 17 | #include <linux/freezer.h> |
18 | #include <linux/kthread.h> | 18 | #include <linux/kthread.h> |
19 | #include <linux/sunrpc/svcauth_gss.h> | 19 | #include <linux/sunrpc/svcauth_gss.h> |
20 | #if defined(CONFIG_NFS_V4_1) | ||
21 | #include <linux/sunrpc/bc_xprt.h> | ||
22 | #endif | ||
20 | 23 | ||
21 | #include <net/inet_sock.h> | 24 | #include <net/inet_sock.h> |
22 | 25 | ||
@@ -28,11 +31,12 @@ | |||
28 | 31 | ||
29 | struct nfs_callback_data { | 32 | struct nfs_callback_data { |
30 | unsigned int users; | 33 | unsigned int users; |
34 | struct svc_serv *serv; | ||
31 | struct svc_rqst *rqst; | 35 | struct svc_rqst *rqst; |
32 | struct task_struct *task; | 36 | struct task_struct *task; |
33 | }; | 37 | }; |
34 | 38 | ||
35 | static struct nfs_callback_data nfs_callback_info; | 39 | static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1]; |
36 | static DEFINE_MUTEX(nfs_callback_mutex); | 40 | static DEFINE_MUTEX(nfs_callback_mutex); |
37 | static struct svc_program nfs4_callback_program; | 41 | static struct svc_program nfs4_callback_program; |
38 | 42 | ||
@@ -56,10 +60,10 @@ module_param_call(callback_tcpport, param_set_port, param_get_int, | |||
56 | &nfs_callback_set_tcpport, 0644); | 60 | &nfs_callback_set_tcpport, 0644); |
57 | 61 | ||
58 | /* | 62 | /* |
59 | * This is the callback kernel thread. | 63 | * This is the NFSv4 callback kernel thread. |
60 | */ | 64 | */ |
61 | static int | 65 | static int |
62 | nfs_callback_svc(void *vrqstp) | 66 | nfs4_callback_svc(void *vrqstp) |
63 | { | 67 | { |
64 | int err, preverr = 0; | 68 | int err, preverr = 0; |
65 | struct svc_rqst *rqstp = vrqstp; | 69 | struct svc_rqst *rqstp = vrqstp; |
@@ -97,20 +101,12 @@ nfs_callback_svc(void *vrqstp) | |||
97 | } | 101 | } |
98 | 102 | ||
99 | /* | 103 | /* |
100 | * Bring up the callback thread if it is not already up. | 104 | * Prepare to bring up the NFSv4 callback service |
101 | */ | 105 | */ |
102 | int nfs_callback_up(void) | 106 | struct svc_rqst * |
107 | nfs4_callback_up(struct svc_serv *serv) | ||
103 | { | 108 | { |
104 | struct svc_serv *serv = NULL; | 109 | int ret; |
105 | int ret = 0; | ||
106 | |||
107 | mutex_lock(&nfs_callback_mutex); | ||
108 | if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) | ||
109 | goto out; | ||
110 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); | ||
111 | ret = -ENOMEM; | ||
112 | if (!serv) | ||
113 | goto out_err; | ||
114 | 110 | ||
115 | ret = svc_create_xprt(serv, "tcp", PF_INET, | 111 | ret = svc_create_xprt(serv, "tcp", PF_INET, |
116 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); | 112 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); |
@@ -127,27 +123,174 @@ int nfs_callback_up(void) | |||
127 | nfs_callback_tcpport6 = ret; | 123 | nfs_callback_tcpport6 = ret; |
128 | dprintk("NFS: Callback listener port = %u (af %u)\n", | 124 | dprintk("NFS: Callback listener port = %u (af %u)\n", |
129 | nfs_callback_tcpport6, PF_INET6); | 125 | nfs_callback_tcpport6, PF_INET6); |
130 | } else if (ret != -EAFNOSUPPORT) | 126 | } else if (ret == -EAFNOSUPPORT) |
127 | ret = 0; | ||
128 | else | ||
131 | goto out_err; | 129 | goto out_err; |
132 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ | 130 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ |
133 | 131 | ||
134 | nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); | 132 | return svc_prepare_thread(serv, &serv->sv_pools[0]); |
135 | if (IS_ERR(nfs_callback_info.rqst)) { | 133 | |
136 | ret = PTR_ERR(nfs_callback_info.rqst); | 134 | out_err: |
137 | nfs_callback_info.rqst = NULL; | 135 | if (ret == 0) |
136 | ret = -ENOMEM; | ||
137 | return ERR_PTR(ret); | ||
138 | } | ||
139 | |||
140 | #if defined(CONFIG_NFS_V4_1) | ||
141 | /* | ||
142 | * The callback service for NFSv4.1 callbacks | ||
143 | */ | ||
144 | static int | ||
145 | nfs41_callback_svc(void *vrqstp) | ||
146 | { | ||
147 | struct svc_rqst *rqstp = vrqstp; | ||
148 | struct svc_serv *serv = rqstp->rq_server; | ||
149 | struct rpc_rqst *req; | ||
150 | int error; | ||
151 | DEFINE_WAIT(wq); | ||
152 | |||
153 | set_freezable(); | ||
154 | |||
155 | /* | ||
156 | * FIXME: do we really need to run this under the BKL? If so, please | ||
157 | * add a comment about what it's intended to protect. | ||
158 | */ | ||
159 | lock_kernel(); | ||
160 | while (!kthread_should_stop()) { | ||
161 | prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); | ||
162 | spin_lock_bh(&serv->sv_cb_lock); | ||
163 | if (!list_empty(&serv->sv_cb_list)) { | ||
164 | req = list_first_entry(&serv->sv_cb_list, | ||
165 | struct rpc_rqst, rq_bc_list); | ||
166 | list_del(&req->rq_bc_list); | ||
167 | spin_unlock_bh(&serv->sv_cb_lock); | ||
168 | dprintk("Invoking bc_svc_process()\n"); | ||
169 | error = bc_svc_process(serv, req, rqstp); | ||
170 | dprintk("bc_svc_process() returned w/ error code= %d\n", | ||
171 | error); | ||
172 | } else { | ||
173 | spin_unlock_bh(&serv->sv_cb_lock); | ||
174 | schedule(); | ||
175 | } | ||
176 | finish_wait(&serv->sv_cb_waitq, &wq); | ||
177 | } | ||
178 | unlock_kernel(); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Bring up the NFSv4.1 callback service | ||
184 | */ | ||
185 | struct svc_rqst * | ||
186 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) | ||
187 | { | ||
188 | struct svc_xprt *bc_xprt; | ||
189 | struct svc_rqst *rqstp = ERR_PTR(-ENOMEM); | ||
190 | |||
191 | dprintk("--> %s\n", __func__); | ||
192 | /* Create a svc_sock for the service */ | ||
193 | bc_xprt = svc_sock_create(serv, xprt->prot); | ||
194 | if (!bc_xprt) | ||
195 | goto out; | ||
196 | |||
197 | /* | ||
198 | * Save the svc_serv in the transport so that it can | ||
199 | * be referenced when the session backchannel is initialized | ||
200 | */ | ||
201 | serv->bc_xprt = bc_xprt; | ||
202 | xprt->bc_serv = serv; | ||
203 | |||
204 | INIT_LIST_HEAD(&serv->sv_cb_list); | ||
205 | spin_lock_init(&serv->sv_cb_lock); | ||
206 | init_waitqueue_head(&serv->sv_cb_waitq); | ||
207 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); | ||
208 | if (IS_ERR(rqstp)) | ||
209 | svc_sock_destroy(bc_xprt); | ||
210 | out: | ||
211 | dprintk("--> %s return %p\n", __func__, rqstp); | ||
212 | return rqstp; | ||
213 | } | ||
214 | |||
215 | static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, | ||
216 | struct svc_serv *serv, struct rpc_xprt *xprt, | ||
217 | struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) | ||
218 | { | ||
219 | if (minorversion) { | ||
220 | *rqstpp = nfs41_callback_up(serv, xprt); | ||
221 | *callback_svc = nfs41_callback_svc; | ||
222 | } | ||
223 | return minorversion; | ||
224 | } | ||
225 | |||
226 | static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | ||
227 | struct nfs_callback_data *cb_info) | ||
228 | { | ||
229 | if (minorversion) | ||
230 | xprt->bc_serv = cb_info->serv; | ||
231 | } | ||
232 | #else | ||
233 | static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, | ||
234 | struct svc_serv *serv, struct rpc_xprt *xprt, | ||
235 | struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) | ||
236 | { | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | ||
241 | struct nfs_callback_data *cb_info) | ||
242 | { | ||
243 | } | ||
244 | #endif /* CONFIG_NFS_V4_1 */ | ||
245 | |||
246 | /* | ||
247 | * Bring up the callback thread if it is not already up. | ||
248 | */ | ||
249 | int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) | ||
250 | { | ||
251 | struct svc_serv *serv = NULL; | ||
252 | struct svc_rqst *rqstp; | ||
253 | int (*callback_svc)(void *vrqstp); | ||
254 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; | ||
255 | char svc_name[12]; | ||
256 | int ret = 0; | ||
257 | int minorversion_setup; | ||
258 | |||
259 | mutex_lock(&nfs_callback_mutex); | ||
260 | if (cb_info->users++ || cb_info->task != NULL) { | ||
261 | nfs_callback_bc_serv(minorversion, xprt, cb_info); | ||
262 | goto out; | ||
263 | } | ||
264 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); | ||
265 | if (!serv) { | ||
266 | ret = -ENOMEM; | ||
267 | goto out_err; | ||
268 | } | ||
269 | |||
270 | minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion, | ||
271 | serv, xprt, &rqstp, &callback_svc); | ||
272 | if (!minorversion_setup) { | ||
273 | /* v4.0 callback setup */ | ||
274 | rqstp = nfs4_callback_up(serv); | ||
275 | callback_svc = nfs4_callback_svc; | ||
276 | } | ||
277 | |||
278 | if (IS_ERR(rqstp)) { | ||
279 | ret = PTR_ERR(rqstp); | ||
138 | goto out_err; | 280 | goto out_err; |
139 | } | 281 | } |
140 | 282 | ||
141 | svc_sock_update_bufs(serv); | 283 | svc_sock_update_bufs(serv); |
142 | 284 | ||
143 | nfs_callback_info.task = kthread_run(nfs_callback_svc, | 285 | sprintf(svc_name, "nfsv4.%u-svc", minorversion); |
144 | nfs_callback_info.rqst, | 286 | cb_info->serv = serv; |
145 | "nfsv4-svc"); | 287 | cb_info->rqst = rqstp; |
146 | if (IS_ERR(nfs_callback_info.task)) { | 288 | cb_info->task = kthread_run(callback_svc, cb_info->rqst, svc_name); |
147 | ret = PTR_ERR(nfs_callback_info.task); | 289 | if (IS_ERR(cb_info->task)) { |
148 | svc_exit_thread(nfs_callback_info.rqst); | 290 | ret = PTR_ERR(cb_info->task); |
149 | nfs_callback_info.rqst = NULL; | 291 | svc_exit_thread(cb_info->rqst); |
150 | nfs_callback_info.task = NULL; | 292 | cb_info->rqst = NULL; |
293 | cb_info->task = NULL; | ||
151 | goto out_err; | 294 | goto out_err; |
152 | } | 295 | } |
153 | out: | 296 | out: |
@@ -164,22 +307,25 @@ out: | |||
164 | out_err: | 307 | out_err: |
165 | dprintk("NFS: Couldn't create callback socket or server thread; " | 308 | dprintk("NFS: Couldn't create callback socket or server thread; " |
166 | "err = %d\n", ret); | 309 | "err = %d\n", ret); |
167 | nfs_callback_info.users--; | 310 | cb_info->users--; |
168 | goto out; | 311 | goto out; |
169 | } | 312 | } |
170 | 313 | ||
171 | /* | 314 | /* |
172 | * Kill the callback thread if it's no longer being used. | 315 | * Kill the callback thread if it's no longer being used. |
173 | */ | 316 | */ |
174 | void nfs_callback_down(void) | 317 | void nfs_callback_down(int minorversion) |
175 | { | 318 | { |
319 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; | ||
320 | |||
176 | mutex_lock(&nfs_callback_mutex); | 321 | mutex_lock(&nfs_callback_mutex); |
177 | nfs_callback_info.users--; | 322 | cb_info->users--; |
178 | if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) { | 323 | if (cb_info->users == 0 && cb_info->task != NULL) { |
179 | kthread_stop(nfs_callback_info.task); | 324 | kthread_stop(cb_info->task); |
180 | svc_exit_thread(nfs_callback_info.rqst); | 325 | svc_exit_thread(cb_info->rqst); |
181 | nfs_callback_info.rqst = NULL; | 326 | cb_info->serv = NULL; |
182 | nfs_callback_info.task = NULL; | 327 | cb_info->rqst = NULL; |
328 | cb_info->task = NULL; | ||
183 | } | 329 | } |
184 | mutex_unlock(&nfs_callback_mutex); | 330 | mutex_unlock(&nfs_callback_mutex); |
185 | } | 331 | } |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index e110e286a262..07baa8254ca1 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -20,13 +20,24 @@ enum nfs4_callback_procnum { | |||
20 | enum nfs4_callback_opnum { | 20 | enum nfs4_callback_opnum { |
21 | OP_CB_GETATTR = 3, | 21 | OP_CB_GETATTR = 3, |
22 | OP_CB_RECALL = 4, | 22 | OP_CB_RECALL = 4, |
23 | /* Callback operations new to NFSv4.1 */ | ||
24 | OP_CB_LAYOUTRECALL = 5, | ||
25 | OP_CB_NOTIFY = 6, | ||
26 | OP_CB_PUSH_DELEG = 7, | ||
27 | OP_CB_RECALL_ANY = 8, | ||
28 | OP_CB_RECALLABLE_OBJ_AVAIL = 9, | ||
29 | OP_CB_RECALL_SLOT = 10, | ||
30 | OP_CB_SEQUENCE = 11, | ||
31 | OP_CB_WANTS_CANCELLED = 12, | ||
32 | OP_CB_NOTIFY_LOCK = 13, | ||
33 | OP_CB_NOTIFY_DEVICEID = 14, | ||
23 | OP_CB_ILLEGAL = 10044, | 34 | OP_CB_ILLEGAL = 10044, |
24 | }; | 35 | }; |
25 | 36 | ||
26 | struct cb_compound_hdr_arg { | 37 | struct cb_compound_hdr_arg { |
27 | unsigned int taglen; | 38 | unsigned int taglen; |
28 | const char *tag; | 39 | const char *tag; |
29 | unsigned int callback_ident; | 40 | unsigned int minorversion; |
30 | unsigned nops; | 41 | unsigned nops; |
31 | }; | 42 | }; |
32 | 43 | ||
@@ -59,16 +70,59 @@ struct cb_recallargs { | |||
59 | uint32_t truncate; | 70 | uint32_t truncate; |
60 | }; | 71 | }; |
61 | 72 | ||
73 | #if defined(CONFIG_NFS_V4_1) | ||
74 | |||
75 | struct referring_call { | ||
76 | uint32_t rc_sequenceid; | ||
77 | uint32_t rc_slotid; | ||
78 | }; | ||
79 | |||
80 | struct referring_call_list { | ||
81 | struct nfs4_sessionid rcl_sessionid; | ||
82 | uint32_t rcl_nrefcalls; | ||
83 | struct referring_call *rcl_refcalls; | ||
84 | }; | ||
85 | |||
86 | struct cb_sequenceargs { | ||
87 | struct sockaddr *csa_addr; | ||
88 | struct nfs4_sessionid csa_sessionid; | ||
89 | uint32_t csa_sequenceid; | ||
90 | uint32_t csa_slotid; | ||
91 | uint32_t csa_highestslotid; | ||
92 | uint32_t csa_cachethis; | ||
93 | uint32_t csa_nrclists; | ||
94 | struct referring_call_list *csa_rclists; | ||
95 | }; | ||
96 | |||
97 | struct cb_sequenceres { | ||
98 | __be32 csr_status; | ||
99 | struct nfs4_sessionid csr_sessionid; | ||
100 | uint32_t csr_sequenceid; | ||
101 | uint32_t csr_slotid; | ||
102 | uint32_t csr_highestslotid; | ||
103 | uint32_t csr_target_highestslotid; | ||
104 | }; | ||
105 | |||
106 | extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
107 | struct cb_sequenceres *res); | ||
108 | |||
109 | #endif /* CONFIG_NFS_V4_1 */ | ||
110 | |||
62 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); | 111 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); |
63 | extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); | 112 | extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); |
64 | 113 | ||
65 | #ifdef CONFIG_NFS_V4 | 114 | #ifdef CONFIG_NFS_V4 |
66 | extern int nfs_callback_up(void); | 115 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); |
67 | extern void nfs_callback_down(void); | 116 | extern void nfs_callback_down(int minorversion); |
68 | #else | 117 | #endif /* CONFIG_NFS_V4 */ |
69 | #define nfs_callback_up() (0) | 118 | |
70 | #define nfs_callback_down() do {} while(0) | 119 | /* |
71 | #endif | 120 | * nfs41: Callbacks are expected to not cause substantial latency, |
121 | * so we limit their concurrency to 1 by setting up the maximum number | ||
122 | * of slots for the backchannel. | ||
123 | */ | ||
124 | #define NFS41_BC_MIN_CALLBACKS 1 | ||
125 | #define NFS41_BC_MAX_CALLBACKS 1 | ||
72 | 126 | ||
73 | extern unsigned int nfs_callback_set_tcpport; | 127 | extern unsigned int nfs_callback_set_tcpport; |
74 | extern unsigned short nfs_callback_tcpport; | 128 | extern unsigned short nfs_callback_tcpport; |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index f7e83e23cf9f..b7da1f54da68 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -101,3 +101,130 @@ out: | |||
101 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); | 101 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); |
102 | return res; | 102 | return res; |
103 | } | 103 | } |
104 | |||
105 | #if defined(CONFIG_NFS_V4_1) | ||
106 | |||
107 | /* | ||
108 | * Validate the sequenceID sent by the server. | ||
109 | * Return success if the sequenceID is one more than what we last saw on | ||
110 | * this slot, accounting for wraparound. Increments the slot's sequence. | ||
111 | * | ||
112 | * We don't yet implement a duplicate request cache, so at this time | ||
113 | * we will log replays, and process them as if we had not seen them before, | ||
114 | * but we don't bump the sequence in the slot. Not too worried about it, | ||
115 | * since we only currently implement idempotent callbacks anyway. | ||
116 | * | ||
117 | * We have a single slot backchannel at this time, so we don't bother | ||
118 | * checking the used_slots bit array on the table. The lower layer guarantees | ||
119 | * a single outstanding callback request at a time. | ||
120 | */ | ||
121 | static int | ||
122 | validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid) | ||
123 | { | ||
124 | struct nfs4_slot *slot; | ||
125 | |||
126 | dprintk("%s enter. slotid %d seqid %d\n", | ||
127 | __func__, slotid, seqid); | ||
128 | |||
129 | if (slotid > NFS41_BC_MAX_CALLBACKS) | ||
130 | return htonl(NFS4ERR_BADSLOT); | ||
131 | |||
132 | slot = tbl->slots + slotid; | ||
133 | dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr); | ||
134 | |||
135 | /* Normal */ | ||
136 | if (likely(seqid == slot->seq_nr + 1)) { | ||
137 | slot->seq_nr++; | ||
138 | return htonl(NFS4_OK); | ||
139 | } | ||
140 | |||
141 | /* Replay */ | ||
142 | if (seqid == slot->seq_nr) { | ||
143 | dprintk("%s seqid %d is a replay - no DRC available\n", | ||
144 | __func__, seqid); | ||
145 | return htonl(NFS4_OK); | ||
146 | } | ||
147 | |||
148 | /* Wraparound */ | ||
149 | if (seqid == 1 && (slot->seq_nr + 1) == 0) { | ||
150 | slot->seq_nr = 1; | ||
151 | return htonl(NFS4_OK); | ||
152 | } | ||
153 | |||
154 | /* Misordered request */ | ||
155 | return htonl(NFS4ERR_SEQ_MISORDERED); | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Returns a pointer to a held 'struct nfs_client' that matches the server's | ||
160 | * address, major version number, and session ID. It is the caller's | ||
161 | * responsibility to release the returned reference. | ||
162 | * | ||
163 | * Returns NULL if there are no connections with sessions, or if no session | ||
164 | * matches the one of interest. | ||
165 | */ | ||
166 | static struct nfs_client *find_client_with_session( | ||
167 | const struct sockaddr *addr, u32 nfsversion, | ||
168 | struct nfs4_sessionid *sessionid) | ||
169 | { | ||
170 | struct nfs_client *clp; | ||
171 | |||
172 | clp = nfs_find_client(addr, 4); | ||
173 | if (clp == NULL) | ||
174 | return NULL; | ||
175 | |||
176 | do { | ||
177 | struct nfs_client *prev = clp; | ||
178 | |||
179 | if (clp->cl_session != NULL) { | ||
180 | if (memcmp(clp->cl_session->sess_id.data, | ||
181 | sessionid->data, | ||
182 | NFS4_MAX_SESSIONID_LEN) == 0) { | ||
183 | /* Returns a held reference to clp */ | ||
184 | return clp; | ||
185 | } | ||
186 | } | ||
187 | clp = nfs_find_client_next(prev); | ||
188 | nfs_put_client(prev); | ||
189 | } while (clp != NULL); | ||
190 | |||
191 | return NULL; | ||
192 | } | ||
193 | |||
194 | /* FIXME: referring calls should be processed */ | ||
195 | unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
196 | struct cb_sequenceres *res) | ||
197 | { | ||
198 | struct nfs_client *clp; | ||
199 | int i, status; | ||
200 | |||
201 | for (i = 0; i < args->csa_nrclists; i++) | ||
202 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
203 | kfree(args->csa_rclists); | ||
204 | |||
205 | status = htonl(NFS4ERR_BADSESSION); | ||
206 | clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid); | ||
207 | if (clp == NULL) | ||
208 | goto out; | ||
209 | |||
210 | status = validate_seqid(&clp->cl_session->bc_slot_table, | ||
211 | args->csa_slotid, args->csa_sequenceid); | ||
212 | if (status) | ||
213 | goto out_putclient; | ||
214 | |||
215 | memcpy(&res->csr_sessionid, &args->csa_sessionid, | ||
216 | sizeof(res->csr_sessionid)); | ||
217 | res->csr_sequenceid = args->csa_sequenceid; | ||
218 | res->csr_slotid = args->csa_slotid; | ||
219 | res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | ||
220 | res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | ||
221 | |||
222 | out_putclient: | ||
223 | nfs_put_client(clp); | ||
224 | out: | ||
225 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
226 | res->csr_status = status; | ||
227 | return res->csr_status; | ||
228 | } | ||
229 | |||
230 | #endif /* CONFIG_NFS_V4_1 */ | ||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index dd0ef34b5845..e5a2dac5f715 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -20,6 +20,11 @@ | |||
20 | 2 + 2 + 3 + 3) | 20 | 2 + 2 + 3 + 3) |
21 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 21 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
22 | 22 | ||
23 | #if defined(CONFIG_NFS_V4_1) | ||
24 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ | ||
25 | 4 + 1 + 3) | ||
26 | #endif /* CONFIG_NFS_V4_1 */ | ||
27 | |||
23 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 28 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
24 | 29 | ||
25 | typedef __be32 (*callback_process_op_t)(void *, void *); | 30 | typedef __be32 (*callback_process_op_t)(void *, void *); |
@@ -132,7 +137,6 @@ static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) | |||
132 | static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) | 137 | static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) |
133 | { | 138 | { |
134 | __be32 *p; | 139 | __be32 *p; |
135 | unsigned int minor_version; | ||
136 | __be32 status; | 140 | __be32 status; |
137 | 141 | ||
138 | status = decode_string(xdr, &hdr->taglen, &hdr->tag); | 142 | status = decode_string(xdr, &hdr->taglen, &hdr->tag); |
@@ -147,15 +151,19 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
147 | p = read_buf(xdr, 12); | 151 | p = read_buf(xdr, 12); |
148 | if (unlikely(p == NULL)) | 152 | if (unlikely(p == NULL)) |
149 | return htonl(NFS4ERR_RESOURCE); | 153 | return htonl(NFS4ERR_RESOURCE); |
150 | minor_version = ntohl(*p++); | 154 | hdr->minorversion = ntohl(*p++); |
151 | /* Check minor version is zero. */ | 155 | /* Check minor version is zero or one. */ |
152 | if (minor_version != 0) { | 156 | if (hdr->minorversion <= 1) { |
153 | printk(KERN_WARNING "%s: NFSv4 server callback with illegal minor version %u!\n", | 157 | p++; /* skip callback_ident */ |
154 | __func__, minor_version); | 158 | } else { |
159 | printk(KERN_WARNING "%s: NFSv4 server callback with " | ||
160 | "illegal minor version %u!\n", | ||
161 | __func__, hdr->minorversion); | ||
155 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | 162 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); |
156 | } | 163 | } |
157 | hdr->callback_ident = ntohl(*p++); | ||
158 | hdr->nops = ntohl(*p); | 164 | hdr->nops = ntohl(*p); |
165 | dprintk("%s: minorversion %d nops %d\n", __func__, | ||
166 | hdr->minorversion, hdr->nops); | ||
159 | return 0; | 167 | return 0; |
160 | } | 168 | } |
161 | 169 | ||
@@ -204,6 +212,122 @@ out: | |||
204 | return status; | 212 | return status; |
205 | } | 213 | } |
206 | 214 | ||
215 | #if defined(CONFIG_NFS_V4_1) | ||
216 | |||
217 | static unsigned decode_sessionid(struct xdr_stream *xdr, | ||
218 | struct nfs4_sessionid *sid) | ||
219 | { | ||
220 | uint32_t *p; | ||
221 | int len = NFS4_MAX_SESSIONID_LEN; | ||
222 | |||
223 | p = read_buf(xdr, len); | ||
224 | if (unlikely(p == NULL)) | ||
225 | return htonl(NFS4ERR_RESOURCE);; | ||
226 | |||
227 | memcpy(sid->data, p, len); | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static unsigned decode_rc_list(struct xdr_stream *xdr, | ||
232 | struct referring_call_list *rc_list) | ||
233 | { | ||
234 | uint32_t *p; | ||
235 | int i; | ||
236 | unsigned status; | ||
237 | |||
238 | status = decode_sessionid(xdr, &rc_list->rcl_sessionid); | ||
239 | if (status) | ||
240 | goto out; | ||
241 | |||
242 | status = htonl(NFS4ERR_RESOURCE); | ||
243 | p = read_buf(xdr, sizeof(uint32_t)); | ||
244 | if (unlikely(p == NULL)) | ||
245 | goto out; | ||
246 | |||
247 | rc_list->rcl_nrefcalls = ntohl(*p++); | ||
248 | if (rc_list->rcl_nrefcalls) { | ||
249 | p = read_buf(xdr, | ||
250 | rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t)); | ||
251 | if (unlikely(p == NULL)) | ||
252 | goto out; | ||
253 | rc_list->rcl_refcalls = kmalloc(rc_list->rcl_nrefcalls * | ||
254 | sizeof(*rc_list->rcl_refcalls), | ||
255 | GFP_KERNEL); | ||
256 | if (unlikely(rc_list->rcl_refcalls == NULL)) | ||
257 | goto out; | ||
258 | for (i = 0; i < rc_list->rcl_nrefcalls; i++) { | ||
259 | rc_list->rcl_refcalls[i].rc_sequenceid = ntohl(*p++); | ||
260 | rc_list->rcl_refcalls[i].rc_slotid = ntohl(*p++); | ||
261 | } | ||
262 | } | ||
263 | status = 0; | ||
264 | |||
265 | out: | ||
266 | return status; | ||
267 | } | ||
268 | |||
269 | static unsigned decode_cb_sequence_args(struct svc_rqst *rqstp, | ||
270 | struct xdr_stream *xdr, | ||
271 | struct cb_sequenceargs *args) | ||
272 | { | ||
273 | uint32_t *p; | ||
274 | int i; | ||
275 | unsigned status; | ||
276 | |||
277 | status = decode_sessionid(xdr, &args->csa_sessionid); | ||
278 | if (status) | ||
279 | goto out; | ||
280 | |||
281 | status = htonl(NFS4ERR_RESOURCE); | ||
282 | p = read_buf(xdr, 5 * sizeof(uint32_t)); | ||
283 | if (unlikely(p == NULL)) | ||
284 | goto out; | ||
285 | |||
286 | args->csa_addr = svc_addr(rqstp); | ||
287 | args->csa_sequenceid = ntohl(*p++); | ||
288 | args->csa_slotid = ntohl(*p++); | ||
289 | args->csa_highestslotid = ntohl(*p++); | ||
290 | args->csa_cachethis = ntohl(*p++); | ||
291 | args->csa_nrclists = ntohl(*p++); | ||
292 | args->csa_rclists = NULL; | ||
293 | if (args->csa_nrclists) { | ||
294 | args->csa_rclists = kmalloc(args->csa_nrclists * | ||
295 | sizeof(*args->csa_rclists), | ||
296 | GFP_KERNEL); | ||
297 | if (unlikely(args->csa_rclists == NULL)) | ||
298 | goto out; | ||
299 | |||
300 | for (i = 0; i < args->csa_nrclists; i++) { | ||
301 | status = decode_rc_list(xdr, &args->csa_rclists[i]); | ||
302 | if (status) | ||
303 | goto out_free; | ||
304 | } | ||
305 | } | ||
306 | status = 0; | ||
307 | |||
308 | dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u slotid %u " | ||
309 | "highestslotid %u cachethis %d nrclists %u\n", | ||
310 | __func__, | ||
311 | ((u32 *)&args->csa_sessionid)[0], | ||
312 | ((u32 *)&args->csa_sessionid)[1], | ||
313 | ((u32 *)&args->csa_sessionid)[2], | ||
314 | ((u32 *)&args->csa_sessionid)[3], | ||
315 | args->csa_sequenceid, args->csa_slotid, | ||
316 | args->csa_highestslotid, args->csa_cachethis, | ||
317 | args->csa_nrclists); | ||
318 | out: | ||
319 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
320 | return status; | ||
321 | |||
322 | out_free: | ||
323 | for (i = 0; i < args->csa_nrclists; i++) | ||
324 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
325 | kfree(args->csa_rclists); | ||
326 | goto out; | ||
327 | } | ||
328 | |||
329 | #endif /* CONFIG_NFS_V4_1 */ | ||
330 | |||
207 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) | 331 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) |
208 | { | 332 | { |
209 | __be32 *p; | 333 | __be32 *p; |
@@ -353,31 +477,134 @@ out: | |||
353 | return status; | 477 | return status; |
354 | } | 478 | } |
355 | 479 | ||
356 | static __be32 process_op(struct svc_rqst *rqstp, | 480 | #if defined(CONFIG_NFS_V4_1) |
481 | |||
482 | static unsigned encode_sessionid(struct xdr_stream *xdr, | ||
483 | const struct nfs4_sessionid *sid) | ||
484 | { | ||
485 | uint32_t *p; | ||
486 | int len = NFS4_MAX_SESSIONID_LEN; | ||
487 | |||
488 | p = xdr_reserve_space(xdr, len); | ||
489 | if (unlikely(p == NULL)) | ||
490 | return htonl(NFS4ERR_RESOURCE); | ||
491 | |||
492 | memcpy(p, sid, len); | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static unsigned encode_cb_sequence_res(struct svc_rqst *rqstp, | ||
497 | struct xdr_stream *xdr, | ||
498 | const struct cb_sequenceres *res) | ||
499 | { | ||
500 | uint32_t *p; | ||
501 | unsigned status = res->csr_status; | ||
502 | |||
503 | if (unlikely(status != 0)) | ||
504 | goto out; | ||
505 | |||
506 | encode_sessionid(xdr, &res->csr_sessionid); | ||
507 | |||
508 | p = xdr_reserve_space(xdr, 4 * sizeof(uint32_t)); | ||
509 | if (unlikely(p == NULL)) | ||
510 | return htonl(NFS4ERR_RESOURCE); | ||
511 | |||
512 | *p++ = htonl(res->csr_sequenceid); | ||
513 | *p++ = htonl(res->csr_slotid); | ||
514 | *p++ = htonl(res->csr_highestslotid); | ||
515 | *p++ = htonl(res->csr_target_highestslotid); | ||
516 | out: | ||
517 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
518 | return status; | ||
519 | } | ||
520 | |||
521 | static __be32 | ||
522 | preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | ||
523 | { | ||
524 | if (op_nr == OP_CB_SEQUENCE) { | ||
525 | if (nop != 0) | ||
526 | return htonl(NFS4ERR_SEQUENCE_POS); | ||
527 | } else { | ||
528 | if (nop == 0) | ||
529 | return htonl(NFS4ERR_OP_NOT_IN_SESSION); | ||
530 | } | ||
531 | |||
532 | switch (op_nr) { | ||
533 | case OP_CB_GETATTR: | ||
534 | case OP_CB_RECALL: | ||
535 | case OP_CB_SEQUENCE: | ||
536 | *op = &callback_ops[op_nr]; | ||
537 | break; | ||
538 | |||
539 | case OP_CB_LAYOUTRECALL: | ||
540 | case OP_CB_NOTIFY_DEVICEID: | ||
541 | case OP_CB_NOTIFY: | ||
542 | case OP_CB_PUSH_DELEG: | ||
543 | case OP_CB_RECALL_ANY: | ||
544 | case OP_CB_RECALLABLE_OBJ_AVAIL: | ||
545 | case OP_CB_RECALL_SLOT: | ||
546 | case OP_CB_WANTS_CANCELLED: | ||
547 | case OP_CB_NOTIFY_LOCK: | ||
548 | return htonl(NFS4ERR_NOTSUPP); | ||
549 | |||
550 | default: | ||
551 | return htonl(NFS4ERR_OP_ILLEGAL); | ||
552 | } | ||
553 | |||
554 | return htonl(NFS_OK); | ||
555 | } | ||
556 | |||
557 | #else /* CONFIG_NFS_V4_1 */ | ||
558 | |||
559 | static __be32 | ||
560 | preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | ||
561 | { | ||
562 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | ||
563 | } | ||
564 | |||
565 | #endif /* CONFIG_NFS_V4_1 */ | ||
566 | |||
567 | static __be32 | ||
568 | preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) | ||
569 | { | ||
570 | switch (op_nr) { | ||
571 | case OP_CB_GETATTR: | ||
572 | case OP_CB_RECALL: | ||
573 | *op = &callback_ops[op_nr]; | ||
574 | break; | ||
575 | default: | ||
576 | return htonl(NFS4ERR_OP_ILLEGAL); | ||
577 | } | ||
578 | |||
579 | return htonl(NFS_OK); | ||
580 | } | ||
581 | |||
582 | static __be32 process_op(uint32_t minorversion, int nop, | ||
583 | struct svc_rqst *rqstp, | ||
357 | struct xdr_stream *xdr_in, void *argp, | 584 | struct xdr_stream *xdr_in, void *argp, |
358 | struct xdr_stream *xdr_out, void *resp) | 585 | struct xdr_stream *xdr_out, void *resp) |
359 | { | 586 | { |
360 | struct callback_op *op = &callback_ops[0]; | 587 | struct callback_op *op = &callback_ops[0]; |
361 | unsigned int op_nr = OP_CB_ILLEGAL; | 588 | unsigned int op_nr = OP_CB_ILLEGAL; |
362 | __be32 status = 0; | 589 | __be32 status; |
363 | long maxlen; | 590 | long maxlen; |
364 | __be32 res; | 591 | __be32 res; |
365 | 592 | ||
366 | dprintk("%s: start\n", __func__); | 593 | dprintk("%s: start\n", __func__); |
367 | status = decode_op_hdr(xdr_in, &op_nr); | 594 | status = decode_op_hdr(xdr_in, &op_nr); |
368 | if (likely(status == 0)) { | 595 | if (unlikely(status)) { |
369 | switch (op_nr) { | 596 | status = htonl(NFS4ERR_OP_ILLEGAL); |
370 | case OP_CB_GETATTR: | 597 | goto out; |
371 | case OP_CB_RECALL: | ||
372 | op = &callback_ops[op_nr]; | ||
373 | break; | ||
374 | default: | ||
375 | op_nr = OP_CB_ILLEGAL; | ||
376 | op = &callback_ops[0]; | ||
377 | status = htonl(NFS4ERR_OP_ILLEGAL); | ||
378 | } | ||
379 | } | 598 | } |
380 | 599 | ||
600 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", | ||
601 | __func__, minorversion, nop, op_nr); | ||
602 | |||
603 | status = minorversion ? preprocess_nfs41_op(nop, op_nr, &op) : | ||
604 | preprocess_nfs4_op(op_nr, &op); | ||
605 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) | ||
606 | op_nr = OP_CB_ILLEGAL; | ||
607 | out: | ||
381 | maxlen = xdr_out->end - xdr_out->p; | 608 | maxlen = xdr_out->end - xdr_out->p; |
382 | if (maxlen > 0 && maxlen < PAGE_SIZE) { | 609 | if (maxlen > 0 && maxlen < PAGE_SIZE) { |
383 | if (likely(status == 0 && op->decode_args != NULL)) | 610 | if (likely(status == 0 && op->decode_args != NULL)) |
@@ -425,7 +652,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
425 | return rpc_system_err; | 652 | return rpc_system_err; |
426 | 653 | ||
427 | while (status == 0 && nops != hdr_arg.nops) { | 654 | while (status == 0 && nops != hdr_arg.nops) { |
428 | status = process_op(rqstp, &xdr_in, argp, &xdr_out, resp); | 655 | status = process_op(hdr_arg.minorversion, nops, |
656 | rqstp, &xdr_in, argp, &xdr_out, resp); | ||
429 | nops++; | 657 | nops++; |
430 | } | 658 | } |
431 | 659 | ||
@@ -452,7 +680,15 @@ static struct callback_op callback_ops[] = { | |||
452 | .process_op = (callback_process_op_t)nfs4_callback_recall, | 680 | .process_op = (callback_process_op_t)nfs4_callback_recall, |
453 | .decode_args = (callback_decode_arg_t)decode_recall_args, | 681 | .decode_args = (callback_decode_arg_t)decode_recall_args, |
454 | .res_maxsize = CB_OP_RECALL_RES_MAXSZ, | 682 | .res_maxsize = CB_OP_RECALL_RES_MAXSZ, |
455 | } | 683 | }, |
684 | #if defined(CONFIG_NFS_V4_1) | ||
685 | [OP_CB_SEQUENCE] = { | ||
686 | .process_op = (callback_process_op_t)nfs4_callback_sequence, | ||
687 | .decode_args = (callback_decode_arg_t)decode_cb_sequence_args, | ||
688 | .encode_res = (callback_encode_res_t)encode_cb_sequence_res, | ||
689 | .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ, | ||
690 | }, | ||
691 | #endif /* CONFIG_NFS_V4_1 */ | ||
456 | }; | 692 | }; |
457 | 693 | ||
458 | /* | 694 | /* |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 75c9cd2aa119..c2d061675d80 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/in6.h> | 37 | #include <linux/in6.h> |
38 | #include <net/ipv6.h> | 38 | #include <net/ipv6.h> |
39 | #include <linux/nfs_xdr.h> | 39 | #include <linux/nfs_xdr.h> |
40 | #include <linux/sunrpc/bc_xprt.h> | ||
40 | 41 | ||
41 | #include <asm/system.h> | 42 | #include <asm/system.h> |
42 | 43 | ||
@@ -102,6 +103,7 @@ struct nfs_client_initdata { | |||
102 | size_t addrlen; | 103 | size_t addrlen; |
103 | const struct nfs_rpc_ops *rpc_ops; | 104 | const struct nfs_rpc_ops *rpc_ops; |
104 | int proto; | 105 | int proto; |
106 | u32 minorversion; | ||
105 | }; | 107 | }; |
106 | 108 | ||
107 | /* | 109 | /* |
@@ -114,18 +116,13 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
114 | { | 116 | { |
115 | struct nfs_client *clp; | 117 | struct nfs_client *clp; |
116 | struct rpc_cred *cred; | 118 | struct rpc_cred *cred; |
119 | int err = -ENOMEM; | ||
117 | 120 | ||
118 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) | 121 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) |
119 | goto error_0; | 122 | goto error_0; |
120 | 123 | ||
121 | clp->rpc_ops = cl_init->rpc_ops; | 124 | clp->rpc_ops = cl_init->rpc_ops; |
122 | 125 | ||
123 | if (cl_init->rpc_ops->version == 4) { | ||
124 | if (nfs_callback_up() < 0) | ||
125 | goto error_2; | ||
126 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
127 | } | ||
128 | |||
129 | atomic_set(&clp->cl_count, 1); | 126 | atomic_set(&clp->cl_count, 1); |
130 | clp->cl_cons_state = NFS_CS_INITING; | 127 | clp->cl_cons_state = NFS_CS_INITING; |
131 | 128 | ||
@@ -133,9 +130,10 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
133 | clp->cl_addrlen = cl_init->addrlen; | 130 | clp->cl_addrlen = cl_init->addrlen; |
134 | 131 | ||
135 | if (cl_init->hostname) { | 132 | if (cl_init->hostname) { |
133 | err = -ENOMEM; | ||
136 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); | 134 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); |
137 | if (!clp->cl_hostname) | 135 | if (!clp->cl_hostname) |
138 | goto error_3; | 136 | goto error_cleanup; |
139 | } | 137 | } |
140 | 138 | ||
141 | INIT_LIST_HEAD(&clp->cl_superblocks); | 139 | INIT_LIST_HEAD(&clp->cl_superblocks); |
@@ -150,6 +148,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
150 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | 148 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); |
151 | clp->cl_boot_time = CURRENT_TIME; | 149 | clp->cl_boot_time = CURRENT_TIME; |
152 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 150 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
151 | clp->cl_minorversion = cl_init->minorversion; | ||
153 | #endif | 152 | #endif |
154 | cred = rpc_lookup_machine_cred(); | 153 | cred = rpc_lookup_machine_cred(); |
155 | if (!IS_ERR(cred)) | 154 | if (!IS_ERR(cred)) |
@@ -159,13 +158,10 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
159 | 158 | ||
160 | return clp; | 159 | return clp; |
161 | 160 | ||
162 | error_3: | 161 | error_cleanup: |
163 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
164 | nfs_callback_down(); | ||
165 | error_2: | ||
166 | kfree(clp); | 162 | kfree(clp); |
167 | error_0: | 163 | error_0: |
168 | return NULL; | 164 | return ERR_PTR(err); |
169 | } | 165 | } |
170 | 166 | ||
171 | static void nfs4_shutdown_client(struct nfs_client *clp) | 167 | static void nfs4_shutdown_client(struct nfs_client *clp) |
@@ -182,12 +178,42 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
182 | } | 178 | } |
183 | 179 | ||
184 | /* | 180 | /* |
181 | * Destroy the NFS4 callback service | ||
182 | */ | ||
183 | static void nfs4_destroy_callback(struct nfs_client *clp) | ||
184 | { | ||
185 | #ifdef CONFIG_NFS_V4 | ||
186 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
187 | nfs_callback_down(clp->cl_minorversion); | ||
188 | #endif /* CONFIG_NFS_V4 */ | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * Clears/puts all minor version specific parts from an nfs_client struct | ||
193 | * reverting it to minorversion 0. | ||
194 | */ | ||
195 | static void nfs4_clear_client_minor_version(struct nfs_client *clp) | ||
196 | { | ||
197 | #ifdef CONFIG_NFS_V4_1 | ||
198 | if (nfs4_has_session(clp)) { | ||
199 | nfs4_destroy_session(clp->cl_session); | ||
200 | clp->cl_session = NULL; | ||
201 | } | ||
202 | |||
203 | clp->cl_call_sync = _nfs4_call_sync; | ||
204 | #endif /* CONFIG_NFS_V4_1 */ | ||
205 | |||
206 | nfs4_destroy_callback(clp); | ||
207 | } | ||
208 | |||
209 | /* | ||
185 | * Destroy a shared client record | 210 | * Destroy a shared client record |
186 | */ | 211 | */ |
187 | static void nfs_free_client(struct nfs_client *clp) | 212 | static void nfs_free_client(struct nfs_client *clp) |
188 | { | 213 | { |
189 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); | 214 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); |
190 | 215 | ||
216 | nfs4_clear_client_minor_version(clp); | ||
191 | nfs4_shutdown_client(clp); | 217 | nfs4_shutdown_client(clp); |
192 | 218 | ||
193 | nfs_fscache_release_client_cookie(clp); | 219 | nfs_fscache_release_client_cookie(clp); |
@@ -196,9 +222,6 @@ static void nfs_free_client(struct nfs_client *clp) | |||
196 | if (!IS_ERR(clp->cl_rpcclient)) | 222 | if (!IS_ERR(clp->cl_rpcclient)) |
197 | rpc_shutdown_client(clp->cl_rpcclient); | 223 | rpc_shutdown_client(clp->cl_rpcclient); |
198 | 224 | ||
199 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
200 | nfs_callback_down(); | ||
201 | |||
202 | if (clp->cl_machine_cred != NULL) | 225 | if (clp->cl_machine_cred != NULL) |
203 | put_rpccred(clp->cl_machine_cred); | 226 | put_rpccred(clp->cl_machine_cred); |
204 | 227 | ||
@@ -347,7 +370,8 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion) | |||
347 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | 370 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; |
348 | 371 | ||
349 | /* Don't match clients that failed to initialise properly */ | 372 | /* Don't match clients that failed to initialise properly */ |
350 | if (clp->cl_cons_state != NFS_CS_READY) | 373 | if (!(clp->cl_cons_state == NFS_CS_READY || |
374 | clp->cl_cons_state == NFS_CS_SESSION_INITING)) | ||
351 | continue; | 375 | continue; |
352 | 376 | ||
353 | /* Different NFS versions cannot share the same nfs_client */ | 377 | /* Different NFS versions cannot share the same nfs_client */ |
@@ -420,7 +444,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat | |||
420 | 444 | ||
421 | if (clp->cl_proto != data->proto) | 445 | if (clp->cl_proto != data->proto) |
422 | continue; | 446 | continue; |
423 | 447 | /* Match nfsv4 minorversion */ | |
448 | if (clp->cl_minorversion != data->minorversion) | ||
449 | continue; | ||
424 | /* Match the full socket address */ | 450 | /* Match the full socket address */ |
425 | if (!nfs_sockaddr_cmp(sap, clap)) | 451 | if (!nfs_sockaddr_cmp(sap, clap)) |
426 | continue; | 452 | continue; |
@@ -456,9 +482,10 @@ static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_in | |||
456 | spin_unlock(&nfs_client_lock); | 482 | spin_unlock(&nfs_client_lock); |
457 | 483 | ||
458 | new = nfs_alloc_client(cl_init); | 484 | new = nfs_alloc_client(cl_init); |
459 | } while (new); | 485 | } while (!IS_ERR(new)); |
460 | 486 | ||
461 | return ERR_PTR(-ENOMEM); | 487 | dprintk("--> nfs_get_client() = %ld [failed]\n", PTR_ERR(new)); |
488 | return new; | ||
462 | 489 | ||
463 | /* install a new client and return with it unready */ | 490 | /* install a new client and return with it unready */ |
464 | install_client: | 491 | install_client: |
@@ -478,7 +505,7 @@ found_client: | |||
478 | nfs_free_client(new); | 505 | nfs_free_client(new); |
479 | 506 | ||
480 | error = wait_event_killable(nfs_client_active_wq, | 507 | error = wait_event_killable(nfs_client_active_wq, |
481 | clp->cl_cons_state != NFS_CS_INITING); | 508 | clp->cl_cons_state < NFS_CS_INITING); |
482 | if (error < 0) { | 509 | if (error < 0) { |
483 | nfs_put_client(clp); | 510 | nfs_put_client(clp); |
484 | return ERR_PTR(-ERESTARTSYS); | 511 | return ERR_PTR(-ERESTARTSYS); |
@@ -499,13 +526,29 @@ found_client: | |||
499 | /* | 526 | /* |
500 | * Mark a server as ready or failed | 527 | * Mark a server as ready or failed |
501 | */ | 528 | */ |
502 | static void nfs_mark_client_ready(struct nfs_client *clp, int state) | 529 | void nfs_mark_client_ready(struct nfs_client *clp, int state) |
503 | { | 530 | { |
504 | clp->cl_cons_state = state; | 531 | clp->cl_cons_state = state; |
505 | wake_up_all(&nfs_client_active_wq); | 532 | wake_up_all(&nfs_client_active_wq); |
506 | } | 533 | } |
507 | 534 | ||
508 | /* | 535 | /* |
536 | * With sessions, the client is not marked ready until after a | ||
537 | * successful EXCHANGE_ID and CREATE_SESSION. | ||
538 | * | ||
539 | * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate | ||
540 | * other versions of NFS can be tried. | ||
541 | */ | ||
542 | int nfs4_check_client_ready(struct nfs_client *clp) | ||
543 | { | ||
544 | if (!nfs4_has_session(clp)) | ||
545 | return 0; | ||
546 | if (clp->cl_cons_state < NFS_CS_READY) | ||
547 | return -EPROTONOSUPPORT; | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | /* | ||
509 | * Initialise the timeout values for a connection | 552 | * Initialise the timeout values for a connection |
510 | */ | 553 | */ |
511 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | 554 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, |
@@ -1050,6 +1093,61 @@ error: | |||
1050 | 1093 | ||
1051 | #ifdef CONFIG_NFS_V4 | 1094 | #ifdef CONFIG_NFS_V4 |
1052 | /* | 1095 | /* |
1096 | * Initialize the NFS4 callback service | ||
1097 | */ | ||
1098 | static int nfs4_init_callback(struct nfs_client *clp) | ||
1099 | { | ||
1100 | int error; | ||
1101 | |||
1102 | if (clp->rpc_ops->version == 4) { | ||
1103 | if (nfs4_has_session(clp)) { | ||
1104 | error = xprt_setup_backchannel( | ||
1105 | clp->cl_rpcclient->cl_xprt, | ||
1106 | NFS41_BC_MIN_CALLBACKS); | ||
1107 | if (error < 0) | ||
1108 | return error; | ||
1109 | } | ||
1110 | |||
1111 | error = nfs_callback_up(clp->cl_minorversion, | ||
1112 | clp->cl_rpcclient->cl_xprt); | ||
1113 | if (error < 0) { | ||
1114 | dprintk("%s: failed to start callback. Error = %d\n", | ||
1115 | __func__, error); | ||
1116 | return error; | ||
1117 | } | ||
1118 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
1119 | } | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | /* | ||
1124 | * Initialize the minor version specific parts of an NFS4 client record | ||
1125 | */ | ||
1126 | static int nfs4_init_client_minor_version(struct nfs_client *clp) | ||
1127 | { | ||
1128 | clp->cl_call_sync = _nfs4_call_sync; | ||
1129 | |||
1130 | #if defined(CONFIG_NFS_V4_1) | ||
1131 | if (clp->cl_minorversion) { | ||
1132 | struct nfs4_session *session = NULL; | ||
1133 | /* | ||
1134 | * Create the session and mark it expired. | ||
1135 | * When a SEQUENCE operation encounters the expired session | ||
1136 | * it will do session recovery to initialize it. | ||
1137 | */ | ||
1138 | session = nfs4_alloc_session(clp); | ||
1139 | if (!session) | ||
1140 | return -ENOMEM; | ||
1141 | |||
1142 | clp->cl_session = session; | ||
1143 | clp->cl_call_sync = _nfs4_call_sync_session; | ||
1144 | } | ||
1145 | #endif /* CONFIG_NFS_V4_1 */ | ||
1146 | |||
1147 | return nfs4_init_callback(clp); | ||
1148 | } | ||
1149 | |||
1150 | /* | ||
1053 | * Initialise an NFS4 client record | 1151 | * Initialise an NFS4 client record |
1054 | */ | 1152 | */ |
1055 | static int nfs4_init_client(struct nfs_client *clp, | 1153 | static int nfs4_init_client(struct nfs_client *clp, |
@@ -1083,7 +1181,12 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
1083 | } | 1181 | } |
1084 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); | 1182 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); |
1085 | 1183 | ||
1086 | nfs_mark_client_ready(clp, NFS_CS_READY); | 1184 | error = nfs4_init_client_minor_version(clp); |
1185 | if (error < 0) | ||
1186 | goto error; | ||
1187 | |||
1188 | if (!nfs4_has_session(clp)) | ||
1189 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
1087 | return 0; | 1190 | return 0; |
1088 | 1191 | ||
1089 | error: | 1192 | error: |
@@ -1101,7 +1204,8 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1101 | const size_t addrlen, | 1204 | const size_t addrlen, |
1102 | const char *ip_addr, | 1205 | const char *ip_addr, |
1103 | rpc_authflavor_t authflavour, | 1206 | rpc_authflavor_t authflavour, |
1104 | int proto, const struct rpc_timeout *timeparms) | 1207 | int proto, const struct rpc_timeout *timeparms, |
1208 | u32 minorversion) | ||
1105 | { | 1209 | { |
1106 | struct nfs_client_initdata cl_init = { | 1210 | struct nfs_client_initdata cl_init = { |
1107 | .hostname = hostname, | 1211 | .hostname = hostname, |
@@ -1109,6 +1213,7 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1109 | .addrlen = addrlen, | 1213 | .addrlen = addrlen, |
1110 | .rpc_ops = &nfs_v4_clientops, | 1214 | .rpc_ops = &nfs_v4_clientops, |
1111 | .proto = proto, | 1215 | .proto = proto, |
1216 | .minorversion = minorversion, | ||
1112 | }; | 1217 | }; |
1113 | struct nfs_client *clp; | 1218 | struct nfs_client *clp; |
1114 | int error; | 1219 | int error; |
@@ -1138,6 +1243,36 @@ error: | |||
1138 | } | 1243 | } |
1139 | 1244 | ||
1140 | /* | 1245 | /* |
1246 | * Initialize a session. | ||
1247 | * Note: save the mount rsize and wsize for create_server negotiation. | ||
1248 | */ | ||
1249 | static void nfs4_init_session(struct nfs_client *clp, | ||
1250 | unsigned int wsize, unsigned int rsize) | ||
1251 | { | ||
1252 | #if defined(CONFIG_NFS_V4_1) | ||
1253 | if (nfs4_has_session(clp)) { | ||
1254 | clp->cl_session->fc_attrs.max_rqst_sz = wsize; | ||
1255 | clp->cl_session->fc_attrs.max_resp_sz = rsize; | ||
1256 | } | ||
1257 | #endif /* CONFIG_NFS_V4_1 */ | ||
1258 | } | ||
1259 | |||
1260 | /* | ||
1261 | * Session has been established, and the client marked ready. | ||
1262 | * Set the mount rsize and wsize with negotiated fore channel | ||
1263 | * attributes which will be bound checked in nfs_server_set_fsinfo. | ||
1264 | */ | ||
1265 | static void nfs4_session_set_rwsize(struct nfs_server *server) | ||
1266 | { | ||
1267 | #ifdef CONFIG_NFS_V4_1 | ||
1268 | if (!nfs4_has_session(server->nfs_client)) | ||
1269 | return; | ||
1270 | server->rsize = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | ||
1271 | server->wsize = server->nfs_client->cl_session->fc_attrs.max_rqst_sz; | ||
1272 | #endif /* CONFIG_NFS_V4_1 */ | ||
1273 | } | ||
1274 | |||
1275 | /* | ||
1141 | * Create a version 4 volume record | 1276 | * Create a version 4 volume record |
1142 | */ | 1277 | */ |
1143 | static int nfs4_init_server(struct nfs_server *server, | 1278 | static int nfs4_init_server(struct nfs_server *server, |
@@ -1164,7 +1299,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1164 | data->client_address, | 1299 | data->client_address, |
1165 | data->auth_flavors[0], | 1300 | data->auth_flavors[0], |
1166 | data->nfs_server.protocol, | 1301 | data->nfs_server.protocol, |
1167 | &timeparms); | 1302 | &timeparms, |
1303 | data->minorversion); | ||
1168 | if (error < 0) | 1304 | if (error < 0) |
1169 | goto error; | 1305 | goto error; |
1170 | 1306 | ||
@@ -1214,6 +1350,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
1214 | BUG_ON(!server->nfs_client->rpc_ops); | 1350 | BUG_ON(!server->nfs_client->rpc_ops); |
1215 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | 1351 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); |
1216 | 1352 | ||
1353 | nfs4_init_session(server->nfs_client, server->wsize, server->rsize); | ||
1354 | |||
1217 | /* Probe the root fh to retrieve its FSID */ | 1355 | /* Probe the root fh to retrieve its FSID */ |
1218 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); | 1356 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); |
1219 | if (error < 0) | 1357 | if (error < 0) |
@@ -1224,6 +1362,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
1224 | (unsigned long long) server->fsid.minor); | 1362 | (unsigned long long) server->fsid.minor); |
1225 | dprintk("Mount FH: %d\n", mntfh->size); | 1363 | dprintk("Mount FH: %d\n", mntfh->size); |
1226 | 1364 | ||
1365 | nfs4_session_set_rwsize(server); | ||
1366 | |||
1227 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | 1367 | error = nfs_probe_fsinfo(server, mntfh, &fattr); |
1228 | if (error < 0) | 1368 | if (error < 0) |
1229 | goto error; | 1369 | goto error; |
@@ -1282,7 +1422,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1282 | parent_client->cl_ipaddr, | 1422 | parent_client->cl_ipaddr, |
1283 | data->authflavor, | 1423 | data->authflavor, |
1284 | parent_server->client->cl_xprt->prot, | 1424 | parent_server->client->cl_xprt->prot, |
1285 | parent_server->client->cl_timeout); | 1425 | parent_server->client->cl_timeout, |
1426 | parent_client->cl_minorversion); | ||
1286 | if (error < 0) | 1427 | if (error < 0) |
1287 | goto error; | 1428 | goto error; |
1288 | 1429 | ||
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 968225a88015..af05b918cb5b 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -68,29 +68,26 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ | |||
68 | { | 68 | { |
69 | struct inode *inode = state->inode; | 69 | struct inode *inode = state->inode; |
70 | struct file_lock *fl; | 70 | struct file_lock *fl; |
71 | int status; | 71 | int status = 0; |
72 | |||
73 | if (inode->i_flock == NULL) | ||
74 | goto out; | ||
72 | 75 | ||
76 | /* Protect inode->i_flock using the BKL */ | ||
77 | lock_kernel(); | ||
73 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 78 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
74 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) | 79 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) |
75 | continue; | 80 | continue; |
76 | if (nfs_file_open_context(fl->fl_file) != ctx) | 81 | if (nfs_file_open_context(fl->fl_file) != ctx) |
77 | continue; | 82 | continue; |
83 | unlock_kernel(); | ||
78 | status = nfs4_lock_delegation_recall(state, fl); | 84 | status = nfs4_lock_delegation_recall(state, fl); |
79 | if (status >= 0) | 85 | if (status < 0) |
80 | continue; | 86 | goto out; |
81 | switch (status) { | 87 | lock_kernel(); |
82 | default: | ||
83 | printk(KERN_ERR "%s: unhandled error %d.\n", | ||
84 | __func__, status); | ||
85 | case -NFS4ERR_EXPIRED: | ||
86 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | ||
87 | case -NFS4ERR_STALE_CLIENTID: | ||
88 | nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs_client); | ||
89 | goto out_err; | ||
90 | } | ||
91 | } | 88 | } |
92 | return 0; | 89 | unlock_kernel(); |
93 | out_err: | 90 | out: |
94 | return status; | 91 | return status; |
95 | } | 92 | } |
96 | 93 | ||
@@ -268,7 +265,10 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat | |||
268 | struct nfs_inode *nfsi = NFS_I(inode); | 265 | struct nfs_inode *nfsi = NFS_I(inode); |
269 | 266 | ||
270 | nfs_msync_inode(inode); | 267 | nfs_msync_inode(inode); |
271 | /* Guard against new delegated open calls */ | 268 | /* |
269 | * Guard against new delegated open/lock/unlock calls and against | ||
270 | * state recovery | ||
271 | */ | ||
272 | down_write(&nfsi->rwsem); | 272 | down_write(&nfsi->rwsem); |
273 | nfs_delegation_claim_opens(inode, &delegation->stateid); | 273 | nfs_delegation_claim_opens(inode, &delegation->stateid); |
274 | up_write(&nfsi->rwsem); | 274 | up_write(&nfsi->rwsem); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 08f6b040d289..489fc01a3204 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -259,6 +259,9 @@ static void nfs_direct_read_release(void *calldata) | |||
259 | } | 259 | } |
260 | 260 | ||
261 | static const struct rpc_call_ops nfs_read_direct_ops = { | 261 | static const struct rpc_call_ops nfs_read_direct_ops = { |
262 | #if defined(CONFIG_NFS_V4_1) | ||
263 | .rpc_call_prepare = nfs_read_prepare, | ||
264 | #endif /* CONFIG_NFS_V4_1 */ | ||
262 | .rpc_call_done = nfs_direct_read_result, | 265 | .rpc_call_done = nfs_direct_read_result, |
263 | .rpc_release = nfs_direct_read_release, | 266 | .rpc_release = nfs_direct_read_release, |
264 | }; | 267 | }; |
@@ -535,6 +538,9 @@ static void nfs_direct_commit_release(void *calldata) | |||
535 | } | 538 | } |
536 | 539 | ||
537 | static const struct rpc_call_ops nfs_commit_direct_ops = { | 540 | static const struct rpc_call_ops nfs_commit_direct_ops = { |
541 | #if defined(CONFIG_NFS_V4_1) | ||
542 | .rpc_call_prepare = nfs_write_prepare, | ||
543 | #endif /* CONFIG_NFS_V4_1 */ | ||
538 | .rpc_call_done = nfs_direct_commit_result, | 544 | .rpc_call_done = nfs_direct_commit_result, |
539 | .rpc_release = nfs_direct_commit_release, | 545 | .rpc_release = nfs_direct_commit_release, |
540 | }; | 546 | }; |
@@ -673,6 +679,9 @@ out_unlock: | |||
673 | } | 679 | } |
674 | 680 | ||
675 | static const struct rpc_call_ops nfs_write_direct_ops = { | 681 | static const struct rpc_call_ops nfs_write_direct_ops = { |
682 | #if defined(CONFIG_NFS_V4_1) | ||
683 | .rpc_call_prepare = nfs_write_prepare, | ||
684 | #endif /* CONFIG_NFS_V4_1 */ | ||
676 | .rpc_call_done = nfs_direct_write_result, | 685 | .rpc_call_done = nfs_direct_write_result, |
677 | .rpc_release = nfs_direct_write_release, | 686 | .rpc_release = nfs_direct_write_release, |
678 | }; | 687 | }; |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index ec7e27d00bc6..0055b813ec2c 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -48,6 +48,9 @@ static ssize_t nfs_file_splice_read(struct file *filp, loff_t *ppos, | |||
48 | size_t count, unsigned int flags); | 48 | size_t count, unsigned int flags); |
49 | static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov, | 49 | static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov, |
50 | unsigned long nr_segs, loff_t pos); | 50 | unsigned long nr_segs, loff_t pos); |
51 | static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | ||
52 | struct file *filp, loff_t *ppos, | ||
53 | size_t count, unsigned int flags); | ||
51 | static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, | 54 | static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, |
52 | unsigned long nr_segs, loff_t pos); | 55 | unsigned long nr_segs, loff_t pos); |
53 | static int nfs_file_flush(struct file *, fl_owner_t id); | 56 | static int nfs_file_flush(struct file *, fl_owner_t id); |
@@ -73,6 +76,7 @@ const struct file_operations nfs_file_operations = { | |||
73 | .lock = nfs_lock, | 76 | .lock = nfs_lock, |
74 | .flock = nfs_flock, | 77 | .flock = nfs_flock, |
75 | .splice_read = nfs_file_splice_read, | 78 | .splice_read = nfs_file_splice_read, |
79 | .splice_write = nfs_file_splice_write, | ||
76 | .check_flags = nfs_check_flags, | 80 | .check_flags = nfs_check_flags, |
77 | .setlease = nfs_setlease, | 81 | .setlease = nfs_setlease, |
78 | }; | 82 | }; |
@@ -587,12 +591,38 @@ out_swapfile: | |||
587 | goto out; | 591 | goto out; |
588 | } | 592 | } |
589 | 593 | ||
594 | static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | ||
595 | struct file *filp, loff_t *ppos, | ||
596 | size_t count, unsigned int flags) | ||
597 | { | ||
598 | struct dentry *dentry = filp->f_path.dentry; | ||
599 | struct inode *inode = dentry->d_inode; | ||
600 | ssize_t ret; | ||
601 | |||
602 | dprintk("NFS splice_write(%s/%s, %lu@%llu)\n", | ||
603 | dentry->d_parent->d_name.name, dentry->d_name.name, | ||
604 | (unsigned long) count, (unsigned long long) *ppos); | ||
605 | |||
606 | /* | ||
607 | * The combination of splice and an O_APPEND destination is disallowed. | ||
608 | */ | ||
609 | |||
610 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); | ||
611 | |||
612 | ret = generic_file_splice_write(pipe, filp, ppos, count, flags); | ||
613 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { | ||
614 | int err = nfs_do_fsync(nfs_file_open_context(filp), inode); | ||
615 | if (err < 0) | ||
616 | ret = err; | ||
617 | } | ||
618 | return ret; | ||
619 | } | ||
620 | |||
590 | static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) | 621 | static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) |
591 | { | 622 | { |
592 | struct inode *inode = filp->f_mapping->host; | 623 | struct inode *inode = filp->f_mapping->host; |
593 | int status = 0; | 624 | int status = 0; |
594 | 625 | ||
595 | lock_kernel(); | ||
596 | /* Try local locking first */ | 626 | /* Try local locking first */ |
597 | posix_test_lock(filp, fl); | 627 | posix_test_lock(filp, fl); |
598 | if (fl->fl_type != F_UNLCK) { | 628 | if (fl->fl_type != F_UNLCK) { |
@@ -608,7 +638,6 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) | |||
608 | 638 | ||
609 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); | 639 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); |
610 | out: | 640 | out: |
611 | unlock_kernel(); | ||
612 | return status; | 641 | return status; |
613 | out_noconflict: | 642 | out_noconflict: |
614 | fl->fl_type = F_UNLCK; | 643 | fl->fl_type = F_UNLCK; |
@@ -650,13 +679,11 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) | |||
650 | * If we're signalled while cleaning up locks on process exit, we | 679 | * If we're signalled while cleaning up locks on process exit, we |
651 | * still need to complete the unlock. | 680 | * still need to complete the unlock. |
652 | */ | 681 | */ |
653 | lock_kernel(); | ||
654 | /* Use local locking if mounted with "-onolock" */ | 682 | /* Use local locking if mounted with "-onolock" */ |
655 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) | 683 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) |
656 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); | 684 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); |
657 | else | 685 | else |
658 | status = do_vfs_lock(filp, fl); | 686 | status = do_vfs_lock(filp, fl); |
659 | unlock_kernel(); | ||
660 | return status; | 687 | return status; |
661 | } | 688 | } |
662 | 689 | ||
@@ -673,13 +700,11 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) | |||
673 | if (status != 0) | 700 | if (status != 0) |
674 | goto out; | 701 | goto out; |
675 | 702 | ||
676 | lock_kernel(); | ||
677 | /* Use local locking if mounted with "-onolock" */ | 703 | /* Use local locking if mounted with "-onolock" */ |
678 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) | 704 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) |
679 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); | 705 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); |
680 | else | 706 | else |
681 | status = do_vfs_lock(filp, fl); | 707 | status = do_vfs_lock(filp, fl); |
682 | unlock_kernel(); | ||
683 | if (status < 0) | 708 | if (status < 0) |
684 | goto out; | 709 | goto out; |
685 | /* | 710 | /* |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index e4d6a8348adf..7dd90a6769d0 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -2,6 +2,7 @@ | |||
2 | * NFS internal definitions | 2 | * NFS internal definitions |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include "nfs4_fs.h" | ||
5 | #include <linux/mount.h> | 6 | #include <linux/mount.h> |
6 | #include <linux/security.h> | 7 | #include <linux/security.h> |
7 | 8 | ||
@@ -17,6 +18,18 @@ struct nfs_string; | |||
17 | */ | 18 | */ |
18 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) | 19 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) |
19 | 20 | ||
21 | /* | ||
22 | * Determine if sessions are in use. | ||
23 | */ | ||
24 | static inline int nfs4_has_session(const struct nfs_client *clp) | ||
25 | { | ||
26 | #ifdef CONFIG_NFS_V4_1 | ||
27 | if (clp->cl_session) | ||
28 | return 1; | ||
29 | #endif /* CONFIG_NFS_V4_1 */ | ||
30 | return 0; | ||
31 | } | ||
32 | |||
20 | struct nfs_clone_mount { | 33 | struct nfs_clone_mount { |
21 | const struct super_block *sb; | 34 | const struct super_block *sb; |
22 | const struct dentry *dentry; | 35 | const struct dentry *dentry; |
@@ -30,6 +43,12 @@ struct nfs_clone_mount { | |||
30 | }; | 43 | }; |
31 | 44 | ||
32 | /* | 45 | /* |
46 | * Note: RFC 1813 doesn't limit the number of auth flavors that | ||
47 | * a server can return, so make something up. | ||
48 | */ | ||
49 | #define NFS_MAX_SECFLAVORS (12) | ||
50 | |||
51 | /* | ||
33 | * In-kernel mount arguments | 52 | * In-kernel mount arguments |
34 | */ | 53 | */ |
35 | struct nfs_parsed_mount_data { | 54 | struct nfs_parsed_mount_data { |
@@ -44,6 +63,7 @@ struct nfs_parsed_mount_data { | |||
44 | unsigned int auth_flavor_len; | 63 | unsigned int auth_flavor_len; |
45 | rpc_authflavor_t auth_flavors[1]; | 64 | rpc_authflavor_t auth_flavors[1]; |
46 | char *client_address; | 65 | char *client_address; |
66 | unsigned int minorversion; | ||
47 | char *fscache_uniq; | 67 | char *fscache_uniq; |
48 | 68 | ||
49 | struct { | 69 | struct { |
@@ -77,6 +97,8 @@ struct nfs_mount_request { | |||
77 | unsigned short protocol; | 97 | unsigned short protocol; |
78 | struct nfs_fh *fh; | 98 | struct nfs_fh *fh; |
79 | int noresvport; | 99 | int noresvport; |
100 | unsigned int *auth_flav_len; | ||
101 | rpc_authflavor_t *auth_flavs; | ||
80 | }; | 102 | }; |
81 | 103 | ||
82 | extern int nfs_mount(struct nfs_mount_request *info); | 104 | extern int nfs_mount(struct nfs_mount_request *info); |
@@ -99,6 +121,8 @@ extern void nfs_free_server(struct nfs_server *server); | |||
99 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, | 121 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, |
100 | struct nfs_fh *, | 122 | struct nfs_fh *, |
101 | struct nfs_fattr *); | 123 | struct nfs_fattr *); |
124 | extern void nfs_mark_client_ready(struct nfs_client *clp, int state); | ||
125 | extern int nfs4_check_client_ready(struct nfs_client *clp); | ||
102 | #ifdef CONFIG_PROC_FS | 126 | #ifdef CONFIG_PROC_FS |
103 | extern int __init nfs_fs_proc_init(void); | 127 | extern int __init nfs_fs_proc_init(void); |
104 | extern void nfs_fs_proc_exit(void); | 128 | extern void nfs_fs_proc_exit(void); |
@@ -146,6 +170,20 @@ extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int); | |||
146 | extern struct rpc_procinfo nfs3_procedures[]; | 170 | extern struct rpc_procinfo nfs3_procedures[]; |
147 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); | 171 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); |
148 | 172 | ||
173 | /* nfs4proc.c */ | ||
174 | static inline void nfs4_restart_rpc(struct rpc_task *task, | ||
175 | const struct nfs_client *clp) | ||
176 | { | ||
177 | #ifdef CONFIG_NFS_V4_1 | ||
178 | if (nfs4_has_session(clp) && | ||
179 | test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | ||
180 | rpc_restart_call_prepare(task); | ||
181 | return; | ||
182 | } | ||
183 | #endif /* CONFIG_NFS_V4_1 */ | ||
184 | rpc_restart_call(task); | ||
185 | } | ||
186 | |||
149 | /* nfs4xdr.c */ | 187 | /* nfs4xdr.c */ |
150 | #ifdef CONFIG_NFS_V4 | 188 | #ifdef CONFIG_NFS_V4 |
151 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); | 189 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); |
@@ -205,6 +243,38 @@ extern int nfs4_path_walk(struct nfs_server *server, | |||
205 | const char *path); | 243 | const char *path); |
206 | #endif | 244 | #endif |
207 | 245 | ||
246 | /* read.c */ | ||
247 | extern void nfs_read_prepare(struct rpc_task *task, void *calldata); | ||
248 | |||
249 | /* write.c */ | ||
250 | extern void nfs_write_prepare(struct rpc_task *task, void *calldata); | ||
251 | |||
252 | /* nfs4proc.c */ | ||
253 | extern int _nfs4_call_sync(struct nfs_server *server, | ||
254 | struct rpc_message *msg, | ||
255 | struct nfs4_sequence_args *args, | ||
256 | struct nfs4_sequence_res *res, | ||
257 | int cache_reply); | ||
258 | extern int _nfs4_call_sync_session(struct nfs_server *server, | ||
259 | struct rpc_message *msg, | ||
260 | struct nfs4_sequence_args *args, | ||
261 | struct nfs4_sequence_res *res, | ||
262 | int cache_reply); | ||
263 | |||
264 | #ifdef CONFIG_NFS_V4_1 | ||
265 | extern void nfs41_sequence_free_slot(const struct nfs_client *, | ||
266 | struct nfs4_sequence_res *res); | ||
267 | #endif /* CONFIG_NFS_V4_1 */ | ||
268 | |||
269 | static inline void nfs4_sequence_free_slot(const struct nfs_client *clp, | ||
270 | struct nfs4_sequence_res *res) | ||
271 | { | ||
272 | #ifdef CONFIG_NFS_V4_1 | ||
273 | if (nfs4_has_session(clp)) | ||
274 | nfs41_sequence_free_slot(clp, res); | ||
275 | #endif /* CONFIG_NFS_V4_1 */ | ||
276 | } | ||
277 | |||
208 | /* | 278 | /* |
209 | * Determine the device name as a string | 279 | * Determine the device name as a string |
210 | */ | 280 | */ |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index ca905a5bb1ba..38ef9eaec407 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -20,8 +20,116 @@ | |||
20 | # define NFSDBG_FACILITY NFSDBG_MOUNT | 20 | # define NFSDBG_FACILITY NFSDBG_MOUNT |
21 | #endif | 21 | #endif |
22 | 22 | ||
23 | /* | ||
24 | * Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4 | ||
25 | */ | ||
26 | #define MNTPATHLEN (1024) | ||
27 | |||
28 | /* | ||
29 | * XDR data type sizes | ||
30 | */ | ||
31 | #define encode_dirpath_sz (1 + XDR_QUADLEN(MNTPATHLEN)) | ||
32 | #define MNT_status_sz (1) | ||
33 | #define MNT_fhs_status_sz (1) | ||
34 | #define MNT_fhandle_sz XDR_QUADLEN(NFS2_FHSIZE) | ||
35 | #define MNT_fhandle3_sz (1 + XDR_QUADLEN(NFS3_FHSIZE)) | ||
36 | #define MNT_authflav3_sz (1 + NFS_MAX_SECFLAVORS) | ||
37 | |||
38 | /* | ||
39 | * XDR argument and result sizes | ||
40 | */ | ||
41 | #define MNT_enc_dirpath_sz encode_dirpath_sz | ||
42 | #define MNT_dec_mountres_sz (MNT_status_sz + MNT_fhandle_sz) | ||
43 | #define MNT_dec_mountres3_sz (MNT_status_sz + MNT_fhandle_sz + \ | ||
44 | MNT_authflav3_sz) | ||
45 | |||
46 | /* | ||
47 | * Defined by RFC 1094, section A.5 | ||
48 | */ | ||
49 | enum { | ||
50 | MOUNTPROC_NULL = 0, | ||
51 | MOUNTPROC_MNT = 1, | ||
52 | MOUNTPROC_DUMP = 2, | ||
53 | MOUNTPROC_UMNT = 3, | ||
54 | MOUNTPROC_UMNTALL = 4, | ||
55 | MOUNTPROC_EXPORT = 5, | ||
56 | }; | ||
57 | |||
58 | /* | ||
59 | * Defined by RFC 1813, section 5.2 | ||
60 | */ | ||
61 | enum { | ||
62 | MOUNTPROC3_NULL = 0, | ||
63 | MOUNTPROC3_MNT = 1, | ||
64 | MOUNTPROC3_DUMP = 2, | ||
65 | MOUNTPROC3_UMNT = 3, | ||
66 | MOUNTPROC3_UMNTALL = 4, | ||
67 | MOUNTPROC3_EXPORT = 5, | ||
68 | }; | ||
69 | |||
23 | static struct rpc_program mnt_program; | 70 | static struct rpc_program mnt_program; |
24 | 71 | ||
72 | /* | ||
73 | * Defined by OpenGroup XNFS Version 3W, chapter 8 | ||
74 | */ | ||
75 | enum mountstat { | ||
76 | MNT_OK = 0, | ||
77 | MNT_EPERM = 1, | ||
78 | MNT_ENOENT = 2, | ||
79 | MNT_EACCES = 13, | ||
80 | MNT_EINVAL = 22, | ||
81 | }; | ||
82 | |||
83 | static struct { | ||
84 | u32 status; | ||
85 | int errno; | ||
86 | } mnt_errtbl[] = { | ||
87 | { .status = MNT_OK, .errno = 0, }, | ||
88 | { .status = MNT_EPERM, .errno = -EPERM, }, | ||
89 | { .status = MNT_ENOENT, .errno = -ENOENT, }, | ||
90 | { .status = MNT_EACCES, .errno = -EACCES, }, | ||
91 | { .status = MNT_EINVAL, .errno = -EINVAL, }, | ||
92 | }; | ||
93 | |||
94 | /* | ||
95 | * Defined by RFC 1813, section 5.1.5 | ||
96 | */ | ||
97 | enum mountstat3 { | ||
98 | MNT3_OK = 0, /* no error */ | ||
99 | MNT3ERR_PERM = 1, /* Not owner */ | ||
100 | MNT3ERR_NOENT = 2, /* No such file or directory */ | ||
101 | MNT3ERR_IO = 5, /* I/O error */ | ||
102 | MNT3ERR_ACCES = 13, /* Permission denied */ | ||
103 | MNT3ERR_NOTDIR = 20, /* Not a directory */ | ||
104 | MNT3ERR_INVAL = 22, /* Invalid argument */ | ||
105 | MNT3ERR_NAMETOOLONG = 63, /* Filename too long */ | ||
106 | MNT3ERR_NOTSUPP = 10004, /* Operation not supported */ | ||
107 | MNT3ERR_SERVERFAULT = 10006, /* A failure on the server */ | ||
108 | }; | ||
109 | |||
110 | static struct { | ||
111 | u32 status; | ||
112 | int errno; | ||
113 | } mnt3_errtbl[] = { | ||
114 | { .status = MNT3_OK, .errno = 0, }, | ||
115 | { .status = MNT3ERR_PERM, .errno = -EPERM, }, | ||
116 | { .status = MNT3ERR_NOENT, .errno = -ENOENT, }, | ||
117 | { .status = MNT3ERR_IO, .errno = -EIO, }, | ||
118 | { .status = MNT3ERR_ACCES, .errno = -EACCES, }, | ||
119 | { .status = MNT3ERR_NOTDIR, .errno = -ENOTDIR, }, | ||
120 | { .status = MNT3ERR_INVAL, .errno = -EINVAL, }, | ||
121 | { .status = MNT3ERR_NAMETOOLONG, .errno = -ENAMETOOLONG, }, | ||
122 | { .status = MNT3ERR_NOTSUPP, .errno = -ENOTSUPP, }, | ||
123 | { .status = MNT3ERR_SERVERFAULT, .errno = -ESERVERFAULT, }, | ||
124 | }; | ||
125 | |||
126 | struct mountres { | ||
127 | int errno; | ||
128 | struct nfs_fh *fh; | ||
129 | unsigned int *auth_count; | ||
130 | rpc_authflavor_t *auth_flavors; | ||
131 | }; | ||
132 | |||
25 | struct mnt_fhstatus { | 133 | struct mnt_fhstatus { |
26 | u32 status; | 134 | u32 status; |
27 | struct nfs_fh *fh; | 135 | struct nfs_fh *fh; |
@@ -35,8 +143,10 @@ struct mnt_fhstatus { | |||
35 | */ | 143 | */ |
36 | int nfs_mount(struct nfs_mount_request *info) | 144 | int nfs_mount(struct nfs_mount_request *info) |
37 | { | 145 | { |
38 | struct mnt_fhstatus result = { | 146 | struct mountres result = { |
39 | .fh = info->fh | 147 | .fh = info->fh, |
148 | .auth_count = info->auth_flav_len, | ||
149 | .auth_flavors = info->auth_flavs, | ||
40 | }; | 150 | }; |
41 | struct rpc_message msg = { | 151 | struct rpc_message msg = { |
42 | .rpc_argp = info->dirpath, | 152 | .rpc_argp = info->dirpath, |
@@ -68,14 +178,14 @@ int nfs_mount(struct nfs_mount_request *info) | |||
68 | if (info->version == NFS_MNT3_VERSION) | 178 | if (info->version == NFS_MNT3_VERSION) |
69 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; | 179 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; |
70 | else | 180 | else |
71 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; | 181 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT]; |
72 | 182 | ||
73 | status = rpc_call_sync(mnt_clnt, &msg, 0); | 183 | status = rpc_call_sync(mnt_clnt, &msg, 0); |
74 | rpc_shutdown_client(mnt_clnt); | 184 | rpc_shutdown_client(mnt_clnt); |
75 | 185 | ||
76 | if (status < 0) | 186 | if (status < 0) |
77 | goto out_call_err; | 187 | goto out_call_err; |
78 | if (result.status != 0) | 188 | if (result.errno != 0) |
79 | goto out_mnt_err; | 189 | goto out_mnt_err; |
80 | 190 | ||
81 | dprintk("NFS: MNT request succeeded\n"); | 191 | dprintk("NFS: MNT request succeeded\n"); |
@@ -86,72 +196,215 @@ out: | |||
86 | 196 | ||
87 | out_clnt_err: | 197 | out_clnt_err: |
88 | status = PTR_ERR(mnt_clnt); | 198 | status = PTR_ERR(mnt_clnt); |
89 | dprintk("NFS: failed to create RPC client, status=%d\n", status); | 199 | dprintk("NFS: failed to create MNT RPC client, status=%d\n", status); |
90 | goto out; | 200 | goto out; |
91 | 201 | ||
92 | out_call_err: | 202 | out_call_err: |
93 | dprintk("NFS: failed to start MNT request, status=%d\n", status); | 203 | dprintk("NFS: MNT request failed, status=%d\n", status); |
94 | goto out; | 204 | goto out; |
95 | 205 | ||
96 | out_mnt_err: | 206 | out_mnt_err: |
97 | dprintk("NFS: MNT server returned result %d\n", result.status); | 207 | dprintk("NFS: MNT server returned result %d\n", result.errno); |
98 | status = nfs_stat_to_errno(result.status); | 208 | status = result.errno; |
99 | goto out; | 209 | goto out; |
100 | } | 210 | } |
101 | 211 | ||
102 | /* | 212 | /* |
103 | * XDR encode/decode functions for MOUNT | 213 | * XDR encode/decode functions for MOUNT |
104 | */ | 214 | */ |
105 | static int xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, | 215 | |
106 | const char *path) | 216 | static int encode_mntdirpath(struct xdr_stream *xdr, const char *pathname) |
217 | { | ||
218 | const u32 pathname_len = strlen(pathname); | ||
219 | __be32 *p; | ||
220 | |||
221 | if (unlikely(pathname_len > MNTPATHLEN)) | ||
222 | return -EIO; | ||
223 | |||
224 | p = xdr_reserve_space(xdr, sizeof(u32) + pathname_len); | ||
225 | if (unlikely(p == NULL)) | ||
226 | return -EIO; | ||
227 | xdr_encode_opaque(p, pathname, pathname_len); | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static int mnt_enc_dirpath(struct rpc_rqst *req, __be32 *p, | ||
233 | const char *dirpath) | ||
234 | { | ||
235 | struct xdr_stream xdr; | ||
236 | |||
237 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
238 | return encode_mntdirpath(&xdr, dirpath); | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * RFC 1094: "A non-zero status indicates some sort of error. In this | ||
243 | * case, the status is a UNIX error number." This can be problematic | ||
244 | * if the server and client use different errno values for the same | ||
245 | * error. | ||
246 | * | ||
247 | * However, the OpenGroup XNFS spec provides a simple mapping that is | ||
248 | * independent of local errno values on the server and the client. | ||
249 | */ | ||
250 | static int decode_status(struct xdr_stream *xdr, struct mountres *res) | ||
107 | { | 251 | { |
108 | p = xdr_encode_string(p, path); | 252 | unsigned int i; |
253 | u32 status; | ||
254 | __be32 *p; | ||
255 | |||
256 | p = xdr_inline_decode(xdr, sizeof(status)); | ||
257 | if (unlikely(p == NULL)) | ||
258 | return -EIO; | ||
259 | status = ntohl(*p); | ||
109 | 260 | ||
110 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | 261 | for (i = 0; i <= ARRAY_SIZE(mnt_errtbl); i++) { |
262 | if (mnt_errtbl[i].status == status) { | ||
263 | res->errno = mnt_errtbl[i].errno; | ||
264 | return 0; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | dprintk("NFS: unrecognized MNT status code: %u\n", status); | ||
269 | res->errno = -EACCES; | ||
111 | return 0; | 270 | return 0; |
112 | } | 271 | } |
113 | 272 | ||
114 | static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, | 273 | static int decode_fhandle(struct xdr_stream *xdr, struct mountres *res) |
115 | struct mnt_fhstatus *res) | ||
116 | { | 274 | { |
117 | struct nfs_fh *fh = res->fh; | 275 | struct nfs_fh *fh = res->fh; |
276 | __be32 *p; | ||
277 | |||
278 | p = xdr_inline_decode(xdr, NFS2_FHSIZE); | ||
279 | if (unlikely(p == NULL)) | ||
280 | return -EIO; | ||
281 | |||
282 | fh->size = NFS2_FHSIZE; | ||
283 | memcpy(fh->data, p, NFS2_FHSIZE); | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int mnt_dec_mountres(struct rpc_rqst *req, __be32 *p, | ||
288 | struct mountres *res) | ||
289 | { | ||
290 | struct xdr_stream xdr; | ||
291 | int status; | ||
292 | |||
293 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | ||
294 | |||
295 | status = decode_status(&xdr, res); | ||
296 | if (unlikely(status != 0 || res->errno != 0)) | ||
297 | return status; | ||
298 | return decode_fhandle(&xdr, res); | ||
299 | } | ||
300 | |||
301 | static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res) | ||
302 | { | ||
303 | unsigned int i; | ||
304 | u32 status; | ||
305 | __be32 *p; | ||
118 | 306 | ||
119 | if ((res->status = ntohl(*p++)) == 0) { | 307 | p = xdr_inline_decode(xdr, sizeof(status)); |
120 | fh->size = NFS2_FHSIZE; | 308 | if (unlikely(p == NULL)) |
121 | memcpy(fh->data, p, NFS2_FHSIZE); | 309 | return -EIO; |
310 | status = ntohl(*p); | ||
311 | |||
312 | for (i = 0; i <= ARRAY_SIZE(mnt3_errtbl); i++) { | ||
313 | if (mnt3_errtbl[i].status == status) { | ||
314 | res->errno = mnt3_errtbl[i].errno; | ||
315 | return 0; | ||
316 | } | ||
122 | } | 317 | } |
318 | |||
319 | dprintk("NFS: unrecognized MNT3 status code: %u\n", status); | ||
320 | res->errno = -EACCES; | ||
123 | return 0; | 321 | return 0; |
124 | } | 322 | } |
125 | 323 | ||
126 | static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, | 324 | static int decode_fhandle3(struct xdr_stream *xdr, struct mountres *res) |
127 | struct mnt_fhstatus *res) | ||
128 | { | 325 | { |
129 | struct nfs_fh *fh = res->fh; | 326 | struct nfs_fh *fh = res->fh; |
130 | unsigned size; | 327 | u32 size; |
131 | 328 | __be32 *p; | |
132 | if ((res->status = ntohl(*p++)) == 0) { | 329 | |
133 | size = ntohl(*p++); | 330 | p = xdr_inline_decode(xdr, sizeof(size)); |
134 | if (size <= NFS3_FHSIZE && size != 0) { | 331 | if (unlikely(p == NULL)) |
135 | fh->size = size; | 332 | return -EIO; |
136 | memcpy(fh->data, p, size); | 333 | |
137 | } else | 334 | size = ntohl(*p++); |
138 | res->status = -EBADHANDLE; | 335 | if (size > NFS3_FHSIZE || size == 0) |
336 | return -EIO; | ||
337 | |||
338 | p = xdr_inline_decode(xdr, size); | ||
339 | if (unlikely(p == NULL)) | ||
340 | return -EIO; | ||
341 | |||
342 | fh->size = size; | ||
343 | memcpy(fh->data, p, size); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res) | ||
348 | { | ||
349 | rpc_authflavor_t *flavors = res->auth_flavors; | ||
350 | unsigned int *count = res->auth_count; | ||
351 | u32 entries, i; | ||
352 | __be32 *p; | ||
353 | |||
354 | if (*count == 0) | ||
355 | return 0; | ||
356 | |||
357 | p = xdr_inline_decode(xdr, sizeof(entries)); | ||
358 | if (unlikely(p == NULL)) | ||
359 | return -EIO; | ||
360 | entries = ntohl(*p); | ||
361 | dprintk("NFS: received %u auth flavors\n", entries); | ||
362 | if (entries > NFS_MAX_SECFLAVORS) | ||
363 | entries = NFS_MAX_SECFLAVORS; | ||
364 | |||
365 | p = xdr_inline_decode(xdr, sizeof(u32) * entries); | ||
366 | if (unlikely(p == NULL)) | ||
367 | return -EIO; | ||
368 | |||
369 | if (entries > *count) | ||
370 | entries = *count; | ||
371 | |||
372 | for (i = 0; i < entries; i++) { | ||
373 | flavors[i] = ntohl(*p++); | ||
374 | dprintk("NFS:\tflavor %u: %d\n", i, flavors[i]); | ||
139 | } | 375 | } |
376 | *count = i; | ||
377 | |||
140 | return 0; | 378 | return 0; |
141 | } | 379 | } |
142 | 380 | ||
143 | #define MNT_dirpath_sz (1 + 256) | 381 | static int mnt_dec_mountres3(struct rpc_rqst *req, __be32 *p, |
144 | #define MNT_fhstatus_sz (1 + 8) | 382 | struct mountres *res) |
145 | #define MNT_fhstatus3_sz (1 + 16) | 383 | { |
384 | struct xdr_stream xdr; | ||
385 | int status; | ||
386 | |||
387 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | ||
388 | |||
389 | status = decode_fhs_status(&xdr, res); | ||
390 | if (unlikely(status != 0 || res->errno != 0)) | ||
391 | return status; | ||
392 | status = decode_fhandle3(&xdr, res); | ||
393 | if (unlikely(status != 0)) { | ||
394 | res->errno = -EBADHANDLE; | ||
395 | return 0; | ||
396 | } | ||
397 | return decode_auth_flavors(&xdr, res); | ||
398 | } | ||
146 | 399 | ||
147 | static struct rpc_procinfo mnt_procedures[] = { | 400 | static struct rpc_procinfo mnt_procedures[] = { |
148 | [MNTPROC_MNT] = { | 401 | [MOUNTPROC_MNT] = { |
149 | .p_proc = MNTPROC_MNT, | 402 | .p_proc = MOUNTPROC_MNT, |
150 | .p_encode = (kxdrproc_t) xdr_encode_dirpath, | 403 | .p_encode = (kxdrproc_t)mnt_enc_dirpath, |
151 | .p_decode = (kxdrproc_t) xdr_decode_fhstatus, | 404 | .p_decode = (kxdrproc_t)mnt_dec_mountres, |
152 | .p_arglen = MNT_dirpath_sz, | 405 | .p_arglen = MNT_enc_dirpath_sz, |
153 | .p_replen = MNT_fhstatus_sz, | 406 | .p_replen = MNT_dec_mountres_sz, |
154 | .p_statidx = MNTPROC_MNT, | 407 | .p_statidx = MOUNTPROC_MNT, |
155 | .p_name = "MOUNT", | 408 | .p_name = "MOUNT", |
156 | }, | 409 | }, |
157 | }; | 410 | }; |
@@ -159,10 +412,10 @@ static struct rpc_procinfo mnt_procedures[] = { | |||
159 | static struct rpc_procinfo mnt3_procedures[] = { | 412 | static struct rpc_procinfo mnt3_procedures[] = { |
160 | [MOUNTPROC3_MNT] = { | 413 | [MOUNTPROC3_MNT] = { |
161 | .p_proc = MOUNTPROC3_MNT, | 414 | .p_proc = MOUNTPROC3_MNT, |
162 | .p_encode = (kxdrproc_t) xdr_encode_dirpath, | 415 | .p_encode = (kxdrproc_t)mnt_enc_dirpath, |
163 | .p_decode = (kxdrproc_t) xdr_decode_fhstatus3, | 416 | .p_decode = (kxdrproc_t)mnt_dec_mountres3, |
164 | .p_arglen = MNT_dirpath_sz, | 417 | .p_arglen = MNT_enc_dirpath_sz, |
165 | .p_replen = MNT_fhstatus3_sz, | 418 | .p_replen = MNT_dec_mountres3_sz, |
166 | .p_statidx = MOUNTPROC3_MNT, | 419 | .p_statidx = MOUNTPROC3_MNT, |
167 | .p_name = "MOUNT", | 420 | .p_name = "MOUNT", |
168 | }, | 421 | }, |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index f01caec84463..40c766782891 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -65,6 +65,11 @@ char *nfs_path(const char *base, | |||
65 | dentry = dentry->d_parent; | 65 | dentry = dentry->d_parent; |
66 | } | 66 | } |
67 | spin_unlock(&dcache_lock); | 67 | spin_unlock(&dcache_lock); |
68 | if (*end != '/') { | ||
69 | if (--buflen < 0) | ||
70 | goto Elong; | ||
71 | *--end = '/'; | ||
72 | } | ||
68 | namelen = strlen(base); | 73 | namelen = strlen(base); |
69 | /* Strip off excess slashes in base string */ | 74 | /* Strip off excess slashes in base string */ |
70 | while (namelen > 0 && base[namelen - 1] == '/') | 75 | while (namelen > 0 && base[namelen - 1] == '/') |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 6bbf0e6daad2..bac60515a4b3 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
@@ -207,8 +207,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
207 | status = nfs_revalidate_inode(server, inode); | 207 | status = nfs_revalidate_inode(server, inode); |
208 | if (status < 0) | 208 | if (status < 0) |
209 | return ERR_PTR(status); | 209 | return ERR_PTR(status); |
210 | if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) | ||
211 | nfs_zap_acl_cache(inode); | ||
212 | acl = nfs3_get_cached_acl(inode, type); | 210 | acl = nfs3_get_cached_acl(inode, type); |
213 | if (acl != ERR_PTR(-EAGAIN)) | 211 | if (acl != ERR_PTR(-EAGAIN)) |
214 | return acl; | 212 | return acl; |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 84345deab26f..61bc3a32e1e2 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -44,6 +44,7 @@ enum nfs4_client_state { | |||
44 | NFS4CLNT_RECLAIM_REBOOT, | 44 | NFS4CLNT_RECLAIM_REBOOT, |
45 | NFS4CLNT_RECLAIM_NOGRACE, | 45 | NFS4CLNT_RECLAIM_NOGRACE, |
46 | NFS4CLNT_DELEGRETURN, | 46 | NFS4CLNT_DELEGRETURN, |
47 | NFS4CLNT_SESSION_SETUP, | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | /* | 50 | /* |
@@ -177,6 +178,14 @@ struct nfs4_state_recovery_ops { | |||
177 | int state_flag_bit; | 178 | int state_flag_bit; |
178 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); | 179 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); |
179 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); | 180 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); |
181 | int (*establish_clid)(struct nfs_client *, struct rpc_cred *); | ||
182 | struct rpc_cred * (*get_clid_cred)(struct nfs_client *); | ||
183 | }; | ||
184 | |||
185 | struct nfs4_state_maintenance_ops { | ||
186 | int (*sched_state_renewal)(struct nfs_client *, struct rpc_cred *); | ||
187 | struct rpc_cred * (*get_state_renewal_cred_locked)(struct nfs_client *); | ||
188 | int (*renew_lease)(struct nfs_client *, struct rpc_cred *); | ||
180 | }; | 189 | }; |
181 | 190 | ||
182 | extern const struct dentry_operations nfs4_dentry_operations; | 191 | extern const struct dentry_operations nfs4_dentry_operations; |
@@ -193,6 +202,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc | |||
193 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); | 202 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); |
194 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); | 203 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
195 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); | 204 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); |
205 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); | ||
196 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); | 206 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); |
197 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 207 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
198 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 208 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
@@ -200,8 +210,26 @@ extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh | |||
200 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | 210 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, |
201 | struct nfs4_fs_locations *fs_locations, struct page *page); | 211 | struct nfs4_fs_locations *fs_locations, struct page *page); |
202 | 212 | ||
203 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; | 213 | extern struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[]; |
204 | extern struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops; | 214 | extern struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[]; |
215 | #if defined(CONFIG_NFS_V4_1) | ||
216 | extern int nfs4_setup_sequence(struct nfs_client *clp, | ||
217 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | ||
218 | int cache_reply, struct rpc_task *task); | ||
219 | extern void nfs4_destroy_session(struct nfs4_session *session); | ||
220 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); | ||
221 | extern int nfs4_proc_create_session(struct nfs_client *, int reset); | ||
222 | extern int nfs4_proc_destroy_session(struct nfs4_session *); | ||
223 | #else /* CONFIG_NFS_v4_1 */ | ||
224 | static inline int nfs4_setup_sequence(struct nfs_client *clp, | ||
225 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | ||
226 | int cache_reply, struct rpc_task *task) | ||
227 | { | ||
228 | return 0; | ||
229 | } | ||
230 | #endif /* CONFIG_NFS_V4_1 */ | ||
231 | |||
232 | extern struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[]; | ||
205 | 233 | ||
206 | extern const u32 nfs4_fattr_bitmap[2]; | 234 | extern const u32 nfs4_fattr_bitmap[2]; |
207 | extern const u32 nfs4_statfs_bitmap[2]; | 235 | extern const u32 nfs4_statfs_bitmap[2]; |
@@ -216,7 +244,12 @@ extern void nfs4_kill_renewd(struct nfs_client *); | |||
216 | extern void nfs4_renew_state(struct work_struct *); | 244 | extern void nfs4_renew_state(struct work_struct *); |
217 | 245 | ||
218 | /* nfs4state.c */ | 246 | /* nfs4state.c */ |
247 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp); | ||
219 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); | 248 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); |
249 | #if defined(CONFIG_NFS_V4_1) | ||
250 | struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp); | ||
251 | struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp); | ||
252 | #endif /* CONFIG_NFS_V4_1 */ | ||
220 | 253 | ||
221 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | 254 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); |
222 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | 255 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4674f8092da8..92ce43517814 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -48,11 +48,14 @@ | |||
48 | #include <linux/smp_lock.h> | 48 | #include <linux/smp_lock.h> |
49 | #include <linux/namei.h> | 49 | #include <linux/namei.h> |
50 | #include <linux/mount.h> | 50 | #include <linux/mount.h> |
51 | #include <linux/module.h> | ||
52 | #include <linux/sunrpc/bc_xprt.h> | ||
51 | 53 | ||
52 | #include "nfs4_fs.h" | 54 | #include "nfs4_fs.h" |
53 | #include "delegation.h" | 55 | #include "delegation.h" |
54 | #include "internal.h" | 56 | #include "internal.h" |
55 | #include "iostat.h" | 57 | #include "iostat.h" |
58 | #include "callback.h" | ||
56 | 59 | ||
57 | #define NFSDBG_FACILITY NFSDBG_PROC | 60 | #define NFSDBG_FACILITY NFSDBG_PROC |
58 | 61 | ||
@@ -247,7 +250,25 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
247 | ret = nfs4_wait_clnt_recover(clp); | 250 | ret = nfs4_wait_clnt_recover(clp); |
248 | if (ret == 0) | 251 | if (ret == 0) |
249 | exception->retry = 1; | 252 | exception->retry = 1; |
253 | #if !defined(CONFIG_NFS_V4_1) | ||
250 | break; | 254 | break; |
255 | #else /* !defined(CONFIG_NFS_V4_1) */ | ||
256 | if (!nfs4_has_session(server->nfs_client)) | ||
257 | break; | ||
258 | /* FALLTHROUGH */ | ||
259 | case -NFS4ERR_BADSESSION: | ||
260 | case -NFS4ERR_BADSLOT: | ||
261 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
262 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
263 | case -NFS4ERR_DEADSESSION: | ||
264 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
265 | case -NFS4ERR_SEQ_MISORDERED: | ||
266 | dprintk("%s ERROR: %d Reset session\n", __func__, | ||
267 | errorcode); | ||
268 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
269 | exception->retry = 1; | ||
270 | /* FALLTHROUGH */ | ||
271 | #endif /* !defined(CONFIG_NFS_V4_1) */ | ||
251 | case -NFS4ERR_FILE_OPEN: | 272 | case -NFS4ERR_FILE_OPEN: |
252 | case -NFS4ERR_GRACE: | 273 | case -NFS4ERR_GRACE: |
253 | case -NFS4ERR_DELAY: | 274 | case -NFS4ERR_DELAY: |
@@ -271,6 +292,353 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
271 | spin_unlock(&clp->cl_lock); | 292 | spin_unlock(&clp->cl_lock); |
272 | } | 293 | } |
273 | 294 | ||
295 | #if defined(CONFIG_NFS_V4_1) | ||
296 | |||
297 | /* | ||
298 | * nfs4_free_slot - free a slot and efficiently update slot table. | ||
299 | * | ||
300 | * freeing a slot is trivially done by clearing its respective bit | ||
301 | * in the bitmap. | ||
302 | * If the freed slotid equals highest_used_slotid we want to update it | ||
303 | * so that the server would be able to size down the slot table if needed, | ||
304 | * otherwise we know that the highest_used_slotid is still in use. | ||
305 | * When updating highest_used_slotid there may be "holes" in the bitmap | ||
306 | * so we need to scan down from highest_used_slotid to 0 looking for the now | ||
307 | * highest slotid in use. | ||
308 | * If none found, highest_used_slotid is set to -1. | ||
309 | */ | ||
310 | static void | ||
311 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | ||
312 | { | ||
313 | int slotid = free_slotid; | ||
314 | |||
315 | spin_lock(&tbl->slot_tbl_lock); | ||
316 | /* clear used bit in bitmap */ | ||
317 | __clear_bit(slotid, tbl->used_slots); | ||
318 | |||
319 | /* update highest_used_slotid when it is freed */ | ||
320 | if (slotid == tbl->highest_used_slotid) { | ||
321 | slotid = find_last_bit(tbl->used_slots, tbl->max_slots); | ||
322 | if (slotid >= 0 && slotid < tbl->max_slots) | ||
323 | tbl->highest_used_slotid = slotid; | ||
324 | else | ||
325 | tbl->highest_used_slotid = -1; | ||
326 | } | ||
327 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
328 | spin_unlock(&tbl->slot_tbl_lock); | ||
329 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, | ||
330 | free_slotid, tbl->highest_used_slotid); | ||
331 | } | ||
332 | |||
333 | void nfs41_sequence_free_slot(const struct nfs_client *clp, | ||
334 | struct nfs4_sequence_res *res) | ||
335 | { | ||
336 | struct nfs4_slot_table *tbl; | ||
337 | |||
338 | if (!nfs4_has_session(clp)) { | ||
339 | dprintk("%s: No session\n", __func__); | ||
340 | return; | ||
341 | } | ||
342 | tbl = &clp->cl_session->fc_slot_table; | ||
343 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | ||
344 | dprintk("%s: No slot\n", __func__); | ||
345 | /* just wake up the next guy waiting since | ||
346 | * we may have not consumed a slot after all */ | ||
347 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
348 | return; | ||
349 | } | ||
350 | nfs4_free_slot(tbl, res->sr_slotid); | ||
351 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
352 | } | ||
353 | |||
354 | static void nfs41_sequence_done(struct nfs_client *clp, | ||
355 | struct nfs4_sequence_res *res, | ||
356 | int rpc_status) | ||
357 | { | ||
358 | unsigned long timestamp; | ||
359 | struct nfs4_slot_table *tbl; | ||
360 | struct nfs4_slot *slot; | ||
361 | |||
362 | /* | ||
363 | * sr_status remains 1 if an RPC level error occurred. The server | ||
364 | * may or may not have processed the sequence operation.. | ||
365 | * Proceed as if the server received and processed the sequence | ||
366 | * operation. | ||
367 | */ | ||
368 | if (res->sr_status == 1) | ||
369 | res->sr_status = NFS_OK; | ||
370 | |||
371 | /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */ | ||
372 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | ||
373 | goto out; | ||
374 | |||
375 | tbl = &clp->cl_session->fc_slot_table; | ||
376 | slot = tbl->slots + res->sr_slotid; | ||
377 | |||
378 | if (res->sr_status == 0) { | ||
379 | /* Update the slot's sequence and clientid lease timer */ | ||
380 | ++slot->seq_nr; | ||
381 | timestamp = res->sr_renewal_time; | ||
382 | spin_lock(&clp->cl_lock); | ||
383 | if (time_before(clp->cl_last_renewal, timestamp)) | ||
384 | clp->cl_last_renewal = timestamp; | ||
385 | spin_unlock(&clp->cl_lock); | ||
386 | return; | ||
387 | } | ||
388 | out: | ||
389 | /* The session may be reset by one of the error handlers. */ | ||
390 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); | ||
391 | nfs41_sequence_free_slot(clp, res); | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * nfs4_find_slot - efficiently look for a free slot | ||
396 | * | ||
397 | * nfs4_find_slot looks for an unset bit in the used_slots bitmap. | ||
398 | * If found, we mark the slot as used, update the highest_used_slotid, | ||
399 | * and respectively set up the sequence operation args. | ||
400 | * The slot number is returned if found, or NFS4_MAX_SLOT_TABLE otherwise. | ||
401 | * | ||
402 | * Note: must be called with under the slot_tbl_lock. | ||
403 | */ | ||
404 | static u8 | ||
405 | nfs4_find_slot(struct nfs4_slot_table *tbl, struct rpc_task *task) | ||
406 | { | ||
407 | int slotid; | ||
408 | u8 ret_id = NFS4_MAX_SLOT_TABLE; | ||
409 | BUILD_BUG_ON((u8)NFS4_MAX_SLOT_TABLE != (int)NFS4_MAX_SLOT_TABLE); | ||
410 | |||
411 | dprintk("--> %s used_slots=%04lx highest_used=%d max_slots=%d\n", | ||
412 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | ||
413 | tbl->max_slots); | ||
414 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots); | ||
415 | if (slotid >= tbl->max_slots) | ||
416 | goto out; | ||
417 | __set_bit(slotid, tbl->used_slots); | ||
418 | if (slotid > tbl->highest_used_slotid) | ||
419 | tbl->highest_used_slotid = slotid; | ||
420 | ret_id = slotid; | ||
421 | out: | ||
422 | dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", | ||
423 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, ret_id); | ||
424 | return ret_id; | ||
425 | } | ||
426 | |||
427 | static int nfs4_recover_session(struct nfs4_session *session) | ||
428 | { | ||
429 | struct nfs_client *clp = session->clp; | ||
430 | int ret; | ||
431 | |||
432 | for (;;) { | ||
433 | ret = nfs4_wait_clnt_recover(clp); | ||
434 | if (ret != 0) | ||
435 | return ret; | ||
436 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
437 | break; | ||
438 | nfs4_schedule_state_manager(clp); | ||
439 | } | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | static int nfs41_setup_sequence(struct nfs4_session *session, | ||
444 | struct nfs4_sequence_args *args, | ||
445 | struct nfs4_sequence_res *res, | ||
446 | int cache_reply, | ||
447 | struct rpc_task *task) | ||
448 | { | ||
449 | struct nfs4_slot *slot; | ||
450 | struct nfs4_slot_table *tbl; | ||
451 | int status = 0; | ||
452 | u8 slotid; | ||
453 | |||
454 | dprintk("--> %s\n", __func__); | ||
455 | /* slot already allocated? */ | ||
456 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) | ||
457 | return 0; | ||
458 | |||
459 | memset(res, 0, sizeof(*res)); | ||
460 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
461 | tbl = &session->fc_slot_table; | ||
462 | |||
463 | spin_lock(&tbl->slot_tbl_lock); | ||
464 | if (test_bit(NFS4CLNT_SESSION_SETUP, &session->clp->cl_state)) { | ||
465 | if (tbl->highest_used_slotid != -1) { | ||
466 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
467 | spin_unlock(&tbl->slot_tbl_lock); | ||
468 | dprintk("<-- %s: Session reset: draining\n", __func__); | ||
469 | return -EAGAIN; | ||
470 | } | ||
471 | |||
472 | /* The slot table is empty; start the reset thread */ | ||
473 | dprintk("%s Session Reset\n", __func__); | ||
474 | spin_unlock(&tbl->slot_tbl_lock); | ||
475 | status = nfs4_recover_session(session); | ||
476 | if (status) | ||
477 | return status; | ||
478 | spin_lock(&tbl->slot_tbl_lock); | ||
479 | } | ||
480 | |||
481 | slotid = nfs4_find_slot(tbl, task); | ||
482 | if (slotid == NFS4_MAX_SLOT_TABLE) { | ||
483 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
484 | spin_unlock(&tbl->slot_tbl_lock); | ||
485 | dprintk("<-- %s: no free slots\n", __func__); | ||
486 | return -EAGAIN; | ||
487 | } | ||
488 | spin_unlock(&tbl->slot_tbl_lock); | ||
489 | |||
490 | slot = tbl->slots + slotid; | ||
491 | args->sa_session = session; | ||
492 | args->sa_slotid = slotid; | ||
493 | args->sa_cache_this = cache_reply; | ||
494 | |||
495 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); | ||
496 | |||
497 | res->sr_session = session; | ||
498 | res->sr_slotid = slotid; | ||
499 | res->sr_renewal_time = jiffies; | ||
500 | /* | ||
501 | * sr_status is only set in decode_sequence, and so will remain | ||
502 | * set to 1 if an rpc level failure occurs. | ||
503 | */ | ||
504 | res->sr_status = 1; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | int nfs4_setup_sequence(struct nfs_client *clp, | ||
509 | struct nfs4_sequence_args *args, | ||
510 | struct nfs4_sequence_res *res, | ||
511 | int cache_reply, | ||
512 | struct rpc_task *task) | ||
513 | { | ||
514 | int ret = 0; | ||
515 | |||
516 | dprintk("--> %s clp %p session %p sr_slotid %d\n", | ||
517 | __func__, clp, clp->cl_session, res->sr_slotid); | ||
518 | |||
519 | if (!nfs4_has_session(clp)) | ||
520 | goto out; | ||
521 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, | ||
522 | task); | ||
523 | if (ret != -EAGAIN) { | ||
524 | /* terminate rpc task */ | ||
525 | task->tk_status = ret; | ||
526 | task->tk_action = NULL; | ||
527 | } | ||
528 | out: | ||
529 | dprintk("<-- %s status=%d\n", __func__, ret); | ||
530 | return ret; | ||
531 | } | ||
532 | |||
533 | struct nfs41_call_sync_data { | ||
534 | struct nfs_client *clp; | ||
535 | struct nfs4_sequence_args *seq_args; | ||
536 | struct nfs4_sequence_res *seq_res; | ||
537 | int cache_reply; | ||
538 | }; | ||
539 | |||
540 | static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | ||
541 | { | ||
542 | struct nfs41_call_sync_data *data = calldata; | ||
543 | |||
544 | dprintk("--> %s data->clp->cl_session %p\n", __func__, | ||
545 | data->clp->cl_session); | ||
546 | if (nfs4_setup_sequence(data->clp, data->seq_args, | ||
547 | data->seq_res, data->cache_reply, task)) | ||
548 | return; | ||
549 | rpc_call_start(task); | ||
550 | } | ||
551 | |||
552 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | ||
553 | { | ||
554 | struct nfs41_call_sync_data *data = calldata; | ||
555 | |||
556 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); | ||
557 | nfs41_sequence_free_slot(data->clp, data->seq_res); | ||
558 | } | ||
559 | |||
560 | struct rpc_call_ops nfs41_call_sync_ops = { | ||
561 | .rpc_call_prepare = nfs41_call_sync_prepare, | ||
562 | .rpc_call_done = nfs41_call_sync_done, | ||
563 | }; | ||
564 | |||
565 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | ||
566 | struct rpc_clnt *clnt, | ||
567 | struct rpc_message *msg, | ||
568 | struct nfs4_sequence_args *args, | ||
569 | struct nfs4_sequence_res *res, | ||
570 | int cache_reply) | ||
571 | { | ||
572 | int ret; | ||
573 | struct rpc_task *task; | ||
574 | struct nfs41_call_sync_data data = { | ||
575 | .clp = clp, | ||
576 | .seq_args = args, | ||
577 | .seq_res = res, | ||
578 | .cache_reply = cache_reply, | ||
579 | }; | ||
580 | struct rpc_task_setup task_setup = { | ||
581 | .rpc_client = clnt, | ||
582 | .rpc_message = msg, | ||
583 | .callback_ops = &nfs41_call_sync_ops, | ||
584 | .callback_data = &data | ||
585 | }; | ||
586 | |||
587 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
588 | task = rpc_run_task(&task_setup); | ||
589 | if (IS_ERR(task)) | ||
590 | ret = PTR_ERR(task); | ||
591 | else { | ||
592 | ret = task->tk_status; | ||
593 | rpc_put_task(task); | ||
594 | } | ||
595 | return ret; | ||
596 | } | ||
597 | |||
598 | int _nfs4_call_sync_session(struct nfs_server *server, | ||
599 | struct rpc_message *msg, | ||
600 | struct nfs4_sequence_args *args, | ||
601 | struct nfs4_sequence_res *res, | ||
602 | int cache_reply) | ||
603 | { | ||
604 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | ||
605 | msg, args, res, cache_reply); | ||
606 | } | ||
607 | |||
608 | #endif /* CONFIG_NFS_V4_1 */ | ||
609 | |||
610 | int _nfs4_call_sync(struct nfs_server *server, | ||
611 | struct rpc_message *msg, | ||
612 | struct nfs4_sequence_args *args, | ||
613 | struct nfs4_sequence_res *res, | ||
614 | int cache_reply) | ||
615 | { | ||
616 | args->sa_session = res->sr_session = NULL; | ||
617 | return rpc_call_sync(server->client, msg, 0); | ||
618 | } | ||
619 | |||
620 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ | ||
621 | (server)->nfs_client->cl_call_sync((server), (msg), &(args)->seq_args, \ | ||
622 | &(res)->seq_res, (cache_reply)) | ||
623 | |||
624 | static void nfs4_sequence_done(const struct nfs_server *server, | ||
625 | struct nfs4_sequence_res *res, int rpc_status) | ||
626 | { | ||
627 | #ifdef CONFIG_NFS_V4_1 | ||
628 | if (nfs4_has_session(server->nfs_client)) | ||
629 | nfs41_sequence_done(server->nfs_client, res, rpc_status); | ||
630 | #endif /* CONFIG_NFS_V4_1 */ | ||
631 | } | ||
632 | |||
633 | /* no restart, therefore free slot here */ | ||
634 | static void nfs4_sequence_done_free_slot(const struct nfs_server *server, | ||
635 | struct nfs4_sequence_res *res, | ||
636 | int rpc_status) | ||
637 | { | ||
638 | nfs4_sequence_done(server, res, rpc_status); | ||
639 | nfs4_sequence_free_slot(server->nfs_client, res); | ||
640 | } | ||
641 | |||
274 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 642 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
275 | { | 643 | { |
276 | struct nfs_inode *nfsi = NFS_I(dir); | 644 | struct nfs_inode *nfsi = NFS_I(dir); |
@@ -312,6 +680,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
312 | p->o_res.server = p->o_arg.server; | 680 | p->o_res.server = p->o_arg.server; |
313 | nfs_fattr_init(&p->f_attr); | 681 | nfs_fattr_init(&p->f_attr); |
314 | nfs_fattr_init(&p->dir_attr); | 682 | nfs_fattr_init(&p->dir_attr); |
683 | p->o_res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
315 | } | 684 | } |
316 | 685 | ||
317 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 686 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, |
@@ -804,16 +1173,30 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
804 | err = _nfs4_open_delegation_recall(ctx, state, stateid); | 1173 | err = _nfs4_open_delegation_recall(ctx, state, stateid); |
805 | switch (err) { | 1174 | switch (err) { |
806 | case 0: | 1175 | case 0: |
807 | return err; | 1176 | case -ENOENT: |
1177 | case -ESTALE: | ||
1178 | goto out; | ||
808 | case -NFS4ERR_STALE_CLIENTID: | 1179 | case -NFS4ERR_STALE_CLIENTID: |
809 | case -NFS4ERR_STALE_STATEID: | 1180 | case -NFS4ERR_STALE_STATEID: |
810 | case -NFS4ERR_EXPIRED: | 1181 | case -NFS4ERR_EXPIRED: |
811 | /* Don't recall a delegation if it was lost */ | 1182 | /* Don't recall a delegation if it was lost */ |
812 | nfs4_schedule_state_recovery(server->nfs_client); | 1183 | nfs4_schedule_state_recovery(server->nfs_client); |
813 | return err; | 1184 | goto out; |
1185 | case -ERESTARTSYS: | ||
1186 | /* | ||
1187 | * The show must go on: exit, but mark the | ||
1188 | * stateid as needing recovery. | ||
1189 | */ | ||
1190 | case -NFS4ERR_ADMIN_REVOKED: | ||
1191 | case -NFS4ERR_BAD_STATEID: | ||
1192 | nfs4_state_mark_reclaim_nograce(server->nfs_client, state); | ||
1193 | case -ENOMEM: | ||
1194 | err = 0; | ||
1195 | goto out; | ||
814 | } | 1196 | } |
815 | err = nfs4_handle_exception(server, err, &exception); | 1197 | err = nfs4_handle_exception(server, err, &exception); |
816 | } while (exception.retry); | 1198 | } while (exception.retry); |
1199 | out: | ||
817 | return err; | 1200 | return err; |
818 | } | 1201 | } |
819 | 1202 | ||
@@ -929,6 +1312,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
929 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | 1312 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); |
930 | } | 1313 | } |
931 | data->timestamp = jiffies; | 1314 | data->timestamp = jiffies; |
1315 | if (nfs4_setup_sequence(data->o_arg.server->nfs_client, | ||
1316 | &data->o_arg.seq_args, | ||
1317 | &data->o_res.seq_res, 1, task)) | ||
1318 | return; | ||
932 | rpc_call_start(task); | 1319 | rpc_call_start(task); |
933 | return; | 1320 | return; |
934 | out_no_action: | 1321 | out_no_action: |
@@ -941,6 +1328,10 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
941 | struct nfs4_opendata *data = calldata; | 1328 | struct nfs4_opendata *data = calldata; |
942 | 1329 | ||
943 | data->rpc_status = task->tk_status; | 1330 | data->rpc_status = task->tk_status; |
1331 | |||
1332 | nfs4_sequence_done_free_slot(data->o_arg.server, &data->o_res.seq_res, | ||
1333 | task->tk_status); | ||
1334 | |||
944 | if (RPC_ASSASSINATED(task)) | 1335 | if (RPC_ASSASSINATED(task)) |
945 | return; | 1336 | return; |
946 | if (task->tk_status == 0) { | 1337 | if (task->tk_status == 0) { |
@@ -1269,7 +1660,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
1269 | } else | 1660 | } else |
1270 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1661 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
1271 | 1662 | ||
1272 | status = rpc_call_sync(server->client, &msg, 0); | 1663 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
1273 | if (status == 0 && state != NULL) | 1664 | if (status == 0 && state != NULL) |
1274 | renew_lease(server, timestamp); | 1665 | renew_lease(server, timestamp); |
1275 | return status; | 1666 | return status; |
@@ -1318,6 +1709,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1318 | struct nfs4_state *state = calldata->state; | 1709 | struct nfs4_state *state = calldata->state; |
1319 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 1710 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
1320 | 1711 | ||
1712 | nfs4_sequence_done(server, &calldata->res.seq_res, task->tk_status); | ||
1321 | if (RPC_ASSASSINATED(task)) | 1713 | if (RPC_ASSASSINATED(task)) |
1322 | return; | 1714 | return; |
1323 | /* hmm. we are done with the inode, and in the process of freeing | 1715 | /* hmm. we are done with the inode, and in the process of freeing |
@@ -1336,10 +1728,11 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1336 | break; | 1728 | break; |
1337 | default: | 1729 | default: |
1338 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { | 1730 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { |
1339 | rpc_restart_call(task); | 1731 | nfs4_restart_rpc(task, server->nfs_client); |
1340 | return; | 1732 | return; |
1341 | } | 1733 | } |
1342 | } | 1734 | } |
1735 | nfs4_sequence_free_slot(server->nfs_client, &calldata->res.seq_res); | ||
1343 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 1736 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
1344 | } | 1737 | } |
1345 | 1738 | ||
@@ -1380,6 +1773,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1380 | calldata->arg.fmode = FMODE_WRITE; | 1773 | calldata->arg.fmode = FMODE_WRITE; |
1381 | } | 1774 | } |
1382 | calldata->timestamp = jiffies; | 1775 | calldata->timestamp = jiffies; |
1776 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, | ||
1777 | &calldata->arg.seq_args, &calldata->res.seq_res, | ||
1778 | 1, task)) | ||
1779 | return; | ||
1383 | rpc_call_start(task); | 1780 | rpc_call_start(task); |
1384 | } | 1781 | } |
1385 | 1782 | ||
@@ -1419,13 +1816,15 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1419 | }; | 1816 | }; |
1420 | int status = -ENOMEM; | 1817 | int status = -ENOMEM; |
1421 | 1818 | ||
1422 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 1819 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); |
1423 | if (calldata == NULL) | 1820 | if (calldata == NULL) |
1424 | goto out; | 1821 | goto out; |
1425 | calldata->inode = state->inode; | 1822 | calldata->inode = state->inode; |
1426 | calldata->state = state; | 1823 | calldata->state = state; |
1427 | calldata->arg.fh = NFS_FH(state->inode); | 1824 | calldata->arg.fh = NFS_FH(state->inode); |
1428 | calldata->arg.stateid = &state->open_stateid; | 1825 | calldata->arg.stateid = &state->open_stateid; |
1826 | if (nfs4_has_session(server->nfs_client)) | ||
1827 | memset(calldata->arg.stateid->data, 0, 4); /* clear seqid */ | ||
1429 | /* Serialization for the sequence id */ | 1828 | /* Serialization for the sequence id */ |
1430 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1829 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1431 | if (calldata->arg.seqid == NULL) | 1830 | if (calldata->arg.seqid == NULL) |
@@ -1435,6 +1834,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1435 | calldata->res.fattr = &calldata->fattr; | 1834 | calldata->res.fattr = &calldata->fattr; |
1436 | calldata->res.seqid = calldata->arg.seqid; | 1835 | calldata->res.seqid = calldata->arg.seqid; |
1437 | calldata->res.server = server; | 1836 | calldata->res.server = server; |
1837 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
1438 | calldata->path.mnt = mntget(path->mnt); | 1838 | calldata->path.mnt = mntget(path->mnt); |
1439 | calldata->path.dentry = dget(path->dentry); | 1839 | calldata->path.dentry = dget(path->dentry); |
1440 | 1840 | ||
@@ -1584,15 +1984,18 @@ void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | |||
1584 | 1984 | ||
1585 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) | 1985 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) |
1586 | { | 1986 | { |
1987 | struct nfs4_server_caps_arg args = { | ||
1988 | .fhandle = fhandle, | ||
1989 | }; | ||
1587 | struct nfs4_server_caps_res res = {}; | 1990 | struct nfs4_server_caps_res res = {}; |
1588 | struct rpc_message msg = { | 1991 | struct rpc_message msg = { |
1589 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], | 1992 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], |
1590 | .rpc_argp = fhandle, | 1993 | .rpc_argp = &args, |
1591 | .rpc_resp = &res, | 1994 | .rpc_resp = &res, |
1592 | }; | 1995 | }; |
1593 | int status; | 1996 | int status; |
1594 | 1997 | ||
1595 | status = rpc_call_sync(server->client, &msg, 0); | 1998 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1596 | if (status == 0) { | 1999 | if (status == 0) { |
1597 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); | 2000 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); |
1598 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) | 2001 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) |
@@ -1606,6 +2009,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
1606 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 2009 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
1607 | server->acl_bitmask = res.acl_bitmask; | 2010 | server->acl_bitmask = res.acl_bitmask; |
1608 | } | 2011 | } |
2012 | |||
1609 | return status; | 2013 | return status; |
1610 | } | 2014 | } |
1611 | 2015 | ||
@@ -1637,8 +2041,15 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1637 | .rpc_argp = &args, | 2041 | .rpc_argp = &args, |
1638 | .rpc_resp = &res, | 2042 | .rpc_resp = &res, |
1639 | }; | 2043 | }; |
2044 | int status; | ||
2045 | |||
1640 | nfs_fattr_init(info->fattr); | 2046 | nfs_fattr_init(info->fattr); |
1641 | return rpc_call_sync(server->client, &msg, 0); | 2047 | status = nfs4_recover_expired_lease(server); |
2048 | if (!status) | ||
2049 | status = nfs4_check_client_ready(server->nfs_client); | ||
2050 | if (!status) | ||
2051 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | ||
2052 | return status; | ||
1642 | } | 2053 | } |
1643 | 2054 | ||
1644 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2055 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -1728,7 +2139,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1728 | }; | 2139 | }; |
1729 | 2140 | ||
1730 | nfs_fattr_init(fattr); | 2141 | nfs_fattr_init(fattr); |
1731 | return rpc_call_sync(server->client, &msg, 0); | 2142 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
1732 | } | 2143 | } |
1733 | 2144 | ||
1734 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2145 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
@@ -1812,7 +2223,7 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *d | |||
1812 | nfs_fattr_init(fattr); | 2223 | nfs_fattr_init(fattr); |
1813 | 2224 | ||
1814 | dprintk("NFS call lookupfh %s\n", name->name); | 2225 | dprintk("NFS call lookupfh %s\n", name->name); |
1815 | status = rpc_call_sync(server->client, &msg, 0); | 2226 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1816 | dprintk("NFS reply lookupfh: %d\n", status); | 2227 | dprintk("NFS reply lookupfh: %d\n", status); |
1817 | return status; | 2228 | return status; |
1818 | } | 2229 | } |
@@ -1898,7 +2309,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
1898 | args.access |= NFS4_ACCESS_EXECUTE; | 2309 | args.access |= NFS4_ACCESS_EXECUTE; |
1899 | } | 2310 | } |
1900 | nfs_fattr_init(&fattr); | 2311 | nfs_fattr_init(&fattr); |
1901 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2312 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1902 | if (!status) { | 2313 | if (!status) { |
1903 | entry->mask = 0; | 2314 | entry->mask = 0; |
1904 | if (res.access & NFS4_ACCESS_READ) | 2315 | if (res.access & NFS4_ACCESS_READ) |
@@ -1957,13 +2368,14 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page, | |||
1957 | .pglen = pglen, | 2368 | .pglen = pglen, |
1958 | .pages = &page, | 2369 | .pages = &page, |
1959 | }; | 2370 | }; |
2371 | struct nfs4_readlink_res res; | ||
1960 | struct rpc_message msg = { | 2372 | struct rpc_message msg = { |
1961 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], | 2373 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], |
1962 | .rpc_argp = &args, | 2374 | .rpc_argp = &args, |
1963 | .rpc_resp = NULL, | 2375 | .rpc_resp = &res, |
1964 | }; | 2376 | }; |
1965 | 2377 | ||
1966 | return rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2378 | return nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); |
1967 | } | 2379 | } |
1968 | 2380 | ||
1969 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, | 2381 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, |
@@ -2057,7 +2469,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
2057 | int status; | 2469 | int status; |
2058 | 2470 | ||
2059 | nfs_fattr_init(&res.dir_attr); | 2471 | nfs_fattr_init(&res.dir_attr); |
2060 | status = rpc_call_sync(server->client, &msg, 0); | 2472 | status = nfs4_call_sync(server, &msg, &args, &res, 1); |
2061 | if (status == 0) { | 2473 | if (status == 0) { |
2062 | update_changeattr(dir, &res.cinfo); | 2474 | update_changeattr(dir, &res.cinfo); |
2063 | nfs_post_op_update_inode(dir, &res.dir_attr); | 2475 | nfs_post_op_update_inode(dir, &res.dir_attr); |
@@ -2092,8 +2504,10 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2092 | { | 2504 | { |
2093 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2505 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
2094 | 2506 | ||
2507 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | ||
2095 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2508 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
2096 | return 0; | 2509 | return 0; |
2510 | nfs4_sequence_free_slot(res->server->nfs_client, &res->seq_res); | ||
2097 | update_changeattr(dir, &res->cinfo); | 2511 | update_changeattr(dir, &res->cinfo); |
2098 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2512 | nfs_post_op_update_inode(dir, &res->dir_attr); |
2099 | return 1; | 2513 | return 1; |
@@ -2125,7 +2539,7 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
2125 | 2539 | ||
2126 | nfs_fattr_init(res.old_fattr); | 2540 | nfs_fattr_init(res.old_fattr); |
2127 | nfs_fattr_init(res.new_fattr); | 2541 | nfs_fattr_init(res.new_fattr); |
2128 | status = rpc_call_sync(server->client, &msg, 0); | 2542 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2129 | 2543 | ||
2130 | if (!status) { | 2544 | if (!status) { |
2131 | update_changeattr(old_dir, &res.old_cinfo); | 2545 | update_changeattr(old_dir, &res.old_cinfo); |
@@ -2174,7 +2588,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
2174 | 2588 | ||
2175 | nfs_fattr_init(res.fattr); | 2589 | nfs_fattr_init(res.fattr); |
2176 | nfs_fattr_init(res.dir_attr); | 2590 | nfs_fattr_init(res.dir_attr); |
2177 | status = rpc_call_sync(server->client, &msg, 0); | 2591 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2178 | if (!status) { | 2592 | if (!status) { |
2179 | update_changeattr(dir, &res.cinfo); | 2593 | update_changeattr(dir, &res.cinfo); |
2180 | nfs_post_op_update_inode(dir, res.dir_attr); | 2594 | nfs_post_op_update_inode(dir, res.dir_attr); |
@@ -2235,7 +2649,8 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, | |||
2235 | 2649 | ||
2236 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) | 2650 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) |
2237 | { | 2651 | { |
2238 | int status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); | 2652 | int status = nfs4_call_sync(NFS_SERVER(dir), &data->msg, |
2653 | &data->arg, &data->res, 1); | ||
2239 | if (status == 0) { | 2654 | if (status == 0) { |
2240 | update_changeattr(dir, &data->res.dir_cinfo); | 2655 | update_changeattr(dir, &data->res.dir_cinfo); |
2241 | nfs_post_op_update_inode(dir, data->res.dir_fattr); | 2656 | nfs_post_op_update_inode(dir, data->res.dir_fattr); |
@@ -2344,7 +2759,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
2344 | (unsigned long long)cookie); | 2759 | (unsigned long long)cookie); |
2345 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 2760 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
2346 | res.pgbase = args.pgbase; | 2761 | res.pgbase = args.pgbase; |
2347 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 2762 | status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0); |
2348 | if (status == 0) | 2763 | if (status == 0) |
2349 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 2764 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
2350 | 2765 | ||
@@ -2422,14 +2837,17 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2422 | .fh = fhandle, | 2837 | .fh = fhandle, |
2423 | .bitmask = server->attr_bitmask, | 2838 | .bitmask = server->attr_bitmask, |
2424 | }; | 2839 | }; |
2840 | struct nfs4_statfs_res res = { | ||
2841 | .fsstat = fsstat, | ||
2842 | }; | ||
2425 | struct rpc_message msg = { | 2843 | struct rpc_message msg = { |
2426 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], | 2844 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], |
2427 | .rpc_argp = &args, | 2845 | .rpc_argp = &args, |
2428 | .rpc_resp = fsstat, | 2846 | .rpc_resp = &res, |
2429 | }; | 2847 | }; |
2430 | 2848 | ||
2431 | nfs_fattr_init(fsstat->fattr); | 2849 | nfs_fattr_init(fsstat->fattr); |
2432 | return rpc_call_sync(server->client, &msg, 0); | 2850 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2433 | } | 2851 | } |
2434 | 2852 | ||
2435 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) | 2853 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) |
@@ -2451,13 +2869,16 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2451 | .fh = fhandle, | 2869 | .fh = fhandle, |
2452 | .bitmask = server->attr_bitmask, | 2870 | .bitmask = server->attr_bitmask, |
2453 | }; | 2871 | }; |
2872 | struct nfs4_fsinfo_res res = { | ||
2873 | .fsinfo = fsinfo, | ||
2874 | }; | ||
2454 | struct rpc_message msg = { | 2875 | struct rpc_message msg = { |
2455 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], | 2876 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], |
2456 | .rpc_argp = &args, | 2877 | .rpc_argp = &args, |
2457 | .rpc_resp = fsinfo, | 2878 | .rpc_resp = &res, |
2458 | }; | 2879 | }; |
2459 | 2880 | ||
2460 | return rpc_call_sync(server->client, &msg, 0); | 2881 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2461 | } | 2882 | } |
2462 | 2883 | ||
2463 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 2884 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) |
@@ -2486,10 +2907,13 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
2486 | .fh = fhandle, | 2907 | .fh = fhandle, |
2487 | .bitmask = server->attr_bitmask, | 2908 | .bitmask = server->attr_bitmask, |
2488 | }; | 2909 | }; |
2910 | struct nfs4_pathconf_res res = { | ||
2911 | .pathconf = pathconf, | ||
2912 | }; | ||
2489 | struct rpc_message msg = { | 2913 | struct rpc_message msg = { |
2490 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], | 2914 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], |
2491 | .rpc_argp = &args, | 2915 | .rpc_argp = &args, |
2492 | .rpc_resp = pathconf, | 2916 | .rpc_resp = &res, |
2493 | }; | 2917 | }; |
2494 | 2918 | ||
2495 | /* None of the pathconf attributes are mandatory to implement */ | 2919 | /* None of the pathconf attributes are mandatory to implement */ |
@@ -2499,7 +2923,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
2499 | } | 2923 | } |
2500 | 2924 | ||
2501 | nfs_fattr_init(pathconf->fattr); | 2925 | nfs_fattr_init(pathconf->fattr); |
2502 | return rpc_call_sync(server->client, &msg, 0); | 2926 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2503 | } | 2927 | } |
2504 | 2928 | ||
2505 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | 2929 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -2520,8 +2944,13 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2520 | { | 2944 | { |
2521 | struct nfs_server *server = NFS_SERVER(data->inode); | 2945 | struct nfs_server *server = NFS_SERVER(data->inode); |
2522 | 2946 | ||
2947 | dprintk("--> %s\n", __func__); | ||
2948 | |||
2949 | /* nfs4_sequence_free_slot called in the read rpc_call_done */ | ||
2950 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | ||
2951 | |||
2523 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 2952 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
2524 | rpc_restart_call(task); | 2953 | nfs4_restart_rpc(task, server->nfs_client); |
2525 | return -EAGAIN; | 2954 | return -EAGAIN; |
2526 | } | 2955 | } |
2527 | 2956 | ||
@@ -2541,8 +2970,12 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2541 | { | 2970 | { |
2542 | struct inode *inode = data->inode; | 2971 | struct inode *inode = data->inode; |
2543 | 2972 | ||
2973 | /* slot is freed in nfs_writeback_done */ | ||
2974 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | ||
2975 | task->tk_status); | ||
2976 | |||
2544 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 2977 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
2545 | rpc_restart_call(task); | 2978 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
2546 | return -EAGAIN; | 2979 | return -EAGAIN; |
2547 | } | 2980 | } |
2548 | if (task->tk_status >= 0) { | 2981 | if (task->tk_status >= 0) { |
@@ -2567,10 +3000,14 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2567 | { | 3000 | { |
2568 | struct inode *inode = data->inode; | 3001 | struct inode *inode = data->inode; |
2569 | 3002 | ||
3003 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | ||
3004 | task->tk_status); | ||
2570 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3005 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
2571 | rpc_restart_call(task); | 3006 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
2572 | return -EAGAIN; | 3007 | return -EAGAIN; |
2573 | } | 3008 | } |
3009 | nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client, | ||
3010 | &data->res.seq_res); | ||
2574 | nfs_refresh_inode(inode, data->res.fattr); | 3011 | nfs_refresh_inode(inode, data->res.fattr); |
2575 | return 0; | 3012 | return 0; |
2576 | } | 3013 | } |
@@ -2603,6 +3040,9 @@ static void nfs4_renew_done(struct rpc_task *task, void *data) | |||
2603 | if (time_before(clp->cl_last_renewal,timestamp)) | 3040 | if (time_before(clp->cl_last_renewal,timestamp)) |
2604 | clp->cl_last_renewal = timestamp; | 3041 | clp->cl_last_renewal = timestamp; |
2605 | spin_unlock(&clp->cl_lock); | 3042 | spin_unlock(&clp->cl_lock); |
3043 | dprintk("%s calling put_rpccred on rpc_cred %p\n", __func__, | ||
3044 | task->tk_msg.rpc_cred); | ||
3045 | put_rpccred(task->tk_msg.rpc_cred); | ||
2606 | } | 3046 | } |
2607 | 3047 | ||
2608 | static const struct rpc_call_ops nfs4_renew_ops = { | 3048 | static const struct rpc_call_ops nfs4_renew_ops = { |
@@ -2742,12 +3182,14 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
2742 | .acl_pages = pages, | 3182 | .acl_pages = pages, |
2743 | .acl_len = buflen, | 3183 | .acl_len = buflen, |
2744 | }; | 3184 | }; |
2745 | size_t resp_len = buflen; | 3185 | struct nfs_getaclres res = { |
3186 | .acl_len = buflen, | ||
3187 | }; | ||
2746 | void *resp_buf; | 3188 | void *resp_buf; |
2747 | struct rpc_message msg = { | 3189 | struct rpc_message msg = { |
2748 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], | 3190 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], |
2749 | .rpc_argp = &args, | 3191 | .rpc_argp = &args, |
2750 | .rpc_resp = &resp_len, | 3192 | .rpc_resp = &res, |
2751 | }; | 3193 | }; |
2752 | struct page *localpage = NULL; | 3194 | struct page *localpage = NULL; |
2753 | int ret; | 3195 | int ret; |
@@ -2761,26 +3203,26 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
2761 | return -ENOMEM; | 3203 | return -ENOMEM; |
2762 | args.acl_pages[0] = localpage; | 3204 | args.acl_pages[0] = localpage; |
2763 | args.acl_pgbase = 0; | 3205 | args.acl_pgbase = 0; |
2764 | resp_len = args.acl_len = PAGE_SIZE; | 3206 | args.acl_len = PAGE_SIZE; |
2765 | } else { | 3207 | } else { |
2766 | resp_buf = buf; | 3208 | resp_buf = buf; |
2767 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | 3209 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); |
2768 | } | 3210 | } |
2769 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 3211 | ret = nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); |
2770 | if (ret) | 3212 | if (ret) |
2771 | goto out_free; | 3213 | goto out_free; |
2772 | if (resp_len > args.acl_len) | 3214 | if (res.acl_len > args.acl_len) |
2773 | nfs4_write_cached_acl(inode, NULL, resp_len); | 3215 | nfs4_write_cached_acl(inode, NULL, res.acl_len); |
2774 | else | 3216 | else |
2775 | nfs4_write_cached_acl(inode, resp_buf, resp_len); | 3217 | nfs4_write_cached_acl(inode, resp_buf, res.acl_len); |
2776 | if (buf) { | 3218 | if (buf) { |
2777 | ret = -ERANGE; | 3219 | ret = -ERANGE; |
2778 | if (resp_len > buflen) | 3220 | if (res.acl_len > buflen) |
2779 | goto out_free; | 3221 | goto out_free; |
2780 | if (localpage) | 3222 | if (localpage) |
2781 | memcpy(buf, resp_buf, resp_len); | 3223 | memcpy(buf, resp_buf, res.acl_len); |
2782 | } | 3224 | } |
2783 | ret = resp_len; | 3225 | ret = res.acl_len; |
2784 | out_free: | 3226 | out_free: |
2785 | if (localpage) | 3227 | if (localpage) |
2786 | __free_page(localpage); | 3228 | __free_page(localpage); |
@@ -2810,8 +3252,6 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | |||
2810 | ret = nfs_revalidate_inode(server, inode); | 3252 | ret = nfs_revalidate_inode(server, inode); |
2811 | if (ret < 0) | 3253 | if (ret < 0) |
2812 | return ret; | 3254 | return ret; |
2813 | if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) | ||
2814 | nfs_zap_acl_cache(inode); | ||
2815 | ret = nfs4_read_cached_acl(inode, buf, buflen); | 3255 | ret = nfs4_read_cached_acl(inode, buf, buflen); |
2816 | if (ret != -ENOENT) | 3256 | if (ret != -ENOENT) |
2817 | return ret; | 3257 | return ret; |
@@ -2827,10 +3267,11 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
2827 | .acl_pages = pages, | 3267 | .acl_pages = pages, |
2828 | .acl_len = buflen, | 3268 | .acl_len = buflen, |
2829 | }; | 3269 | }; |
3270 | struct nfs_setaclres res; | ||
2830 | struct rpc_message msg = { | 3271 | struct rpc_message msg = { |
2831 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], | 3272 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], |
2832 | .rpc_argp = &arg, | 3273 | .rpc_argp = &arg, |
2833 | .rpc_resp = NULL, | 3274 | .rpc_resp = &res, |
2834 | }; | 3275 | }; |
2835 | int ret; | 3276 | int ret; |
2836 | 3277 | ||
@@ -2838,7 +3279,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
2838 | return -EOPNOTSUPP; | 3279 | return -EOPNOTSUPP; |
2839 | nfs_inode_return_delegation(inode); | 3280 | nfs_inode_return_delegation(inode); |
2840 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 3281 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
2841 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 3282 | ret = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2842 | nfs_access_zap_cache(inode); | 3283 | nfs_access_zap_cache(inode); |
2843 | nfs_zap_acl_cache(inode); | 3284 | nfs_zap_acl_cache(inode); |
2844 | return ret; | 3285 | return ret; |
@@ -2857,10 +3298,8 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
2857 | } | 3298 | } |
2858 | 3299 | ||
2859 | static int | 3300 | static int |
2860 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | 3301 | _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs_client *clp, struct nfs4_state *state) |
2861 | { | 3302 | { |
2862 | struct nfs_client *clp = server->nfs_client; | ||
2863 | |||
2864 | if (!clp || task->tk_status >= 0) | 3303 | if (!clp || task->tk_status >= 0) |
2865 | return 0; | 3304 | return 0; |
2866 | switch(task->tk_status) { | 3305 | switch(task->tk_status) { |
@@ -2879,8 +3318,23 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
2879 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | 3318 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
2880 | task->tk_status = 0; | 3319 | task->tk_status = 0; |
2881 | return -EAGAIN; | 3320 | return -EAGAIN; |
3321 | #if defined(CONFIG_NFS_V4_1) | ||
3322 | case -NFS4ERR_BADSESSION: | ||
3323 | case -NFS4ERR_BADSLOT: | ||
3324 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
3325 | case -NFS4ERR_DEADSESSION: | ||
3326 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
3327 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
3328 | case -NFS4ERR_SEQ_MISORDERED: | ||
3329 | dprintk("%s ERROR %d, Reset session\n", __func__, | ||
3330 | task->tk_status); | ||
3331 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
3332 | task->tk_status = 0; | ||
3333 | return -EAGAIN; | ||
3334 | #endif /* CONFIG_NFS_V4_1 */ | ||
2882 | case -NFS4ERR_DELAY: | 3335 | case -NFS4ERR_DELAY: |
2883 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 3336 | if (server) |
3337 | nfs_inc_server_stats(server, NFSIOS_DELAY); | ||
2884 | case -NFS4ERR_GRACE: | 3338 | case -NFS4ERR_GRACE: |
2885 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3339 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
2886 | task->tk_status = 0; | 3340 | task->tk_status = 0; |
@@ -2893,6 +3347,12 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
2893 | return 0; | 3347 | return 0; |
2894 | } | 3348 | } |
2895 | 3349 | ||
3350 | static int | ||
3351 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | ||
3352 | { | ||
3353 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); | ||
3354 | } | ||
3355 | |||
2896 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 3356 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
2897 | { | 3357 | { |
2898 | nfs4_verifier sc_verifier; | 3358 | nfs4_verifier sc_verifier; |
@@ -3000,6 +3460,10 @@ struct nfs4_delegreturndata { | |||
3000 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | 3460 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) |
3001 | { | 3461 | { |
3002 | struct nfs4_delegreturndata *data = calldata; | 3462 | struct nfs4_delegreturndata *data = calldata; |
3463 | |||
3464 | nfs4_sequence_done_free_slot(data->res.server, &data->res.seq_res, | ||
3465 | task->tk_status); | ||
3466 | |||
3003 | data->rpc_status = task->tk_status; | 3467 | data->rpc_status = task->tk_status; |
3004 | if (data->rpc_status == 0) | 3468 | if (data->rpc_status == 0) |
3005 | renew_lease(data->res.server, data->timestamp); | 3469 | renew_lease(data->res.server, data->timestamp); |
@@ -3010,7 +3474,25 @@ static void nfs4_delegreturn_release(void *calldata) | |||
3010 | kfree(calldata); | 3474 | kfree(calldata); |
3011 | } | 3475 | } |
3012 | 3476 | ||
3477 | #if defined(CONFIG_NFS_V4_1) | ||
3478 | static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | ||
3479 | { | ||
3480 | struct nfs4_delegreturndata *d_data; | ||
3481 | |||
3482 | d_data = (struct nfs4_delegreturndata *)data; | ||
3483 | |||
3484 | if (nfs4_setup_sequence(d_data->res.server->nfs_client, | ||
3485 | &d_data->args.seq_args, | ||
3486 | &d_data->res.seq_res, 1, task)) | ||
3487 | return; | ||
3488 | rpc_call_start(task); | ||
3489 | } | ||
3490 | #endif /* CONFIG_NFS_V4_1 */ | ||
3491 | |||
3013 | static const struct rpc_call_ops nfs4_delegreturn_ops = { | 3492 | static const struct rpc_call_ops nfs4_delegreturn_ops = { |
3493 | #if defined(CONFIG_NFS_V4_1) | ||
3494 | .rpc_call_prepare = nfs4_delegreturn_prepare, | ||
3495 | #endif /* CONFIG_NFS_V4_1 */ | ||
3014 | .rpc_call_done = nfs4_delegreturn_done, | 3496 | .rpc_call_done = nfs4_delegreturn_done, |
3015 | .rpc_release = nfs4_delegreturn_release, | 3497 | .rpc_release = nfs4_delegreturn_release, |
3016 | }; | 3498 | }; |
@@ -3032,7 +3514,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3032 | }; | 3514 | }; |
3033 | int status = 0; | 3515 | int status = 0; |
3034 | 3516 | ||
3035 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 3517 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
3036 | if (data == NULL) | 3518 | if (data == NULL) |
3037 | return -ENOMEM; | 3519 | return -ENOMEM; |
3038 | data->args.fhandle = &data->fh; | 3520 | data->args.fhandle = &data->fh; |
@@ -3042,6 +3524,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3042 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | 3524 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); |
3043 | data->res.fattr = &data->fattr; | 3525 | data->res.fattr = &data->fattr; |
3044 | data->res.server = server; | 3526 | data->res.server = server; |
3527 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3045 | nfs_fattr_init(data->res.fattr); | 3528 | nfs_fattr_init(data->res.fattr); |
3046 | data->timestamp = jiffies; | 3529 | data->timestamp = jiffies; |
3047 | data->rpc_status = 0; | 3530 | data->rpc_status = 0; |
@@ -3127,7 +3610,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3127 | goto out; | 3610 | goto out; |
3128 | lsp = request->fl_u.nfs4_fl.owner; | 3611 | lsp = request->fl_u.nfs4_fl.owner; |
3129 | arg.lock_owner.id = lsp->ls_id.id; | 3612 | arg.lock_owner.id = lsp->ls_id.id; |
3130 | status = rpc_call_sync(server->client, &msg, 0); | 3613 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
3131 | switch (status) { | 3614 | switch (status) { |
3132 | case 0: | 3615 | case 0: |
3133 | request->fl_type = F_UNLCK; | 3616 | request->fl_type = F_UNLCK; |
@@ -3187,13 +3670,14 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
3187 | struct nfs4_unlockdata *p; | 3670 | struct nfs4_unlockdata *p; |
3188 | struct inode *inode = lsp->ls_state->inode; | 3671 | struct inode *inode = lsp->ls_state->inode; |
3189 | 3672 | ||
3190 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 3673 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
3191 | if (p == NULL) | 3674 | if (p == NULL) |
3192 | return NULL; | 3675 | return NULL; |
3193 | p->arg.fh = NFS_FH(inode); | 3676 | p->arg.fh = NFS_FH(inode); |
3194 | p->arg.fl = &p->fl; | 3677 | p->arg.fl = &p->fl; |
3195 | p->arg.seqid = seqid; | 3678 | p->arg.seqid = seqid; |
3196 | p->res.seqid = seqid; | 3679 | p->res.seqid = seqid; |
3680 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3197 | p->arg.stateid = &lsp->ls_stateid; | 3681 | p->arg.stateid = &lsp->ls_stateid; |
3198 | p->lsp = lsp; | 3682 | p->lsp = lsp; |
3199 | atomic_inc(&lsp->ls_count); | 3683 | atomic_inc(&lsp->ls_count); |
@@ -3217,6 +3701,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3217 | { | 3701 | { |
3218 | struct nfs4_unlockdata *calldata = data; | 3702 | struct nfs4_unlockdata *calldata = data; |
3219 | 3703 | ||
3704 | nfs4_sequence_done(calldata->server, &calldata->res.seq_res, | ||
3705 | task->tk_status); | ||
3220 | if (RPC_ASSASSINATED(task)) | 3706 | if (RPC_ASSASSINATED(task)) |
3221 | return; | 3707 | return; |
3222 | switch (task->tk_status) { | 3708 | switch (task->tk_status) { |
@@ -3233,8 +3719,11 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3233 | break; | 3719 | break; |
3234 | default: | 3720 | default: |
3235 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) | 3721 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
3236 | rpc_restart_call(task); | 3722 | nfs4_restart_rpc(task, |
3723 | calldata->server->nfs_client); | ||
3237 | } | 3724 | } |
3725 | nfs4_sequence_free_slot(calldata->server->nfs_client, | ||
3726 | &calldata->res.seq_res); | ||
3238 | } | 3727 | } |
3239 | 3728 | ||
3240 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) | 3729 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
@@ -3249,6 +3738,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
3249 | return; | 3738 | return; |
3250 | } | 3739 | } |
3251 | calldata->timestamp = jiffies; | 3740 | calldata->timestamp = jiffies; |
3741 | if (nfs4_setup_sequence(calldata->server->nfs_client, | ||
3742 | &calldata->arg.seq_args, | ||
3743 | &calldata->res.seq_res, 1, task)) | ||
3744 | return; | ||
3252 | rpc_call_start(task); | 3745 | rpc_call_start(task); |
3253 | } | 3746 | } |
3254 | 3747 | ||
@@ -3341,6 +3834,7 @@ struct nfs4_lockdata { | |||
3341 | unsigned long timestamp; | 3834 | unsigned long timestamp; |
3342 | int rpc_status; | 3835 | int rpc_status; |
3343 | int cancelled; | 3836 | int cancelled; |
3837 | struct nfs_server *server; | ||
3344 | }; | 3838 | }; |
3345 | 3839 | ||
3346 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | 3840 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, |
@@ -3366,7 +3860,9 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3366 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3860 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3367 | p->arg.lock_owner.id = lsp->ls_id.id; | 3861 | p->arg.lock_owner.id = lsp->ls_id.id; |
3368 | p->res.lock_seqid = p->arg.lock_seqid; | 3862 | p->res.lock_seqid = p->arg.lock_seqid; |
3863 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3369 | p->lsp = lsp; | 3864 | p->lsp = lsp; |
3865 | p->server = server; | ||
3370 | atomic_inc(&lsp->ls_count); | 3866 | atomic_inc(&lsp->ls_count); |
3371 | p->ctx = get_nfs_open_context(ctx); | 3867 | p->ctx = get_nfs_open_context(ctx); |
3372 | memcpy(&p->fl, fl, sizeof(p->fl)); | 3868 | memcpy(&p->fl, fl, sizeof(p->fl)); |
@@ -3396,6 +3892,9 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
3396 | } else | 3892 | } else |
3397 | data->arg.new_lock_owner = 0; | 3893 | data->arg.new_lock_owner = 0; |
3398 | data->timestamp = jiffies; | 3894 | data->timestamp = jiffies; |
3895 | if (nfs4_setup_sequence(data->server->nfs_client, &data->arg.seq_args, | ||
3896 | &data->res.seq_res, 1, task)) | ||
3897 | return; | ||
3399 | rpc_call_start(task); | 3898 | rpc_call_start(task); |
3400 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); | 3899 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); |
3401 | } | 3900 | } |
@@ -3406,6 +3905,9 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3406 | 3905 | ||
3407 | dprintk("%s: begin!\n", __func__); | 3906 | dprintk("%s: begin!\n", __func__); |
3408 | 3907 | ||
3908 | nfs4_sequence_done_free_slot(data->server, &data->res.seq_res, | ||
3909 | task->tk_status); | ||
3910 | |||
3409 | data->rpc_status = task->tk_status; | 3911 | data->rpc_status = task->tk_status; |
3410 | if (RPC_ASSASSINATED(task)) | 3912 | if (RPC_ASSASSINATED(task)) |
3411 | goto out; | 3913 | goto out; |
@@ -3487,8 +3989,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
3487 | ret = nfs4_wait_for_completion_rpc_task(task); | 3989 | ret = nfs4_wait_for_completion_rpc_task(task); |
3488 | if (ret == 0) { | 3990 | if (ret == 0) { |
3489 | ret = data->rpc_status; | 3991 | ret = data->rpc_status; |
3490 | if (ret == -NFS4ERR_DENIED) | ||
3491 | ret = -EAGAIN; | ||
3492 | } else | 3992 | } else |
3493 | data->cancelled = 1; | 3993 | data->cancelled = 1; |
3494 | rpc_put_task(task); | 3994 | rpc_put_task(task); |
@@ -3576,9 +4076,11 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock * | |||
3576 | int err; | 4076 | int err; |
3577 | 4077 | ||
3578 | do { | 4078 | do { |
4079 | err = _nfs4_proc_setlk(state, cmd, request); | ||
4080 | if (err == -NFS4ERR_DENIED) | ||
4081 | err = -EAGAIN; | ||
3579 | err = nfs4_handle_exception(NFS_SERVER(state->inode), | 4082 | err = nfs4_handle_exception(NFS_SERVER(state->inode), |
3580 | _nfs4_proc_setlk(state, cmd, request), | 4083 | err, &exception); |
3581 | &exception); | ||
3582 | } while (exception.retry); | 4084 | } while (exception.retry); |
3583 | return err; | 4085 | return err; |
3584 | } | 4086 | } |
@@ -3630,8 +4132,37 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
3630 | goto out; | 4132 | goto out; |
3631 | do { | 4133 | do { |
3632 | err = _nfs4_do_setlk(state, F_SETLK, fl, 0); | 4134 | err = _nfs4_do_setlk(state, F_SETLK, fl, 0); |
3633 | if (err != -NFS4ERR_DELAY) | 4135 | switch (err) { |
3634 | break; | 4136 | default: |
4137 | printk(KERN_ERR "%s: unhandled error %d.\n", | ||
4138 | __func__, err); | ||
4139 | case 0: | ||
4140 | case -ESTALE: | ||
4141 | goto out; | ||
4142 | case -NFS4ERR_EXPIRED: | ||
4143 | case -NFS4ERR_STALE_CLIENTID: | ||
4144 | case -NFS4ERR_STALE_STATEID: | ||
4145 | nfs4_schedule_state_recovery(server->nfs_client); | ||
4146 | goto out; | ||
4147 | case -ERESTARTSYS: | ||
4148 | /* | ||
4149 | * The show must go on: exit, but mark the | ||
4150 | * stateid as needing recovery. | ||
4151 | */ | ||
4152 | case -NFS4ERR_ADMIN_REVOKED: | ||
4153 | case -NFS4ERR_BAD_STATEID: | ||
4154 | case -NFS4ERR_OPENMODE: | ||
4155 | nfs4_state_mark_reclaim_nograce(server->nfs_client, state); | ||
4156 | err = 0; | ||
4157 | goto out; | ||
4158 | case -ENOMEM: | ||
4159 | case -NFS4ERR_DENIED: | ||
4160 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | ||
4161 | err = 0; | ||
4162 | goto out; | ||
4163 | case -NFS4ERR_DELAY: | ||
4164 | break; | ||
4165 | } | ||
3635 | err = nfs4_handle_exception(server, err, &exception); | 4166 | err = nfs4_handle_exception(server, err, &exception); |
3636 | } while (exception.retry); | 4167 | } while (exception.retry); |
3637 | out: | 4168 | out: |
@@ -3706,10 +4237,13 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
3706 | .page = page, | 4237 | .page = page, |
3707 | .bitmask = bitmask, | 4238 | .bitmask = bitmask, |
3708 | }; | 4239 | }; |
4240 | struct nfs4_fs_locations_res res = { | ||
4241 | .fs_locations = fs_locations, | ||
4242 | }; | ||
3709 | struct rpc_message msg = { | 4243 | struct rpc_message msg = { |
3710 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], | 4244 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], |
3711 | .rpc_argp = &args, | 4245 | .rpc_argp = &args, |
3712 | .rpc_resp = fs_locations, | 4246 | .rpc_resp = &res, |
3713 | }; | 4247 | }; |
3714 | int status; | 4248 | int status; |
3715 | 4249 | ||
@@ -3717,24 +4251,720 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
3717 | nfs_fattr_init(&fs_locations->fattr); | 4251 | nfs_fattr_init(&fs_locations->fattr); |
3718 | fs_locations->server = server; | 4252 | fs_locations->server = server; |
3719 | fs_locations->nlocations = 0; | 4253 | fs_locations->nlocations = 0; |
3720 | status = rpc_call_sync(server->client, &msg, 0); | 4254 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
3721 | nfs_fixup_referral_attributes(&fs_locations->fattr); | 4255 | nfs_fixup_referral_attributes(&fs_locations->fattr); |
3722 | dprintk("%s: returned status = %d\n", __func__, status); | 4256 | dprintk("%s: returned status = %d\n", __func__, status); |
3723 | return status; | 4257 | return status; |
3724 | } | 4258 | } |
3725 | 4259 | ||
3726 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 4260 | #ifdef CONFIG_NFS_V4_1 |
4261 | /* | ||
4262 | * nfs4_proc_exchange_id() | ||
4263 | * | ||
4264 | * Since the clientid has expired, all compounds using sessions | ||
4265 | * associated with the stale clientid will be returning | ||
4266 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore | ||
4267 | * be in some phase of session reset. | ||
4268 | */ | ||
4269 | static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | ||
4270 | { | ||
4271 | nfs4_verifier verifier; | ||
4272 | struct nfs41_exchange_id_args args = { | ||
4273 | .client = clp, | ||
4274 | .flags = clp->cl_exchange_flags, | ||
4275 | }; | ||
4276 | struct nfs41_exchange_id_res res = { | ||
4277 | .client = clp, | ||
4278 | }; | ||
4279 | int status; | ||
4280 | struct rpc_message msg = { | ||
4281 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID], | ||
4282 | .rpc_argp = &args, | ||
4283 | .rpc_resp = &res, | ||
4284 | .rpc_cred = cred, | ||
4285 | }; | ||
4286 | __be32 *p; | ||
4287 | |||
4288 | dprintk("--> %s\n", __func__); | ||
4289 | BUG_ON(clp == NULL); | ||
4290 | |||
4291 | p = (u32 *)verifier.data; | ||
4292 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | ||
4293 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
4294 | args.verifier = &verifier; | ||
4295 | |||
4296 | while (1) { | ||
4297 | args.id_len = scnprintf(args.id, sizeof(args.id), | ||
4298 | "%s/%s %u", | ||
4299 | clp->cl_ipaddr, | ||
4300 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
4301 | RPC_DISPLAY_ADDR), | ||
4302 | clp->cl_id_uniquifier); | ||
4303 | |||
4304 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | ||
4305 | |||
4306 | if (status != NFS4ERR_CLID_INUSE) | ||
4307 | break; | ||
4308 | |||
4309 | if (signalled()) | ||
4310 | break; | ||
4311 | |||
4312 | if (++clp->cl_id_uniquifier == 0) | ||
4313 | break; | ||
4314 | } | ||
4315 | |||
4316 | dprintk("<-- %s status= %d\n", __func__, status); | ||
4317 | return status; | ||
4318 | } | ||
4319 | |||
4320 | struct nfs4_get_lease_time_data { | ||
4321 | struct nfs4_get_lease_time_args *args; | ||
4322 | struct nfs4_get_lease_time_res *res; | ||
4323 | struct nfs_client *clp; | ||
4324 | }; | ||
4325 | |||
4326 | static void nfs4_get_lease_time_prepare(struct rpc_task *task, | ||
4327 | void *calldata) | ||
4328 | { | ||
4329 | int ret; | ||
4330 | struct nfs4_get_lease_time_data *data = | ||
4331 | (struct nfs4_get_lease_time_data *)calldata; | ||
4332 | |||
4333 | dprintk("--> %s\n", __func__); | ||
4334 | /* just setup sequence, do not trigger session recovery | ||
4335 | since we're invoked within one */ | ||
4336 | ret = nfs41_setup_sequence(data->clp->cl_session, | ||
4337 | &data->args->la_seq_args, | ||
4338 | &data->res->lr_seq_res, 0, task); | ||
4339 | |||
4340 | BUG_ON(ret == -EAGAIN); | ||
4341 | rpc_call_start(task); | ||
4342 | dprintk("<-- %s\n", __func__); | ||
4343 | } | ||
4344 | |||
4345 | /* | ||
4346 | * Called from nfs4_state_manager thread for session setup, so don't recover | ||
4347 | * from sequence operation or clientid errors. | ||
4348 | */ | ||
4349 | static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | ||
4350 | { | ||
4351 | struct nfs4_get_lease_time_data *data = | ||
4352 | (struct nfs4_get_lease_time_data *)calldata; | ||
4353 | |||
4354 | dprintk("--> %s\n", __func__); | ||
4355 | nfs41_sequence_done(data->clp, &data->res->lr_seq_res, task->tk_status); | ||
4356 | switch (task->tk_status) { | ||
4357 | case -NFS4ERR_DELAY: | ||
4358 | case -NFS4ERR_GRACE: | ||
4359 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | ||
4360 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | ||
4361 | task->tk_status = 0; | ||
4362 | nfs4_restart_rpc(task, data->clp); | ||
4363 | return; | ||
4364 | } | ||
4365 | nfs41_sequence_free_slot(data->clp, &data->res->lr_seq_res); | ||
4366 | dprintk("<-- %s\n", __func__); | ||
4367 | } | ||
4368 | |||
4369 | struct rpc_call_ops nfs4_get_lease_time_ops = { | ||
4370 | .rpc_call_prepare = nfs4_get_lease_time_prepare, | ||
4371 | .rpc_call_done = nfs4_get_lease_time_done, | ||
4372 | }; | ||
4373 | |||
4374 | int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | ||
4375 | { | ||
4376 | struct rpc_task *task; | ||
4377 | struct nfs4_get_lease_time_args args; | ||
4378 | struct nfs4_get_lease_time_res res = { | ||
4379 | .lr_fsinfo = fsinfo, | ||
4380 | }; | ||
4381 | struct nfs4_get_lease_time_data data = { | ||
4382 | .args = &args, | ||
4383 | .res = &res, | ||
4384 | .clp = clp, | ||
4385 | }; | ||
4386 | struct rpc_message msg = { | ||
4387 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GET_LEASE_TIME], | ||
4388 | .rpc_argp = &args, | ||
4389 | .rpc_resp = &res, | ||
4390 | }; | ||
4391 | struct rpc_task_setup task_setup = { | ||
4392 | .rpc_client = clp->cl_rpcclient, | ||
4393 | .rpc_message = &msg, | ||
4394 | .callback_ops = &nfs4_get_lease_time_ops, | ||
4395 | .callback_data = &data | ||
4396 | }; | ||
4397 | int status; | ||
4398 | |||
4399 | res.lr_seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4400 | dprintk("--> %s\n", __func__); | ||
4401 | task = rpc_run_task(&task_setup); | ||
4402 | |||
4403 | if (IS_ERR(task)) | ||
4404 | status = PTR_ERR(task); | ||
4405 | else { | ||
4406 | status = task->tk_status; | ||
4407 | rpc_put_task(task); | ||
4408 | } | ||
4409 | dprintk("<-- %s return %d\n", __func__, status); | ||
4410 | |||
4411 | return status; | ||
4412 | } | ||
4413 | |||
4414 | /* | ||
4415 | * Reset a slot table | ||
4416 | */ | ||
4417 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots, | ||
4418 | int old_max_slots, int ivalue) | ||
4419 | { | ||
4420 | int i; | ||
4421 | int ret = 0; | ||
4422 | |||
4423 | dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__, max_slots, tbl); | ||
4424 | |||
4425 | /* | ||
4426 | * Until we have dynamic slot table adjustment, insist | ||
4427 | * upon the same slot table size | ||
4428 | */ | ||
4429 | if (max_slots != old_max_slots) { | ||
4430 | dprintk("%s reset slot table does't match old\n", | ||
4431 | __func__); | ||
4432 | ret = -EINVAL; /*XXX NFS4ERR_REQ_TOO_BIG ? */ | ||
4433 | goto out; | ||
4434 | } | ||
4435 | spin_lock(&tbl->slot_tbl_lock); | ||
4436 | for (i = 0; i < max_slots; ++i) | ||
4437 | tbl->slots[i].seq_nr = ivalue; | ||
4438 | tbl->highest_used_slotid = -1; | ||
4439 | spin_unlock(&tbl->slot_tbl_lock); | ||
4440 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
4441 | tbl, tbl->slots, tbl->max_slots); | ||
4442 | out: | ||
4443 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
4444 | return ret; | ||
4445 | } | ||
4446 | |||
4447 | /* | ||
4448 | * Reset the forechannel and backchannel slot tables | ||
4449 | */ | ||
4450 | static int nfs4_reset_slot_tables(struct nfs4_session *session) | ||
4451 | { | ||
4452 | int status; | ||
4453 | |||
4454 | status = nfs4_reset_slot_table(&session->fc_slot_table, | ||
4455 | session->fc_attrs.max_reqs, | ||
4456 | session->fc_slot_table.max_slots, | ||
4457 | 1); | ||
4458 | if (status) | ||
4459 | return status; | ||
4460 | |||
4461 | status = nfs4_reset_slot_table(&session->bc_slot_table, | ||
4462 | session->bc_attrs.max_reqs, | ||
4463 | session->bc_slot_table.max_slots, | ||
4464 | 0); | ||
4465 | return status; | ||
4466 | } | ||
4467 | |||
4468 | /* Destroy the slot table */ | ||
4469 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) | ||
4470 | { | ||
4471 | if (session->fc_slot_table.slots != NULL) { | ||
4472 | kfree(session->fc_slot_table.slots); | ||
4473 | session->fc_slot_table.slots = NULL; | ||
4474 | } | ||
4475 | if (session->bc_slot_table.slots != NULL) { | ||
4476 | kfree(session->bc_slot_table.slots); | ||
4477 | session->bc_slot_table.slots = NULL; | ||
4478 | } | ||
4479 | return; | ||
4480 | } | ||
4481 | |||
4482 | /* | ||
4483 | * Initialize slot table | ||
4484 | */ | ||
4485 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | ||
4486 | int max_slots, int ivalue) | ||
4487 | { | ||
4488 | int i; | ||
4489 | struct nfs4_slot *slot; | ||
4490 | int ret = -ENOMEM; | ||
4491 | |||
4492 | BUG_ON(max_slots > NFS4_MAX_SLOT_TABLE); | ||
4493 | |||
4494 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); | ||
4495 | |||
4496 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); | ||
4497 | if (!slot) | ||
4498 | goto out; | ||
4499 | for (i = 0; i < max_slots; ++i) | ||
4500 | slot[i].seq_nr = ivalue; | ||
4501 | ret = 0; | ||
4502 | |||
4503 | spin_lock(&tbl->slot_tbl_lock); | ||
4504 | if (tbl->slots != NULL) { | ||
4505 | spin_unlock(&tbl->slot_tbl_lock); | ||
4506 | dprintk("%s: slot table already initialized. tbl=%p slots=%p\n", | ||
4507 | __func__, tbl, tbl->slots); | ||
4508 | WARN_ON(1); | ||
4509 | goto out_free; | ||
4510 | } | ||
4511 | tbl->max_slots = max_slots; | ||
4512 | tbl->slots = slot; | ||
4513 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | ||
4514 | spin_unlock(&tbl->slot_tbl_lock); | ||
4515 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
4516 | tbl, tbl->slots, tbl->max_slots); | ||
4517 | out: | ||
4518 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
4519 | return ret; | ||
4520 | |||
4521 | out_free: | ||
4522 | kfree(slot); | ||
4523 | goto out; | ||
4524 | } | ||
4525 | |||
4526 | /* | ||
4527 | * Initialize the forechannel and backchannel tables | ||
4528 | */ | ||
4529 | static int nfs4_init_slot_tables(struct nfs4_session *session) | ||
4530 | { | ||
4531 | int status; | ||
4532 | |||
4533 | status = nfs4_init_slot_table(&session->fc_slot_table, | ||
4534 | session->fc_attrs.max_reqs, 1); | ||
4535 | if (status) | ||
4536 | return status; | ||
4537 | |||
4538 | status = nfs4_init_slot_table(&session->bc_slot_table, | ||
4539 | session->bc_attrs.max_reqs, 0); | ||
4540 | if (status) | ||
4541 | nfs4_destroy_slot_tables(session); | ||
4542 | |||
4543 | return status; | ||
4544 | } | ||
4545 | |||
4546 | struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | ||
4547 | { | ||
4548 | struct nfs4_session *session; | ||
4549 | struct nfs4_slot_table *tbl; | ||
4550 | |||
4551 | session = kzalloc(sizeof(struct nfs4_session), GFP_KERNEL); | ||
4552 | if (!session) | ||
4553 | return NULL; | ||
4554 | |||
4555 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
4556 | /* | ||
4557 | * The create session reply races with the server back | ||
4558 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
4559 | * so that the client back channel can find the | ||
4560 | * nfs_client struct | ||
4561 | */ | ||
4562 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | ||
4563 | |||
4564 | tbl = &session->fc_slot_table; | ||
4565 | spin_lock_init(&tbl->slot_tbl_lock); | ||
4566 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | ||
4567 | |||
4568 | tbl = &session->bc_slot_table; | ||
4569 | spin_lock_init(&tbl->slot_tbl_lock); | ||
4570 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | ||
4571 | |||
4572 | session->clp = clp; | ||
4573 | return session; | ||
4574 | } | ||
4575 | |||
4576 | void nfs4_destroy_session(struct nfs4_session *session) | ||
4577 | { | ||
4578 | nfs4_proc_destroy_session(session); | ||
4579 | dprintk("%s Destroy backchannel for xprt %p\n", | ||
4580 | __func__, session->clp->cl_rpcclient->cl_xprt); | ||
4581 | xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt, | ||
4582 | NFS41_BC_MIN_CALLBACKS); | ||
4583 | nfs4_destroy_slot_tables(session); | ||
4584 | kfree(session); | ||
4585 | } | ||
4586 | |||
4587 | /* | ||
4588 | * Initialize the values to be used by the client in CREATE_SESSION | ||
4589 | * If nfs4_init_session set the fore channel request and response sizes, | ||
4590 | * use them. | ||
4591 | * | ||
4592 | * Set the back channel max_resp_sz_cached to zero to force the client to | ||
4593 | * always set csa_cachethis to FALSE because the current implementation | ||
4594 | * of the back channel DRC only supports caching the CB_SEQUENCE operation. | ||
4595 | */ | ||
4596 | static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | ||
4597 | { | ||
4598 | struct nfs4_session *session = args->client->cl_session; | ||
4599 | unsigned int mxrqst_sz = session->fc_attrs.max_rqst_sz, | ||
4600 | mxresp_sz = session->fc_attrs.max_resp_sz; | ||
4601 | |||
4602 | if (mxrqst_sz == 0) | ||
4603 | mxrqst_sz = NFS_MAX_FILE_IO_SIZE; | ||
4604 | if (mxresp_sz == 0) | ||
4605 | mxresp_sz = NFS_MAX_FILE_IO_SIZE; | ||
4606 | /* Fore channel attributes */ | ||
4607 | args->fc_attrs.headerpadsz = 0; | ||
4608 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | ||
4609 | args->fc_attrs.max_resp_sz = mxresp_sz; | ||
4610 | args->fc_attrs.max_resp_sz_cached = mxresp_sz; | ||
4611 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | ||
4612 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; | ||
4613 | |||
4614 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " | ||
4615 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | ||
4616 | __func__, | ||
4617 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, | ||
4618 | args->fc_attrs.max_resp_sz_cached, args->fc_attrs.max_ops, | ||
4619 | args->fc_attrs.max_reqs); | ||
4620 | |||
4621 | /* Back channel attributes */ | ||
4622 | args->bc_attrs.headerpadsz = 0; | ||
4623 | args->bc_attrs.max_rqst_sz = PAGE_SIZE; | ||
4624 | args->bc_attrs.max_resp_sz = PAGE_SIZE; | ||
4625 | args->bc_attrs.max_resp_sz_cached = 0; | ||
4626 | args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS; | ||
4627 | args->bc_attrs.max_reqs = 1; | ||
4628 | |||
4629 | dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u " | ||
4630 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | ||
4631 | __func__, | ||
4632 | args->bc_attrs.max_rqst_sz, args->bc_attrs.max_resp_sz, | ||
4633 | args->bc_attrs.max_resp_sz_cached, args->bc_attrs.max_ops, | ||
4634 | args->bc_attrs.max_reqs); | ||
4635 | } | ||
4636 | |||
4637 | static int _verify_channel_attr(char *chan, char *attr_name, u32 sent, u32 rcvd) | ||
4638 | { | ||
4639 | if (rcvd <= sent) | ||
4640 | return 0; | ||
4641 | printk(KERN_WARNING "%s: Session INVALID: %s channel %s increased. " | ||
4642 | "sent=%u rcvd=%u\n", __func__, chan, attr_name, sent, rcvd); | ||
4643 | return -EINVAL; | ||
4644 | } | ||
4645 | |||
4646 | #define _verify_fore_channel_attr(_name_) \ | ||
4647 | _verify_channel_attr("fore", #_name_, \ | ||
4648 | args->fc_attrs._name_, \ | ||
4649 | session->fc_attrs._name_) | ||
4650 | |||
4651 | #define _verify_back_channel_attr(_name_) \ | ||
4652 | _verify_channel_attr("back", #_name_, \ | ||
4653 | args->bc_attrs._name_, \ | ||
4654 | session->bc_attrs._name_) | ||
4655 | |||
4656 | /* | ||
4657 | * The server is not allowed to increase the fore channel header pad size, | ||
4658 | * maximum response size, or maximum number of operations. | ||
4659 | * | ||
4660 | * The back channel attributes are only negotiatied down: We send what the | ||
4661 | * (back channel) server insists upon. | ||
4662 | */ | ||
4663 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, | ||
4664 | struct nfs4_session *session) | ||
4665 | { | ||
4666 | int ret = 0; | ||
4667 | |||
4668 | ret |= _verify_fore_channel_attr(headerpadsz); | ||
4669 | ret |= _verify_fore_channel_attr(max_resp_sz); | ||
4670 | ret |= _verify_fore_channel_attr(max_ops); | ||
4671 | |||
4672 | ret |= _verify_back_channel_attr(headerpadsz); | ||
4673 | ret |= _verify_back_channel_attr(max_rqst_sz); | ||
4674 | ret |= _verify_back_channel_attr(max_resp_sz); | ||
4675 | ret |= _verify_back_channel_attr(max_resp_sz_cached); | ||
4676 | ret |= _verify_back_channel_attr(max_ops); | ||
4677 | ret |= _verify_back_channel_attr(max_reqs); | ||
4678 | |||
4679 | return ret; | ||
4680 | } | ||
4681 | |||
4682 | static int _nfs4_proc_create_session(struct nfs_client *clp) | ||
4683 | { | ||
4684 | struct nfs4_session *session = clp->cl_session; | ||
4685 | struct nfs41_create_session_args args = { | ||
4686 | .client = clp, | ||
4687 | .cb_program = NFS4_CALLBACK, | ||
4688 | }; | ||
4689 | struct nfs41_create_session_res res = { | ||
4690 | .client = clp, | ||
4691 | }; | ||
4692 | struct rpc_message msg = { | ||
4693 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION], | ||
4694 | .rpc_argp = &args, | ||
4695 | .rpc_resp = &res, | ||
4696 | }; | ||
4697 | int status; | ||
4698 | |||
4699 | nfs4_init_channel_attrs(&args); | ||
4700 | args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); | ||
4701 | |||
4702 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | ||
4703 | |||
4704 | if (!status) | ||
4705 | /* Verify the session's negotiated channel_attrs values */ | ||
4706 | status = nfs4_verify_channel_attrs(&args, session); | ||
4707 | if (!status) { | ||
4708 | /* Increment the clientid slot sequence id */ | ||
4709 | clp->cl_seqid++; | ||
4710 | } | ||
4711 | |||
4712 | return status; | ||
4713 | } | ||
4714 | |||
4715 | /* | ||
4716 | * Issues a CREATE_SESSION operation to the server. | ||
4717 | * It is the responsibility of the caller to verify the session is | ||
4718 | * expired before calling this routine. | ||
4719 | */ | ||
4720 | int nfs4_proc_create_session(struct nfs_client *clp, int reset) | ||
4721 | { | ||
4722 | int status; | ||
4723 | unsigned *ptr; | ||
4724 | struct nfs_fsinfo fsinfo; | ||
4725 | struct nfs4_session *session = clp->cl_session; | ||
4726 | |||
4727 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); | ||
4728 | |||
4729 | status = _nfs4_proc_create_session(clp); | ||
4730 | if (status) | ||
4731 | goto out; | ||
4732 | |||
4733 | /* Init or reset the fore channel */ | ||
4734 | if (reset) | ||
4735 | status = nfs4_reset_slot_tables(session); | ||
4736 | else | ||
4737 | status = nfs4_init_slot_tables(session); | ||
4738 | dprintk("fore channel slot table initialization returned %d\n", status); | ||
4739 | if (status) | ||
4740 | goto out; | ||
4741 | |||
4742 | ptr = (unsigned *)&session->sess_id.data[0]; | ||
4743 | dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__, | ||
4744 | clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]); | ||
4745 | |||
4746 | if (reset) | ||
4747 | /* Lease time is aleady set */ | ||
4748 | goto out; | ||
4749 | |||
4750 | /* Get the lease time */ | ||
4751 | status = nfs4_proc_get_lease_time(clp, &fsinfo); | ||
4752 | if (status == 0) { | ||
4753 | /* Update lease time and schedule renewal */ | ||
4754 | spin_lock(&clp->cl_lock); | ||
4755 | clp->cl_lease_time = fsinfo.lease_time * HZ; | ||
4756 | clp->cl_last_renewal = jiffies; | ||
4757 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
4758 | spin_unlock(&clp->cl_lock); | ||
4759 | |||
4760 | nfs4_schedule_state_renewal(clp); | ||
4761 | } | ||
4762 | out: | ||
4763 | dprintk("<-- %s\n", __func__); | ||
4764 | return status; | ||
4765 | } | ||
4766 | |||
4767 | /* | ||
4768 | * Issue the over-the-wire RPC DESTROY_SESSION. | ||
4769 | * The caller must serialize access to this routine. | ||
4770 | */ | ||
4771 | int nfs4_proc_destroy_session(struct nfs4_session *session) | ||
4772 | { | ||
4773 | int status = 0; | ||
4774 | struct rpc_message msg; | ||
4775 | |||
4776 | dprintk("--> nfs4_proc_destroy_session\n"); | ||
4777 | |||
4778 | /* session is still being setup */ | ||
4779 | if (session->clp->cl_cons_state != NFS_CS_READY) | ||
4780 | return status; | ||
4781 | |||
4782 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_SESSION]; | ||
4783 | msg.rpc_argp = session; | ||
4784 | msg.rpc_resp = NULL; | ||
4785 | msg.rpc_cred = NULL; | ||
4786 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | ||
4787 | |||
4788 | if (status) | ||
4789 | printk(KERN_WARNING | ||
4790 | "Got error %d from the server on DESTROY_SESSION. " | ||
4791 | "Session has been destroyed regardless...\n", status); | ||
4792 | |||
4793 | dprintk("<-- nfs4_proc_destroy_session\n"); | ||
4794 | return status; | ||
4795 | } | ||
4796 | |||
4797 | /* | ||
4798 | * Renew the cl_session lease. | ||
4799 | */ | ||
4800 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
4801 | { | ||
4802 | struct nfs4_sequence_args args; | ||
4803 | struct nfs4_sequence_res res; | ||
4804 | |||
4805 | struct rpc_message msg = { | ||
4806 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
4807 | .rpc_argp = &args, | ||
4808 | .rpc_resp = &res, | ||
4809 | .rpc_cred = cred, | ||
4810 | }; | ||
4811 | |||
4812 | args.sa_cache_this = 0; | ||
4813 | |||
4814 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | ||
4815 | &res, 0); | ||
4816 | } | ||
4817 | |||
4818 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | ||
4819 | { | ||
4820 | struct nfs_client *clp = (struct nfs_client *)data; | ||
4821 | |||
4822 | nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status); | ||
4823 | |||
4824 | if (task->tk_status < 0) { | ||
4825 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | ||
4826 | |||
4827 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | ||
4828 | == -EAGAIN) { | ||
4829 | nfs4_restart_rpc(task, clp); | ||
4830 | return; | ||
4831 | } | ||
4832 | } | ||
4833 | nfs41_sequence_free_slot(clp, task->tk_msg.rpc_resp); | ||
4834 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | ||
4835 | |||
4836 | put_rpccred(task->tk_msg.rpc_cred); | ||
4837 | kfree(task->tk_msg.rpc_argp); | ||
4838 | kfree(task->tk_msg.rpc_resp); | ||
4839 | |||
4840 | dprintk("<-- %s\n", __func__); | ||
4841 | } | ||
4842 | |||
4843 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | ||
4844 | { | ||
4845 | struct nfs_client *clp; | ||
4846 | struct nfs4_sequence_args *args; | ||
4847 | struct nfs4_sequence_res *res; | ||
4848 | |||
4849 | clp = (struct nfs_client *)data; | ||
4850 | args = task->tk_msg.rpc_argp; | ||
4851 | res = task->tk_msg.rpc_resp; | ||
4852 | |||
4853 | if (nfs4_setup_sequence(clp, args, res, 0, task)) | ||
4854 | return; | ||
4855 | rpc_call_start(task); | ||
4856 | } | ||
4857 | |||
4858 | static const struct rpc_call_ops nfs41_sequence_ops = { | ||
4859 | .rpc_call_done = nfs41_sequence_call_done, | ||
4860 | .rpc_call_prepare = nfs41_sequence_prepare, | ||
4861 | }; | ||
4862 | |||
4863 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | ||
4864 | struct rpc_cred *cred) | ||
4865 | { | ||
4866 | struct nfs4_sequence_args *args; | ||
4867 | struct nfs4_sequence_res *res; | ||
4868 | struct rpc_message msg = { | ||
4869 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
4870 | .rpc_cred = cred, | ||
4871 | }; | ||
4872 | |||
4873 | args = kzalloc(sizeof(*args), GFP_KERNEL); | ||
4874 | if (!args) | ||
4875 | return -ENOMEM; | ||
4876 | res = kzalloc(sizeof(*res), GFP_KERNEL); | ||
4877 | if (!res) { | ||
4878 | kfree(args); | ||
4879 | return -ENOMEM; | ||
4880 | } | ||
4881 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4882 | msg.rpc_argp = args; | ||
4883 | msg.rpc_resp = res; | ||
4884 | |||
4885 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | ||
4886 | &nfs41_sequence_ops, (void *)clp); | ||
4887 | } | ||
4888 | |||
4889 | #endif /* CONFIG_NFS_V4_1 */ | ||
4890 | |||
4891 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | ||
3727 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | 4892 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, |
3728 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | 4893 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, |
3729 | .recover_open = nfs4_open_reclaim, | 4894 | .recover_open = nfs4_open_reclaim, |
3730 | .recover_lock = nfs4_lock_reclaim, | 4895 | .recover_lock = nfs4_lock_reclaim, |
4896 | .establish_clid = nfs4_init_clientid, | ||
4897 | .get_clid_cred = nfs4_get_setclientid_cred, | ||
4898 | }; | ||
4899 | |||
4900 | #if defined(CONFIG_NFS_V4_1) | ||
4901 | struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | ||
4902 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | ||
4903 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | ||
4904 | .recover_open = nfs4_open_reclaim, | ||
4905 | .recover_lock = nfs4_lock_reclaim, | ||
4906 | .establish_clid = nfs4_proc_exchange_id, | ||
4907 | .get_clid_cred = nfs4_get_exchange_id_cred, | ||
4908 | }; | ||
4909 | #endif /* CONFIG_NFS_V4_1 */ | ||
4910 | |||
4911 | struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { | ||
4912 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | ||
4913 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | ||
4914 | .recover_open = nfs4_open_expired, | ||
4915 | .recover_lock = nfs4_lock_expired, | ||
4916 | .establish_clid = nfs4_init_clientid, | ||
4917 | .get_clid_cred = nfs4_get_setclientid_cred, | ||
3731 | }; | 4918 | }; |
3732 | 4919 | ||
3733 | struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops = { | 4920 | #if defined(CONFIG_NFS_V4_1) |
4921 | struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { | ||
3734 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | 4922 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, |
3735 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 4923 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
3736 | .recover_open = nfs4_open_expired, | 4924 | .recover_open = nfs4_open_expired, |
3737 | .recover_lock = nfs4_lock_expired, | 4925 | .recover_lock = nfs4_lock_expired, |
4926 | .establish_clid = nfs4_proc_exchange_id, | ||
4927 | .get_clid_cred = nfs4_get_exchange_id_cred, | ||
4928 | }; | ||
4929 | #endif /* CONFIG_NFS_V4_1 */ | ||
4930 | |||
4931 | struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = { | ||
4932 | .sched_state_renewal = nfs4_proc_async_renew, | ||
4933 | .get_state_renewal_cred_locked = nfs4_get_renew_cred_locked, | ||
4934 | .renew_lease = nfs4_proc_renew, | ||
4935 | }; | ||
4936 | |||
4937 | #if defined(CONFIG_NFS_V4_1) | ||
4938 | struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | ||
4939 | .sched_state_renewal = nfs41_proc_async_sequence, | ||
4940 | .get_state_renewal_cred_locked = nfs4_get_machine_cred_locked, | ||
4941 | .renew_lease = nfs4_proc_sequence, | ||
4942 | }; | ||
4943 | #endif | ||
4944 | |||
4945 | /* | ||
4946 | * Per minor version reboot and network partition recovery ops | ||
4947 | */ | ||
4948 | |||
4949 | struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[] = { | ||
4950 | &nfs40_reboot_recovery_ops, | ||
4951 | #if defined(CONFIG_NFS_V4_1) | ||
4952 | &nfs41_reboot_recovery_ops, | ||
4953 | #endif | ||
4954 | }; | ||
4955 | |||
4956 | struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[] = { | ||
4957 | &nfs40_nograce_recovery_ops, | ||
4958 | #if defined(CONFIG_NFS_V4_1) | ||
4959 | &nfs41_nograce_recovery_ops, | ||
4960 | #endif | ||
4961 | }; | ||
4962 | |||
4963 | struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[] = { | ||
4964 | &nfs40_state_renewal_ops, | ||
4965 | #if defined(CONFIG_NFS_V4_1) | ||
4966 | &nfs41_state_renewal_ops, | ||
4967 | #endif | ||
3738 | }; | 4968 | }; |
3739 | 4969 | ||
3740 | static const struct inode_operations nfs4_file_inode_operations = { | 4970 | static const struct inode_operations nfs4_file_inode_operations = { |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index f524e932ff7b..e27c6cef18f2 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -59,12 +59,14 @@ | |||
59 | void | 59 | void |
60 | nfs4_renew_state(struct work_struct *work) | 60 | nfs4_renew_state(struct work_struct *work) |
61 | { | 61 | { |
62 | struct nfs4_state_maintenance_ops *ops; | ||
62 | struct nfs_client *clp = | 63 | struct nfs_client *clp = |
63 | container_of(work, struct nfs_client, cl_renewd.work); | 64 | container_of(work, struct nfs_client, cl_renewd.work); |
64 | struct rpc_cred *cred; | 65 | struct rpc_cred *cred; |
65 | long lease, timeout; | 66 | long lease, timeout; |
66 | unsigned long last, now; | 67 | unsigned long last, now; |
67 | 68 | ||
69 | ops = nfs4_state_renewal_ops[clp->cl_minorversion]; | ||
68 | dprintk("%s: start\n", __func__); | 70 | dprintk("%s: start\n", __func__); |
69 | /* Are there any active superblocks? */ | 71 | /* Are there any active superblocks? */ |
70 | if (list_empty(&clp->cl_superblocks)) | 72 | if (list_empty(&clp->cl_superblocks)) |
@@ -76,7 +78,7 @@ nfs4_renew_state(struct work_struct *work) | |||
76 | timeout = (2 * lease) / 3 + (long)last - (long)now; | 78 | timeout = (2 * lease) / 3 + (long)last - (long)now; |
77 | /* Are we close to a lease timeout? */ | 79 | /* Are we close to a lease timeout? */ |
78 | if (time_after(now, last + lease/3)) { | 80 | if (time_after(now, last + lease/3)) { |
79 | cred = nfs4_get_renew_cred_locked(clp); | 81 | cred = ops->get_state_renewal_cred_locked(clp); |
80 | spin_unlock(&clp->cl_lock); | 82 | spin_unlock(&clp->cl_lock); |
81 | if (cred == NULL) { | 83 | if (cred == NULL) { |
82 | if (list_empty(&clp->cl_delegations)) { | 84 | if (list_empty(&clp->cl_delegations)) { |
@@ -86,7 +88,7 @@ nfs4_renew_state(struct work_struct *work) | |||
86 | nfs_expire_all_delegations(clp); | 88 | nfs_expire_all_delegations(clp); |
87 | } else { | 89 | } else { |
88 | /* Queue an asynchronous RENEW. */ | 90 | /* Queue an asynchronous RENEW. */ |
89 | nfs4_proc_async_renew(clp, cred); | 91 | ops->sched_state_renewal(clp, cred); |
90 | put_rpccred(cred); | 92 | put_rpccred(cred); |
91 | } | 93 | } |
92 | timeout = (2 * lease) / 3; | 94 | timeout = (2 * lease) / 3; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0298e909559f..b73c5a728655 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -60,7 +60,7 @@ const nfs4_stateid zero_stateid; | |||
60 | 60 | ||
61 | static LIST_HEAD(nfs4_clientid_list); | 61 | static LIST_HEAD(nfs4_clientid_list); |
62 | 62 | ||
63 | static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | 63 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) |
64 | { | 64 | { |
65 | unsigned short port; | 65 | unsigned short port; |
66 | int status; | 66 | int status; |
@@ -77,7 +77,7 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | |||
77 | return status; | 77 | return status; |
78 | } | 78 | } |
79 | 79 | ||
80 | static struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) | 80 | struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) |
81 | { | 81 | { |
82 | struct rpc_cred *cred = NULL; | 82 | struct rpc_cred *cred = NULL; |
83 | 83 | ||
@@ -114,17 +114,21 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp) | |||
114 | return cred; | 114 | return cred; |
115 | } | 115 | } |
116 | 116 | ||
117 | static struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | 117 | #if defined(CONFIG_NFS_V4_1) |
118 | |||
119 | struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp) | ||
118 | { | 120 | { |
119 | struct rpc_cred *cred; | 121 | struct rpc_cred *cred; |
120 | 122 | ||
121 | spin_lock(&clp->cl_lock); | 123 | spin_lock(&clp->cl_lock); |
122 | cred = nfs4_get_renew_cred_locked(clp); | 124 | cred = nfs4_get_machine_cred_locked(clp); |
123 | spin_unlock(&clp->cl_lock); | 125 | spin_unlock(&clp->cl_lock); |
124 | return cred; | 126 | return cred; |
125 | } | 127 | } |
126 | 128 | ||
127 | static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | 129 | #endif /* CONFIG_NFS_V4_1 */ |
130 | |||
131 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | ||
128 | { | 132 | { |
129 | struct nfs4_state_owner *sp; | 133 | struct nfs4_state_owner *sp; |
130 | struct rb_node *pos; | 134 | struct rb_node *pos; |
@@ -738,12 +742,14 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) | |||
738 | 742 | ||
739 | void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) | 743 | void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) |
740 | { | 744 | { |
741 | if (status == -NFS4ERR_BAD_SEQID) { | 745 | struct nfs4_state_owner *sp = container_of(seqid->sequence, |
742 | struct nfs4_state_owner *sp = container_of(seqid->sequence, | 746 | struct nfs4_state_owner, so_seqid); |
743 | struct nfs4_state_owner, so_seqid); | 747 | struct nfs_server *server = sp->so_server; |
748 | |||
749 | if (status == -NFS4ERR_BAD_SEQID) | ||
744 | nfs4_drop_state_owner(sp); | 750 | nfs4_drop_state_owner(sp); |
745 | } | 751 | if (!nfs4_has_session(server->nfs_client)) |
746 | nfs_increment_seqid(status, seqid); | 752 | nfs_increment_seqid(status, seqid); |
747 | } | 753 | } |
748 | 754 | ||
749 | /* | 755 | /* |
@@ -847,32 +853,45 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ | |||
847 | struct file_lock *fl; | 853 | struct file_lock *fl; |
848 | int status = 0; | 854 | int status = 0; |
849 | 855 | ||
856 | if (inode->i_flock == NULL) | ||
857 | return 0; | ||
858 | |||
859 | /* Guard against delegation returns and new lock/unlock calls */ | ||
850 | down_write(&nfsi->rwsem); | 860 | down_write(&nfsi->rwsem); |
861 | /* Protect inode->i_flock using the BKL */ | ||
862 | lock_kernel(); | ||
851 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 863 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
852 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) | 864 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) |
853 | continue; | 865 | continue; |
854 | if (nfs_file_open_context(fl->fl_file)->state != state) | 866 | if (nfs_file_open_context(fl->fl_file)->state != state) |
855 | continue; | 867 | continue; |
868 | unlock_kernel(); | ||
856 | status = ops->recover_lock(state, fl); | 869 | status = ops->recover_lock(state, fl); |
857 | if (status >= 0) | ||
858 | continue; | ||
859 | switch (status) { | 870 | switch (status) { |
871 | case 0: | ||
872 | break; | ||
873 | case -ESTALE: | ||
874 | case -NFS4ERR_ADMIN_REVOKED: | ||
875 | case -NFS4ERR_STALE_STATEID: | ||
876 | case -NFS4ERR_BAD_STATEID: | ||
877 | case -NFS4ERR_EXPIRED: | ||
878 | case -NFS4ERR_NO_GRACE: | ||
879 | case -NFS4ERR_STALE_CLIENTID: | ||
880 | goto out; | ||
860 | default: | 881 | default: |
861 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", | 882 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", |
862 | __func__, status); | 883 | __func__, status); |
863 | case -NFS4ERR_EXPIRED: | 884 | case -ENOMEM: |
864 | case -NFS4ERR_NO_GRACE: | 885 | case -NFS4ERR_DENIED: |
865 | case -NFS4ERR_RECLAIM_BAD: | 886 | case -NFS4ERR_RECLAIM_BAD: |
866 | case -NFS4ERR_RECLAIM_CONFLICT: | 887 | case -NFS4ERR_RECLAIM_CONFLICT: |
867 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | 888 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ |
868 | break; | 889 | status = 0; |
869 | case -NFS4ERR_STALE_CLIENTID: | ||
870 | goto out_err; | ||
871 | } | 890 | } |
891 | lock_kernel(); | ||
872 | } | 892 | } |
873 | up_write(&nfsi->rwsem); | 893 | unlock_kernel(); |
874 | return 0; | 894 | out: |
875 | out_err: | ||
876 | up_write(&nfsi->rwsem); | 895 | up_write(&nfsi->rwsem); |
877 | return status; | 896 | return status; |
878 | } | 897 | } |
@@ -918,6 +937,7 @@ restart: | |||
918 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", | 937 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", |
919 | __func__, status); | 938 | __func__, status); |
920 | case -ENOENT: | 939 | case -ENOENT: |
940 | case -ENOMEM: | ||
921 | case -ESTALE: | 941 | case -ESTALE: |
922 | /* | 942 | /* |
923 | * Open state on this file cannot be recovered | 943 | * Open state on this file cannot be recovered |
@@ -928,6 +948,9 @@ restart: | |||
928 | /* Mark the file as being 'closed' */ | 948 | /* Mark the file as being 'closed' */ |
929 | state->state = 0; | 949 | state->state = 0; |
930 | break; | 950 | break; |
951 | case -NFS4ERR_ADMIN_REVOKED: | ||
952 | case -NFS4ERR_STALE_STATEID: | ||
953 | case -NFS4ERR_BAD_STATEID: | ||
931 | case -NFS4ERR_RECLAIM_BAD: | 954 | case -NFS4ERR_RECLAIM_BAD: |
932 | case -NFS4ERR_RECLAIM_CONFLICT: | 955 | case -NFS4ERR_RECLAIM_CONFLICT: |
933 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); | 956 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); |
@@ -1042,6 +1065,14 @@ static void nfs4_recovery_handle_error(struct nfs_client *clp, int error) | |||
1042 | case -NFS4ERR_EXPIRED: | 1065 | case -NFS4ERR_EXPIRED: |
1043 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1066 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
1044 | nfs4_state_start_reclaim_nograce(clp); | 1067 | nfs4_state_start_reclaim_nograce(clp); |
1068 | case -NFS4ERR_BADSESSION: | ||
1069 | case -NFS4ERR_BADSLOT: | ||
1070 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
1071 | case -NFS4ERR_DEADSESSION: | ||
1072 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
1073 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
1074 | case -NFS4ERR_SEQ_MISORDERED: | ||
1075 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1045 | } | 1076 | } |
1046 | } | 1077 | } |
1047 | 1078 | ||
@@ -1075,18 +1106,22 @@ restart: | |||
1075 | static int nfs4_check_lease(struct nfs_client *clp) | 1106 | static int nfs4_check_lease(struct nfs_client *clp) |
1076 | { | 1107 | { |
1077 | struct rpc_cred *cred; | 1108 | struct rpc_cred *cred; |
1109 | struct nfs4_state_maintenance_ops *ops = | ||
1110 | nfs4_state_renewal_ops[clp->cl_minorversion]; | ||
1078 | int status = -NFS4ERR_EXPIRED; | 1111 | int status = -NFS4ERR_EXPIRED; |
1079 | 1112 | ||
1080 | /* Is the client already known to have an expired lease? */ | 1113 | /* Is the client already known to have an expired lease? */ |
1081 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 1114 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
1082 | return 0; | 1115 | return 0; |
1083 | cred = nfs4_get_renew_cred(clp); | 1116 | spin_lock(&clp->cl_lock); |
1117 | cred = ops->get_state_renewal_cred_locked(clp); | ||
1118 | spin_unlock(&clp->cl_lock); | ||
1084 | if (cred == NULL) { | 1119 | if (cred == NULL) { |
1085 | cred = nfs4_get_setclientid_cred(clp); | 1120 | cred = nfs4_get_setclientid_cred(clp); |
1086 | if (cred == NULL) | 1121 | if (cred == NULL) |
1087 | goto out; | 1122 | goto out; |
1088 | } | 1123 | } |
1089 | status = nfs4_proc_renew(clp, cred); | 1124 | status = ops->renew_lease(clp, cred); |
1090 | put_rpccred(cred); | 1125 | put_rpccred(cred); |
1091 | out: | 1126 | out: |
1092 | nfs4_recovery_handle_error(clp, status); | 1127 | nfs4_recovery_handle_error(clp, status); |
@@ -1096,21 +1131,98 @@ out: | |||
1096 | static int nfs4_reclaim_lease(struct nfs_client *clp) | 1131 | static int nfs4_reclaim_lease(struct nfs_client *clp) |
1097 | { | 1132 | { |
1098 | struct rpc_cred *cred; | 1133 | struct rpc_cred *cred; |
1134 | struct nfs4_state_recovery_ops *ops = | ||
1135 | nfs4_reboot_recovery_ops[clp->cl_minorversion]; | ||
1099 | int status = -ENOENT; | 1136 | int status = -ENOENT; |
1100 | 1137 | ||
1101 | cred = nfs4_get_setclientid_cred(clp); | 1138 | cred = ops->get_clid_cred(clp); |
1102 | if (cred != NULL) { | 1139 | if (cred != NULL) { |
1103 | status = nfs4_init_client(clp, cred); | 1140 | status = ops->establish_clid(clp, cred); |
1104 | put_rpccred(cred); | 1141 | put_rpccred(cred); |
1105 | /* Handle case where the user hasn't set up machine creds */ | 1142 | /* Handle case where the user hasn't set up machine creds */ |
1106 | if (status == -EACCES && cred == clp->cl_machine_cred) { | 1143 | if (status == -EACCES && cred == clp->cl_machine_cred) { |
1107 | nfs4_clear_machine_cred(clp); | 1144 | nfs4_clear_machine_cred(clp); |
1108 | status = -EAGAIN; | 1145 | status = -EAGAIN; |
1109 | } | 1146 | } |
1147 | if (status == -NFS4ERR_MINOR_VERS_MISMATCH) | ||
1148 | status = -EPROTONOSUPPORT; | ||
1149 | } | ||
1150 | return status; | ||
1151 | } | ||
1152 | |||
1153 | #ifdef CONFIG_NFS_V4_1 | ||
1154 | static void nfs4_session_recovery_handle_error(struct nfs_client *clp, int err) | ||
1155 | { | ||
1156 | switch (err) { | ||
1157 | case -NFS4ERR_STALE_CLIENTID: | ||
1158 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1159 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 | static int nfs4_reset_session(struct nfs_client *clp) | ||
1164 | { | ||
1165 | int status; | ||
1166 | |||
1167 | status = nfs4_proc_destroy_session(clp->cl_session); | ||
1168 | if (status && status != -NFS4ERR_BADSESSION && | ||
1169 | status != -NFS4ERR_DEADSESSION) { | ||
1170 | nfs4_session_recovery_handle_error(clp, status); | ||
1171 | goto out; | ||
1110 | } | 1172 | } |
1173 | |||
1174 | memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN); | ||
1175 | status = nfs4_proc_create_session(clp, 1); | ||
1176 | if (status) | ||
1177 | nfs4_session_recovery_handle_error(clp, status); | ||
1178 | /* fall through*/ | ||
1179 | out: | ||
1180 | /* Wake up the next rpc task even on error */ | ||
1181 | rpc_wake_up_next(&clp->cl_session->fc_slot_table.slot_tbl_waitq); | ||
1111 | return status; | 1182 | return status; |
1112 | } | 1183 | } |
1113 | 1184 | ||
1185 | static int nfs4_initialize_session(struct nfs_client *clp) | ||
1186 | { | ||
1187 | int status; | ||
1188 | |||
1189 | status = nfs4_proc_create_session(clp, 0); | ||
1190 | if (!status) { | ||
1191 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
1192 | } else if (status == -NFS4ERR_STALE_CLIENTID) { | ||
1193 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1194 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1195 | } else { | ||
1196 | nfs_mark_client_ready(clp, status); | ||
1197 | } | ||
1198 | return status; | ||
1199 | } | ||
1200 | #else /* CONFIG_NFS_V4_1 */ | ||
1201 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } | ||
1202 | static int nfs4_initialize_session(struct nfs_client *clp) { return 0; } | ||
1203 | #endif /* CONFIG_NFS_V4_1 */ | ||
1204 | |||
1205 | /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors | ||
1206 | * on EXCHANGE_ID for v4.1 | ||
1207 | */ | ||
1208 | static void nfs4_set_lease_expired(struct nfs_client *clp, int status) | ||
1209 | { | ||
1210 | if (nfs4_has_session(clp)) { | ||
1211 | switch (status) { | ||
1212 | case -NFS4ERR_DELAY: | ||
1213 | case -NFS4ERR_CLID_INUSE: | ||
1214 | case -EAGAIN: | ||
1215 | break; | ||
1216 | |||
1217 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery | ||
1218 | * in nfs4_exchange_id */ | ||
1219 | default: | ||
1220 | return; | ||
1221 | } | ||
1222 | } | ||
1223 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1224 | } | ||
1225 | |||
1114 | static void nfs4_state_manager(struct nfs_client *clp) | 1226 | static void nfs4_state_manager(struct nfs_client *clp) |
1115 | { | 1227 | { |
1116 | int status = 0; | 1228 | int status = 0; |
@@ -1121,9 +1233,12 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1121 | /* We're going to have to re-establish a clientid */ | 1233 | /* We're going to have to re-establish a clientid */ |
1122 | status = nfs4_reclaim_lease(clp); | 1234 | status = nfs4_reclaim_lease(clp); |
1123 | if (status) { | 1235 | if (status) { |
1124 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1236 | nfs4_set_lease_expired(clp, status); |
1125 | if (status == -EAGAIN) | 1237 | if (status == -EAGAIN) |
1126 | continue; | 1238 | continue; |
1239 | if (clp->cl_cons_state == | ||
1240 | NFS_CS_SESSION_INITING) | ||
1241 | nfs_mark_client_ready(clp, status); | ||
1127 | goto out_error; | 1242 | goto out_error; |
1128 | } | 1243 | } |
1129 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | 1244 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); |
@@ -1134,25 +1249,44 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1134 | if (status != 0) | 1249 | if (status != 0) |
1135 | continue; | 1250 | continue; |
1136 | } | 1251 | } |
1137 | 1252 | /* Initialize or reset the session */ | |
1253 | if (nfs4_has_session(clp) && | ||
1254 | test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | ||
1255 | if (clp->cl_cons_state == NFS_CS_SESSION_INITING) | ||
1256 | status = nfs4_initialize_session(clp); | ||
1257 | else | ||
1258 | status = nfs4_reset_session(clp); | ||
1259 | if (status) { | ||
1260 | if (status == -NFS4ERR_STALE_CLIENTID) | ||
1261 | continue; | ||
1262 | goto out_error; | ||
1263 | } | ||
1264 | } | ||
1138 | /* First recover reboot state... */ | 1265 | /* First recover reboot state... */ |
1139 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { | 1266 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { |
1140 | status = nfs4_do_reclaim(clp, &nfs4_reboot_recovery_ops); | 1267 | status = nfs4_do_reclaim(clp, |
1268 | nfs4_reboot_recovery_ops[clp->cl_minorversion]); | ||
1141 | if (status == -NFS4ERR_STALE_CLIENTID) | 1269 | if (status == -NFS4ERR_STALE_CLIENTID) |
1142 | continue; | 1270 | continue; |
1271 | if (test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
1272 | continue; | ||
1143 | nfs4_state_end_reclaim_reboot(clp); | 1273 | nfs4_state_end_reclaim_reboot(clp); |
1144 | continue; | 1274 | continue; |
1145 | } | 1275 | } |
1146 | 1276 | ||
1147 | /* Now recover expired state... */ | 1277 | /* Now recover expired state... */ |
1148 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { | 1278 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { |
1149 | status = nfs4_do_reclaim(clp, &nfs4_nograce_recovery_ops); | 1279 | status = nfs4_do_reclaim(clp, |
1280 | nfs4_nograce_recovery_ops[clp->cl_minorversion]); | ||
1150 | if (status < 0) { | 1281 | if (status < 0) { |
1151 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); | 1282 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); |
1152 | if (status == -NFS4ERR_STALE_CLIENTID) | 1283 | if (status == -NFS4ERR_STALE_CLIENTID) |
1153 | continue; | 1284 | continue; |
1154 | if (status == -NFS4ERR_EXPIRED) | 1285 | if (status == -NFS4ERR_EXPIRED) |
1155 | continue; | 1286 | continue; |
1287 | if (test_bit(NFS4CLNT_SESSION_SETUP, | ||
1288 | &clp->cl_state)) | ||
1289 | continue; | ||
1156 | goto out_error; | 1290 | goto out_error; |
1157 | } else | 1291 | } else |
1158 | nfs4_state_end_reclaim_nograce(clp); | 1292 | nfs4_state_end_reclaim_nograce(clp); |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1690f0e44b91..617273e7d47f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -192,12 +192,16 @@ static int nfs4_stat_to_errno(int); | |||
192 | decode_verifier_maxsz) | 192 | decode_verifier_maxsz) |
193 | #define encode_remove_maxsz (op_encode_hdr_maxsz + \ | 193 | #define encode_remove_maxsz (op_encode_hdr_maxsz + \ |
194 | nfs4_name_maxsz) | 194 | nfs4_name_maxsz) |
195 | #define decode_remove_maxsz (op_decode_hdr_maxsz + \ | ||
196 | decode_change_info_maxsz) | ||
195 | #define encode_rename_maxsz (op_encode_hdr_maxsz + \ | 197 | #define encode_rename_maxsz (op_encode_hdr_maxsz + \ |
196 | 2 * nfs4_name_maxsz) | 198 | 2 * nfs4_name_maxsz) |
197 | #define decode_rename_maxsz (op_decode_hdr_maxsz + 5 + 5) | 199 | #define decode_rename_maxsz (op_decode_hdr_maxsz + \ |
200 | decode_change_info_maxsz + \ | ||
201 | decode_change_info_maxsz) | ||
198 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ | 202 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ |
199 | nfs4_name_maxsz) | 203 | nfs4_name_maxsz) |
200 | #define decode_link_maxsz (op_decode_hdr_maxsz + 5) | 204 | #define decode_link_maxsz (op_decode_hdr_maxsz + decode_change_info_maxsz) |
201 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ | 205 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ |
202 | 7 + \ | 206 | 7 + \ |
203 | 1 + encode_stateid_maxsz + 8) | 207 | 1 + encode_stateid_maxsz + 8) |
@@ -240,43 +244,115 @@ static int nfs4_stat_to_errno(int); | |||
240 | (encode_getattr_maxsz) | 244 | (encode_getattr_maxsz) |
241 | #define decode_fs_locations_maxsz \ | 245 | #define decode_fs_locations_maxsz \ |
242 | (0) | 246 | (0) |
247 | |||
248 | #if defined(CONFIG_NFS_V4_1) | ||
249 | #define NFS4_MAX_MACHINE_NAME_LEN (64) | ||
250 | |||
251 | #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \ | ||
252 | encode_verifier_maxsz + \ | ||
253 | 1 /* co_ownerid.len */ + \ | ||
254 | XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \ | ||
255 | 1 /* flags */ + \ | ||
256 | 1 /* spa_how */ + \ | ||
257 | 0 /* SP4_NONE (for now) */ + \ | ||
258 | 1 /* zero implemetation id array */) | ||
259 | #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \ | ||
260 | 2 /* eir_clientid */ + \ | ||
261 | 1 /* eir_sequenceid */ + \ | ||
262 | 1 /* eir_flags */ + \ | ||
263 | 1 /* spr_how */ + \ | ||
264 | 0 /* SP4_NONE (for now) */ + \ | ||
265 | 2 /* eir_server_owner.so_minor_id */ + \ | ||
266 | /* eir_server_owner.so_major_id<> */ \ | ||
267 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | ||
268 | /* eir_server_scope<> */ \ | ||
269 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | ||
270 | 1 /* eir_server_impl_id array length */ + \ | ||
271 | 0 /* ignored eir_server_impl_id contents */) | ||
272 | #define encode_channel_attrs_maxsz (6 + 1 /* ca_rdma_ird.len (0) */) | ||
273 | #define decode_channel_attrs_maxsz (6 + \ | ||
274 | 1 /* ca_rdma_ird.len */ + \ | ||
275 | 1 /* ca_rdma_ird */) | ||
276 | #define encode_create_session_maxsz (op_encode_hdr_maxsz + \ | ||
277 | 2 /* csa_clientid */ + \ | ||
278 | 1 /* csa_sequence */ + \ | ||
279 | 1 /* csa_flags */ + \ | ||
280 | encode_channel_attrs_maxsz + \ | ||
281 | encode_channel_attrs_maxsz + \ | ||
282 | 1 /* csa_cb_program */ + \ | ||
283 | 1 /* csa_sec_parms.len (1) */ + \ | ||
284 | 1 /* cb_secflavor (AUTH_SYS) */ + \ | ||
285 | 1 /* stamp */ + \ | ||
286 | 1 /* machinename.len */ + \ | ||
287 | XDR_QUADLEN(NFS4_MAX_MACHINE_NAME_LEN) + \ | ||
288 | 1 /* uid */ + \ | ||
289 | 1 /* gid */ + \ | ||
290 | 1 /* gids.len (0) */) | ||
291 | #define decode_create_session_maxsz (op_decode_hdr_maxsz + \ | ||
292 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ | ||
293 | 1 /* csr_sequence */ + \ | ||
294 | 1 /* csr_flags */ + \ | ||
295 | decode_channel_attrs_maxsz + \ | ||
296 | decode_channel_attrs_maxsz) | ||
297 | #define encode_destroy_session_maxsz (op_encode_hdr_maxsz + 4) | ||
298 | #define decode_destroy_session_maxsz (op_decode_hdr_maxsz) | ||
299 | #define encode_sequence_maxsz (op_encode_hdr_maxsz + \ | ||
300 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4) | ||
301 | #define decode_sequence_maxsz (op_decode_hdr_maxsz + \ | ||
302 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) | ||
303 | #else /* CONFIG_NFS_V4_1 */ | ||
304 | #define encode_sequence_maxsz 0 | ||
305 | #define decode_sequence_maxsz 0 | ||
306 | #endif /* CONFIG_NFS_V4_1 */ | ||
307 | |||
243 | #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ | 308 | #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ |
244 | #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ | 309 | #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ |
245 | #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ | 310 | #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ |
311 | encode_sequence_maxsz + \ | ||
246 | encode_putfh_maxsz + \ | 312 | encode_putfh_maxsz + \ |
247 | encode_read_maxsz) | 313 | encode_read_maxsz) |
248 | #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ | 314 | #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ |
315 | decode_sequence_maxsz + \ | ||
249 | decode_putfh_maxsz + \ | 316 | decode_putfh_maxsz + \ |
250 | decode_read_maxsz) | 317 | decode_read_maxsz) |
251 | #define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ | 318 | #define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ |
319 | encode_sequence_maxsz + \ | ||
252 | encode_putfh_maxsz + \ | 320 | encode_putfh_maxsz + \ |
253 | encode_readlink_maxsz) | 321 | encode_readlink_maxsz) |
254 | #define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ | 322 | #define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ |
323 | decode_sequence_maxsz + \ | ||
255 | decode_putfh_maxsz + \ | 324 | decode_putfh_maxsz + \ |
256 | decode_readlink_maxsz) | 325 | decode_readlink_maxsz) |
257 | #define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ | 326 | #define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ |
327 | encode_sequence_maxsz + \ | ||
258 | encode_putfh_maxsz + \ | 328 | encode_putfh_maxsz + \ |
259 | encode_readdir_maxsz) | 329 | encode_readdir_maxsz) |
260 | #define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ | 330 | #define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ |
331 | decode_sequence_maxsz + \ | ||
261 | decode_putfh_maxsz + \ | 332 | decode_putfh_maxsz + \ |
262 | decode_readdir_maxsz) | 333 | decode_readdir_maxsz) |
263 | #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ | 334 | #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ |
335 | encode_sequence_maxsz + \ | ||
264 | encode_putfh_maxsz + \ | 336 | encode_putfh_maxsz + \ |
265 | encode_write_maxsz + \ | 337 | encode_write_maxsz + \ |
266 | encode_getattr_maxsz) | 338 | encode_getattr_maxsz) |
267 | #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ | 339 | #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ |
340 | decode_sequence_maxsz + \ | ||
268 | decode_putfh_maxsz + \ | 341 | decode_putfh_maxsz + \ |
269 | decode_write_maxsz + \ | 342 | decode_write_maxsz + \ |
270 | decode_getattr_maxsz) | 343 | decode_getattr_maxsz) |
271 | #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ | 344 | #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ |
345 | encode_sequence_maxsz + \ | ||
272 | encode_putfh_maxsz + \ | 346 | encode_putfh_maxsz + \ |
273 | encode_commit_maxsz + \ | 347 | encode_commit_maxsz + \ |
274 | encode_getattr_maxsz) | 348 | encode_getattr_maxsz) |
275 | #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ | 349 | #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ |
350 | decode_sequence_maxsz + \ | ||
276 | decode_putfh_maxsz + \ | 351 | decode_putfh_maxsz + \ |
277 | decode_commit_maxsz + \ | 352 | decode_commit_maxsz + \ |
278 | decode_getattr_maxsz) | 353 | decode_getattr_maxsz) |
279 | #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ | 354 | #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ |
355 | encode_sequence_maxsz + \ | ||
280 | encode_putfh_maxsz + \ | 356 | encode_putfh_maxsz + \ |
281 | encode_savefh_maxsz + \ | 357 | encode_savefh_maxsz + \ |
282 | encode_open_maxsz + \ | 358 | encode_open_maxsz + \ |
@@ -285,6 +361,7 @@ static int nfs4_stat_to_errno(int); | |||
285 | encode_restorefh_maxsz + \ | 361 | encode_restorefh_maxsz + \ |
286 | encode_getattr_maxsz) | 362 | encode_getattr_maxsz) |
287 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ | 363 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ |
364 | decode_sequence_maxsz + \ | ||
288 | decode_putfh_maxsz + \ | 365 | decode_putfh_maxsz + \ |
289 | decode_savefh_maxsz + \ | 366 | decode_savefh_maxsz + \ |
290 | decode_open_maxsz + \ | 367 | decode_open_maxsz + \ |
@@ -301,43 +378,53 @@ static int nfs4_stat_to_errno(int); | |||
301 | decode_putfh_maxsz + \ | 378 | decode_putfh_maxsz + \ |
302 | decode_open_confirm_maxsz) | 379 | decode_open_confirm_maxsz) |
303 | #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ | 380 | #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ |
381 | encode_sequence_maxsz + \ | ||
304 | encode_putfh_maxsz + \ | 382 | encode_putfh_maxsz + \ |
305 | encode_open_maxsz + \ | 383 | encode_open_maxsz + \ |
306 | encode_getattr_maxsz) | 384 | encode_getattr_maxsz) |
307 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ | 385 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ |
386 | decode_sequence_maxsz + \ | ||
308 | decode_putfh_maxsz + \ | 387 | decode_putfh_maxsz + \ |
309 | decode_open_maxsz + \ | 388 | decode_open_maxsz + \ |
310 | decode_getattr_maxsz) | 389 | decode_getattr_maxsz) |
311 | #define NFS4_enc_open_downgrade_sz \ | 390 | #define NFS4_enc_open_downgrade_sz \ |
312 | (compound_encode_hdr_maxsz + \ | 391 | (compound_encode_hdr_maxsz + \ |
392 | encode_sequence_maxsz + \ | ||
313 | encode_putfh_maxsz + \ | 393 | encode_putfh_maxsz + \ |
314 | encode_open_downgrade_maxsz + \ | 394 | encode_open_downgrade_maxsz + \ |
315 | encode_getattr_maxsz) | 395 | encode_getattr_maxsz) |
316 | #define NFS4_dec_open_downgrade_sz \ | 396 | #define NFS4_dec_open_downgrade_sz \ |
317 | (compound_decode_hdr_maxsz + \ | 397 | (compound_decode_hdr_maxsz + \ |
398 | decode_sequence_maxsz + \ | ||
318 | decode_putfh_maxsz + \ | 399 | decode_putfh_maxsz + \ |
319 | decode_open_downgrade_maxsz + \ | 400 | decode_open_downgrade_maxsz + \ |
320 | decode_getattr_maxsz) | 401 | decode_getattr_maxsz) |
321 | #define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ | 402 | #define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ |
403 | encode_sequence_maxsz + \ | ||
322 | encode_putfh_maxsz + \ | 404 | encode_putfh_maxsz + \ |
323 | encode_close_maxsz + \ | 405 | encode_close_maxsz + \ |
324 | encode_getattr_maxsz) | 406 | encode_getattr_maxsz) |
325 | #define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ | 407 | #define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ |
408 | decode_sequence_maxsz + \ | ||
326 | decode_putfh_maxsz + \ | 409 | decode_putfh_maxsz + \ |
327 | decode_close_maxsz + \ | 410 | decode_close_maxsz + \ |
328 | decode_getattr_maxsz) | 411 | decode_getattr_maxsz) |
329 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ | 412 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ |
413 | encode_sequence_maxsz + \ | ||
330 | encode_putfh_maxsz + \ | 414 | encode_putfh_maxsz + \ |
331 | encode_setattr_maxsz + \ | 415 | encode_setattr_maxsz + \ |
332 | encode_getattr_maxsz) | 416 | encode_getattr_maxsz) |
333 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ | 417 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ |
418 | decode_sequence_maxsz + \ | ||
334 | decode_putfh_maxsz + \ | 419 | decode_putfh_maxsz + \ |
335 | decode_setattr_maxsz + \ | 420 | decode_setattr_maxsz + \ |
336 | decode_getattr_maxsz) | 421 | decode_getattr_maxsz) |
337 | #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ | 422 | #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ |
423 | encode_sequence_maxsz + \ | ||
338 | encode_putfh_maxsz + \ | 424 | encode_putfh_maxsz + \ |
339 | encode_fsinfo_maxsz) | 425 | encode_fsinfo_maxsz) |
340 | #define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \ | 426 | #define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \ |
427 | decode_sequence_maxsz + \ | ||
341 | decode_putfh_maxsz + \ | 428 | decode_putfh_maxsz + \ |
342 | decode_fsinfo_maxsz) | 429 | decode_fsinfo_maxsz) |
343 | #define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \ | 430 | #define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \ |
@@ -359,64 +446,81 @@ static int nfs4_stat_to_errno(int); | |||
359 | decode_putrootfh_maxsz + \ | 446 | decode_putrootfh_maxsz + \ |
360 | decode_fsinfo_maxsz) | 447 | decode_fsinfo_maxsz) |
361 | #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ | 448 | #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ |
449 | encode_sequence_maxsz + \ | ||
362 | encode_putfh_maxsz + \ | 450 | encode_putfh_maxsz + \ |
363 | encode_lock_maxsz) | 451 | encode_lock_maxsz) |
364 | #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ | 452 | #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ |
453 | decode_sequence_maxsz + \ | ||
365 | decode_putfh_maxsz + \ | 454 | decode_putfh_maxsz + \ |
366 | decode_lock_maxsz) | 455 | decode_lock_maxsz) |
367 | #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ | 456 | #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ |
457 | encode_sequence_maxsz + \ | ||
368 | encode_putfh_maxsz + \ | 458 | encode_putfh_maxsz + \ |
369 | encode_lockt_maxsz) | 459 | encode_lockt_maxsz) |
370 | #define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \ | 460 | #define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \ |
461 | decode_sequence_maxsz + \ | ||
371 | decode_putfh_maxsz + \ | 462 | decode_putfh_maxsz + \ |
372 | decode_lockt_maxsz) | 463 | decode_lockt_maxsz) |
373 | #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ | 464 | #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ |
465 | encode_sequence_maxsz + \ | ||
374 | encode_putfh_maxsz + \ | 466 | encode_putfh_maxsz + \ |
375 | encode_locku_maxsz) | 467 | encode_locku_maxsz) |
376 | #define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \ | 468 | #define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \ |
469 | decode_sequence_maxsz + \ | ||
377 | decode_putfh_maxsz + \ | 470 | decode_putfh_maxsz + \ |
378 | decode_locku_maxsz) | 471 | decode_locku_maxsz) |
379 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ | 472 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ |
473 | encode_sequence_maxsz + \ | ||
380 | encode_putfh_maxsz + \ | 474 | encode_putfh_maxsz + \ |
381 | encode_access_maxsz + \ | 475 | encode_access_maxsz + \ |
382 | encode_getattr_maxsz) | 476 | encode_getattr_maxsz) |
383 | #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ | 477 | #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ |
478 | decode_sequence_maxsz + \ | ||
384 | decode_putfh_maxsz + \ | 479 | decode_putfh_maxsz + \ |
385 | decode_access_maxsz + \ | 480 | decode_access_maxsz + \ |
386 | decode_getattr_maxsz) | 481 | decode_getattr_maxsz) |
387 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ | 482 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ |
483 | encode_sequence_maxsz + \ | ||
388 | encode_putfh_maxsz + \ | 484 | encode_putfh_maxsz + \ |
389 | encode_getattr_maxsz) | 485 | encode_getattr_maxsz) |
390 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ | 486 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ |
487 | decode_sequence_maxsz + \ | ||
391 | decode_putfh_maxsz + \ | 488 | decode_putfh_maxsz + \ |
392 | decode_getattr_maxsz) | 489 | decode_getattr_maxsz) |
393 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ | 490 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ |
491 | encode_sequence_maxsz + \ | ||
394 | encode_putfh_maxsz + \ | 492 | encode_putfh_maxsz + \ |
395 | encode_lookup_maxsz + \ | 493 | encode_lookup_maxsz + \ |
396 | encode_getattr_maxsz + \ | 494 | encode_getattr_maxsz + \ |
397 | encode_getfh_maxsz) | 495 | encode_getfh_maxsz) |
398 | #define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ | 496 | #define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ |
497 | decode_sequence_maxsz + \ | ||
399 | decode_putfh_maxsz + \ | 498 | decode_putfh_maxsz + \ |
400 | decode_lookup_maxsz + \ | 499 | decode_lookup_maxsz + \ |
401 | decode_getattr_maxsz + \ | 500 | decode_getattr_maxsz + \ |
402 | decode_getfh_maxsz) | 501 | decode_getfh_maxsz) |
403 | #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ | 502 | #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ |
503 | encode_sequence_maxsz + \ | ||
404 | encode_putrootfh_maxsz + \ | 504 | encode_putrootfh_maxsz + \ |
405 | encode_getattr_maxsz + \ | 505 | encode_getattr_maxsz + \ |
406 | encode_getfh_maxsz) | 506 | encode_getfh_maxsz) |
407 | #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \ | 507 | #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \ |
508 | decode_sequence_maxsz + \ | ||
408 | decode_putrootfh_maxsz + \ | 509 | decode_putrootfh_maxsz + \ |
409 | decode_getattr_maxsz + \ | 510 | decode_getattr_maxsz + \ |
410 | decode_getfh_maxsz) | 511 | decode_getfh_maxsz) |
411 | #define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ | 512 | #define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ |
513 | encode_sequence_maxsz + \ | ||
412 | encode_putfh_maxsz + \ | 514 | encode_putfh_maxsz + \ |
413 | encode_remove_maxsz + \ | 515 | encode_remove_maxsz + \ |
414 | encode_getattr_maxsz) | 516 | encode_getattr_maxsz) |
415 | #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ | 517 | #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ |
518 | decode_sequence_maxsz + \ | ||
416 | decode_putfh_maxsz + \ | 519 | decode_putfh_maxsz + \ |
417 | op_decode_hdr_maxsz + 5 + \ | 520 | decode_remove_maxsz + \ |
418 | decode_getattr_maxsz) | 521 | decode_getattr_maxsz) |
419 | #define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ | 522 | #define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ |
523 | encode_sequence_maxsz + \ | ||
420 | encode_putfh_maxsz + \ | 524 | encode_putfh_maxsz + \ |
421 | encode_savefh_maxsz + \ | 525 | encode_savefh_maxsz + \ |
422 | encode_putfh_maxsz + \ | 526 | encode_putfh_maxsz + \ |
@@ -425,6 +529,7 @@ static int nfs4_stat_to_errno(int); | |||
425 | encode_restorefh_maxsz + \ | 529 | encode_restorefh_maxsz + \ |
426 | encode_getattr_maxsz) | 530 | encode_getattr_maxsz) |
427 | #define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ | 531 | #define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ |
532 | decode_sequence_maxsz + \ | ||
428 | decode_putfh_maxsz + \ | 533 | decode_putfh_maxsz + \ |
429 | decode_savefh_maxsz + \ | 534 | decode_savefh_maxsz + \ |
430 | decode_putfh_maxsz + \ | 535 | decode_putfh_maxsz + \ |
@@ -433,6 +538,7 @@ static int nfs4_stat_to_errno(int); | |||
433 | decode_restorefh_maxsz + \ | 538 | decode_restorefh_maxsz + \ |
434 | decode_getattr_maxsz) | 539 | decode_getattr_maxsz) |
435 | #define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ | 540 | #define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ |
541 | encode_sequence_maxsz + \ | ||
436 | encode_putfh_maxsz + \ | 542 | encode_putfh_maxsz + \ |
437 | encode_savefh_maxsz + \ | 543 | encode_savefh_maxsz + \ |
438 | encode_putfh_maxsz + \ | 544 | encode_putfh_maxsz + \ |
@@ -441,6 +547,7 @@ static int nfs4_stat_to_errno(int); | |||
441 | encode_restorefh_maxsz + \ | 547 | encode_restorefh_maxsz + \ |
442 | decode_getattr_maxsz) | 548 | decode_getattr_maxsz) |
443 | #define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ | 549 | #define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ |
550 | decode_sequence_maxsz + \ | ||
444 | decode_putfh_maxsz + \ | 551 | decode_putfh_maxsz + \ |
445 | decode_savefh_maxsz + \ | 552 | decode_savefh_maxsz + \ |
446 | decode_putfh_maxsz + \ | 553 | decode_putfh_maxsz + \ |
@@ -449,16 +556,19 @@ static int nfs4_stat_to_errno(int); | |||
449 | decode_restorefh_maxsz + \ | 556 | decode_restorefh_maxsz + \ |
450 | decode_getattr_maxsz) | 557 | decode_getattr_maxsz) |
451 | #define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \ | 558 | #define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \ |
559 | encode_sequence_maxsz + \ | ||
452 | encode_putfh_maxsz + \ | 560 | encode_putfh_maxsz + \ |
453 | encode_symlink_maxsz + \ | 561 | encode_symlink_maxsz + \ |
454 | encode_getattr_maxsz + \ | 562 | encode_getattr_maxsz + \ |
455 | encode_getfh_maxsz) | 563 | encode_getfh_maxsz) |
456 | #define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \ | 564 | #define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \ |
565 | decode_sequence_maxsz + \ | ||
457 | decode_putfh_maxsz + \ | 566 | decode_putfh_maxsz + \ |
458 | decode_symlink_maxsz + \ | 567 | decode_symlink_maxsz + \ |
459 | decode_getattr_maxsz + \ | 568 | decode_getattr_maxsz + \ |
460 | decode_getfh_maxsz) | 569 | decode_getfh_maxsz) |
461 | #define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ | 570 | #define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ |
571 | encode_sequence_maxsz + \ | ||
462 | encode_putfh_maxsz + \ | 572 | encode_putfh_maxsz + \ |
463 | encode_savefh_maxsz + \ | 573 | encode_savefh_maxsz + \ |
464 | encode_create_maxsz + \ | 574 | encode_create_maxsz + \ |
@@ -467,6 +577,7 @@ static int nfs4_stat_to_errno(int); | |||
467 | encode_restorefh_maxsz + \ | 577 | encode_restorefh_maxsz + \ |
468 | encode_getattr_maxsz) | 578 | encode_getattr_maxsz) |
469 | #define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ | 579 | #define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ |
580 | decode_sequence_maxsz + \ | ||
470 | decode_putfh_maxsz + \ | 581 | decode_putfh_maxsz + \ |
471 | decode_savefh_maxsz + \ | 582 | decode_savefh_maxsz + \ |
472 | decode_create_maxsz + \ | 583 | decode_create_maxsz + \ |
@@ -475,52 +586,98 @@ static int nfs4_stat_to_errno(int); | |||
475 | decode_restorefh_maxsz + \ | 586 | decode_restorefh_maxsz + \ |
476 | decode_getattr_maxsz) | 587 | decode_getattr_maxsz) |
477 | #define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ | 588 | #define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ |
589 | encode_sequence_maxsz + \ | ||
478 | encode_putfh_maxsz + \ | 590 | encode_putfh_maxsz + \ |
479 | encode_getattr_maxsz) | 591 | encode_getattr_maxsz) |
480 | #define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ | 592 | #define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ |
593 | decode_sequence_maxsz + \ | ||
481 | decode_putfh_maxsz + \ | 594 | decode_putfh_maxsz + \ |
482 | decode_getattr_maxsz) | 595 | decode_getattr_maxsz) |
483 | #define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ | 596 | #define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ |
597 | encode_sequence_maxsz + \ | ||
484 | encode_putfh_maxsz + \ | 598 | encode_putfh_maxsz + \ |
485 | encode_statfs_maxsz) | 599 | encode_statfs_maxsz) |
486 | #define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ | 600 | #define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ |
601 | decode_sequence_maxsz + \ | ||
487 | decode_putfh_maxsz + \ | 602 | decode_putfh_maxsz + \ |
488 | decode_statfs_maxsz) | 603 | decode_statfs_maxsz) |
489 | #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ | 604 | #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ |
605 | encode_sequence_maxsz + \ | ||
490 | encode_putfh_maxsz + \ | 606 | encode_putfh_maxsz + \ |
491 | encode_getattr_maxsz) | 607 | encode_getattr_maxsz) |
492 | #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ | 608 | #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ |
609 | decode_sequence_maxsz + \ | ||
493 | decode_putfh_maxsz + \ | 610 | decode_putfh_maxsz + \ |
494 | decode_getattr_maxsz) | 611 | decode_getattr_maxsz) |
495 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ | 612 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ |
613 | encode_sequence_maxsz + \ | ||
496 | encode_putfh_maxsz + \ | 614 | encode_putfh_maxsz + \ |
497 | encode_delegreturn_maxsz + \ | 615 | encode_delegreturn_maxsz + \ |
498 | encode_getattr_maxsz) | 616 | encode_getattr_maxsz) |
499 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ | 617 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ |
618 | decode_sequence_maxsz + \ | ||
500 | decode_delegreturn_maxsz + \ | 619 | decode_delegreturn_maxsz + \ |
501 | decode_getattr_maxsz) | 620 | decode_getattr_maxsz) |
502 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ | 621 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ |
622 | encode_sequence_maxsz + \ | ||
503 | encode_putfh_maxsz + \ | 623 | encode_putfh_maxsz + \ |
504 | encode_getacl_maxsz) | 624 | encode_getacl_maxsz) |
505 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ | 625 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ |
626 | decode_sequence_maxsz + \ | ||
506 | decode_putfh_maxsz + \ | 627 | decode_putfh_maxsz + \ |
507 | decode_getacl_maxsz) | 628 | decode_getacl_maxsz) |
508 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ | 629 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ |
630 | encode_sequence_maxsz + \ | ||
509 | encode_putfh_maxsz + \ | 631 | encode_putfh_maxsz + \ |
510 | encode_setacl_maxsz) | 632 | encode_setacl_maxsz) |
511 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ | 633 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ |
634 | decode_sequence_maxsz + \ | ||
512 | decode_putfh_maxsz + \ | 635 | decode_putfh_maxsz + \ |
513 | decode_setacl_maxsz) | 636 | decode_setacl_maxsz) |
514 | #define NFS4_enc_fs_locations_sz \ | 637 | #define NFS4_enc_fs_locations_sz \ |
515 | (compound_encode_hdr_maxsz + \ | 638 | (compound_encode_hdr_maxsz + \ |
639 | encode_sequence_maxsz + \ | ||
516 | encode_putfh_maxsz + \ | 640 | encode_putfh_maxsz + \ |
517 | encode_lookup_maxsz + \ | 641 | encode_lookup_maxsz + \ |
518 | encode_fs_locations_maxsz) | 642 | encode_fs_locations_maxsz) |
519 | #define NFS4_dec_fs_locations_sz \ | 643 | #define NFS4_dec_fs_locations_sz \ |
520 | (compound_decode_hdr_maxsz + \ | 644 | (compound_decode_hdr_maxsz + \ |
645 | decode_sequence_maxsz + \ | ||
521 | decode_putfh_maxsz + \ | 646 | decode_putfh_maxsz + \ |
522 | decode_lookup_maxsz + \ | 647 | decode_lookup_maxsz + \ |
523 | decode_fs_locations_maxsz) | 648 | decode_fs_locations_maxsz) |
649 | #if defined(CONFIG_NFS_V4_1) | ||
650 | #define NFS4_enc_exchange_id_sz \ | ||
651 | (compound_encode_hdr_maxsz + \ | ||
652 | encode_exchange_id_maxsz) | ||
653 | #define NFS4_dec_exchange_id_sz \ | ||
654 | (compound_decode_hdr_maxsz + \ | ||
655 | decode_exchange_id_maxsz) | ||
656 | #define NFS4_enc_create_session_sz \ | ||
657 | (compound_encode_hdr_maxsz + \ | ||
658 | encode_create_session_maxsz) | ||
659 | #define NFS4_dec_create_session_sz \ | ||
660 | (compound_decode_hdr_maxsz + \ | ||
661 | decode_create_session_maxsz) | ||
662 | #define NFS4_enc_destroy_session_sz (compound_encode_hdr_maxsz + \ | ||
663 | encode_destroy_session_maxsz) | ||
664 | #define NFS4_dec_destroy_session_sz (compound_decode_hdr_maxsz + \ | ||
665 | decode_destroy_session_maxsz) | ||
666 | #define NFS4_enc_sequence_sz \ | ||
667 | (compound_decode_hdr_maxsz + \ | ||
668 | encode_sequence_maxsz) | ||
669 | #define NFS4_dec_sequence_sz \ | ||
670 | (compound_decode_hdr_maxsz + \ | ||
671 | decode_sequence_maxsz) | ||
672 | #define NFS4_enc_get_lease_time_sz (compound_encode_hdr_maxsz + \ | ||
673 | encode_sequence_maxsz + \ | ||
674 | encode_putrootfh_maxsz + \ | ||
675 | encode_fsinfo_maxsz) | ||
676 | #define NFS4_dec_get_lease_time_sz (compound_decode_hdr_maxsz + \ | ||
677 | decode_sequence_maxsz + \ | ||
678 | decode_putrootfh_maxsz + \ | ||
679 | decode_fsinfo_maxsz) | ||
680 | #endif /* CONFIG_NFS_V4_1 */ | ||
524 | 681 | ||
525 | static const umode_t nfs_type2fmt[] = { | 682 | static const umode_t nfs_type2fmt[] = { |
526 | [NF4BAD] = 0, | 683 | [NF4BAD] = 0, |
@@ -541,6 +698,8 @@ struct compound_hdr { | |||
541 | __be32 * nops_p; | 698 | __be32 * nops_p; |
542 | uint32_t taglen; | 699 | uint32_t taglen; |
543 | char * tag; | 700 | char * tag; |
701 | uint32_t replen; /* expected reply words */ | ||
702 | u32 minorversion; | ||
544 | }; | 703 | }; |
545 | 704 | ||
546 | /* | 705 | /* |
@@ -576,22 +735,31 @@ static void encode_string(struct xdr_stream *xdr, unsigned int len, const char * | |||
576 | xdr_encode_opaque(p, str, len); | 735 | xdr_encode_opaque(p, str, len); |
577 | } | 736 | } |
578 | 737 | ||
579 | static void encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) | 738 | static void encode_compound_hdr(struct xdr_stream *xdr, |
739 | struct rpc_rqst *req, | ||
740 | struct compound_hdr *hdr) | ||
580 | { | 741 | { |
581 | __be32 *p; | 742 | __be32 *p; |
743 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
744 | |||
745 | /* initialize running count of expected bytes in reply. | ||
746 | * NOTE: the replied tag SHOULD be the same is the one sent, | ||
747 | * but this is not required as a MUST for the server to do so. */ | ||
748 | hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen; | ||
582 | 749 | ||
583 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); | 750 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); |
584 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); | 751 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); |
585 | RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); | 752 | RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); |
586 | WRITE32(hdr->taglen); | 753 | WRITE32(hdr->taglen); |
587 | WRITEMEM(hdr->tag, hdr->taglen); | 754 | WRITEMEM(hdr->tag, hdr->taglen); |
588 | WRITE32(NFS4_MINOR_VERSION); | 755 | WRITE32(hdr->minorversion); |
589 | hdr->nops_p = p; | 756 | hdr->nops_p = p; |
590 | WRITE32(hdr->nops); | 757 | WRITE32(hdr->nops); |
591 | } | 758 | } |
592 | 759 | ||
593 | static void encode_nops(struct compound_hdr *hdr) | 760 | static void encode_nops(struct compound_hdr *hdr) |
594 | { | 761 | { |
762 | BUG_ON(hdr->nops > NFS4_MAX_OPS); | ||
595 | *hdr->nops_p = htonl(hdr->nops); | 763 | *hdr->nops_p = htonl(hdr->nops); |
596 | } | 764 | } |
597 | 765 | ||
@@ -736,6 +904,7 @@ static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hd | |||
736 | WRITE32(OP_ACCESS); | 904 | WRITE32(OP_ACCESS); |
737 | WRITE32(access); | 905 | WRITE32(access); |
738 | hdr->nops++; | 906 | hdr->nops++; |
907 | hdr->replen += decode_access_maxsz; | ||
739 | } | 908 | } |
740 | 909 | ||
741 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) | 910 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
@@ -747,6 +916,7 @@ static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg | |||
747 | WRITE32(arg->seqid->sequence->counter); | 916 | WRITE32(arg->seqid->sequence->counter); |
748 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 917 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
749 | hdr->nops++; | 918 | hdr->nops++; |
919 | hdr->replen += decode_close_maxsz; | ||
750 | } | 920 | } |
751 | 921 | ||
752 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) | 922 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
@@ -758,6 +928,7 @@ static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *ar | |||
758 | WRITE64(args->offset); | 928 | WRITE64(args->offset); |
759 | WRITE32(args->count); | 929 | WRITE32(args->count); |
760 | hdr->nops++; | 930 | hdr->nops++; |
931 | hdr->replen += decode_commit_maxsz; | ||
761 | } | 932 | } |
762 | 933 | ||
763 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) | 934 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) |
@@ -789,6 +960,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * | |||
789 | WRITE32(create->name->len); | 960 | WRITE32(create->name->len); |
790 | WRITEMEM(create->name->name, create->name->len); | 961 | WRITEMEM(create->name->name, create->name->len); |
791 | hdr->nops++; | 962 | hdr->nops++; |
963 | hdr->replen += decode_create_maxsz; | ||
792 | 964 | ||
793 | encode_attrs(xdr, create->attrs, create->server); | 965 | encode_attrs(xdr, create->attrs, create->server); |
794 | } | 966 | } |
@@ -802,6 +974,7 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c | |||
802 | WRITE32(1); | 974 | WRITE32(1); |
803 | WRITE32(bitmap); | 975 | WRITE32(bitmap); |
804 | hdr->nops++; | 976 | hdr->nops++; |
977 | hdr->replen += decode_getattr_maxsz; | ||
805 | } | 978 | } |
806 | 979 | ||
807 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) | 980 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) |
@@ -814,6 +987,7 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm | |||
814 | WRITE32(bm0); | 987 | WRITE32(bm0); |
815 | WRITE32(bm1); | 988 | WRITE32(bm1); |
816 | hdr->nops++; | 989 | hdr->nops++; |
990 | hdr->replen += decode_getattr_maxsz; | ||
817 | } | 991 | } |
818 | 992 | ||
819 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) | 993 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
@@ -841,6 +1015,7 @@ static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
841 | RESERVE_SPACE(4); | 1015 | RESERVE_SPACE(4); |
842 | WRITE32(OP_GETFH); | 1016 | WRITE32(OP_GETFH); |
843 | hdr->nops++; | 1017 | hdr->nops++; |
1018 | hdr->replen += decode_getfh_maxsz; | ||
844 | } | 1019 | } |
845 | 1020 | ||
846 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1021 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
@@ -852,6 +1027,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct | |||
852 | WRITE32(name->len); | 1027 | WRITE32(name->len); |
853 | WRITEMEM(name->name, name->len); | 1028 | WRITEMEM(name->name, name->len); |
854 | hdr->nops++; | 1029 | hdr->nops++; |
1030 | hdr->replen += decode_link_maxsz; | ||
855 | } | 1031 | } |
856 | 1032 | ||
857 | static inline int nfs4_lock_type(struct file_lock *fl, int block) | 1033 | static inline int nfs4_lock_type(struct file_lock *fl, int block) |
@@ -899,6 +1075,7 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args | |||
899 | WRITE32(args->lock_seqid->sequence->counter); | 1075 | WRITE32(args->lock_seqid->sequence->counter); |
900 | } | 1076 | } |
901 | hdr->nops++; | 1077 | hdr->nops++; |
1078 | hdr->replen += decode_lock_maxsz; | ||
902 | } | 1079 | } |
903 | 1080 | ||
904 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) | 1081 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) |
@@ -915,6 +1092,7 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar | |||
915 | WRITEMEM("lock id:", 8); | 1092 | WRITEMEM("lock id:", 8); |
916 | WRITE64(args->lock_owner.id); | 1093 | WRITE64(args->lock_owner.id); |
917 | hdr->nops++; | 1094 | hdr->nops++; |
1095 | hdr->replen += decode_lockt_maxsz; | ||
918 | } | 1096 | } |
919 | 1097 | ||
920 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) | 1098 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) |
@@ -929,6 +1107,7 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar | |||
929 | WRITE64(args->fl->fl_start); | 1107 | WRITE64(args->fl->fl_start); |
930 | WRITE64(nfs4_lock_length(args->fl)); | 1108 | WRITE64(nfs4_lock_length(args->fl)); |
931 | hdr->nops++; | 1109 | hdr->nops++; |
1110 | hdr->replen += decode_locku_maxsz; | ||
932 | } | 1111 | } |
933 | 1112 | ||
934 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1113 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
@@ -941,6 +1120,7 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc | |||
941 | WRITE32(len); | 1120 | WRITE32(len); |
942 | WRITEMEM(name->name, len); | 1121 | WRITEMEM(name->name, len); |
943 | hdr->nops++; | 1122 | hdr->nops++; |
1123 | hdr->replen += decode_lookup_maxsz; | ||
944 | } | 1124 | } |
945 | 1125 | ||
946 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) | 1126 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) |
@@ -1080,6 +1260,7 @@ static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, | |||
1080 | BUG(); | 1260 | BUG(); |
1081 | } | 1261 | } |
1082 | hdr->nops++; | 1262 | hdr->nops++; |
1263 | hdr->replen += decode_open_maxsz; | ||
1083 | } | 1264 | } |
1084 | 1265 | ||
1085 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) | 1266 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) |
@@ -1091,6 +1272,7 @@ static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_co | |||
1091 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 1272 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
1092 | WRITE32(arg->seqid->sequence->counter); | 1273 | WRITE32(arg->seqid->sequence->counter); |
1093 | hdr->nops++; | 1274 | hdr->nops++; |
1275 | hdr->replen += decode_open_confirm_maxsz; | ||
1094 | } | 1276 | } |
1095 | 1277 | ||
1096 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) | 1278 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
@@ -1103,6 +1285,7 @@ static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_close | |||
1103 | WRITE32(arg->seqid->sequence->counter); | 1285 | WRITE32(arg->seqid->sequence->counter); |
1104 | encode_share_access(xdr, arg->fmode); | 1286 | encode_share_access(xdr, arg->fmode); |
1105 | hdr->nops++; | 1287 | hdr->nops++; |
1288 | hdr->replen += decode_open_downgrade_maxsz; | ||
1106 | } | 1289 | } |
1107 | 1290 | ||
1108 | static void | 1291 | static void |
@@ -1116,6 +1299,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hd | |||
1116 | WRITE32(len); | 1299 | WRITE32(len); |
1117 | WRITEMEM(fh->data, len); | 1300 | WRITEMEM(fh->data, len); |
1118 | hdr->nops++; | 1301 | hdr->nops++; |
1302 | hdr->replen += decode_putfh_maxsz; | ||
1119 | } | 1303 | } |
1120 | 1304 | ||
1121 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | 1305 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
@@ -1125,6 +1309,7 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1125 | RESERVE_SPACE(4); | 1309 | RESERVE_SPACE(4); |
1126 | WRITE32(OP_PUTROOTFH); | 1310 | WRITE32(OP_PUTROOTFH); |
1127 | hdr->nops++; | 1311 | hdr->nops++; |
1312 | hdr->replen += decode_putrootfh_maxsz; | ||
1128 | } | 1313 | } |
1129 | 1314 | ||
1130 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) | 1315 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) |
@@ -1153,6 +1338,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, | |||
1153 | WRITE64(args->offset); | 1338 | WRITE64(args->offset); |
1154 | WRITE32(args->count); | 1339 | WRITE32(args->count); |
1155 | hdr->nops++; | 1340 | hdr->nops++; |
1341 | hdr->replen += decode_read_maxsz; | ||
1156 | } | 1342 | } |
1157 | 1343 | ||
1158 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) | 1344 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) |
@@ -1178,6 +1364,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1178 | WRITE32(attrs[0] & readdir->bitmask[0]); | 1364 | WRITE32(attrs[0] & readdir->bitmask[0]); |
1179 | WRITE32(attrs[1] & readdir->bitmask[1]); | 1365 | WRITE32(attrs[1] & readdir->bitmask[1]); |
1180 | hdr->nops++; | 1366 | hdr->nops++; |
1367 | hdr->replen += decode_readdir_maxsz; | ||
1181 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", | 1368 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", |
1182 | __func__, | 1369 | __func__, |
1183 | (unsigned long long)readdir->cookie, | 1370 | (unsigned long long)readdir->cookie, |
@@ -1194,6 +1381,7 @@ static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink * | |||
1194 | RESERVE_SPACE(4); | 1381 | RESERVE_SPACE(4); |
1195 | WRITE32(OP_READLINK); | 1382 | WRITE32(OP_READLINK); |
1196 | hdr->nops++; | 1383 | hdr->nops++; |
1384 | hdr->replen += decode_readlink_maxsz; | ||
1197 | } | 1385 | } |
1198 | 1386 | ||
1199 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1387 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
@@ -1205,6 +1393,7 @@ static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struc | |||
1205 | WRITE32(name->len); | 1393 | WRITE32(name->len); |
1206 | WRITEMEM(name->name, name->len); | 1394 | WRITEMEM(name->name, name->len); |
1207 | hdr->nops++; | 1395 | hdr->nops++; |
1396 | hdr->replen += decode_remove_maxsz; | ||
1208 | } | 1397 | } |
1209 | 1398 | ||
1210 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) | 1399 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) |
@@ -1220,6 +1409,7 @@ static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, co | |||
1220 | WRITE32(newname->len); | 1409 | WRITE32(newname->len); |
1221 | WRITEMEM(newname->name, newname->len); | 1410 | WRITEMEM(newname->name, newname->len); |
1222 | hdr->nops++; | 1411 | hdr->nops++; |
1412 | hdr->replen += decode_rename_maxsz; | ||
1223 | } | 1413 | } |
1224 | 1414 | ||
1225 | static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr) | 1415 | static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr) |
@@ -1230,6 +1420,7 @@ static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client | |||
1230 | WRITE32(OP_RENEW); | 1420 | WRITE32(OP_RENEW); |
1231 | WRITE64(client_stateid->cl_clientid); | 1421 | WRITE64(client_stateid->cl_clientid); |
1232 | hdr->nops++; | 1422 | hdr->nops++; |
1423 | hdr->replen += decode_renew_maxsz; | ||
1233 | } | 1424 | } |
1234 | 1425 | ||
1235 | static void | 1426 | static void |
@@ -1240,6 +1431,7 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1240 | RESERVE_SPACE(4); | 1431 | RESERVE_SPACE(4); |
1241 | WRITE32(OP_RESTOREFH); | 1432 | WRITE32(OP_RESTOREFH); |
1242 | hdr->nops++; | 1433 | hdr->nops++; |
1434 | hdr->replen += decode_restorefh_maxsz; | ||
1243 | } | 1435 | } |
1244 | 1436 | ||
1245 | static int | 1437 | static int |
@@ -1259,6 +1451,7 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun | |||
1259 | WRITE32(arg->acl_len); | 1451 | WRITE32(arg->acl_len); |
1260 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); | 1452 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); |
1261 | hdr->nops++; | 1453 | hdr->nops++; |
1454 | hdr->replen += decode_setacl_maxsz; | ||
1262 | return 0; | 1455 | return 0; |
1263 | } | 1456 | } |
1264 | 1457 | ||
@@ -1270,6 +1463,7 @@ encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1270 | RESERVE_SPACE(4); | 1463 | RESERVE_SPACE(4); |
1271 | WRITE32(OP_SAVEFH); | 1464 | WRITE32(OP_SAVEFH); |
1272 | hdr->nops++; | 1465 | hdr->nops++; |
1466 | hdr->replen += decode_savefh_maxsz; | ||
1273 | } | 1467 | } |
1274 | 1468 | ||
1275 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) | 1469 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) |
@@ -1280,6 +1474,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs | |||
1280 | WRITE32(OP_SETATTR); | 1474 | WRITE32(OP_SETATTR); |
1281 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); | 1475 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); |
1282 | hdr->nops++; | 1476 | hdr->nops++; |
1477 | hdr->replen += decode_setattr_maxsz; | ||
1283 | encode_attrs(xdr, arg->iap, server); | 1478 | encode_attrs(xdr, arg->iap, server); |
1284 | } | 1479 | } |
1285 | 1480 | ||
@@ -1299,6 +1494,7 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie | |||
1299 | RESERVE_SPACE(4); | 1494 | RESERVE_SPACE(4); |
1300 | WRITE32(setclientid->sc_cb_ident); | 1495 | WRITE32(setclientid->sc_cb_ident); |
1301 | hdr->nops++; | 1496 | hdr->nops++; |
1497 | hdr->replen += decode_setclientid_maxsz; | ||
1302 | } | 1498 | } |
1303 | 1499 | ||
1304 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) | 1500 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) |
@@ -1310,6 +1506,7 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_ | |||
1310 | WRITE64(client_state->cl_clientid); | 1506 | WRITE64(client_state->cl_clientid); |
1311 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); | 1507 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); |
1312 | hdr->nops++; | 1508 | hdr->nops++; |
1509 | hdr->replen += decode_setclientid_confirm_maxsz; | ||
1313 | } | 1510 | } |
1314 | 1511 | ||
1315 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) | 1512 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
@@ -1328,6 +1525,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg | |||
1328 | 1525 | ||
1329 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); | 1526 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); |
1330 | hdr->nops++; | 1527 | hdr->nops++; |
1528 | hdr->replen += decode_write_maxsz; | ||
1331 | } | 1529 | } |
1332 | 1530 | ||
1333 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) | 1531 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) |
@@ -1339,11 +1537,163 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state | |||
1339 | WRITE32(OP_DELEGRETURN); | 1537 | WRITE32(OP_DELEGRETURN); |
1340 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); | 1538 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); |
1341 | hdr->nops++; | 1539 | hdr->nops++; |
1540 | hdr->replen += decode_delegreturn_maxsz; | ||
1541 | } | ||
1542 | |||
1543 | #if defined(CONFIG_NFS_V4_1) | ||
1544 | /* NFSv4.1 operations */ | ||
1545 | static void encode_exchange_id(struct xdr_stream *xdr, | ||
1546 | struct nfs41_exchange_id_args *args, | ||
1547 | struct compound_hdr *hdr) | ||
1548 | { | ||
1549 | __be32 *p; | ||
1550 | |||
1551 | RESERVE_SPACE(4 + sizeof(args->verifier->data)); | ||
1552 | WRITE32(OP_EXCHANGE_ID); | ||
1553 | WRITEMEM(args->verifier->data, sizeof(args->verifier->data)); | ||
1554 | |||
1555 | encode_string(xdr, args->id_len, args->id); | ||
1556 | |||
1557 | RESERVE_SPACE(12); | ||
1558 | WRITE32(args->flags); | ||
1559 | WRITE32(0); /* zero length state_protect4_a */ | ||
1560 | WRITE32(0); /* zero length implementation id array */ | ||
1561 | hdr->nops++; | ||
1562 | hdr->replen += decode_exchange_id_maxsz; | ||
1563 | } | ||
1564 | |||
1565 | static void encode_create_session(struct xdr_stream *xdr, | ||
1566 | struct nfs41_create_session_args *args, | ||
1567 | struct compound_hdr *hdr) | ||
1568 | { | ||
1569 | __be32 *p; | ||
1570 | char machine_name[NFS4_MAX_MACHINE_NAME_LEN]; | ||
1571 | uint32_t len; | ||
1572 | struct nfs_client *clp = args->client; | ||
1573 | |||
1574 | RESERVE_SPACE(4); | ||
1575 | WRITE32(OP_CREATE_SESSION); | ||
1576 | |||
1577 | RESERVE_SPACE(8); | ||
1578 | WRITE64(clp->cl_ex_clid); | ||
1579 | |||
1580 | RESERVE_SPACE(8); | ||
1581 | WRITE32(clp->cl_seqid); /*Sequence id */ | ||
1582 | WRITE32(args->flags); /*flags */ | ||
1583 | |||
1584 | RESERVE_SPACE(2*28); /* 2 channel_attrs */ | ||
1585 | /* Fore Channel */ | ||
1586 | WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ | ||
1587 | WRITE32(args->fc_attrs.max_rqst_sz); /* max req size */ | ||
1588 | WRITE32(args->fc_attrs.max_resp_sz); /* max resp size */ | ||
1589 | WRITE32(args->fc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | ||
1590 | WRITE32(args->fc_attrs.max_ops); /* max operations */ | ||
1591 | WRITE32(args->fc_attrs.max_reqs); /* max requests */ | ||
1592 | WRITE32(0); /* rdmachannel_attrs */ | ||
1593 | |||
1594 | /* Back Channel */ | ||
1595 | WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ | ||
1596 | WRITE32(args->bc_attrs.max_rqst_sz); /* max req size */ | ||
1597 | WRITE32(args->bc_attrs.max_resp_sz); /* max resp size */ | ||
1598 | WRITE32(args->bc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | ||
1599 | WRITE32(args->bc_attrs.max_ops); /* max operations */ | ||
1600 | WRITE32(args->bc_attrs.max_reqs); /* max requests */ | ||
1601 | WRITE32(0); /* rdmachannel_attrs */ | ||
1602 | |||
1603 | RESERVE_SPACE(4); | ||
1604 | WRITE32(args->cb_program); /* cb_program */ | ||
1605 | |||
1606 | RESERVE_SPACE(4); /* # of security flavors */ | ||
1607 | WRITE32(1); | ||
1608 | |||
1609 | RESERVE_SPACE(4); | ||
1610 | WRITE32(RPC_AUTH_UNIX); /* auth_sys */ | ||
1611 | |||
1612 | /* authsys_parms rfc1831 */ | ||
1613 | RESERVE_SPACE(4); | ||
1614 | WRITE32((u32)clp->cl_boot_time.tv_nsec); /* stamp */ | ||
1615 | len = scnprintf(machine_name, sizeof(machine_name), "%s", | ||
1616 | clp->cl_ipaddr); | ||
1617 | RESERVE_SPACE(16 + len); | ||
1618 | WRITE32(len); | ||
1619 | WRITEMEM(machine_name, len); | ||
1620 | WRITE32(0); /* UID */ | ||
1621 | WRITE32(0); /* GID */ | ||
1622 | WRITE32(0); /* No more gids */ | ||
1623 | hdr->nops++; | ||
1624 | hdr->replen += decode_create_session_maxsz; | ||
1625 | } | ||
1626 | |||
1627 | static void encode_destroy_session(struct xdr_stream *xdr, | ||
1628 | struct nfs4_session *session, | ||
1629 | struct compound_hdr *hdr) | ||
1630 | { | ||
1631 | __be32 *p; | ||
1632 | RESERVE_SPACE(4 + NFS4_MAX_SESSIONID_LEN); | ||
1633 | WRITE32(OP_DESTROY_SESSION); | ||
1634 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | ||
1635 | hdr->nops++; | ||
1636 | hdr->replen += decode_destroy_session_maxsz; | ||
1342 | } | 1637 | } |
1638 | #endif /* CONFIG_NFS_V4_1 */ | ||
1639 | |||
1640 | static void encode_sequence(struct xdr_stream *xdr, | ||
1641 | const struct nfs4_sequence_args *args, | ||
1642 | struct compound_hdr *hdr) | ||
1643 | { | ||
1644 | #if defined(CONFIG_NFS_V4_1) | ||
1645 | struct nfs4_session *session = args->sa_session; | ||
1646 | struct nfs4_slot_table *tp; | ||
1647 | struct nfs4_slot *slot; | ||
1648 | __be32 *p; | ||
1649 | |||
1650 | if (!session) | ||
1651 | return; | ||
1652 | |||
1653 | tp = &session->fc_slot_table; | ||
1654 | |||
1655 | WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); | ||
1656 | slot = tp->slots + args->sa_slotid; | ||
1657 | |||
1658 | RESERVE_SPACE(4); | ||
1659 | WRITE32(OP_SEQUENCE); | ||
1660 | |||
1661 | /* | ||
1662 | * Sessionid + seqid + slotid + max slotid + cache_this | ||
1663 | */ | ||
1664 | dprintk("%s: sessionid=%u:%u:%u:%u seqid=%d slotid=%d " | ||
1665 | "max_slotid=%d cache_this=%d\n", | ||
1666 | __func__, | ||
1667 | ((u32 *)session->sess_id.data)[0], | ||
1668 | ((u32 *)session->sess_id.data)[1], | ||
1669 | ((u32 *)session->sess_id.data)[2], | ||
1670 | ((u32 *)session->sess_id.data)[3], | ||
1671 | slot->seq_nr, args->sa_slotid, | ||
1672 | tp->highest_used_slotid, args->sa_cache_this); | ||
1673 | RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 16); | ||
1674 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | ||
1675 | WRITE32(slot->seq_nr); | ||
1676 | WRITE32(args->sa_slotid); | ||
1677 | WRITE32(tp->highest_used_slotid); | ||
1678 | WRITE32(args->sa_cache_this); | ||
1679 | hdr->nops++; | ||
1680 | hdr->replen += decode_sequence_maxsz; | ||
1681 | #endif /* CONFIG_NFS_V4_1 */ | ||
1682 | } | ||
1683 | |||
1343 | /* | 1684 | /* |
1344 | * END OF "GENERIC" ENCODE ROUTINES. | 1685 | * END OF "GENERIC" ENCODE ROUTINES. |
1345 | */ | 1686 | */ |
1346 | 1687 | ||
1688 | static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args) | ||
1689 | { | ||
1690 | #if defined(CONFIG_NFS_V4_1) | ||
1691 | if (args->sa_session) | ||
1692 | return args->sa_session->clp->cl_minorversion; | ||
1693 | #endif /* CONFIG_NFS_V4_1 */ | ||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1347 | /* | 1697 | /* |
1348 | * Encode an ACCESS request | 1698 | * Encode an ACCESS request |
1349 | */ | 1699 | */ |
@@ -1351,11 +1701,12 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1351 | { | 1701 | { |
1352 | struct xdr_stream xdr; | 1702 | struct xdr_stream xdr; |
1353 | struct compound_hdr hdr = { | 1703 | struct compound_hdr hdr = { |
1354 | .nops = 0, | 1704 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1355 | }; | 1705 | }; |
1356 | 1706 | ||
1357 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1707 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1358 | encode_compound_hdr(&xdr, &hdr); | 1708 | encode_compound_hdr(&xdr, req, &hdr); |
1709 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1359 | encode_putfh(&xdr, args->fh, &hdr); | 1710 | encode_putfh(&xdr, args->fh, &hdr); |
1360 | encode_access(&xdr, args->access, &hdr); | 1711 | encode_access(&xdr, args->access, &hdr); |
1361 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1712 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1370,11 +1721,12 @@ static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1370 | { | 1721 | { |
1371 | struct xdr_stream xdr; | 1722 | struct xdr_stream xdr; |
1372 | struct compound_hdr hdr = { | 1723 | struct compound_hdr hdr = { |
1373 | .nops = 0, | 1724 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1374 | }; | 1725 | }; |
1375 | 1726 | ||
1376 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1727 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1377 | encode_compound_hdr(&xdr, &hdr); | 1728 | encode_compound_hdr(&xdr, req, &hdr); |
1729 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1378 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1730 | encode_putfh(&xdr, args->dir_fh, &hdr); |
1379 | encode_lookup(&xdr, args->name, &hdr); | 1731 | encode_lookup(&xdr, args->name, &hdr); |
1380 | encode_getfh(&xdr, &hdr); | 1732 | encode_getfh(&xdr, &hdr); |
@@ -1390,11 +1742,12 @@ static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struc | |||
1390 | { | 1742 | { |
1391 | struct xdr_stream xdr; | 1743 | struct xdr_stream xdr; |
1392 | struct compound_hdr hdr = { | 1744 | struct compound_hdr hdr = { |
1393 | .nops = 0, | 1745 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1394 | }; | 1746 | }; |
1395 | 1747 | ||
1396 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1748 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1397 | encode_compound_hdr(&xdr, &hdr); | 1749 | encode_compound_hdr(&xdr, req, &hdr); |
1750 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1398 | encode_putrootfh(&xdr, &hdr); | 1751 | encode_putrootfh(&xdr, &hdr); |
1399 | encode_getfh(&xdr, &hdr); | 1752 | encode_getfh(&xdr, &hdr); |
1400 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1753 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1409,11 +1762,12 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1409 | { | 1762 | { |
1410 | struct xdr_stream xdr; | 1763 | struct xdr_stream xdr; |
1411 | struct compound_hdr hdr = { | 1764 | struct compound_hdr hdr = { |
1412 | .nops = 0, | 1765 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1413 | }; | 1766 | }; |
1414 | 1767 | ||
1415 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1768 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1416 | encode_compound_hdr(&xdr, &hdr); | 1769 | encode_compound_hdr(&xdr, req, &hdr); |
1770 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1417 | encode_putfh(&xdr, args->fh, &hdr); | 1771 | encode_putfh(&xdr, args->fh, &hdr); |
1418 | encode_remove(&xdr, &args->name, &hdr); | 1772 | encode_remove(&xdr, &args->name, &hdr); |
1419 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1773 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1428,11 +1782,12 @@ static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1428 | { | 1782 | { |
1429 | struct xdr_stream xdr; | 1783 | struct xdr_stream xdr; |
1430 | struct compound_hdr hdr = { | 1784 | struct compound_hdr hdr = { |
1431 | .nops = 0, | 1785 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1432 | }; | 1786 | }; |
1433 | 1787 | ||
1434 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1788 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1435 | encode_compound_hdr(&xdr, &hdr); | 1789 | encode_compound_hdr(&xdr, req, &hdr); |
1790 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1436 | encode_putfh(&xdr, args->old_dir, &hdr); | 1791 | encode_putfh(&xdr, args->old_dir, &hdr); |
1437 | encode_savefh(&xdr, &hdr); | 1792 | encode_savefh(&xdr, &hdr); |
1438 | encode_putfh(&xdr, args->new_dir, &hdr); | 1793 | encode_putfh(&xdr, args->new_dir, &hdr); |
@@ -1451,11 +1806,12 @@ static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_ | |||
1451 | { | 1806 | { |
1452 | struct xdr_stream xdr; | 1807 | struct xdr_stream xdr; |
1453 | struct compound_hdr hdr = { | 1808 | struct compound_hdr hdr = { |
1454 | .nops = 0, | 1809 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1455 | }; | 1810 | }; |
1456 | 1811 | ||
1457 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1812 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1458 | encode_compound_hdr(&xdr, &hdr); | 1813 | encode_compound_hdr(&xdr, req, &hdr); |
1814 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1459 | encode_putfh(&xdr, args->fh, &hdr); | 1815 | encode_putfh(&xdr, args->fh, &hdr); |
1460 | encode_savefh(&xdr, &hdr); | 1816 | encode_savefh(&xdr, &hdr); |
1461 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1817 | encode_putfh(&xdr, args->dir_fh, &hdr); |
@@ -1474,11 +1830,12 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1474 | { | 1830 | { |
1475 | struct xdr_stream xdr; | 1831 | struct xdr_stream xdr; |
1476 | struct compound_hdr hdr = { | 1832 | struct compound_hdr hdr = { |
1477 | .nops = 0, | 1833 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1478 | }; | 1834 | }; |
1479 | 1835 | ||
1480 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1836 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1481 | encode_compound_hdr(&xdr, &hdr); | 1837 | encode_compound_hdr(&xdr, req, &hdr); |
1838 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1482 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1839 | encode_putfh(&xdr, args->dir_fh, &hdr); |
1483 | encode_savefh(&xdr, &hdr); | 1840 | encode_savefh(&xdr, &hdr); |
1484 | encode_create(&xdr, args, &hdr); | 1841 | encode_create(&xdr, args, &hdr); |
@@ -1505,11 +1862,12 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nf | |||
1505 | { | 1862 | { |
1506 | struct xdr_stream xdr; | 1863 | struct xdr_stream xdr; |
1507 | struct compound_hdr hdr = { | 1864 | struct compound_hdr hdr = { |
1508 | .nops = 0, | 1865 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1509 | }; | 1866 | }; |
1510 | 1867 | ||
1511 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1868 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1512 | encode_compound_hdr(&xdr, &hdr); | 1869 | encode_compound_hdr(&xdr, req, &hdr); |
1870 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1513 | encode_putfh(&xdr, args->fh, &hdr); | 1871 | encode_putfh(&xdr, args->fh, &hdr); |
1514 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1872 | encode_getfattr(&xdr, args->bitmask, &hdr); |
1515 | encode_nops(&hdr); | 1873 | encode_nops(&hdr); |
@@ -1523,11 +1881,12 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closea | |||
1523 | { | 1881 | { |
1524 | struct xdr_stream xdr; | 1882 | struct xdr_stream xdr; |
1525 | struct compound_hdr hdr = { | 1883 | struct compound_hdr hdr = { |
1526 | .nops = 0, | 1884 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1527 | }; | 1885 | }; |
1528 | 1886 | ||
1529 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1887 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1530 | encode_compound_hdr(&xdr, &hdr); | 1888 | encode_compound_hdr(&xdr, req, &hdr); |
1889 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1531 | encode_putfh(&xdr, args->fh, &hdr); | 1890 | encode_putfh(&xdr, args->fh, &hdr); |
1532 | encode_close(&xdr, args, &hdr); | 1891 | encode_close(&xdr, args, &hdr); |
1533 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1892 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1542,11 +1901,12 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openarg | |||
1542 | { | 1901 | { |
1543 | struct xdr_stream xdr; | 1902 | struct xdr_stream xdr; |
1544 | struct compound_hdr hdr = { | 1903 | struct compound_hdr hdr = { |
1545 | .nops = 0, | 1904 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1546 | }; | 1905 | }; |
1547 | 1906 | ||
1548 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1907 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1549 | encode_compound_hdr(&xdr, &hdr); | 1908 | encode_compound_hdr(&xdr, req, &hdr); |
1909 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1550 | encode_putfh(&xdr, args->fh, &hdr); | 1910 | encode_putfh(&xdr, args->fh, &hdr); |
1551 | encode_savefh(&xdr, &hdr); | 1911 | encode_savefh(&xdr, &hdr); |
1552 | encode_open(&xdr, args, &hdr); | 1912 | encode_open(&xdr, args, &hdr); |
@@ -1569,7 +1929,7 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs | |||
1569 | }; | 1929 | }; |
1570 | 1930 | ||
1571 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1931 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1572 | encode_compound_hdr(&xdr, &hdr); | 1932 | encode_compound_hdr(&xdr, req, &hdr); |
1573 | encode_putfh(&xdr, args->fh, &hdr); | 1933 | encode_putfh(&xdr, args->fh, &hdr); |
1574 | encode_open_confirm(&xdr, args, &hdr); | 1934 | encode_open_confirm(&xdr, args, &hdr); |
1575 | encode_nops(&hdr); | 1935 | encode_nops(&hdr); |
@@ -1583,11 +1943,12 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_ | |||
1583 | { | 1943 | { |
1584 | struct xdr_stream xdr; | 1944 | struct xdr_stream xdr; |
1585 | struct compound_hdr hdr = { | 1945 | struct compound_hdr hdr = { |
1586 | .nops = 0, | 1946 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1587 | }; | 1947 | }; |
1588 | 1948 | ||
1589 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1949 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1590 | encode_compound_hdr(&xdr, &hdr); | 1950 | encode_compound_hdr(&xdr, req, &hdr); |
1951 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1591 | encode_putfh(&xdr, args->fh, &hdr); | 1952 | encode_putfh(&xdr, args->fh, &hdr); |
1592 | encode_open(&xdr, args, &hdr); | 1953 | encode_open(&xdr, args, &hdr); |
1593 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1954 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1602,11 +1963,12 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct n | |||
1602 | { | 1963 | { |
1603 | struct xdr_stream xdr; | 1964 | struct xdr_stream xdr; |
1604 | struct compound_hdr hdr = { | 1965 | struct compound_hdr hdr = { |
1605 | .nops = 0, | 1966 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1606 | }; | 1967 | }; |
1607 | 1968 | ||
1608 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1969 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1609 | encode_compound_hdr(&xdr, &hdr); | 1970 | encode_compound_hdr(&xdr, req, &hdr); |
1971 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1610 | encode_putfh(&xdr, args->fh, &hdr); | 1972 | encode_putfh(&xdr, args->fh, &hdr); |
1611 | encode_open_downgrade(&xdr, args, &hdr); | 1973 | encode_open_downgrade(&xdr, args, &hdr); |
1612 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1974 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1621,11 +1983,12 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_ar | |||
1621 | { | 1983 | { |
1622 | struct xdr_stream xdr; | 1984 | struct xdr_stream xdr; |
1623 | struct compound_hdr hdr = { | 1985 | struct compound_hdr hdr = { |
1624 | .nops = 0, | 1986 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1625 | }; | 1987 | }; |
1626 | 1988 | ||
1627 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1989 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1628 | encode_compound_hdr(&xdr, &hdr); | 1990 | encode_compound_hdr(&xdr, req, &hdr); |
1991 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1629 | encode_putfh(&xdr, args->fh, &hdr); | 1992 | encode_putfh(&xdr, args->fh, &hdr); |
1630 | encode_lock(&xdr, args, &hdr); | 1993 | encode_lock(&xdr, args, &hdr); |
1631 | encode_nops(&hdr); | 1994 | encode_nops(&hdr); |
@@ -1639,11 +2002,12 @@ static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_ | |||
1639 | { | 2002 | { |
1640 | struct xdr_stream xdr; | 2003 | struct xdr_stream xdr; |
1641 | struct compound_hdr hdr = { | 2004 | struct compound_hdr hdr = { |
1642 | .nops = 0, | 2005 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1643 | }; | 2006 | }; |
1644 | 2007 | ||
1645 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2008 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1646 | encode_compound_hdr(&xdr, &hdr); | 2009 | encode_compound_hdr(&xdr, req, &hdr); |
2010 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1647 | encode_putfh(&xdr, args->fh, &hdr); | 2011 | encode_putfh(&xdr, args->fh, &hdr); |
1648 | encode_lockt(&xdr, args, &hdr); | 2012 | encode_lockt(&xdr, args, &hdr); |
1649 | encode_nops(&hdr); | 2013 | encode_nops(&hdr); |
@@ -1657,11 +2021,12 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_ | |||
1657 | { | 2021 | { |
1658 | struct xdr_stream xdr; | 2022 | struct xdr_stream xdr; |
1659 | struct compound_hdr hdr = { | 2023 | struct compound_hdr hdr = { |
1660 | .nops = 0, | 2024 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1661 | }; | 2025 | }; |
1662 | 2026 | ||
1663 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2027 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1664 | encode_compound_hdr(&xdr, &hdr); | 2028 | encode_compound_hdr(&xdr, req, &hdr); |
2029 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1665 | encode_putfh(&xdr, args->fh, &hdr); | 2030 | encode_putfh(&xdr, args->fh, &hdr); |
1666 | encode_locku(&xdr, args, &hdr); | 2031 | encode_locku(&xdr, args, &hdr); |
1667 | encode_nops(&hdr); | 2032 | encode_nops(&hdr); |
@@ -1675,22 +2040,16 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n | |||
1675 | { | 2040 | { |
1676 | struct xdr_stream xdr; | 2041 | struct xdr_stream xdr; |
1677 | struct compound_hdr hdr = { | 2042 | struct compound_hdr hdr = { |
1678 | .nops = 0, | 2043 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1679 | }; | 2044 | }; |
1680 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1681 | unsigned int replen; | ||
1682 | 2045 | ||
1683 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2046 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1684 | encode_compound_hdr(&xdr, &hdr); | 2047 | encode_compound_hdr(&xdr, req, &hdr); |
2048 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1685 | encode_putfh(&xdr, args->fh, &hdr); | 2049 | encode_putfh(&xdr, args->fh, &hdr); |
1686 | encode_readlink(&xdr, args, req, &hdr); | 2050 | encode_readlink(&xdr, args, req, &hdr); |
1687 | 2051 | ||
1688 | /* set up reply kvec | 2052 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages, |
1689 | * toplevel_status + taglen + rescount + OP_PUTFH + status | ||
1690 | * + OP_READLINK + status + string length = 8 | ||
1691 | */ | ||
1692 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readlink_sz) << 2; | ||
1693 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, | ||
1694 | args->pgbase, args->pglen); | 2053 | args->pgbase, args->pglen); |
1695 | encode_nops(&hdr); | 2054 | encode_nops(&hdr); |
1696 | return 0; | 2055 | return 0; |
@@ -1703,25 +2062,19 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf | |||
1703 | { | 2062 | { |
1704 | struct xdr_stream xdr; | 2063 | struct xdr_stream xdr; |
1705 | struct compound_hdr hdr = { | 2064 | struct compound_hdr hdr = { |
1706 | .nops = 0, | 2065 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1707 | }; | 2066 | }; |
1708 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1709 | int replen; | ||
1710 | 2067 | ||
1711 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2068 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1712 | encode_compound_hdr(&xdr, &hdr); | 2069 | encode_compound_hdr(&xdr, req, &hdr); |
2070 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1713 | encode_putfh(&xdr, args->fh, &hdr); | 2071 | encode_putfh(&xdr, args->fh, &hdr); |
1714 | encode_readdir(&xdr, args, req, &hdr); | 2072 | encode_readdir(&xdr, args, req, &hdr); |
1715 | 2073 | ||
1716 | /* set up reply kvec | 2074 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages, |
1717 | * toplevel_status + taglen + rescount + OP_PUTFH + status | ||
1718 | * + OP_READDIR + status + verifer(2) = 9 | ||
1719 | */ | ||
1720 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readdir_sz) << 2; | ||
1721 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, | ||
1722 | args->pgbase, args->count); | 2075 | args->pgbase, args->count); |
1723 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", | 2076 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", |
1724 | __func__, replen, args->pages, | 2077 | __func__, hdr.replen << 2, args->pages, |
1725 | args->pgbase, args->count); | 2078 | args->pgbase, args->count); |
1726 | encode_nops(&hdr); | 2079 | encode_nops(&hdr); |
1727 | return 0; | 2080 | return 0; |
@@ -1732,24 +2085,18 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf | |||
1732 | */ | 2085 | */ |
1733 | static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) | 2086 | static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) |
1734 | { | 2087 | { |
1735 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1736 | struct xdr_stream xdr; | 2088 | struct xdr_stream xdr; |
1737 | struct compound_hdr hdr = { | 2089 | struct compound_hdr hdr = { |
1738 | .nops = 0, | 2090 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1739 | }; | 2091 | }; |
1740 | int replen; | ||
1741 | 2092 | ||
1742 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2093 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1743 | encode_compound_hdr(&xdr, &hdr); | 2094 | encode_compound_hdr(&xdr, req, &hdr); |
2095 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1744 | encode_putfh(&xdr, args->fh, &hdr); | 2096 | encode_putfh(&xdr, args->fh, &hdr); |
1745 | encode_read(&xdr, args, &hdr); | 2097 | encode_read(&xdr, args, &hdr); |
1746 | 2098 | ||
1747 | /* set up reply kvec | 2099 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, |
1748 | * toplevel status + taglen=0 + rescount + OP_PUTFH + status | ||
1749 | * + OP_READ + status + eof + datalen = 9 | ||
1750 | */ | ||
1751 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2; | ||
1752 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
1753 | args->pages, args->pgbase, args->count); | 2100 | args->pages, args->pgbase, args->count); |
1754 | req->rq_rcv_buf.flags |= XDRBUF_READ; | 2101 | req->rq_rcv_buf.flags |= XDRBUF_READ; |
1755 | encode_nops(&hdr); | 2102 | encode_nops(&hdr); |
@@ -1763,11 +2110,12 @@ static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_seta | |||
1763 | { | 2110 | { |
1764 | struct xdr_stream xdr; | 2111 | struct xdr_stream xdr; |
1765 | struct compound_hdr hdr = { | 2112 | struct compound_hdr hdr = { |
1766 | .nops = 0, | 2113 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1767 | }; | 2114 | }; |
1768 | 2115 | ||
1769 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2116 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1770 | encode_compound_hdr(&xdr, &hdr); | 2117 | encode_compound_hdr(&xdr, req, &hdr); |
2118 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1771 | encode_putfh(&xdr, args->fh, &hdr); | 2119 | encode_putfh(&xdr, args->fh, &hdr); |
1772 | encode_setattr(&xdr, args, args->server, &hdr); | 2120 | encode_setattr(&xdr, args, args->server, &hdr); |
1773 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2121 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1783,20 +2131,19 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p, | |||
1783 | struct nfs_getaclargs *args) | 2131 | struct nfs_getaclargs *args) |
1784 | { | 2132 | { |
1785 | struct xdr_stream xdr; | 2133 | struct xdr_stream xdr; |
1786 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1787 | struct compound_hdr hdr = { | 2134 | struct compound_hdr hdr = { |
1788 | .nops = 0, | 2135 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1789 | }; | 2136 | }; |
1790 | int replen; | 2137 | uint32_t replen; |
1791 | 2138 | ||
1792 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2139 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1793 | encode_compound_hdr(&xdr, &hdr); | 2140 | encode_compound_hdr(&xdr, req, &hdr); |
2141 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1794 | encode_putfh(&xdr, args->fh, &hdr); | 2142 | encode_putfh(&xdr, args->fh, &hdr); |
2143 | replen = hdr.replen + nfs4_fattr_bitmap_maxsz + 1; | ||
1795 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); | 2144 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); |
1796 | 2145 | ||
1797 | /* set up reply buffer: */ | 2146 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, |
1798 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2; | ||
1799 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
1800 | args->acl_pages, args->acl_pgbase, args->acl_len); | 2147 | args->acl_pages, args->acl_pgbase, args->acl_len); |
1801 | encode_nops(&hdr); | 2148 | encode_nops(&hdr); |
1802 | return 0; | 2149 | return 0; |
@@ -1809,11 +2156,12 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea | |||
1809 | { | 2156 | { |
1810 | struct xdr_stream xdr; | 2157 | struct xdr_stream xdr; |
1811 | struct compound_hdr hdr = { | 2158 | struct compound_hdr hdr = { |
1812 | .nops = 0, | 2159 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1813 | }; | 2160 | }; |
1814 | 2161 | ||
1815 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2162 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1816 | encode_compound_hdr(&xdr, &hdr); | 2163 | encode_compound_hdr(&xdr, req, &hdr); |
2164 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1817 | encode_putfh(&xdr, args->fh, &hdr); | 2165 | encode_putfh(&xdr, args->fh, &hdr); |
1818 | encode_write(&xdr, args, &hdr); | 2166 | encode_write(&xdr, args, &hdr); |
1819 | req->rq_snd_buf.flags |= XDRBUF_WRITE; | 2167 | req->rq_snd_buf.flags |= XDRBUF_WRITE; |
@@ -1829,11 +2177,12 @@ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_write | |||
1829 | { | 2177 | { |
1830 | struct xdr_stream xdr; | 2178 | struct xdr_stream xdr; |
1831 | struct compound_hdr hdr = { | 2179 | struct compound_hdr hdr = { |
1832 | .nops = 0, | 2180 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1833 | }; | 2181 | }; |
1834 | 2182 | ||
1835 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2183 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1836 | encode_compound_hdr(&xdr, &hdr); | 2184 | encode_compound_hdr(&xdr, req, &hdr); |
2185 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1837 | encode_putfh(&xdr, args->fh, &hdr); | 2186 | encode_putfh(&xdr, args->fh, &hdr); |
1838 | encode_commit(&xdr, args, &hdr); | 2187 | encode_commit(&xdr, args, &hdr); |
1839 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2188 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1848,11 +2197,12 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsin | |||
1848 | { | 2197 | { |
1849 | struct xdr_stream xdr; | 2198 | struct xdr_stream xdr; |
1850 | struct compound_hdr hdr = { | 2199 | struct compound_hdr hdr = { |
1851 | .nops = 0, | 2200 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1852 | }; | 2201 | }; |
1853 | 2202 | ||
1854 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2203 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1855 | encode_compound_hdr(&xdr, &hdr); | 2204 | encode_compound_hdr(&xdr, req, &hdr); |
2205 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1856 | encode_putfh(&xdr, args->fh, &hdr); | 2206 | encode_putfh(&xdr, args->fh, &hdr); |
1857 | encode_fsinfo(&xdr, args->bitmask, &hdr); | 2207 | encode_fsinfo(&xdr, args->bitmask, &hdr); |
1858 | encode_nops(&hdr); | 2208 | encode_nops(&hdr); |
@@ -1866,11 +2216,12 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct n | |||
1866 | { | 2216 | { |
1867 | struct xdr_stream xdr; | 2217 | struct xdr_stream xdr; |
1868 | struct compound_hdr hdr = { | 2218 | struct compound_hdr hdr = { |
1869 | .nops = 0, | 2219 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1870 | }; | 2220 | }; |
1871 | 2221 | ||
1872 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2222 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1873 | encode_compound_hdr(&xdr, &hdr); | 2223 | encode_compound_hdr(&xdr, req, &hdr); |
2224 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1874 | encode_putfh(&xdr, args->fh, &hdr); | 2225 | encode_putfh(&xdr, args->fh, &hdr); |
1875 | encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0], | 2226 | encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0], |
1876 | &hdr); | 2227 | &hdr); |
@@ -1885,11 +2236,12 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1885 | { | 2236 | { |
1886 | struct xdr_stream xdr; | 2237 | struct xdr_stream xdr; |
1887 | struct compound_hdr hdr = { | 2238 | struct compound_hdr hdr = { |
1888 | .nops = 0, | 2239 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1889 | }; | 2240 | }; |
1890 | 2241 | ||
1891 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2242 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1892 | encode_compound_hdr(&xdr, &hdr); | 2243 | encode_compound_hdr(&xdr, req, &hdr); |
2244 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1893 | encode_putfh(&xdr, args->fh, &hdr); | 2245 | encode_putfh(&xdr, args->fh, &hdr); |
1894 | encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0], | 2246 | encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0], |
1895 | args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr); | 2247 | args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr); |
@@ -1900,16 +2252,18 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1900 | /* | 2252 | /* |
1901 | * GETATTR_BITMAP request | 2253 | * GETATTR_BITMAP request |
1902 | */ | 2254 | */ |
1903 | static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle) | 2255 | static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, |
2256 | struct nfs4_server_caps_arg *args) | ||
1904 | { | 2257 | { |
1905 | struct xdr_stream xdr; | 2258 | struct xdr_stream xdr; |
1906 | struct compound_hdr hdr = { | 2259 | struct compound_hdr hdr = { |
1907 | .nops = 0, | 2260 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1908 | }; | 2261 | }; |
1909 | 2262 | ||
1910 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2263 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1911 | encode_compound_hdr(&xdr, &hdr); | 2264 | encode_compound_hdr(&xdr, req, &hdr); |
1912 | encode_putfh(&xdr, fhandle, &hdr); | 2265 | encode_sequence(&xdr, &args->seq_args, &hdr); |
2266 | encode_putfh(&xdr, args->fhandle, &hdr); | ||
1913 | encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| | 2267 | encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| |
1914 | FATTR4_WORD0_LINK_SUPPORT| | 2268 | FATTR4_WORD0_LINK_SUPPORT| |
1915 | FATTR4_WORD0_SYMLINK_SUPPORT| | 2269 | FATTR4_WORD0_SYMLINK_SUPPORT| |
@@ -1929,7 +2283,7 @@ static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client | |||
1929 | }; | 2283 | }; |
1930 | 2284 | ||
1931 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2285 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1932 | encode_compound_hdr(&xdr, &hdr); | 2286 | encode_compound_hdr(&xdr, req, &hdr); |
1933 | encode_renew(&xdr, clp, &hdr); | 2287 | encode_renew(&xdr, clp, &hdr); |
1934 | encode_nops(&hdr); | 2288 | encode_nops(&hdr); |
1935 | return 0; | 2289 | return 0; |
@@ -1946,7 +2300,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
1946 | }; | 2300 | }; |
1947 | 2301 | ||
1948 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2302 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1949 | encode_compound_hdr(&xdr, &hdr); | 2303 | encode_compound_hdr(&xdr, req, &hdr); |
1950 | encode_setclientid(&xdr, sc, &hdr); | 2304 | encode_setclientid(&xdr, sc, &hdr); |
1951 | encode_nops(&hdr); | 2305 | encode_nops(&hdr); |
1952 | return 0; | 2306 | return 0; |
@@ -1964,7 +2318,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
1964 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; | 2318 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; |
1965 | 2319 | ||
1966 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2320 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1967 | encode_compound_hdr(&xdr, &hdr); | 2321 | encode_compound_hdr(&xdr, req, &hdr); |
1968 | encode_setclientid_confirm(&xdr, clp, &hdr); | 2322 | encode_setclientid_confirm(&xdr, clp, &hdr); |
1969 | encode_putrootfh(&xdr, &hdr); | 2323 | encode_putrootfh(&xdr, &hdr); |
1970 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | 2324 | encode_fsinfo(&xdr, lease_bitmap, &hdr); |
@@ -1979,11 +2333,12 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struc | |||
1979 | { | 2333 | { |
1980 | struct xdr_stream xdr; | 2334 | struct xdr_stream xdr; |
1981 | struct compound_hdr hdr = { | 2335 | struct compound_hdr hdr = { |
1982 | .nops = 0, | 2336 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1983 | }; | 2337 | }; |
1984 | 2338 | ||
1985 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2339 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1986 | encode_compound_hdr(&xdr, &hdr); | 2340 | encode_compound_hdr(&xdr, req, &hdr); |
2341 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1987 | encode_putfh(&xdr, args->fhandle, &hdr); | 2342 | encode_putfh(&xdr, args->fhandle, &hdr); |
1988 | encode_delegreturn(&xdr, args->stateid, &hdr); | 2343 | encode_delegreturn(&xdr, args->stateid, &hdr); |
1989 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2344 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1998,28 +2353,119 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
1998 | { | 2353 | { |
1999 | struct xdr_stream xdr; | 2354 | struct xdr_stream xdr; |
2000 | struct compound_hdr hdr = { | 2355 | struct compound_hdr hdr = { |
2001 | .nops = 0, | 2356 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
2002 | }; | 2357 | }; |
2003 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 2358 | uint32_t replen; |
2004 | int replen; | ||
2005 | 2359 | ||
2006 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2360 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
2007 | encode_compound_hdr(&xdr, &hdr); | 2361 | encode_compound_hdr(&xdr, req, &hdr); |
2362 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
2008 | encode_putfh(&xdr, args->dir_fh, &hdr); | 2363 | encode_putfh(&xdr, args->dir_fh, &hdr); |
2009 | encode_lookup(&xdr, args->name, &hdr); | 2364 | encode_lookup(&xdr, args->name, &hdr); |
2365 | replen = hdr.replen; /* get the attribute into args->page */ | ||
2010 | encode_fs_locations(&xdr, args->bitmask, &hdr); | 2366 | encode_fs_locations(&xdr, args->bitmask, &hdr); |
2011 | 2367 | ||
2012 | /* set up reply | 2368 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page, |
2013 | * toplevel_status + OP_PUTFH + status | ||
2014 | * + OP_LOOKUP + status + OP_GETATTR + status = 7 | ||
2015 | */ | ||
2016 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2; | ||
2017 | xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page, | ||
2018 | 0, PAGE_SIZE); | 2369 | 0, PAGE_SIZE); |
2019 | encode_nops(&hdr); | 2370 | encode_nops(&hdr); |
2020 | return 0; | 2371 | return 0; |
2021 | } | 2372 | } |
2022 | 2373 | ||
2374 | #if defined(CONFIG_NFS_V4_1) | ||
2375 | /* | ||
2376 | * EXCHANGE_ID request | ||
2377 | */ | ||
2378 | static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p, | ||
2379 | struct nfs41_exchange_id_args *args) | ||
2380 | { | ||
2381 | struct xdr_stream xdr; | ||
2382 | struct compound_hdr hdr = { | ||
2383 | .minorversion = args->client->cl_minorversion, | ||
2384 | }; | ||
2385 | |||
2386 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2387 | encode_compound_hdr(&xdr, req, &hdr); | ||
2388 | encode_exchange_id(&xdr, args, &hdr); | ||
2389 | encode_nops(&hdr); | ||
2390 | return 0; | ||
2391 | } | ||
2392 | |||
2393 | /* | ||
2394 | * a CREATE_SESSION request | ||
2395 | */ | ||
2396 | static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p, | ||
2397 | struct nfs41_create_session_args *args) | ||
2398 | { | ||
2399 | struct xdr_stream xdr; | ||
2400 | struct compound_hdr hdr = { | ||
2401 | .minorversion = args->client->cl_minorversion, | ||
2402 | }; | ||
2403 | |||
2404 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2405 | encode_compound_hdr(&xdr, req, &hdr); | ||
2406 | encode_create_session(&xdr, args, &hdr); | ||
2407 | encode_nops(&hdr); | ||
2408 | return 0; | ||
2409 | } | ||
2410 | |||
2411 | /* | ||
2412 | * a DESTROY_SESSION request | ||
2413 | */ | ||
2414 | static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p, | ||
2415 | struct nfs4_session *session) | ||
2416 | { | ||
2417 | struct xdr_stream xdr; | ||
2418 | struct compound_hdr hdr = { | ||
2419 | .minorversion = session->clp->cl_minorversion, | ||
2420 | }; | ||
2421 | |||
2422 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2423 | encode_compound_hdr(&xdr, req, &hdr); | ||
2424 | encode_destroy_session(&xdr, session, &hdr); | ||
2425 | encode_nops(&hdr); | ||
2426 | return 0; | ||
2427 | } | ||
2428 | |||
2429 | /* | ||
2430 | * a SEQUENCE request | ||
2431 | */ | ||
2432 | static int nfs4_xdr_enc_sequence(struct rpc_rqst *req, uint32_t *p, | ||
2433 | struct nfs4_sequence_args *args) | ||
2434 | { | ||
2435 | struct xdr_stream xdr; | ||
2436 | struct compound_hdr hdr = { | ||
2437 | .minorversion = nfs4_xdr_minorversion(args), | ||
2438 | }; | ||
2439 | |||
2440 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2441 | encode_compound_hdr(&xdr, req, &hdr); | ||
2442 | encode_sequence(&xdr, args, &hdr); | ||
2443 | encode_nops(&hdr); | ||
2444 | return 0; | ||
2445 | } | ||
2446 | |||
2447 | /* | ||
2448 | * a GET_LEASE_TIME request | ||
2449 | */ | ||
2450 | static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, | ||
2451 | struct nfs4_get_lease_time_args *args) | ||
2452 | { | ||
2453 | struct xdr_stream xdr; | ||
2454 | struct compound_hdr hdr = { | ||
2455 | .minorversion = nfs4_xdr_minorversion(&args->la_seq_args), | ||
2456 | }; | ||
2457 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; | ||
2458 | |||
2459 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2460 | encode_compound_hdr(&xdr, req, &hdr); | ||
2461 | encode_sequence(&xdr, &args->la_seq_args, &hdr); | ||
2462 | encode_putrootfh(&xdr, &hdr); | ||
2463 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | ||
2464 | encode_nops(&hdr); | ||
2465 | return 0; | ||
2466 | } | ||
2467 | #endif /* CONFIG_NFS_V4_1 */ | ||
2468 | |||
2023 | /* | 2469 | /* |
2024 | * START OF "GENERIC" DECODE ROUTINES. | 2470 | * START OF "GENERIC" DECODE ROUTINES. |
2025 | * These may look a little ugly since they are imported from a "generic" | 2471 | * These may look a little ugly since they are imported from a "generic" |
@@ -3657,7 +4103,7 @@ decode_savefh(struct xdr_stream *xdr) | |||
3657 | return decode_op_hdr(xdr, OP_SAVEFH); | 4103 | return decode_op_hdr(xdr, OP_SAVEFH); |
3658 | } | 4104 | } |
3659 | 4105 | ||
3660 | static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) | 4106 | static int decode_setattr(struct xdr_stream *xdr) |
3661 | { | 4107 | { |
3662 | __be32 *p; | 4108 | __be32 *p; |
3663 | uint32_t bmlen; | 4109 | uint32_t bmlen; |
@@ -3735,6 +4181,169 @@ static int decode_delegreturn(struct xdr_stream *xdr) | |||
3735 | return decode_op_hdr(xdr, OP_DELEGRETURN); | 4181 | return decode_op_hdr(xdr, OP_DELEGRETURN); |
3736 | } | 4182 | } |
3737 | 4183 | ||
4184 | #if defined(CONFIG_NFS_V4_1) | ||
4185 | static int decode_exchange_id(struct xdr_stream *xdr, | ||
4186 | struct nfs41_exchange_id_res *res) | ||
4187 | { | ||
4188 | __be32 *p; | ||
4189 | uint32_t dummy; | ||
4190 | int status; | ||
4191 | struct nfs_client *clp = res->client; | ||
4192 | |||
4193 | status = decode_op_hdr(xdr, OP_EXCHANGE_ID); | ||
4194 | if (status) | ||
4195 | return status; | ||
4196 | |||
4197 | READ_BUF(8); | ||
4198 | READ64(clp->cl_ex_clid); | ||
4199 | READ_BUF(12); | ||
4200 | READ32(clp->cl_seqid); | ||
4201 | READ32(clp->cl_exchange_flags); | ||
4202 | |||
4203 | /* We ask for SP4_NONE */ | ||
4204 | READ32(dummy); | ||
4205 | if (dummy != SP4_NONE) | ||
4206 | return -EIO; | ||
4207 | |||
4208 | /* Throw away minor_id */ | ||
4209 | READ_BUF(8); | ||
4210 | |||
4211 | /* Throw away Major id */ | ||
4212 | READ_BUF(4); | ||
4213 | READ32(dummy); | ||
4214 | READ_BUF(dummy); | ||
4215 | |||
4216 | /* Throw away server_scope */ | ||
4217 | READ_BUF(4); | ||
4218 | READ32(dummy); | ||
4219 | READ_BUF(dummy); | ||
4220 | |||
4221 | /* Throw away Implementation id array */ | ||
4222 | READ_BUF(4); | ||
4223 | READ32(dummy); | ||
4224 | READ_BUF(dummy); | ||
4225 | |||
4226 | return 0; | ||
4227 | } | ||
4228 | |||
4229 | static int decode_chan_attrs(struct xdr_stream *xdr, | ||
4230 | struct nfs4_channel_attrs *attrs) | ||
4231 | { | ||
4232 | __be32 *p; | ||
4233 | u32 nr_attrs; | ||
4234 | |||
4235 | READ_BUF(28); | ||
4236 | READ32(attrs->headerpadsz); | ||
4237 | READ32(attrs->max_rqst_sz); | ||
4238 | READ32(attrs->max_resp_sz); | ||
4239 | READ32(attrs->max_resp_sz_cached); | ||
4240 | READ32(attrs->max_ops); | ||
4241 | READ32(attrs->max_reqs); | ||
4242 | READ32(nr_attrs); | ||
4243 | if (unlikely(nr_attrs > 1)) { | ||
4244 | printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n", | ||
4245 | __func__, nr_attrs); | ||
4246 | return -EINVAL; | ||
4247 | } | ||
4248 | if (nr_attrs == 1) | ||
4249 | READ_BUF(4); /* skip rdma_attrs */ | ||
4250 | return 0; | ||
4251 | } | ||
4252 | |||
4253 | static int decode_create_session(struct xdr_stream *xdr, | ||
4254 | struct nfs41_create_session_res *res) | ||
4255 | { | ||
4256 | __be32 *p; | ||
4257 | int status; | ||
4258 | struct nfs_client *clp = res->client; | ||
4259 | struct nfs4_session *session = clp->cl_session; | ||
4260 | |||
4261 | status = decode_op_hdr(xdr, OP_CREATE_SESSION); | ||
4262 | |||
4263 | if (status) | ||
4264 | return status; | ||
4265 | |||
4266 | /* sessionid */ | ||
4267 | READ_BUF(NFS4_MAX_SESSIONID_LEN); | ||
4268 | COPYMEM(&session->sess_id, NFS4_MAX_SESSIONID_LEN); | ||
4269 | |||
4270 | /* seqid, flags */ | ||
4271 | READ_BUF(8); | ||
4272 | READ32(clp->cl_seqid); | ||
4273 | READ32(session->flags); | ||
4274 | |||
4275 | /* Channel attributes */ | ||
4276 | status = decode_chan_attrs(xdr, &session->fc_attrs); | ||
4277 | if (!status) | ||
4278 | status = decode_chan_attrs(xdr, &session->bc_attrs); | ||
4279 | return status; | ||
4280 | } | ||
4281 | |||
4282 | static int decode_destroy_session(struct xdr_stream *xdr, void *dummy) | ||
4283 | { | ||
4284 | return decode_op_hdr(xdr, OP_DESTROY_SESSION); | ||
4285 | } | ||
4286 | #endif /* CONFIG_NFS_V4_1 */ | ||
4287 | |||
4288 | static int decode_sequence(struct xdr_stream *xdr, | ||
4289 | struct nfs4_sequence_res *res, | ||
4290 | struct rpc_rqst *rqstp) | ||
4291 | { | ||
4292 | #if defined(CONFIG_NFS_V4_1) | ||
4293 | struct nfs4_slot *slot; | ||
4294 | struct nfs4_sessionid id; | ||
4295 | u32 dummy; | ||
4296 | int status; | ||
4297 | __be32 *p; | ||
4298 | |||
4299 | if (!res->sr_session) | ||
4300 | return 0; | ||
4301 | |||
4302 | status = decode_op_hdr(xdr, OP_SEQUENCE); | ||
4303 | if (status) | ||
4304 | goto out_err; | ||
4305 | |||
4306 | /* | ||
4307 | * If the server returns different values for sessionID, slotID or | ||
4308 | * sequence number, the server is looney tunes. | ||
4309 | */ | ||
4310 | status = -ESERVERFAULT; | ||
4311 | |||
4312 | slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; | ||
4313 | READ_BUF(NFS4_MAX_SESSIONID_LEN + 20); | ||
4314 | COPYMEM(id.data, NFS4_MAX_SESSIONID_LEN); | ||
4315 | if (memcmp(id.data, res->sr_session->sess_id.data, | ||
4316 | NFS4_MAX_SESSIONID_LEN)) { | ||
4317 | dprintk("%s Invalid session id\n", __func__); | ||
4318 | goto out_err; | ||
4319 | } | ||
4320 | /* seqid */ | ||
4321 | READ32(dummy); | ||
4322 | if (dummy != slot->seq_nr) { | ||
4323 | dprintk("%s Invalid sequence number\n", __func__); | ||
4324 | goto out_err; | ||
4325 | } | ||
4326 | /* slot id */ | ||
4327 | READ32(dummy); | ||
4328 | if (dummy != res->sr_slotid) { | ||
4329 | dprintk("%s Invalid slot id\n", __func__); | ||
4330 | goto out_err; | ||
4331 | } | ||
4332 | /* highest slot id - currently not processed */ | ||
4333 | READ32(dummy); | ||
4334 | /* target highest slot id - currently not processed */ | ||
4335 | READ32(dummy); | ||
4336 | /* result flags - currently not processed */ | ||
4337 | READ32(dummy); | ||
4338 | status = 0; | ||
4339 | out_err: | ||
4340 | res->sr_status = status; | ||
4341 | return status; | ||
4342 | #else /* CONFIG_NFS_V4_1 */ | ||
4343 | return 0; | ||
4344 | #endif /* CONFIG_NFS_V4_1 */ | ||
4345 | } | ||
4346 | |||
3738 | /* | 4347 | /* |
3739 | * END OF "GENERIC" DECODE ROUTINES. | 4348 | * END OF "GENERIC" DECODE ROUTINES. |
3740 | */ | 4349 | */ |
@@ -3752,6 +4361,9 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct | |||
3752 | status = decode_compound_hdr(&xdr, &hdr); | 4361 | status = decode_compound_hdr(&xdr, &hdr); |
3753 | if (status) | 4362 | if (status) |
3754 | goto out; | 4363 | goto out; |
4364 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4365 | if (status) | ||
4366 | goto out; | ||
3755 | status = decode_putfh(&xdr); | 4367 | status = decode_putfh(&xdr); |
3756 | if (status) | 4368 | if (status) |
3757 | goto out; | 4369 | goto out; |
@@ -3773,7 +4385,11 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac | |||
3773 | int status; | 4385 | int status; |
3774 | 4386 | ||
3775 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4387 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3776 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4388 | status = decode_compound_hdr(&xdr, &hdr); |
4389 | if (status) | ||
4390 | goto out; | ||
4391 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4392 | if (status) | ||
3777 | goto out; | 4393 | goto out; |
3778 | status = decode_putfh(&xdr); | 4394 | status = decode_putfh(&xdr); |
3779 | if (status != 0) | 4395 | if (status != 0) |
@@ -3796,7 +4412,11 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo | |||
3796 | int status; | 4412 | int status; |
3797 | 4413 | ||
3798 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4414 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3799 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4415 | status = decode_compound_hdr(&xdr, &hdr); |
4416 | if (status) | ||
4417 | goto out; | ||
4418 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4419 | if (status) | ||
3800 | goto out; | 4420 | goto out; |
3801 | if ((status = decode_putfh(&xdr)) != 0) | 4421 | if ((status = decode_putfh(&xdr)) != 0) |
3802 | goto out; | 4422 | goto out; |
@@ -3819,7 +4439,11 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
3819 | int status; | 4439 | int status; |
3820 | 4440 | ||
3821 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4441 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3822 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4442 | status = decode_compound_hdr(&xdr, &hdr); |
4443 | if (status) | ||
4444 | goto out; | ||
4445 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4446 | if (status) | ||
3823 | goto out; | 4447 | goto out; |
3824 | if ((status = decode_putrootfh(&xdr)) != 0) | 4448 | if ((status = decode_putrootfh(&xdr)) != 0) |
3825 | goto out; | 4449 | goto out; |
@@ -3839,7 +4463,11 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem | |||
3839 | int status; | 4463 | int status; |
3840 | 4464 | ||
3841 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4465 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3842 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4466 | status = decode_compound_hdr(&xdr, &hdr); |
4467 | if (status) | ||
4468 | goto out; | ||
4469 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4470 | if (status) | ||
3843 | goto out; | 4471 | goto out; |
3844 | if ((status = decode_putfh(&xdr)) != 0) | 4472 | if ((status = decode_putfh(&xdr)) != 0) |
3845 | goto out; | 4473 | goto out; |
@@ -3860,7 +4488,11 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re | |||
3860 | int status; | 4488 | int status; |
3861 | 4489 | ||
3862 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4490 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3863 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4491 | status = decode_compound_hdr(&xdr, &hdr); |
4492 | if (status) | ||
4493 | goto out; | ||
4494 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4495 | if (status) | ||
3864 | goto out; | 4496 | goto out; |
3865 | if ((status = decode_putfh(&xdr)) != 0) | 4497 | if ((status = decode_putfh(&xdr)) != 0) |
3866 | goto out; | 4498 | goto out; |
@@ -3890,7 +4522,11 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link | |||
3890 | int status; | 4522 | int status; |
3891 | 4523 | ||
3892 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4524 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3893 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4525 | status = decode_compound_hdr(&xdr, &hdr); |
4526 | if (status) | ||
4527 | goto out; | ||
4528 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4529 | if (status) | ||
3894 | goto out; | 4530 | goto out; |
3895 | if ((status = decode_putfh(&xdr)) != 0) | 4531 | if ((status = decode_putfh(&xdr)) != 0) |
3896 | goto out; | 4532 | goto out; |
@@ -3923,7 +4559,11 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr | |||
3923 | int status; | 4559 | int status; |
3924 | 4560 | ||
3925 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4561 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3926 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4562 | status = decode_compound_hdr(&xdr, &hdr); |
4563 | if (status) | ||
4564 | goto out; | ||
4565 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4566 | if (status) | ||
3927 | goto out; | 4567 | goto out; |
3928 | if ((status = decode_putfh(&xdr)) != 0) | 4568 | if ((status = decode_putfh(&xdr)) != 0) |
3929 | goto out; | 4569 | goto out; |
@@ -3963,6 +4603,9 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g | |||
3963 | status = decode_compound_hdr(&xdr, &hdr); | 4603 | status = decode_compound_hdr(&xdr, &hdr); |
3964 | if (status) | 4604 | if (status) |
3965 | goto out; | 4605 | goto out; |
4606 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4607 | if (status) | ||
4608 | goto out; | ||
3966 | status = decode_putfh(&xdr); | 4609 | status = decode_putfh(&xdr); |
3967 | if (status) | 4610 | if (status) |
3968 | goto out; | 4611 | goto out; |
@@ -3979,12 +4622,13 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args | |||
3979 | { | 4622 | { |
3980 | struct xdr_stream xdr; | 4623 | struct xdr_stream xdr; |
3981 | struct compound_hdr hdr = { | 4624 | struct compound_hdr hdr = { |
3982 | .nops = 0, | 4625 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
3983 | }; | 4626 | }; |
3984 | int status; | 4627 | int status; |
3985 | 4628 | ||
3986 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 4629 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
3987 | encode_compound_hdr(&xdr, &hdr); | 4630 | encode_compound_hdr(&xdr, req, &hdr); |
4631 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
3988 | encode_putfh(&xdr, args->fh, &hdr); | 4632 | encode_putfh(&xdr, args->fh, &hdr); |
3989 | status = encode_setacl(&xdr, args, &hdr); | 4633 | status = encode_setacl(&xdr, args, &hdr); |
3990 | encode_nops(&hdr); | 4634 | encode_nops(&hdr); |
@@ -3995,7 +4639,8 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args | |||
3995 | * Decode SETACL response | 4639 | * Decode SETACL response |
3996 | */ | 4640 | */ |
3997 | static int | 4641 | static int |
3998 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res) | 4642 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, |
4643 | struct nfs_setaclres *res) | ||
3999 | { | 4644 | { |
4000 | struct xdr_stream xdr; | 4645 | struct xdr_stream xdr; |
4001 | struct compound_hdr hdr; | 4646 | struct compound_hdr hdr; |
@@ -4005,10 +4650,13 @@ nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res) | |||
4005 | status = decode_compound_hdr(&xdr, &hdr); | 4650 | status = decode_compound_hdr(&xdr, &hdr); |
4006 | if (status) | 4651 | if (status) |
4007 | goto out; | 4652 | goto out; |
4653 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4654 | if (status) | ||
4655 | goto out; | ||
4008 | status = decode_putfh(&xdr); | 4656 | status = decode_putfh(&xdr); |
4009 | if (status) | 4657 | if (status) |
4010 | goto out; | 4658 | goto out; |
4011 | status = decode_setattr(&xdr, res); | 4659 | status = decode_setattr(&xdr); |
4012 | out: | 4660 | out: |
4013 | return status; | 4661 | return status; |
4014 | } | 4662 | } |
@@ -4017,7 +4665,8 @@ out: | |||
4017 | * Decode GETACL response | 4665 | * Decode GETACL response |
4018 | */ | 4666 | */ |
4019 | static int | 4667 | static int |
4020 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len) | 4668 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, |
4669 | struct nfs_getaclres *res) | ||
4021 | { | 4670 | { |
4022 | struct xdr_stream xdr; | 4671 | struct xdr_stream xdr; |
4023 | struct compound_hdr hdr; | 4672 | struct compound_hdr hdr; |
@@ -4027,10 +4676,13 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len) | |||
4027 | status = decode_compound_hdr(&xdr, &hdr); | 4676 | status = decode_compound_hdr(&xdr, &hdr); |
4028 | if (status) | 4677 | if (status) |
4029 | goto out; | 4678 | goto out; |
4679 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4680 | if (status) | ||
4681 | goto out; | ||
4030 | status = decode_putfh(&xdr); | 4682 | status = decode_putfh(&xdr); |
4031 | if (status) | 4683 | if (status) |
4032 | goto out; | 4684 | goto out; |
4033 | status = decode_getacl(&xdr, rqstp, acl_len); | 4685 | status = decode_getacl(&xdr, rqstp, &res->acl_len); |
4034 | 4686 | ||
4035 | out: | 4687 | out: |
4036 | return status; | 4688 | return status; |
@@ -4049,6 +4701,9 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos | |||
4049 | status = decode_compound_hdr(&xdr, &hdr); | 4701 | status = decode_compound_hdr(&xdr, &hdr); |
4050 | if (status) | 4702 | if (status) |
4051 | goto out; | 4703 | goto out; |
4704 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4705 | if (status) | ||
4706 | goto out; | ||
4052 | status = decode_putfh(&xdr); | 4707 | status = decode_putfh(&xdr); |
4053 | if (status) | 4708 | if (status) |
4054 | goto out; | 4709 | goto out; |
@@ -4079,6 +4734,9 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr | |||
4079 | status = decode_compound_hdr(&xdr, &hdr); | 4734 | status = decode_compound_hdr(&xdr, &hdr); |
4080 | if (status) | 4735 | if (status) |
4081 | goto out; | 4736 | goto out; |
4737 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4738 | if (status) | ||
4739 | goto out; | ||
4082 | status = decode_putfh(&xdr); | 4740 | status = decode_putfh(&xdr); |
4083 | if (status) | 4741 | if (status) |
4084 | goto out; | 4742 | goto out; |
@@ -4133,6 +4791,9 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
4133 | status = decode_compound_hdr(&xdr, &hdr); | 4791 | status = decode_compound_hdr(&xdr, &hdr); |
4134 | if (status) | 4792 | if (status) |
4135 | goto out; | 4793 | goto out; |
4794 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4795 | if (status) | ||
4796 | goto out; | ||
4136 | status = decode_putfh(&xdr); | 4797 | status = decode_putfh(&xdr); |
4137 | if (status) | 4798 | if (status) |
4138 | goto out; | 4799 | goto out; |
@@ -4157,10 +4818,13 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se | |||
4157 | status = decode_compound_hdr(&xdr, &hdr); | 4818 | status = decode_compound_hdr(&xdr, &hdr); |
4158 | if (status) | 4819 | if (status) |
4159 | goto out; | 4820 | goto out; |
4821 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4822 | if (status) | ||
4823 | goto out; | ||
4160 | status = decode_putfh(&xdr); | 4824 | status = decode_putfh(&xdr); |
4161 | if (status) | 4825 | if (status) |
4162 | goto out; | 4826 | goto out; |
4163 | status = decode_setattr(&xdr, res); | 4827 | status = decode_setattr(&xdr); |
4164 | if (status) | 4828 | if (status) |
4165 | goto out; | 4829 | goto out; |
4166 | decode_getfattr(&xdr, res->fattr, res->server); | 4830 | decode_getfattr(&xdr, res->fattr, res->server); |
@@ -4181,6 +4845,9 @@ static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_ | |||
4181 | status = decode_compound_hdr(&xdr, &hdr); | 4845 | status = decode_compound_hdr(&xdr, &hdr); |
4182 | if (status) | 4846 | if (status) |
4183 | goto out; | 4847 | goto out; |
4848 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4849 | if (status) | ||
4850 | goto out; | ||
4184 | status = decode_putfh(&xdr); | 4851 | status = decode_putfh(&xdr); |
4185 | if (status) | 4852 | if (status) |
4186 | goto out; | 4853 | goto out; |
@@ -4202,6 +4869,9 @@ static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock | |||
4202 | status = decode_compound_hdr(&xdr, &hdr); | 4869 | status = decode_compound_hdr(&xdr, &hdr); |
4203 | if (status) | 4870 | if (status) |
4204 | goto out; | 4871 | goto out; |
4872 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4873 | if (status) | ||
4874 | goto out; | ||
4205 | status = decode_putfh(&xdr); | 4875 | status = decode_putfh(&xdr); |
4206 | if (status) | 4876 | if (status) |
4207 | goto out; | 4877 | goto out; |
@@ -4223,6 +4893,9 @@ static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock | |||
4223 | status = decode_compound_hdr(&xdr, &hdr); | 4893 | status = decode_compound_hdr(&xdr, &hdr); |
4224 | if (status) | 4894 | if (status) |
4225 | goto out; | 4895 | goto out; |
4896 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4897 | if (status) | ||
4898 | goto out; | ||
4226 | status = decode_putfh(&xdr); | 4899 | status = decode_putfh(&xdr); |
4227 | if (status) | 4900 | if (status) |
4228 | goto out; | 4901 | goto out; |
@@ -4234,7 +4907,8 @@ out: | |||
4234 | /* | 4907 | /* |
4235 | * Decode READLINK response | 4908 | * Decode READLINK response |
4236 | */ | 4909 | */ |
4237 | static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res) | 4910 | static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, |
4911 | struct nfs4_readlink_res *res) | ||
4238 | { | 4912 | { |
4239 | struct xdr_stream xdr; | 4913 | struct xdr_stream xdr; |
4240 | struct compound_hdr hdr; | 4914 | struct compound_hdr hdr; |
@@ -4244,6 +4918,9 @@ static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res) | |||
4244 | status = decode_compound_hdr(&xdr, &hdr); | 4918 | status = decode_compound_hdr(&xdr, &hdr); |
4245 | if (status) | 4919 | if (status) |
4246 | goto out; | 4920 | goto out; |
4921 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4922 | if (status) | ||
4923 | goto out; | ||
4247 | status = decode_putfh(&xdr); | 4924 | status = decode_putfh(&xdr); |
4248 | if (status) | 4925 | if (status) |
4249 | goto out; | 4926 | goto out; |
@@ -4265,6 +4942,9 @@ static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_r | |||
4265 | status = decode_compound_hdr(&xdr, &hdr); | 4942 | status = decode_compound_hdr(&xdr, &hdr); |
4266 | if (status) | 4943 | if (status) |
4267 | goto out; | 4944 | goto out; |
4945 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4946 | if (status) | ||
4947 | goto out; | ||
4268 | status = decode_putfh(&xdr); | 4948 | status = decode_putfh(&xdr); |
4269 | if (status) | 4949 | if (status) |
4270 | goto out; | 4950 | goto out; |
@@ -4286,6 +4966,9 @@ static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readr | |||
4286 | status = decode_compound_hdr(&xdr, &hdr); | 4966 | status = decode_compound_hdr(&xdr, &hdr); |
4287 | if (status) | 4967 | if (status) |
4288 | goto out; | 4968 | goto out; |
4969 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4970 | if (status) | ||
4971 | goto out; | ||
4289 | status = decode_putfh(&xdr); | 4972 | status = decode_putfh(&xdr); |
4290 | if (status) | 4973 | if (status) |
4291 | goto out; | 4974 | goto out; |
@@ -4309,6 +4992,9 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writ | |||
4309 | status = decode_compound_hdr(&xdr, &hdr); | 4992 | status = decode_compound_hdr(&xdr, &hdr); |
4310 | if (status) | 4993 | if (status) |
4311 | goto out; | 4994 | goto out; |
4995 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4996 | if (status) | ||
4997 | goto out; | ||
4312 | status = decode_putfh(&xdr); | 4998 | status = decode_putfh(&xdr); |
4313 | if (status) | 4999 | if (status) |
4314 | goto out; | 5000 | goto out; |
@@ -4335,6 +5021,9 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_wri | |||
4335 | status = decode_compound_hdr(&xdr, &hdr); | 5021 | status = decode_compound_hdr(&xdr, &hdr); |
4336 | if (status) | 5022 | if (status) |
4337 | goto out; | 5023 | goto out; |
5024 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
5025 | if (status) | ||
5026 | goto out; | ||
4338 | status = decode_putfh(&xdr); | 5027 | status = decode_putfh(&xdr); |
4339 | if (status) | 5028 | if (status) |
4340 | goto out; | 5029 | goto out; |
@@ -4349,7 +5038,8 @@ out: | |||
4349 | /* | 5038 | /* |
4350 | * FSINFO request | 5039 | * FSINFO request |
4351 | */ | 5040 | */ |
4352 | static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo) | 5041 | static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, |
5042 | struct nfs4_fsinfo_res *res) | ||
4353 | { | 5043 | { |
4354 | struct xdr_stream xdr; | 5044 | struct xdr_stream xdr; |
4355 | struct compound_hdr hdr; | 5045 | struct compound_hdr hdr; |
@@ -4358,16 +5048,19 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinf | |||
4358 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5048 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4359 | status = decode_compound_hdr(&xdr, &hdr); | 5049 | status = decode_compound_hdr(&xdr, &hdr); |
4360 | if (!status) | 5050 | if (!status) |
5051 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5052 | if (!status) | ||
4361 | status = decode_putfh(&xdr); | 5053 | status = decode_putfh(&xdr); |
4362 | if (!status) | 5054 | if (!status) |
4363 | status = decode_fsinfo(&xdr, fsinfo); | 5055 | status = decode_fsinfo(&xdr, res->fsinfo); |
4364 | return status; | 5056 | return status; |
4365 | } | 5057 | } |
4366 | 5058 | ||
4367 | /* | 5059 | /* |
4368 | * PATHCONF request | 5060 | * PATHCONF request |
4369 | */ | 5061 | */ |
4370 | static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf) | 5062 | static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, |
5063 | struct nfs4_pathconf_res *res) | ||
4371 | { | 5064 | { |
4372 | struct xdr_stream xdr; | 5065 | struct xdr_stream xdr; |
4373 | struct compound_hdr hdr; | 5066 | struct compound_hdr hdr; |
@@ -4376,16 +5069,19 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pat | |||
4376 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5069 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4377 | status = decode_compound_hdr(&xdr, &hdr); | 5070 | status = decode_compound_hdr(&xdr, &hdr); |
4378 | if (!status) | 5071 | if (!status) |
5072 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5073 | if (!status) | ||
4379 | status = decode_putfh(&xdr); | 5074 | status = decode_putfh(&xdr); |
4380 | if (!status) | 5075 | if (!status) |
4381 | status = decode_pathconf(&xdr, pathconf); | 5076 | status = decode_pathconf(&xdr, res->pathconf); |
4382 | return status; | 5077 | return status; |
4383 | } | 5078 | } |
4384 | 5079 | ||
4385 | /* | 5080 | /* |
4386 | * STATFS request | 5081 | * STATFS request |
4387 | */ | 5082 | */ |
4388 | static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat) | 5083 | static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, |
5084 | struct nfs4_statfs_res *res) | ||
4389 | { | 5085 | { |
4390 | struct xdr_stream xdr; | 5086 | struct xdr_stream xdr; |
4391 | struct compound_hdr hdr; | 5087 | struct compound_hdr hdr; |
@@ -4394,9 +5090,11 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fssta | |||
4394 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5090 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4395 | status = decode_compound_hdr(&xdr, &hdr); | 5091 | status = decode_compound_hdr(&xdr, &hdr); |
4396 | if (!status) | 5092 | if (!status) |
5093 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5094 | if (!status) | ||
4397 | status = decode_putfh(&xdr); | 5095 | status = decode_putfh(&xdr); |
4398 | if (!status) | 5096 | if (!status) |
4399 | status = decode_statfs(&xdr, fsstat); | 5097 | status = decode_statfs(&xdr, res->fsstat); |
4400 | return status; | 5098 | return status; |
4401 | } | 5099 | } |
4402 | 5100 | ||
@@ -4410,7 +5108,11 @@ static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
4410 | int status; | 5108 | int status; |
4411 | 5109 | ||
4412 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5110 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4413 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 5111 | status = decode_compound_hdr(&xdr, &hdr); |
5112 | if (status) | ||
5113 | goto out; | ||
5114 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5115 | if (status) | ||
4414 | goto out; | 5116 | goto out; |
4415 | if ((status = decode_putfh(&xdr)) != 0) | 5117 | if ((status = decode_putfh(&xdr)) != 0) |
4416 | goto out; | 5118 | goto out; |
@@ -4483,7 +5185,10 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
4483 | 5185 | ||
4484 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 5186 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
4485 | status = decode_compound_hdr(&xdr, &hdr); | 5187 | status = decode_compound_hdr(&xdr, &hdr); |
4486 | if (status != 0) | 5188 | if (status) |
5189 | goto out; | ||
5190 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
5191 | if (status) | ||
4487 | goto out; | 5192 | goto out; |
4488 | status = decode_putfh(&xdr); | 5193 | status = decode_putfh(&xdr); |
4489 | if (status != 0) | 5194 | if (status != 0) |
@@ -4497,7 +5202,8 @@ out: | |||
4497 | /* | 5202 | /* |
4498 | * FS_LOCATIONS request | 5203 | * FS_LOCATIONS request |
4499 | */ | 5204 | */ |
4500 | static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations *res) | 5205 | static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, |
5206 | struct nfs4_fs_locations_res *res) | ||
4501 | { | 5207 | { |
4502 | struct xdr_stream xdr; | 5208 | struct xdr_stream xdr; |
4503 | struct compound_hdr hdr; | 5209 | struct compound_hdr hdr; |
@@ -4505,18 +5211,113 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
4505 | 5211 | ||
4506 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5212 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4507 | status = decode_compound_hdr(&xdr, &hdr); | 5213 | status = decode_compound_hdr(&xdr, &hdr); |
4508 | if (status != 0) | 5214 | if (status) |
5215 | goto out; | ||
5216 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5217 | if (status) | ||
4509 | goto out; | 5218 | goto out; |
4510 | if ((status = decode_putfh(&xdr)) != 0) | 5219 | if ((status = decode_putfh(&xdr)) != 0) |
4511 | goto out; | 5220 | goto out; |
4512 | if ((status = decode_lookup(&xdr)) != 0) | 5221 | if ((status = decode_lookup(&xdr)) != 0) |
4513 | goto out; | 5222 | goto out; |
4514 | xdr_enter_page(&xdr, PAGE_SIZE); | 5223 | xdr_enter_page(&xdr, PAGE_SIZE); |
4515 | status = decode_getfattr(&xdr, &res->fattr, res->server); | 5224 | status = decode_getfattr(&xdr, &res->fs_locations->fattr, |
5225 | res->fs_locations->server); | ||
4516 | out: | 5226 | out: |
4517 | return status; | 5227 | return status; |
4518 | } | 5228 | } |
4519 | 5229 | ||
5230 | #if defined(CONFIG_NFS_V4_1) | ||
5231 | /* | ||
5232 | * EXCHANGE_ID request | ||
5233 | */ | ||
5234 | static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p, | ||
5235 | void *res) | ||
5236 | { | ||
5237 | struct xdr_stream xdr; | ||
5238 | struct compound_hdr hdr; | ||
5239 | int status; | ||
5240 | |||
5241 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5242 | status = decode_compound_hdr(&xdr, &hdr); | ||
5243 | if (!status) | ||
5244 | status = decode_exchange_id(&xdr, res); | ||
5245 | return status; | ||
5246 | } | ||
5247 | |||
5248 | /* | ||
5249 | * a CREATE_SESSION request | ||
5250 | */ | ||
5251 | static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p, | ||
5252 | struct nfs41_create_session_res *res) | ||
5253 | { | ||
5254 | struct xdr_stream xdr; | ||
5255 | struct compound_hdr hdr; | ||
5256 | int status; | ||
5257 | |||
5258 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5259 | status = decode_compound_hdr(&xdr, &hdr); | ||
5260 | if (!status) | ||
5261 | status = decode_create_session(&xdr, res); | ||
5262 | return status; | ||
5263 | } | ||
5264 | |||
5265 | /* | ||
5266 | * a DESTROY_SESSION request | ||
5267 | */ | ||
5268 | static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p, | ||
5269 | void *dummy) | ||
5270 | { | ||
5271 | struct xdr_stream xdr; | ||
5272 | struct compound_hdr hdr; | ||
5273 | int status; | ||
5274 | |||
5275 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5276 | status = decode_compound_hdr(&xdr, &hdr); | ||
5277 | if (!status) | ||
5278 | status = decode_destroy_session(&xdr, dummy); | ||
5279 | return status; | ||
5280 | } | ||
5281 | |||
5282 | /* | ||
5283 | * a SEQUENCE request | ||
5284 | */ | ||
5285 | static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p, | ||
5286 | struct nfs4_sequence_res *res) | ||
5287 | { | ||
5288 | struct xdr_stream xdr; | ||
5289 | struct compound_hdr hdr; | ||
5290 | int status; | ||
5291 | |||
5292 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5293 | status = decode_compound_hdr(&xdr, &hdr); | ||
5294 | if (!status) | ||
5295 | status = decode_sequence(&xdr, res, rqstp); | ||
5296 | return status; | ||
5297 | } | ||
5298 | |||
5299 | /* | ||
5300 | * a GET_LEASE_TIME request | ||
5301 | */ | ||
5302 | static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p, | ||
5303 | struct nfs4_get_lease_time_res *res) | ||
5304 | { | ||
5305 | struct xdr_stream xdr; | ||
5306 | struct compound_hdr hdr; | ||
5307 | int status; | ||
5308 | |||
5309 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5310 | status = decode_compound_hdr(&xdr, &hdr); | ||
5311 | if (!status) | ||
5312 | status = decode_sequence(&xdr, &res->lr_seq_res, rqstp); | ||
5313 | if (!status) | ||
5314 | status = decode_putrootfh(&xdr); | ||
5315 | if (!status) | ||
5316 | status = decode_fsinfo(&xdr, res->lr_fsinfo); | ||
5317 | return status; | ||
5318 | } | ||
5319 | #endif /* CONFIG_NFS_V4_1 */ | ||
5320 | |||
4520 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | 5321 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) |
4521 | { | 5322 | { |
4522 | uint32_t bitmap[2] = {0}; | 5323 | uint32_t bitmap[2] = {0}; |
@@ -4686,6 +5487,13 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
4686 | PROC(GETACL, enc_getacl, dec_getacl), | 5487 | PROC(GETACL, enc_getacl, dec_getacl), |
4687 | PROC(SETACL, enc_setacl, dec_setacl), | 5488 | PROC(SETACL, enc_setacl, dec_setacl), |
4688 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), | 5489 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), |
5490 | #if defined(CONFIG_NFS_V4_1) | ||
5491 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | ||
5492 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), | ||
5493 | PROC(DESTROY_SESSION, enc_destroy_session, dec_destroy_session), | ||
5494 | PROC(SEQUENCE, enc_sequence, dec_sequence), | ||
5495 | PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time), | ||
5496 | #endif /* CONFIG_NFS_V4_1 */ | ||
4689 | }; | 5497 | }; |
4690 | 5498 | ||
4691 | struct rpc_version nfs_version4 = { | 5499 | struct rpc_version nfs_version4 = { |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index e3ed5908820b..8c55b27c0de4 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
@@ -92,6 +92,9 @@ | |||
92 | #undef NFSROOT_DEBUG | 92 | #undef NFSROOT_DEBUG |
93 | #define NFSDBG_FACILITY NFSDBG_ROOT | 93 | #define NFSDBG_FACILITY NFSDBG_ROOT |
94 | 94 | ||
95 | /* Default port to use if server is not running a portmapper */ | ||
96 | #define NFS_MNT_PORT 627 | ||
97 | |||
95 | /* Default path we try to mount. "%s" gets replaced by our IP address */ | 98 | /* Default path we try to mount. "%s" gets replaced by our IP address */ |
96 | #define NFS_ROOT "/tftpboot/%s" | 99 | #define NFS_ROOT "/tftpboot/%s" |
97 | 100 | ||
@@ -487,6 +490,7 @@ static int __init root_nfs_get_handle(void) | |||
487 | { | 490 | { |
488 | struct nfs_fh fh; | 491 | struct nfs_fh fh; |
489 | struct sockaddr_in sin; | 492 | struct sockaddr_in sin; |
493 | unsigned int auth_flav_len = 0; | ||
490 | struct nfs_mount_request request = { | 494 | struct nfs_mount_request request = { |
491 | .sap = (struct sockaddr *)&sin, | 495 | .sap = (struct sockaddr *)&sin, |
492 | .salen = sizeof(sin), | 496 | .salen = sizeof(sin), |
@@ -496,6 +500,7 @@ static int __init root_nfs_get_handle(void) | |||
496 | .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? | 500 | .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? |
497 | XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, | 501 | XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, |
498 | .fh = &fh, | 502 | .fh = &fh, |
503 | .auth_flav_len = &auth_flav_len, | ||
499 | }; | 504 | }; |
500 | int status; | 505 | int status; |
501 | 506 | ||
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 4ace3c50a8eb..96c4ebfa46f4 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <asm/system.h> | 23 | #include <asm/system.h> |
24 | 24 | ||
25 | #include "nfs4_fs.h" | ||
25 | #include "internal.h" | 26 | #include "internal.h" |
26 | #include "iostat.h" | 27 | #include "iostat.h" |
27 | #include "fscache.h" | 28 | #include "fscache.h" |
@@ -46,6 +47,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | |||
46 | memset(p, 0, sizeof(*p)); | 47 | memset(p, 0, sizeof(*p)); |
47 | INIT_LIST_HEAD(&p->pages); | 48 | INIT_LIST_HEAD(&p->pages); |
48 | p->npages = pagecount; | 49 | p->npages = pagecount; |
50 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
49 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 51 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
50 | p->pagevec = p->page_array; | 52 | p->pagevec = p->page_array; |
51 | else { | 53 | else { |
@@ -357,19 +359,25 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data | |||
357 | struct nfs_readres *resp = &data->res; | 359 | struct nfs_readres *resp = &data->res; |
358 | 360 | ||
359 | if (resp->eof || resp->count == argp->count) | 361 | if (resp->eof || resp->count == argp->count) |
360 | return; | 362 | goto out; |
361 | 363 | ||
362 | /* This is a short read! */ | 364 | /* This is a short read! */ |
363 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | 365 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); |
364 | /* Has the server at least made some progress? */ | 366 | /* Has the server at least made some progress? */ |
365 | if (resp->count == 0) | 367 | if (resp->count == 0) |
366 | return; | 368 | goto out; |
367 | 369 | ||
368 | /* Yes, so retry the read at the end of the data */ | 370 | /* Yes, so retry the read at the end of the data */ |
369 | argp->offset += resp->count; | 371 | argp->offset += resp->count; |
370 | argp->pgbase += resp->count; | 372 | argp->pgbase += resp->count; |
371 | argp->count -= resp->count; | 373 | argp->count -= resp->count; |
372 | rpc_restart_call(task); | 374 | nfs4_restart_rpc(task, NFS_SERVER(data->inode)->nfs_client); |
375 | return; | ||
376 | out: | ||
377 | nfs4_sequence_free_slot(NFS_SERVER(data->inode)->nfs_client, | ||
378 | &data->res.seq_res); | ||
379 | return; | ||
380 | |||
373 | } | 381 | } |
374 | 382 | ||
375 | /* | 383 | /* |
@@ -406,7 +414,23 @@ static void nfs_readpage_release_partial(void *calldata) | |||
406 | nfs_readdata_release(calldata); | 414 | nfs_readdata_release(calldata); |
407 | } | 415 | } |
408 | 416 | ||
417 | #if defined(CONFIG_NFS_V4_1) | ||
418 | void nfs_read_prepare(struct rpc_task *task, void *calldata) | ||
419 | { | ||
420 | struct nfs_read_data *data = calldata; | ||
421 | |||
422 | if (nfs4_setup_sequence(NFS_SERVER(data->inode)->nfs_client, | ||
423 | &data->args.seq_args, &data->res.seq_res, | ||
424 | 0, task)) | ||
425 | return; | ||
426 | rpc_call_start(task); | ||
427 | } | ||
428 | #endif /* CONFIG_NFS_V4_1 */ | ||
429 | |||
409 | static const struct rpc_call_ops nfs_read_partial_ops = { | 430 | static const struct rpc_call_ops nfs_read_partial_ops = { |
431 | #if defined(CONFIG_NFS_V4_1) | ||
432 | .rpc_call_prepare = nfs_read_prepare, | ||
433 | #endif /* CONFIG_NFS_V4_1 */ | ||
410 | .rpc_call_done = nfs_readpage_result_partial, | 434 | .rpc_call_done = nfs_readpage_result_partial, |
411 | .rpc_release = nfs_readpage_release_partial, | 435 | .rpc_release = nfs_readpage_release_partial, |
412 | }; | 436 | }; |
@@ -470,6 +494,9 @@ static void nfs_readpage_release_full(void *calldata) | |||
470 | } | 494 | } |
471 | 495 | ||
472 | static const struct rpc_call_ops nfs_read_full_ops = { | 496 | static const struct rpc_call_ops nfs_read_full_ops = { |
497 | #if defined(CONFIG_NFS_V4_1) | ||
498 | .rpc_call_prepare = nfs_read_prepare, | ||
499 | #endif /* CONFIG_NFS_V4_1 */ | ||
473 | .rpc_call_done = nfs_readpage_result_full, | 500 | .rpc_call_done = nfs_readpage_result_full, |
474 | .rpc_release = nfs_readpage_release_full, | 501 | .rpc_release = nfs_readpage_release_full, |
475 | }; | 502 | }; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 26127b69a275..0b4cbdc60abd 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -42,6 +42,8 @@ | |||
42 | #include <linux/smp_lock.h> | 42 | #include <linux/smp_lock.h> |
43 | #include <linux/seq_file.h> | 43 | #include <linux/seq_file.h> |
44 | #include <linux/mount.h> | 44 | #include <linux/mount.h> |
45 | #include <linux/mnt_namespace.h> | ||
46 | #include <linux/namei.h> | ||
45 | #include <linux/nfs_idmap.h> | 47 | #include <linux/nfs_idmap.h> |
46 | #include <linux/vfs.h> | 48 | #include <linux/vfs.h> |
47 | #include <linux/inet.h> | 49 | #include <linux/inet.h> |
@@ -90,6 +92,7 @@ enum { | |||
90 | Opt_mountport, | 92 | Opt_mountport, |
91 | Opt_mountvers, | 93 | Opt_mountvers, |
92 | Opt_nfsvers, | 94 | Opt_nfsvers, |
95 | Opt_minorversion, | ||
93 | 96 | ||
94 | /* Mount options that take string arguments */ | 97 | /* Mount options that take string arguments */ |
95 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, | 98 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
@@ -139,22 +142,23 @@ static const match_table_t nfs_mount_option_tokens = { | |||
139 | { Opt_fscache_uniq, "fsc=%s" }, | 142 | { Opt_fscache_uniq, "fsc=%s" }, |
140 | { Opt_nofscache, "nofsc" }, | 143 | { Opt_nofscache, "nofsc" }, |
141 | 144 | ||
142 | { Opt_port, "port=%u" }, | 145 | { Opt_port, "port=%s" }, |
143 | { Opt_rsize, "rsize=%u" }, | 146 | { Opt_rsize, "rsize=%s" }, |
144 | { Opt_wsize, "wsize=%u" }, | 147 | { Opt_wsize, "wsize=%s" }, |
145 | { Opt_bsize, "bsize=%u" }, | 148 | { Opt_bsize, "bsize=%s" }, |
146 | { Opt_timeo, "timeo=%u" }, | 149 | { Opt_timeo, "timeo=%s" }, |
147 | { Opt_retrans, "retrans=%u" }, | 150 | { Opt_retrans, "retrans=%s" }, |
148 | { Opt_acregmin, "acregmin=%u" }, | 151 | { Opt_acregmin, "acregmin=%s" }, |
149 | { Opt_acregmax, "acregmax=%u" }, | 152 | { Opt_acregmax, "acregmax=%s" }, |
150 | { Opt_acdirmin, "acdirmin=%u" }, | 153 | { Opt_acdirmin, "acdirmin=%s" }, |
151 | { Opt_acdirmax, "acdirmax=%u" }, | 154 | { Opt_acdirmax, "acdirmax=%s" }, |
152 | { Opt_actimeo, "actimeo=%u" }, | 155 | { Opt_actimeo, "actimeo=%s" }, |
153 | { Opt_namelen, "namlen=%u" }, | 156 | { Opt_namelen, "namlen=%s" }, |
154 | { Opt_mountport, "mountport=%u" }, | 157 | { Opt_mountport, "mountport=%s" }, |
155 | { Opt_mountvers, "mountvers=%u" }, | 158 | { Opt_mountvers, "mountvers=%s" }, |
156 | { Opt_nfsvers, "nfsvers=%u" }, | 159 | { Opt_nfsvers, "nfsvers=%s" }, |
157 | { Opt_nfsvers, "vers=%u" }, | 160 | { Opt_nfsvers, "vers=%s" }, |
161 | { Opt_minorversion, "minorversion=%u" }, | ||
158 | 162 | ||
159 | { Opt_sec, "sec=%s" }, | 163 | { Opt_sec, "sec=%s" }, |
160 | { Opt_proto, "proto=%s" }, | 164 | { Opt_proto, "proto=%s" }, |
@@ -270,10 +274,14 @@ static const struct super_operations nfs_sops = { | |||
270 | #ifdef CONFIG_NFS_V4 | 274 | #ifdef CONFIG_NFS_V4 |
271 | static int nfs4_get_sb(struct file_system_type *fs_type, | 275 | static int nfs4_get_sb(struct file_system_type *fs_type, |
272 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 276 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
277 | static int nfs4_remote_get_sb(struct file_system_type *fs_type, | ||
278 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | ||
273 | static int nfs4_xdev_get_sb(struct file_system_type *fs_type, | 279 | static int nfs4_xdev_get_sb(struct file_system_type *fs_type, |
274 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 280 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
275 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, | 281 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, |
276 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 282 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
283 | static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | ||
284 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | ||
277 | static void nfs4_kill_super(struct super_block *sb); | 285 | static void nfs4_kill_super(struct super_block *sb); |
278 | 286 | ||
279 | static struct file_system_type nfs4_fs_type = { | 287 | static struct file_system_type nfs4_fs_type = { |
@@ -284,6 +292,14 @@ static struct file_system_type nfs4_fs_type = { | |||
284 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 292 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
285 | }; | 293 | }; |
286 | 294 | ||
295 | static struct file_system_type nfs4_remote_fs_type = { | ||
296 | .owner = THIS_MODULE, | ||
297 | .name = "nfs4", | ||
298 | .get_sb = nfs4_remote_get_sb, | ||
299 | .kill_sb = nfs4_kill_super, | ||
300 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
301 | }; | ||
302 | |||
287 | struct file_system_type nfs4_xdev_fs_type = { | 303 | struct file_system_type nfs4_xdev_fs_type = { |
288 | .owner = THIS_MODULE, | 304 | .owner = THIS_MODULE, |
289 | .name = "nfs4", | 305 | .name = "nfs4", |
@@ -292,6 +308,14 @@ struct file_system_type nfs4_xdev_fs_type = { | |||
292 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 308 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
293 | }; | 309 | }; |
294 | 310 | ||
311 | static struct file_system_type nfs4_remote_referral_fs_type = { | ||
312 | .owner = THIS_MODULE, | ||
313 | .name = "nfs4", | ||
314 | .get_sb = nfs4_remote_referral_get_sb, | ||
315 | .kill_sb = nfs4_kill_super, | ||
316 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
317 | }; | ||
318 | |||
295 | struct file_system_type nfs4_referral_fs_type = { | 319 | struct file_system_type nfs4_referral_fs_type = { |
296 | .owner = THIS_MODULE, | 320 | .owner = THIS_MODULE, |
297 | .name = "nfs4", | 321 | .name = "nfs4", |
@@ -514,7 +538,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
514 | const char *nostr; | 538 | const char *nostr; |
515 | } nfs_info[] = { | 539 | } nfs_info[] = { |
516 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, | 540 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, |
517 | { NFS_MOUNT_INTR, ",intr", ",nointr" }, | ||
518 | { NFS_MOUNT_POSIX, ",posix", "" }, | 541 | { NFS_MOUNT_POSIX, ",posix", "" }, |
519 | { NFS_MOUNT_NOCTO, ",nocto", "" }, | 542 | { NFS_MOUNT_NOCTO, ",nocto", "" }, |
520 | { NFS_MOUNT_NOAC, ",noac", "" }, | 543 | { NFS_MOUNT_NOAC, ",noac", "" }, |
@@ -943,11 +966,6 @@ static int nfs_parse_security_flavors(char *value, | |||
943 | return 1; | 966 | return 1; |
944 | } | 967 | } |
945 | 968 | ||
946 | static void nfs_parse_invalid_value(const char *option) | ||
947 | { | ||
948 | dfprintk(MOUNT, "NFS: bad value specified for %s option\n", option); | ||
949 | } | ||
950 | |||
951 | /* | 969 | /* |
952 | * Error-check and convert a string of mount options from user space into | 970 | * Error-check and convert a string of mount options from user space into |
953 | * a data structure. The whole mount string is processed; bad options are | 971 | * a data structure. The whole mount string is processed; bad options are |
@@ -958,7 +976,7 @@ static int nfs_parse_mount_options(char *raw, | |||
958 | struct nfs_parsed_mount_data *mnt) | 976 | struct nfs_parsed_mount_data *mnt) |
959 | { | 977 | { |
960 | char *p, *string, *secdata; | 978 | char *p, *string, *secdata; |
961 | int rc, sloppy = 0, errors = 0; | 979 | int rc, sloppy = 0, invalid_option = 0; |
962 | 980 | ||
963 | if (!raw) { | 981 | if (!raw) { |
964 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | 982 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); |
@@ -982,7 +1000,9 @@ static int nfs_parse_mount_options(char *raw, | |||
982 | 1000 | ||
983 | while ((p = strsep(&raw, ",")) != NULL) { | 1001 | while ((p = strsep(&raw, ",")) != NULL) { |
984 | substring_t args[MAX_OPT_ARGS]; | 1002 | substring_t args[MAX_OPT_ARGS]; |
985 | int option, token; | 1003 | unsigned long option; |
1004 | int int_option; | ||
1005 | int token; | ||
986 | 1006 | ||
987 | if (!*p) | 1007 | if (!*p) |
988 | continue; | 1008 | continue; |
@@ -1091,114 +1111,156 @@ static int nfs_parse_mount_options(char *raw, | |||
1091 | * options that take numeric values | 1111 | * options that take numeric values |
1092 | */ | 1112 | */ |
1093 | case Opt_port: | 1113 | case Opt_port: |
1094 | if (match_int(args, &option) || | 1114 | string = match_strdup(args); |
1095 | option < 0 || option > USHORT_MAX) { | 1115 | if (string == NULL) |
1096 | errors++; | 1116 | goto out_nomem; |
1097 | nfs_parse_invalid_value("port"); | 1117 | rc = strict_strtoul(string, 10, &option); |
1098 | } else | 1118 | kfree(string); |
1099 | mnt->nfs_server.port = option; | 1119 | if (rc != 0 || option > USHORT_MAX) |
1120 | goto out_invalid_value; | ||
1121 | mnt->nfs_server.port = option; | ||
1100 | break; | 1122 | break; |
1101 | case Opt_rsize: | 1123 | case Opt_rsize: |
1102 | if (match_int(args, &option) || option < 0) { | 1124 | string = match_strdup(args); |
1103 | errors++; | 1125 | if (string == NULL) |
1104 | nfs_parse_invalid_value("rsize"); | 1126 | goto out_nomem; |
1105 | } else | 1127 | rc = strict_strtoul(string, 10, &option); |
1106 | mnt->rsize = option; | 1128 | kfree(string); |
1129 | if (rc != 0) | ||
1130 | goto out_invalid_value; | ||
1131 | mnt->rsize = option; | ||
1107 | break; | 1132 | break; |
1108 | case Opt_wsize: | 1133 | case Opt_wsize: |
1109 | if (match_int(args, &option) || option < 0) { | 1134 | string = match_strdup(args); |
1110 | errors++; | 1135 | if (string == NULL) |
1111 | nfs_parse_invalid_value("wsize"); | 1136 | goto out_nomem; |
1112 | } else | 1137 | rc = strict_strtoul(string, 10, &option); |
1113 | mnt->wsize = option; | 1138 | kfree(string); |
1139 | if (rc != 0) | ||
1140 | goto out_invalid_value; | ||
1141 | mnt->wsize = option; | ||
1114 | break; | 1142 | break; |
1115 | case Opt_bsize: | 1143 | case Opt_bsize: |
1116 | if (match_int(args, &option) || option < 0) { | 1144 | string = match_strdup(args); |
1117 | errors++; | 1145 | if (string == NULL) |
1118 | nfs_parse_invalid_value("bsize"); | 1146 | goto out_nomem; |
1119 | } else | 1147 | rc = strict_strtoul(string, 10, &option); |
1120 | mnt->bsize = option; | 1148 | kfree(string); |
1149 | if (rc != 0) | ||
1150 | goto out_invalid_value; | ||
1151 | mnt->bsize = option; | ||
1121 | break; | 1152 | break; |
1122 | case Opt_timeo: | 1153 | case Opt_timeo: |
1123 | if (match_int(args, &option) || option <= 0) { | 1154 | string = match_strdup(args); |
1124 | errors++; | 1155 | if (string == NULL) |
1125 | nfs_parse_invalid_value("timeo"); | 1156 | goto out_nomem; |
1126 | } else | 1157 | rc = strict_strtoul(string, 10, &option); |
1127 | mnt->timeo = option; | 1158 | kfree(string); |
1159 | if (rc != 0 || option == 0) | ||
1160 | goto out_invalid_value; | ||
1161 | mnt->timeo = option; | ||
1128 | break; | 1162 | break; |
1129 | case Opt_retrans: | 1163 | case Opt_retrans: |
1130 | if (match_int(args, &option) || option <= 0) { | 1164 | string = match_strdup(args); |
1131 | errors++; | 1165 | if (string == NULL) |
1132 | nfs_parse_invalid_value("retrans"); | 1166 | goto out_nomem; |
1133 | } else | 1167 | rc = strict_strtoul(string, 10, &option); |
1134 | mnt->retrans = option; | 1168 | kfree(string); |
1169 | if (rc != 0 || option == 0) | ||
1170 | goto out_invalid_value; | ||
1171 | mnt->retrans = option; | ||
1135 | break; | 1172 | break; |
1136 | case Opt_acregmin: | 1173 | case Opt_acregmin: |
1137 | if (match_int(args, &option) || option < 0) { | 1174 | string = match_strdup(args); |
1138 | errors++; | 1175 | if (string == NULL) |
1139 | nfs_parse_invalid_value("acregmin"); | 1176 | goto out_nomem; |
1140 | } else | 1177 | rc = strict_strtoul(string, 10, &option); |
1141 | mnt->acregmin = option; | 1178 | kfree(string); |
1179 | if (rc != 0) | ||
1180 | goto out_invalid_value; | ||
1181 | mnt->acregmin = option; | ||
1142 | break; | 1182 | break; |
1143 | case Opt_acregmax: | 1183 | case Opt_acregmax: |
1144 | if (match_int(args, &option) || option < 0) { | 1184 | string = match_strdup(args); |
1145 | errors++; | 1185 | if (string == NULL) |
1146 | nfs_parse_invalid_value("acregmax"); | 1186 | goto out_nomem; |
1147 | } else | 1187 | rc = strict_strtoul(string, 10, &option); |
1148 | mnt->acregmax = option; | 1188 | kfree(string); |
1189 | if (rc != 0) | ||
1190 | goto out_invalid_value; | ||
1191 | mnt->acregmax = option; | ||
1149 | break; | 1192 | break; |
1150 | case Opt_acdirmin: | 1193 | case Opt_acdirmin: |
1151 | if (match_int(args, &option) || option < 0) { | 1194 | string = match_strdup(args); |
1152 | errors++; | 1195 | if (string == NULL) |
1153 | nfs_parse_invalid_value("acdirmin"); | 1196 | goto out_nomem; |
1154 | } else | 1197 | rc = strict_strtoul(string, 10, &option); |
1155 | mnt->acdirmin = option; | 1198 | kfree(string); |
1199 | if (rc != 0) | ||
1200 | goto out_invalid_value; | ||
1201 | mnt->acdirmin = option; | ||
1156 | break; | 1202 | break; |
1157 | case Opt_acdirmax: | 1203 | case Opt_acdirmax: |
1158 | if (match_int(args, &option) || option < 0) { | 1204 | string = match_strdup(args); |
1159 | errors++; | 1205 | if (string == NULL) |
1160 | nfs_parse_invalid_value("acdirmax"); | 1206 | goto out_nomem; |
1161 | } else | 1207 | rc = strict_strtoul(string, 10, &option); |
1162 | mnt->acdirmax = option; | 1208 | kfree(string); |
1209 | if (rc != 0) | ||
1210 | goto out_invalid_value; | ||
1211 | mnt->acdirmax = option; | ||
1163 | break; | 1212 | break; |
1164 | case Opt_actimeo: | 1213 | case Opt_actimeo: |
1165 | if (match_int(args, &option) || option < 0) { | 1214 | string = match_strdup(args); |
1166 | errors++; | 1215 | if (string == NULL) |
1167 | nfs_parse_invalid_value("actimeo"); | 1216 | goto out_nomem; |
1168 | } else | 1217 | rc = strict_strtoul(string, 10, &option); |
1169 | mnt->acregmin = mnt->acregmax = | 1218 | kfree(string); |
1170 | mnt->acdirmin = mnt->acdirmax = option; | 1219 | if (rc != 0) |
1220 | goto out_invalid_value; | ||
1221 | mnt->acregmin = mnt->acregmax = | ||
1222 | mnt->acdirmin = mnt->acdirmax = option; | ||
1171 | break; | 1223 | break; |
1172 | case Opt_namelen: | 1224 | case Opt_namelen: |
1173 | if (match_int(args, &option) || option < 0) { | 1225 | string = match_strdup(args); |
1174 | errors++; | 1226 | if (string == NULL) |
1175 | nfs_parse_invalid_value("namlen"); | 1227 | goto out_nomem; |
1176 | } else | 1228 | rc = strict_strtoul(string, 10, &option); |
1177 | mnt->namlen = option; | 1229 | kfree(string); |
1230 | if (rc != 0) | ||
1231 | goto out_invalid_value; | ||
1232 | mnt->namlen = option; | ||
1178 | break; | 1233 | break; |
1179 | case Opt_mountport: | 1234 | case Opt_mountport: |
1180 | if (match_int(args, &option) || | 1235 | string = match_strdup(args); |
1181 | option < 0 || option > USHORT_MAX) { | 1236 | if (string == NULL) |
1182 | errors++; | 1237 | goto out_nomem; |
1183 | nfs_parse_invalid_value("mountport"); | 1238 | rc = strict_strtoul(string, 10, &option); |
1184 | } else | 1239 | kfree(string); |
1185 | mnt->mount_server.port = option; | 1240 | if (rc != 0 || option > USHORT_MAX) |
1241 | goto out_invalid_value; | ||
1242 | mnt->mount_server.port = option; | ||
1186 | break; | 1243 | break; |
1187 | case Opt_mountvers: | 1244 | case Opt_mountvers: |
1188 | if (match_int(args, &option) || | 1245 | string = match_strdup(args); |
1246 | if (string == NULL) | ||
1247 | goto out_nomem; | ||
1248 | rc = strict_strtoul(string, 10, &option); | ||
1249 | kfree(string); | ||
1250 | if (rc != 0 || | ||
1189 | option < NFS_MNT_VERSION || | 1251 | option < NFS_MNT_VERSION || |
1190 | option > NFS_MNT3_VERSION) { | 1252 | option > NFS_MNT3_VERSION) |
1191 | errors++; | 1253 | goto out_invalid_value; |
1192 | nfs_parse_invalid_value("mountvers"); | 1254 | mnt->mount_server.version = option; |
1193 | } else | ||
1194 | mnt->mount_server.version = option; | ||
1195 | break; | 1255 | break; |
1196 | case Opt_nfsvers: | 1256 | case Opt_nfsvers: |
1197 | if (match_int(args, &option)) { | 1257 | string = match_strdup(args); |
1198 | errors++; | 1258 | if (string == NULL) |
1199 | nfs_parse_invalid_value("nfsvers"); | 1259 | goto out_nomem; |
1200 | break; | 1260 | rc = strict_strtoul(string, 10, &option); |
1201 | } | 1261 | kfree(string); |
1262 | if (rc != 0) | ||
1263 | goto out_invalid_value; | ||
1202 | switch (option) { | 1264 | switch (option) { |
1203 | case NFS2_VERSION: | 1265 | case NFS2_VERSION: |
1204 | mnt->flags &= ~NFS_MOUNT_VER3; | 1266 | mnt->flags &= ~NFS_MOUNT_VER3; |
@@ -1207,10 +1269,16 @@ static int nfs_parse_mount_options(char *raw, | |||
1207 | mnt->flags |= NFS_MOUNT_VER3; | 1269 | mnt->flags |= NFS_MOUNT_VER3; |
1208 | break; | 1270 | break; |
1209 | default: | 1271 | default: |
1210 | errors++; | 1272 | goto out_invalid_value; |
1211 | nfs_parse_invalid_value("nfsvers"); | ||
1212 | } | 1273 | } |
1213 | break; | 1274 | break; |
1275 | case Opt_minorversion: | ||
1276 | if (match_int(args, &int_option)) | ||
1277 | return 0; | ||
1278 | if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION) | ||
1279 | return 0; | ||
1280 | mnt->minorversion = int_option; | ||
1281 | break; | ||
1214 | 1282 | ||
1215 | /* | 1283 | /* |
1216 | * options that take text values | 1284 | * options that take text values |
@@ -1222,9 +1290,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1222 | rc = nfs_parse_security_flavors(string, mnt); | 1290 | rc = nfs_parse_security_flavors(string, mnt); |
1223 | kfree(string); | 1291 | kfree(string); |
1224 | if (!rc) { | 1292 | if (!rc) { |
1225 | errors++; | ||
1226 | dfprintk(MOUNT, "NFS: unrecognized " | 1293 | dfprintk(MOUNT, "NFS: unrecognized " |
1227 | "security flavor\n"); | 1294 | "security flavor\n"); |
1295 | return 0; | ||
1228 | } | 1296 | } |
1229 | break; | 1297 | break; |
1230 | case Opt_proto: | 1298 | case Opt_proto: |
@@ -1238,23 +1306,25 @@ static int nfs_parse_mount_options(char *raw, | |||
1238 | case Opt_xprt_udp: | 1306 | case Opt_xprt_udp: |
1239 | mnt->flags &= ~NFS_MOUNT_TCP; | 1307 | mnt->flags &= ~NFS_MOUNT_TCP; |
1240 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1308 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
1309 | kfree(string); | ||
1241 | break; | 1310 | break; |
1242 | case Opt_xprt_tcp: | 1311 | case Opt_xprt_tcp: |
1243 | mnt->flags |= NFS_MOUNT_TCP; | 1312 | mnt->flags |= NFS_MOUNT_TCP; |
1244 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1313 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1314 | kfree(string); | ||
1245 | break; | 1315 | break; |
1246 | case Opt_xprt_rdma: | 1316 | case Opt_xprt_rdma: |
1247 | /* vector side protocols to TCP */ | 1317 | /* vector side protocols to TCP */ |
1248 | mnt->flags |= NFS_MOUNT_TCP; | 1318 | mnt->flags |= NFS_MOUNT_TCP; |
1249 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; | 1319 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; |
1250 | xprt_load_transport(string); | 1320 | xprt_load_transport(string); |
1321 | kfree(string); | ||
1251 | break; | 1322 | break; |
1252 | default: | 1323 | default: |
1253 | errors++; | ||
1254 | dfprintk(MOUNT, "NFS: unrecognized " | 1324 | dfprintk(MOUNT, "NFS: unrecognized " |
1255 | "transport protocol\n"); | 1325 | "transport protocol\n"); |
1326 | return 0; | ||
1256 | } | 1327 | } |
1257 | kfree(string); | ||
1258 | break; | 1328 | break; |
1259 | case Opt_mountproto: | 1329 | case Opt_mountproto: |
1260 | string = match_strdup(args); | 1330 | string = match_strdup(args); |
@@ -1273,9 +1343,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1273 | break; | 1343 | break; |
1274 | case Opt_xprt_rdma: /* not used for side protocols */ | 1344 | case Opt_xprt_rdma: /* not used for side protocols */ |
1275 | default: | 1345 | default: |
1276 | errors++; | ||
1277 | dfprintk(MOUNT, "NFS: unrecognized " | 1346 | dfprintk(MOUNT, "NFS: unrecognized " |
1278 | "transport protocol\n"); | 1347 | "transport protocol\n"); |
1348 | return 0; | ||
1279 | } | 1349 | } |
1280 | break; | 1350 | break; |
1281 | case Opt_addr: | 1351 | case Opt_addr: |
@@ -1331,9 +1401,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1331 | mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; | 1401 | mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; |
1332 | break; | 1402 | break; |
1333 | default: | 1403 | default: |
1334 | errors++; | ||
1335 | dfprintk(MOUNT, "NFS: invalid " | 1404 | dfprintk(MOUNT, "NFS: invalid " |
1336 | "lookupcache argument\n"); | 1405 | "lookupcache argument\n"); |
1406 | return 0; | ||
1337 | }; | 1407 | }; |
1338 | break; | 1408 | break; |
1339 | 1409 | ||
@@ -1351,20 +1421,20 @@ static int nfs_parse_mount_options(char *raw, | |||
1351 | break; | 1421 | break; |
1352 | 1422 | ||
1353 | default: | 1423 | default: |
1354 | errors++; | 1424 | invalid_option = 1; |
1355 | dfprintk(MOUNT, "NFS: unrecognized mount option " | 1425 | dfprintk(MOUNT, "NFS: unrecognized mount option " |
1356 | "'%s'\n", p); | 1426 | "'%s'\n", p); |
1357 | } | 1427 | } |
1358 | } | 1428 | } |
1359 | 1429 | ||
1360 | if (errors > 0) { | 1430 | if (!sloppy && invalid_option) |
1361 | dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n", | 1431 | return 0; |
1362 | errors, (errors == 1 ? "" : "s")); | 1432 | |
1363 | if (!sloppy) | ||
1364 | return 0; | ||
1365 | } | ||
1366 | return 1; | 1433 | return 1; |
1367 | 1434 | ||
1435 | out_invalid_value: | ||
1436 | printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p); | ||
1437 | return 0; | ||
1368 | out_nomem: | 1438 | out_nomem: |
1369 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); | 1439 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); |
1370 | return 0; | 1440 | return 0; |
@@ -1381,6 +1451,7 @@ out_security_failure: | |||
1381 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1451 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
1382 | struct nfs_fh *root_fh) | 1452 | struct nfs_fh *root_fh) |
1383 | { | 1453 | { |
1454 | unsigned int auth_flavor_len = 0; | ||
1384 | struct nfs_mount_request request = { | 1455 | struct nfs_mount_request request = { |
1385 | .sap = (struct sockaddr *) | 1456 | .sap = (struct sockaddr *) |
1386 | &args->mount_server.address, | 1457 | &args->mount_server.address, |
@@ -1388,6 +1459,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1388 | .protocol = args->mount_server.protocol, | 1459 | .protocol = args->mount_server.protocol, |
1389 | .fh = root_fh, | 1460 | .fh = root_fh, |
1390 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | 1461 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, |
1462 | .auth_flav_len = &auth_flavor_len, | ||
1391 | }; | 1463 | }; |
1392 | int status; | 1464 | int status; |
1393 | 1465 | ||
@@ -2240,6 +2312,11 @@ static void nfs4_fill_super(struct super_block *sb) | |||
2240 | nfs_initialise_sb(sb); | 2312 | nfs_initialise_sb(sb); |
2241 | } | 2313 | } |
2242 | 2314 | ||
2315 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) | ||
2316 | { | ||
2317 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3); | ||
2318 | } | ||
2319 | |||
2243 | /* | 2320 | /* |
2244 | * Validate NFSv4 mount options | 2321 | * Validate NFSv4 mount options |
2245 | */ | 2322 | */ |
@@ -2263,6 +2340,7 @@ static int nfs4_validate_mount_data(void *options, | |||
2263 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | 2340 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ |
2264 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 2341 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
2265 | args->auth_flavor_len = 0; | 2342 | args->auth_flavor_len = 0; |
2343 | args->minorversion = 0; | ||
2266 | 2344 | ||
2267 | switch (data->version) { | 2345 | switch (data->version) { |
2268 | case 1: | 2346 | case 1: |
@@ -2336,6 +2414,8 @@ static int nfs4_validate_mount_data(void *options, | |||
2336 | 2414 | ||
2337 | nfs_validate_transport_protocol(args); | 2415 | nfs_validate_transport_protocol(args); |
2338 | 2416 | ||
2417 | nfs4_validate_mount_flags(args); | ||
2418 | |||
2339 | if (args->auth_flavor_len > 1) | 2419 | if (args->auth_flavor_len > 1) |
2340 | goto out_inval_auth; | 2420 | goto out_inval_auth; |
2341 | 2421 | ||
@@ -2375,12 +2455,12 @@ out_no_client_address: | |||
2375 | } | 2455 | } |
2376 | 2456 | ||
2377 | /* | 2457 | /* |
2378 | * Get the superblock for an NFS4 mountpoint | 2458 | * Get the superblock for the NFS4 root partition |
2379 | */ | 2459 | */ |
2380 | static int nfs4_get_sb(struct file_system_type *fs_type, | 2460 | static int nfs4_remote_get_sb(struct file_system_type *fs_type, |
2381 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 2461 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) |
2382 | { | 2462 | { |
2383 | struct nfs_parsed_mount_data *data; | 2463 | struct nfs_parsed_mount_data *data = raw_data; |
2384 | struct super_block *s; | 2464 | struct super_block *s; |
2385 | struct nfs_server *server; | 2465 | struct nfs_server *server; |
2386 | struct nfs_fh *mntfh; | 2466 | struct nfs_fh *mntfh; |
@@ -2391,18 +2471,12 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2391 | }; | 2471 | }; |
2392 | int error = -ENOMEM; | 2472 | int error = -ENOMEM; |
2393 | 2473 | ||
2394 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
2395 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2474 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); |
2396 | if (data == NULL || mntfh == NULL) | 2475 | if (data == NULL || mntfh == NULL) |
2397 | goto out_free_fh; | 2476 | goto out_free_fh; |
2398 | 2477 | ||
2399 | security_init_mnt_opts(&data->lsm_opts); | 2478 | security_init_mnt_opts(&data->lsm_opts); |
2400 | 2479 | ||
2401 | /* Validate the mount data */ | ||
2402 | error = nfs4_validate_mount_data(raw_data, data, dev_name); | ||
2403 | if (error < 0) | ||
2404 | goto out; | ||
2405 | |||
2406 | /* Get a volume representation */ | 2480 | /* Get a volume representation */ |
2407 | server = nfs4_create_server(data, mntfh); | 2481 | server = nfs4_create_server(data, mntfh); |
2408 | if (IS_ERR(server)) { | 2482 | if (IS_ERR(server)) { |
@@ -2415,7 +2489,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2415 | compare_super = NULL; | 2489 | compare_super = NULL; |
2416 | 2490 | ||
2417 | /* Get a superblock - note that we may end up sharing one that already exists */ | 2491 | /* Get a superblock - note that we may end up sharing one that already exists */ |
2418 | s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); | 2492 | s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata); |
2419 | if (IS_ERR(s)) { | 2493 | if (IS_ERR(s)) { |
2420 | error = PTR_ERR(s); | 2494 | error = PTR_ERR(s); |
2421 | goto out_free; | 2495 | goto out_free; |
@@ -2452,14 +2526,9 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2452 | error = 0; | 2526 | error = 0; |
2453 | 2527 | ||
2454 | out: | 2528 | out: |
2455 | kfree(data->client_address); | ||
2456 | kfree(data->nfs_server.export_path); | ||
2457 | kfree(data->nfs_server.hostname); | ||
2458 | kfree(data->fscache_uniq); | ||
2459 | security_free_mnt_opts(&data->lsm_opts); | 2529 | security_free_mnt_opts(&data->lsm_opts); |
2460 | out_free_fh: | 2530 | out_free_fh: |
2461 | kfree(mntfh); | 2531 | kfree(mntfh); |
2462 | kfree(data); | ||
2463 | return error; | 2532 | return error; |
2464 | 2533 | ||
2465 | out_free: | 2534 | out_free: |
@@ -2473,16 +2542,137 @@ error_splat_super: | |||
2473 | goto out; | 2542 | goto out; |
2474 | } | 2543 | } |
2475 | 2544 | ||
2545 | static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, | ||
2546 | int flags, void *data, const char *hostname) | ||
2547 | { | ||
2548 | struct vfsmount *root_mnt; | ||
2549 | char *root_devname; | ||
2550 | size_t len; | ||
2551 | |||
2552 | len = strlen(hostname) + 3; | ||
2553 | root_devname = kmalloc(len, GFP_KERNEL); | ||
2554 | if (root_devname == NULL) | ||
2555 | return ERR_PTR(-ENOMEM); | ||
2556 | snprintf(root_devname, len, "%s:/", hostname); | ||
2557 | root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); | ||
2558 | kfree(root_devname); | ||
2559 | return root_mnt; | ||
2560 | } | ||
2561 | |||
2562 | static void nfs_fix_devname(const struct path *path, struct vfsmount *mnt) | ||
2563 | { | ||
2564 | char *page = (char *) __get_free_page(GFP_KERNEL); | ||
2565 | char *devname, *tmp; | ||
2566 | |||
2567 | if (page == NULL) | ||
2568 | return; | ||
2569 | devname = nfs_path(path->mnt->mnt_devname, | ||
2570 | path->mnt->mnt_root, path->dentry, | ||
2571 | page, PAGE_SIZE); | ||
2572 | if (devname == NULL) | ||
2573 | goto out_freepage; | ||
2574 | tmp = kstrdup(devname, GFP_KERNEL); | ||
2575 | if (tmp == NULL) | ||
2576 | goto out_freepage; | ||
2577 | kfree(mnt->mnt_devname); | ||
2578 | mnt->mnt_devname = tmp; | ||
2579 | out_freepage: | ||
2580 | free_page((unsigned long)page); | ||
2581 | } | ||
2582 | |||
2583 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, | ||
2584 | const char *export_path, struct vfsmount *mnt_target) | ||
2585 | { | ||
2586 | struct mnt_namespace *ns_private; | ||
2587 | struct nameidata nd; | ||
2588 | struct super_block *s; | ||
2589 | int ret; | ||
2590 | |||
2591 | ns_private = create_mnt_ns(root_mnt); | ||
2592 | ret = PTR_ERR(ns_private); | ||
2593 | if (IS_ERR(ns_private)) | ||
2594 | goto out_mntput; | ||
2595 | |||
2596 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, | ||
2597 | export_path, LOOKUP_FOLLOW, &nd); | ||
2598 | |||
2599 | put_mnt_ns(ns_private); | ||
2600 | |||
2601 | if (ret != 0) | ||
2602 | goto out_err; | ||
2603 | |||
2604 | s = nd.path.mnt->mnt_sb; | ||
2605 | atomic_inc(&s->s_active); | ||
2606 | mnt_target->mnt_sb = s; | ||
2607 | mnt_target->mnt_root = dget(nd.path.dentry); | ||
2608 | |||
2609 | /* Correct the device pathname */ | ||
2610 | nfs_fix_devname(&nd.path, mnt_target); | ||
2611 | |||
2612 | path_put(&nd.path); | ||
2613 | down_write(&s->s_umount); | ||
2614 | return 0; | ||
2615 | out_mntput: | ||
2616 | mntput(root_mnt); | ||
2617 | out_err: | ||
2618 | return ret; | ||
2619 | } | ||
2620 | |||
2621 | /* | ||
2622 | * Get the superblock for an NFS4 mountpoint | ||
2623 | */ | ||
2624 | static int nfs4_get_sb(struct file_system_type *fs_type, | ||
2625 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | ||
2626 | { | ||
2627 | struct nfs_parsed_mount_data *data; | ||
2628 | char *export_path; | ||
2629 | struct vfsmount *root_mnt; | ||
2630 | int error = -ENOMEM; | ||
2631 | |||
2632 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
2633 | if (data == NULL) | ||
2634 | goto out_free_data; | ||
2635 | |||
2636 | /* Validate the mount data */ | ||
2637 | error = nfs4_validate_mount_data(raw_data, data, dev_name); | ||
2638 | if (error < 0) | ||
2639 | goto out; | ||
2640 | |||
2641 | export_path = data->nfs_server.export_path; | ||
2642 | data->nfs_server.export_path = "/"; | ||
2643 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, | ||
2644 | data->nfs_server.hostname); | ||
2645 | data->nfs_server.export_path = export_path; | ||
2646 | |||
2647 | error = PTR_ERR(root_mnt); | ||
2648 | if (IS_ERR(root_mnt)) | ||
2649 | goto out; | ||
2650 | |||
2651 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
2652 | |||
2653 | out: | ||
2654 | kfree(data->client_address); | ||
2655 | kfree(data->nfs_server.export_path); | ||
2656 | kfree(data->nfs_server.hostname); | ||
2657 | kfree(data->fscache_uniq); | ||
2658 | out_free_data: | ||
2659 | kfree(data); | ||
2660 | dprintk("<-- nfs4_get_sb() = %d%s\n", error, | ||
2661 | error != 0 ? " [error]" : ""); | ||
2662 | return error; | ||
2663 | } | ||
2664 | |||
2476 | static void nfs4_kill_super(struct super_block *sb) | 2665 | static void nfs4_kill_super(struct super_block *sb) |
2477 | { | 2666 | { |
2478 | struct nfs_server *server = NFS_SB(sb); | 2667 | struct nfs_server *server = NFS_SB(sb); |
2479 | 2668 | ||
2669 | dprintk("--> %s\n", __func__); | ||
2480 | nfs_super_return_all_delegations(sb); | 2670 | nfs_super_return_all_delegations(sb); |
2481 | kill_anon_super(sb); | 2671 | kill_anon_super(sb); |
2482 | |||
2483 | nfs4_renewd_prepare_shutdown(server); | 2672 | nfs4_renewd_prepare_shutdown(server); |
2484 | nfs_fscache_release_super_cookie(sb); | 2673 | nfs_fscache_release_super_cookie(sb); |
2485 | nfs_free_server(server); | 2674 | nfs_free_server(server); |
2675 | dprintk("<-- %s\n", __func__); | ||
2486 | } | 2676 | } |
2487 | 2677 | ||
2488 | /* | 2678 | /* |
@@ -2568,12 +2758,9 @@ error_splat_super: | |||
2568 | return error; | 2758 | return error; |
2569 | } | 2759 | } |
2570 | 2760 | ||
2571 | /* | 2761 | static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, |
2572 | * Create an NFS4 server record on referral traversal | 2762 | int flags, const char *dev_name, void *raw_data, |
2573 | */ | 2763 | struct vfsmount *mnt) |
2574 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, | ||
2575 | const char *dev_name, void *raw_data, | ||
2576 | struct vfsmount *mnt) | ||
2577 | { | 2764 | { |
2578 | struct nfs_clone_mount *data = raw_data; | 2765 | struct nfs_clone_mount *data = raw_data; |
2579 | struct super_block *s; | 2766 | struct super_block *s; |
@@ -2652,4 +2839,36 @@ error_splat_super: | |||
2652 | return error; | 2839 | return error; |
2653 | } | 2840 | } |
2654 | 2841 | ||
2842 | /* | ||
2843 | * Create an NFS4 server record on referral traversal | ||
2844 | */ | ||
2845 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, | ||
2846 | int flags, const char *dev_name, void *raw_data, | ||
2847 | struct vfsmount *mnt) | ||
2848 | { | ||
2849 | struct nfs_clone_mount *data = raw_data; | ||
2850 | char *export_path; | ||
2851 | struct vfsmount *root_mnt; | ||
2852 | int error; | ||
2853 | |||
2854 | dprintk("--> nfs4_referral_get_sb()\n"); | ||
2855 | |||
2856 | export_path = data->mnt_path; | ||
2857 | data->mnt_path = "/"; | ||
2858 | |||
2859 | root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type, | ||
2860 | flags, data, data->hostname); | ||
2861 | data->mnt_path = export_path; | ||
2862 | |||
2863 | error = PTR_ERR(root_mnt); | ||
2864 | if (IS_ERR(root_mnt)) | ||
2865 | goto out; | ||
2866 | |||
2867 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
2868 | out: | ||
2869 | dprintk("<-- nfs4_referral_get_sb() = %d%s\n", error, | ||
2870 | error != 0 ? " [error]" : ""); | ||
2871 | return error; | ||
2872 | } | ||
2873 | |||
2655 | #endif /* CONFIG_NFS_V4 */ | 2874 | #endif /* CONFIG_NFS_V4 */ |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index ecc295347775..1064c91ae810 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/wait.h> | 15 | #include <linux/wait.h> |
16 | 16 | ||
17 | #include "internal.h" | 17 | #include "internal.h" |
18 | #include "nfs4_fs.h" | ||
18 | 19 | ||
19 | struct nfs_unlinkdata { | 20 | struct nfs_unlinkdata { |
20 | struct hlist_node list; | 21 | struct hlist_node list; |
@@ -82,7 +83,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) | |||
82 | struct inode *dir = data->dir; | 83 | struct inode *dir = data->dir; |
83 | 84 | ||
84 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) | 85 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) |
85 | rpc_restart_call(task); | 86 | nfs4_restart_rpc(task, NFS_SERVER(dir)->nfs_client); |
86 | } | 87 | } |
87 | 88 | ||
88 | /** | 89 | /** |
@@ -102,9 +103,25 @@ static void nfs_async_unlink_release(void *calldata) | |||
102 | nfs_sb_deactive(sb); | 103 | nfs_sb_deactive(sb); |
103 | } | 104 | } |
104 | 105 | ||
106 | #if defined(CONFIG_NFS_V4_1) | ||
107 | void nfs_unlink_prepare(struct rpc_task *task, void *calldata) | ||
108 | { | ||
109 | struct nfs_unlinkdata *data = calldata; | ||
110 | struct nfs_server *server = NFS_SERVER(data->dir); | ||
111 | |||
112 | if (nfs4_setup_sequence(server->nfs_client, &data->args.seq_args, | ||
113 | &data->res.seq_res, 1, task)) | ||
114 | return; | ||
115 | rpc_call_start(task); | ||
116 | } | ||
117 | #endif /* CONFIG_NFS_V4_1 */ | ||
118 | |||
105 | static const struct rpc_call_ops nfs_unlink_ops = { | 119 | static const struct rpc_call_ops nfs_unlink_ops = { |
106 | .rpc_call_done = nfs_async_unlink_done, | 120 | .rpc_call_done = nfs_async_unlink_done, |
107 | .rpc_release = nfs_async_unlink_release, | 121 | .rpc_release = nfs_async_unlink_release, |
122 | #if defined(CONFIG_NFS_V4_1) | ||
123 | .rpc_call_prepare = nfs_unlink_prepare, | ||
124 | #endif /* CONFIG_NFS_V4_1 */ | ||
108 | }; | 125 | }; |
109 | 126 | ||
110 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) | 127 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) |
@@ -241,6 +258,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) | |||
241 | status = PTR_ERR(data->cred); | 258 | status = PTR_ERR(data->cred); |
242 | goto out_free; | 259 | goto out_free; |
243 | } | 260 | } |
261 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
244 | 262 | ||
245 | status = -EBUSY; | 263 | status = -EBUSY; |
246 | spin_lock(&dentry->d_lock); | 264 | spin_lock(&dentry->d_lock); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e560a78995a3..ce728829f79a 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "delegation.h" | 25 | #include "delegation.h" |
26 | #include "internal.h" | 26 | #include "internal.h" |
27 | #include "iostat.h" | 27 | #include "iostat.h" |
28 | #include "nfs4_fs.h" | ||
28 | 29 | ||
29 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 30 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
30 | 31 | ||
@@ -52,6 +53,7 @@ struct nfs_write_data *nfs_commitdata_alloc(void) | |||
52 | if (p) { | 53 | if (p) { |
53 | memset(p, 0, sizeof(*p)); | 54 | memset(p, 0, sizeof(*p)); |
54 | INIT_LIST_HEAD(&p->pages); | 55 | INIT_LIST_HEAD(&p->pages); |
56 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
55 | } | 57 | } |
56 | return p; | 58 | return p; |
57 | } | 59 | } |
@@ -71,6 +73,7 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | |||
71 | memset(p, 0, sizeof(*p)); | 73 | memset(p, 0, sizeof(*p)); |
72 | INIT_LIST_HEAD(&p->pages); | 74 | INIT_LIST_HEAD(&p->pages); |
73 | p->npages = pagecount; | 75 | p->npages = pagecount; |
76 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
74 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 77 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
75 | p->pagevec = p->page_array; | 78 | p->pagevec = p->page_array; |
76 | else { | 79 | else { |
@@ -1048,7 +1051,23 @@ out: | |||
1048 | nfs_writedata_release(calldata); | 1051 | nfs_writedata_release(calldata); |
1049 | } | 1052 | } |
1050 | 1053 | ||
1054 | #if defined(CONFIG_NFS_V4_1) | ||
1055 | void nfs_write_prepare(struct rpc_task *task, void *calldata) | ||
1056 | { | ||
1057 | struct nfs_write_data *data = calldata; | ||
1058 | struct nfs_client *clp = (NFS_SERVER(data->inode))->nfs_client; | ||
1059 | |||
1060 | if (nfs4_setup_sequence(clp, &data->args.seq_args, | ||
1061 | &data->res.seq_res, 1, task)) | ||
1062 | return; | ||
1063 | rpc_call_start(task); | ||
1064 | } | ||
1065 | #endif /* CONFIG_NFS_V4_1 */ | ||
1066 | |||
1051 | static const struct rpc_call_ops nfs_write_partial_ops = { | 1067 | static const struct rpc_call_ops nfs_write_partial_ops = { |
1068 | #if defined(CONFIG_NFS_V4_1) | ||
1069 | .rpc_call_prepare = nfs_write_prepare, | ||
1070 | #endif /* CONFIG_NFS_V4_1 */ | ||
1052 | .rpc_call_done = nfs_writeback_done_partial, | 1071 | .rpc_call_done = nfs_writeback_done_partial, |
1053 | .rpc_release = nfs_writeback_release_partial, | 1072 | .rpc_release = nfs_writeback_release_partial, |
1054 | }; | 1073 | }; |
@@ -1111,6 +1130,9 @@ remove_request: | |||
1111 | } | 1130 | } |
1112 | 1131 | ||
1113 | static const struct rpc_call_ops nfs_write_full_ops = { | 1132 | static const struct rpc_call_ops nfs_write_full_ops = { |
1133 | #if defined(CONFIG_NFS_V4_1) | ||
1134 | .rpc_call_prepare = nfs_write_prepare, | ||
1135 | #endif /* CONFIG_NFS_V4_1 */ | ||
1114 | .rpc_call_done = nfs_writeback_done_full, | 1136 | .rpc_call_done = nfs_writeback_done_full, |
1115 | .rpc_release = nfs_writeback_release_full, | 1137 | .rpc_release = nfs_writeback_release_full, |
1116 | }; | 1138 | }; |
@@ -1123,6 +1145,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1123 | { | 1145 | { |
1124 | struct nfs_writeargs *argp = &data->args; | 1146 | struct nfs_writeargs *argp = &data->args; |
1125 | struct nfs_writeres *resp = &data->res; | 1147 | struct nfs_writeres *resp = &data->res; |
1148 | struct nfs_server *server = NFS_SERVER(data->inode); | ||
1126 | int status; | 1149 | int status; |
1127 | 1150 | ||
1128 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", | 1151 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", |
@@ -1155,7 +1178,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1155 | if (time_before(complain, jiffies)) { | 1178 | if (time_before(complain, jiffies)) { |
1156 | dprintk("NFS: faulty NFS server %s:" | 1179 | dprintk("NFS: faulty NFS server %s:" |
1157 | " (committed = %d) != (stable = %d)\n", | 1180 | " (committed = %d) != (stable = %d)\n", |
1158 | NFS_SERVER(data->inode)->nfs_client->cl_hostname, | 1181 | server->nfs_client->cl_hostname, |
1159 | resp->verf->committed, argp->stable); | 1182 | resp->verf->committed, argp->stable); |
1160 | complain = jiffies + 300 * HZ; | 1183 | complain = jiffies + 300 * HZ; |
1161 | } | 1184 | } |
@@ -1181,7 +1204,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1181 | */ | 1204 | */ |
1182 | argp->stable = NFS_FILE_SYNC; | 1205 | argp->stable = NFS_FILE_SYNC; |
1183 | } | 1206 | } |
1184 | rpc_restart_call(task); | 1207 | nfs4_restart_rpc(task, server->nfs_client); |
1185 | return -EAGAIN; | 1208 | return -EAGAIN; |
1186 | } | 1209 | } |
1187 | if (time_before(complain, jiffies)) { | 1210 | if (time_before(complain, jiffies)) { |
@@ -1193,6 +1216,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1193 | /* Can't do anything about it except throw an error. */ | 1216 | /* Can't do anything about it except throw an error. */ |
1194 | task->tk_status = -EIO; | 1217 | task->tk_status = -EIO; |
1195 | } | 1218 | } |
1219 | nfs4_sequence_free_slot(server->nfs_client, &data->res.seq_res); | ||
1196 | return 0; | 1220 | return 0; |
1197 | } | 1221 | } |
1198 | 1222 | ||
@@ -1349,6 +1373,9 @@ static void nfs_commit_release(void *calldata) | |||
1349 | } | 1373 | } |
1350 | 1374 | ||
1351 | static const struct rpc_call_ops nfs_commit_ops = { | 1375 | static const struct rpc_call_ops nfs_commit_ops = { |
1376 | #if defined(CONFIG_NFS_V4_1) | ||
1377 | .rpc_call_prepare = nfs_write_prepare, | ||
1378 | #endif /* CONFIG_NFS_V4_1 */ | ||
1352 | .rpc_call_done = nfs_commit_done, | 1379 | .rpc_call_done = nfs_commit_done, |
1353 | .rpc_release = nfs_commit_release, | 1380 | .rpc_release = nfs_commit_release, |
1354 | }; | 1381 | }; |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 8b1f8efb4690..b92a27629fb7 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -464,16 +464,11 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) | |||
464 | if (err) | 464 | if (err) |
465 | return err; | 465 | return err; |
466 | /* | 466 | /* |
467 | * Just a quick sanity check; we could also try to check | 467 | * XXX: It would be nice to also check whether this |
468 | * whether this pseudoflavor is supported, but at worst | 468 | * pseudoflavor is supported, so we can discover the |
469 | * an unsupported pseudoflavor on the export would just | 469 | * problem at export time instead of when a client fails |
470 | * be a pseudoflavor that won't match the flavor of any | 470 | * to authenticate. |
471 | * authenticated request. The administrator will | ||
472 | * probably discover the problem when someone fails to | ||
473 | * authenticate. | ||
474 | */ | 471 | */ |
475 | if (f->pseudoflavor < 0) | ||
476 | return -EINVAL; | ||
477 | err = get_int(mesg, &f->flags); | 472 | err = get_int(mesg, &f->flags); |
478 | if (err) | 473 | if (err) |
479 | return err; | 474 | return err; |
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 7c9fe838f038..a713c418a922 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c | |||
@@ -652,8 +652,6 @@ nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp, | |||
652 | * NFSv3 Server procedures. | 652 | * NFSv3 Server procedures. |
653 | * Only the results of non-idempotent operations are cached. | 653 | * Only the results of non-idempotent operations are cached. |
654 | */ | 654 | */ |
655 | #define nfs3svc_decode_voidargs NULL | ||
656 | #define nfs3svc_release_void NULL | ||
657 | #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle | 655 | #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle |
658 | #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat | 656 | #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat |
659 | #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat | 657 | #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat |
@@ -686,28 +684,219 @@ struct nfsd3_voidargs { int dummy; }; | |||
686 | #define WC (7+pAT) /* WCC attributes */ | 684 | #define WC (7+pAT) /* WCC attributes */ |
687 | 685 | ||
688 | static struct svc_procedure nfsd_procedures3[22] = { | 686 | static struct svc_procedure nfsd_procedures3[22] = { |
689 | PROC(null, void, void, void, RC_NOCACHE, ST), | 687 | [NFS3PROC_NULL] = { |
690 | PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), | 688 | .pc_func = (svc_procfunc) nfsd3_proc_null, |
691 | PROC(setattr, sattr, wccstat, fhandle, RC_REPLBUFF, ST+WC), | 689 | .pc_encode = (kxdrproc_t) nfs3svc_encode_voidres, |
692 | PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE, ST+FH+pAT+pAT), | 690 | .pc_argsize = sizeof(struct nfsd3_voidargs), |
693 | PROC(access, access, access, fhandle, RC_NOCACHE, ST+pAT+1), | 691 | .pc_ressize = sizeof(struct nfsd3_voidres), |
694 | PROC(readlink, readlink, readlink, fhandle, RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4), | 692 | .pc_cachetype = RC_NOCACHE, |
695 | PROC(read, read, read, fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE/4), | 693 | .pc_xdrressize = ST, |
696 | PROC(write, write, write, fhandle, RC_REPLBUFF, ST+WC+4), | 694 | }, |
697 | PROC(create, create, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 695 | [NFS3PROC_GETATTR] = { |
698 | PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 696 | .pc_func = (svc_procfunc) nfsd3_proc_getattr, |
699 | PROC(symlink, symlink, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 697 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, |
700 | PROC(mknod, mknod, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 698 | .pc_encode = (kxdrproc_t) nfs3svc_encode_attrstatres, |
701 | PROC(remove, dirop, wccstat, fhandle, RC_REPLBUFF, ST+WC), | 699 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, |
702 | PROC(rmdir, dirop, wccstat, fhandle, RC_REPLBUFF, ST+WC), | 700 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), |
703 | PROC(rename, rename, rename, fhandle2, RC_REPLBUFF, ST+WC+WC), | 701 | .pc_ressize = sizeof(struct nfsd3_attrstatres), |
704 | PROC(link, link, link, fhandle2, RC_REPLBUFF, ST+pAT+WC), | 702 | .pc_cachetype = RC_NOCACHE, |
705 | PROC(readdir, readdir, readdir, fhandle, RC_NOCACHE, 0), | 703 | .pc_xdrressize = ST+AT, |
706 | PROC(readdirplus,readdirplus, readdir, fhandle, RC_NOCACHE, 0), | 704 | }, |
707 | PROC(fsstat, fhandle, fsstat, void, RC_NOCACHE, ST+pAT+2*6+1), | 705 | [NFS3PROC_SETATTR] = { |
708 | PROC(fsinfo, fhandle, fsinfo, void, RC_NOCACHE, ST+pAT+12), | 706 | .pc_func = (svc_procfunc) nfsd3_proc_setattr, |
709 | PROC(pathconf, fhandle, pathconf, void, RC_NOCACHE, ST+pAT+6), | 707 | .pc_decode = (kxdrproc_t) nfs3svc_decode_sattrargs, |
710 | PROC(commit, commit, commit, fhandle, RC_NOCACHE, ST+WC+2), | 708 | .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres, |
709 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
710 | .pc_argsize = sizeof(struct nfsd3_sattrargs), | ||
711 | .pc_ressize = sizeof(struct nfsd3_wccstatres), | ||
712 | .pc_cachetype = RC_REPLBUFF, | ||
713 | .pc_xdrressize = ST+WC, | ||
714 | }, | ||
715 | [NFS3PROC_LOOKUP] = { | ||
716 | .pc_func = (svc_procfunc) nfsd3_proc_lookup, | ||
717 | .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs, | ||
718 | .pc_encode = (kxdrproc_t) nfs3svc_encode_diropres, | ||
719 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
720 | .pc_argsize = sizeof(struct nfsd3_diropargs), | ||
721 | .pc_ressize = sizeof(struct nfsd3_diropres), | ||
722 | .pc_cachetype = RC_NOCACHE, | ||
723 | .pc_xdrressize = ST+FH+pAT+pAT, | ||
724 | }, | ||
725 | [NFS3PROC_ACCESS] = { | ||
726 | .pc_func = (svc_procfunc) nfsd3_proc_access, | ||
727 | .pc_decode = (kxdrproc_t) nfs3svc_decode_accessargs, | ||
728 | .pc_encode = (kxdrproc_t) nfs3svc_encode_accessres, | ||
729 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
730 | .pc_argsize = sizeof(struct nfsd3_accessargs), | ||
731 | .pc_ressize = sizeof(struct nfsd3_accessres), | ||
732 | .pc_cachetype = RC_NOCACHE, | ||
733 | .pc_xdrressize = ST+pAT+1, | ||
734 | }, | ||
735 | [NFS3PROC_READLINK] = { | ||
736 | .pc_func = (svc_procfunc) nfsd3_proc_readlink, | ||
737 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readlinkargs, | ||
738 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readlinkres, | ||
739 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
740 | .pc_argsize = sizeof(struct nfsd3_readlinkargs), | ||
741 | .pc_ressize = sizeof(struct nfsd3_readlinkres), | ||
742 | .pc_cachetype = RC_NOCACHE, | ||
743 | .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4, | ||
744 | }, | ||
745 | [NFS3PROC_READ] = { | ||
746 | .pc_func = (svc_procfunc) nfsd3_proc_read, | ||
747 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readargs, | ||
748 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readres, | ||
749 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
750 | .pc_argsize = sizeof(struct nfsd3_readargs), | ||
751 | .pc_ressize = sizeof(struct nfsd3_readres), | ||
752 | .pc_cachetype = RC_NOCACHE, | ||
753 | .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4, | ||
754 | }, | ||
755 | [NFS3PROC_WRITE] = { | ||
756 | .pc_func = (svc_procfunc) nfsd3_proc_write, | ||
757 | .pc_decode = (kxdrproc_t) nfs3svc_decode_writeargs, | ||
758 | .pc_encode = (kxdrproc_t) nfs3svc_encode_writeres, | ||
759 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
760 | .pc_argsize = sizeof(struct nfsd3_writeargs), | ||
761 | .pc_ressize = sizeof(struct nfsd3_writeres), | ||
762 | .pc_cachetype = RC_REPLBUFF, | ||
763 | .pc_xdrressize = ST+WC+4, | ||
764 | }, | ||
765 | [NFS3PROC_CREATE] = { | ||
766 | .pc_func = (svc_procfunc) nfsd3_proc_create, | ||
767 | .pc_decode = (kxdrproc_t) nfs3svc_decode_createargs, | ||
768 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
769 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
770 | .pc_argsize = sizeof(struct nfsd3_createargs), | ||
771 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
772 | .pc_cachetype = RC_REPLBUFF, | ||
773 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
774 | }, | ||
775 | [NFS3PROC_MKDIR] = { | ||
776 | .pc_func = (svc_procfunc) nfsd3_proc_mkdir, | ||
777 | .pc_decode = (kxdrproc_t) nfs3svc_decode_mkdirargs, | ||
778 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
779 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
780 | .pc_argsize = sizeof(struct nfsd3_mkdirargs), | ||
781 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
782 | .pc_cachetype = RC_REPLBUFF, | ||
783 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
784 | }, | ||
785 | [NFS3PROC_SYMLINK] = { | ||
786 | .pc_func = (svc_procfunc) nfsd3_proc_symlink, | ||
787 | .pc_decode = (kxdrproc_t) nfs3svc_decode_symlinkargs, | ||
788 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
789 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
790 | .pc_argsize = sizeof(struct nfsd3_symlinkargs), | ||
791 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
792 | .pc_cachetype = RC_REPLBUFF, | ||
793 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
794 | }, | ||
795 | [NFS3PROC_MKNOD] = { | ||
796 | .pc_func = (svc_procfunc) nfsd3_proc_mknod, | ||
797 | .pc_decode = (kxdrproc_t) nfs3svc_decode_mknodargs, | ||
798 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
799 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
800 | .pc_argsize = sizeof(struct nfsd3_mknodargs), | ||
801 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
802 | .pc_cachetype = RC_REPLBUFF, | ||
803 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
804 | }, | ||
805 | [NFS3PROC_REMOVE] = { | ||
806 | .pc_func = (svc_procfunc) nfsd3_proc_remove, | ||
807 | .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs, | ||
808 | .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres, | ||
809 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
810 | .pc_argsize = sizeof(struct nfsd3_diropargs), | ||
811 | .pc_ressize = sizeof(struct nfsd3_wccstatres), | ||
812 | .pc_cachetype = RC_REPLBUFF, | ||
813 | .pc_xdrressize = ST+WC, | ||
814 | }, | ||
815 | [NFS3PROC_RMDIR] = { | ||
816 | .pc_func = (svc_procfunc) nfsd3_proc_rmdir, | ||
817 | .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs, | ||
818 | .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres, | ||
819 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
820 | .pc_argsize = sizeof(struct nfsd3_diropargs), | ||
821 | .pc_ressize = sizeof(struct nfsd3_wccstatres), | ||
822 | .pc_cachetype = RC_REPLBUFF, | ||
823 | .pc_xdrressize = ST+WC, | ||
824 | }, | ||
825 | [NFS3PROC_RENAME] = { | ||
826 | .pc_func = (svc_procfunc) nfsd3_proc_rename, | ||
827 | .pc_decode = (kxdrproc_t) nfs3svc_decode_renameargs, | ||
828 | .pc_encode = (kxdrproc_t) nfs3svc_encode_renameres, | ||
829 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
830 | .pc_argsize = sizeof(struct nfsd3_renameargs), | ||
831 | .pc_ressize = sizeof(struct nfsd3_renameres), | ||
832 | .pc_cachetype = RC_REPLBUFF, | ||
833 | .pc_xdrressize = ST+WC+WC, | ||
834 | }, | ||
835 | [NFS3PROC_LINK] = { | ||
836 | .pc_func = (svc_procfunc) nfsd3_proc_link, | ||
837 | .pc_decode = (kxdrproc_t) nfs3svc_decode_linkargs, | ||
838 | .pc_encode = (kxdrproc_t) nfs3svc_encode_linkres, | ||
839 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
840 | .pc_argsize = sizeof(struct nfsd3_linkargs), | ||
841 | .pc_ressize = sizeof(struct nfsd3_linkres), | ||
842 | .pc_cachetype = RC_REPLBUFF, | ||
843 | .pc_xdrressize = ST+pAT+WC, | ||
844 | }, | ||
845 | [NFS3PROC_READDIR] = { | ||
846 | .pc_func = (svc_procfunc) nfsd3_proc_readdir, | ||
847 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirargs, | ||
848 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres, | ||
849 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
850 | .pc_argsize = sizeof(struct nfsd3_readdirargs), | ||
851 | .pc_ressize = sizeof(struct nfsd3_readdirres), | ||
852 | .pc_cachetype = RC_NOCACHE, | ||
853 | }, | ||
854 | [NFS3PROC_READDIRPLUS] = { | ||
855 | .pc_func = (svc_procfunc) nfsd3_proc_readdirplus, | ||
856 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirplusargs, | ||
857 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres, | ||
858 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
859 | .pc_argsize = sizeof(struct nfsd3_readdirplusargs), | ||
860 | .pc_ressize = sizeof(struct nfsd3_readdirres), | ||
861 | .pc_cachetype = RC_NOCACHE, | ||
862 | }, | ||
863 | [NFS3PROC_FSSTAT] = { | ||
864 | .pc_func = (svc_procfunc) nfsd3_proc_fsstat, | ||
865 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, | ||
866 | .pc_encode = (kxdrproc_t) nfs3svc_encode_fsstatres, | ||
867 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), | ||
868 | .pc_ressize = sizeof(struct nfsd3_fsstatres), | ||
869 | .pc_cachetype = RC_NOCACHE, | ||
870 | .pc_xdrressize = ST+pAT+2*6+1, | ||
871 | }, | ||
872 | [NFS3PROC_FSINFO] = { | ||
873 | .pc_func = (svc_procfunc) nfsd3_proc_fsinfo, | ||
874 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, | ||
875 | .pc_encode = (kxdrproc_t) nfs3svc_encode_fsinfores, | ||
876 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), | ||
877 | .pc_ressize = sizeof(struct nfsd3_fsinfores), | ||
878 | .pc_cachetype = RC_NOCACHE, | ||
879 | .pc_xdrressize = ST+pAT+12, | ||
880 | }, | ||
881 | [NFS3PROC_PATHCONF] = { | ||
882 | .pc_func = (svc_procfunc) nfsd3_proc_pathconf, | ||
883 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, | ||
884 | .pc_encode = (kxdrproc_t) nfs3svc_encode_pathconfres, | ||
885 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), | ||
886 | .pc_ressize = sizeof(struct nfsd3_pathconfres), | ||
887 | .pc_cachetype = RC_NOCACHE, | ||
888 | .pc_xdrressize = ST+pAT+6, | ||
889 | }, | ||
890 | [NFS3PROC_COMMIT] = { | ||
891 | .pc_func = (svc_procfunc) nfsd3_proc_commit, | ||
892 | .pc_decode = (kxdrproc_t) nfs3svc_decode_commitargs, | ||
893 | .pc_encode = (kxdrproc_t) nfs3svc_encode_commitres, | ||
894 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
895 | .pc_argsize = sizeof(struct nfsd3_commitargs), | ||
896 | .pc_ressize = sizeof(struct nfsd3_commitres), | ||
897 | .pc_cachetype = RC_NOCACHE, | ||
898 | .pc_xdrressize = ST+WC+2, | ||
899 | }, | ||
711 | }; | 900 | }; |
712 | 901 | ||
713 | struct svc_version nfsd_version3 = { | 902 | struct svc_version nfsd_version3 = { |
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 17d0dd997204..01d4ec1c88e0 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -272,6 +272,7 @@ void fill_post_wcc(struct svc_fh *fhp) | |||
272 | 272 | ||
273 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, | 273 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, |
274 | &fhp->fh_post_attr); | 274 | &fhp->fh_post_attr); |
275 | fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; | ||
275 | if (err) | 276 | if (err) |
276 | fhp->fh_post_saved = 0; | 277 | fhp->fh_post_saved = 0; |
277 | else | 278 | else |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 290289bd44f7..3fd23f7aceca 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -140,8 +140,10 @@ struct nfs4_cb_compound_hdr { | |||
140 | int status; | 140 | int status; |
141 | u32 ident; | 141 | u32 ident; |
142 | u32 nops; | 142 | u32 nops; |
143 | __be32 *nops_p; | ||
144 | u32 minorversion; | ||
143 | u32 taglen; | 145 | u32 taglen; |
144 | char * tag; | 146 | char *tag; |
145 | }; | 147 | }; |
146 | 148 | ||
147 | static struct { | 149 | static struct { |
@@ -201,33 +203,39 @@ nfs_cb_stat_to_errno(int stat) | |||
201 | * XDR encode | 203 | * XDR encode |
202 | */ | 204 | */ |
203 | 205 | ||
204 | static int | 206 | static void |
205 | encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) | 207 | encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) |
206 | { | 208 | { |
207 | __be32 * p; | 209 | __be32 * p; |
208 | 210 | ||
209 | RESERVE_SPACE(16); | 211 | RESERVE_SPACE(16); |
210 | WRITE32(0); /* tag length is always 0 */ | 212 | WRITE32(0); /* tag length is always 0 */ |
211 | WRITE32(NFS4_MINOR_VERSION); | 213 | WRITE32(hdr->minorversion); |
212 | WRITE32(hdr->ident); | 214 | WRITE32(hdr->ident); |
215 | hdr->nops_p = p; | ||
213 | WRITE32(hdr->nops); | 216 | WRITE32(hdr->nops); |
214 | return 0; | ||
215 | } | 217 | } |
216 | 218 | ||
217 | static int | 219 | static void encode_cb_nops(struct nfs4_cb_compound_hdr *hdr) |
218 | encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec) | 220 | { |
221 | *hdr->nops_p = htonl(hdr->nops); | ||
222 | } | ||
223 | |||
224 | static void | ||
225 | encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp, | ||
226 | struct nfs4_cb_compound_hdr *hdr) | ||
219 | { | 227 | { |
220 | __be32 *p; | 228 | __be32 *p; |
221 | int len = cb_rec->cbr_fh.fh_size; | 229 | int len = dp->dl_fh.fh_size; |
222 | 230 | ||
223 | RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len); | 231 | RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len); |
224 | WRITE32(OP_CB_RECALL); | 232 | WRITE32(OP_CB_RECALL); |
225 | WRITE32(cb_rec->cbr_stateid.si_generation); | 233 | WRITE32(dp->dl_stateid.si_generation); |
226 | WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t)); | 234 | WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t)); |
227 | WRITE32(cb_rec->cbr_trunc); | 235 | WRITE32(0); /* truncate optimization not implemented */ |
228 | WRITE32(len); | 236 | WRITE32(len); |
229 | WRITEMEM(&cb_rec->cbr_fh.fh_base, len); | 237 | WRITEMEM(&dp->dl_fh.fh_base, len); |
230 | return 0; | 238 | hdr->nops++; |
231 | } | 239 | } |
232 | 240 | ||
233 | static int | 241 | static int |
@@ -241,17 +249,18 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p) | |||
241 | } | 249 | } |
242 | 250 | ||
243 | static int | 251 | static int |
244 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args) | 252 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_delegation *args) |
245 | { | 253 | { |
246 | struct xdr_stream xdr; | 254 | struct xdr_stream xdr; |
247 | struct nfs4_cb_compound_hdr hdr = { | 255 | struct nfs4_cb_compound_hdr hdr = { |
248 | .ident = args->cbr_ident, | 256 | .ident = args->dl_ident, |
249 | .nops = 1, | ||
250 | }; | 257 | }; |
251 | 258 | ||
252 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 259 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
253 | encode_cb_compound_hdr(&xdr, &hdr); | 260 | encode_cb_compound_hdr(&xdr, &hdr); |
254 | return (encode_cb_recall(&xdr, args)); | 261 | encode_cb_recall(&xdr, args, &hdr); |
262 | encode_cb_nops(&hdr); | ||
263 | return 0; | ||
255 | } | 264 | } |
256 | 265 | ||
257 | 266 | ||
@@ -358,18 +367,21 @@ static struct rpc_program cb_program = { | |||
358 | .pipe_dir_name = "/nfsd4_cb", | 367 | .pipe_dir_name = "/nfsd4_cb", |
359 | }; | 368 | }; |
360 | 369 | ||
370 | static int max_cb_time(void) | ||
371 | { | ||
372 | return max(NFSD_LEASE_TIME/10, (time_t)1) * HZ; | ||
373 | } | ||
374 | |||
361 | /* Reference counting, callback cleanup, etc., all look racy as heck. | 375 | /* Reference counting, callback cleanup, etc., all look racy as heck. |
362 | * And why is cb_set an atomic? */ | 376 | * And why is cb_set an atomic? */ |
363 | 377 | ||
364 | static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | 378 | int setup_callback_client(struct nfs4_client *clp) |
365 | { | 379 | { |
366 | struct sockaddr_in addr; | 380 | struct sockaddr_in addr; |
367 | struct nfs4_callback *cb = &clp->cl_callback; | 381 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
368 | struct rpc_timeout timeparms = { | 382 | struct rpc_timeout timeparms = { |
369 | .to_initval = (NFSD_LEASE_TIME/4) * HZ, | 383 | .to_initval = max_cb_time(), |
370 | .to_retries = 5, | 384 | .to_retries = 0, |
371 | .to_maxval = (NFSD_LEASE_TIME/2) * HZ, | ||
372 | .to_exponential = 1, | ||
373 | }; | 385 | }; |
374 | struct rpc_create_args args = { | 386 | struct rpc_create_args args = { |
375 | .protocol = IPPROTO_TCP, | 387 | .protocol = IPPROTO_TCP, |
@@ -386,7 +398,7 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | |||
386 | struct rpc_clnt *client; | 398 | struct rpc_clnt *client; |
387 | 399 | ||
388 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) | 400 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) |
389 | return ERR_PTR(-EINVAL); | 401 | return -EINVAL; |
390 | 402 | ||
391 | /* Initialize address */ | 403 | /* Initialize address */ |
392 | memset(&addr, 0, sizeof(addr)); | 404 | memset(&addr, 0, sizeof(addr)); |
@@ -396,48 +408,77 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | |||
396 | 408 | ||
397 | /* Create RPC client */ | 409 | /* Create RPC client */ |
398 | client = rpc_create(&args); | 410 | client = rpc_create(&args); |
399 | if (IS_ERR(client)) | 411 | if (IS_ERR(client)) { |
400 | dprintk("NFSD: couldn't create callback client: %ld\n", | 412 | dprintk("NFSD: couldn't create callback client: %ld\n", |
401 | PTR_ERR(client)); | 413 | PTR_ERR(client)); |
402 | return client; | 414 | return PTR_ERR(client); |
415 | } | ||
416 | cb->cb_client = client; | ||
417 | return 0; | ||
418 | |||
419 | } | ||
420 | |||
421 | static void warn_no_callback_path(struct nfs4_client *clp, int reason) | ||
422 | { | ||
423 | dprintk("NFSD: warning: no callback path to client %.*s: error %d\n", | ||
424 | (int)clp->cl_name.len, clp->cl_name.data, reason); | ||
425 | } | ||
426 | |||
427 | static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) | ||
428 | { | ||
429 | struct nfs4_client *clp = calldata; | ||
430 | |||
431 | if (task->tk_status) | ||
432 | warn_no_callback_path(clp, task->tk_status); | ||
433 | else | ||
434 | atomic_set(&clp->cl_cb_conn.cb_set, 1); | ||
435 | put_nfs4_client(clp); | ||
436 | } | ||
437 | |||
438 | static const struct rpc_call_ops nfsd4_cb_probe_ops = { | ||
439 | .rpc_call_done = nfsd4_cb_probe_done, | ||
440 | }; | ||
403 | 441 | ||
442 | static struct rpc_cred *lookup_cb_cred(struct nfs4_cb_conn *cb) | ||
443 | { | ||
444 | struct auth_cred acred = { | ||
445 | .machine_cred = 1 | ||
446 | }; | ||
447 | |||
448 | /* | ||
449 | * Note in the gss case this doesn't actually have to wait for a | ||
450 | * gss upcall (or any calls to the client); this just creates a | ||
451 | * non-uptodate cred which the rpc state machine will fill in with | ||
452 | * a refresh_upcall later. | ||
453 | */ | ||
454 | return rpcauth_lookup_credcache(cb->cb_client->cl_auth, &acred, | ||
455 | RPCAUTH_LOOKUP_NEW); | ||
404 | } | 456 | } |
405 | 457 | ||
406 | static int do_probe_callback(void *data) | 458 | void do_probe_callback(struct nfs4_client *clp) |
407 | { | 459 | { |
408 | struct nfs4_client *clp = data; | 460 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
409 | struct nfs4_callback *cb = &clp->cl_callback; | ||
410 | struct rpc_message msg = { | 461 | struct rpc_message msg = { |
411 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], | 462 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], |
412 | .rpc_argp = clp, | 463 | .rpc_argp = clp, |
413 | }; | 464 | }; |
414 | struct rpc_clnt *client; | 465 | struct rpc_cred *cred; |
415 | int status; | 466 | int status; |
416 | 467 | ||
417 | client = setup_callback_client(clp); | 468 | cred = lookup_cb_cred(cb); |
418 | if (IS_ERR(client)) { | 469 | if (IS_ERR(cred)) { |
419 | status = PTR_ERR(client); | 470 | status = PTR_ERR(cred); |
420 | dprintk("NFSD: couldn't create callback client: %d\n", | 471 | goto out; |
421 | status); | 472 | } |
422 | goto out_err; | 473 | cb->cb_cred = cred; |
474 | msg.rpc_cred = cb->cb_cred; | ||
475 | status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT, | ||
476 | &nfsd4_cb_probe_ops, (void *)clp); | ||
477 | out: | ||
478 | if (status) { | ||
479 | warn_no_callback_path(clp, status); | ||
480 | put_nfs4_client(clp); | ||
423 | } | 481 | } |
424 | |||
425 | status = rpc_call_sync(client, &msg, RPC_TASK_SOFT); | ||
426 | |||
427 | if (status) | ||
428 | goto out_release_client; | ||
429 | |||
430 | cb->cb_client = client; | ||
431 | atomic_set(&cb->cb_set, 1); | ||
432 | put_nfs4_client(clp); | ||
433 | return 0; | ||
434 | out_release_client: | ||
435 | rpc_shutdown_client(client); | ||
436 | out_err: | ||
437 | dprintk("NFSD: warning: no callback path to client %.*s: error %d\n", | ||
438 | (int)clp->cl_name.len, clp->cl_name.data, status); | ||
439 | put_nfs4_client(clp); | ||
440 | return 0; | ||
441 | } | 482 | } |
442 | 483 | ||
443 | /* | 484 | /* |
@@ -446,21 +487,65 @@ out_err: | |||
446 | void | 487 | void |
447 | nfsd4_probe_callback(struct nfs4_client *clp) | 488 | nfsd4_probe_callback(struct nfs4_client *clp) |
448 | { | 489 | { |
449 | struct task_struct *t; | 490 | int status; |
450 | 491 | ||
451 | BUG_ON(atomic_read(&clp->cl_callback.cb_set)); | 492 | BUG_ON(atomic_read(&clp->cl_cb_conn.cb_set)); |
493 | |||
494 | status = setup_callback_client(clp); | ||
495 | if (status) { | ||
496 | warn_no_callback_path(clp, status); | ||
497 | return; | ||
498 | } | ||
452 | 499 | ||
453 | /* the task holds a reference to the nfs4_client struct */ | 500 | /* the task holds a reference to the nfs4_client struct */ |
454 | atomic_inc(&clp->cl_count); | 501 | atomic_inc(&clp->cl_count); |
455 | 502 | ||
456 | t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe"); | 503 | do_probe_callback(clp); |
504 | } | ||
457 | 505 | ||
458 | if (IS_ERR(t)) | 506 | static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) |
459 | atomic_dec(&clp->cl_count); | 507 | { |
508 | struct nfs4_delegation *dp = calldata; | ||
509 | struct nfs4_client *clp = dp->dl_client; | ||
460 | 510 | ||
461 | return; | 511 | switch (task->tk_status) { |
512 | case -EIO: | ||
513 | /* Network partition? */ | ||
514 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | ||
515 | warn_no_callback_path(clp, task->tk_status); | ||
516 | case -EBADHANDLE: | ||
517 | case -NFS4ERR_BAD_STATEID: | ||
518 | /* Race: client probably got cb_recall | ||
519 | * before open reply granting delegation */ | ||
520 | break; | ||
521 | default: | ||
522 | /* success, or error we can't handle */ | ||
523 | return; | ||
524 | } | ||
525 | if (dp->dl_retries--) { | ||
526 | rpc_delay(task, 2*HZ); | ||
527 | task->tk_status = 0; | ||
528 | rpc_restart_call(task); | ||
529 | } else { | ||
530 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | ||
531 | warn_no_callback_path(clp, task->tk_status); | ||
532 | } | ||
533 | } | ||
534 | |||
535 | static void nfsd4_cb_recall_release(void *calldata) | ||
536 | { | ||
537 | struct nfs4_delegation *dp = calldata; | ||
538 | struct nfs4_client *clp = dp->dl_client; | ||
539 | |||
540 | nfs4_put_delegation(dp); | ||
541 | put_nfs4_client(clp); | ||
462 | } | 542 | } |
463 | 543 | ||
544 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { | ||
545 | .rpc_call_done = nfsd4_cb_recall_done, | ||
546 | .rpc_release = nfsd4_cb_recall_release, | ||
547 | }; | ||
548 | |||
464 | /* | 549 | /* |
465 | * called with dp->dl_count inc'ed. | 550 | * called with dp->dl_count inc'ed. |
466 | */ | 551 | */ |
@@ -468,41 +553,19 @@ void | |||
468 | nfsd4_cb_recall(struct nfs4_delegation *dp) | 553 | nfsd4_cb_recall(struct nfs4_delegation *dp) |
469 | { | 554 | { |
470 | struct nfs4_client *clp = dp->dl_client; | 555 | struct nfs4_client *clp = dp->dl_client; |
471 | struct rpc_clnt *clnt = clp->cl_callback.cb_client; | 556 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; |
472 | struct nfs4_cb_recall *cbr = &dp->dl_recall; | ||
473 | struct rpc_message msg = { | 557 | struct rpc_message msg = { |
474 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], | 558 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], |
475 | .rpc_argp = cbr, | 559 | .rpc_argp = dp, |
560 | .rpc_cred = clp->cl_cb_conn.cb_cred | ||
476 | }; | 561 | }; |
477 | int retries = 1; | 562 | int status; |
478 | int status = 0; | 563 | |
479 | 564 | dp->dl_retries = 1; | |
480 | cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ | 565 | status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, |
481 | cbr->cbr_dp = dp; | 566 | &nfsd4_cb_recall_ops, dp); |
482 | 567 | if (status) { | |
483 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); | 568 | put_nfs4_client(clp); |
484 | while (retries--) { | 569 | nfs4_put_delegation(dp); |
485 | switch (status) { | ||
486 | case -EIO: | ||
487 | /* Network partition? */ | ||
488 | atomic_set(&clp->cl_callback.cb_set, 0); | ||
489 | case -EBADHANDLE: | ||
490 | case -NFS4ERR_BAD_STATEID: | ||
491 | /* Race: client probably got cb_recall | ||
492 | * before open reply granting delegation */ | ||
493 | break; | ||
494 | default: | ||
495 | goto out_put_cred; | ||
496 | } | ||
497 | ssleep(2); | ||
498 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); | ||
499 | } | 570 | } |
500 | out_put_cred: | ||
501 | /* | ||
502 | * Success or failure, now we're either waiting for lease expiration | ||
503 | * or deleg_return. | ||
504 | */ | ||
505 | put_nfs4_client(clp); | ||
506 | nfs4_put_delegation(dp); | ||
507 | return; | ||
508 | } | 571 | } |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index b2883e9c6381..7c8801769a3c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -51,6 +51,78 @@ | |||
51 | 51 | ||
52 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 52 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
53 | 53 | ||
54 | static u32 nfsd_attrmask[] = { | ||
55 | NFSD_WRITEABLE_ATTRS_WORD0, | ||
56 | NFSD_WRITEABLE_ATTRS_WORD1, | ||
57 | NFSD_WRITEABLE_ATTRS_WORD2 | ||
58 | }; | ||
59 | |||
60 | static u32 nfsd41_ex_attrmask[] = { | ||
61 | NFSD_SUPPATTR_EXCLCREAT_WORD0, | ||
62 | NFSD_SUPPATTR_EXCLCREAT_WORD1, | ||
63 | NFSD_SUPPATTR_EXCLCREAT_WORD2 | ||
64 | }; | ||
65 | |||
66 | static __be32 | ||
67 | check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
68 | u32 *bmval, u32 *writable) | ||
69 | { | ||
70 | struct dentry *dentry = cstate->current_fh.fh_dentry; | ||
71 | struct svc_export *exp = cstate->current_fh.fh_export; | ||
72 | |||
73 | /* | ||
74 | * Check about attributes are supported by the NFSv4 server or not. | ||
75 | * According to spec, unsupported attributes return ERR_ATTRNOTSUPP. | ||
76 | */ | ||
77 | if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) || | ||
78 | (bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) || | ||
79 | (bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) | ||
80 | return nfserr_attrnotsupp; | ||
81 | |||
82 | /* | ||
83 | * Check FATTR4_WORD0_ACL & FATTR4_WORD0_FS_LOCATIONS can be supported | ||
84 | * in current environment or not. | ||
85 | */ | ||
86 | if (bmval[0] & FATTR4_WORD0_ACL) { | ||
87 | if (!IS_POSIXACL(dentry->d_inode)) | ||
88 | return nfserr_attrnotsupp; | ||
89 | } | ||
90 | if (bmval[0] & FATTR4_WORD0_FS_LOCATIONS) { | ||
91 | if (exp->ex_fslocs.locations == NULL) | ||
92 | return nfserr_attrnotsupp; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * According to spec, read-only attributes return ERR_INVAL. | ||
97 | */ | ||
98 | if (writable) { | ||
99 | if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) || | ||
100 | (bmval[2] & ~writable[2])) | ||
101 | return nfserr_inval; | ||
102 | } | ||
103 | |||
104 | return nfs_ok; | ||
105 | } | ||
106 | |||
107 | static __be32 | ||
108 | nfsd4_check_open_attributes(struct svc_rqst *rqstp, | ||
109 | struct nfsd4_compound_state *cstate, struct nfsd4_open *open) | ||
110 | { | ||
111 | __be32 status = nfs_ok; | ||
112 | |||
113 | if (open->op_create == NFS4_OPEN_CREATE) { | ||
114 | if (open->op_createmode == NFS4_CREATE_UNCHECKED | ||
115 | || open->op_createmode == NFS4_CREATE_GUARDED) | ||
116 | status = check_attr_support(rqstp, cstate, | ||
117 | open->op_bmval, nfsd_attrmask); | ||
118 | else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1) | ||
119 | status = check_attr_support(rqstp, cstate, | ||
120 | open->op_bmval, nfsd41_ex_attrmask); | ||
121 | } | ||
122 | |||
123 | return status; | ||
124 | } | ||
125 | |||
54 | static inline void | 126 | static inline void |
55 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) | 127 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) |
56 | { | 128 | { |
@@ -225,6 +297,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
225 | if (status) | 297 | if (status) |
226 | goto out; | 298 | goto out; |
227 | 299 | ||
300 | status = nfsd4_check_open_attributes(rqstp, cstate, open); | ||
301 | if (status) | ||
302 | goto out; | ||
303 | |||
228 | /* Openowner is now set, so sequence id will get bumped. Now we need | 304 | /* Openowner is now set, so sequence id will get bumped. Now we need |
229 | * these checks before we do any creates: */ | 305 | * these checks before we do any creates: */ |
230 | status = nfserr_grace; | 306 | status = nfserr_grace; |
@@ -395,6 +471,11 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
395 | if (status) | 471 | if (status) |
396 | return status; | 472 | return status; |
397 | 473 | ||
474 | status = check_attr_support(rqstp, cstate, create->cr_bmval, | ||
475 | nfsd_attrmask); | ||
476 | if (status) | ||
477 | return status; | ||
478 | |||
398 | switch (create->cr_type) { | 479 | switch (create->cr_type) { |
399 | case NF4LNK: | 480 | case NF4LNK: |
400 | /* ugh! we have to null-terminate the linktext, or | 481 | /* ugh! we have to null-terminate the linktext, or |
@@ -689,6 +770,12 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
689 | if (status) | 770 | if (status) |
690 | return status; | 771 | return status; |
691 | status = nfs_ok; | 772 | status = nfs_ok; |
773 | |||
774 | status = check_attr_support(rqstp, cstate, setattr->sa_bmval, | ||
775 | nfsd_attrmask); | ||
776 | if (status) | ||
777 | goto out; | ||
778 | |||
692 | if (setattr->sa_acl != NULL) | 779 | if (setattr->sa_acl != NULL) |
693 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, | 780 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, |
694 | setattr->sa_acl); | 781 | setattr->sa_acl); |
@@ -763,10 +850,10 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
763 | if (status) | 850 | if (status) |
764 | return status; | 851 | return status; |
765 | 852 | ||
766 | if ((verify->ve_bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) | 853 | status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL); |
767 | || (verify->ve_bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) | 854 | if (status) |
768 | || (verify->ve_bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) | 855 | return status; |
769 | return nfserr_attrnotsupp; | 856 | |
770 | if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) | 857 | if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) |
771 | || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) | 858 | || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) |
772 | return nfserr_inval; | 859 | return nfserr_inval; |
@@ -1226,24 +1313,9 @@ static const char *nfsd4_op_name(unsigned opnum) | |||
1226 | return "unknown_operation"; | 1313 | return "unknown_operation"; |
1227 | } | 1314 | } |
1228 | 1315 | ||
1229 | #define nfs4svc_decode_voidargs NULL | ||
1230 | #define nfs4svc_release_void NULL | ||
1231 | #define nfsd4_voidres nfsd4_voidargs | 1316 | #define nfsd4_voidres nfsd4_voidargs |
1232 | #define nfs4svc_release_compound NULL | ||
1233 | struct nfsd4_voidargs { int dummy; }; | 1317 | struct nfsd4_voidargs { int dummy; }; |
1234 | 1318 | ||
1235 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
1236 | { (svc_procfunc) nfsd4_proc_##name, \ | ||
1237 | (kxdrproc_t) nfs4svc_decode_##argt##args, \ | ||
1238 | (kxdrproc_t) nfs4svc_encode_##rest##res, \ | ||
1239 | (kxdrproc_t) nfs4svc_release_##relt, \ | ||
1240 | sizeof(struct nfsd4_##argt##args), \ | ||
1241 | sizeof(struct nfsd4_##rest##res), \ | ||
1242 | 0, \ | ||
1243 | cache, \ | ||
1244 | respsize, \ | ||
1245 | } | ||
1246 | |||
1247 | /* | 1319 | /* |
1248 | * TODO: At the present time, the NFSv4 server does not do XID caching | 1320 | * TODO: At the present time, the NFSv4 server does not do XID caching |
1249 | * of requests. Implementing XID caching would not be a serious problem, | 1321 | * of requests. Implementing XID caching would not be a serious problem, |
@@ -1255,8 +1327,23 @@ struct nfsd4_voidargs { int dummy; }; | |||
1255 | * better XID's. | 1327 | * better XID's. |
1256 | */ | 1328 | */ |
1257 | static struct svc_procedure nfsd_procedures4[2] = { | 1329 | static struct svc_procedure nfsd_procedures4[2] = { |
1258 | PROC(null, void, void, void, RC_NOCACHE, 1), | 1330 | [NFSPROC4_NULL] = { |
1259 | PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE/4) | 1331 | .pc_func = (svc_procfunc) nfsd4_proc_null, |
1332 | .pc_encode = (kxdrproc_t) nfs4svc_encode_voidres, | ||
1333 | .pc_argsize = sizeof(struct nfsd4_voidargs), | ||
1334 | .pc_ressize = sizeof(struct nfsd4_voidres), | ||
1335 | .pc_cachetype = RC_NOCACHE, | ||
1336 | .pc_xdrressize = 1, | ||
1337 | }, | ||
1338 | [NFSPROC4_COMPOUND] = { | ||
1339 | .pc_func = (svc_procfunc) nfsd4_proc_compound, | ||
1340 | .pc_decode = (kxdrproc_t) nfs4svc_decode_compoundargs, | ||
1341 | .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres, | ||
1342 | .pc_argsize = sizeof(struct nfsd4_compoundargs), | ||
1343 | .pc_ressize = sizeof(struct nfsd4_compoundres), | ||
1344 | .pc_cachetype = RC_NOCACHE, | ||
1345 | .pc_xdrressize = NFSD_BUFSIZE/4, | ||
1346 | }, | ||
1260 | }; | 1347 | }; |
1261 | 1348 | ||
1262 | struct svc_version nfsd_version4 = { | 1349 | struct svc_version nfsd_version4 = { |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3b711f5147a7..980a216a48c8 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -182,7 +182,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
182 | { | 182 | { |
183 | struct nfs4_delegation *dp; | 183 | struct nfs4_delegation *dp; |
184 | struct nfs4_file *fp = stp->st_file; | 184 | struct nfs4_file *fp = stp->st_file; |
185 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; | 185 | struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn; |
186 | 186 | ||
187 | dprintk("NFSD alloc_init_deleg\n"); | 187 | dprintk("NFSD alloc_init_deleg\n"); |
188 | if (fp->fi_had_conflict) | 188 | if (fp->fi_had_conflict) |
@@ -203,10 +203,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
203 | get_file(stp->st_vfs_file); | 203 | get_file(stp->st_vfs_file); |
204 | dp->dl_vfs_file = stp->st_vfs_file; | 204 | dp->dl_vfs_file = stp->st_vfs_file; |
205 | dp->dl_type = type; | 205 | dp->dl_type = type; |
206 | dp->dl_recall.cbr_dp = NULL; | 206 | dp->dl_ident = cb->cb_ident; |
207 | dp->dl_recall.cbr_ident = cb->cb_ident; | 207 | dp->dl_stateid.si_boot = get_seconds(); |
208 | dp->dl_recall.cbr_trunc = 0; | ||
209 | dp->dl_stateid.si_boot = boot_time; | ||
210 | dp->dl_stateid.si_stateownerid = current_delegid++; | 208 | dp->dl_stateid.si_stateownerid = current_delegid++; |
211 | dp->dl_stateid.si_fileid = 0; | 209 | dp->dl_stateid.si_fileid = 0; |
212 | dp->dl_stateid.si_generation = 0; | 210 | dp->dl_stateid.si_generation = 0; |
@@ -427,6 +425,11 @@ static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan) | |||
427 | { | 425 | { |
428 | int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT; | 426 | int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT; |
429 | 427 | ||
428 | if (fchan->maxreqs < 1) | ||
429 | return nfserr_inval; | ||
430 | else if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
431 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
432 | |||
430 | spin_lock(&nfsd_serv->sv_lock); | 433 | spin_lock(&nfsd_serv->sv_lock); |
431 | if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages) | 434 | if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages) |
432 | np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used; | 435 | np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used; |
@@ -446,8 +449,8 @@ static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan) | |||
446 | * fchan holds the client values on input, and the server values on output | 449 | * fchan holds the client values on input, and the server values on output |
447 | */ | 450 | */ |
448 | static int init_forechannel_attrs(struct svc_rqst *rqstp, | 451 | static int init_forechannel_attrs(struct svc_rqst *rqstp, |
449 | struct nfsd4_session *session, | 452 | struct nfsd4_channel_attrs *session_fchan, |
450 | struct nfsd4_channel_attrs *fchan) | 453 | struct nfsd4_channel_attrs *fchan) |
451 | { | 454 | { |
452 | int status = 0; | 455 | int status = 0; |
453 | __u32 maxcount = svc_max_payload(rqstp); | 456 | __u32 maxcount = svc_max_payload(rqstp); |
@@ -457,21 +460,21 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp, | |||
457 | /* Use the client's max request and max response size if possible */ | 460 | /* Use the client's max request and max response size if possible */ |
458 | if (fchan->maxreq_sz > maxcount) | 461 | if (fchan->maxreq_sz > maxcount) |
459 | fchan->maxreq_sz = maxcount; | 462 | fchan->maxreq_sz = maxcount; |
460 | session->se_fmaxreq_sz = fchan->maxreq_sz; | 463 | session_fchan->maxreq_sz = fchan->maxreq_sz; |
461 | 464 | ||
462 | if (fchan->maxresp_sz > maxcount) | 465 | if (fchan->maxresp_sz > maxcount) |
463 | fchan->maxresp_sz = maxcount; | 466 | fchan->maxresp_sz = maxcount; |
464 | session->se_fmaxresp_sz = fchan->maxresp_sz; | 467 | session_fchan->maxresp_sz = fchan->maxresp_sz; |
465 | 468 | ||
466 | /* Set the max response cached size our default which is | 469 | /* Set the max response cached size our default which is |
467 | * a multiple of PAGE_SIZE and small */ | 470 | * a multiple of PAGE_SIZE and small */ |
468 | session->se_fmaxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE; | 471 | session_fchan->maxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE; |
469 | fchan->maxresp_cached = session->se_fmaxresp_cached; | 472 | fchan->maxresp_cached = session_fchan->maxresp_cached; |
470 | 473 | ||
471 | /* Use the client's maxops if possible */ | 474 | /* Use the client's maxops if possible */ |
472 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) | 475 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) |
473 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; | 476 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; |
474 | session->se_fmaxops = fchan->maxops; | 477 | session_fchan->maxops = fchan->maxops; |
475 | 478 | ||
476 | /* try to use the client requested number of slots */ | 479 | /* try to use the client requested number of slots */ |
477 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | 480 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) |
@@ -483,7 +486,7 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp, | |||
483 | */ | 486 | */ |
484 | status = set_forechannel_maxreqs(fchan); | 487 | status = set_forechannel_maxreqs(fchan); |
485 | 488 | ||
486 | session->se_fnumslots = fchan->maxreqs; | 489 | session_fchan->maxreqs = fchan->maxreqs; |
487 | return status; | 490 | return status; |
488 | } | 491 | } |
489 | 492 | ||
@@ -497,12 +500,14 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
497 | memset(&tmp, 0, sizeof(tmp)); | 500 | memset(&tmp, 0, sizeof(tmp)); |
498 | 501 | ||
499 | /* FIXME: For now, we just accept the client back channel attributes. */ | 502 | /* FIXME: For now, we just accept the client back channel attributes. */ |
500 | status = init_forechannel_attrs(rqstp, &tmp, &cses->fore_channel); | 503 | tmp.se_bchannel = cses->back_channel; |
504 | status = init_forechannel_attrs(rqstp, &tmp.se_fchannel, | ||
505 | &cses->fore_channel); | ||
501 | if (status) | 506 | if (status) |
502 | goto out; | 507 | goto out; |
503 | 508 | ||
504 | /* allocate struct nfsd4_session and slot table in one piece */ | 509 | /* allocate struct nfsd4_session and slot table in one piece */ |
505 | slotsize = tmp.se_fnumslots * sizeof(struct nfsd4_slot); | 510 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot); |
506 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); | 511 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); |
507 | if (!new) | 512 | if (!new) |
508 | goto out; | 513 | goto out; |
@@ -576,7 +581,7 @@ free_session(struct kref *kref) | |||
576 | int i; | 581 | int i; |
577 | 582 | ||
578 | ses = container_of(kref, struct nfsd4_session, se_ref); | 583 | ses = container_of(kref, struct nfsd4_session, se_ref); |
579 | for (i = 0; i < ses->se_fnumslots; i++) { | 584 | for (i = 0; i < ses->se_fchannel.maxreqs; i++) { |
580 | struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry; | 585 | struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry; |
581 | nfsd4_release_respages(e->ce_respages, e->ce_resused); | 586 | nfsd4_release_respages(e->ce_respages, e->ce_resused); |
582 | } | 587 | } |
@@ -632,16 +637,20 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
632 | static void | 637 | static void |
633 | shutdown_callback_client(struct nfs4_client *clp) | 638 | shutdown_callback_client(struct nfs4_client *clp) |
634 | { | 639 | { |
635 | struct rpc_clnt *clnt = clp->cl_callback.cb_client; | 640 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; |
636 | 641 | ||
637 | if (clnt) { | 642 | if (clnt) { |
638 | /* | 643 | /* |
639 | * Callback threads take a reference on the client, so there | 644 | * Callback threads take a reference on the client, so there |
640 | * should be no outstanding callbacks at this point. | 645 | * should be no outstanding callbacks at this point. |
641 | */ | 646 | */ |
642 | clp->cl_callback.cb_client = NULL; | 647 | clp->cl_cb_conn.cb_client = NULL; |
643 | rpc_shutdown_client(clnt); | 648 | rpc_shutdown_client(clnt); |
644 | } | 649 | } |
650 | if (clp->cl_cb_conn.cb_cred) { | ||
651 | put_rpccred(clp->cl_cb_conn.cb_cred); | ||
652 | clp->cl_cb_conn.cb_cred = NULL; | ||
653 | } | ||
645 | } | 654 | } |
646 | 655 | ||
647 | static inline void | 656 | static inline void |
@@ -714,7 +723,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir) | |||
714 | return NULL; | 723 | return NULL; |
715 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 724 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
716 | atomic_set(&clp->cl_count, 1); | 725 | atomic_set(&clp->cl_count, 1); |
717 | atomic_set(&clp->cl_callback.cb_set, 0); | 726 | atomic_set(&clp->cl_cb_conn.cb_set, 0); |
718 | INIT_LIST_HEAD(&clp->cl_idhash); | 727 | INIT_LIST_HEAD(&clp->cl_idhash); |
719 | INIT_LIST_HEAD(&clp->cl_strhash); | 728 | INIT_LIST_HEAD(&clp->cl_strhash); |
720 | INIT_LIST_HEAD(&clp->cl_openowners); | 729 | INIT_LIST_HEAD(&clp->cl_openowners); |
@@ -966,7 +975,7 @@ parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigne | |||
966 | static void | 975 | static void |
967 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | 976 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) |
968 | { | 977 | { |
969 | struct nfs4_callback *cb = &clp->cl_callback; | 978 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
970 | 979 | ||
971 | /* Currently, we only support tcp for the callback channel */ | 980 | /* Currently, we only support tcp for the callback channel */ |
972 | if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3)) | 981 | if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3)) |
@@ -975,6 +984,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | |||
975 | if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val, | 984 | if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val, |
976 | &cb->cb_addr, &cb->cb_port))) | 985 | &cb->cb_addr, &cb->cb_port))) |
977 | goto out_err; | 986 | goto out_err; |
987 | cb->cb_minorversion = 0; | ||
978 | cb->cb_prog = se->se_callback_prog; | 988 | cb->cb_prog = se->se_callback_prog; |
979 | cb->cb_ident = se->se_callback_ident; | 989 | cb->cb_ident = se->se_callback_ident; |
980 | return; | 990 | return; |
@@ -1128,7 +1138,7 @@ nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | |||
1128 | * is sent (lease renewal). | 1138 | * is sent (lease renewal). |
1129 | */ | 1139 | */ |
1130 | if (seq && nfsd4_not_cached(resp)) { | 1140 | if (seq && nfsd4_not_cached(resp)) { |
1131 | seq->maxslots = resp->cstate.session->se_fnumslots; | 1141 | seq->maxslots = resp->cstate.session->se_fchannel.maxreqs; |
1132 | return nfs_ok; | 1142 | return nfs_ok; |
1133 | } | 1143 | } |
1134 | 1144 | ||
@@ -1238,12 +1248,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1238 | expire_client(conf); | 1248 | expire_client(conf); |
1239 | goto out_new; | 1249 | goto out_new; |
1240 | } | 1250 | } |
1241 | if (ip_addr != conf->cl_addr && | ||
1242 | !(exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A)) { | ||
1243 | /* Client collision. 18.35.4 case 3 */ | ||
1244 | status = nfserr_clid_inuse; | ||
1245 | goto out; | ||
1246 | } | ||
1247 | /* | 1251 | /* |
1248 | * Set bit when the owner id and verifier map to an already | 1252 | * Set bit when the owner id and verifier map to an already |
1249 | * confirmed client id (18.35.3). | 1253 | * confirmed client id (18.35.3). |
@@ -1257,12 +1261,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1257 | copy_verf(conf, &verf); | 1261 | copy_verf(conf, &verf); |
1258 | new = conf; | 1262 | new = conf; |
1259 | goto out_copy; | 1263 | goto out_copy; |
1260 | } else { | 1264 | } |
1261 | /* 18.35.4 case 7 */ | 1265 | |
1262 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1266 | /* 18.35.4 case 7 */ |
1263 | status = nfserr_noent; | 1267 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { |
1264 | goto out; | 1268 | status = nfserr_noent; |
1265 | } | 1269 | goto out; |
1266 | } | 1270 | } |
1267 | 1271 | ||
1268 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); | 1272 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); |
@@ -1471,7 +1475,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1471 | goto out; | 1475 | goto out; |
1472 | 1476 | ||
1473 | status = nfserr_badslot; | 1477 | status = nfserr_badslot; |
1474 | if (seq->slotid >= session->se_fnumslots) | 1478 | if (seq->slotid >= session->se_fchannel.maxreqs) |
1475 | goto out; | 1479 | goto out; |
1476 | 1480 | ||
1477 | slot = &session->se_slots[seq->slotid]; | 1481 | slot = &session->se_slots[seq->slotid]; |
@@ -1686,9 +1690,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1686 | else { | 1690 | else { |
1687 | /* XXX: We just turn off callbacks until we can handle | 1691 | /* XXX: We just turn off callbacks until we can handle |
1688 | * change request correctly. */ | 1692 | * change request correctly. */ |
1689 | atomic_set(&conf->cl_callback.cb_set, 0); | 1693 | atomic_set(&conf->cl_cb_conn.cb_set, 0); |
1690 | gen_confirm(conf); | ||
1691 | nfsd4_remove_clid_dir(unconf); | ||
1692 | expire_client(unconf); | 1694 | expire_client(unconf); |
1693 | status = nfs_ok; | 1695 | status = nfs_ok; |
1694 | 1696 | ||
@@ -1882,7 +1884,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open * | |||
1882 | stp->st_stateowner = sop; | 1884 | stp->st_stateowner = sop; |
1883 | get_nfs4_file(fp); | 1885 | get_nfs4_file(fp); |
1884 | stp->st_file = fp; | 1886 | stp->st_file = fp; |
1885 | stp->st_stateid.si_boot = boot_time; | 1887 | stp->st_stateid.si_boot = get_seconds(); |
1886 | stp->st_stateid.si_stateownerid = sop->so_id; | 1888 | stp->st_stateid.si_stateownerid = sop->so_id; |
1887 | stp->st_stateid.si_fileid = fp->fi_id; | 1889 | stp->st_stateid.si_fileid = fp->fi_id; |
1888 | stp->st_stateid.si_generation = 0; | 1890 | stp->st_stateid.si_generation = 0; |
@@ -2059,19 +2061,6 @@ nfs4_file_downgrade(struct file *filp, unsigned int share_access) | |||
2059 | } | 2061 | } |
2060 | 2062 | ||
2061 | /* | 2063 | /* |
2062 | * Recall a delegation | ||
2063 | */ | ||
2064 | static int | ||
2065 | do_recall(void *__dp) | ||
2066 | { | ||
2067 | struct nfs4_delegation *dp = __dp; | ||
2068 | |||
2069 | dp->dl_file->fi_had_conflict = true; | ||
2070 | nfsd4_cb_recall(dp); | ||
2071 | return 0; | ||
2072 | } | ||
2073 | |||
2074 | /* | ||
2075 | * Spawn a thread to perform a recall on the delegation represented | 2064 | * Spawn a thread to perform a recall on the delegation represented |
2076 | * by the lease (file_lock) | 2065 | * by the lease (file_lock) |
2077 | * | 2066 | * |
@@ -2082,8 +2071,7 @@ do_recall(void *__dp) | |||
2082 | static | 2071 | static |
2083 | void nfsd_break_deleg_cb(struct file_lock *fl) | 2072 | void nfsd_break_deleg_cb(struct file_lock *fl) |
2084 | { | 2073 | { |
2085 | struct nfs4_delegation *dp= (struct nfs4_delegation *)fl->fl_owner; | 2074 | struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; |
2086 | struct task_struct *t; | ||
2087 | 2075 | ||
2088 | dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); | 2076 | dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); |
2089 | if (!dp) | 2077 | if (!dp) |
@@ -2111,16 +2099,8 @@ void nfsd_break_deleg_cb(struct file_lock *fl) | |||
2111 | */ | 2099 | */ |
2112 | fl->fl_break_time = 0; | 2100 | fl->fl_break_time = 0; |
2113 | 2101 | ||
2114 | t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall"); | 2102 | dp->dl_file->fi_had_conflict = true; |
2115 | if (IS_ERR(t)) { | 2103 | nfsd4_cb_recall(dp); |
2116 | struct nfs4_client *clp = dp->dl_client; | ||
2117 | |||
2118 | printk(KERN_INFO "NFSD: Callback thread failed for " | ||
2119 | "for client (clientid %08x/%08x)\n", | ||
2120 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | ||
2121 | put_nfs4_client(dp->dl_client); | ||
2122 | nfs4_put_delegation(dp); | ||
2123 | } | ||
2124 | } | 2104 | } |
2125 | 2105 | ||
2126 | /* | 2106 | /* |
@@ -2422,7 +2402,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2422 | { | 2402 | { |
2423 | struct nfs4_delegation *dp; | 2403 | struct nfs4_delegation *dp; |
2424 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2404 | struct nfs4_stateowner *sop = stp->st_stateowner; |
2425 | struct nfs4_callback *cb = &sop->so_client->cl_callback; | 2405 | struct nfs4_cb_conn *cb = &sop->so_client->cl_cb_conn; |
2426 | struct file_lock fl, *flp = &fl; | 2406 | struct file_lock fl, *flp = &fl; |
2427 | int status, flag = 0; | 2407 | int status, flag = 0; |
2428 | 2408 | ||
@@ -2614,7 +2594,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2614 | renew_client(clp); | 2594 | renew_client(clp); |
2615 | status = nfserr_cb_path_down; | 2595 | status = nfserr_cb_path_down; |
2616 | if (!list_empty(&clp->cl_delegations) | 2596 | if (!list_empty(&clp->cl_delegations) |
2617 | && !atomic_read(&clp->cl_callback.cb_set)) | 2597 | && !atomic_read(&clp->cl_cb_conn.cb_set)) |
2618 | goto out; | 2598 | goto out; |
2619 | status = nfs_ok; | 2599 | status = nfs_ok; |
2620 | out: | 2600 | out: |
@@ -2738,12 +2718,42 @@ nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | |||
2738 | static int | 2718 | static int |
2739 | STALE_STATEID(stateid_t *stateid) | 2719 | STALE_STATEID(stateid_t *stateid) |
2740 | { | 2720 | { |
2741 | if (stateid->si_boot == boot_time) | 2721 | if (time_after((unsigned long)boot_time, |
2742 | return 0; | 2722 | (unsigned long)stateid->si_boot)) { |
2743 | dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", | 2723 | dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", |
2744 | stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, | 2724 | stateid->si_boot, stateid->si_stateownerid, |
2745 | stateid->si_generation); | 2725 | stateid->si_fileid, stateid->si_generation); |
2746 | return 1; | 2726 | return 1; |
2727 | } | ||
2728 | return 0; | ||
2729 | } | ||
2730 | |||
2731 | static int | ||
2732 | EXPIRED_STATEID(stateid_t *stateid) | ||
2733 | { | ||
2734 | if (time_before((unsigned long)boot_time, | ||
2735 | ((unsigned long)stateid->si_boot)) && | ||
2736 | time_before((unsigned long)(stateid->si_boot + lease_time), get_seconds())) { | ||
2737 | dprintk("NFSD: expired stateid (%08x/%08x/%08x/%08x)!\n", | ||
2738 | stateid->si_boot, stateid->si_stateownerid, | ||
2739 | stateid->si_fileid, stateid->si_generation); | ||
2740 | return 1; | ||
2741 | } | ||
2742 | return 0; | ||
2743 | } | ||
2744 | |||
2745 | static __be32 | ||
2746 | stateid_error_map(stateid_t *stateid) | ||
2747 | { | ||
2748 | if (STALE_STATEID(stateid)) | ||
2749 | return nfserr_stale_stateid; | ||
2750 | if (EXPIRED_STATEID(stateid)) | ||
2751 | return nfserr_expired; | ||
2752 | |||
2753 | dprintk("NFSD: bad stateid (%08x/%08x/%08x/%08x)!\n", | ||
2754 | stateid->si_boot, stateid->si_stateownerid, | ||
2755 | stateid->si_fileid, stateid->si_generation); | ||
2756 | return nfserr_bad_stateid; | ||
2747 | } | 2757 | } |
2748 | 2758 | ||
2749 | static inline int | 2759 | static inline int |
@@ -2867,8 +2877,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2867 | status = nfserr_bad_stateid; | 2877 | status = nfserr_bad_stateid; |
2868 | if (is_delegation_stateid(stateid)) { | 2878 | if (is_delegation_stateid(stateid)) { |
2869 | dp = find_delegation_stateid(ino, stateid); | 2879 | dp = find_delegation_stateid(ino, stateid); |
2870 | if (!dp) | 2880 | if (!dp) { |
2881 | status = stateid_error_map(stateid); | ||
2871 | goto out; | 2882 | goto out; |
2883 | } | ||
2872 | status = check_stateid_generation(stateid, &dp->dl_stateid, | 2884 | status = check_stateid_generation(stateid, &dp->dl_stateid, |
2873 | flags); | 2885 | flags); |
2874 | if (status) | 2886 | if (status) |
@@ -2881,8 +2893,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2881 | *filpp = dp->dl_vfs_file; | 2893 | *filpp = dp->dl_vfs_file; |
2882 | } else { /* open or lock stateid */ | 2894 | } else { /* open or lock stateid */ |
2883 | stp = find_stateid(stateid, flags); | 2895 | stp = find_stateid(stateid, flags); |
2884 | if (!stp) | 2896 | if (!stp) { |
2897 | status = stateid_error_map(stateid); | ||
2885 | goto out; | 2898 | goto out; |
2899 | } | ||
2886 | if (nfs4_check_fh(current_fh, stp)) | 2900 | if (nfs4_check_fh(current_fh, stp)) |
2887 | goto out; | 2901 | goto out; |
2888 | if (!stp->st_stateowner->so_confirmed) | 2902 | if (!stp->st_stateowner->so_confirmed) |
@@ -2956,7 +2970,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
2956 | */ | 2970 | */ |
2957 | sop = search_close_lru(stateid->si_stateownerid, flags); | 2971 | sop = search_close_lru(stateid->si_stateownerid, flags); |
2958 | if (sop == NULL) | 2972 | if (sop == NULL) |
2959 | return nfserr_bad_stateid; | 2973 | return stateid_error_map(stateid); |
2960 | *sopp = sop; | 2974 | *sopp = sop; |
2961 | goto check_replay; | 2975 | goto check_replay; |
2962 | } | 2976 | } |
@@ -3227,8 +3241,10 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3227 | if (!is_delegation_stateid(stateid)) | 3241 | if (!is_delegation_stateid(stateid)) |
3228 | goto out; | 3242 | goto out; |
3229 | dp = find_delegation_stateid(inode, stateid); | 3243 | dp = find_delegation_stateid(inode, stateid); |
3230 | if (!dp) | 3244 | if (!dp) { |
3245 | status = stateid_error_map(stateid); | ||
3231 | goto out; | 3246 | goto out; |
3247 | } | ||
3232 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); | 3248 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); |
3233 | if (status) | 3249 | if (status) |
3234 | goto out; | 3250 | goto out; |
@@ -3455,7 +3471,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3455 | stp->st_stateowner = sop; | 3471 | stp->st_stateowner = sop; |
3456 | get_nfs4_file(fp); | 3472 | get_nfs4_file(fp); |
3457 | stp->st_file = fp; | 3473 | stp->st_file = fp; |
3458 | stp->st_stateid.si_boot = boot_time; | 3474 | stp->st_stateid.si_boot = get_seconds(); |
3459 | stp->st_stateid.si_stateownerid = sop->so_id; | 3475 | stp->st_stateid.si_stateownerid = sop->so_id; |
3460 | stp->st_stateid.si_fileid = fp->fi_id; | 3476 | stp->st_stateid.si_fileid = fp->fi_id; |
3461 | stp->st_stateid.si_generation = 0; | 3477 | stp->st_stateid.si_generation = 0; |
@@ -3987,6 +4003,7 @@ nfs4_state_init(void) | |||
3987 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); | 4003 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); |
3988 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); | 4004 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); |
3989 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); | 4005 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); |
4006 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
3990 | } | 4007 | } |
3991 | for (i = 0; i < SESSION_HASH_SIZE; i++) | 4008 | for (i = 0; i < SESSION_HASH_SIZE; i++) |
3992 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); | 4009 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); |
@@ -4009,8 +4026,6 @@ nfs4_state_init(void) | |||
4009 | INIT_LIST_HEAD(&close_lru); | 4026 | INIT_LIST_HEAD(&close_lru); |
4010 | INIT_LIST_HEAD(&client_lru); | 4027 | INIT_LIST_HEAD(&client_lru); |
4011 | INIT_LIST_HEAD(&del_recall_lru); | 4028 | INIT_LIST_HEAD(&del_recall_lru); |
4012 | for (i = 0; i < CLIENT_HASH_SIZE; i++) | ||
4013 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
4014 | reclaim_str_hashtbl_size = 0; | 4029 | reclaim_str_hashtbl_size = 0; |
4015 | return 0; | 4030 | return 0; |
4016 | } | 4031 | } |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b73549d293be..2dcc7feaa6ff 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -83,16 +83,6 @@ check_filename(char *str, int len, __be32 err) | |||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | /* | ||
87 | * START OF "GENERIC" DECODE ROUTINES. | ||
88 | * These may look a little ugly since they are imported from a "generic" | ||
89 | * set of XDR encode/decode routines which are intended to be shared by | ||
90 | * all of our NFSv4 implementations (OpenBSD, MacOS X...). | ||
91 | * | ||
92 | * If the pain of reading these is too great, it should be a straightforward | ||
93 | * task to translate them into Linux-specific versions which are more | ||
94 | * consistent with the style used in NFSv2/v3... | ||
95 | */ | ||
96 | #define DECODE_HEAD \ | 86 | #define DECODE_HEAD \ |
97 | __be32 *p; \ | 87 | __be32 *p; \ |
98 | __be32 status | 88 | __be32 status |
@@ -254,20 +244,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) | |||
254 | DECODE_TAIL; | 244 | DECODE_TAIL; |
255 | } | 245 | } |
256 | 246 | ||
257 | static u32 nfsd_attrmask[] = { | ||
258 | NFSD_WRITEABLE_ATTRS_WORD0, | ||
259 | NFSD_WRITEABLE_ATTRS_WORD1, | ||
260 | NFSD_WRITEABLE_ATTRS_WORD2 | ||
261 | }; | ||
262 | |||
263 | static u32 nfsd41_ex_attrmask[] = { | ||
264 | NFSD_SUPPATTR_EXCLCREAT_WORD0, | ||
265 | NFSD_SUPPATTR_EXCLCREAT_WORD1, | ||
266 | NFSD_SUPPATTR_EXCLCREAT_WORD2 | ||
267 | }; | ||
268 | |||
269 | static __be32 | 247 | static __be32 |
270 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | 248 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, |
271 | struct iattr *iattr, struct nfs4_acl **acl) | 249 | struct iattr *iattr, struct nfs4_acl **acl) |
272 | { | 250 | { |
273 | int expected_len, len = 0; | 251 | int expected_len, len = 0; |
@@ -280,18 +258,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | |||
280 | if ((status = nfsd4_decode_bitmap(argp, bmval))) | 258 | if ((status = nfsd4_decode_bitmap(argp, bmval))) |
281 | return status; | 259 | return status; |
282 | 260 | ||
283 | /* | ||
284 | * According to spec, unsupported attributes return ERR_ATTRNOTSUPP; | ||
285 | * read-only attributes return ERR_INVAL. | ||
286 | */ | ||
287 | if ((bmval[0] & ~nfsd_suppattrs0(argp->minorversion)) || | ||
288 | (bmval[1] & ~nfsd_suppattrs1(argp->minorversion)) || | ||
289 | (bmval[2] & ~nfsd_suppattrs2(argp->minorversion))) | ||
290 | return nfserr_attrnotsupp; | ||
291 | if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) || | ||
292 | (bmval[2] & ~writable[2])) | ||
293 | return nfserr_inval; | ||
294 | |||
295 | READ_BUF(4); | 261 | READ_BUF(4); |
296 | READ32(expected_len); | 262 | READ32(expected_len); |
297 | 263 | ||
@@ -424,8 +390,11 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | |||
424 | goto xdr_error; | 390 | goto xdr_error; |
425 | } | 391 | } |
426 | } | 392 | } |
427 | BUG_ON(bmval[2]); /* no such writeable attr supported yet */ | 393 | if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 |
428 | if (len != expected_len) | 394 | || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 |
395 | || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) | ||
396 | READ_BUF(expected_len - len); | ||
397 | else if (len != expected_len) | ||
429 | goto xdr_error; | 398 | goto xdr_error; |
430 | 399 | ||
431 | DECODE_TAIL; | 400 | DECODE_TAIL; |
@@ -518,8 +487,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create | |||
518 | if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) | 487 | if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) |
519 | return status; | 488 | return status; |
520 | 489 | ||
521 | status = nfsd4_decode_fattr(argp, create->cr_bmval, nfsd_attrmask, | 490 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, |
522 | &create->cr_iattr, &create->cr_acl); | 491 | &create->cr_acl); |
523 | if (status) | 492 | if (status) |
524 | goto out; | 493 | goto out; |
525 | 494 | ||
@@ -682,7 +651,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
682 | case NFS4_CREATE_UNCHECKED: | 651 | case NFS4_CREATE_UNCHECKED: |
683 | case NFS4_CREATE_GUARDED: | 652 | case NFS4_CREATE_GUARDED: |
684 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 653 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
685 | nfsd_attrmask, &open->op_iattr, &open->op_acl); | 654 | &open->op_iattr, &open->op_acl); |
686 | if (status) | 655 | if (status) |
687 | goto out; | 656 | goto out; |
688 | break; | 657 | break; |
@@ -696,8 +665,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
696 | READ_BUF(8); | 665 | READ_BUF(8); |
697 | COPYMEM(open->op_verf.data, 8); | 666 | COPYMEM(open->op_verf.data, 8); |
698 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 667 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
699 | nfsd41_ex_attrmask, &open->op_iattr, | 668 | &open->op_iattr, &open->op_acl); |
700 | &open->op_acl); | ||
701 | if (status) | 669 | if (status) |
702 | goto out; | 670 | goto out; |
703 | break; | 671 | break; |
@@ -893,8 +861,8 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta | |||
893 | status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); | 861 | status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); |
894 | if (status) | 862 | if (status) |
895 | return status; | 863 | return status; |
896 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, nfsd_attrmask, | 864 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, |
897 | &setattr->sa_iattr, &setattr->sa_acl); | 865 | &setattr->sa_acl); |
898 | } | 866 | } |
899 | 867 | ||
900 | static __be32 | 868 | static __be32 |
@@ -1328,64 +1296,64 @@ static nfsd4_dec nfsd4_dec_ops[] = { | |||
1328 | }; | 1296 | }; |
1329 | 1297 | ||
1330 | static nfsd4_dec nfsd41_dec_ops[] = { | 1298 | static nfsd4_dec nfsd41_dec_ops[] = { |
1331 | [OP_ACCESS] (nfsd4_dec)nfsd4_decode_access, | 1299 | [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, |
1332 | [OP_CLOSE] (nfsd4_dec)nfsd4_decode_close, | 1300 | [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, |
1333 | [OP_COMMIT] (nfsd4_dec)nfsd4_decode_commit, | 1301 | [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, |
1334 | [OP_CREATE] (nfsd4_dec)nfsd4_decode_create, | 1302 | [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, |
1335 | [OP_DELEGPURGE] (nfsd4_dec)nfsd4_decode_notsupp, | 1303 | [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, |
1336 | [OP_DELEGRETURN] (nfsd4_dec)nfsd4_decode_delegreturn, | 1304 | [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, |
1337 | [OP_GETATTR] (nfsd4_dec)nfsd4_decode_getattr, | 1305 | [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, |
1338 | [OP_GETFH] (nfsd4_dec)nfsd4_decode_noop, | 1306 | [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, |
1339 | [OP_LINK] (nfsd4_dec)nfsd4_decode_link, | 1307 | [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, |
1340 | [OP_LOCK] (nfsd4_dec)nfsd4_decode_lock, | 1308 | [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, |
1341 | [OP_LOCKT] (nfsd4_dec)nfsd4_decode_lockt, | 1309 | [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, |
1342 | [OP_LOCKU] (nfsd4_dec)nfsd4_decode_locku, | 1310 | [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, |
1343 | [OP_LOOKUP] (nfsd4_dec)nfsd4_decode_lookup, | 1311 | [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, |
1344 | [OP_LOOKUPP] (nfsd4_dec)nfsd4_decode_noop, | 1312 | [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, |
1345 | [OP_NVERIFY] (nfsd4_dec)nfsd4_decode_verify, | 1313 | [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, |
1346 | [OP_OPEN] (nfsd4_dec)nfsd4_decode_open, | 1314 | [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, |
1347 | [OP_OPENATTR] (nfsd4_dec)nfsd4_decode_notsupp, | 1315 | [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, |
1348 | [OP_OPEN_CONFIRM] (nfsd4_dec)nfsd4_decode_notsupp, | 1316 | [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_notsupp, |
1349 | [OP_OPEN_DOWNGRADE] (nfsd4_dec)nfsd4_decode_open_downgrade, | 1317 | [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, |
1350 | [OP_PUTFH] (nfsd4_dec)nfsd4_decode_putfh, | 1318 | [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, |
1351 | [OP_PUTPUBFH] (nfsd4_dec)nfsd4_decode_notsupp, | 1319 | [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp, |
1352 | [OP_PUTROOTFH] (nfsd4_dec)nfsd4_decode_noop, | 1320 | [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, |
1353 | [OP_READ] (nfsd4_dec)nfsd4_decode_read, | 1321 | [OP_READ] = (nfsd4_dec)nfsd4_decode_read, |
1354 | [OP_READDIR] (nfsd4_dec)nfsd4_decode_readdir, | 1322 | [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, |
1355 | [OP_READLINK] (nfsd4_dec)nfsd4_decode_noop, | 1323 | [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, |
1356 | [OP_REMOVE] (nfsd4_dec)nfsd4_decode_remove, | 1324 | [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, |
1357 | [OP_RENAME] (nfsd4_dec)nfsd4_decode_rename, | 1325 | [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, |
1358 | [OP_RENEW] (nfsd4_dec)nfsd4_decode_notsupp, | 1326 | [OP_RENEW] = (nfsd4_dec)nfsd4_decode_notsupp, |
1359 | [OP_RESTOREFH] (nfsd4_dec)nfsd4_decode_noop, | 1327 | [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, |
1360 | [OP_SAVEFH] (nfsd4_dec)nfsd4_decode_noop, | 1328 | [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, |
1361 | [OP_SECINFO] (nfsd4_dec)nfsd4_decode_secinfo, | 1329 | [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, |
1362 | [OP_SETATTR] (nfsd4_dec)nfsd4_decode_setattr, | 1330 | [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, |
1363 | [OP_SETCLIENTID] (nfsd4_dec)nfsd4_decode_notsupp, | 1331 | [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, |
1364 | [OP_SETCLIENTID_CONFIRM](nfsd4_dec)nfsd4_decode_notsupp, | 1332 | [OP_SETCLIENTID_CONFIRM]= (nfsd4_dec)nfsd4_decode_notsupp, |
1365 | [OP_VERIFY] (nfsd4_dec)nfsd4_decode_verify, | 1333 | [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, |
1366 | [OP_WRITE] (nfsd4_dec)nfsd4_decode_write, | 1334 | [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, |
1367 | [OP_RELEASE_LOCKOWNER] (nfsd4_dec)nfsd4_decode_notsupp, | 1335 | [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp, |
1368 | 1336 | ||
1369 | /* new operations for NFSv4.1 */ | 1337 | /* new operations for NFSv4.1 */ |
1370 | [OP_BACKCHANNEL_CTL] (nfsd4_dec)nfsd4_decode_notsupp, | 1338 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp, |
1371 | [OP_BIND_CONN_TO_SESSION](nfsd4_dec)nfsd4_decode_notsupp, | 1339 | [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_notsupp, |
1372 | [OP_EXCHANGE_ID] (nfsd4_dec)nfsd4_decode_exchange_id, | 1340 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, |
1373 | [OP_CREATE_SESSION] (nfsd4_dec)nfsd4_decode_create_session, | 1341 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, |
1374 | [OP_DESTROY_SESSION] (nfsd4_dec)nfsd4_decode_destroy_session, | 1342 | [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, |
1375 | [OP_FREE_STATEID] (nfsd4_dec)nfsd4_decode_notsupp, | 1343 | [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, |
1376 | [OP_GET_DIR_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp, | 1344 | [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, |
1377 | [OP_GETDEVICEINFO] (nfsd4_dec)nfsd4_decode_notsupp, | 1345 | [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, |
1378 | [OP_GETDEVICELIST] (nfsd4_dec)nfsd4_decode_notsupp, | 1346 | [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, |
1379 | [OP_LAYOUTCOMMIT] (nfsd4_dec)nfsd4_decode_notsupp, | 1347 | [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, |
1380 | [OP_LAYOUTGET] (nfsd4_dec)nfsd4_decode_notsupp, | 1348 | [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, |
1381 | [OP_LAYOUTRETURN] (nfsd4_dec)nfsd4_decode_notsupp, | 1349 | [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, |
1382 | [OP_SECINFO_NO_NAME] (nfsd4_dec)nfsd4_decode_notsupp, | 1350 | [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_notsupp, |
1383 | [OP_SEQUENCE] (nfsd4_dec)nfsd4_decode_sequence, | 1351 | [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, |
1384 | [OP_SET_SSV] (nfsd4_dec)nfsd4_decode_notsupp, | 1352 | [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, |
1385 | [OP_TEST_STATEID] (nfsd4_dec)nfsd4_decode_notsupp, | 1353 | [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, |
1386 | [OP_WANT_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp, | 1354 | [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, |
1387 | [OP_DESTROY_CLIENTID] (nfsd4_dec)nfsd4_decode_notsupp, | 1355 | [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, |
1388 | [OP_RECLAIM_COMPLETE] (nfsd4_dec)nfsd4_decode_notsupp, | 1356 | [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_notsupp, |
1389 | }; | 1357 | }; |
1390 | 1358 | ||
1391 | struct nfsd4_minorversion_ops { | 1359 | struct nfsd4_minorversion_ops { |
@@ -1489,21 +1457,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1489 | 1457 | ||
1490 | DECODE_TAIL; | 1458 | DECODE_TAIL; |
1491 | } | 1459 | } |
1492 | /* | ||
1493 | * END OF "GENERIC" DECODE ROUTINES. | ||
1494 | */ | ||
1495 | |||
1496 | /* | ||
1497 | * START OF "GENERIC" ENCODE ROUTINES. | ||
1498 | * These may look a little ugly since they are imported from a "generic" | ||
1499 | * set of XDR encode/decode routines which are intended to be shared by | ||
1500 | * all of our NFSv4 implementations (OpenBSD, MacOS X...). | ||
1501 | * | ||
1502 | * If the pain of reading these is too great, it should be a straightforward | ||
1503 | * task to translate them into Linux-specific versions which are more | ||
1504 | * consistent with the style used in NFSv2/v3... | ||
1505 | */ | ||
1506 | #define ENCODE_HEAD __be32 *p | ||
1507 | 1460 | ||
1508 | #define WRITE32(n) *p++ = htonl(n) | 1461 | #define WRITE32(n) *p++ = htonl(n) |
1509 | #define WRITE64(n) do { \ | 1462 | #define WRITE64(n) do { \ |
@@ -1515,13 +1468,41 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1515 | memcpy(p, ptr, nbytes); \ | 1468 | memcpy(p, ptr, nbytes); \ |
1516 | p += XDR_QUADLEN(nbytes); \ | 1469 | p += XDR_QUADLEN(nbytes); \ |
1517 | }} while (0) | 1470 | }} while (0) |
1518 | #define WRITECINFO(c) do { \ | 1471 | |
1519 | *p++ = htonl(c.atomic); \ | 1472 | static void write32(__be32 **p, u32 n) |
1520 | *p++ = htonl(c.before_ctime_sec); \ | 1473 | { |
1521 | *p++ = htonl(c.before_ctime_nsec); \ | 1474 | *(*p)++ = n; |
1522 | *p++ = htonl(c.after_ctime_sec); \ | 1475 | } |
1523 | *p++ = htonl(c.after_ctime_nsec); \ | 1476 | |
1524 | } while (0) | 1477 | static void write64(__be32 **p, u64 n) |
1478 | { | ||
1479 | write32(p, (u32)(n >> 32)); | ||
1480 | write32(p, (u32)n); | ||
1481 | } | ||
1482 | |||
1483 | static void write_change(__be32 **p, struct kstat *stat, struct inode *inode) | ||
1484 | { | ||
1485 | if (IS_I_VERSION(inode)) { | ||
1486 | write64(p, inode->i_version); | ||
1487 | } else { | ||
1488 | write32(p, stat->ctime.tv_sec); | ||
1489 | write32(p, stat->ctime.tv_nsec); | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1493 | static void write_cinfo(__be32 **p, struct nfsd4_change_info *c) | ||
1494 | { | ||
1495 | write32(p, c->atomic); | ||
1496 | if (c->change_supported) { | ||
1497 | write64(p, c->before_change); | ||
1498 | write64(p, c->after_change); | ||
1499 | } else { | ||
1500 | write32(p, c->before_ctime_sec); | ||
1501 | write32(p, c->before_ctime_nsec); | ||
1502 | write32(p, c->after_ctime_sec); | ||
1503 | write32(p, c->after_ctime_nsec); | ||
1504 | } | ||
1505 | } | ||
1525 | 1506 | ||
1526 | #define RESERVE_SPACE(nbytes) do { \ | 1507 | #define RESERVE_SPACE(nbytes) do { \ |
1527 | p = resp->p; \ | 1508 | p = resp->p; \ |
@@ -1874,16 +1855,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1874 | WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); | 1855 | WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); |
1875 | } | 1856 | } |
1876 | if (bmval0 & FATTR4_WORD0_CHANGE) { | 1857 | if (bmval0 & FATTR4_WORD0_CHANGE) { |
1877 | /* | ||
1878 | * Note: This _must_ be consistent with the scheme for writing | ||
1879 | * change_info, so any changes made here must be reflected there | ||
1880 | * as well. (See xdr4.h:set_change_info() and the WRITECINFO() | ||
1881 | * macro above.) | ||
1882 | */ | ||
1883 | if ((buflen -= 8) < 0) | 1858 | if ((buflen -= 8) < 0) |
1884 | goto out_resource; | 1859 | goto out_resource; |
1885 | WRITE32(stat.ctime.tv_sec); | 1860 | write_change(&p, &stat, dentry->d_inode); |
1886 | WRITE32(stat.ctime.tv_nsec); | ||
1887 | } | 1861 | } |
1888 | if (bmval0 & FATTR4_WORD0_SIZE) { | 1862 | if (bmval0 & FATTR4_WORD0_SIZE) { |
1889 | if ((buflen -= 8) < 0) | 1863 | if ((buflen -= 8) < 0) |
@@ -2348,7 +2322,7 @@ fail: | |||
2348 | static void | 2322 | static void |
2349 | nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) | 2323 | nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) |
2350 | { | 2324 | { |
2351 | ENCODE_HEAD; | 2325 | __be32 *p; |
2352 | 2326 | ||
2353 | RESERVE_SPACE(sizeof(stateid_t)); | 2327 | RESERVE_SPACE(sizeof(stateid_t)); |
2354 | WRITE32(sid->si_generation); | 2328 | WRITE32(sid->si_generation); |
@@ -2359,7 +2333,7 @@ nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) | |||
2359 | static __be32 | 2333 | static __be32 |
2360 | nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) | 2334 | nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) |
2361 | { | 2335 | { |
2362 | ENCODE_HEAD; | 2336 | __be32 *p; |
2363 | 2337 | ||
2364 | if (!nfserr) { | 2338 | if (!nfserr) { |
2365 | RESERVE_SPACE(8); | 2339 | RESERVE_SPACE(8); |
@@ -2386,7 +2360,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c | |||
2386 | static __be32 | 2360 | static __be32 |
2387 | nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) | 2361 | nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) |
2388 | { | 2362 | { |
2389 | ENCODE_HEAD; | 2363 | __be32 *p; |
2390 | 2364 | ||
2391 | if (!nfserr) { | 2365 | if (!nfserr) { |
2392 | RESERVE_SPACE(8); | 2366 | RESERVE_SPACE(8); |
@@ -2399,11 +2373,11 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2399 | static __be32 | 2373 | static __be32 |
2400 | nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) | 2374 | nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) |
2401 | { | 2375 | { |
2402 | ENCODE_HEAD; | 2376 | __be32 *p; |
2403 | 2377 | ||
2404 | if (!nfserr) { | 2378 | if (!nfserr) { |
2405 | RESERVE_SPACE(32); | 2379 | RESERVE_SPACE(32); |
2406 | WRITECINFO(create->cr_cinfo); | 2380 | write_cinfo(&p, &create->cr_cinfo); |
2407 | WRITE32(2); | 2381 | WRITE32(2); |
2408 | WRITE32(create->cr_bmval[0]); | 2382 | WRITE32(create->cr_bmval[0]); |
2409 | WRITE32(create->cr_bmval[1]); | 2383 | WRITE32(create->cr_bmval[1]); |
@@ -2435,7 +2409,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh | |||
2435 | { | 2409 | { |
2436 | struct svc_fh *fhp = *fhpp; | 2410 | struct svc_fh *fhp = *fhpp; |
2437 | unsigned int len; | 2411 | unsigned int len; |
2438 | ENCODE_HEAD; | 2412 | __be32 *p; |
2439 | 2413 | ||
2440 | if (!nfserr) { | 2414 | if (!nfserr) { |
2441 | len = fhp->fh_handle.fh_size; | 2415 | len = fhp->fh_handle.fh_size; |
@@ -2454,7 +2428,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh | |||
2454 | static void | 2428 | static void |
2455 | nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) | 2429 | nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) |
2456 | { | 2430 | { |
2457 | ENCODE_HEAD; | 2431 | __be32 *p; |
2458 | 2432 | ||
2459 | RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0)); | 2433 | RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0)); |
2460 | WRITE64(ld->ld_start); | 2434 | WRITE64(ld->ld_start); |
@@ -2510,11 +2484,11 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l | |||
2510 | static __be32 | 2484 | static __be32 |
2511 | nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) | 2485 | nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) |
2512 | { | 2486 | { |
2513 | ENCODE_HEAD; | 2487 | __be32 *p; |
2514 | 2488 | ||
2515 | if (!nfserr) { | 2489 | if (!nfserr) { |
2516 | RESERVE_SPACE(20); | 2490 | RESERVE_SPACE(20); |
2517 | WRITECINFO(link->li_cinfo); | 2491 | write_cinfo(&p, &link->li_cinfo); |
2518 | ADJUST_ARGS(); | 2492 | ADJUST_ARGS(); |
2519 | } | 2493 | } |
2520 | return nfserr; | 2494 | return nfserr; |
@@ -2524,7 +2498,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li | |||
2524 | static __be32 | 2498 | static __be32 |
2525 | nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) | 2499 | nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) |
2526 | { | 2500 | { |
2527 | ENCODE_HEAD; | 2501 | __be32 *p; |
2528 | ENCODE_SEQID_OP_HEAD; | 2502 | ENCODE_SEQID_OP_HEAD; |
2529 | 2503 | ||
2530 | if (nfserr) | 2504 | if (nfserr) |
@@ -2532,7 +2506,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op | |||
2532 | 2506 | ||
2533 | nfsd4_encode_stateid(resp, &open->op_stateid); | 2507 | nfsd4_encode_stateid(resp, &open->op_stateid); |
2534 | RESERVE_SPACE(40); | 2508 | RESERVE_SPACE(40); |
2535 | WRITECINFO(open->op_cinfo); | 2509 | write_cinfo(&p, &open->op_cinfo); |
2536 | WRITE32(open->op_rflags); | 2510 | WRITE32(open->op_rflags); |
2537 | WRITE32(2); | 2511 | WRITE32(2); |
2538 | WRITE32(open->op_bmval[0]); | 2512 | WRITE32(open->op_bmval[0]); |
@@ -2619,7 +2593,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
2619 | int v, pn; | 2593 | int v, pn; |
2620 | unsigned long maxcount; | 2594 | unsigned long maxcount; |
2621 | long len; | 2595 | long len; |
2622 | ENCODE_HEAD; | 2596 | __be32 *p; |
2623 | 2597 | ||
2624 | if (nfserr) | 2598 | if (nfserr) |
2625 | return nfserr; | 2599 | return nfserr; |
@@ -2681,7 +2655,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd | |||
2681 | { | 2655 | { |
2682 | int maxcount; | 2656 | int maxcount; |
2683 | char *page; | 2657 | char *page; |
2684 | ENCODE_HEAD; | 2658 | __be32 *p; |
2685 | 2659 | ||
2686 | if (nfserr) | 2660 | if (nfserr) |
2687 | return nfserr; | 2661 | return nfserr; |
@@ -2730,7 +2704,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
2730 | int maxcount; | 2704 | int maxcount; |
2731 | loff_t offset; | 2705 | loff_t offset; |
2732 | __be32 *page, *savep, *tailbase; | 2706 | __be32 *page, *savep, *tailbase; |
2733 | ENCODE_HEAD; | 2707 | __be32 *p; |
2734 | 2708 | ||
2735 | if (nfserr) | 2709 | if (nfserr) |
2736 | return nfserr; | 2710 | return nfserr; |
@@ -2806,11 +2780,11 @@ err_no_verf: | |||
2806 | static __be32 | 2780 | static __be32 |
2807 | nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) | 2781 | nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) |
2808 | { | 2782 | { |
2809 | ENCODE_HEAD; | 2783 | __be32 *p; |
2810 | 2784 | ||
2811 | if (!nfserr) { | 2785 | if (!nfserr) { |
2812 | RESERVE_SPACE(20); | 2786 | RESERVE_SPACE(20); |
2813 | WRITECINFO(remove->rm_cinfo); | 2787 | write_cinfo(&p, &remove->rm_cinfo); |
2814 | ADJUST_ARGS(); | 2788 | ADJUST_ARGS(); |
2815 | } | 2789 | } |
2816 | return nfserr; | 2790 | return nfserr; |
@@ -2819,12 +2793,12 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2819 | static __be32 | 2793 | static __be32 |
2820 | nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) | 2794 | nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) |
2821 | { | 2795 | { |
2822 | ENCODE_HEAD; | 2796 | __be32 *p; |
2823 | 2797 | ||
2824 | if (!nfserr) { | 2798 | if (!nfserr) { |
2825 | RESERVE_SPACE(40); | 2799 | RESERVE_SPACE(40); |
2826 | WRITECINFO(rename->rn_sinfo); | 2800 | write_cinfo(&p, &rename->rn_sinfo); |
2827 | WRITECINFO(rename->rn_tinfo); | 2801 | write_cinfo(&p, &rename->rn_tinfo); |
2828 | ADJUST_ARGS(); | 2802 | ADJUST_ARGS(); |
2829 | } | 2803 | } |
2830 | return nfserr; | 2804 | return nfserr; |
@@ -2839,7 +2813,7 @@ nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
2839 | u32 nflavs; | 2813 | u32 nflavs; |
2840 | struct exp_flavor_info *flavs; | 2814 | struct exp_flavor_info *flavs; |
2841 | struct exp_flavor_info def_flavs[2]; | 2815 | struct exp_flavor_info def_flavs[2]; |
2842 | ENCODE_HEAD; | 2816 | __be32 *p; |
2843 | 2817 | ||
2844 | if (nfserr) | 2818 | if (nfserr) |
2845 | goto out; | 2819 | goto out; |
@@ -2904,7 +2878,7 @@ out: | |||
2904 | static __be32 | 2878 | static __be32 |
2905 | nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) | 2879 | nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) |
2906 | { | 2880 | { |
2907 | ENCODE_HEAD; | 2881 | __be32 *p; |
2908 | 2882 | ||
2909 | RESERVE_SPACE(12); | 2883 | RESERVE_SPACE(12); |
2910 | if (nfserr) { | 2884 | if (nfserr) { |
@@ -2924,7 +2898,7 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
2924 | static __be32 | 2898 | static __be32 |
2925 | nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) | 2899 | nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) |
2926 | { | 2900 | { |
2927 | ENCODE_HEAD; | 2901 | __be32 *p; |
2928 | 2902 | ||
2929 | if (!nfserr) { | 2903 | if (!nfserr) { |
2930 | RESERVE_SPACE(8 + sizeof(nfs4_verifier)); | 2904 | RESERVE_SPACE(8 + sizeof(nfs4_verifier)); |
@@ -2944,7 +2918,7 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n | |||
2944 | static __be32 | 2918 | static __be32 |
2945 | nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) | 2919 | nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) |
2946 | { | 2920 | { |
2947 | ENCODE_HEAD; | 2921 | __be32 *p; |
2948 | 2922 | ||
2949 | if (!nfserr) { | 2923 | if (!nfserr) { |
2950 | RESERVE_SPACE(16); | 2924 | RESERVE_SPACE(16); |
@@ -2960,7 +2934,7 @@ static __be32 | |||
2960 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, | 2934 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, |
2961 | struct nfsd4_exchange_id *exid) | 2935 | struct nfsd4_exchange_id *exid) |
2962 | { | 2936 | { |
2963 | ENCODE_HEAD; | 2937 | __be32 *p; |
2964 | char *major_id; | 2938 | char *major_id; |
2965 | char *server_scope; | 2939 | char *server_scope; |
2966 | int major_id_sz; | 2940 | int major_id_sz; |
@@ -3015,7 +2989,7 @@ static __be32 | |||
3015 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, | 2989 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, |
3016 | struct nfsd4_create_session *sess) | 2990 | struct nfsd4_create_session *sess) |
3017 | { | 2991 | { |
3018 | ENCODE_HEAD; | 2992 | __be32 *p; |
3019 | 2993 | ||
3020 | if (nfserr) | 2994 | if (nfserr) |
3021 | return nfserr; | 2995 | return nfserr; |
@@ -3071,7 +3045,7 @@ __be32 | |||
3071 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | 3045 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, |
3072 | struct nfsd4_sequence *seq) | 3046 | struct nfsd4_sequence *seq) |
3073 | { | 3047 | { |
3074 | ENCODE_HEAD; | 3048 | __be32 *p; |
3075 | 3049 | ||
3076 | if (nfserr) | 3050 | if (nfserr) |
3077 | return nfserr; | 3051 | return nfserr; |
@@ -3209,7 +3183,7 @@ static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) | |||
3209 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, | 3183 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, |
3210 | length, xb->page_len, tlen, pad); | 3184 | length, xb->page_len, tlen, pad); |
3211 | 3185 | ||
3212 | if (length <= session->se_fmaxresp_cached) | 3186 | if (length <= session->se_fchannel.maxresp_cached) |
3213 | return status; | 3187 | return status; |
3214 | else | 3188 | else |
3215 | return nfserr_rep_too_big_to_cache; | 3189 | return nfserr_rep_too_big_to_cache; |
@@ -3219,7 +3193,7 @@ void | |||
3219 | nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | 3193 | nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) |
3220 | { | 3194 | { |
3221 | __be32 *statp; | 3195 | __be32 *statp; |
3222 | ENCODE_HEAD; | 3196 | __be32 *p; |
3223 | 3197 | ||
3224 | RESERVE_SPACE(8); | 3198 | RESERVE_SPACE(8); |
3225 | WRITE32(op->opnum); | 3199 | WRITE32(op->opnum); |
@@ -3253,7 +3227,7 @@ status: | |||
3253 | void | 3227 | void |
3254 | nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | 3228 | nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) |
3255 | { | 3229 | { |
3256 | ENCODE_HEAD; | 3230 | __be32 *p; |
3257 | struct nfs4_replay *rp = op->replay; | 3231 | struct nfs4_replay *rp = op->replay; |
3258 | 3232 | ||
3259 | BUG_ON(!rp); | 3233 | BUG_ON(!rp); |
@@ -3268,10 +3242,6 @@ nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | |||
3268 | ADJUST_ARGS(); | 3242 | ADJUST_ARGS(); |
3269 | } | 3243 | } |
3270 | 3244 | ||
3271 | /* | ||
3272 | * END OF "GENERIC" ENCODE ROUTINES. | ||
3273 | */ | ||
3274 | |||
3275 | int | 3245 | int |
3276 | nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) | 3246 | nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) |
3277 | { | 3247 | { |
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 5bfc2ac60d54..4638635c5d87 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c | |||
@@ -29,15 +29,24 @@ | |||
29 | */ | 29 | */ |
30 | #define CACHESIZE 1024 | 30 | #define CACHESIZE 1024 |
31 | #define HASHSIZE 64 | 31 | #define HASHSIZE 64 |
32 | #define REQHASH(xid) (((((__force __u32)xid) >> 24) ^ ((__force __u32)xid)) & (HASHSIZE-1)) | ||
33 | 32 | ||
34 | static struct hlist_head * hash_list; | 33 | static struct hlist_head * cache_hash; |
35 | static struct list_head lru_head; | 34 | static struct list_head lru_head; |
36 | static int cache_disabled = 1; | 35 | static int cache_disabled = 1; |
37 | 36 | ||
37 | /* | ||
38 | * Calculate the hash index from an XID. | ||
39 | */ | ||
40 | static inline u32 request_hash(u32 xid) | ||
41 | { | ||
42 | u32 h = xid; | ||
43 | h ^= (xid >> 24); | ||
44 | return h & (HASHSIZE-1); | ||
45 | } | ||
46 | |||
38 | static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); | 47 | static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); |
39 | 48 | ||
40 | /* | 49 | /* |
41 | * locking for the reply cache: | 50 | * locking for the reply cache: |
42 | * A cache entry is "single use" if c_state == RC_INPROG | 51 | * A cache entry is "single use" if c_state == RC_INPROG |
43 | * Otherwise, it when accessing _prev or _next, the lock must be held. | 52 | * Otherwise, it when accessing _prev or _next, the lock must be held. |
@@ -62,8 +71,8 @@ int nfsd_reply_cache_init(void) | |||
62 | i--; | 71 | i--; |
63 | } | 72 | } |
64 | 73 | ||
65 | hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); | 74 | cache_hash = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); |
66 | if (!hash_list) | 75 | if (!cache_hash) |
67 | goto out_nomem; | 76 | goto out_nomem; |
68 | 77 | ||
69 | cache_disabled = 0; | 78 | cache_disabled = 0; |
@@ -88,8 +97,8 @@ void nfsd_reply_cache_shutdown(void) | |||
88 | 97 | ||
89 | cache_disabled = 1; | 98 | cache_disabled = 1; |
90 | 99 | ||
91 | kfree (hash_list); | 100 | kfree (cache_hash); |
92 | hash_list = NULL; | 101 | cache_hash = NULL; |
93 | } | 102 | } |
94 | 103 | ||
95 | /* | 104 | /* |
@@ -108,7 +117,7 @@ static void | |||
108 | hash_refile(struct svc_cacherep *rp) | 117 | hash_refile(struct svc_cacherep *rp) |
109 | { | 118 | { |
110 | hlist_del_init(&rp->c_hash); | 119 | hlist_del_init(&rp->c_hash); |
111 | hlist_add_head(&rp->c_hash, hash_list + REQHASH(rp->c_xid)); | 120 | hlist_add_head(&rp->c_hash, cache_hash + request_hash(rp->c_xid)); |
112 | } | 121 | } |
113 | 122 | ||
114 | /* | 123 | /* |
@@ -138,7 +147,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) | |||
138 | spin_lock(&cache_lock); | 147 | spin_lock(&cache_lock); |
139 | rtn = RC_DOIT; | 148 | rtn = RC_DOIT; |
140 | 149 | ||
141 | rh = &hash_list[REQHASH(xid)]; | 150 | rh = &cache_hash[request_hash(xid)]; |
142 | hlist_for_each_entry(rp, hn, rh, c_hash) { | 151 | hlist_for_each_entry(rp, hn, rh, c_hash) { |
143 | if (rp->c_state != RC_UNUSED && | 152 | if (rp->c_state != RC_UNUSED && |
144 | xid == rp->c_xid && proc == rp->c_proc && | 153 | xid == rp->c_xid && proc == rp->c_proc && |
@@ -165,8 +174,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) | |||
165 | } | 174 | } |
166 | } | 175 | } |
167 | 176 | ||
168 | /* This should not happen */ | 177 | /* All entries on the LRU are in-progress. This should not happen */ |
169 | if (rp == NULL) { | 178 | if (&rp->c_lru == &lru_head) { |
170 | static int complaints; | 179 | static int complaints; |
171 | 180 | ||
172 | printk(KERN_WARNING "nfsd: all repcache entries locked!\n"); | 181 | printk(KERN_WARNING "nfsd: all repcache entries locked!\n"); |
@@ -264,7 +273,7 @@ nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp) | |||
264 | 273 | ||
265 | len = resv->iov_len - ((char*)statp - (char*)resv->iov_base); | 274 | len = resv->iov_len - ((char*)statp - (char*)resv->iov_base); |
266 | len >>= 2; | 275 | len >>= 2; |
267 | 276 | ||
268 | /* Don't cache excessive amounts of data and XDR failures */ | 277 | /* Don't cache excessive amounts of data and XDR failures */ |
269 | if (!statp || len > (256 >> 2)) { | 278 | if (!statp || len > (256 >> 2)) { |
270 | rp->c_state = RC_UNUSED; | 279 | rp->c_state = RC_UNUSED; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index af16849d243a..1250fb978ac1 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -207,10 +207,14 @@ static struct file_operations pool_stats_operations = { | |||
207 | static ssize_t write_svc(struct file *file, char *buf, size_t size) | 207 | static ssize_t write_svc(struct file *file, char *buf, size_t size) |
208 | { | 208 | { |
209 | struct nfsctl_svc *data; | 209 | struct nfsctl_svc *data; |
210 | int err; | ||
210 | if (size < sizeof(*data)) | 211 | if (size < sizeof(*data)) |
211 | return -EINVAL; | 212 | return -EINVAL; |
212 | data = (struct nfsctl_svc*) buf; | 213 | data = (struct nfsctl_svc*) buf; |
213 | return nfsd_svc(data->svc_port, data->svc_nthreads); | 214 | err = nfsd_svc(data->svc_port, data->svc_nthreads); |
215 | if (err < 0) | ||
216 | return err; | ||
217 | return 0; | ||
214 | } | 218 | } |
215 | 219 | ||
216 | /** | 220 | /** |
@@ -692,11 +696,12 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) | |||
692 | if (newthreads < 0) | 696 | if (newthreads < 0) |
693 | return -EINVAL; | 697 | return -EINVAL; |
694 | rv = nfsd_svc(NFS_PORT, newthreads); | 698 | rv = nfsd_svc(NFS_PORT, newthreads); |
695 | if (rv) | 699 | if (rv < 0) |
696 | return rv; | 700 | return rv; |
697 | } | 701 | } else |
698 | sprintf(buf, "%d\n", nfsd_nrthreads()); | 702 | rv = nfsd_nrthreads(); |
699 | return strlen(buf); | 703 | |
704 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv); | ||
700 | } | 705 | } |
701 | 706 | ||
702 | /** | 707 | /** |
@@ -793,7 +798,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
793 | { | 798 | { |
794 | char *mesg = buf; | 799 | char *mesg = buf; |
795 | char *vers, *minorp, sign; | 800 | char *vers, *minorp, sign; |
796 | int len, num; | 801 | int len, num, remaining; |
797 | unsigned minor; | 802 | unsigned minor; |
798 | ssize_t tlen = 0; | 803 | ssize_t tlen = 0; |
799 | char *sep; | 804 | char *sep; |
@@ -840,32 +845,50 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
840 | } | 845 | } |
841 | next: | 846 | next: |
842 | vers += len + 1; | 847 | vers += len + 1; |
843 | tlen += len; | ||
844 | } while ((len = qword_get(&mesg, vers, size)) > 0); | 848 | } while ((len = qword_get(&mesg, vers, size)) > 0); |
845 | /* If all get turned off, turn them back on, as | 849 | /* If all get turned off, turn them back on, as |
846 | * having no versions is BAD | 850 | * having no versions is BAD |
847 | */ | 851 | */ |
848 | nfsd_reset_versions(); | 852 | nfsd_reset_versions(); |
849 | } | 853 | } |
854 | |||
850 | /* Now write current state into reply buffer */ | 855 | /* Now write current state into reply buffer */ |
851 | len = 0; | 856 | len = 0; |
852 | sep = ""; | 857 | sep = ""; |
858 | remaining = SIMPLE_TRANSACTION_LIMIT; | ||
853 | for (num=2 ; num <= 4 ; num++) | 859 | for (num=2 ; num <= 4 ; num++) |
854 | if (nfsd_vers(num, NFSD_AVAIL)) { | 860 | if (nfsd_vers(num, NFSD_AVAIL)) { |
855 | len += sprintf(buf+len, "%s%c%d", sep, | 861 | len = snprintf(buf, remaining, "%s%c%d", sep, |
856 | nfsd_vers(num, NFSD_TEST)?'+':'-', | 862 | nfsd_vers(num, NFSD_TEST)?'+':'-', |
857 | num); | 863 | num); |
858 | sep = " "; | 864 | sep = " "; |
865 | |||
866 | if (len > remaining) | ||
867 | break; | ||
868 | remaining -= len; | ||
869 | buf += len; | ||
870 | tlen += len; | ||
859 | } | 871 | } |
860 | if (nfsd_vers(4, NFSD_AVAIL)) | 872 | if (nfsd_vers(4, NFSD_AVAIL)) |
861 | for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; minor++) | 873 | for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; |
862 | len += sprintf(buf+len, " %c4.%u", | 874 | minor++) { |
875 | len = snprintf(buf, remaining, " %c4.%u", | ||
863 | (nfsd_vers(4, NFSD_TEST) && | 876 | (nfsd_vers(4, NFSD_TEST) && |
864 | nfsd_minorversion(minor, NFSD_TEST)) ? | 877 | nfsd_minorversion(minor, NFSD_TEST)) ? |
865 | '+' : '-', | 878 | '+' : '-', |
866 | minor); | 879 | minor); |
867 | len += sprintf(buf+len, "\n"); | 880 | |
868 | return len; | 881 | if (len > remaining) |
882 | break; | ||
883 | remaining -= len; | ||
884 | buf += len; | ||
885 | tlen += len; | ||
886 | } | ||
887 | |||
888 | len = snprintf(buf, remaining, "\n"); | ||
889 | if (len > remaining) | ||
890 | return -EINVAL; | ||
891 | return tlen + len; | ||
869 | } | 892 | } |
870 | 893 | ||
871 | /** | 894 | /** |
@@ -910,104 +933,143 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) | |||
910 | return rv; | 933 | return rv; |
911 | } | 934 | } |
912 | 935 | ||
913 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) | 936 | /* |
937 | * Zero-length write. Return a list of NFSD's current listener | ||
938 | * transports. | ||
939 | */ | ||
940 | static ssize_t __write_ports_names(char *buf) | ||
914 | { | 941 | { |
915 | if (size == 0) { | 942 | if (nfsd_serv == NULL) |
916 | int len = 0; | 943 | return 0; |
944 | return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT); | ||
945 | } | ||
917 | 946 | ||
918 | if (nfsd_serv) | 947 | /* |
919 | len = svc_xprt_names(nfsd_serv, buf, 0); | 948 | * A single 'fd' number was written, in which case it must be for |
920 | return len; | 949 | * a socket of a supported family/protocol, and we use it as an |
921 | } | 950 | * nfsd listener. |
922 | /* Either a single 'fd' number is written, in which | 951 | */ |
923 | * case it must be for a socket of a supported family/protocol, | 952 | static ssize_t __write_ports_addfd(char *buf) |
924 | * and we use it as an nfsd socket, or | 953 | { |
925 | * A '-' followed by the 'name' of a socket in which case | 954 | char *mesg = buf; |
926 | * we close the socket. | 955 | int fd, err; |
927 | */ | 956 | |
928 | if (isdigit(buf[0])) { | 957 | err = get_int(&mesg, &fd); |
929 | char *mesg = buf; | 958 | if (err != 0 || fd < 0) |
930 | int fd; | 959 | return -EINVAL; |
931 | int err; | 960 | |
932 | err = get_int(&mesg, &fd); | 961 | err = nfsd_create_serv(); |
933 | if (err) | 962 | if (err != 0) |
934 | return -EINVAL; | 963 | return err; |
935 | if (fd < 0) | 964 | |
936 | return -EINVAL; | 965 | err = lockd_up(); |
937 | err = nfsd_create_serv(); | 966 | if (err != 0) |
938 | if (!err) { | 967 | goto out; |
939 | err = svc_addsock(nfsd_serv, fd, buf); | 968 | |
940 | if (err >= 0) { | 969 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
941 | err = lockd_up(); | 970 | if (err < 0) |
942 | if (err < 0) | 971 | lockd_down(); |
943 | svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf); | 972 | |
944 | } | 973 | out: |
945 | /* Decrease the count, but don't shutdown the | 974 | /* Decrease the count, but don't shut down the service */ |
946 | * the service | 975 | nfsd_serv->sv_nrthreads--; |
947 | */ | 976 | return err; |
948 | nfsd_serv->sv_nrthreads--; | 977 | } |
949 | } | 978 | |
950 | return err < 0 ? err : 0; | 979 | /* |
951 | } | 980 | * A '-' followed by the 'name' of a socket means we close the socket. |
952 | if (buf[0] == '-' && isdigit(buf[1])) { | 981 | */ |
953 | char *toclose = kstrdup(buf+1, GFP_KERNEL); | 982 | static ssize_t __write_ports_delfd(char *buf) |
954 | int len = 0; | 983 | { |
955 | if (!toclose) | 984 | char *toclose; |
956 | return -ENOMEM; | 985 | int len = 0; |
957 | if (nfsd_serv) | 986 | |
958 | len = svc_sock_names(buf, nfsd_serv, toclose); | 987 | toclose = kstrdup(buf + 1, GFP_KERNEL); |
959 | if (len >= 0) | 988 | if (toclose == NULL) |
960 | lockd_down(); | 989 | return -ENOMEM; |
961 | kfree(toclose); | 990 | |
962 | return len; | 991 | if (nfsd_serv != NULL) |
963 | } | 992 | len = svc_sock_names(nfsd_serv, buf, |
964 | /* | 993 | SIMPLE_TRANSACTION_LIMIT, toclose); |
965 | * Add a transport listener by writing it's transport name | 994 | if (len >= 0) |
966 | */ | 995 | lockd_down(); |
967 | if (isalpha(buf[0])) { | 996 | |
968 | int err; | 997 | kfree(toclose); |
969 | char transport[16]; | 998 | return len; |
970 | int port; | 999 | } |
971 | if (sscanf(buf, "%15s %4d", transport, &port) == 2) { | 1000 | |
972 | if (port < 1 || port > 65535) | 1001 | /* |
973 | return -EINVAL; | 1002 | * A transport listener is added by writing it's transport name and |
974 | err = nfsd_create_serv(); | 1003 | * a port number. |
975 | if (!err) { | 1004 | */ |
976 | err = svc_create_xprt(nfsd_serv, | 1005 | static ssize_t __write_ports_addxprt(char *buf) |
977 | transport, PF_INET, port, | 1006 | { |
978 | SVC_SOCK_ANONYMOUS); | 1007 | char transport[16]; |
979 | if (err == -ENOENT) | 1008 | int port, err; |
980 | /* Give a reasonable perror msg for | 1009 | |
981 | * bad transport string */ | 1010 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) |
982 | err = -EPROTONOSUPPORT; | 1011 | return -EINVAL; |
983 | } | 1012 | |
984 | return err < 0 ? err : 0; | 1013 | if (port < 1 || port > USHORT_MAX) |
985 | } | 1014 | return -EINVAL; |
986 | } | 1015 | |
987 | /* | 1016 | err = nfsd_create_serv(); |
988 | * Remove a transport by writing it's transport name and port number | 1017 | if (err != 0) |
989 | */ | 1018 | return err; |
990 | if (buf[0] == '-' && isalpha(buf[1])) { | 1019 | |
991 | struct svc_xprt *xprt; | 1020 | err = svc_create_xprt(nfsd_serv, transport, |
992 | int err = -EINVAL; | 1021 | PF_INET, port, SVC_SOCK_ANONYMOUS); |
993 | char transport[16]; | 1022 | if (err < 0) { |
994 | int port; | 1023 | /* Give a reasonable perror msg for bad transport string */ |
995 | if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { | 1024 | if (err == -ENOENT) |
996 | if (port < 1 || port > 65535) | 1025 | err = -EPROTONOSUPPORT; |
997 | return -EINVAL; | 1026 | return err; |
998 | if (nfsd_serv) { | ||
999 | xprt = svc_find_xprt(nfsd_serv, transport, | ||
1000 | AF_UNSPEC, port); | ||
1001 | if (xprt) { | ||
1002 | svc_close_xprt(xprt); | ||
1003 | svc_xprt_put(xprt); | ||
1004 | err = 0; | ||
1005 | } else | ||
1006 | err = -ENOTCONN; | ||
1007 | } | ||
1008 | return err < 0 ? err : 0; | ||
1009 | } | ||
1010 | } | 1027 | } |
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | /* | ||
1032 | * A transport listener is removed by writing a "-", it's transport | ||
1033 | * name, and it's port number. | ||
1034 | */ | ||
1035 | static ssize_t __write_ports_delxprt(char *buf) | ||
1036 | { | ||
1037 | struct svc_xprt *xprt; | ||
1038 | char transport[16]; | ||
1039 | int port; | ||
1040 | |||
1041 | if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2) | ||
1042 | return -EINVAL; | ||
1043 | |||
1044 | if (port < 1 || port > USHORT_MAX || nfsd_serv == NULL) | ||
1045 | return -EINVAL; | ||
1046 | |||
1047 | xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port); | ||
1048 | if (xprt == NULL) | ||
1049 | return -ENOTCONN; | ||
1050 | |||
1051 | svc_close_xprt(xprt); | ||
1052 | svc_xprt_put(xprt); | ||
1053 | return 0; | ||
1054 | } | ||
1055 | |||
1056 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) | ||
1057 | { | ||
1058 | if (size == 0) | ||
1059 | return __write_ports_names(buf); | ||
1060 | |||
1061 | if (isdigit(buf[0])) | ||
1062 | return __write_ports_addfd(buf); | ||
1063 | |||
1064 | if (buf[0] == '-' && isdigit(buf[1])) | ||
1065 | return __write_ports_delfd(buf); | ||
1066 | |||
1067 | if (isalpha(buf[0])) | ||
1068 | return __write_ports_addxprt(buf); | ||
1069 | |||
1070 | if (buf[0] == '-' && isalpha(buf[1])) | ||
1071 | return __write_ports_delxprt(buf); | ||
1072 | |||
1011 | return -EINVAL; | 1073 | return -EINVAL; |
1012 | } | 1074 | } |
1013 | 1075 | ||
@@ -1030,7 +1092,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) | |||
1030 | * buf: C string containing an unsigned | 1092 | * buf: C string containing an unsigned |
1031 | * integer value representing a bound | 1093 | * integer value representing a bound |
1032 | * but unconnected socket that is to be | 1094 | * but unconnected socket that is to be |
1033 | * used as an NFSD listener | 1095 | * used as an NFSD listener; listen(3) |
1096 | * must be called for a SOCK_STREAM | ||
1097 | * socket, otherwise it is ignored | ||
1034 | * size: non-zero length of C string in @buf | 1098 | * size: non-zero length of C string in @buf |
1035 | * Output: | 1099 | * Output: |
1036 | * On success: NFS service is started; | 1100 | * On success: NFS service is started; |
@@ -1138,7 +1202,9 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) | |||
1138 | nfsd_max_blksize = bsize; | 1202 | nfsd_max_blksize = bsize; |
1139 | mutex_unlock(&nfsd_mutex); | 1203 | mutex_unlock(&nfsd_mutex); |
1140 | } | 1204 | } |
1141 | return sprintf(buf, "%d\n", nfsd_max_blksize); | 1205 | |
1206 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", | ||
1207 | nfsd_max_blksize); | ||
1142 | } | 1208 | } |
1143 | 1209 | ||
1144 | #ifdef CONFIG_NFSD_V4 | 1210 | #ifdef CONFIG_NFSD_V4 |
@@ -1162,8 +1228,9 @@ static ssize_t __write_leasetime(struct file *file, char *buf, size_t size) | |||
1162 | return -EINVAL; | 1228 | return -EINVAL; |
1163 | nfs4_reset_lease(lease); | 1229 | nfs4_reset_lease(lease); |
1164 | } | 1230 | } |
1165 | sprintf(buf, "%ld\n", nfs4_lease_time()); | 1231 | |
1166 | return strlen(buf); | 1232 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", |
1233 | nfs4_lease_time()); | ||
1167 | } | 1234 | } |
1168 | 1235 | ||
1169 | /** | 1236 | /** |
@@ -1219,8 +1286,9 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) | |||
1219 | 1286 | ||
1220 | status = nfs4_reset_recoverydir(recdir); | 1287 | status = nfs4_reset_recoverydir(recdir); |
1221 | } | 1288 | } |
1222 | sprintf(buf, "%s\n", nfs4_recoverydir()); | 1289 | |
1223 | return strlen(buf); | 1290 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n", |
1291 | nfs4_recoverydir()); | ||
1224 | } | 1292 | } |
1225 | 1293 | ||
1226 | /** | 1294 | /** |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 9f1ca17293d3..8847f3fbfc1e 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -27,9 +27,6 @@ | |||
27 | #define NFSDDBG_FACILITY NFSDDBG_FH | 27 | #define NFSDDBG_FACILITY NFSDDBG_FH |
28 | 28 | ||
29 | 29 | ||
30 | static int nfsd_nr_verified; | ||
31 | static int nfsd_nr_put; | ||
32 | |||
33 | /* | 30 | /* |
34 | * our acceptability function. | 31 | * our acceptability function. |
35 | * if NOSUBTREECHECK, accept anything | 32 | * if NOSUBTREECHECK, accept anything |
@@ -251,7 +248,6 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) | |||
251 | 248 | ||
252 | fhp->fh_dentry = dentry; | 249 | fhp->fh_dentry = dentry; |
253 | fhp->fh_export = exp; | 250 | fhp->fh_export = exp; |
254 | nfsd_nr_verified++; | ||
255 | return 0; | 251 | return 0; |
256 | out: | 252 | out: |
257 | exp_put(exp); | 253 | exp_put(exp); |
@@ -552,7 +548,6 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
552 | return nfserr_opnotsupp; | 548 | return nfserr_opnotsupp; |
553 | } | 549 | } |
554 | 550 | ||
555 | nfsd_nr_verified++; | ||
556 | return 0; | 551 | return 0; |
557 | } | 552 | } |
558 | 553 | ||
@@ -609,7 +604,6 @@ fh_put(struct svc_fh *fhp) | |||
609 | fhp->fh_pre_saved = 0; | 604 | fhp->fh_pre_saved = 0; |
610 | fhp->fh_post_saved = 0; | 605 | fhp->fh_post_saved = 0; |
611 | #endif | 606 | #endif |
612 | nfsd_nr_put++; | ||
613 | } | 607 | } |
614 | if (exp) { | 608 | if (exp) { |
615 | cache_put(&exp->h, &svc_export_cache); | 609 | cache_put(&exp->h, &svc_export_cache); |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index e298e260b5f1..0eb9c820b7a6 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -533,45 +533,179 @@ nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, | |||
533 | * NFSv2 Server procedures. | 533 | * NFSv2 Server procedures. |
534 | * Only the results of non-idempotent operations are cached. | 534 | * Only the results of non-idempotent operations are cached. |
535 | */ | 535 | */ |
536 | #define nfsd_proc_none NULL | ||
537 | #define nfssvc_release_none NULL | ||
538 | struct nfsd_void { int dummy; }; | 536 | struct nfsd_void { int dummy; }; |
539 | 537 | ||
540 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
541 | { (svc_procfunc) nfsd_proc_##name, \ | ||
542 | (kxdrproc_t) nfssvc_decode_##argt, \ | ||
543 | (kxdrproc_t) nfssvc_encode_##rest, \ | ||
544 | (kxdrproc_t) nfssvc_release_##relt, \ | ||
545 | sizeof(struct nfsd_##argt), \ | ||
546 | sizeof(struct nfsd_##rest), \ | ||
547 | 0, \ | ||
548 | cache, \ | ||
549 | respsize, \ | ||
550 | } | ||
551 | |||
552 | #define ST 1 /* status */ | 538 | #define ST 1 /* status */ |
553 | #define FH 8 /* filehandle */ | 539 | #define FH 8 /* filehandle */ |
554 | #define AT 18 /* attributes */ | 540 | #define AT 18 /* attributes */ |
555 | 541 | ||
556 | static struct svc_procedure nfsd_procedures2[18] = { | 542 | static struct svc_procedure nfsd_procedures2[18] = { |
557 | PROC(null, void, void, none, RC_NOCACHE, ST), | 543 | [NFSPROC_NULL] = { |
558 | PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), | 544 | .pc_func = (svc_procfunc) nfsd_proc_null, |
559 | PROC(setattr, sattrargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), | 545 | .pc_decode = (kxdrproc_t) nfssvc_decode_void, |
560 | PROC(none, void, void, none, RC_NOCACHE, ST), | 546 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, |
561 | PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT), | 547 | .pc_argsize = sizeof(struct nfsd_void), |
562 | PROC(readlink, readlinkargs, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4), | 548 | .pc_ressize = sizeof(struct nfsd_void), |
563 | PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4), | 549 | .pc_cachetype = RC_NOCACHE, |
564 | PROC(none, void, void, none, RC_NOCACHE, ST), | 550 | .pc_xdrressize = ST, |
565 | PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), | 551 | }, |
566 | PROC(create, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT), | 552 | [NFSPROC_GETATTR] = { |
567 | PROC(remove, diropargs, void, none, RC_REPLSTAT, ST), | 553 | .pc_func = (svc_procfunc) nfsd_proc_getattr, |
568 | PROC(rename, renameargs, void, none, RC_REPLSTAT, ST), | 554 | .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle, |
569 | PROC(link, linkargs, void, none, RC_REPLSTAT, ST), | 555 | .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, |
570 | PROC(symlink, symlinkargs, void, none, RC_REPLSTAT, ST), | 556 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, |
571 | PROC(mkdir, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT), | 557 | .pc_argsize = sizeof(struct nfsd_fhandle), |
572 | PROC(rmdir, diropargs, void, none, RC_REPLSTAT, ST), | 558 | .pc_ressize = sizeof(struct nfsd_attrstat), |
573 | PROC(readdir, readdirargs, readdirres, none, RC_NOCACHE, 0), | 559 | .pc_cachetype = RC_NOCACHE, |
574 | PROC(statfs, fhandle, statfsres, none, RC_NOCACHE, ST+5), | 560 | .pc_xdrressize = ST+AT, |
561 | }, | ||
562 | [NFSPROC_SETATTR] = { | ||
563 | .pc_func = (svc_procfunc) nfsd_proc_setattr, | ||
564 | .pc_decode = (kxdrproc_t) nfssvc_decode_sattrargs, | ||
565 | .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, | ||
566 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
567 | .pc_argsize = sizeof(struct nfsd_sattrargs), | ||
568 | .pc_ressize = sizeof(struct nfsd_attrstat), | ||
569 | .pc_cachetype = RC_REPLBUFF, | ||
570 | .pc_xdrressize = ST+AT, | ||
571 | }, | ||
572 | [NFSPROC_ROOT] = { | ||
573 | .pc_decode = (kxdrproc_t) nfssvc_decode_void, | ||
574 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
575 | .pc_argsize = sizeof(struct nfsd_void), | ||
576 | .pc_ressize = sizeof(struct nfsd_void), | ||
577 | .pc_cachetype = RC_NOCACHE, | ||
578 | .pc_xdrressize = ST, | ||
579 | }, | ||
580 | [NFSPROC_LOOKUP] = { | ||
581 | .pc_func = (svc_procfunc) nfsd_proc_lookup, | ||
582 | .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, | ||
583 | .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, | ||
584 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
585 | .pc_argsize = sizeof(struct nfsd_diropargs), | ||
586 | .pc_ressize = sizeof(struct nfsd_diropres), | ||
587 | .pc_cachetype = RC_NOCACHE, | ||
588 | .pc_xdrressize = ST+FH+AT, | ||
589 | }, | ||
590 | [NFSPROC_READLINK] = { | ||
591 | .pc_func = (svc_procfunc) nfsd_proc_readlink, | ||
592 | .pc_decode = (kxdrproc_t) nfssvc_decode_readlinkargs, | ||
593 | .pc_encode = (kxdrproc_t) nfssvc_encode_readlinkres, | ||
594 | .pc_argsize = sizeof(struct nfsd_readlinkargs), | ||
595 | .pc_ressize = sizeof(struct nfsd_readlinkres), | ||
596 | .pc_cachetype = RC_NOCACHE, | ||
597 | .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4, | ||
598 | }, | ||
599 | [NFSPROC_READ] = { | ||
600 | .pc_func = (svc_procfunc) nfsd_proc_read, | ||
601 | .pc_decode = (kxdrproc_t) nfssvc_decode_readargs, | ||
602 | .pc_encode = (kxdrproc_t) nfssvc_encode_readres, | ||
603 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
604 | .pc_argsize = sizeof(struct nfsd_readargs), | ||
605 | .pc_ressize = sizeof(struct nfsd_readres), | ||
606 | .pc_cachetype = RC_NOCACHE, | ||
607 | .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4, | ||
608 | }, | ||
609 | [NFSPROC_WRITECACHE] = { | ||
610 | .pc_decode = (kxdrproc_t) nfssvc_decode_void, | ||
611 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
612 | .pc_argsize = sizeof(struct nfsd_void), | ||
613 | .pc_ressize = sizeof(struct nfsd_void), | ||
614 | .pc_cachetype = RC_NOCACHE, | ||
615 | .pc_xdrressize = ST, | ||
616 | }, | ||
617 | [NFSPROC_WRITE] = { | ||
618 | .pc_func = (svc_procfunc) nfsd_proc_write, | ||
619 | .pc_decode = (kxdrproc_t) nfssvc_decode_writeargs, | ||
620 | .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, | ||
621 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
622 | .pc_argsize = sizeof(struct nfsd_writeargs), | ||
623 | .pc_ressize = sizeof(struct nfsd_attrstat), | ||
624 | .pc_cachetype = RC_REPLBUFF, | ||
625 | .pc_xdrressize = ST+AT, | ||
626 | }, | ||
627 | [NFSPROC_CREATE] = { | ||
628 | .pc_func = (svc_procfunc) nfsd_proc_create, | ||
629 | .pc_decode = (kxdrproc_t) nfssvc_decode_createargs, | ||
630 | .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, | ||
631 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
632 | .pc_argsize = sizeof(struct nfsd_createargs), | ||
633 | .pc_ressize = sizeof(struct nfsd_diropres), | ||
634 | .pc_cachetype = RC_REPLBUFF, | ||
635 | .pc_xdrressize = ST+FH+AT, | ||
636 | }, | ||
637 | [NFSPROC_REMOVE] = { | ||
638 | .pc_func = (svc_procfunc) nfsd_proc_remove, | ||
639 | .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, | ||
640 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
641 | .pc_argsize = sizeof(struct nfsd_diropargs), | ||
642 | .pc_ressize = sizeof(struct nfsd_void), | ||
643 | .pc_cachetype = RC_REPLSTAT, | ||
644 | .pc_xdrressize = ST, | ||
645 | }, | ||
646 | [NFSPROC_RENAME] = { | ||
647 | .pc_func = (svc_procfunc) nfsd_proc_rename, | ||
648 | .pc_decode = (kxdrproc_t) nfssvc_decode_renameargs, | ||
649 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
650 | .pc_argsize = sizeof(struct nfsd_renameargs), | ||
651 | .pc_ressize = sizeof(struct nfsd_void), | ||
652 | .pc_cachetype = RC_REPLSTAT, | ||
653 | .pc_xdrressize = ST, | ||
654 | }, | ||
655 | [NFSPROC_LINK] = { | ||
656 | .pc_func = (svc_procfunc) nfsd_proc_link, | ||
657 | .pc_decode = (kxdrproc_t) nfssvc_decode_linkargs, | ||
658 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
659 | .pc_argsize = sizeof(struct nfsd_linkargs), | ||
660 | .pc_ressize = sizeof(struct nfsd_void), | ||
661 | .pc_cachetype = RC_REPLSTAT, | ||
662 | .pc_xdrressize = ST, | ||
663 | }, | ||
664 | [NFSPROC_SYMLINK] = { | ||
665 | .pc_func = (svc_procfunc) nfsd_proc_symlink, | ||
666 | .pc_decode = (kxdrproc_t) nfssvc_decode_symlinkargs, | ||
667 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
668 | .pc_argsize = sizeof(struct nfsd_symlinkargs), | ||
669 | .pc_ressize = sizeof(struct nfsd_void), | ||
670 | .pc_cachetype = RC_REPLSTAT, | ||
671 | .pc_xdrressize = ST, | ||
672 | }, | ||
673 | [NFSPROC_MKDIR] = { | ||
674 | .pc_func = (svc_procfunc) nfsd_proc_mkdir, | ||
675 | .pc_decode = (kxdrproc_t) nfssvc_decode_createargs, | ||
676 | .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, | ||
677 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
678 | .pc_argsize = sizeof(struct nfsd_createargs), | ||
679 | .pc_ressize = sizeof(struct nfsd_diropres), | ||
680 | .pc_cachetype = RC_REPLBUFF, | ||
681 | .pc_xdrressize = ST+FH+AT, | ||
682 | }, | ||
683 | [NFSPROC_RMDIR] = { | ||
684 | .pc_func = (svc_procfunc) nfsd_proc_rmdir, | ||
685 | .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, | ||
686 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
687 | .pc_argsize = sizeof(struct nfsd_diropargs), | ||
688 | .pc_ressize = sizeof(struct nfsd_void), | ||
689 | .pc_cachetype = RC_REPLSTAT, | ||
690 | .pc_xdrressize = ST, | ||
691 | }, | ||
692 | [NFSPROC_READDIR] = { | ||
693 | .pc_func = (svc_procfunc) nfsd_proc_readdir, | ||
694 | .pc_decode = (kxdrproc_t) nfssvc_decode_readdirargs, | ||
695 | .pc_encode = (kxdrproc_t) nfssvc_encode_readdirres, | ||
696 | .pc_argsize = sizeof(struct nfsd_readdirargs), | ||
697 | .pc_ressize = sizeof(struct nfsd_readdirres), | ||
698 | .pc_cachetype = RC_NOCACHE, | ||
699 | }, | ||
700 | [NFSPROC_STATFS] = { | ||
701 | .pc_func = (svc_procfunc) nfsd_proc_statfs, | ||
702 | .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle, | ||
703 | .pc_encode = (kxdrproc_t) nfssvc_encode_statfsres, | ||
704 | .pc_argsize = sizeof(struct nfsd_fhandle), | ||
705 | .pc_ressize = sizeof(struct nfsd_statfsres), | ||
706 | .pc_cachetype = RC_NOCACHE, | ||
707 | .pc_xdrressize = ST+5, | ||
708 | }, | ||
575 | }; | 709 | }; |
576 | 710 | ||
577 | 711 | ||
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index cbba4a935786..d4c9884cd54b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -390,12 +390,14 @@ nfsd_svc(unsigned short port, int nrservs) | |||
390 | 390 | ||
391 | mutex_lock(&nfsd_mutex); | 391 | mutex_lock(&nfsd_mutex); |
392 | dprintk("nfsd: creating service\n"); | 392 | dprintk("nfsd: creating service\n"); |
393 | error = -EINVAL; | ||
394 | if (nrservs <= 0) | 393 | if (nrservs <= 0) |
395 | nrservs = 0; | 394 | nrservs = 0; |
396 | if (nrservs > NFSD_MAXSERVS) | 395 | if (nrservs > NFSD_MAXSERVS) |
397 | nrservs = NFSD_MAXSERVS; | 396 | nrservs = NFSD_MAXSERVS; |
398 | 397 | error = 0; | |
398 | if (nrservs == 0 && nfsd_serv == NULL) | ||
399 | goto out; | ||
400 | |||
399 | /* Readahead param cache - will no-op if it already exists */ | 401 | /* Readahead param cache - will no-op if it already exists */ |
400 | error = nfsd_racache_init(2*nrservs); | 402 | error = nfsd_racache_init(2*nrservs); |
401 | if (error<0) | 403 | if (error<0) |
@@ -413,6 +415,12 @@ nfsd_svc(unsigned short port, int nrservs) | |||
413 | goto failure; | 415 | goto failure; |
414 | 416 | ||
415 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); | 417 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); |
418 | if (error == 0) | ||
419 | /* We are holding a reference to nfsd_serv which | ||
420 | * we don't want to count in the return value, | ||
421 | * so subtract 1 | ||
422 | */ | ||
423 | error = nfsd_serv->sv_nrthreads - 1; | ||
416 | failure: | 424 | failure: |
417 | svc_destroy(nfsd_serv); /* Release server */ | 425 | svc_destroy(nfsd_serv); /* Release server */ |
418 | out: | 426 | out: |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 99f835753596..4145083dcf88 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -966,6 +966,43 @@ static void kill_suid(struct dentry *dentry) | |||
966 | mutex_unlock(&dentry->d_inode->i_mutex); | 966 | mutex_unlock(&dentry->d_inode->i_mutex); |
967 | } | 967 | } |
968 | 968 | ||
969 | /* | ||
970 | * Gathered writes: If another process is currently writing to the file, | ||
971 | * there's a high chance this is another nfsd (triggered by a bulk write | ||
972 | * from a client's biod). Rather than syncing the file with each write | ||
973 | * request, we sleep for 10 msec. | ||
974 | * | ||
975 | * I don't know if this roughly approximates C. Juszak's idea of | ||
976 | * gathered writes, but it's a nice and simple solution (IMHO), and it | ||
977 | * seems to work:-) | ||
978 | * | ||
979 | * Note: we do this only in the NFSv2 case, since v3 and higher have a | ||
980 | * better tool (separate unstable writes and commits) for solving this | ||
981 | * problem. | ||
982 | */ | ||
983 | static int wait_for_concurrent_writes(struct file *file) | ||
984 | { | ||
985 | struct inode *inode = file->f_path.dentry->d_inode; | ||
986 | static ino_t last_ino; | ||
987 | static dev_t last_dev; | ||
988 | int err = 0; | ||
989 | |||
990 | if (atomic_read(&inode->i_writecount) > 1 | ||
991 | || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) { | ||
992 | dprintk("nfsd: write defer %d\n", task_pid_nr(current)); | ||
993 | msleep(10); | ||
994 | dprintk("nfsd: write resume %d\n", task_pid_nr(current)); | ||
995 | } | ||
996 | |||
997 | if (inode->i_state & I_DIRTY) { | ||
998 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); | ||
999 | err = nfsd_sync(file); | ||
1000 | } | ||
1001 | last_ino = inode->i_ino; | ||
1002 | last_dev = inode->i_sb->s_dev; | ||
1003 | return err; | ||
1004 | } | ||
1005 | |||
969 | static __be32 | 1006 | static __be32 |
970 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 1007 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
971 | loff_t offset, struct kvec *vec, int vlen, | 1008 | loff_t offset, struct kvec *vec, int vlen, |
@@ -978,6 +1015,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
978 | __be32 err = 0; | 1015 | __be32 err = 0; |
979 | int host_err; | 1016 | int host_err; |
980 | int stable = *stablep; | 1017 | int stable = *stablep; |
1018 | int use_wgather; | ||
981 | 1019 | ||
982 | #ifdef MSNFS | 1020 | #ifdef MSNFS |
983 | err = nfserr_perm; | 1021 | err = nfserr_perm; |
@@ -996,9 +1034,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
996 | * - the sync export option has been set, or | 1034 | * - the sync export option has been set, or |
997 | * - the client requested O_SYNC behavior (NFSv3 feature). | 1035 | * - the client requested O_SYNC behavior (NFSv3 feature). |
998 | * - The file system doesn't support fsync(). | 1036 | * - The file system doesn't support fsync(). |
999 | * When gathered writes have been configured for this volume, | 1037 | * When NFSv2 gathered writes have been configured for this volume, |
1000 | * flushing the data to disk is handled separately below. | 1038 | * flushing the data to disk is handled separately below. |
1001 | */ | 1039 | */ |
1040 | use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp); | ||
1002 | 1041 | ||
1003 | if (!file->f_op->fsync) {/* COMMIT3 cannot work */ | 1042 | if (!file->f_op->fsync) {/* COMMIT3 cannot work */ |
1004 | stable = 2; | 1043 | stable = 2; |
@@ -1007,7 +1046,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1007 | 1046 | ||
1008 | if (!EX_ISSYNC(exp)) | 1047 | if (!EX_ISSYNC(exp)) |
1009 | stable = 0; | 1048 | stable = 0; |
1010 | if (stable && !EX_WGATHER(exp)) { | 1049 | if (stable && !use_wgather) { |
1011 | spin_lock(&file->f_lock); | 1050 | spin_lock(&file->f_lock); |
1012 | file->f_flags |= O_SYNC; | 1051 | file->f_flags |= O_SYNC; |
1013 | spin_unlock(&file->f_lock); | 1052 | spin_unlock(&file->f_lock); |
@@ -1017,52 +1056,20 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1017 | oldfs = get_fs(); set_fs(KERNEL_DS); | 1056 | oldfs = get_fs(); set_fs(KERNEL_DS); |
1018 | host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); | 1057 | host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); |
1019 | set_fs(oldfs); | 1058 | set_fs(oldfs); |
1020 | if (host_err >= 0) { | 1059 | if (host_err < 0) |
1021 | *cnt = host_err; | 1060 | goto out_nfserr; |
1022 | nfsdstats.io_write += host_err; | 1061 | *cnt = host_err; |
1023 | fsnotify_modify(file->f_path.dentry); | 1062 | nfsdstats.io_write += host_err; |
1024 | } | 1063 | fsnotify_modify(file->f_path.dentry); |
1025 | 1064 | ||
1026 | /* clear setuid/setgid flag after write */ | 1065 | /* clear setuid/setgid flag after write */ |
1027 | if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) | 1066 | if (inode->i_mode & (S_ISUID | S_ISGID)) |
1028 | kill_suid(dentry); | 1067 | kill_suid(dentry); |
1029 | 1068 | ||
1030 | if (host_err >= 0 && stable) { | 1069 | if (stable && use_wgather) |
1031 | static ino_t last_ino; | 1070 | host_err = wait_for_concurrent_writes(file); |
1032 | static dev_t last_dev; | ||
1033 | |||
1034 | /* | ||
1035 | * Gathered writes: If another process is currently | ||
1036 | * writing to the file, there's a high chance | ||
1037 | * this is another nfsd (triggered by a bulk write | ||
1038 | * from a client's biod). Rather than syncing the | ||
1039 | * file with each write request, we sleep for 10 msec. | ||
1040 | * | ||
1041 | * I don't know if this roughly approximates | ||
1042 | * C. Juszak's idea of gathered writes, but it's a | ||
1043 | * nice and simple solution (IMHO), and it seems to | ||
1044 | * work:-) | ||
1045 | */ | ||
1046 | if (EX_WGATHER(exp)) { | ||
1047 | if (atomic_read(&inode->i_writecount) > 1 | ||
1048 | || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) { | ||
1049 | dprintk("nfsd: write defer %d\n", task_pid_nr(current)); | ||
1050 | msleep(10); | ||
1051 | dprintk("nfsd: write resume %d\n", task_pid_nr(current)); | ||
1052 | } | ||
1053 | |||
1054 | if (inode->i_state & I_DIRTY) { | ||
1055 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); | ||
1056 | host_err=nfsd_sync(file); | ||
1057 | } | ||
1058 | #if 0 | ||
1059 | wake_up(&inode->i_wait); | ||
1060 | #endif | ||
1061 | } | ||
1062 | last_ino = inode->i_ino; | ||
1063 | last_dev = inode->i_sb->s_dev; | ||
1064 | } | ||
1065 | 1071 | ||
1072 | out_nfserr: | ||
1066 | dprintk("nfsd: write complete host_err=%d\n", host_err); | 1073 | dprintk("nfsd: write complete host_err=%d\n", host_err); |
1067 | if (host_err >= 0) | 1074 | if (host_err >= 0) |
1068 | err = 0; | 1075 | err = 0; |
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 2696d6b513b7..fe9d8f2a13f8 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c | |||
@@ -309,10 +309,6 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode) | |||
309 | /* ii->i_file_acl = 0; */ | 309 | /* ii->i_file_acl = 0; */ |
310 | /* ii->i_dir_acl = 0; */ | 310 | /* ii->i_dir_acl = 0; */ |
311 | ii->i_dir_start_lookup = 0; | 311 | ii->i_dir_start_lookup = 0; |
312 | #ifdef CONFIG_NILFS_FS_POSIX_ACL | ||
313 | ii->i_acl = NULL; | ||
314 | ii->i_default_acl = NULL; | ||
315 | #endif | ||
316 | ii->i_cno = 0; | 312 | ii->i_cno = 0; |
317 | nilfs_set_inode_flags(inode); | 313 | nilfs_set_inode_flags(inode); |
318 | spin_lock(&sbi->s_next_gen_lock); | 314 | spin_lock(&sbi->s_next_gen_lock); |
@@ -434,10 +430,6 @@ static int __nilfs_read_inode(struct super_block *sb, unsigned long ino, | |||
434 | 430 | ||
435 | raw_inode = nilfs_ifile_map_inode(sbi->s_ifile, ino, bh); | 431 | raw_inode = nilfs_ifile_map_inode(sbi->s_ifile, ino, bh); |
436 | 432 | ||
437 | #ifdef CONFIG_NILFS_FS_POSIX_ACL | ||
438 | ii->i_acl = NILFS_ACL_NOT_CACHED; | ||
439 | ii->i_default_acl = NILFS_ACL_NOT_CACHED; | ||
440 | #endif | ||
441 | if (nilfs_read_inode_common(inode, raw_inode)) | 433 | if (nilfs_read_inode_common(inode, raw_inode)) |
442 | goto failed_unmap; | 434 | goto failed_unmap; |
443 | 435 | ||
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index edf6a59d9f2a..724c63766e82 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h | |||
@@ -58,10 +58,6 @@ struct nilfs_inode_info { | |||
58 | */ | 58 | */ |
59 | struct rw_semaphore xattr_sem; | 59 | struct rw_semaphore xattr_sem; |
60 | #endif | 60 | #endif |
61 | #ifdef CONFIG_NILFS_POSIX_ACL | ||
62 | struct posix_acl *i_acl; | ||
63 | struct posix_acl *i_default_acl; | ||
64 | #endif | ||
65 | struct buffer_head *i_bh; /* i_bh contains a new or dirty | 61 | struct buffer_head *i_bh; /* i_bh contains a new or dirty |
66 | disk inode */ | 62 | disk inode */ |
67 | struct inode vfs_inode; | 63 | struct inode vfs_inode; |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index ab785f85aa50..8e2ec43b18f4 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -189,16 +189,6 @@ static void nilfs_clear_inode(struct inode *inode) | |||
189 | { | 189 | { |
190 | struct nilfs_inode_info *ii = NILFS_I(inode); | 190 | struct nilfs_inode_info *ii = NILFS_I(inode); |
191 | 191 | ||
192 | #ifdef CONFIG_NILFS_POSIX_ACL | ||
193 | if (ii->i_acl && ii->i_acl != NILFS_ACL_NOT_CACHED) { | ||
194 | posix_acl_release(ii->i_acl); | ||
195 | ii->i_acl = NILFS_ACL_NOT_CACHED; | ||
196 | } | ||
197 | if (ii->i_default_acl && ii->i_default_acl != NILFS_ACL_NOT_CACHED) { | ||
198 | posix_acl_release(ii->i_default_acl); | ||
199 | ii->i_default_acl = NILFS_ACL_NOT_CACHED; | ||
200 | } | ||
201 | #endif | ||
202 | /* | 192 | /* |
203 | * Free resources allocated in nilfs_read_inode(), here. | 193 | * Free resources allocated in nilfs_read_inode(), here. |
204 | */ | 194 | */ |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index ff231ad23895..ff27a2965844 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -296,12 +296,15 @@ static int inotify_fasync(int fd, struct file *file, int on) | |||
296 | static int inotify_release(struct inode *ignored, struct file *file) | 296 | static int inotify_release(struct inode *ignored, struct file *file) |
297 | { | 297 | { |
298 | struct fsnotify_group *group = file->private_data; | 298 | struct fsnotify_group *group = file->private_data; |
299 | struct user_struct *user = group->inotify_data.user; | ||
299 | 300 | ||
300 | fsnotify_clear_marks_by_group(group); | 301 | fsnotify_clear_marks_by_group(group); |
301 | 302 | ||
302 | /* free this group, matching get was inotify_init->fsnotify_obtain_group */ | 303 | /* free this group, matching get was inotify_init->fsnotify_obtain_group */ |
303 | fsnotify_put_group(group); | 304 | fsnotify_put_group(group); |
304 | 305 | ||
306 | atomic_dec(&user->inotify_devs); | ||
307 | |||
305 | return 0; | 308 | return 0; |
306 | } | 309 | } |
307 | 310 | ||
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 6cdeaa76f27f..110bb57c46ab 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c | |||
@@ -92,6 +92,9 @@ struct ocfs2_unblock_ctl { | |||
92 | enum ocfs2_unblock_action unblock_action; | 92 | enum ocfs2_unblock_action unblock_action; |
93 | }; | 93 | }; |
94 | 94 | ||
95 | /* Lockdep class keys */ | ||
96 | struct lock_class_key lockdep_keys[OCFS2_NUM_LOCK_TYPES]; | ||
97 | |||
95 | static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres, | 98 | static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres, |
96 | int new_level); | 99 | int new_level); |
97 | static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres); | 100 | static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres); |
@@ -317,9 +320,16 @@ static int ocfs2_lock_create(struct ocfs2_super *osb, | |||
317 | u32 dlm_flags); | 320 | u32 dlm_flags); |
318 | static inline int ocfs2_may_continue_on_blocked_lock(struct ocfs2_lock_res *lockres, | 321 | static inline int ocfs2_may_continue_on_blocked_lock(struct ocfs2_lock_res *lockres, |
319 | int wanted); | 322 | int wanted); |
320 | static void ocfs2_cluster_unlock(struct ocfs2_super *osb, | 323 | static void __ocfs2_cluster_unlock(struct ocfs2_super *osb, |
321 | struct ocfs2_lock_res *lockres, | 324 | struct ocfs2_lock_res *lockres, |
322 | int level); | 325 | int level, unsigned long caller_ip); |
326 | static inline void ocfs2_cluster_unlock(struct ocfs2_super *osb, | ||
327 | struct ocfs2_lock_res *lockres, | ||
328 | int level) | ||
329 | { | ||
330 | __ocfs2_cluster_unlock(osb, lockres, level, _RET_IP_); | ||
331 | } | ||
332 | |||
323 | static inline void ocfs2_generic_handle_downconvert_action(struct ocfs2_lock_res *lockres); | 333 | static inline void ocfs2_generic_handle_downconvert_action(struct ocfs2_lock_res *lockres); |
324 | static inline void ocfs2_generic_handle_convert_action(struct ocfs2_lock_res *lockres); | 334 | static inline void ocfs2_generic_handle_convert_action(struct ocfs2_lock_res *lockres); |
325 | static inline void ocfs2_generic_handle_attach_action(struct ocfs2_lock_res *lockres); | 335 | static inline void ocfs2_generic_handle_attach_action(struct ocfs2_lock_res *lockres); |
@@ -489,6 +499,13 @@ static void ocfs2_lock_res_init_common(struct ocfs2_super *osb, | |||
489 | ocfs2_add_lockres_tracking(res, osb->osb_dlm_debug); | 499 | ocfs2_add_lockres_tracking(res, osb->osb_dlm_debug); |
490 | 500 | ||
491 | ocfs2_init_lock_stats(res); | 501 | ocfs2_init_lock_stats(res); |
502 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
503 | if (type != OCFS2_LOCK_TYPE_OPEN) | ||
504 | lockdep_init_map(&res->l_lockdep_map, ocfs2_lock_type_strings[type], | ||
505 | &lockdep_keys[type], 0); | ||
506 | else | ||
507 | res->l_lockdep_map.key = NULL; | ||
508 | #endif | ||
492 | } | 509 | } |
493 | 510 | ||
494 | void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res) | 511 | void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res) |
@@ -644,14 +661,10 @@ static void ocfs2_nfs_sync_lock_res_init(struct ocfs2_lock_res *res, | |||
644 | static void ocfs2_orphan_scan_lock_res_init(struct ocfs2_lock_res *res, | 661 | static void ocfs2_orphan_scan_lock_res_init(struct ocfs2_lock_res *res, |
645 | struct ocfs2_super *osb) | 662 | struct ocfs2_super *osb) |
646 | { | 663 | { |
647 | struct ocfs2_orphan_scan_lvb *lvb; | ||
648 | |||
649 | ocfs2_lock_res_init_once(res); | 664 | ocfs2_lock_res_init_once(res); |
650 | ocfs2_build_lock_name(OCFS2_LOCK_TYPE_ORPHAN_SCAN, 0, 0, res->l_name); | 665 | ocfs2_build_lock_name(OCFS2_LOCK_TYPE_ORPHAN_SCAN, 0, 0, res->l_name); |
651 | ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_ORPHAN_SCAN, | 666 | ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_ORPHAN_SCAN, |
652 | &ocfs2_orphan_scan_lops, osb); | 667 | &ocfs2_orphan_scan_lops, osb); |
653 | lvb = ocfs2_dlm_lvb(&res->l_lksb); | ||
654 | lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION; | ||
655 | } | 668 | } |
656 | 669 | ||
657 | void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, | 670 | void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, |
@@ -1256,11 +1269,13 @@ static int ocfs2_wait_for_mask_interruptible(struct ocfs2_mask_waiter *mw, | |||
1256 | return ret; | 1269 | return ret; |
1257 | } | 1270 | } |
1258 | 1271 | ||
1259 | static int ocfs2_cluster_lock(struct ocfs2_super *osb, | 1272 | static int __ocfs2_cluster_lock(struct ocfs2_super *osb, |
1260 | struct ocfs2_lock_res *lockres, | 1273 | struct ocfs2_lock_res *lockres, |
1261 | int level, | 1274 | int level, |
1262 | u32 lkm_flags, | 1275 | u32 lkm_flags, |
1263 | int arg_flags) | 1276 | int arg_flags, |
1277 | int l_subclass, | ||
1278 | unsigned long caller_ip) | ||
1264 | { | 1279 | { |
1265 | struct ocfs2_mask_waiter mw; | 1280 | struct ocfs2_mask_waiter mw; |
1266 | int wait, catch_signals = !(osb->s_mount_opt & OCFS2_MOUNT_NOINTR); | 1281 | int wait, catch_signals = !(osb->s_mount_opt & OCFS2_MOUNT_NOINTR); |
@@ -1403,13 +1418,37 @@ out: | |||
1403 | } | 1418 | } |
1404 | ocfs2_update_lock_stats(lockres, level, &mw, ret); | 1419 | ocfs2_update_lock_stats(lockres, level, &mw, ret); |
1405 | 1420 | ||
1421 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
1422 | if (!ret && lockres->l_lockdep_map.key != NULL) { | ||
1423 | if (level == DLM_LOCK_PR) | ||
1424 | rwsem_acquire_read(&lockres->l_lockdep_map, l_subclass, | ||
1425 | !!(arg_flags & OCFS2_META_LOCK_NOQUEUE), | ||
1426 | caller_ip); | ||
1427 | else | ||
1428 | rwsem_acquire(&lockres->l_lockdep_map, l_subclass, | ||
1429 | !!(arg_flags & OCFS2_META_LOCK_NOQUEUE), | ||
1430 | caller_ip); | ||
1431 | } | ||
1432 | #endif | ||
1406 | mlog_exit(ret); | 1433 | mlog_exit(ret); |
1407 | return ret; | 1434 | return ret; |
1408 | } | 1435 | } |
1409 | 1436 | ||
1410 | static void ocfs2_cluster_unlock(struct ocfs2_super *osb, | 1437 | static inline int ocfs2_cluster_lock(struct ocfs2_super *osb, |
1411 | struct ocfs2_lock_res *lockres, | 1438 | struct ocfs2_lock_res *lockres, |
1412 | int level) | 1439 | int level, |
1440 | u32 lkm_flags, | ||
1441 | int arg_flags) | ||
1442 | { | ||
1443 | return __ocfs2_cluster_lock(osb, lockres, level, lkm_flags, arg_flags, | ||
1444 | 0, _RET_IP_); | ||
1445 | } | ||
1446 | |||
1447 | |||
1448 | static void __ocfs2_cluster_unlock(struct ocfs2_super *osb, | ||
1449 | struct ocfs2_lock_res *lockres, | ||
1450 | int level, | ||
1451 | unsigned long caller_ip) | ||
1413 | { | 1452 | { |
1414 | unsigned long flags; | 1453 | unsigned long flags; |
1415 | 1454 | ||
@@ -1418,6 +1457,10 @@ static void ocfs2_cluster_unlock(struct ocfs2_super *osb, | |||
1418 | ocfs2_dec_holders(lockres, level); | 1457 | ocfs2_dec_holders(lockres, level); |
1419 | ocfs2_downconvert_on_unlock(osb, lockres); | 1458 | ocfs2_downconvert_on_unlock(osb, lockres); |
1420 | spin_unlock_irqrestore(&lockres->l_lock, flags); | 1459 | spin_unlock_irqrestore(&lockres->l_lock, flags); |
1460 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
1461 | if (lockres->l_lockdep_map.key != NULL) | ||
1462 | rwsem_release(&lockres->l_lockdep_map, 1, caller_ip); | ||
1463 | #endif | ||
1421 | mlog_exit_void(); | 1464 | mlog_exit_void(); |
1422 | } | 1465 | } |
1423 | 1466 | ||
@@ -1989,7 +2032,8 @@ static inline int ocfs2_meta_lvb_is_trustable(struct inode *inode, | |||
1989 | { | 2032 | { |
1990 | struct ocfs2_meta_lvb *lvb = ocfs2_dlm_lvb(&lockres->l_lksb); | 2033 | struct ocfs2_meta_lvb *lvb = ocfs2_dlm_lvb(&lockres->l_lksb); |
1991 | 2034 | ||
1992 | if (lvb->lvb_version == OCFS2_LVB_VERSION | 2035 | if (ocfs2_dlm_lvb_valid(&lockres->l_lksb) |
2036 | && lvb->lvb_version == OCFS2_LVB_VERSION | ||
1993 | && be32_to_cpu(lvb->lvb_igeneration) == inode->i_generation) | 2037 | && be32_to_cpu(lvb->lvb_igeneration) == inode->i_generation) |
1994 | return 1; | 2038 | return 1; |
1995 | return 0; | 2039 | return 0; |
@@ -2162,10 +2206,11 @@ static int ocfs2_assign_bh(struct inode *inode, | |||
2162 | * returns < 0 error if the callback will never be called, otherwise | 2206 | * returns < 0 error if the callback will never be called, otherwise |
2163 | * the result of the lock will be communicated via the callback. | 2207 | * the result of the lock will be communicated via the callback. |
2164 | */ | 2208 | */ |
2165 | int ocfs2_inode_lock_full(struct inode *inode, | 2209 | int ocfs2_inode_lock_full_nested(struct inode *inode, |
2166 | struct buffer_head **ret_bh, | 2210 | struct buffer_head **ret_bh, |
2167 | int ex, | 2211 | int ex, |
2168 | int arg_flags) | 2212 | int arg_flags, |
2213 | int subclass) | ||
2169 | { | 2214 | { |
2170 | int status, level, acquired; | 2215 | int status, level, acquired; |
2171 | u32 dlm_flags; | 2216 | u32 dlm_flags; |
@@ -2203,7 +2248,8 @@ int ocfs2_inode_lock_full(struct inode *inode, | |||
2203 | if (arg_flags & OCFS2_META_LOCK_NOQUEUE) | 2248 | if (arg_flags & OCFS2_META_LOCK_NOQUEUE) |
2204 | dlm_flags |= DLM_LKF_NOQUEUE; | 2249 | dlm_flags |= DLM_LKF_NOQUEUE; |
2205 | 2250 | ||
2206 | status = ocfs2_cluster_lock(osb, lockres, level, dlm_flags, arg_flags); | 2251 | status = __ocfs2_cluster_lock(osb, lockres, level, dlm_flags, |
2252 | arg_flags, subclass, _RET_IP_); | ||
2207 | if (status < 0) { | 2253 | if (status < 0) { |
2208 | if (status != -EAGAIN && status != -EIOCBRETRY) | 2254 | if (status != -EAGAIN && status != -EIOCBRETRY) |
2209 | mlog_errno(status); | 2255 | mlog_errno(status); |
@@ -2369,35 +2415,45 @@ void ocfs2_inode_unlock(struct inode *inode, | |||
2369 | mlog_exit_void(); | 2415 | mlog_exit_void(); |
2370 | } | 2416 | } |
2371 | 2417 | ||
2372 | int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex) | 2418 | int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno) |
2373 | { | 2419 | { |
2374 | struct ocfs2_lock_res *lockres; | 2420 | struct ocfs2_lock_res *lockres; |
2375 | struct ocfs2_orphan_scan_lvb *lvb; | 2421 | struct ocfs2_orphan_scan_lvb *lvb; |
2376 | int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR; | ||
2377 | int status = 0; | 2422 | int status = 0; |
2378 | 2423 | ||
2424 | if (ocfs2_is_hard_readonly(osb)) | ||
2425 | return -EROFS; | ||
2426 | |||
2427 | if (ocfs2_mount_local(osb)) | ||
2428 | return 0; | ||
2429 | |||
2379 | lockres = &osb->osb_orphan_scan.os_lockres; | 2430 | lockres = &osb->osb_orphan_scan.os_lockres; |
2380 | status = ocfs2_cluster_lock(osb, lockres, level, 0, 0); | 2431 | status = ocfs2_cluster_lock(osb, lockres, DLM_LOCK_EX, 0, 0); |
2381 | if (status < 0) | 2432 | if (status < 0) |
2382 | return status; | 2433 | return status; |
2383 | 2434 | ||
2384 | lvb = ocfs2_dlm_lvb(&lockres->l_lksb); | 2435 | lvb = ocfs2_dlm_lvb(&lockres->l_lksb); |
2385 | if (lvb->lvb_version == OCFS2_ORPHAN_LVB_VERSION) | 2436 | if (ocfs2_dlm_lvb_valid(&lockres->l_lksb) && |
2437 | lvb->lvb_version == OCFS2_ORPHAN_LVB_VERSION) | ||
2386 | *seqno = be32_to_cpu(lvb->lvb_os_seqno); | 2438 | *seqno = be32_to_cpu(lvb->lvb_os_seqno); |
2439 | else | ||
2440 | *seqno = osb->osb_orphan_scan.os_seqno + 1; | ||
2441 | |||
2387 | return status; | 2442 | return status; |
2388 | } | 2443 | } |
2389 | 2444 | ||
2390 | void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex) | 2445 | void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno) |
2391 | { | 2446 | { |
2392 | struct ocfs2_lock_res *lockres; | 2447 | struct ocfs2_lock_res *lockres; |
2393 | struct ocfs2_orphan_scan_lvb *lvb; | 2448 | struct ocfs2_orphan_scan_lvb *lvb; |
2394 | int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR; | ||
2395 | 2449 | ||
2396 | lockres = &osb->osb_orphan_scan.os_lockres; | 2450 | if (!ocfs2_is_hard_readonly(osb) && !ocfs2_mount_local(osb)) { |
2397 | lvb = ocfs2_dlm_lvb(&lockres->l_lksb); | 2451 | lockres = &osb->osb_orphan_scan.os_lockres; |
2398 | lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION; | 2452 | lvb = ocfs2_dlm_lvb(&lockres->l_lksb); |
2399 | lvb->lvb_os_seqno = cpu_to_be32(seqno); | 2453 | lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION; |
2400 | ocfs2_cluster_unlock(osb, lockres, level); | 2454 | lvb->lvb_os_seqno = cpu_to_be32(seqno); |
2455 | ocfs2_cluster_unlock(osb, lockres, DLM_LOCK_EX); | ||
2456 | } | ||
2401 | } | 2457 | } |
2402 | 2458 | ||
2403 | int ocfs2_super_lock(struct ocfs2_super *osb, | 2459 | int ocfs2_super_lock(struct ocfs2_super *osb, |
@@ -3627,7 +3683,8 @@ static int ocfs2_refresh_qinfo(struct ocfs2_mem_dqinfo *oinfo) | |||
3627 | struct ocfs2_global_disk_dqinfo *gdinfo; | 3683 | struct ocfs2_global_disk_dqinfo *gdinfo; |
3628 | int status = 0; | 3684 | int status = 0; |
3629 | 3685 | ||
3630 | if (lvb->lvb_version == OCFS2_QINFO_LVB_VERSION) { | 3686 | if (ocfs2_dlm_lvb_valid(&lockres->l_lksb) && |
3687 | lvb->lvb_version == OCFS2_QINFO_LVB_VERSION) { | ||
3631 | info->dqi_bgrace = be32_to_cpu(lvb->lvb_bgrace); | 3688 | info->dqi_bgrace = be32_to_cpu(lvb->lvb_bgrace); |
3632 | info->dqi_igrace = be32_to_cpu(lvb->lvb_igrace); | 3689 | info->dqi_igrace = be32_to_cpu(lvb->lvb_igrace); |
3633 | oinfo->dqi_syncms = be32_to_cpu(lvb->lvb_syncms); | 3690 | oinfo->dqi_syncms = be32_to_cpu(lvb->lvb_syncms); |
diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h index 31b90d7b8f51..7553836931de 100644 --- a/fs/ocfs2/dlmglue.h +++ b/fs/ocfs2/dlmglue.h | |||
@@ -78,6 +78,14 @@ struct ocfs2_orphan_scan_lvb { | |||
78 | /* don't block waiting for the downconvert thread, instead return -EAGAIN */ | 78 | /* don't block waiting for the downconvert thread, instead return -EAGAIN */ |
79 | #define OCFS2_LOCK_NONBLOCK (0x04) | 79 | #define OCFS2_LOCK_NONBLOCK (0x04) |
80 | 80 | ||
81 | /* Locking subclasses of inode cluster lock */ | ||
82 | enum { | ||
83 | OI_LS_NORMAL = 0, | ||
84 | OI_LS_PARENT, | ||
85 | OI_LS_RENAME1, | ||
86 | OI_LS_RENAME2, | ||
87 | }; | ||
88 | |||
81 | int ocfs2_dlm_init(struct ocfs2_super *osb); | 89 | int ocfs2_dlm_init(struct ocfs2_super *osb); |
82 | void ocfs2_dlm_shutdown(struct ocfs2_super *osb, int hangup_pending); | 90 | void ocfs2_dlm_shutdown(struct ocfs2_super *osb, int hangup_pending); |
83 | void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res); | 91 | void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res); |
@@ -104,25 +112,31 @@ void ocfs2_open_unlock(struct inode *inode); | |||
104 | int ocfs2_inode_lock_atime(struct inode *inode, | 112 | int ocfs2_inode_lock_atime(struct inode *inode, |
105 | struct vfsmount *vfsmnt, | 113 | struct vfsmount *vfsmnt, |
106 | int *level); | 114 | int *level); |
107 | int ocfs2_inode_lock_full(struct inode *inode, | 115 | int ocfs2_inode_lock_full_nested(struct inode *inode, |
108 | struct buffer_head **ret_bh, | 116 | struct buffer_head **ret_bh, |
109 | int ex, | 117 | int ex, |
110 | int arg_flags); | 118 | int arg_flags, |
119 | int subclass); | ||
111 | int ocfs2_inode_lock_with_page(struct inode *inode, | 120 | int ocfs2_inode_lock_with_page(struct inode *inode, |
112 | struct buffer_head **ret_bh, | 121 | struct buffer_head **ret_bh, |
113 | int ex, | 122 | int ex, |
114 | struct page *page); | 123 | struct page *page); |
124 | /* Variants without special locking class or flags */ | ||
125 | #define ocfs2_inode_lock_full(i, r, e, f)\ | ||
126 | ocfs2_inode_lock_full_nested(i, r, e, f, OI_LS_NORMAL) | ||
127 | #define ocfs2_inode_lock_nested(i, b, e, s)\ | ||
128 | ocfs2_inode_lock_full_nested(i, b, e, 0, s) | ||
115 | /* 99% of the time we don't want to supply any additional flags -- | 129 | /* 99% of the time we don't want to supply any additional flags -- |
116 | * those are for very specific cases only. */ | 130 | * those are for very specific cases only. */ |
117 | #define ocfs2_inode_lock(i, b, e) ocfs2_inode_lock_full(i, b, e, 0) | 131 | #define ocfs2_inode_lock(i, b, e) ocfs2_inode_lock_full_nested(i, b, e, 0, OI_LS_NORMAL) |
118 | void ocfs2_inode_unlock(struct inode *inode, | 132 | void ocfs2_inode_unlock(struct inode *inode, |
119 | int ex); | 133 | int ex); |
120 | int ocfs2_super_lock(struct ocfs2_super *osb, | 134 | int ocfs2_super_lock(struct ocfs2_super *osb, |
121 | int ex); | 135 | int ex); |
122 | void ocfs2_super_unlock(struct ocfs2_super *osb, | 136 | void ocfs2_super_unlock(struct ocfs2_super *osb, |
123 | int ex); | 137 | int ex); |
124 | int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex); | 138 | int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno); |
125 | void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex); | 139 | void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno); |
126 | 140 | ||
127 | int ocfs2_rename_lock(struct ocfs2_super *osb); | 141 | int ocfs2_rename_lock(struct ocfs2_super *osb); |
128 | void ocfs2_rename_unlock(struct ocfs2_super *osb); | 142 | void ocfs2_rename_unlock(struct ocfs2_super *osb); |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 07267e0da909..62442e413a00 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -2026,7 +2026,7 @@ static ssize_t ocfs2_file_splice_read(struct file *in, | |||
2026 | size_t len, | 2026 | size_t len, |
2027 | unsigned int flags) | 2027 | unsigned int flags) |
2028 | { | 2028 | { |
2029 | int ret = 0; | 2029 | int ret = 0, lock_level = 0; |
2030 | struct inode *inode = in->f_path.dentry->d_inode; | 2030 | struct inode *inode = in->f_path.dentry->d_inode; |
2031 | 2031 | ||
2032 | mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", in, pipe, | 2032 | mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", in, pipe, |
@@ -2037,12 +2037,12 @@ static ssize_t ocfs2_file_splice_read(struct file *in, | |||
2037 | /* | 2037 | /* |
2038 | * See the comment in ocfs2_file_aio_read() | 2038 | * See the comment in ocfs2_file_aio_read() |
2039 | */ | 2039 | */ |
2040 | ret = ocfs2_inode_lock(inode, NULL, 0); | 2040 | ret = ocfs2_inode_lock_atime(inode, in->f_vfsmnt, &lock_level); |
2041 | if (ret < 0) { | 2041 | if (ret < 0) { |
2042 | mlog_errno(ret); | 2042 | mlog_errno(ret); |
2043 | goto bail; | 2043 | goto bail; |
2044 | } | 2044 | } |
2045 | ocfs2_inode_unlock(inode, 0); | 2045 | ocfs2_inode_unlock(inode, lock_level); |
2046 | 2046 | ||
2047 | ret = generic_file_splice_read(in, ppos, pipe, len, flags); | 2047 | ret = generic_file_splice_read(in, ppos, pipe, len, flags); |
2048 | 2048 | ||
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 10e1fa87396a..4dc8890ba316 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
@@ -215,6 +215,8 @@ bail: | |||
215 | static int ocfs2_init_locked_inode(struct inode *inode, void *opaque) | 215 | static int ocfs2_init_locked_inode(struct inode *inode, void *opaque) |
216 | { | 216 | { |
217 | struct ocfs2_find_inode_args *args = opaque; | 217 | struct ocfs2_find_inode_args *args = opaque; |
218 | static struct lock_class_key ocfs2_quota_ip_alloc_sem_key, | ||
219 | ocfs2_file_ip_alloc_sem_key; | ||
218 | 220 | ||
219 | mlog_entry("inode = %p, opaque = %p\n", inode, opaque); | 221 | mlog_entry("inode = %p, opaque = %p\n", inode, opaque); |
220 | 222 | ||
@@ -223,6 +225,15 @@ static int ocfs2_init_locked_inode(struct inode *inode, void *opaque) | |||
223 | if (args->fi_sysfile_type != 0) | 225 | if (args->fi_sysfile_type != 0) |
224 | lockdep_set_class(&inode->i_mutex, | 226 | lockdep_set_class(&inode->i_mutex, |
225 | &ocfs2_sysfile_lock_key[args->fi_sysfile_type]); | 227 | &ocfs2_sysfile_lock_key[args->fi_sysfile_type]); |
228 | if (args->fi_sysfile_type == USER_QUOTA_SYSTEM_INODE || | ||
229 | args->fi_sysfile_type == GROUP_QUOTA_SYSTEM_INODE || | ||
230 | args->fi_sysfile_type == LOCAL_USER_QUOTA_SYSTEM_INODE || | ||
231 | args->fi_sysfile_type == LOCAL_GROUP_QUOTA_SYSTEM_INODE) | ||
232 | lockdep_set_class(&OCFS2_I(inode)->ip_alloc_sem, | ||
233 | &ocfs2_quota_ip_alloc_sem_key); | ||
234 | else | ||
235 | lockdep_set_class(&OCFS2_I(inode)->ip_alloc_sem, | ||
236 | &ocfs2_file_ip_alloc_sem_key); | ||
226 | 237 | ||
227 | mlog_exit(0); | 238 | mlog_exit(0); |
228 | return 0; | 239 | return 0; |
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 4a3b9e6b31ad..f033760ecbea 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c | |||
@@ -1880,13 +1880,20 @@ void ocfs2_queue_orphan_scan(struct ocfs2_super *osb) | |||
1880 | 1880 | ||
1881 | os = &osb->osb_orphan_scan; | 1881 | os = &osb->osb_orphan_scan; |
1882 | 1882 | ||
1883 | status = ocfs2_orphan_scan_lock(osb, &seqno, DLM_LOCK_EX); | 1883 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE) |
1884 | goto out; | ||
1885 | |||
1886 | status = ocfs2_orphan_scan_lock(osb, &seqno); | ||
1884 | if (status < 0) { | 1887 | if (status < 0) { |
1885 | if (status != -EAGAIN) | 1888 | if (status != -EAGAIN) |
1886 | mlog_errno(status); | 1889 | mlog_errno(status); |
1887 | goto out; | 1890 | goto out; |
1888 | } | 1891 | } |
1889 | 1892 | ||
1893 | /* Do no queue the tasks if the volume is being umounted */ | ||
1894 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE) | ||
1895 | goto unlock; | ||
1896 | |||
1890 | if (os->os_seqno != seqno) { | 1897 | if (os->os_seqno != seqno) { |
1891 | os->os_seqno = seqno; | 1898 | os->os_seqno = seqno; |
1892 | goto unlock; | 1899 | goto unlock; |
@@ -1903,7 +1910,7 @@ void ocfs2_queue_orphan_scan(struct ocfs2_super *osb) | |||
1903 | os->os_count++; | 1910 | os->os_count++; |
1904 | os->os_scantime = CURRENT_TIME; | 1911 | os->os_scantime = CURRENT_TIME; |
1905 | unlock: | 1912 | unlock: |
1906 | ocfs2_orphan_scan_unlock(osb, seqno, DLM_LOCK_EX); | 1913 | ocfs2_orphan_scan_unlock(osb, seqno); |
1907 | out: | 1914 | out: |
1908 | return; | 1915 | return; |
1909 | } | 1916 | } |
@@ -1920,8 +1927,9 @@ void ocfs2_orphan_scan_work(struct work_struct *work) | |||
1920 | 1927 | ||
1921 | mutex_lock(&os->os_lock); | 1928 | mutex_lock(&os->os_lock); |
1922 | ocfs2_queue_orphan_scan(osb); | 1929 | ocfs2_queue_orphan_scan(osb); |
1923 | schedule_delayed_work(&os->os_orphan_scan_work, | 1930 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_ACTIVE) |
1924 | ocfs2_orphan_scan_timeout()); | 1931 | schedule_delayed_work(&os->os_orphan_scan_work, |
1932 | ocfs2_orphan_scan_timeout()); | ||
1925 | mutex_unlock(&os->os_lock); | 1933 | mutex_unlock(&os->os_lock); |
1926 | } | 1934 | } |
1927 | 1935 | ||
@@ -1930,26 +1938,33 @@ void ocfs2_orphan_scan_stop(struct ocfs2_super *osb) | |||
1930 | struct ocfs2_orphan_scan *os; | 1938 | struct ocfs2_orphan_scan *os; |
1931 | 1939 | ||
1932 | os = &osb->osb_orphan_scan; | 1940 | os = &osb->osb_orphan_scan; |
1933 | mutex_lock(&os->os_lock); | 1941 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_ACTIVE) { |
1934 | cancel_delayed_work(&os->os_orphan_scan_work); | 1942 | atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE); |
1935 | mutex_unlock(&os->os_lock); | 1943 | mutex_lock(&os->os_lock); |
1944 | cancel_delayed_work(&os->os_orphan_scan_work); | ||
1945 | mutex_unlock(&os->os_lock); | ||
1946 | } | ||
1936 | } | 1947 | } |
1937 | 1948 | ||
1938 | int ocfs2_orphan_scan_init(struct ocfs2_super *osb) | 1949 | void ocfs2_orphan_scan_init(struct ocfs2_super *osb) |
1939 | { | 1950 | { |
1940 | struct ocfs2_orphan_scan *os; | 1951 | struct ocfs2_orphan_scan *os; |
1941 | 1952 | ||
1942 | os = &osb->osb_orphan_scan; | 1953 | os = &osb->osb_orphan_scan; |
1943 | os->os_osb = osb; | 1954 | os->os_osb = osb; |
1944 | os->os_count = 0; | 1955 | os->os_count = 0; |
1956 | os->os_seqno = 0; | ||
1945 | os->os_scantime = CURRENT_TIME; | 1957 | os->os_scantime = CURRENT_TIME; |
1946 | mutex_init(&os->os_lock); | 1958 | mutex_init(&os->os_lock); |
1947 | 1959 | INIT_DELAYED_WORK(&os->os_orphan_scan_work, ocfs2_orphan_scan_work); | |
1948 | INIT_DELAYED_WORK(&os->os_orphan_scan_work, | 1960 | |
1949 | ocfs2_orphan_scan_work); | 1961 | if (ocfs2_is_hard_readonly(osb) || ocfs2_mount_local(osb)) |
1950 | schedule_delayed_work(&os->os_orphan_scan_work, | 1962 | atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE); |
1951 | ocfs2_orphan_scan_timeout()); | 1963 | else { |
1952 | return 0; | 1964 | atomic_set(&os->os_state, ORPHAN_SCAN_ACTIVE); |
1965 | schedule_delayed_work(&os->os_orphan_scan_work, | ||
1966 | ocfs2_orphan_scan_timeout()); | ||
1967 | } | ||
1953 | } | 1968 | } |
1954 | 1969 | ||
1955 | struct ocfs2_orphan_filldir_priv { | 1970 | struct ocfs2_orphan_filldir_priv { |
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index 61045eeb3f6e..5432c7f79cc6 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h | |||
@@ -144,7 +144,7 @@ static inline void ocfs2_inode_set_new(struct ocfs2_super *osb, | |||
144 | } | 144 | } |
145 | 145 | ||
146 | /* Exported only for the journal struct init code in super.c. Do not call. */ | 146 | /* Exported only for the journal struct init code in super.c. Do not call. */ |
147 | int ocfs2_orphan_scan_init(struct ocfs2_super *osb); | 147 | void ocfs2_orphan_scan_init(struct ocfs2_super *osb); |
148 | void ocfs2_orphan_scan_stop(struct ocfs2_super *osb); | 148 | void ocfs2_orphan_scan_stop(struct ocfs2_super *osb); |
149 | void ocfs2_orphan_scan_exit(struct ocfs2_super *osb); | 149 | void ocfs2_orphan_scan_exit(struct ocfs2_super *osb); |
150 | 150 | ||
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 33464c6b60a2..8601f934010b 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -118,7 +118,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, | |||
118 | mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len, | 118 | mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len, |
119 | dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno); | 119 | dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno); |
120 | 120 | ||
121 | status = ocfs2_inode_lock(dir, NULL, 0); | 121 | status = ocfs2_inode_lock_nested(dir, NULL, 0, OI_LS_PARENT); |
122 | if (status < 0) { | 122 | if (status < 0) { |
123 | if (status != -ENOENT) | 123 | if (status != -ENOENT) |
124 | mlog_errno(status); | 124 | mlog_errno(status); |
@@ -636,7 +636,7 @@ static int ocfs2_link(struct dentry *old_dentry, | |||
636 | if (S_ISDIR(inode->i_mode)) | 636 | if (S_ISDIR(inode->i_mode)) |
637 | return -EPERM; | 637 | return -EPERM; |
638 | 638 | ||
639 | err = ocfs2_inode_lock(dir, &parent_fe_bh, 1); | 639 | err = ocfs2_inode_lock_nested(dir, &parent_fe_bh, 1, OI_LS_PARENT); |
640 | if (err < 0) { | 640 | if (err < 0) { |
641 | if (err != -ENOENT) | 641 | if (err != -ENOENT) |
642 | mlog_errno(err); | 642 | mlog_errno(err); |
@@ -800,7 +800,8 @@ static int ocfs2_unlink(struct inode *dir, | |||
800 | return -EPERM; | 800 | return -EPERM; |
801 | } | 801 | } |
802 | 802 | ||
803 | status = ocfs2_inode_lock(dir, &parent_node_bh, 1); | 803 | status = ocfs2_inode_lock_nested(dir, &parent_node_bh, 1, |
804 | OI_LS_PARENT); | ||
804 | if (status < 0) { | 805 | if (status < 0) { |
805 | if (status != -ENOENT) | 806 | if (status != -ENOENT) |
806 | mlog_errno(status); | 807 | mlog_errno(status); |
@@ -978,7 +979,8 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, | |||
978 | inode1 = tmpinode; | 979 | inode1 = tmpinode; |
979 | } | 980 | } |
980 | /* lock id2 */ | 981 | /* lock id2 */ |
981 | status = ocfs2_inode_lock(inode2, bh2, 1); | 982 | status = ocfs2_inode_lock_nested(inode2, bh2, 1, |
983 | OI_LS_RENAME1); | ||
982 | if (status < 0) { | 984 | if (status < 0) { |
983 | if (status != -ENOENT) | 985 | if (status != -ENOENT) |
984 | mlog_errno(status); | 986 | mlog_errno(status); |
@@ -987,7 +989,7 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, | |||
987 | } | 989 | } |
988 | 990 | ||
989 | /* lock id1 */ | 991 | /* lock id1 */ |
990 | status = ocfs2_inode_lock(inode1, bh1, 1); | 992 | status = ocfs2_inode_lock_nested(inode1, bh1, 1, OI_LS_RENAME2); |
991 | if (status < 0) { | 993 | if (status < 0) { |
992 | /* | 994 | /* |
993 | * An error return must mean that no cluster locks | 995 | * An error return must mean that no cluster locks |
@@ -1103,7 +1105,8 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1103 | * won't have to concurrently downconvert the inode and the | 1105 | * won't have to concurrently downconvert the inode and the |
1104 | * dentry locks. | 1106 | * dentry locks. |
1105 | */ | 1107 | */ |
1106 | status = ocfs2_inode_lock(old_inode, &old_inode_bh, 1); | 1108 | status = ocfs2_inode_lock_nested(old_inode, &old_inode_bh, 1, |
1109 | OI_LS_PARENT); | ||
1107 | if (status < 0) { | 1110 | if (status < 0) { |
1108 | if (status != -ENOENT) | 1111 | if (status != -ENOENT) |
1109 | mlog_errno(status); | 1112 | mlog_errno(status); |
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 18c1d9ec1c93..c9345ebb8493 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/workqueue.h> | 34 | #include <linux/workqueue.h> |
35 | #include <linux/kref.h> | 35 | #include <linux/kref.h> |
36 | #include <linux/mutex.h> | 36 | #include <linux/mutex.h> |
37 | #include <linux/lockdep.h> | ||
37 | #ifndef CONFIG_OCFS2_COMPAT_JBD | 38 | #ifndef CONFIG_OCFS2_COMPAT_JBD |
38 | # include <linux/jbd2.h> | 39 | # include <linux/jbd2.h> |
39 | #else | 40 | #else |
@@ -152,6 +153,14 @@ struct ocfs2_lock_res { | |||
152 | unsigned int l_lock_max_exmode; /* Max wait for EX */ | 153 | unsigned int l_lock_max_exmode; /* Max wait for EX */ |
153 | unsigned int l_lock_refresh; /* Disk refreshes */ | 154 | unsigned int l_lock_refresh; /* Disk refreshes */ |
154 | #endif | 155 | #endif |
156 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
157 | struct lockdep_map l_lockdep_map; | ||
158 | #endif | ||
159 | }; | ||
160 | |||
161 | enum ocfs2_orphan_scan_state { | ||
162 | ORPHAN_SCAN_ACTIVE, | ||
163 | ORPHAN_SCAN_INACTIVE | ||
155 | }; | 164 | }; |
156 | 165 | ||
157 | struct ocfs2_orphan_scan { | 166 | struct ocfs2_orphan_scan { |
@@ -162,6 +171,7 @@ struct ocfs2_orphan_scan { | |||
162 | struct timespec os_scantime; /* time this node ran the scan */ | 171 | struct timespec os_scantime; /* time this node ran the scan */ |
163 | u32 os_count; /* tracks node specific scans */ | 172 | u32 os_count; /* tracks node specific scans */ |
164 | u32 os_seqno; /* tracks cluster wide scans */ | 173 | u32 os_seqno; /* tracks cluster wide scans */ |
174 | atomic_t os_state; /* ACTIVE or INACTIVE */ | ||
165 | }; | 175 | }; |
166 | 176 | ||
167 | struct ocfs2_dlm_debug { | 177 | struct ocfs2_dlm_debug { |
diff --git a/fs/ocfs2/stack_o2cb.c b/fs/ocfs2/stack_o2cb.c index fcd120f1493a..3f661376a2de 100644 --- a/fs/ocfs2/stack_o2cb.c +++ b/fs/ocfs2/stack_o2cb.c | |||
@@ -236,6 +236,16 @@ static int o2cb_dlm_lock_status(union ocfs2_dlm_lksb *lksb) | |||
236 | return dlm_status_to_errno(lksb->lksb_o2dlm.status); | 236 | return dlm_status_to_errno(lksb->lksb_o2dlm.status); |
237 | } | 237 | } |
238 | 238 | ||
239 | /* | ||
240 | * o2dlm aways has a "valid" LVB. If the dlm loses track of the LVB | ||
241 | * contents, it will zero out the LVB. Thus the caller can always trust | ||
242 | * the contents. | ||
243 | */ | ||
244 | static int o2cb_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb) | ||
245 | { | ||
246 | return 1; | ||
247 | } | ||
248 | |||
239 | static void *o2cb_dlm_lvb(union ocfs2_dlm_lksb *lksb) | 249 | static void *o2cb_dlm_lvb(union ocfs2_dlm_lksb *lksb) |
240 | { | 250 | { |
241 | return (void *)(lksb->lksb_o2dlm.lvb); | 251 | return (void *)(lksb->lksb_o2dlm.lvb); |
@@ -354,6 +364,7 @@ static struct ocfs2_stack_operations o2cb_stack_ops = { | |||
354 | .dlm_lock = o2cb_dlm_lock, | 364 | .dlm_lock = o2cb_dlm_lock, |
355 | .dlm_unlock = o2cb_dlm_unlock, | 365 | .dlm_unlock = o2cb_dlm_unlock, |
356 | .lock_status = o2cb_dlm_lock_status, | 366 | .lock_status = o2cb_dlm_lock_status, |
367 | .lvb_valid = o2cb_dlm_lvb_valid, | ||
357 | .lock_lvb = o2cb_dlm_lvb, | 368 | .lock_lvb = o2cb_dlm_lvb, |
358 | .dump_lksb = o2cb_dump_lksb, | 369 | .dump_lksb = o2cb_dump_lksb, |
359 | }; | 370 | }; |
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index 9b76d41a8ac6..ff4c798a5635 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c | |||
@@ -738,6 +738,13 @@ static int user_dlm_lock_status(union ocfs2_dlm_lksb *lksb) | |||
738 | return lksb->lksb_fsdlm.sb_status; | 738 | return lksb->lksb_fsdlm.sb_status; |
739 | } | 739 | } |
740 | 740 | ||
741 | static int user_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb) | ||
742 | { | ||
743 | int invalid = lksb->lksb_fsdlm.sb_flags & DLM_SBF_VALNOTVALID; | ||
744 | |||
745 | return !invalid; | ||
746 | } | ||
747 | |||
741 | static void *user_dlm_lvb(union ocfs2_dlm_lksb *lksb) | 748 | static void *user_dlm_lvb(union ocfs2_dlm_lksb *lksb) |
742 | { | 749 | { |
743 | if (!lksb->lksb_fsdlm.sb_lvbptr) | 750 | if (!lksb->lksb_fsdlm.sb_lvbptr) |
@@ -873,6 +880,7 @@ static struct ocfs2_stack_operations ocfs2_user_plugin_ops = { | |||
873 | .dlm_lock = user_dlm_lock, | 880 | .dlm_lock = user_dlm_lock, |
874 | .dlm_unlock = user_dlm_unlock, | 881 | .dlm_unlock = user_dlm_unlock, |
875 | .lock_status = user_dlm_lock_status, | 882 | .lock_status = user_dlm_lock_status, |
883 | .lvb_valid = user_dlm_lvb_valid, | ||
876 | .lock_lvb = user_dlm_lvb, | 884 | .lock_lvb = user_dlm_lvb, |
877 | .plock = user_plock, | 885 | .plock = user_plock, |
878 | .dump_lksb = user_dlm_dump_lksb, | 886 | .dump_lksb = user_dlm_dump_lksb, |
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c index 68b668b0e60a..3f2f1c45b7b6 100644 --- a/fs/ocfs2/stackglue.c +++ b/fs/ocfs2/stackglue.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Code which implements an OCFS2 specific interface to underlying | 6 | * Code which implements an OCFS2 specific interface to underlying |
7 | * cluster stacks. | 7 | * cluster stacks. |
8 | * | 8 | * |
9 | * Copyright (C) 2007 Oracle. All rights reserved. | 9 | * Copyright (C) 2007, 2009 Oracle. All rights reserved. |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or | 11 | * This program is free software; you can redistribute it and/or |
12 | * modify it under the terms of the GNU General Public | 12 | * modify it under the terms of the GNU General Public |
@@ -271,11 +271,12 @@ int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb) | |||
271 | } | 271 | } |
272 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lock_status); | 272 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lock_status); |
273 | 273 | ||
274 | /* | 274 | int ocfs2_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb) |
275 | * Why don't we cast to ocfs2_meta_lvb? The "clean" answer is that we | 275 | { |
276 | * don't cast at the glue level. The real answer is that the header | 276 | return active_stack->sp_ops->lvb_valid(lksb); |
277 | * ordering is nigh impossible. | 277 | } |
278 | */ | 278 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lvb_valid); |
279 | |||
279 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb) | 280 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb) |
280 | { | 281 | { |
281 | return active_stack->sp_ops->lock_lvb(lksb); | 282 | return active_stack->sp_ops->lock_lvb(lksb); |
diff --git a/fs/ocfs2/stackglue.h b/fs/ocfs2/stackglue.h index c571af375ef8..03a44d60eac9 100644 --- a/fs/ocfs2/stackglue.h +++ b/fs/ocfs2/stackglue.h | |||
@@ -186,6 +186,11 @@ struct ocfs2_stack_operations { | |||
186 | int (*lock_status)(union ocfs2_dlm_lksb *lksb); | 186 | int (*lock_status)(union ocfs2_dlm_lksb *lksb); |
187 | 187 | ||
188 | /* | 188 | /* |
189 | * Return non-zero if the LVB is valid. | ||
190 | */ | ||
191 | int (*lvb_valid)(union ocfs2_dlm_lksb *lksb); | ||
192 | |||
193 | /* | ||
189 | * Pull the lvb pointer off of the stack-specific lksb. | 194 | * Pull the lvb pointer off of the stack-specific lksb. |
190 | */ | 195 | */ |
191 | void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb); | 196 | void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb); |
@@ -252,6 +257,7 @@ int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn, | |||
252 | struct ocfs2_lock_res *astarg); | 257 | struct ocfs2_lock_res *astarg); |
253 | 258 | ||
254 | int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb); | 259 | int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb); |
260 | int ocfs2_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb); | ||
255 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); | 261 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); |
256 | void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb); | 262 | void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb); |
257 | 263 | ||
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 8439f6b324b9..73a16d4666dc 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
@@ -923,14 +923,23 @@ static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh, | |||
923 | int nr) | 923 | int nr) |
924 | { | 924 | { |
925 | struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data; | 925 | struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data; |
926 | int ret; | ||
926 | 927 | ||
927 | if (ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap)) | 928 | if (ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap)) |
928 | return 0; | 929 | return 0; |
929 | if (!buffer_jbd(bg_bh) || !bh2jh(bg_bh)->b_committed_data) | 930 | |
931 | if (!buffer_jbd(bg_bh)) | ||
930 | return 1; | 932 | return 1; |
931 | 933 | ||
934 | jbd_lock_bh_state(bg_bh); | ||
932 | bg = (struct ocfs2_group_desc *) bh2jh(bg_bh)->b_committed_data; | 935 | bg = (struct ocfs2_group_desc *) bh2jh(bg_bh)->b_committed_data; |
933 | return !ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap); | 936 | if (bg) |
937 | ret = !ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap); | ||
938 | else | ||
939 | ret = 1; | ||
940 | jbd_unlock_bh_state(bg_bh); | ||
941 | |||
942 | return ret; | ||
934 | } | 943 | } |
935 | 944 | ||
936 | static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb, | 945 | static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb, |
@@ -1885,6 +1894,7 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle, | |||
1885 | unsigned int tmp; | 1894 | unsigned int tmp; |
1886 | int journal_type = OCFS2_JOURNAL_ACCESS_WRITE; | 1895 | int journal_type = OCFS2_JOURNAL_ACCESS_WRITE; |
1887 | struct ocfs2_group_desc *undo_bg = NULL; | 1896 | struct ocfs2_group_desc *undo_bg = NULL; |
1897 | int cluster_bitmap = 0; | ||
1888 | 1898 | ||
1889 | mlog_entry_void(); | 1899 | mlog_entry_void(); |
1890 | 1900 | ||
@@ -1905,18 +1915,28 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle, | |||
1905 | } | 1915 | } |
1906 | 1916 | ||
1907 | if (ocfs2_is_cluster_bitmap(alloc_inode)) | 1917 | if (ocfs2_is_cluster_bitmap(alloc_inode)) |
1908 | undo_bg = (struct ocfs2_group_desc *) bh2jh(group_bh)->b_committed_data; | 1918 | cluster_bitmap = 1; |
1919 | |||
1920 | if (cluster_bitmap) { | ||
1921 | jbd_lock_bh_state(group_bh); | ||
1922 | undo_bg = (struct ocfs2_group_desc *) | ||
1923 | bh2jh(group_bh)->b_committed_data; | ||
1924 | BUG_ON(!undo_bg); | ||
1925 | } | ||
1909 | 1926 | ||
1910 | tmp = num_bits; | 1927 | tmp = num_bits; |
1911 | while(tmp--) { | 1928 | while(tmp--) { |
1912 | ocfs2_clear_bit((bit_off + tmp), | 1929 | ocfs2_clear_bit((bit_off + tmp), |
1913 | (unsigned long *) bg->bg_bitmap); | 1930 | (unsigned long *) bg->bg_bitmap); |
1914 | if (ocfs2_is_cluster_bitmap(alloc_inode)) | 1931 | if (cluster_bitmap) |
1915 | ocfs2_set_bit(bit_off + tmp, | 1932 | ocfs2_set_bit(bit_off + tmp, |
1916 | (unsigned long *) undo_bg->bg_bitmap); | 1933 | (unsigned long *) undo_bg->bg_bitmap); |
1917 | } | 1934 | } |
1918 | le16_add_cpu(&bg->bg_free_bits_count, num_bits); | 1935 | le16_add_cpu(&bg->bg_free_bits_count, num_bits); |
1919 | 1936 | ||
1937 | if (cluster_bitmap) | ||
1938 | jbd_unlock_bh_state(group_bh); | ||
1939 | |||
1920 | status = ocfs2_journal_dirty(handle, group_bh); | 1940 | status = ocfs2_journal_dirty(handle, group_bh); |
1921 | if (status < 0) | 1941 | if (status < 0) |
1922 | mlog_errno(status); | 1942 | mlog_errno(status); |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 0d3ed7407a04..7efb349fb9bd 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -205,11 +205,10 @@ static const match_table_t tokens = { | |||
205 | #ifdef CONFIG_DEBUG_FS | 205 | #ifdef CONFIG_DEBUG_FS |
206 | static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | 206 | static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) |
207 | { | 207 | { |
208 | int out = 0; | ||
209 | int i; | ||
210 | struct ocfs2_cluster_connection *cconn = osb->cconn; | 208 | struct ocfs2_cluster_connection *cconn = osb->cconn; |
211 | struct ocfs2_recovery_map *rm = osb->recovery_map; | 209 | struct ocfs2_recovery_map *rm = osb->recovery_map; |
212 | struct ocfs2_orphan_scan *os; | 210 | struct ocfs2_orphan_scan *os = &osb->osb_orphan_scan; |
211 | int i, out = 0; | ||
213 | 212 | ||
214 | out += snprintf(buf + out, len - out, | 213 | out += snprintf(buf + out, len - out, |
215 | "%10s => Id: %-s Uuid: %-s Gen: 0x%X Label: %-s\n", | 214 | "%10s => Id: %-s Uuid: %-s Gen: 0x%X Label: %-s\n", |
@@ -234,20 +233,24 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | |||
234 | "%10s => Opts: 0x%lX AtimeQuanta: %u\n", "Mount", | 233 | "%10s => Opts: 0x%lX AtimeQuanta: %u\n", "Mount", |
235 | osb->s_mount_opt, osb->s_atime_quantum); | 234 | osb->s_mount_opt, osb->s_atime_quantum); |
236 | 235 | ||
237 | out += snprintf(buf + out, len - out, | 236 | if (cconn) { |
238 | "%10s => Stack: %s Name: %*s Version: %d.%d\n", | 237 | out += snprintf(buf + out, len - out, |
239 | "Cluster", | 238 | "%10s => Stack: %s Name: %*s " |
240 | (*osb->osb_cluster_stack == '\0' ? | 239 | "Version: %d.%d\n", "Cluster", |
241 | "o2cb" : osb->osb_cluster_stack), | 240 | (*osb->osb_cluster_stack == '\0' ? |
242 | cconn->cc_namelen, cconn->cc_name, | 241 | "o2cb" : osb->osb_cluster_stack), |
243 | cconn->cc_version.pv_major, cconn->cc_version.pv_minor); | 242 | cconn->cc_namelen, cconn->cc_name, |
243 | cconn->cc_version.pv_major, | ||
244 | cconn->cc_version.pv_minor); | ||
245 | } | ||
244 | 246 | ||
245 | spin_lock(&osb->dc_task_lock); | 247 | spin_lock(&osb->dc_task_lock); |
246 | out += snprintf(buf + out, len - out, | 248 | out += snprintf(buf + out, len - out, |
247 | "%10s => Pid: %d Count: %lu WakeSeq: %lu " | 249 | "%10s => Pid: %d Count: %lu WakeSeq: %lu " |
248 | "WorkSeq: %lu\n", "DownCnvt", | 250 | "WorkSeq: %lu\n", "DownCnvt", |
249 | task_pid_nr(osb->dc_task), osb->blocked_lock_count, | 251 | (osb->dc_task ? task_pid_nr(osb->dc_task) : -1), |
250 | osb->dc_wake_sequence, osb->dc_work_sequence); | 252 | osb->blocked_lock_count, osb->dc_wake_sequence, |
253 | osb->dc_work_sequence); | ||
251 | spin_unlock(&osb->dc_task_lock); | 254 | spin_unlock(&osb->dc_task_lock); |
252 | 255 | ||
253 | spin_lock(&osb->osb_lock); | 256 | spin_lock(&osb->osb_lock); |
@@ -267,14 +270,15 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | |||
267 | 270 | ||
268 | out += snprintf(buf + out, len - out, | 271 | out += snprintf(buf + out, len - out, |
269 | "%10s => Pid: %d Interval: %lu Needs: %d\n", "Commit", | 272 | "%10s => Pid: %d Interval: %lu Needs: %d\n", "Commit", |
270 | task_pid_nr(osb->commit_task), osb->osb_commit_interval, | 273 | (osb->commit_task ? task_pid_nr(osb->commit_task) : -1), |
274 | osb->osb_commit_interval, | ||
271 | atomic_read(&osb->needs_checkpoint)); | 275 | atomic_read(&osb->needs_checkpoint)); |
272 | 276 | ||
273 | out += snprintf(buf + out, len - out, | 277 | out += snprintf(buf + out, len - out, |
274 | "%10s => State: %d NumTxns: %d TxnId: %lu\n", | 278 | "%10s => State: %d TxnId: %lu NumTxns: %d\n", |
275 | "Journal", osb->journal->j_state, | 279 | "Journal", osb->journal->j_state, |
276 | atomic_read(&osb->journal->j_num_trans), | 280 | osb->journal->j_trans_id, |
277 | osb->journal->j_trans_id); | 281 | atomic_read(&osb->journal->j_num_trans)); |
278 | 282 | ||
279 | out += snprintf(buf + out, len - out, | 283 | out += snprintf(buf + out, len - out, |
280 | "%10s => GlobalAllocs: %d LocalAllocs: %d " | 284 | "%10s => GlobalAllocs: %d LocalAllocs: %d " |
@@ -300,9 +304,18 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | |||
300 | atomic_read(&osb->s_num_inodes_stolen)); | 304 | atomic_read(&osb->s_num_inodes_stolen)); |
301 | spin_unlock(&osb->osb_lock); | 305 | spin_unlock(&osb->osb_lock); |
302 | 306 | ||
307 | out += snprintf(buf + out, len - out, "OrphanScan => "); | ||
308 | out += snprintf(buf + out, len - out, "Local: %u Global: %u ", | ||
309 | os->os_count, os->os_seqno); | ||
310 | out += snprintf(buf + out, len - out, " Last Scan: "); | ||
311 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE) | ||
312 | out += snprintf(buf + out, len - out, "Disabled\n"); | ||
313 | else | ||
314 | out += snprintf(buf + out, len - out, "%lu seconds ago\n", | ||
315 | (get_seconds() - os->os_scantime.tv_sec)); | ||
316 | |||
303 | out += snprintf(buf + out, len - out, "%10s => %3s %10s\n", | 317 | out += snprintf(buf + out, len - out, "%10s => %3s %10s\n", |
304 | "Slots", "Num", "RecoGen"); | 318 | "Slots", "Num", "RecoGen"); |
305 | |||
306 | for (i = 0; i < osb->max_slots; ++i) { | 319 | for (i = 0; i < osb->max_slots; ++i) { |
307 | out += snprintf(buf + out, len - out, | 320 | out += snprintf(buf + out, len - out, |
308 | "%10s %c %3d %10d\n", | 321 | "%10s %c %3d %10d\n", |
@@ -311,13 +324,6 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | |||
311 | i, osb->slot_recovery_generations[i]); | 324 | i, osb->slot_recovery_generations[i]); |
312 | } | 325 | } |
313 | 326 | ||
314 | os = &osb->osb_orphan_scan; | ||
315 | out += snprintf(buf + out, len - out, "Orphan Scan=> "); | ||
316 | out += snprintf(buf + out, len - out, "Local: %u Global: %u ", | ||
317 | os->os_count, os->os_seqno); | ||
318 | out += snprintf(buf + out, len - out, " Last Scan: %lu seconds ago\n", | ||
319 | (get_seconds() - os->os_scantime.tv_sec)); | ||
320 | |||
321 | return out; | 327 | return out; |
322 | } | 328 | } |
323 | 329 | ||
@@ -1175,6 +1181,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | |||
1175 | atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS); | 1181 | atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS); |
1176 | wake_up(&osb->osb_mount_event); | 1182 | wake_up(&osb->osb_mount_event); |
1177 | 1183 | ||
1184 | /* Start this when the mount is almost sure of being successful */ | ||
1185 | ocfs2_orphan_scan_init(osb); | ||
1186 | |||
1178 | mlog_exit(status); | 1187 | mlog_exit(status); |
1179 | return status; | 1188 | return status; |
1180 | 1189 | ||
@@ -1810,14 +1819,15 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) | |||
1810 | 1819 | ||
1811 | debugfs_remove(osb->osb_ctxt); | 1820 | debugfs_remove(osb->osb_ctxt); |
1812 | 1821 | ||
1822 | /* Orphan scan should be stopped as early as possible */ | ||
1823 | ocfs2_orphan_scan_stop(osb); | ||
1824 | |||
1813 | ocfs2_disable_quotas(osb); | 1825 | ocfs2_disable_quotas(osb); |
1814 | 1826 | ||
1815 | ocfs2_shutdown_local_alloc(osb); | 1827 | ocfs2_shutdown_local_alloc(osb); |
1816 | 1828 | ||
1817 | ocfs2_truncate_log_shutdown(osb); | 1829 | ocfs2_truncate_log_shutdown(osb); |
1818 | 1830 | ||
1819 | ocfs2_orphan_scan_stop(osb); | ||
1820 | |||
1821 | /* This will disable recovery and flush any recovery work. */ | 1831 | /* This will disable recovery and flush any recovery work. */ |
1822 | ocfs2_recovery_exit(osb); | 1832 | ocfs2_recovery_exit(osb); |
1823 | 1833 | ||
@@ -1978,13 +1988,6 @@ static int ocfs2_initialize_super(struct super_block *sb, | |||
1978 | goto bail; | 1988 | goto bail; |
1979 | } | 1989 | } |
1980 | 1990 | ||
1981 | status = ocfs2_orphan_scan_init(osb); | ||
1982 | if (status) { | ||
1983 | mlog(ML_ERROR, "Unable to initialize delayed orphan scan\n"); | ||
1984 | mlog_errno(status); | ||
1985 | goto bail; | ||
1986 | } | ||
1987 | |||
1988 | init_waitqueue_head(&osb->checkpoint_event); | 1991 | init_waitqueue_head(&osb->checkpoint_event); |
1989 | atomic_set(&osb->needs_checkpoint, 0); | 1992 | atomic_set(&osb->needs_checkpoint, 0); |
1990 | 1993 | ||
diff --git a/fs/ocfs2/sysfile.c b/fs/ocfs2/sysfile.c index ab713ebdd546..40e53702948c 100644 --- a/fs/ocfs2/sysfile.c +++ b/fs/ocfs2/sysfile.c | |||
@@ -50,6 +50,10 @@ static inline int is_in_system_inode_array(struct ocfs2_super *osb, | |||
50 | int type, | 50 | int type, |
51 | u32 slot); | 51 | u32 slot); |
52 | 52 | ||
53 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
54 | static struct lock_class_key ocfs2_sysfile_cluster_lock_key[NUM_SYSTEM_INODES]; | ||
55 | #endif | ||
56 | |||
53 | static inline int is_global_system_inode(int type) | 57 | static inline int is_global_system_inode(int type) |
54 | { | 58 | { |
55 | return type >= OCFS2_FIRST_ONLINE_SYSTEM_INODE && | 59 | return type >= OCFS2_FIRST_ONLINE_SYSTEM_INODE && |
@@ -118,6 +122,21 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb, | |||
118 | inode = NULL; | 122 | inode = NULL; |
119 | goto bail; | 123 | goto bail; |
120 | } | 124 | } |
125 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
126 | if (type == LOCAL_USER_QUOTA_SYSTEM_INODE || | ||
127 | type == LOCAL_GROUP_QUOTA_SYSTEM_INODE || | ||
128 | type == JOURNAL_SYSTEM_INODE) { | ||
129 | /* Ignore inode lock on these inodes as the lock does not | ||
130 | * really belong to any process and lockdep cannot handle | ||
131 | * that */ | ||
132 | OCFS2_I(inode)->ip_inode_lockres.l_lockdep_map.key = NULL; | ||
133 | } else { | ||
134 | lockdep_init_map(&OCFS2_I(inode)->ip_inode_lockres. | ||
135 | l_lockdep_map, | ||
136 | ocfs2_system_inodes[type].si_name, | ||
137 | &ocfs2_sysfile_cluster_lock_key[type], 0); | ||
138 | } | ||
139 | #endif | ||
121 | bail: | 140 | bail: |
122 | 141 | ||
123 | return inode; | 142 | return inode; |
@@ -378,63 +378,63 @@ SYSCALL_ALIAS(sys_ftruncate64, SyS_ftruncate64); | |||
378 | #endif | 378 | #endif |
379 | #endif /* BITS_PER_LONG == 32 */ | 379 | #endif /* BITS_PER_LONG == 32 */ |
380 | 380 | ||
381 | SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) | 381 | |
382 | int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | ||
382 | { | 383 | { |
383 | struct file *file; | 384 | struct inode *inode = file->f_path.dentry->d_inode; |
384 | struct inode *inode; | 385 | long ret; |
385 | long ret = -EINVAL; | ||
386 | 386 | ||
387 | if (offset < 0 || len <= 0) | 387 | if (offset < 0 || len <= 0) |
388 | goto out; | 388 | return -EINVAL; |
389 | 389 | ||
390 | /* Return error if mode is not supported */ | 390 | /* Return error if mode is not supported */ |
391 | ret = -EOPNOTSUPP; | ||
392 | if (mode && !(mode & FALLOC_FL_KEEP_SIZE)) | 391 | if (mode && !(mode & FALLOC_FL_KEEP_SIZE)) |
393 | goto out; | 392 | return -EOPNOTSUPP; |
394 | 393 | ||
395 | ret = -EBADF; | ||
396 | file = fget(fd); | ||
397 | if (!file) | ||
398 | goto out; | ||
399 | if (!(file->f_mode & FMODE_WRITE)) | 394 | if (!(file->f_mode & FMODE_WRITE)) |
400 | goto out_fput; | 395 | return -EBADF; |
401 | /* | 396 | /* |
402 | * Revalidate the write permissions, in case security policy has | 397 | * Revalidate the write permissions, in case security policy has |
403 | * changed since the files were opened. | 398 | * changed since the files were opened. |
404 | */ | 399 | */ |
405 | ret = security_file_permission(file, MAY_WRITE); | 400 | ret = security_file_permission(file, MAY_WRITE); |
406 | if (ret) | 401 | if (ret) |
407 | goto out_fput; | 402 | return ret; |
408 | 403 | ||
409 | inode = file->f_path.dentry->d_inode; | ||
410 | |||
411 | ret = -ESPIPE; | ||
412 | if (S_ISFIFO(inode->i_mode)) | 404 | if (S_ISFIFO(inode->i_mode)) |
413 | goto out_fput; | 405 | return -ESPIPE; |
414 | 406 | ||
415 | ret = -ENODEV; | ||
416 | /* | 407 | /* |
417 | * Let individual file system decide if it supports preallocation | 408 | * Let individual file system decide if it supports preallocation |
418 | * for directories or not. | 409 | * for directories or not. |
419 | */ | 410 | */ |
420 | if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) | 411 | if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) |
421 | goto out_fput; | 412 | return -ENODEV; |
422 | 413 | ||
423 | ret = -EFBIG; | ||
424 | /* Check for wrap through zero too */ | 414 | /* Check for wrap through zero too */ |
425 | if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) | 415 | if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) |
426 | goto out_fput; | 416 | return -EFBIG; |
427 | 417 | ||
428 | if (inode->i_op->fallocate) | 418 | if (!inode->i_op->fallocate) |
429 | ret = inode->i_op->fallocate(inode, mode, offset, len); | 419 | return -EOPNOTSUPP; |
430 | else | ||
431 | ret = -EOPNOTSUPP; | ||
432 | 420 | ||
433 | out_fput: | 421 | return inode->i_op->fallocate(inode, mode, offset, len); |
434 | fput(file); | ||
435 | out: | ||
436 | return ret; | ||
437 | } | 422 | } |
423 | |||
424 | SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) | ||
425 | { | ||
426 | struct file *file; | ||
427 | int error = -EBADF; | ||
428 | |||
429 | file = fget(fd); | ||
430 | if (file) { | ||
431 | error = do_fallocate(file, mode, offset, len); | ||
432 | fput(file); | ||
433 | } | ||
434 | |||
435 | return error; | ||
436 | } | ||
437 | |||
438 | #ifdef CONFIG_HAVE_SYSCALL_WRAPPERS | 438 | #ifdef CONFIG_HAVE_SYSCALL_WRAPPERS |
439 | asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len) | 439 | asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len) |
440 | { | 440 | { |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 6fd0f47e45db..a14d6cd9eeda 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -1131,8 +1131,6 @@ static void init_inode(struct inode *inode, struct treepath *path) | |||
1131 | REISERFS_I(inode)->i_trans_id = 0; | 1131 | REISERFS_I(inode)->i_trans_id = 0; |
1132 | REISERFS_I(inode)->i_jl = NULL; | 1132 | REISERFS_I(inode)->i_jl = NULL; |
1133 | mutex_init(&(REISERFS_I(inode)->i_mmap)); | 1133 | mutex_init(&(REISERFS_I(inode)->i_mmap)); |
1134 | reiserfs_init_acl_access(inode); | ||
1135 | reiserfs_init_acl_default(inode); | ||
1136 | reiserfs_init_xattr_rwsem(inode); | 1134 | reiserfs_init_xattr_rwsem(inode); |
1137 | 1135 | ||
1138 | if (stat_data_v1(ih)) { | 1136 | if (stat_data_v1(ih)) { |
@@ -1834,8 +1832,6 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, | |||
1834 | REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; | 1832 | REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; |
1835 | sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); | 1833 | sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); |
1836 | mutex_init(&(REISERFS_I(inode)->i_mmap)); | 1834 | mutex_init(&(REISERFS_I(inode)->i_mmap)); |
1837 | reiserfs_init_acl_access(inode); | ||
1838 | reiserfs_init_acl_default(inode); | ||
1839 | reiserfs_init_xattr_rwsem(inode); | 1835 | reiserfs_init_xattr_rwsem(inode); |
1840 | 1836 | ||
1841 | /* key to search for correct place for new stat data */ | 1837 | /* key to search for correct place for new stat data */ |
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c index 238e9d9b31e0..18b315d3d104 100644 --- a/fs/reiserfs/resize.c +++ b/fs/reiserfs/resize.c | |||
@@ -82,7 +82,6 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) | |||
82 | if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) { | 82 | if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) { |
83 | printk | 83 | printk |
84 | ("reiserfs_resize: unable to allocate memory for journal bitmaps\n"); | 84 | ("reiserfs_resize: unable to allocate memory for journal bitmaps\n"); |
85 | unlock_super(s); | ||
86 | return -ENOMEM; | 85 | return -ENOMEM; |
87 | } | 86 | } |
88 | /* the new journal bitmaps are zero filled, now we copy in the bitmap | 87 | /* the new journal bitmaps are zero filled, now we copy in the bitmap |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 2969773cfc22..d3aeb061612b 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -529,10 +529,6 @@ static void init_once(void *foo) | |||
529 | 529 | ||
530 | INIT_LIST_HEAD(&ei->i_prealloc_list); | 530 | INIT_LIST_HEAD(&ei->i_prealloc_list); |
531 | inode_init_once(&ei->vfs_inode); | 531 | inode_init_once(&ei->vfs_inode); |
532 | #ifdef CONFIG_REISERFS_FS_POSIX_ACL | ||
533 | ei->i_acl_access = NULL; | ||
534 | ei->i_acl_default = NULL; | ||
535 | #endif | ||
536 | } | 532 | } |
537 | 533 | ||
538 | static int init_inodecache(void) | 534 | static int init_inodecache(void) |
@@ -580,25 +576,6 @@ static void reiserfs_dirty_inode(struct inode *inode) | |||
580 | reiserfs_write_unlock(inode->i_sb); | 576 | reiserfs_write_unlock(inode->i_sb); |
581 | } | 577 | } |
582 | 578 | ||
583 | #ifdef CONFIG_REISERFS_FS_POSIX_ACL | ||
584 | static void reiserfs_clear_inode(struct inode *inode) | ||
585 | { | ||
586 | struct posix_acl *acl; | ||
587 | |||
588 | acl = REISERFS_I(inode)->i_acl_access; | ||
589 | if (acl && !IS_ERR(acl)) | ||
590 | posix_acl_release(acl); | ||
591 | REISERFS_I(inode)->i_acl_access = NULL; | ||
592 | |||
593 | acl = REISERFS_I(inode)->i_acl_default; | ||
594 | if (acl && !IS_ERR(acl)) | ||
595 | posix_acl_release(acl); | ||
596 | REISERFS_I(inode)->i_acl_default = NULL; | ||
597 | } | ||
598 | #else | ||
599 | #define reiserfs_clear_inode NULL | ||
600 | #endif | ||
601 | |||
602 | #ifdef CONFIG_QUOTA | 579 | #ifdef CONFIG_QUOTA |
603 | static ssize_t reiserfs_quota_write(struct super_block *, int, const char *, | 580 | static ssize_t reiserfs_quota_write(struct super_block *, int, const char *, |
604 | size_t, loff_t); | 581 | size_t, loff_t); |
@@ -612,7 +589,6 @@ static const struct super_operations reiserfs_sops = { | |||
612 | .write_inode = reiserfs_write_inode, | 589 | .write_inode = reiserfs_write_inode, |
613 | .dirty_inode = reiserfs_dirty_inode, | 590 | .dirty_inode = reiserfs_dirty_inode, |
614 | .delete_inode = reiserfs_delete_inode, | 591 | .delete_inode = reiserfs_delete_inode, |
615 | .clear_inode = reiserfs_clear_inode, | ||
616 | .put_super = reiserfs_put_super, | 592 | .put_super = reiserfs_put_super, |
617 | .write_super = reiserfs_write_super, | 593 | .write_super = reiserfs_write_super, |
618 | .sync_fs = reiserfs_sync_fs, | 594 | .sync_fs = reiserfs_sync_fs, |
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index c303c426fe2b..35d6e672a279 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c | |||
@@ -188,29 +188,6 @@ static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size) | |||
188 | return ERR_PTR(-EINVAL); | 188 | return ERR_PTR(-EINVAL); |
189 | } | 189 | } |
190 | 190 | ||
191 | static inline void iset_acl(struct inode *inode, struct posix_acl **i_acl, | ||
192 | struct posix_acl *acl) | ||
193 | { | ||
194 | spin_lock(&inode->i_lock); | ||
195 | if (*i_acl != ERR_PTR(-ENODATA)) | ||
196 | posix_acl_release(*i_acl); | ||
197 | *i_acl = posix_acl_dup(acl); | ||
198 | spin_unlock(&inode->i_lock); | ||
199 | } | ||
200 | |||
201 | static inline struct posix_acl *iget_acl(struct inode *inode, | ||
202 | struct posix_acl **i_acl) | ||
203 | { | ||
204 | struct posix_acl *acl = ERR_PTR(-ENODATA); | ||
205 | |||
206 | spin_lock(&inode->i_lock); | ||
207 | if (*i_acl != ERR_PTR(-ENODATA)) | ||
208 | acl = posix_acl_dup(*i_acl); | ||
209 | spin_unlock(&inode->i_lock); | ||
210 | |||
211 | return acl; | ||
212 | } | ||
213 | |||
214 | /* | 191 | /* |
215 | * Inode operation get_posix_acl(). | 192 | * Inode operation get_posix_acl(). |
216 | * | 193 | * |
@@ -220,34 +197,29 @@ static inline struct posix_acl *iget_acl(struct inode *inode, | |||
220 | struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) | 197 | struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) |
221 | { | 198 | { |
222 | char *name, *value; | 199 | char *name, *value; |
223 | struct posix_acl *acl, **p_acl; | 200 | struct posix_acl *acl; |
224 | int size; | 201 | int size; |
225 | int retval; | 202 | int retval; |
226 | struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); | 203 | |
204 | acl = get_cached_acl(inode, type); | ||
205 | if (acl != ACL_NOT_CACHED) | ||
206 | return acl; | ||
227 | 207 | ||
228 | switch (type) { | 208 | switch (type) { |
229 | case ACL_TYPE_ACCESS: | 209 | case ACL_TYPE_ACCESS: |
230 | name = POSIX_ACL_XATTR_ACCESS; | 210 | name = POSIX_ACL_XATTR_ACCESS; |
231 | p_acl = &reiserfs_i->i_acl_access; | ||
232 | break; | 211 | break; |
233 | case ACL_TYPE_DEFAULT: | 212 | case ACL_TYPE_DEFAULT: |
234 | name = POSIX_ACL_XATTR_DEFAULT; | 213 | name = POSIX_ACL_XATTR_DEFAULT; |
235 | p_acl = &reiserfs_i->i_acl_default; | ||
236 | break; | 214 | break; |
237 | default: | 215 | default: |
238 | return ERR_PTR(-EINVAL); | 216 | BUG(); |
239 | } | 217 | } |
240 | 218 | ||
241 | acl = iget_acl(inode, p_acl); | ||
242 | if (acl && !IS_ERR(acl)) | ||
243 | return acl; | ||
244 | else if (PTR_ERR(acl) == -ENODATA) | ||
245 | return NULL; | ||
246 | |||
247 | size = reiserfs_xattr_get(inode, name, NULL, 0); | 219 | size = reiserfs_xattr_get(inode, name, NULL, 0); |
248 | if (size < 0) { | 220 | if (size < 0) { |
249 | if (size == -ENODATA || size == -ENOSYS) { | 221 | if (size == -ENODATA || size == -ENOSYS) { |
250 | *p_acl = ERR_PTR(-ENODATA); | 222 | set_cached_acl(inode, type, NULL); |
251 | return NULL; | 223 | return NULL; |
252 | } | 224 | } |
253 | return ERR_PTR(size); | 225 | return ERR_PTR(size); |
@@ -262,14 +234,13 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) | |||
262 | /* This shouldn't actually happen as it should have | 234 | /* This shouldn't actually happen as it should have |
263 | been caught above.. but just in case */ | 235 | been caught above.. but just in case */ |
264 | acl = NULL; | 236 | acl = NULL; |
265 | *p_acl = ERR_PTR(-ENODATA); | ||
266 | } else if (retval < 0) { | 237 | } else if (retval < 0) { |
267 | acl = ERR_PTR(retval); | 238 | acl = ERR_PTR(retval); |
268 | } else { | 239 | } else { |
269 | acl = posix_acl_from_disk(value, retval); | 240 | acl = posix_acl_from_disk(value, retval); |
270 | if (!IS_ERR(acl)) | ||
271 | iset_acl(inode, p_acl, acl); | ||
272 | } | 241 | } |
242 | if (!IS_ERR(acl)) | ||
243 | set_cached_acl(inode, type, acl); | ||
273 | 244 | ||
274 | kfree(value); | 245 | kfree(value); |
275 | return acl; | 246 | return acl; |
@@ -287,10 +258,8 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, | |||
287 | { | 258 | { |
288 | char *name; | 259 | char *name; |
289 | void *value = NULL; | 260 | void *value = NULL; |
290 | struct posix_acl **p_acl; | ||
291 | size_t size = 0; | 261 | size_t size = 0; |
292 | int error; | 262 | int error; |
293 | struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); | ||
294 | 263 | ||
295 | if (S_ISLNK(inode->i_mode)) | 264 | if (S_ISLNK(inode->i_mode)) |
296 | return -EOPNOTSUPP; | 265 | return -EOPNOTSUPP; |
@@ -298,7 +267,6 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, | |||
298 | switch (type) { | 267 | switch (type) { |
299 | case ACL_TYPE_ACCESS: | 268 | case ACL_TYPE_ACCESS: |
300 | name = POSIX_ACL_XATTR_ACCESS; | 269 | name = POSIX_ACL_XATTR_ACCESS; |
301 | p_acl = &reiserfs_i->i_acl_access; | ||
302 | if (acl) { | 270 | if (acl) { |
303 | mode_t mode = inode->i_mode; | 271 | mode_t mode = inode->i_mode; |
304 | error = posix_acl_equiv_mode(acl, &mode); | 272 | error = posix_acl_equiv_mode(acl, &mode); |
@@ -313,7 +281,6 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, | |||
313 | break; | 281 | break; |
314 | case ACL_TYPE_DEFAULT: | 282 | case ACL_TYPE_DEFAULT: |
315 | name = POSIX_ACL_XATTR_DEFAULT; | 283 | name = POSIX_ACL_XATTR_DEFAULT; |
316 | p_acl = &reiserfs_i->i_acl_default; | ||
317 | if (!S_ISDIR(inode->i_mode)) | 284 | if (!S_ISDIR(inode->i_mode)) |
318 | return acl ? -EACCES : 0; | 285 | return acl ? -EACCES : 0; |
319 | break; | 286 | break; |
@@ -346,7 +313,7 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, | |||
346 | kfree(value); | 313 | kfree(value); |
347 | 314 | ||
348 | if (!error) | 315 | if (!error) |
349 | iset_acl(inode, p_acl, acl); | 316 | set_cached_acl(inode, type, acl); |
350 | 317 | ||
351 | return error; | 318 | return error; |
352 | } | 319 | } |
@@ -379,11 +346,8 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, | |||
379 | } | 346 | } |
380 | 347 | ||
381 | acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT); | 348 | acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT); |
382 | if (IS_ERR(acl)) { | 349 | if (IS_ERR(acl)) |
383 | if (PTR_ERR(acl) == -ENODATA) | ||
384 | goto apply_umask; | ||
385 | return PTR_ERR(acl); | 350 | return PTR_ERR(acl); |
386 | } | ||
387 | 351 | ||
388 | if (acl) { | 352 | if (acl) { |
389 | struct posix_acl *acl_copy; | 353 | struct posix_acl *acl_copy; |
diff --git a/fs/super.c b/fs/super.c index d40d53a22fb5..2761d3e22ed9 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -608,6 +608,7 @@ void emergency_remount(void) | |||
608 | 608 | ||
609 | static DEFINE_IDA(unnamed_dev_ida); | 609 | static DEFINE_IDA(unnamed_dev_ida); |
610 | static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */ | 610 | static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */ |
611 | static int unnamed_dev_start = 0; /* don't bother trying below it */ | ||
611 | 612 | ||
612 | int set_anon_super(struct super_block *s, void *data) | 613 | int set_anon_super(struct super_block *s, void *data) |
613 | { | 614 | { |
@@ -618,7 +619,9 @@ int set_anon_super(struct super_block *s, void *data) | |||
618 | if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0) | 619 | if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0) |
619 | return -ENOMEM; | 620 | return -ENOMEM; |
620 | spin_lock(&unnamed_dev_lock); | 621 | spin_lock(&unnamed_dev_lock); |
621 | error = ida_get_new(&unnamed_dev_ida, &dev); | 622 | error = ida_get_new_above(&unnamed_dev_ida, unnamed_dev_start, &dev); |
623 | if (!error) | ||
624 | unnamed_dev_start = dev + 1; | ||
622 | spin_unlock(&unnamed_dev_lock); | 625 | spin_unlock(&unnamed_dev_lock); |
623 | if (error == -EAGAIN) | 626 | if (error == -EAGAIN) |
624 | /* We raced and lost with another CPU. */ | 627 | /* We raced and lost with another CPU. */ |
@@ -629,6 +632,8 @@ int set_anon_super(struct super_block *s, void *data) | |||
629 | if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) { | 632 | if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) { |
630 | spin_lock(&unnamed_dev_lock); | 633 | spin_lock(&unnamed_dev_lock); |
631 | ida_remove(&unnamed_dev_ida, dev); | 634 | ida_remove(&unnamed_dev_ida, dev); |
635 | if (unnamed_dev_start > dev) | ||
636 | unnamed_dev_start = dev; | ||
632 | spin_unlock(&unnamed_dev_lock); | 637 | spin_unlock(&unnamed_dev_lock); |
633 | return -EMFILE; | 638 | return -EMFILE; |
634 | } | 639 | } |
@@ -645,6 +650,8 @@ void kill_anon_super(struct super_block *sb) | |||
645 | generic_shutdown_super(sb); | 650 | generic_shutdown_super(sb); |
646 | spin_lock(&unnamed_dev_lock); | 651 | spin_lock(&unnamed_dev_lock); |
647 | ida_remove(&unnamed_dev_ida, slot); | 652 | ida_remove(&unnamed_dev_ida, slot); |
653 | if (slot < unnamed_dev_start) | ||
654 | unnamed_dev_start = slot; | ||
648 | spin_unlock(&unnamed_dev_lock); | 655 | spin_unlock(&unnamed_dev_lock); |
649 | } | 656 | } |
650 | 657 | ||
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c index cfd31e229c89..adafcf556531 100644 --- a/fs/ubifs/xattr.c +++ b/fs/ubifs/xattr.c | |||
@@ -55,9 +55,9 @@ | |||
55 | * ACL support is not implemented. | 55 | * ACL support is not implemented. |
56 | */ | 56 | */ |
57 | 57 | ||
58 | #include "ubifs.h" | ||
58 | #include <linux/xattr.h> | 59 | #include <linux/xattr.h> |
59 | #include <linux/posix_acl_xattr.h> | 60 | #include <linux/posix_acl_xattr.h> |
60 | #include "ubifs.h" | ||
61 | 61 | ||
62 | /* | 62 | /* |
63 | * Limit the number of extended attributes per inode so that the total size | 63 | * Limit the number of extended attributes per inode so that the total size |
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index e48e9a3af763..1e068535b58b 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c | |||
@@ -238,7 +238,7 @@ static int udf_bitmap_prealloc_blocks(struct super_block *sb, | |||
238 | 238 | ||
239 | mutex_lock(&sbi->s_alloc_mutex); | 239 | mutex_lock(&sbi->s_alloc_mutex); |
240 | part_len = sbi->s_partmaps[partition].s_partition_len; | 240 | part_len = sbi->s_partmaps[partition].s_partition_len; |
241 | if (first_block < 0 || first_block >= part_len) | 241 | if (first_block >= part_len) |
242 | goto out; | 242 | goto out; |
243 | 243 | ||
244 | if (first_block + block_count > part_len) | 244 | if (first_block + block_count > part_len) |
@@ -297,7 +297,7 @@ static int udf_bitmap_new_block(struct super_block *sb, | |||
297 | mutex_lock(&sbi->s_alloc_mutex); | 297 | mutex_lock(&sbi->s_alloc_mutex); |
298 | 298 | ||
299 | repeat: | 299 | repeat: |
300 | if (goal < 0 || goal >= sbi->s_partmaps[partition].s_partition_len) | 300 | if (goal >= sbi->s_partmaps[partition].s_partition_len) |
301 | goal = 0; | 301 | goal = 0; |
302 | 302 | ||
303 | nr_groups = bitmap->s_nr_groups; | 303 | nr_groups = bitmap->s_nr_groups; |
@@ -666,8 +666,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb, | |||
666 | int8_t etype = -1; | 666 | int8_t etype = -1; |
667 | struct udf_inode_info *iinfo; | 667 | struct udf_inode_info *iinfo; |
668 | 668 | ||
669 | if (first_block < 0 || | 669 | if (first_block >= sbi->s_partmaps[partition].s_partition_len) |
670 | first_block >= sbi->s_partmaps[partition].s_partition_len) | ||
671 | return 0; | 670 | return 0; |
672 | 671 | ||
673 | iinfo = UDF_I(table); | 672 | iinfo = UDF_I(table); |
@@ -743,7 +742,7 @@ static int udf_table_new_block(struct super_block *sb, | |||
743 | return newblock; | 742 | return newblock; |
744 | 743 | ||
745 | mutex_lock(&sbi->s_alloc_mutex); | 744 | mutex_lock(&sbi->s_alloc_mutex); |
746 | if (goal < 0 || goal >= sbi->s_partmaps[partition].s_partition_len) | 745 | if (goal >= sbi->s_partmaps[partition].s_partition_len) |
747 | goal = 0; | 746 | goal = 0; |
748 | 747 | ||
749 | /* We search for the closest matching block to goal. If we find | 748 | /* We search for the closest matching block to goal. If we find |
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c index 703843f30ffd..1b88fd5df05d 100644 --- a/fs/udf/lowlevel.c +++ b/fs/udf/lowlevel.c | |||
@@ -56,7 +56,12 @@ unsigned long udf_get_last_block(struct super_block *sb) | |||
56 | struct block_device *bdev = sb->s_bdev; | 56 | struct block_device *bdev = sb->s_bdev; |
57 | unsigned long lblock = 0; | 57 | unsigned long lblock = 0; |
58 | 58 | ||
59 | if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock)) | 59 | /* |
60 | * ioctl failed or returned obviously bogus value? | ||
61 | * Try using the device size... | ||
62 | */ | ||
63 | if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock) || | ||
64 | lblock == 0) | ||
60 | lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits; | 65 | lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits; |
61 | 66 | ||
62 | if (lblock) | 67 | if (lblock) |
diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/linux-2.6/xfs_acl.c index 1e9d1246eebc..b23a54506446 100644 --- a/fs/xfs/linux-2.6/xfs_acl.c +++ b/fs/xfs/linux-2.6/xfs_acl.c | |||
@@ -25,14 +25,10 @@ | |||
25 | #include <linux/posix_acl_xattr.h> | 25 | #include <linux/posix_acl_xattr.h> |
26 | 26 | ||
27 | 27 | ||
28 | #define XFS_ACL_NOT_CACHED ((void *)-1) | ||
29 | |||
30 | /* | 28 | /* |
31 | * Locking scheme: | 29 | * Locking scheme: |
32 | * - all ACL updates are protected by inode->i_mutex, which is taken before | 30 | * - all ACL updates are protected by inode->i_mutex, which is taken before |
33 | * calling into this file. | 31 | * calling into this file. |
34 | * - access and updates to the ip->i_acl and ip->i_default_acl pointers are | ||
35 | * protected by inode->i_lock. | ||
36 | */ | 32 | */ |
37 | 33 | ||
38 | STATIC struct posix_acl * | 34 | STATIC struct posix_acl * |
@@ -102,59 +98,35 @@ xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl) | |||
102 | } | 98 | } |
103 | } | 99 | } |
104 | 100 | ||
105 | /* | ||
106 | * Update the cached ACL pointer in the inode. | ||
107 | * | ||
108 | * Because we don't hold any locks while reading/writing the attribute | ||
109 | * from/to disk another thread could have raced and updated the cached | ||
110 | * ACL value before us. In that case we release the previous cached value | ||
111 | * and update it with our new value. | ||
112 | */ | ||
113 | STATIC void | ||
114 | xfs_update_cached_acl(struct inode *inode, struct posix_acl **p_acl, | ||
115 | struct posix_acl *acl) | ||
116 | { | ||
117 | spin_lock(&inode->i_lock); | ||
118 | if (*p_acl && *p_acl != XFS_ACL_NOT_CACHED) | ||
119 | posix_acl_release(*p_acl); | ||
120 | *p_acl = posix_acl_dup(acl); | ||
121 | spin_unlock(&inode->i_lock); | ||
122 | } | ||
123 | |||
124 | struct posix_acl * | 101 | struct posix_acl * |
125 | xfs_get_acl(struct inode *inode, int type) | 102 | xfs_get_acl(struct inode *inode, int type) |
126 | { | 103 | { |
127 | struct xfs_inode *ip = XFS_I(inode); | 104 | struct xfs_inode *ip = XFS_I(inode); |
128 | struct posix_acl *acl = NULL, **p_acl; | 105 | struct posix_acl *acl; |
129 | struct xfs_acl *xfs_acl; | 106 | struct xfs_acl *xfs_acl; |
130 | int len = sizeof(struct xfs_acl); | 107 | int len = sizeof(struct xfs_acl); |
131 | char *ea_name; | 108 | char *ea_name; |
132 | int error; | 109 | int error; |
133 | 110 | ||
111 | acl = get_cached_acl(inode, type); | ||
112 | if (acl != ACL_NOT_CACHED) | ||
113 | return acl; | ||
114 | |||
134 | switch (type) { | 115 | switch (type) { |
135 | case ACL_TYPE_ACCESS: | 116 | case ACL_TYPE_ACCESS: |
136 | ea_name = SGI_ACL_FILE; | 117 | ea_name = SGI_ACL_FILE; |
137 | p_acl = &ip->i_acl; | ||
138 | break; | 118 | break; |
139 | case ACL_TYPE_DEFAULT: | 119 | case ACL_TYPE_DEFAULT: |
140 | ea_name = SGI_ACL_DEFAULT; | 120 | ea_name = SGI_ACL_DEFAULT; |
141 | p_acl = &ip->i_default_acl; | ||
142 | break; | 121 | break; |
143 | default: | 122 | default: |
144 | return ERR_PTR(-EINVAL); | 123 | BUG(); |
145 | } | 124 | } |
146 | 125 | ||
147 | spin_lock(&inode->i_lock); | ||
148 | if (*p_acl != XFS_ACL_NOT_CACHED) | ||
149 | acl = posix_acl_dup(*p_acl); | ||
150 | spin_unlock(&inode->i_lock); | ||
151 | |||
152 | /* | 126 | /* |
153 | * If we have a cached ACLs value just return it, not need to | 127 | * If we have a cached ACLs value just return it, not need to |
154 | * go out to the disk. | 128 | * go out to the disk. |
155 | */ | 129 | */ |
156 | if (acl) | ||
157 | return acl; | ||
158 | 130 | ||
159 | xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL); | 131 | xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL); |
160 | if (!xfs_acl) | 132 | if (!xfs_acl) |
@@ -165,7 +137,7 @@ xfs_get_acl(struct inode *inode, int type) | |||
165 | /* | 137 | /* |
166 | * If the attribute doesn't exist make sure we have a negative | 138 | * If the attribute doesn't exist make sure we have a negative |
167 | * cache entry, for any other error assume it is transient and | 139 | * cache entry, for any other error assume it is transient and |
168 | * leave the cache entry as XFS_ACL_NOT_CACHED. | 140 | * leave the cache entry as ACL_NOT_CACHED. |
169 | */ | 141 | */ |
170 | if (error == -ENOATTR) { | 142 | if (error == -ENOATTR) { |
171 | acl = NULL; | 143 | acl = NULL; |
@@ -179,7 +151,7 @@ xfs_get_acl(struct inode *inode, int type) | |||
179 | goto out; | 151 | goto out; |
180 | 152 | ||
181 | out_update_cache: | 153 | out_update_cache: |
182 | xfs_update_cached_acl(inode, p_acl, acl); | 154 | set_cached_acl(inode, type, acl); |
183 | out: | 155 | out: |
184 | kfree(xfs_acl); | 156 | kfree(xfs_acl); |
185 | return acl; | 157 | return acl; |
@@ -189,7 +161,6 @@ STATIC int | |||
189 | xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | 161 | xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) |
190 | { | 162 | { |
191 | struct xfs_inode *ip = XFS_I(inode); | 163 | struct xfs_inode *ip = XFS_I(inode); |
192 | struct posix_acl **p_acl; | ||
193 | char *ea_name; | 164 | char *ea_name; |
194 | int error; | 165 | int error; |
195 | 166 | ||
@@ -199,13 +170,11 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
199 | switch (type) { | 170 | switch (type) { |
200 | case ACL_TYPE_ACCESS: | 171 | case ACL_TYPE_ACCESS: |
201 | ea_name = SGI_ACL_FILE; | 172 | ea_name = SGI_ACL_FILE; |
202 | p_acl = &ip->i_acl; | ||
203 | break; | 173 | break; |
204 | case ACL_TYPE_DEFAULT: | 174 | case ACL_TYPE_DEFAULT: |
205 | if (!S_ISDIR(inode->i_mode)) | 175 | if (!S_ISDIR(inode->i_mode)) |
206 | return acl ? -EACCES : 0; | 176 | return acl ? -EACCES : 0; |
207 | ea_name = SGI_ACL_DEFAULT; | 177 | ea_name = SGI_ACL_DEFAULT; |
208 | p_acl = &ip->i_default_acl; | ||
209 | break; | 178 | break; |
210 | default: | 179 | default: |
211 | return -EINVAL; | 180 | return -EINVAL; |
@@ -242,7 +211,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
242 | } | 211 | } |
243 | 212 | ||
244 | if (!error) | 213 | if (!error) |
245 | xfs_update_cached_acl(inode, p_acl, acl); | 214 | set_cached_acl(inode, type, acl); |
246 | return error; | 215 | return error; |
247 | } | 216 | } |
248 | 217 | ||
@@ -384,30 +353,6 @@ xfs_acl_chmod(struct inode *inode) | |||
384 | return error; | 353 | return error; |
385 | } | 354 | } |
386 | 355 | ||
387 | void | ||
388 | xfs_inode_init_acls(struct xfs_inode *ip) | ||
389 | { | ||
390 | /* | ||
391 | * No need for locking, inode is not live yet. | ||
392 | */ | ||
393 | ip->i_acl = XFS_ACL_NOT_CACHED; | ||
394 | ip->i_default_acl = XFS_ACL_NOT_CACHED; | ||
395 | } | ||
396 | |||
397 | void | ||
398 | xfs_inode_clear_acls(struct xfs_inode *ip) | ||
399 | { | ||
400 | /* | ||
401 | * No need for locking here, the inode is not live anymore | ||
402 | * and just about to be freed. | ||
403 | */ | ||
404 | if (ip->i_acl != XFS_ACL_NOT_CACHED) | ||
405 | posix_acl_release(ip->i_acl); | ||
406 | if (ip->i_default_acl != XFS_ACL_NOT_CACHED) | ||
407 | posix_acl_release(ip->i_default_acl); | ||
408 | } | ||
409 | |||
410 | |||
411 | /* | 356 | /* |
412 | * System xattr handlers. | 357 | * System xattr handlers. |
413 | * | 358 | * |
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h index 63dc1f2efad5..947b150df8ed 100644 --- a/fs/xfs/xfs_acl.h +++ b/fs/xfs/xfs_acl.h | |||
@@ -46,8 +46,6 @@ extern int xfs_check_acl(struct inode *inode, int mask); | |||
46 | extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); | 46 | extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); |
47 | extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl); | 47 | extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl); |
48 | extern int xfs_acl_chmod(struct inode *inode); | 48 | extern int xfs_acl_chmod(struct inode *inode); |
49 | extern void xfs_inode_init_acls(struct xfs_inode *ip); | ||
50 | extern void xfs_inode_clear_acls(struct xfs_inode *ip); | ||
51 | extern int posix_acl_access_exists(struct inode *inode); | 49 | extern int posix_acl_access_exists(struct inode *inode); |
52 | extern int posix_acl_default_exists(struct inode *inode); | 50 | extern int posix_acl_default_exists(struct inode *inode); |
53 | 51 | ||
@@ -57,8 +55,6 @@ extern struct xattr_handler xfs_xattr_system_handler; | |||
57 | # define xfs_get_acl(inode, type) NULL | 55 | # define xfs_get_acl(inode, type) NULL |
58 | # define xfs_inherit_acl(inode, default_acl) 0 | 56 | # define xfs_inherit_acl(inode, default_acl) 0 |
59 | # define xfs_acl_chmod(inode) 0 | 57 | # define xfs_acl_chmod(inode) 0 |
60 | # define xfs_inode_init_acls(ip) | ||
61 | # define xfs_inode_clear_acls(ip) | ||
62 | # define posix_acl_access_exists(inode) 0 | 58 | # define posix_acl_access_exists(inode) 0 |
63 | # define posix_acl_default_exists(inode) 0 | 59 | # define posix_acl_default_exists(inode) 0 |
64 | #endif /* CONFIG_XFS_POSIX_ACL */ | 60 | #endif /* CONFIG_XFS_POSIX_ACL */ |
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 76c540f719e4..5fcec6f020a7 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c | |||
@@ -83,7 +83,6 @@ xfs_inode_alloc( | |||
83 | memset(&ip->i_d, 0, sizeof(xfs_icdinode_t)); | 83 | memset(&ip->i_d, 0, sizeof(xfs_icdinode_t)); |
84 | ip->i_size = 0; | 84 | ip->i_size = 0; |
85 | ip->i_new_size = 0; | 85 | ip->i_new_size = 0; |
86 | xfs_inode_init_acls(ip); | ||
87 | 86 | ||
88 | /* | 87 | /* |
89 | * Initialize inode's trace buffers. | 88 | * Initialize inode's trace buffers. |
@@ -560,7 +559,6 @@ xfs_ireclaim( | |||
560 | ASSERT(atomic_read(&ip->i_pincount) == 0); | 559 | ASSERT(atomic_read(&ip->i_pincount) == 0); |
561 | ASSERT(!spin_is_locked(&ip->i_flags_lock)); | 560 | ASSERT(!spin_is_locked(&ip->i_flags_lock)); |
562 | ASSERT(completion_done(&ip->i_flush)); | 561 | ASSERT(completion_done(&ip->i_flush)); |
563 | xfs_inode_clear_acls(ip); | ||
564 | kmem_zone_free(xfs_inode_zone, ip); | 562 | kmem_zone_free(xfs_inode_zone, ip); |
565 | } | 563 | } |
566 | 564 | ||
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 77016702938b..1804f866a71d 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -273,11 +273,6 @@ typedef struct xfs_inode { | |||
273 | /* VFS inode */ | 273 | /* VFS inode */ |
274 | struct inode i_vnode; /* embedded VFS inode */ | 274 | struct inode i_vnode; /* embedded VFS inode */ |
275 | 275 | ||
276 | #ifdef CONFIG_XFS_POSIX_ACL | ||
277 | struct posix_acl *i_acl; | ||
278 | struct posix_acl *i_default_acl; | ||
279 | #endif | ||
280 | |||
281 | /* Trace buffers per inode. */ | 276 | /* Trace buffers per inode. */ |
282 | #ifdef XFS_INODE_TRACE | 277 | #ifdef XFS_INODE_TRACE |
283 | struct ktrace *i_trace; /* general inode trace */ | 278 | struct ktrace *i_trace; /* general inode trace */ |