diff options
Diffstat (limited to 'fs')
80 files changed, 2051 insertions, 1527 deletions
diff --git a/fs/afs/flock.c b/fs/afs/flock.c index 210acafe4a9..3ff8bdd18fb 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 | ||
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index c52be53f694..5ffb570cd3a 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
| @@ -17,7 +17,6 @@ | |||
| 17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
| 18 | #include <linux/mount.h> | 18 | #include <linux/mount.h> |
| 19 | #include <linux/namei.h> | 19 | #include <linux/namei.h> |
| 20 | #include <linux/mnt_namespace.h> | ||
| 21 | #include "internal.h" | 20 | #include "internal.h" |
| 22 | 21 | ||
| 23 | 22 | ||
| @@ -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 9fa212b014a..b7c1603cd4b 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 31c46a241ba..49a34e7f730 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); |
| @@ -705,14 +705,13 @@ static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count, | |||
| 705 | } | 705 | } |
| 706 | 706 | ||
| 707 | static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs, | 707 | static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs, |
| 708 | struct sg_iovec *iov, int iov_count, int uncopy, | 708 | struct sg_iovec *iov, int iov_count, |
| 709 | int do_free_page) | 709 | int to_user, int from_user, int do_free_page) |
| 710 | { | 710 | { |
| 711 | int ret = 0, i; | 711 | int ret = 0, i; |
| 712 | struct bio_vec *bvec; | 712 | struct bio_vec *bvec; |
| 713 | int iov_idx = 0; | 713 | int iov_idx = 0; |
| 714 | unsigned int iov_off = 0; | 714 | unsigned int iov_off = 0; |
| 715 | int read = bio_data_dir(bio) == READ; | ||
| 716 | 715 | ||
| 717 | __bio_for_each_segment(bvec, bio, i, 0) { | 716 | __bio_for_each_segment(bvec, bio, i, 0) { |
| 718 | char *bv_addr = page_address(bvec->bv_page); | 717 | char *bv_addr = page_address(bvec->bv_page); |
| @@ -727,13 +726,14 @@ static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs, | |||
| 727 | iov_addr = iov[iov_idx].iov_base + iov_off; | 726 | iov_addr = iov[iov_idx].iov_base + iov_off; |
| 728 | 727 | ||
| 729 | if (!ret) { | 728 | if (!ret) { |
| 730 | if (!read && !uncopy) | 729 | if (to_user) |
| 731 | ret = copy_from_user(bv_addr, iov_addr, | ||
| 732 | bytes); | ||
| 733 | if (read && uncopy) | ||
| 734 | ret = copy_to_user(iov_addr, bv_addr, | 730 | ret = copy_to_user(iov_addr, bv_addr, |
| 735 | bytes); | 731 | bytes); |
| 736 | 732 | ||
| 733 | if (from_user) | ||
| 734 | ret = copy_from_user(bv_addr, iov_addr, | ||
| 735 | bytes); | ||
| 736 | |||
| 737 | if (ret) | 737 | if (ret) |
| 738 | ret = -EFAULT; | 738 | ret = -EFAULT; |
| 739 | } | 739 | } |
| @@ -770,7 +770,8 @@ int bio_uncopy_user(struct bio *bio) | |||
| 770 | 770 | ||
| 771 | if (!bio_flagged(bio, BIO_NULL_MAPPED)) | 771 | if (!bio_flagged(bio, BIO_NULL_MAPPED)) |
| 772 | ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs, | 772 | ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs, |
| 773 | bmd->nr_sgvecs, 1, bmd->is_our_pages); | 773 | bmd->nr_sgvecs, bio_data_dir(bio) == READ, |
| 774 | 0, bmd->is_our_pages); | ||
| 774 | bio_free_map_data(bmd); | 775 | bio_free_map_data(bmd); |
| 775 | bio_put(bio); | 776 | bio_put(bio); |
| 776 | return ret; | 777 | return ret; |
| @@ -875,8 +876,9 @@ struct bio *bio_copy_user_iov(struct request_queue *q, | |||
| 875 | /* | 876 | /* |
| 876 | * success | 877 | * success |
| 877 | */ | 878 | */ |
| 878 | if (!write_to_vm && (!map_data || !map_data->null_mapped)) { | 879 | if ((!write_to_vm && (!map_data || !map_data->null_mapped)) || |
| 879 | ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 0); | 880 | (map_data && map_data->from_user)) { |
| 881 | ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 1, 0); | ||
| 880 | if (ret) | 882 | if (ret) |
| 881 | goto cleanup; | 883 | goto cleanup; |
| 882 | } | 884 | } |
| @@ -1539,6 +1541,7 @@ void bioset_free(struct bio_set *bs) | |||
| 1539 | if (bs->bio_pool) | 1541 | if (bs->bio_pool) |
| 1540 | mempool_destroy(bs->bio_pool); | 1542 | mempool_destroy(bs->bio_pool); |
| 1541 | 1543 | ||
| 1544 | bioset_integrity_free(bs); | ||
| 1542 | biovec_free_pools(bs); | 1545 | biovec_free_pools(bs); |
| 1543 | bio_put_slab(bs); | 1546 | bio_put_slab(bs); |
| 1544 | 1547 | ||
| @@ -1579,6 +1582,9 @@ struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad) | |||
| 1579 | if (!bs->bio_pool) | 1582 | if (!bs->bio_pool) |
| 1580 | goto bad; | 1583 | goto bad; |
| 1581 | 1584 | ||
| 1585 | if (bioset_integrity_create(bs, pool_size)) | ||
| 1586 | goto bad; | ||
| 1587 | |||
| 1582 | if (!biovec_create_pools(bs, pool_size)) | 1588 | if (!biovec_create_pools(bs, pool_size)) |
| 1583 | return bs; | 1589 | return bs; |
| 1584 | 1590 | ||
| @@ -1616,6 +1622,7 @@ static int __init init_bio(void) | |||
| 1616 | if (!bio_slabs) | 1622 | if (!bio_slabs) |
| 1617 | panic("bio: can't allocate bios\n"); | 1623 | panic("bio: can't allocate bios\n"); |
| 1618 | 1624 | ||
| 1625 | bio_integrity_init(); | ||
| 1619 | biovec_init_slabs(); | 1626 | biovec_init_slabs(); |
| 1620 | 1627 | ||
| 1621 | fs_bio_set = bioset_create(BIO_POOL_SIZE, 0); | 1628 | fs_bio_set = bioset_create(BIO_POOL_SIZE, 0); |
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 7f88628a1a7..6e4f6c50a12 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/ctree.h b/fs/btrfs/ctree.h index 2779c2f5360..98a87383871 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -2074,8 +2074,7 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, | |||
| 2074 | 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); |
| 2075 | 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); |
| 2076 | 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); |
| 2077 | int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | 2077 | int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref); |
| 2078 | *root); | ||
| 2079 | int btrfs_drop_subtree(struct btrfs_trans_handle *trans, | 2078 | int btrfs_drop_subtree(struct btrfs_trans_handle *trans, |
| 2080 | struct btrfs_root *root, | 2079 | struct btrfs_root *root, |
| 2081 | struct extent_buffer *node, | 2080 | struct extent_buffer *node, |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index edc7d208c5c..a5aca3997d4 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 126477eaecf..7c3cd248d8d 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 dbe1aabf96c..7ffa3d34ea1 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -3580,12 +3580,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
| 3580 | owner = 1; | 3580 | owner = 1; |
| 3581 | BTRFS_I(inode)->block_group = | 3581 | BTRFS_I(inode)->block_group = |
| 3582 | btrfs_find_block_group(root, 0, alloc_hint, owner); | 3582 | btrfs_find_block_group(root, 0, alloc_hint, owner); |
| 3583 | if ((mode & S_IFREG)) { | ||
| 3584 | if (btrfs_test_opt(root, NODATASUM)) | ||
| 3585 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; | ||
| 3586 | if (btrfs_test_opt(root, NODATACOW)) | ||
| 3587 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; | ||
| 3588 | } | ||
| 3589 | 3583 | ||
| 3590 | key[0].objectid = objectid; | 3584 | key[0].objectid = objectid; |
| 3591 | btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY); | 3585 | btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY); |
| @@ -3640,6 +3634,13 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
| 3640 | 3634 | ||
| 3641 | btrfs_inherit_iflags(inode, dir); | 3635 | btrfs_inherit_iflags(inode, dir); |
| 3642 | 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 | |||
| 3643 | insert_inode_hash(inode); | 3644 | insert_inode_hash(inode); |
| 3644 | inode_tree_add(inode); | 3645 | inode_tree_add(inode); |
| 3645 | return inode; | 3646 | return inode; |
| @@ -5082,6 +5083,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
| 5082 | u64 mask = BTRFS_I(inode)->root->sectorsize - 1; | 5083 | u64 mask = BTRFS_I(inode)->root->sectorsize - 1; |
| 5083 | struct extent_map *em; | 5084 | struct extent_map *em; |
| 5084 | struct btrfs_trans_handle *trans; | 5085 | struct btrfs_trans_handle *trans; |
| 5086 | struct btrfs_root *root; | ||
| 5085 | int ret; | 5087 | int ret; |
| 5086 | 5088 | ||
| 5087 | alloc_start = offset & ~mask; | 5089 | alloc_start = offset & ~mask; |
| @@ -5100,6 +5102,13 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
| 5100 | goto out; | 5102 | goto out; |
| 5101 | } | 5103 | } |
| 5102 | 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 | |||
| 5103 | locked_end = alloc_end - 1; | 5112 | locked_end = alloc_end - 1; |
| 5104 | while (1) { | 5113 | while (1) { |
| 5105 | struct btrfs_ordered_extent *ordered; | 5114 | struct btrfs_ordered_extent *ordered; |
| @@ -5107,7 +5116,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
| 5107 | trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1); | 5116 | trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1); |
| 5108 | if (!trans) { | 5117 | if (!trans) { |
| 5109 | ret = -EIO; | 5118 | ret = -EIO; |
| 5110 | goto out; | 5119 | goto out_free; |
| 5111 | } | 5120 | } |
| 5112 | 5121 | ||
| 5113 | /* the extent lock is ordered inside the running | 5122 | /* the extent lock is ordered inside the running |
| @@ -5168,6 +5177,8 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
| 5168 | GFP_NOFS); | 5177 | GFP_NOFS); |
| 5169 | 5178 | ||
| 5170 | 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); | ||
| 5171 | out: | 5182 | out: |
| 5172 | mutex_unlock(&inode->i_mutex); | 5183 | mutex_unlock(&inode->i_mutex); |
| 5173 | return ret; | 5184 | return ret; |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index eff18f5b536..9f4db848db1 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 b23dc209ae1..00839793477 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 4e83457ea25..2dbf1c1f56e 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 b4868983942..92888aa9074 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
| @@ -5,7 +5,11 @@ 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 mount parm. Improve |
| 9 | hard link detection to use same inode for both. Do not set | ||
| 10 | read-only dos attribute on directories (for chmod) since Windows | ||
| 11 | explorer special cases this attribute bit for directories for | ||
| 12 | a different purpose. | ||
| 9 | 13 | ||
| 10 | Version 1.58 | 14 | Version 1.58 |
| 11 | ------------ | 15 | ------------ |
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 1b09f167006..20692fbfdb2 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/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 4a4581cb2b5..051caecf7d6 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
| @@ -86,6 +86,9 @@ struct key_type cifs_spnego_key_type = { | |||
| 86 | /* strlen of ";user=" */ | 86 | /* strlen of ";user=" */ |
| 87 | #define USER_KEY_LEN 6 | 87 | #define USER_KEY_LEN 6 |
| 88 | 88 | ||
| 89 | /* strlen of ";pid=0x" */ | ||
| 90 | #define PID_KEY_LEN 7 | ||
| 91 | |||
| 89 | /* get a key struct with a SPNEGO security blob, suitable for session setup */ | 92 | /* get a key struct with a SPNEGO security blob, suitable for session setup */ |
| 90 | struct key * | 93 | struct key * |
| 91 | cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | 94 | cifs_get_spnego_key(struct cifsSesInfo *sesInfo) |
| @@ -103,7 +106,8 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
| 103 | IP_KEY_LEN + INET6_ADDRSTRLEN + | 106 | IP_KEY_LEN + INET6_ADDRSTRLEN + |
| 104 | MAX_MECH_STR_LEN + | 107 | MAX_MECH_STR_LEN + |
| 105 | UID_KEY_LEN + (sizeof(uid_t) * 2) + | 108 | UID_KEY_LEN + (sizeof(uid_t) * 2) + |
| 106 | USER_KEY_LEN + strlen(sesInfo->userName) + 1; | 109 | USER_KEY_LEN + strlen(sesInfo->userName) + |
| 110 | PID_KEY_LEN + (sizeof(pid_t) * 2) + 1; | ||
| 107 | 111 | ||
| 108 | spnego_key = ERR_PTR(-ENOMEM); | 112 | spnego_key = ERR_PTR(-ENOMEM); |
| 109 | description = kzalloc(desc_len, GFP_KERNEL); | 113 | description = kzalloc(desc_len, GFP_KERNEL); |
| @@ -141,6 +145,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
| 141 | dp = description + strlen(description); | 145 | dp = description + strlen(description); |
| 142 | sprintf(dp, ";user=%s", sesInfo->userName); | 146 | sprintf(dp, ";user=%s", sesInfo->userName); |
| 143 | 147 | ||
| 148 | dp = description + strlen(description); | ||
| 149 | sprintf(dp, ";pid=0x%x", current->pid); | ||
| 150 | |||
| 144 | cFYI(1, ("key description = %s", description)); | 151 | cFYI(1, ("key description = %s", description)); |
| 145 | spnego_key = request_key(&cifs_spnego_key_type, description, ""); | 152 | spnego_key = request_key(&cifs_spnego_key_type, description, ""); |
| 146 | 153 | ||
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 1403b5d86a7..6941c22398a 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
| @@ -327,7 +327,7 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl) | |||
| 327 | 327 | ||
| 328 | static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | 328 | static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, |
| 329 | struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, | 329 | struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, |
| 330 | struct inode *inode) | 330 | struct cifs_fattr *fattr) |
| 331 | { | 331 | { |
| 332 | int i; | 332 | int i; |
| 333 | int num_aces = 0; | 333 | int num_aces = 0; |
| @@ -340,7 +340,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
| 340 | if (!pdacl) { | 340 | if (!pdacl) { |
| 341 | /* no DACL in the security descriptor, set | 341 | /* no DACL in the security descriptor, set |
| 342 | all the permissions for user/group/other */ | 342 | all the permissions for user/group/other */ |
| 343 | inode->i_mode |= S_IRWXUGO; | 343 | fattr->cf_mode |= S_IRWXUGO; |
| 344 | return; | 344 | return; |
| 345 | } | 345 | } |
| 346 | 346 | ||
| @@ -357,7 +357,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
| 357 | /* reset rwx permissions for user/group/other. | 357 | /* reset rwx permissions for user/group/other. |
| 358 | Also, if num_aces is 0 i.e. DACL has no ACEs, | 358 | Also, if num_aces is 0 i.e. DACL has no ACEs, |
| 359 | user/group/other have no permissions */ | 359 | user/group/other have no permissions */ |
| 360 | inode->i_mode &= ~(S_IRWXUGO); | 360 | fattr->cf_mode &= ~(S_IRWXUGO); |
| 361 | 361 | ||
| 362 | acl_base = (char *)pdacl; | 362 | acl_base = (char *)pdacl; |
| 363 | acl_size = sizeof(struct cifs_acl); | 363 | acl_size = sizeof(struct cifs_acl); |
| @@ -379,17 +379,17 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
| 379 | if (compare_sids(&(ppace[i]->sid), pownersid)) | 379 | if (compare_sids(&(ppace[i]->sid), pownersid)) |
| 380 | access_flags_to_mode(ppace[i]->access_req, | 380 | access_flags_to_mode(ppace[i]->access_req, |
| 381 | ppace[i]->type, | 381 | ppace[i]->type, |
| 382 | &(inode->i_mode), | 382 | &fattr->cf_mode, |
| 383 | &user_mask); | 383 | &user_mask); |
| 384 | if (compare_sids(&(ppace[i]->sid), pgrpsid)) | 384 | if (compare_sids(&(ppace[i]->sid), pgrpsid)) |
| 385 | access_flags_to_mode(ppace[i]->access_req, | 385 | access_flags_to_mode(ppace[i]->access_req, |
| 386 | ppace[i]->type, | 386 | ppace[i]->type, |
| 387 | &(inode->i_mode), | 387 | &fattr->cf_mode, |
| 388 | &group_mask); | 388 | &group_mask); |
| 389 | if (compare_sids(&(ppace[i]->sid), &sid_everyone)) | 389 | if (compare_sids(&(ppace[i]->sid), &sid_everyone)) |
| 390 | access_flags_to_mode(ppace[i]->access_req, | 390 | access_flags_to_mode(ppace[i]->access_req, |
| 391 | ppace[i]->type, | 391 | ppace[i]->type, |
| 392 | &(inode->i_mode), | 392 | &fattr->cf_mode, |
| 393 | &other_mask); | 393 | &other_mask); |
| 394 | 394 | ||
| 395 | /* memcpy((void *)(&(cifscred->aces[i])), | 395 | /* memcpy((void *)(&(cifscred->aces[i])), |
| @@ -464,7 +464,7 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) | |||
| 464 | 464 | ||
| 465 | /* Convert CIFS ACL to POSIX form */ | 465 | /* Convert CIFS ACL to POSIX form */ |
| 466 | static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | 466 | static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, |
| 467 | struct inode *inode) | 467 | struct cifs_fattr *fattr) |
| 468 | { | 468 | { |
| 469 | int rc; | 469 | int rc; |
| 470 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; | 470 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; |
| @@ -472,7 +472,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
| 472 | char *end_of_acl = ((char *)pntsd) + acl_len; | 472 | char *end_of_acl = ((char *)pntsd) + acl_len; |
| 473 | __u32 dacloffset; | 473 | __u32 dacloffset; |
| 474 | 474 | ||
| 475 | if ((inode == NULL) || (pntsd == NULL)) | 475 | if (pntsd == NULL) |
| 476 | return -EIO; | 476 | return -EIO; |
| 477 | 477 | ||
| 478 | owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + | 478 | owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + |
| @@ -497,7 +497,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
| 497 | 497 | ||
| 498 | if (dacloffset) | 498 | if (dacloffset) |
| 499 | parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, | 499 | parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, |
| 500 | group_sid_ptr, inode); | 500 | group_sid_ptr, fattr); |
| 501 | else | 501 | else |
| 502 | cFYI(1, ("no ACL")); /* BB grant all or default perms? */ | 502 | cFYI(1, ("no ACL")); /* BB grant all or default perms? */ |
| 503 | 503 | ||
| @@ -508,7 +508,6 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
| 508 | memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, | 508 | memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, |
| 509 | sizeof(struct cifs_sid)); */ | 509 | sizeof(struct cifs_sid)); */ |
| 510 | 510 | ||
| 511 | |||
| 512 | return 0; | 511 | return 0; |
| 513 | } | 512 | } |
| 514 | 513 | ||
| @@ -671,8 +670,9 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
| 671 | } | 670 | } |
| 672 | 671 | ||
| 673 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ | 672 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ |
| 674 | void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode, | 673 | void |
| 675 | const char *path, const __u16 *pfid) | 674 | cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, |
| 675 | struct inode *inode, const char *path, const __u16 *pfid) | ||
| 676 | { | 676 | { |
| 677 | struct cifs_ntsd *pntsd = NULL; | 677 | struct cifs_ntsd *pntsd = NULL; |
| 678 | u32 acllen = 0; | 678 | u32 acllen = 0; |
| @@ -687,7 +687,7 @@ void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode, | |||
| 687 | 687 | ||
| 688 | /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ | 688 | /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ |
| 689 | if (pntsd) | 689 | if (pntsd) |
| 690 | rc = parse_sec_desc(pntsd, acllen, inode); | 690 | rc = parse_sec_desc(pntsd, acllen, fattr); |
| 691 | if (rc) | 691 | if (rc) |
| 692 | cFYI(1, ("parse sec desc failed rc = %d", rc)); | 692 | cFYI(1, ("parse sec desc failed rc = %d", rc)); |
| 693 | 693 | ||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0d92114195a..44f30504b82 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -308,7 +308,6 @@ cifs_alloc_inode(struct super_block *sb) | |||
| 308 | if (!cifs_inode) | 308 | if (!cifs_inode) |
| 309 | return NULL; | 309 | return NULL; |
| 310 | cifs_inode->cifsAttrs = 0x20; /* default */ | 310 | cifs_inode->cifsAttrs = 0x20; /* default */ |
| 311 | atomic_set(&cifs_inode->inUse, 0); | ||
| 312 | cifs_inode->time = 0; | 311 | cifs_inode->time = 0; |
| 313 | cifs_inode->write_behind_rc = 0; | 312 | cifs_inode->write_behind_rc = 0; |
| 314 | /* Until the file is open and we have gotten oplock | 313 | /* Until the file is open and we have gotten oplock |
| @@ -333,6 +332,27 @@ cifs_destroy_inode(struct inode *inode) | |||
| 333 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); | 332 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); |
| 334 | } | 333 | } |
| 335 | 334 | ||
| 335 | static void | ||
| 336 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) | ||
| 337 | { | ||
| 338 | seq_printf(s, ",addr="); | ||
| 339 | |||
| 340 | switch (server->addr.sockAddr.sin_family) { | ||
| 341 | case AF_INET: | ||
| 342 | seq_printf(s, "%pI4", &server->addr.sockAddr.sin_addr.s_addr); | ||
| 343 | break; | ||
| 344 | case AF_INET6: | ||
| 345 | seq_printf(s, "%pI6", | ||
| 346 | &server->addr.sockAddr6.sin6_addr.s6_addr); | ||
| 347 | if (server->addr.sockAddr6.sin6_scope_id) | ||
| 348 | seq_printf(s, "%%%u", | ||
| 349 | server->addr.sockAddr6.sin6_scope_id); | ||
| 350 | break; | ||
| 351 | default: | ||
| 352 | seq_printf(s, "(unknown)"); | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 336 | /* | 356 | /* |
| 337 | * cifs_show_options() is for displaying mount options in /proc/mounts. | 357 | * cifs_show_options() is for displaying mount options in /proc/mounts. |
| 338 | * Not all settable options are displayed but most of the important | 358 | * Not all settable options are displayed but most of the important |
| @@ -343,83 +363,64 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) | |||
| 343 | { | 363 | { |
| 344 | struct cifs_sb_info *cifs_sb; | 364 | struct cifs_sb_info *cifs_sb; |
| 345 | struct cifsTconInfo *tcon; | 365 | struct cifsTconInfo *tcon; |
| 346 | struct TCP_Server_Info *server; | ||
| 347 | 366 | ||
| 348 | cifs_sb = CIFS_SB(m->mnt_sb); | 367 | cifs_sb = CIFS_SB(m->mnt_sb); |
| 368 | tcon = cifs_sb->tcon; | ||
| 349 | 369 | ||
| 350 | if (cifs_sb) { | 370 | seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); |
| 351 | tcon = cifs_sb->tcon; | 371 | if (tcon->ses->userName) |
| 352 | if (tcon) { | 372 | seq_printf(s, ",username=%s", tcon->ses->userName); |
| 353 | seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); | 373 | if (tcon->ses->domainName) |
| 354 | if (tcon->ses) { | 374 | seq_printf(s, ",domain=%s", tcon->ses->domainName); |
| 355 | if (tcon->ses->userName) | 375 | |
| 356 | seq_printf(s, ",username=%s", | 376 | seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); |
| 357 | tcon->ses->userName); | 377 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) |
| 358 | if (tcon->ses->domainName) | 378 | seq_printf(s, ",forceuid"); |
| 359 | seq_printf(s, ",domain=%s", | 379 | |
| 360 | tcon->ses->domainName); | 380 | seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); |
| 361 | server = tcon->ses->server; | 381 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) |
| 362 | if (server) { | 382 | seq_printf(s, ",forcegid"); |
| 363 | seq_printf(s, ",addr="); | 383 | |
| 364 | switch (server->addr.sockAddr6. | 384 | cifs_show_address(s, tcon->ses->server); |
| 365 | sin6_family) { | 385 | |
| 366 | case AF_INET6: | 386 | if (!tcon->unix_ext) |
| 367 | seq_printf(s, "%pI6", | 387 | 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, | 388 | cifs_sb->mnt_file_mode, |
| 386 | cifs_sb->mnt_dir_mode); | 389 | cifs_sb->mnt_dir_mode); |
| 387 | } | 390 | if (tcon->seal) |
| 388 | if (tcon->seal) | 391 | seq_printf(s, ",seal"); |
| 389 | seq_printf(s, ",seal"); | 392 | if (tcon->nocase) |
| 390 | if (tcon->nocase) | 393 | seq_printf(s, ",nocase"); |
| 391 | seq_printf(s, ",nocase"); | 394 | if (tcon->retry) |
| 392 | if (tcon->retry) | 395 | seq_printf(s, ",hard"); |
| 393 | seq_printf(s, ",hard"); | 396 | if (cifs_sb->prepath) |
| 394 | } | 397 | seq_printf(s, ",prepath=%s", cifs_sb->prepath); |
| 395 | if (cifs_sb->prepath) | 398 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) |
| 396 | seq_printf(s, ",prepath=%s", cifs_sb->prepath); | 399 | seq_printf(s, ",posixpaths"); |
| 397 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) | 400 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) |
| 398 | seq_printf(s, ",posixpaths"); | 401 | seq_printf(s, ",setuids"); |
| 399 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) | 402 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) |
| 400 | seq_printf(s, ",setuids"); | 403 | seq_printf(s, ",serverino"); |
| 401 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) | 404 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) |
| 402 | seq_printf(s, ",serverino"); | 405 | seq_printf(s, ",directio"); |
| 403 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | 406 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) |
| 404 | seq_printf(s, ",directio"); | 407 | seq_printf(s, ",nouser_xattr"); |
| 405 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | 408 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) |
| 406 | seq_printf(s, ",nouser_xattr"); | 409 | seq_printf(s, ",mapchars"); |
| 407 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) | 410 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) |
| 408 | seq_printf(s, ",mapchars"); | 411 | seq_printf(s, ",sfu"); |
| 409 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) | 412 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) |
| 410 | seq_printf(s, ",sfu"); | 413 | seq_printf(s, ",nobrl"); |
| 411 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 414 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) |
| 412 | seq_printf(s, ",nobrl"); | 415 | seq_printf(s, ",cifsacl"); |
| 413 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) | 416 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) |
| 414 | seq_printf(s, ",cifsacl"); | 417 | seq_printf(s, ",dynperm"); |
| 415 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) | 418 | if (m->mnt_sb->s_flags & MS_POSIXACL) |
| 416 | seq_printf(s, ",dynperm"); | 419 | seq_printf(s, ",acl"); |
| 417 | if (m->mnt_sb->s_flags & MS_POSIXACL) | 420 | |
| 418 | seq_printf(s, ",acl"); | 421 | seq_printf(s, ",rsize=%d", cifs_sb->rsize); |
| 419 | 422 | seq_printf(s, ",wsize=%d", cifs_sb->wsize); | |
| 420 | seq_printf(s, ",rsize=%d", cifs_sb->rsize); | 423 | |
| 421 | seq_printf(s, ",wsize=%d", cifs_sb->wsize); | ||
| 422 | } | ||
| 423 | return 0; | 424 | return 0; |
| 424 | } | 425 | } |
| 425 | 426 | ||
| @@ -535,9 +536,14 @@ static void cifs_umount_begin(struct super_block *sb) | |||
| 535 | if (tcon == NULL) | 536 | if (tcon == NULL) |
| 536 | return; | 537 | return; |
| 537 | 538 | ||
| 538 | lock_kernel(); | ||
| 539 | read_lock(&cifs_tcp_ses_lock); | 539 | read_lock(&cifs_tcp_ses_lock); |
| 540 | if (tcon->tc_count == 1) | 540 | if ((tcon->tc_count > 1) || (tcon->tidStatus == CifsExiting)) { |
| 541 | /* we have other mounts to same share or we have | ||
| 542 | already tried to force umount this and woken up | ||
| 543 | all waiting network requests, nothing to do */ | ||
| 544 | read_unlock(&cifs_tcp_ses_lock); | ||
| 545 | return; | ||
| 546 | } else if (tcon->tc_count == 1) | ||
| 541 | tcon->tidStatus = CifsExiting; | 547 | tcon->tidStatus = CifsExiting; |
| 542 | read_unlock(&cifs_tcp_ses_lock); | 548 | read_unlock(&cifs_tcp_ses_lock); |
| 543 | 549 | ||
| @@ -552,9 +558,7 @@ static void cifs_umount_begin(struct super_block *sb) | |||
| 552 | wake_up_all(&tcon->ses->server->response_q); | 558 | wake_up_all(&tcon->ses->server->response_q); |
| 553 | msleep(1); | 559 | msleep(1); |
| 554 | } | 560 | } |
| 555 | /* BB FIXME - finish add checks for tidStatus BB */ | ||
| 556 | 561 | ||
| 557 | unlock_kernel(); | ||
| 558 | return; | 562 | return; |
| 559 | } | 563 | } |
| 560 | 564 | ||
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 9570a0e8023..6c170948300 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
| @@ -24,6 +24,19 @@ | |||
| 24 | 24 | ||
| 25 | #define ROOT_I 2 | 25 | #define ROOT_I 2 |
| 26 | 26 | ||
| 27 | /* | ||
| 28 | * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down | ||
| 29 | * so that it will fit. | ||
| 30 | */ | ||
| 31 | static inline ino_t | ||
| 32 | cifs_uniqueid_to_ino_t(u64 fileid) | ||
| 33 | { | ||
| 34 | ino_t ino = (ino_t) fileid; | ||
| 35 | if (sizeof(ino_t) < sizeof(u64)) | ||
| 36 | ino ^= fileid >> (sizeof(u64)-sizeof(ino_t)) * 8; | ||
| 37 | return ino; | ||
| 38 | } | ||
| 39 | |||
| 27 | extern struct file_system_type cifs_fs_type; | 40 | extern struct file_system_type cifs_fs_type; |
| 28 | extern const struct address_space_operations cifs_addr_ops; | 41 | extern const struct address_space_operations cifs_addr_ops; |
| 29 | extern const struct address_space_operations cifs_addr_ops_smallbuf; | 42 | extern const struct address_space_operations cifs_addr_ops_smallbuf; |
| @@ -100,5 +113,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
| 100 | extern const struct export_operations cifs_export_ops; | 113 | extern const struct export_operations cifs_export_ops; |
| 101 | #endif /* EXPERIMENTAL */ | 114 | #endif /* EXPERIMENTAL */ |
| 102 | 115 | ||
| 103 | #define CIFS_VERSION "1.59" | 116 | #define CIFS_VERSION "1.60" |
| 104 | #endif /* _CIFSFS_H */ | 117 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a61ab772c6f..63f6cdfa563 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 | }; |
| @@ -364,13 +364,13 @@ struct cifsInodeInfo { | |||
| 364 | struct list_head openFileList; | 364 | struct list_head openFileList; |
| 365 | int write_behind_rc; | 365 | int write_behind_rc; |
| 366 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ | 366 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ |
| 367 | atomic_t inUse; /* num concurrent users (local openers cifs) of file*/ | ||
| 368 | unsigned long time; /* jiffies of last update/check of inode */ | 367 | unsigned long time; /* jiffies of last update/check of inode */ |
| 369 | bool clientCanCacheRead:1; /* read oplock */ | 368 | bool clientCanCacheRead:1; /* read oplock */ |
| 370 | bool clientCanCacheAll:1; /* read and writebehind oplock */ | 369 | bool clientCanCacheAll:1; /* read and writebehind oplock */ |
| 371 | bool oplockPending:1; | 370 | bool oplockPending:1; |
| 372 | bool delete_pending:1; /* DELETE_ON_CLOSE is set */ | 371 | bool delete_pending:1; /* DELETE_ON_CLOSE is set */ |
| 373 | u64 server_eof; /* current file size on server */ | 372 | u64 server_eof; /* current file size on server */ |
| 373 | u64 uniqueid; /* server inode number */ | ||
| 374 | struct inode vfs_inode; | 374 | struct inode vfs_inode; |
| 375 | }; | 375 | }; |
| 376 | 376 | ||
| @@ -472,6 +472,32 @@ struct dfs_info3_param { | |||
| 472 | char *node_name; | 472 | char *node_name; |
| 473 | }; | 473 | }; |
| 474 | 474 | ||
| 475 | /* | ||
| 476 | * common struct for holding inode info when searching for or updating an | ||
| 477 | * inode with new info | ||
| 478 | */ | ||
| 479 | |||
| 480 | #define CIFS_FATTR_DFS_REFERRAL 0x1 | ||
| 481 | #define CIFS_FATTR_DELETE_PENDING 0x2 | ||
| 482 | #define CIFS_FATTR_NEED_REVAL 0x4 | ||
| 483 | |||
| 484 | struct cifs_fattr { | ||
| 485 | u32 cf_flags; | ||
| 486 | u32 cf_cifsattrs; | ||
| 487 | u64 cf_uniqueid; | ||
| 488 | u64 cf_eof; | ||
| 489 | u64 cf_bytes; | ||
| 490 | uid_t cf_uid; | ||
| 491 | gid_t cf_gid; | ||
| 492 | umode_t cf_mode; | ||
| 493 | dev_t cf_rdev; | ||
| 494 | unsigned int cf_nlink; | ||
| 495 | unsigned int cf_dtype; | ||
| 496 | struct timespec cf_atime; | ||
| 497 | struct timespec cf_mtime; | ||
| 498 | struct timespec cf_ctime; | ||
| 499 | }; | ||
| 500 | |||
| 475 | static inline void free_dfs_info_param(struct dfs_info3_param *param) | 501 | static inline void free_dfs_info_param(struct dfs_info3_param *param) |
| 476 | { | 502 | { |
| 477 | if (param) { | 503 | if (param) { |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index a785f69dbc9..2d07f890a84 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
| @@ -2328,19 +2328,7 @@ struct file_attrib_tag { | |||
| 2328 | typedef struct { | 2328 | typedef struct { |
| 2329 | __le32 NextEntryOffset; | 2329 | __le32 NextEntryOffset; |
| 2330 | __u32 ResumeKey; /* as with FileIndex - no need to convert */ | 2330 | __u32 ResumeKey; /* as with FileIndex - no need to convert */ |
| 2331 | __le64 EndOfFile; | 2331 | FILE_UNIX_BASIC_INFO basic; |
| 2332 | __le64 NumOfBytes; | ||
| 2333 | __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */ | ||
| 2334 | __le64 LastAccessTime; | ||
| 2335 | __le64 LastModificationTime; | ||
| 2336 | __le64 Uid; | ||
| 2337 | __le64 Gid; | ||
| 2338 | __le32 Type; | ||
| 2339 | __le64 DevMajor; | ||
| 2340 | __le64 DevMinor; | ||
| 2341 | __le64 UniqueId; | ||
| 2342 | __le64 Permissions; | ||
| 2343 | __le64 Nlinks; | ||
| 2344 | char FileName[1]; | 2332 | char FileName[1]; |
| 2345 | } __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */ | 2333 | } __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */ |
| 2346 | 2334 | ||
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index f9452329bcc..da8fbf56599 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 |
| @@ -98,9 +98,13 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, | |||
| 98 | extern int cifs_posix_open(char *full_path, struct inode **pinode, | 98 | extern int cifs_posix_open(char *full_path, struct inode **pinode, |
| 99 | struct super_block *sb, int mode, int oflags, | 99 | struct super_block *sb, int mode, int oflags, |
| 100 | int *poplock, __u16 *pnetfid, int xid); | 100 | int *poplock, __u16 *pnetfid, int xid); |
| 101 | extern void posix_fill_in_inode(struct inode *tmp_inode, | 101 | extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, |
| 102 | FILE_UNIX_BASIC_INFO *pData, int isNewInode); | 102 | FILE_UNIX_BASIC_INFO *info, |
| 103 | extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum); | 103 | struct cifs_sb_info *cifs_sb); |
| 104 | extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr); | ||
| 105 | extern struct inode *cifs_iget(struct super_block *sb, | ||
| 106 | struct cifs_fattr *fattr); | ||
| 107 | |||
| 104 | extern int cifs_get_inode_info(struct inode **pinode, | 108 | extern int cifs_get_inode_info(struct inode **pinode, |
| 105 | const unsigned char *search_path, | 109 | const unsigned char *search_path, |
| 106 | FILE_ALL_INFO *pfile_info, | 110 | FILE_ALL_INFO *pfile_info, |
| @@ -108,8 +112,9 @@ extern int cifs_get_inode_info(struct inode **pinode, | |||
| 108 | extern int cifs_get_inode_info_unix(struct inode **pinode, | 112 | extern int cifs_get_inode_info_unix(struct inode **pinode, |
| 109 | const unsigned char *search_path, | 113 | const unsigned char *search_path, |
| 110 | struct super_block *sb, int xid); | 114 | struct super_block *sb, int xid); |
| 111 | extern void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode, | 115 | extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, |
| 112 | const char *path, const __u16 *pfid); | 116 | struct cifs_fattr *fattr, struct inode *inode, |
| 117 | const char *path, const __u16 *pfid); | ||
| 113 | extern int mode_to_acl(struct inode *inode, const char *path, __u64); | 118 | extern int mode_to_acl(struct inode *inode, const char *path, __u64); |
| 114 | 119 | ||
| 115 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, | 120 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, |
| @@ -215,7 +220,11 @@ struct cifs_unix_set_info_args { | |||
| 215 | dev_t device; | 220 | dev_t device; |
| 216 | }; | 221 | }; |
| 217 | 222 | ||
| 218 | extern int CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *pTcon, | 223 | extern int CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, |
| 224 | const struct cifs_unix_set_info_args *args, | ||
| 225 | u16 fid, u32 pid_of_opener); | ||
| 226 | |||
| 227 | extern int CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *pTcon, | ||
| 219 | char *fileName, | 228 | char *fileName, |
| 220 | const struct cifs_unix_set_info_args *args, | 229 | const struct cifs_unix_set_info_args *args, |
| 221 | const struct nls_table *nls_codepage, | 230 | const struct nls_table *nls_codepage, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b84c61d5bca..922f5fe2084 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, |
| @@ -5074,10 +5074,114 @@ SetAttrLgcyRetry: | |||
| 5074 | } | 5074 | } |
| 5075 | #endif /* temporarily unneeded SetAttr legacy function */ | 5075 | #endif /* temporarily unneeded SetAttr legacy function */ |
| 5076 | 5076 | ||
| 5077 | static void | ||
| 5078 | cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, | ||
| 5079 | const struct cifs_unix_set_info_args *args) | ||
| 5080 | { | ||
| 5081 | u64 mode = args->mode; | ||
| 5082 | |||
| 5083 | /* | ||
| 5084 | * Samba server ignores set of file size to zero due to bugs in some | ||
| 5085 | * older clients, but we should be precise - we use SetFileSize to | ||
| 5086 | * set file size and do not want to truncate file size to zero | ||
| 5087 | * accidently as happened on one Samba server beta by putting | ||
| 5088 | * zero instead of -1 here | ||
| 5089 | */ | ||
| 5090 | data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64); | ||
| 5091 | data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64); | ||
| 5092 | data_offset->LastStatusChange = cpu_to_le64(args->ctime); | ||
| 5093 | data_offset->LastAccessTime = cpu_to_le64(args->atime); | ||
| 5094 | data_offset->LastModificationTime = cpu_to_le64(args->mtime); | ||
| 5095 | data_offset->Uid = cpu_to_le64(args->uid); | ||
| 5096 | data_offset->Gid = cpu_to_le64(args->gid); | ||
| 5097 | /* better to leave device as zero when it is */ | ||
| 5098 | data_offset->DevMajor = cpu_to_le64(MAJOR(args->device)); | ||
| 5099 | data_offset->DevMinor = cpu_to_le64(MINOR(args->device)); | ||
| 5100 | data_offset->Permissions = cpu_to_le64(mode); | ||
| 5101 | |||
| 5102 | if (S_ISREG(mode)) | ||
| 5103 | data_offset->Type = cpu_to_le32(UNIX_FILE); | ||
| 5104 | else if (S_ISDIR(mode)) | ||
| 5105 | data_offset->Type = cpu_to_le32(UNIX_DIR); | ||
| 5106 | else if (S_ISLNK(mode)) | ||
| 5107 | data_offset->Type = cpu_to_le32(UNIX_SYMLINK); | ||
| 5108 | else if (S_ISCHR(mode)) | ||
| 5109 | data_offset->Type = cpu_to_le32(UNIX_CHARDEV); | ||
| 5110 | else if (S_ISBLK(mode)) | ||
| 5111 | data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV); | ||
| 5112 | else if (S_ISFIFO(mode)) | ||
| 5113 | data_offset->Type = cpu_to_le32(UNIX_FIFO); | ||
| 5114 | else if (S_ISSOCK(mode)) | ||
| 5115 | data_offset->Type = cpu_to_le32(UNIX_SOCKET); | ||
| 5116 | } | ||
| 5117 | |||
| 5077 | int | 5118 | int |
| 5078 | CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName, | 5119 | CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, |
| 5079 | const struct cifs_unix_set_info_args *args, | 5120 | const struct cifs_unix_set_info_args *args, |
| 5080 | const struct nls_table *nls_codepage, int remap) | 5121 | u16 fid, u32 pid_of_opener) |
| 5122 | { | ||
| 5123 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | ||
| 5124 | FILE_UNIX_BASIC_INFO *data_offset; | ||
| 5125 | int rc = 0; | ||
| 5126 | u16 params, param_offset, offset, byte_count, count; | ||
| 5127 | |||
| 5128 | cFYI(1, ("Set Unix Info (via SetFileInfo)")); | ||
| 5129 | rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); | ||
| 5130 | |||
| 5131 | if (rc) | ||
| 5132 | return rc; | ||
| 5133 | |||
| 5134 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); | ||
| 5135 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); | ||
| 5136 | |||
| 5137 | params = 6; | ||
| 5138 | pSMB->MaxSetupCount = 0; | ||
| 5139 | pSMB->Reserved = 0; | ||
| 5140 | pSMB->Flags = 0; | ||
| 5141 | pSMB->Timeout = 0; | ||
| 5142 | pSMB->Reserved2 = 0; | ||
| 5143 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | ||
| 5144 | offset = param_offset + params; | ||
| 5145 | |||
| 5146 | data_offset = (FILE_UNIX_BASIC_INFO *) | ||
| 5147 | ((char *)(&pSMB->hdr.Protocol) + offset); | ||
| 5148 | count = sizeof(FILE_UNIX_BASIC_INFO); | ||
| 5149 | |||
| 5150 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
| 5151 | /* BB find max SMB PDU from sess */ | ||
| 5152 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
| 5153 | pSMB->SetupCount = 1; | ||
| 5154 | pSMB->Reserved3 = 0; | ||
| 5155 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | ||
| 5156 | byte_count = 3 /* pad */ + params + count; | ||
| 5157 | pSMB->DataCount = cpu_to_le16(count); | ||
| 5158 | pSMB->ParameterCount = cpu_to_le16(params); | ||
| 5159 | pSMB->TotalDataCount = pSMB->DataCount; | ||
| 5160 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
| 5161 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
| 5162 | pSMB->DataOffset = cpu_to_le16(offset); | ||
| 5163 | pSMB->Fid = fid; | ||
| 5164 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); | ||
| 5165 | pSMB->Reserved4 = 0; | ||
| 5166 | pSMB->hdr.smb_buf_length += byte_count; | ||
| 5167 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
| 5168 | |||
| 5169 | cifs_fill_unix_set_info(data_offset, args); | ||
| 5170 | |||
| 5171 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); | ||
| 5172 | if (rc) | ||
| 5173 | cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc)); | ||
| 5174 | |||
| 5175 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
| 5176 | since file handle passed in no longer valid */ | ||
| 5177 | |||
| 5178 | return rc; | ||
| 5179 | } | ||
| 5180 | |||
| 5181 | int | ||
| 5182 | CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName, | ||
| 5183 | const struct cifs_unix_set_info_args *args, | ||
| 5184 | const struct nls_table *nls_codepage, int remap) | ||
| 5081 | { | 5185 | { |
| 5082 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 5186 | TRANSACTION2_SPI_REQ *pSMB = NULL; |
| 5083 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | 5187 | TRANSACTION2_SPI_RSP *pSMBr = NULL; |
| @@ -5086,7 +5190,6 @@ CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName, | |||
| 5086 | int bytes_returned = 0; | 5190 | int bytes_returned = 0; |
| 5087 | FILE_UNIX_BASIC_INFO *data_offset; | 5191 | FILE_UNIX_BASIC_INFO *data_offset; |
| 5088 | __u16 params, param_offset, offset, count, byte_count; | 5192 | __u16 params, param_offset, offset, count, byte_count; |
| 5089 | __u64 mode = args->mode; | ||
| 5090 | 5193 | ||
| 5091 | cFYI(1, ("In SetUID/GID/Mode")); | 5194 | cFYI(1, ("In SetUID/GID/Mode")); |
| 5092 | setPermsRetry: | 5195 | setPermsRetry: |
| @@ -5137,38 +5240,8 @@ setPermsRetry: | |||
| 5137 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); | 5240 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); |
| 5138 | pSMB->Reserved4 = 0; | 5241 | pSMB->Reserved4 = 0; |
| 5139 | pSMB->hdr.smb_buf_length += byte_count; | 5242 | pSMB->hdr.smb_buf_length += byte_count; |
| 5140 | /* Samba server ignores set of file size to zero due to bugs in some | ||
| 5141 | older clients, but we should be precise - we use SetFileSize to | ||
| 5142 | set file size and do not want to truncate file size to zero | ||
| 5143 | accidently as happened on one Samba server beta by putting | ||
| 5144 | zero instead of -1 here */ | ||
| 5145 | data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64); | ||
| 5146 | data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64); | ||
| 5147 | data_offset->LastStatusChange = cpu_to_le64(args->ctime); | ||
| 5148 | data_offset->LastAccessTime = cpu_to_le64(args->atime); | ||
| 5149 | data_offset->LastModificationTime = cpu_to_le64(args->mtime); | ||
| 5150 | data_offset->Uid = cpu_to_le64(args->uid); | ||
| 5151 | data_offset->Gid = cpu_to_le64(args->gid); | ||
| 5152 | /* better to leave device as zero when it is */ | ||
| 5153 | data_offset->DevMajor = cpu_to_le64(MAJOR(args->device)); | ||
| 5154 | data_offset->DevMinor = cpu_to_le64(MINOR(args->device)); | ||
| 5155 | data_offset->Permissions = cpu_to_le64(mode); | ||
| 5156 | |||
| 5157 | if (S_ISREG(mode)) | ||
| 5158 | data_offset->Type = cpu_to_le32(UNIX_FILE); | ||
| 5159 | else if (S_ISDIR(mode)) | ||
| 5160 | data_offset->Type = cpu_to_le32(UNIX_DIR); | ||
| 5161 | else if (S_ISLNK(mode)) | ||
| 5162 | data_offset->Type = cpu_to_le32(UNIX_SYMLINK); | ||
| 5163 | else if (S_ISCHR(mode)) | ||
| 5164 | data_offset->Type = cpu_to_le32(UNIX_CHARDEV); | ||
| 5165 | else if (S_ISBLK(mode)) | ||
| 5166 | data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV); | ||
| 5167 | else if (S_ISFIFO(mode)) | ||
| 5168 | data_offset->Type = cpu_to_le32(UNIX_FIFO); | ||
| 5169 | else if (S_ISSOCK(mode)) | ||
| 5170 | data_offset->Type = cpu_to_le32(UNIX_SOCKET); | ||
| 5171 | 5243 | ||
| 5244 | cifs_fill_unix_set_info(data_offset, args); | ||
| 5172 | 5245 | ||
| 5173 | pSMB->ByteCount = cpu_to_le16(byte_count); | 5246 | pSMB->ByteCount = cpu_to_le16(byte_count); |
| 5174 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 5247 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 97f4311b9a8..e16d7592116 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 3758965d73d..4326ffd90fa 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -188,6 +188,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
| 188 | FILE_UNIX_BASIC_INFO *presp_data; | 188 | FILE_UNIX_BASIC_INFO *presp_data; |
| 189 | __u32 posix_flags = 0; | 189 | __u32 posix_flags = 0; |
| 190 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 190 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
| 191 | struct cifs_fattr fattr; | ||
| 191 | 192 | ||
| 192 | cFYI(1, ("posix open %s", full_path)); | 193 | cFYI(1, ("posix open %s", full_path)); |
| 193 | 194 | ||
| @@ -236,22 +237,21 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
| 236 | if (presp_data->Type == cpu_to_le32(-1)) | 237 | if (presp_data->Type == cpu_to_le32(-1)) |
| 237 | goto posix_open_ret; /* open ok, caller does qpathinfo */ | 238 | goto posix_open_ret; /* open ok, caller does qpathinfo */ |
| 238 | 239 | ||
| 239 | /* get new inode and set it up */ | ||
| 240 | if (!pinode) | 240 | if (!pinode) |
| 241 | goto posix_open_ret; /* caller does not need info */ | 241 | goto posix_open_ret; /* caller does not need info */ |
| 242 | 242 | ||
| 243 | cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); | ||
| 244 | |||
| 245 | /* get new inode and set it up */ | ||
| 243 | if (*pinode == NULL) { | 246 | if (*pinode == NULL) { |
| 244 | __u64 unique_id = le64_to_cpu(presp_data->UniqueId); | 247 | *pinode = cifs_iget(sb, &fattr); |
| 245 | *pinode = cifs_new_inode(sb, &unique_id); | 248 | if (!*pinode) { |
| 249 | rc = -ENOMEM; | ||
| 250 | goto posix_open_ret; | ||
| 251 | } | ||
| 252 | } else { | ||
| 253 | cifs_fattr_to_inode(*pinode, &fattr); | ||
| 246 | } | 254 | } |
| 247 | /* else an inode was passed in. Update its info, don't create one */ | ||
| 248 | |||
| 249 | /* We do not need to close the file if new_inode fails since | ||
| 250 | the caller will retry qpathinfo as long as inode is null */ | ||
| 251 | if (*pinode == NULL) | ||
| 252 | goto posix_open_ret; | ||
| 253 | |||
| 254 | posix_fill_in_inode(*pinode, presp_data, 1); | ||
| 255 | 255 | ||
| 256 | cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only); | 256 | cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only); |
| 257 | 257 | ||
| @@ -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) |
| @@ -424,9 +425,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 424 | args.uid = NO_CHANGE_64; | 425 | args.uid = NO_CHANGE_64; |
| 425 | args.gid = NO_CHANGE_64; | 426 | args.gid = NO_CHANGE_64; |
| 426 | } | 427 | } |
| 427 | CIFSSMBUnixSetInfo(xid, tcon, full_path, &args, | 428 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, |
| 428 | cifs_sb->local_nls, | 429 | cifs_sb->local_nls, |
| 429 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 430 | cifs_sb->mnt_cifs_flags & |
| 431 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 430 | } else { | 432 | } else { |
| 431 | /* BB implement mode setting via Windows security | 433 | /* BB implement mode setting via Windows security |
| 432 | descriptors e.g. */ | 434 | descriptors e.g. */ |
| @@ -514,10 +516,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
| 514 | args.uid = NO_CHANGE_64; | 516 | args.uid = NO_CHANGE_64; |
| 515 | args.gid = NO_CHANGE_64; | 517 | args.gid = NO_CHANGE_64; |
| 516 | } | 518 | } |
| 517 | rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, | 519 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args, |
| 518 | &args, cifs_sb->local_nls, | 520 | cifs_sb->local_nls, |
| 519 | cifs_sb->mnt_cifs_flags & | 521 | cifs_sb->mnt_cifs_flags & |
| 520 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 522 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 521 | 523 | ||
| 522 | if (!rc) { | 524 | if (!rc) { |
| 523 | rc = cifs_get_inode_info_unix(&newinode, full_path, | 525 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
| @@ -540,8 +542,9 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
| 540 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | 542 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
| 541 | if (buf == NULL) { | 543 | if (buf == NULL) { |
| 542 | kfree(full_path); | 544 | kfree(full_path); |
| 545 | rc = -ENOMEM; | ||
| 543 | FreeXid(xid); | 546 | FreeXid(xid); |
| 544 | return -ENOMEM; | 547 | return rc; |
| 545 | } | 548 | } |
| 546 | 549 | ||
| 547 | rc = CIFSSMBOpen(xid, pTcon, full_path, | 550 | rc = CIFSSMBOpen(xid, pTcon, full_path, |
| @@ -641,6 +644,15 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
| 641 | } | 644 | } |
| 642 | } | 645 | } |
| 643 | 646 | ||
| 647 | /* | ||
| 648 | * O_EXCL: optimize away the lookup, but don't hash the dentry. Let | ||
| 649 | * the VFS handle the create. | ||
| 650 | */ | ||
| 651 | if (nd->flags & LOOKUP_EXCL) { | ||
| 652 | d_instantiate(direntry, NULL); | ||
| 653 | return 0; | ||
| 654 | } | ||
| 655 | |||
| 644 | /* can not grab the rename sem here since it would | 656 | /* can not grab the rename sem here since it would |
| 645 | deadlock in the cases (beginning of sys_rename itself) | 657 | deadlock in the cases (beginning of sys_rename itself) |
| 646 | in which we already have the sb rename sem */ | 658 | in which we already have the sb rename sem */ |
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index df4a306f697..87948147d7e 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 06866841b97..c34b7f8a217 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", |
| @@ -446,9 +448,9 @@ int cifs_open(struct inode *inode, struct file *file) | |||
| 446 | .mtime = NO_CHANGE_64, | 448 | .mtime = NO_CHANGE_64, |
| 447 | .device = 0, | 449 | .device = 0, |
| 448 | }; | 450 | }; |
| 449 | CIFSSMBUnixSetInfo(xid, tcon, full_path, &args, | 451 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, |
| 450 | cifs_sb->local_nls, | 452 | cifs_sb->local_nls, |
| 451 | cifs_sb->mnt_cifs_flags & | 453 | cifs_sb->mnt_cifs_flags & |
| 452 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 454 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 453 | } | 455 | } |
| 454 | } | 456 | } |
| @@ -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 fad882b075b..18afe57b246 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -77,239 +77,202 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) | |||
| 77 | } | 77 | } |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | static void cifs_unix_info_to_inode(struct inode *inode, | 80 | /* populate an inode with info from a cifs_fattr struct */ |
| 81 | FILE_UNIX_BASIC_INFO *info, int force_uid_gid) | 81 | void |
| 82 | cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) | ||
| 82 | { | 83 | { |
| 84 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); | ||
| 83 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 85 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
| 84 | struct cifsInodeInfo *cifsInfo = CIFS_I(inode); | 86 | unsigned long oldtime = cifs_i->time; |
| 85 | __u64 num_of_bytes = le64_to_cpu(info->NumOfBytes); | 87 | |
| 86 | __u64 end_of_file = le64_to_cpu(info->EndOfFile); | 88 | inode->i_atime = fattr->cf_atime; |
| 89 | inode->i_mtime = fattr->cf_mtime; | ||
| 90 | inode->i_ctime = fattr->cf_ctime; | ||
| 91 | inode->i_rdev = fattr->cf_rdev; | ||
| 92 | inode->i_nlink = fattr->cf_nlink; | ||
| 93 | inode->i_uid = fattr->cf_uid; | ||
| 94 | inode->i_gid = fattr->cf_gid; | ||
| 95 | |||
| 96 | /* if dynperm is set, don't clobber existing mode */ | ||
| 97 | if (inode->i_state & I_NEW || | ||
| 98 | !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) | ||
| 99 | inode->i_mode = fattr->cf_mode; | ||
| 100 | |||
| 101 | cifs_i->cifsAttrs = fattr->cf_cifsattrs; | ||
| 102 | cifs_i->uniqueid = fattr->cf_uniqueid; | ||
| 103 | |||
| 104 | if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL) | ||
| 105 | cifs_i->time = 0; | ||
| 106 | else | ||
| 107 | cifs_i->time = jiffies; | ||
| 108 | |||
| 109 | cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode, | ||
| 110 | oldtime, cifs_i->time)); | ||
| 87 | 111 | ||
| 88 | inode->i_atime = cifs_NTtimeToUnix(info->LastAccessTime); | 112 | cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING; |
| 89 | inode->i_mtime = | 113 | |
| 90 | cifs_NTtimeToUnix(info->LastModificationTime); | 114 | /* |
| 91 | inode->i_ctime = cifs_NTtimeToUnix(info->LastStatusChange); | 115 | * Can't safely change the file size here if the client is writing to |
| 92 | inode->i_mode = le64_to_cpu(info->Permissions); | 116 | * it due to potential races. |
| 117 | */ | ||
| 118 | spin_lock(&inode->i_lock); | ||
| 119 | if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) { | ||
| 120 | i_size_write(inode, fattr->cf_eof); | ||
| 121 | |||
| 122 | /* | ||
| 123 | * i_blocks is not related to (i_size / i_blksize), | ||
| 124 | * but instead 512 byte (2**9) size is required for | ||
| 125 | * calculating num blocks. | ||
| 126 | */ | ||
| 127 | inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9; | ||
| 128 | } | ||
| 129 | spin_unlock(&inode->i_lock); | ||
| 130 | |||
| 131 | cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL); | ||
| 132 | } | ||
| 133 | |||
| 134 | /* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */ | ||
| 135 | void | ||
| 136 | cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, | ||
| 137 | struct cifs_sb_info *cifs_sb) | ||
| 138 | { | ||
| 139 | memset(fattr, 0, sizeof(*fattr)); | ||
| 140 | fattr->cf_uniqueid = le64_to_cpu(info->UniqueId); | ||
| 141 | fattr->cf_bytes = le64_to_cpu(info->NumOfBytes); | ||
| 142 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); | ||
| 143 | |||
| 144 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); | ||
| 145 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime); | ||
| 146 | fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange); | ||
| 147 | fattr->cf_mode = le64_to_cpu(info->Permissions); | ||
| 93 | 148 | ||
| 94 | /* | 149 | /* |
| 95 | * Since we set the inode type below we need to mask off | 150 | * Since we set the inode type below we need to mask off |
| 96 | * to avoid strange results if bits set above. | 151 | * to avoid strange results if bits set above. |
| 97 | */ | 152 | */ |
| 98 | inode->i_mode &= ~S_IFMT; | 153 | fattr->cf_mode &= ~S_IFMT; |
| 99 | switch (le32_to_cpu(info->Type)) { | 154 | switch (le32_to_cpu(info->Type)) { |
| 100 | case UNIX_FILE: | 155 | case UNIX_FILE: |
| 101 | inode->i_mode |= S_IFREG; | 156 | fattr->cf_mode |= S_IFREG; |
| 157 | fattr->cf_dtype = DT_REG; | ||
| 102 | break; | 158 | break; |
| 103 | case UNIX_SYMLINK: | 159 | case UNIX_SYMLINK: |
| 104 | inode->i_mode |= S_IFLNK; | 160 | fattr->cf_mode |= S_IFLNK; |
| 161 | fattr->cf_dtype = DT_LNK; | ||
| 105 | break; | 162 | break; |
| 106 | case UNIX_DIR: | 163 | case UNIX_DIR: |
| 107 | inode->i_mode |= S_IFDIR; | 164 | fattr->cf_mode |= S_IFDIR; |
| 165 | fattr->cf_dtype = DT_DIR; | ||
| 108 | break; | 166 | break; |
| 109 | case UNIX_CHARDEV: | 167 | case UNIX_CHARDEV: |
| 110 | inode->i_mode |= S_IFCHR; | 168 | fattr->cf_mode |= S_IFCHR; |
| 111 | inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor), | 169 | fattr->cf_dtype = DT_CHR; |
| 112 | le64_to_cpu(info->DevMinor) & MINORMASK); | 170 | fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), |
| 171 | le64_to_cpu(info->DevMinor) & MINORMASK); | ||
| 113 | break; | 172 | break; |
| 114 | case UNIX_BLOCKDEV: | 173 | case UNIX_BLOCKDEV: |
| 115 | inode->i_mode |= S_IFBLK; | 174 | fattr->cf_mode |= S_IFBLK; |
| 116 | inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor), | 175 | fattr->cf_dtype = DT_BLK; |
| 117 | le64_to_cpu(info->DevMinor) & MINORMASK); | 176 | fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), |
| 177 | le64_to_cpu(info->DevMinor) & MINORMASK); | ||
| 118 | break; | 178 | break; |
| 119 | case UNIX_FIFO: | 179 | case UNIX_FIFO: |
| 120 | inode->i_mode |= S_IFIFO; | 180 | fattr->cf_mode |= S_IFIFO; |
| 181 | fattr->cf_dtype = DT_FIFO; | ||
| 121 | break; | 182 | break; |
| 122 | case UNIX_SOCKET: | 183 | case UNIX_SOCKET: |
| 123 | inode->i_mode |= S_IFSOCK; | 184 | fattr->cf_mode |= S_IFSOCK; |
| 185 | fattr->cf_dtype = DT_SOCK; | ||
| 124 | break; | 186 | break; |
| 125 | default: | 187 | default: |
| 126 | /* safest to call it a file if we do not know */ | 188 | /* safest to call it a file if we do not know */ |
| 127 | inode->i_mode |= S_IFREG; | 189 | fattr->cf_mode |= S_IFREG; |
| 190 | fattr->cf_dtype = DT_REG; | ||
| 128 | cFYI(1, ("unknown type %d", le32_to_cpu(info->Type))); | 191 | cFYI(1, ("unknown type %d", le32_to_cpu(info->Type))); |
| 129 | break; | 192 | break; |
| 130 | } | 193 | } |
| 131 | 194 | ||
| 132 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) && | 195 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) |
| 133 | !force_uid_gid) | 196 | fattr->cf_uid = cifs_sb->mnt_uid; |
| 134 | inode->i_uid = cifs_sb->mnt_uid; | ||
| 135 | else | 197 | else |
| 136 | inode->i_uid = le64_to_cpu(info->Uid); | 198 | fattr->cf_uid = le64_to_cpu(info->Uid); |
| 137 | 199 | ||
| 138 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) && | 200 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) |
| 139 | !force_uid_gid) | 201 | fattr->cf_gid = cifs_sb->mnt_gid; |
| 140 | inode->i_gid = cifs_sb->mnt_gid; | ||
| 141 | else | 202 | else |
| 142 | inode->i_gid = le64_to_cpu(info->Gid); | 203 | fattr->cf_gid = le64_to_cpu(info->Gid); |
| 143 | |||
| 144 | inode->i_nlink = le64_to_cpu(info->Nlinks); | ||
| 145 | |||
| 146 | cifsInfo->server_eof = end_of_file; | ||
| 147 | spin_lock(&inode->i_lock); | ||
| 148 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | ||
| 149 | /* | ||
| 150 | * We can not safely change the file size here if the client | ||
| 151 | * is writing to it due to potential races. | ||
| 152 | */ | ||
| 153 | i_size_write(inode, end_of_file); | ||
| 154 | 204 | ||
| 155 | /* | 205 | fattr->cf_nlink = le64_to_cpu(info->Nlinks); |
| 156 | * i_blocks is not related to (i_size / i_blksize), | ||
| 157 | * but instead 512 byte (2**9) size is required for | ||
| 158 | * calculating num blocks. | ||
| 159 | */ | ||
| 160 | inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; | ||
| 161 | } | ||
| 162 | spin_unlock(&inode->i_lock); | ||
| 163 | } | 206 | } |
| 164 | 207 | ||
| 165 | |||
| 166 | /* | 208 | /* |
| 167 | * Needed to setup inode data for the directory which is the | 209 | * Fill a cifs_fattr struct with fake inode info. |
| 168 | * junction to the new submount (ie to setup the fake directory | ||
| 169 | * which represents a DFS referral) | ||
| 170 | */ | ||
| 171 | static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat, | ||
| 172 | struct super_block *sb) | ||
| 173 | { | ||
| 174 | struct inode *pinode = NULL; | ||
| 175 | |||
| 176 | memset(pfnd_dat, 0, sizeof(FILE_UNIX_BASIC_INFO)); | ||
| 177 | |||
| 178 | /* __le64 pfnd_dat->EndOfFile = cpu_to_le64(0); | ||
| 179 | __le64 pfnd_dat->NumOfBytes = cpu_to_le64(0); | ||
| 180 | __u64 UniqueId = 0; */ | ||
| 181 | pfnd_dat->LastStatusChange = | ||
| 182 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
| 183 | pfnd_dat->LastAccessTime = | ||
| 184 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
| 185 | pfnd_dat->LastModificationTime = | ||
| 186 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
| 187 | pfnd_dat->Type = cpu_to_le32(UNIX_DIR); | ||
| 188 | pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU); | ||
| 189 | pfnd_dat->Nlinks = cpu_to_le64(2); | ||
| 190 | if (sb->s_root) | ||
| 191 | pinode = sb->s_root->d_inode; | ||
| 192 | if (pinode == NULL) | ||
| 193 | return; | ||
| 194 | |||
| 195 | /* fill in default values for the remaining based on root | ||
| 196 | inode since we can not query the server for this inode info */ | ||
| 197 | pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev)); | ||
| 198 | pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev)); | ||
| 199 | pfnd_dat->Uid = cpu_to_le64(pinode->i_uid); | ||
| 200 | pfnd_dat->Gid = cpu_to_le64(pinode->i_gid); | ||
| 201 | } | ||
| 202 | |||
| 203 | /** | ||
| 204 | * cifs_new inode - create new inode, initialize, and hash it | ||
| 205 | * @sb - pointer to superblock | ||
| 206 | * @inum - if valid pointer and serverino is enabled, replace i_ino with val | ||
| 207 | * | ||
| 208 | * Create a new inode, initialize it for CIFS and hash it. Returns the new | ||
| 209 | * inode or NULL if one couldn't be allocated. | ||
| 210 | * | 210 | * |
| 211 | * If the share isn't mounted with "serverino" or inum is a NULL pointer then | 211 | * Needed to setup cifs_fattr data for the directory which is the |
| 212 | * we'll just use the inode number assigned by new_inode(). Note that this can | 212 | * junction to the new submount (ie to setup the fake directory |
| 213 | * mean i_ino collisions since the i_ino assigned by new_inode is not | 213 | * which represents a DFS referral). |
| 214 | * guaranteed to be unique. | ||
| 215 | */ | 214 | */ |
| 216 | struct inode * | 215 | void |
| 217 | cifs_new_inode(struct super_block *sb, __u64 *inum) | 216 | cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) |
| 218 | { | 217 | { |
| 219 | struct inode *inode; | 218 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
| 220 | |||
| 221 | inode = new_inode(sb); | ||
| 222 | if (inode == NULL) | ||
| 223 | return NULL; | ||
| 224 | |||
| 225 | /* | ||
| 226 | * BB: Is i_ino == 0 legal? Here, we assume that it is. If it isn't we | ||
| 227 | * stop passing inum as ptr. Are there sanity checks we can use to | ||
| 228 | * ensure that the server is really filling in that field? Also, | ||
| 229 | * if serverino is disabled, perhaps we should be using iunique()? | ||
| 230 | */ | ||
| 231 | if (inum && (CIFS_SB(sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) | ||
| 232 | inode->i_ino = (unsigned long) *inum; | ||
| 233 | |||
| 234 | /* | ||
| 235 | * must set this here instead of cifs_alloc_inode since VFS will | ||
| 236 | * clobber i_flags | ||
| 237 | */ | ||
| 238 | if (sb->s_flags & MS_NOATIME) | ||
| 239 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | ||
| 240 | |||
| 241 | insert_inode_hash(inode); | ||
| 242 | 219 | ||
| 243 | return inode; | 220 | cFYI(1, ("creating fake fattr for DFS referral")); |
| 221 | |||
| 222 | memset(fattr, 0, sizeof(*fattr)); | ||
| 223 | fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU; | ||
| 224 | fattr->cf_uid = cifs_sb->mnt_uid; | ||
| 225 | fattr->cf_gid = cifs_sb->mnt_gid; | ||
| 226 | fattr->cf_atime = CURRENT_TIME; | ||
| 227 | fattr->cf_ctime = CURRENT_TIME; | ||
| 228 | fattr->cf_mtime = CURRENT_TIME; | ||
| 229 | fattr->cf_nlink = 2; | ||
| 230 | fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL; | ||
| 244 | } | 231 | } |
| 245 | 232 | ||
| 246 | int cifs_get_inode_info_unix(struct inode **pinode, | 233 | int cifs_get_inode_info_unix(struct inode **pinode, |
| 247 | const unsigned char *full_path, struct super_block *sb, int xid) | 234 | const unsigned char *full_path, |
| 235 | struct super_block *sb, int xid) | ||
| 248 | { | 236 | { |
| 249 | int rc = 0; | 237 | int rc; |
| 250 | FILE_UNIX_BASIC_INFO find_data; | 238 | FILE_UNIX_BASIC_INFO find_data; |
| 251 | struct cifsTconInfo *pTcon; | 239 | struct cifs_fattr fattr; |
| 252 | struct inode *inode; | 240 | struct cifsTconInfo *tcon; |
| 253 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 241 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
| 254 | bool is_dfs_referral = false; | ||
| 255 | struct cifsInodeInfo *cifsInfo; | ||
| 256 | __u64 num_of_bytes; | ||
| 257 | __u64 end_of_file; | ||
| 258 | 242 | ||
| 259 | pTcon = cifs_sb->tcon; | 243 | tcon = cifs_sb->tcon; |
| 260 | cFYI(1, ("Getting info on %s", full_path)); | 244 | cFYI(1, ("Getting info on %s", full_path)); |
| 261 | 245 | ||
| 262 | /* could have done a find first instead but this returns more info */ | 246 | /* could have done a find first instead but this returns more info */ |
| 263 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data, | 247 | rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, |
| 264 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 248 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
| 265 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 249 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 266 | if (rc == -EREMOTE && !is_dfs_referral) { | ||
| 267 | is_dfs_referral = true; | ||
| 268 | cFYI(DBG2, ("DFS ref")); | ||
| 269 | /* for DFS, server does not give us real inode data */ | ||
| 270 | fill_fake_finddataunix(&find_data, sb); | ||
| 271 | rc = 0; | ||
| 272 | } else if (rc) | ||
| 273 | goto cgiiu_exit; | ||
| 274 | 250 | ||
| 275 | num_of_bytes = le64_to_cpu(find_data.NumOfBytes); | 251 | if (!rc) { |
| 276 | end_of_file = le64_to_cpu(find_data.EndOfFile); | 252 | cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); |
| 253 | } else if (rc == -EREMOTE) { | ||
| 254 | cifs_create_dfs_fattr(&fattr, sb); | ||
| 255 | rc = 0; | ||
| 256 | } else { | ||
| 257 | return rc; | ||
| 258 | } | ||
| 277 | 259 | ||
| 278 | /* get new inode */ | ||
| 279 | if (*pinode == NULL) { | 260 | if (*pinode == NULL) { |
| 280 | __u64 unique_id = le64_to_cpu(find_data.UniqueId); | 261 | /* get new inode */ |
| 281 | *pinode = cifs_new_inode(sb, &unique_id); | 262 | *pinode = cifs_iget(sb, &fattr); |
| 282 | if (*pinode == NULL) { | 263 | if (!*pinode) |
| 283 | rc = -ENOMEM; | 264 | rc = -ENOMEM; |
| 284 | goto cgiiu_exit; | 265 | } else { |
| 285 | } | 266 | /* we already have inode, update it */ |
| 267 | cifs_fattr_to_inode(*pinode, &fattr); | ||
| 286 | } | 268 | } |
| 287 | 269 | ||
| 288 | inode = *pinode; | ||
| 289 | cifsInfo = CIFS_I(inode); | ||
| 290 | |||
| 291 | cFYI(1, ("Old time %ld", cifsInfo->time)); | ||
| 292 | cifsInfo->time = jiffies; | ||
| 293 | cFYI(1, ("New time %ld", cifsInfo->time)); | ||
| 294 | /* this is ok to set on every inode revalidate */ | ||
| 295 | atomic_set(&cifsInfo->inUse, 1); | ||
| 296 | |||
| 297 | cifs_unix_info_to_inode(inode, &find_data, 0); | ||
| 298 | |||
| 299 | if (num_of_bytes < end_of_file) | ||
| 300 | cFYI(1, ("allocation size less than end of file")); | ||
| 301 | cFYI(1, ("Size %ld and blocks %llu", | ||
| 302 | (unsigned long) inode->i_size, | ||
| 303 | (unsigned long long)inode->i_blocks)); | ||
| 304 | |||
| 305 | cifs_set_ops(inode, is_dfs_referral); | ||
| 306 | cgiiu_exit: | ||
| 307 | return rc; | 270 | return rc; |
| 308 | } | 271 | } |
| 309 | 272 | ||
| 310 | static int decode_sfu_inode(struct inode *inode, __u64 size, | 273 | static int |
| 311 | const unsigned char *path, | 274 | cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, |
| 312 | struct cifs_sb_info *cifs_sb, int xid) | 275 | struct cifs_sb_info *cifs_sb, int xid) |
| 313 | { | 276 | { |
| 314 | int rc; | 277 | int rc; |
| 315 | int oplock = 0; | 278 | int oplock = 0; |
| @@ -321,10 +284,15 @@ static int decode_sfu_inode(struct inode *inode, __u64 size, | |||
| 321 | 284 | ||
| 322 | pbuf = buf; | 285 | pbuf = buf; |
| 323 | 286 | ||
| 324 | if (size == 0) { | 287 | fattr->cf_mode &= ~S_IFMT; |
| 325 | inode->i_mode |= S_IFIFO; | 288 | |
| 289 | if (fattr->cf_eof == 0) { | ||
| 290 | fattr->cf_mode |= S_IFIFO; | ||
| 291 | fattr->cf_dtype = DT_FIFO; | ||
| 326 | return 0; | 292 | return 0; |
| 327 | } else if (size < 8) { | 293 | } else if (fattr->cf_eof < 8) { |
| 294 | fattr->cf_mode |= S_IFREG; | ||
| 295 | fattr->cf_dtype = DT_REG; | ||
| 328 | return -EINVAL; /* EOPNOTSUPP? */ | 296 | return -EINVAL; /* EOPNOTSUPP? */ |
| 329 | } | 297 | } |
| 330 | 298 | ||
| @@ -336,42 +304,46 @@ static int decode_sfu_inode(struct inode *inode, __u64 size, | |||
| 336 | if (rc == 0) { | 304 | if (rc == 0) { |
| 337 | int buf_type = CIFS_NO_BUFFER; | 305 | int buf_type = CIFS_NO_BUFFER; |
| 338 | /* Read header */ | 306 | /* Read header */ |
| 339 | rc = CIFSSMBRead(xid, pTcon, | 307 | rc = CIFSSMBRead(xid, pTcon, netfid, |
| 340 | netfid, | ||
| 341 | 24 /* length */, 0 /* offset */, | 308 | 24 /* length */, 0 /* offset */, |
| 342 | &bytes_read, &pbuf, &buf_type); | 309 | &bytes_read, &pbuf, &buf_type); |
| 343 | if ((rc == 0) && (bytes_read >= 8)) { | 310 | if ((rc == 0) && (bytes_read >= 8)) { |
| 344 | if (memcmp("IntxBLK", pbuf, 8) == 0) { | 311 | if (memcmp("IntxBLK", pbuf, 8) == 0) { |
| 345 | cFYI(1, ("Block device")); | 312 | cFYI(1, ("Block device")); |
| 346 | inode->i_mode |= S_IFBLK; | 313 | fattr->cf_mode |= S_IFBLK; |
| 314 | fattr->cf_dtype = DT_BLK; | ||
| 347 | if (bytes_read == 24) { | 315 | if (bytes_read == 24) { |
| 348 | /* we have enough to decode dev num */ | 316 | /* we have enough to decode dev num */ |
| 349 | __u64 mjr; /* major */ | 317 | __u64 mjr; /* major */ |
| 350 | __u64 mnr; /* minor */ | 318 | __u64 mnr; /* minor */ |
| 351 | mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); | 319 | mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); |
| 352 | mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); | 320 | mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); |
| 353 | inode->i_rdev = MKDEV(mjr, mnr); | 321 | fattr->cf_rdev = MKDEV(mjr, mnr); |
| 354 | } | 322 | } |
| 355 | } else if (memcmp("IntxCHR", pbuf, 8) == 0) { | 323 | } else if (memcmp("IntxCHR", pbuf, 8) == 0) { |
| 356 | cFYI(1, ("Char device")); | 324 | cFYI(1, ("Char device")); |
| 357 | inode->i_mode |= S_IFCHR; | 325 | fattr->cf_mode |= S_IFCHR; |
| 326 | fattr->cf_dtype = DT_CHR; | ||
| 358 | if (bytes_read == 24) { | 327 | if (bytes_read == 24) { |
| 359 | /* we have enough to decode dev num */ | 328 | /* we have enough to decode dev num */ |
| 360 | __u64 mjr; /* major */ | 329 | __u64 mjr; /* major */ |
| 361 | __u64 mnr; /* minor */ | 330 | __u64 mnr; /* minor */ |
| 362 | mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); | 331 | mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); |
| 363 | mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); | 332 | mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); |
| 364 | inode->i_rdev = MKDEV(mjr, mnr); | 333 | fattr->cf_rdev = MKDEV(mjr, mnr); |
| 365 | } | 334 | } |
| 366 | } else if (memcmp("IntxLNK", pbuf, 7) == 0) { | 335 | } else if (memcmp("IntxLNK", pbuf, 7) == 0) { |
| 367 | cFYI(1, ("Symlink")); | 336 | cFYI(1, ("Symlink")); |
| 368 | inode->i_mode |= S_IFLNK; | 337 | fattr->cf_mode |= S_IFLNK; |
| 338 | fattr->cf_dtype = DT_LNK; | ||
| 369 | } else { | 339 | } else { |
| 370 | inode->i_mode |= S_IFREG; /* file? */ | 340 | fattr->cf_mode |= S_IFREG; /* file? */ |
| 341 | fattr->cf_dtype = DT_REG; | ||
| 371 | rc = -EOPNOTSUPP; | 342 | rc = -EOPNOTSUPP; |
| 372 | } | 343 | } |
| 373 | } else { | 344 | } else { |
| 374 | inode->i_mode |= S_IFREG; /* then it is a file */ | 345 | fattr->cf_mode |= S_IFREG; /* then it is a file */ |
| 346 | fattr->cf_dtype = DT_REG; | ||
| 375 | rc = -EOPNOTSUPP; /* or some unknown SFU type */ | 347 | rc = -EOPNOTSUPP; /* or some unknown SFU type */ |
| 376 | } | 348 | } |
| 377 | CIFSSMBClose(xid, pTcon, netfid); | 349 | CIFSSMBClose(xid, pTcon, netfid); |
| @@ -381,9 +353,13 @@ static int decode_sfu_inode(struct inode *inode, __u64 size, | |||
| 381 | 353 | ||
| 382 | #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ | 354 | #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ |
| 383 | 355 | ||
| 384 | static int get_sfu_mode(struct inode *inode, | 356 | /* |
| 385 | const unsigned char *path, | 357 | * Fetch mode bits as provided by SFU. |
| 386 | struct cifs_sb_info *cifs_sb, int xid) | 358 | * |
| 359 | * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ? | ||
| 360 | */ | ||
| 361 | static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, | ||
| 362 | struct cifs_sb_info *cifs_sb, int xid) | ||
| 387 | { | 363 | { |
| 388 | #ifdef CONFIG_CIFS_XATTR | 364 | #ifdef CONFIG_CIFS_XATTR |
| 389 | ssize_t rc; | 365 | ssize_t rc; |
| @@ -391,68 +367,80 @@ static int get_sfu_mode(struct inode *inode, | |||
| 391 | __u32 mode; | 367 | __u32 mode; |
| 392 | 368 | ||
| 393 | rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", | 369 | rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", |
| 394 | ea_value, 4 /* size of buf */, cifs_sb->local_nls, | 370 | ea_value, 4 /* size of buf */, cifs_sb->local_nls, |
| 395 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 371 | cifs_sb->mnt_cifs_flags & |
| 372 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 396 | if (rc < 0) | 373 | if (rc < 0) |
| 397 | return (int)rc; | 374 | return (int)rc; |
| 398 | else if (rc > 3) { | 375 | else if (rc > 3) { |
| 399 | mode = le32_to_cpu(*((__le32 *)ea_value)); | 376 | mode = le32_to_cpu(*((__le32 *)ea_value)); |
| 400 | inode->i_mode &= ~SFBITS_MASK; | 377 | fattr->cf_mode &= ~SFBITS_MASK; |
| 401 | cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode)); | 378 | cFYI(1, ("special bits 0%o org mode 0%o", mode, |
| 402 | inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode; | 379 | fattr->cf_mode)); |
| 380 | fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode; | ||
| 403 | cFYI(1, ("special mode bits 0%o", mode)); | 381 | cFYI(1, ("special mode bits 0%o", mode)); |
| 404 | return 0; | ||
| 405 | } else { | ||
| 406 | return 0; | ||
| 407 | } | 382 | } |
| 383 | |||
| 384 | return 0; | ||
| 408 | #else | 385 | #else |
| 409 | return -EOPNOTSUPP; | 386 | return -EOPNOTSUPP; |
| 410 | #endif | 387 | #endif |
| 411 | } | 388 | } |
| 412 | 389 | ||
| 413 | /* | 390 | /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ |
| 414 | * Needed to setup inode data for the directory which is the | 391 | void |
| 415 | * junction to the new submount (ie to setup the fake directory | 392 | cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, |
| 416 | * which represents a DFS referral) | 393 | struct cifs_sb_info *cifs_sb, bool adjust_tz) |
| 417 | */ | ||
| 418 | static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat, | ||
| 419 | struct super_block *sb) | ||
| 420 | { | 394 | { |
| 421 | memset(pfnd_dat, 0, sizeof(FILE_ALL_INFO)); | 395 | memset(fattr, 0, sizeof(*fattr)); |
| 422 | 396 | fattr->cf_cifsattrs = le32_to_cpu(info->Attributes); | |
| 423 | /* __le64 pfnd_dat->AllocationSize = cpu_to_le64(0); | 397 | if (info->DeletePending) |
| 424 | __le64 pfnd_dat->EndOfFile = cpu_to_le64(0); | 398 | fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING; |
| 425 | __u8 pfnd_dat->DeletePending = 0; | 399 | |
| 426 | __u8 pfnd_data->Directory = 0; | 400 | if (info->LastAccessTime) |
| 427 | __le32 pfnd_dat->EASize = 0; | 401 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
| 428 | __u64 pfnd_dat->IndexNumber = 0; | 402 | else |
| 429 | __u64 pfnd_dat->IndexNumber1 = 0; */ | 403 | fattr->cf_atime = CURRENT_TIME; |
| 430 | pfnd_dat->CreationTime = | 404 | |
| 431 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 405 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
| 432 | pfnd_dat->LastAccessTime = | 406 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
| 433 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 407 | |
| 434 | pfnd_dat->LastWriteTime = | 408 | if (adjust_tz) { |
| 435 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 409 | fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj; |
| 436 | pfnd_dat->ChangeTime = | 410 | fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj; |
| 437 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 411 | } |
| 438 | pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY); | 412 | |
| 439 | pfnd_dat->NumberOfLinks = cpu_to_le32(2); | 413 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
| 414 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); | ||
| 415 | |||
| 416 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { | ||
| 417 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; | ||
| 418 | fattr->cf_dtype = DT_DIR; | ||
| 419 | } else { | ||
| 420 | fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; | ||
| 421 | fattr->cf_dtype = DT_REG; | ||
| 422 | |||
| 423 | /* clear write bits if ATTR_READONLY is set */ | ||
| 424 | if (fattr->cf_cifsattrs & ATTR_READONLY) | ||
| 425 | fattr->cf_mode &= ~(S_IWUGO); | ||
| 426 | } | ||
| 427 | |||
| 428 | fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); | ||
| 429 | |||
| 430 | fattr->cf_uid = cifs_sb->mnt_uid; | ||
| 431 | fattr->cf_gid = cifs_sb->mnt_gid; | ||
| 440 | } | 432 | } |
| 441 | 433 | ||
| 442 | int cifs_get_inode_info(struct inode **pinode, | 434 | int cifs_get_inode_info(struct inode **pinode, |
| 443 | const unsigned char *full_path, FILE_ALL_INFO *pfindData, | 435 | const unsigned char *full_path, FILE_ALL_INFO *pfindData, |
| 444 | struct super_block *sb, int xid, const __u16 *pfid) | 436 | struct super_block *sb, int xid, const __u16 *pfid) |
| 445 | { | 437 | { |
| 446 | int rc = 0; | 438 | int rc = 0, tmprc; |
| 447 | __u32 attr; | ||
| 448 | struct cifsInodeInfo *cifsInfo; | ||
| 449 | struct cifsTconInfo *pTcon; | 439 | struct cifsTconInfo *pTcon; |
| 450 | struct inode *inode; | ||
| 451 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 440 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
| 452 | char *buf = NULL; | 441 | char *buf = NULL; |
| 453 | bool adjustTZ = false; | 442 | bool adjustTZ = false; |
| 454 | bool is_dfs_referral = false; | 443 | struct cifs_fattr fattr; |
| 455 | umode_t default_mode; | ||
| 456 | 444 | ||
| 457 | pTcon = cifs_sb->tcon; | 445 | pTcon = cifs_sb->tcon; |
| 458 | cFYI(1, ("Getting info on %s", full_path)); | 446 | cFYI(1, ("Getting info on %s", full_path)); |
| @@ -487,163 +475,82 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 487 | adjustTZ = true; | 475 | adjustTZ = true; |
| 488 | } | 476 | } |
| 489 | } | 477 | } |
| 490 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ | 478 | |
| 491 | if (rc == -EREMOTE) { | 479 | if (!rc) { |
| 492 | is_dfs_referral = true; | 480 | cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData, |
| 493 | fill_fake_finddata(pfindData, sb); | 481 | cifs_sb, adjustTZ); |
| 482 | } else if (rc == -EREMOTE) { | ||
| 483 | cifs_create_dfs_fattr(&fattr, sb); | ||
| 494 | rc = 0; | 484 | rc = 0; |
| 495 | } else if (rc) | 485 | } else { |
| 496 | goto cgii_exit; | 486 | goto cgii_exit; |
| 487 | } | ||
| 497 | 488 | ||
| 498 | attr = le32_to_cpu(pfindData->Attributes); | 489 | /* |
| 499 | 490 | * If an inode wasn't passed in, then get the inode number | |
| 500 | /* get new inode */ | 491 | * |
| 492 | * Is an i_ino of zero legal? Can we use that to check if the server | ||
| 493 | * supports returning inode numbers? Are there other sanity checks we | ||
| 494 | * can use to ensure that the server is really filling in that field? | ||
| 495 | * | ||
| 496 | * We can not use the IndexNumber field by default from Windows or | ||
| 497 | * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA | ||
| 498 | * CIFS spec claims that this value is unique within the scope of a | ||
| 499 | * share, and the windows docs hint that it's actually unique | ||
| 500 | * per-machine. | ||
| 501 | * | ||
| 502 | * There may be higher info levels that work but are there Windows | ||
| 503 | * server or network appliances for which IndexNumber field is not | ||
| 504 | * guaranteed unique? | ||
| 505 | */ | ||
| 501 | if (*pinode == NULL) { | 506 | if (*pinode == NULL) { |
| 502 | __u64 inode_num; | ||
| 503 | __u64 *pinum = &inode_num; | ||
| 504 | |||
| 505 | /* Is an i_ino of zero legal? Can we use that to check | ||
| 506 | if the server supports returning inode numbers? Are | ||
| 507 | there other sanity checks we can use to ensure that | ||
| 508 | the server is really filling in that field? */ | ||
| 509 | |||
| 510 | /* We can not use the IndexNumber field by default from | ||
| 511 | Windows or Samba (in ALL_INFO buf) but we can request | ||
| 512 | it explicitly. It may not be unique presumably if | ||
| 513 | the server has multiple devices mounted under one share */ | ||
| 514 | |||
| 515 | /* There may be higher info levels that work but are | ||
| 516 | there Windows server or network appliances for which | ||
| 517 | IndexNumber field is not guaranteed unique? */ | ||
| 518 | |||
| 519 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | 507 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { |
| 520 | int rc1 = 0; | 508 | int rc1 = 0; |
| 521 | 509 | ||
| 522 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, | 510 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, |
| 523 | full_path, pinum, | 511 | full_path, &fattr.cf_uniqueid, |
| 524 | cifs_sb->local_nls, | 512 | cifs_sb->local_nls, |
| 525 | cifs_sb->mnt_cifs_flags & | 513 | cifs_sb->mnt_cifs_flags & |
| 526 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 514 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 527 | if (rc1) { | 515 | if (rc1) { |
| 528 | cFYI(1, ("GetSrvInodeNum rc %d", rc1)); | ||
| 529 | pinum = NULL; | ||
| 530 | /* BB EOPNOSUPP disable SERVER_INUM? */ | 516 | /* BB EOPNOSUPP disable SERVER_INUM? */ |
| 517 | cFYI(1, ("GetSrvInodeNum rc %d", rc1)); | ||
| 518 | fattr.cf_uniqueid = iunique(sb, ROOT_I); | ||
| 531 | } | 519 | } |
| 532 | } else { | 520 | } else { |
| 533 | pinum = NULL; | 521 | fattr.cf_uniqueid = iunique(sb, ROOT_I); |
| 534 | } | 522 | } |
| 535 | |||
| 536 | *pinode = cifs_new_inode(sb, pinum); | ||
| 537 | if (*pinode == NULL) { | ||
| 538 | rc = -ENOMEM; | ||
| 539 | goto cgii_exit; | ||
| 540 | } | ||
| 541 | } | ||
| 542 | inode = *pinode; | ||
| 543 | cifsInfo = CIFS_I(inode); | ||
| 544 | cifsInfo->cifsAttrs = attr; | ||
| 545 | cifsInfo->delete_pending = pfindData->DeletePending ? true : false; | ||
| 546 | cFYI(1, ("Old time %ld", cifsInfo->time)); | ||
| 547 | cifsInfo->time = jiffies; | ||
| 548 | cFYI(1, ("New time %ld", cifsInfo->time)); | ||
| 549 | |||
| 550 | /* blksize needs to be multiple of two. So safer to default to | ||
| 551 | blksize and blkbits set in superblock so 2**blkbits and blksize | ||
| 552 | will match rather than setting to: | ||
| 553 | (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ | ||
| 554 | |||
| 555 | /* Linux can not store file creation time so ignore it */ | ||
| 556 | if (pfindData->LastAccessTime) | ||
| 557 | inode->i_atime = cifs_NTtimeToUnix(pfindData->LastAccessTime); | ||
| 558 | else /* do not need to use current_fs_time - time not stored */ | ||
| 559 | inode->i_atime = CURRENT_TIME; | ||
| 560 | inode->i_mtime = cifs_NTtimeToUnix(pfindData->LastWriteTime); | ||
| 561 | inode->i_ctime = cifs_NTtimeToUnix(pfindData->ChangeTime); | ||
| 562 | cFYI(DBG2, ("Attributes came in as 0x%x", attr)); | ||
| 563 | if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { | ||
| 564 | inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; | ||
| 565 | inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; | ||
| 566 | } | ||
| 567 | |||
| 568 | /* get default inode mode */ | ||
| 569 | if (attr & ATTR_DIRECTORY) | ||
| 570 | default_mode = cifs_sb->mnt_dir_mode; | ||
| 571 | else | ||
| 572 | default_mode = cifs_sb->mnt_file_mode; | ||
| 573 | |||
| 574 | /* set permission bits */ | ||
| 575 | if (atomic_read(&cifsInfo->inUse) == 0 || | ||
| 576 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) | ||
| 577 | inode->i_mode = default_mode; | ||
| 578 | else { | ||
| 579 | /* just reenable write bits if !ATTR_READONLY */ | ||
| 580 | if ((inode->i_mode & S_IWUGO) == 0 && | ||
| 581 | (attr & ATTR_READONLY) == 0) | ||
| 582 | inode->i_mode |= (S_IWUGO & default_mode); | ||
| 583 | |||
| 584 | inode->i_mode &= ~S_IFMT; | ||
| 585 | } | ||
| 586 | /* clear write bits if ATTR_READONLY is set */ | ||
| 587 | if (attr & ATTR_READONLY) | ||
| 588 | inode->i_mode &= ~S_IWUGO; | ||
| 589 | |||
| 590 | /* set inode type */ | ||
| 591 | if ((attr & ATTR_SYSTEM) && | ||
| 592 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { | ||
| 593 | /* no need to fix endianness on 0 */ | ||
| 594 | if (pfindData->EndOfFile == 0) | ||
| 595 | inode->i_mode |= S_IFIFO; | ||
| 596 | else if (decode_sfu_inode(inode, | ||
| 597 | le64_to_cpu(pfindData->EndOfFile), | ||
| 598 | full_path, cifs_sb, xid)) | ||
| 599 | cFYI(1, ("unknown SFU file type\n")); | ||
| 600 | } else { | 523 | } else { |
| 601 | if (attr & ATTR_DIRECTORY) | 524 | fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid; |
| 602 | inode->i_mode |= S_IFDIR; | ||
| 603 | else | ||
| 604 | inode->i_mode |= S_IFREG; | ||
| 605 | } | 525 | } |
| 606 | 526 | ||
| 607 | cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile); | 527 | /* query for SFU type info if supported and needed */ |
| 608 | spin_lock(&inode->i_lock); | 528 | if (fattr.cf_cifsattrs & ATTR_SYSTEM && |
| 609 | if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) { | 529 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { |
| 610 | /* can not safely shrink the file size here if the | 530 | tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid); |
| 611 | client is writing to it due to potential races */ | 531 | if (tmprc) |
| 612 | i_size_write(inode, cifsInfo->server_eof); | 532 | cFYI(1, ("cifs_sfu_type failed: %d", tmprc)); |
| 613 | |||
| 614 | /* 512 bytes (2**9) is the fake blocksize that must be | ||
| 615 | used for this calculation */ | ||
| 616 | inode->i_blocks = (512 - 1 + le64_to_cpu( | ||
| 617 | pfindData->AllocationSize)) >> 9; | ||
| 618 | } | 533 | } |
| 619 | spin_unlock(&inode->i_lock); | ||
| 620 | |||
| 621 | inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); | ||
| 622 | 534 | ||
| 623 | /* BB fill in uid and gid here? with help from winbind? | ||
| 624 | or retrieve from NTFS stream extended attribute */ | ||
| 625 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 535 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| 626 | /* fill in 0777 bits from ACL */ | 536 | /* fill in 0777 bits from ACL */ |
| 627 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | 537 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
| 628 | cFYI(1, ("Getting mode bits from ACL")); | 538 | cFYI(1, ("Getting mode bits from ACL")); |
| 629 | acl_to_uid_mode(cifs_sb, inode, full_path, pfid); | 539 | cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid); |
| 630 | } | 540 | } |
| 631 | #endif | 541 | #endif |
| 632 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | ||
| 633 | /* fill in remaining high mode bits e.g. SUID, VTX */ | ||
| 634 | get_sfu_mode(inode, full_path, cifs_sb, xid); | ||
| 635 | } else if (atomic_read(&cifsInfo->inUse) == 0) { | ||
| 636 | inode->i_uid = cifs_sb->mnt_uid; | ||
| 637 | inode->i_gid = cifs_sb->mnt_gid; | ||
| 638 | /* set so we do not keep refreshing these fields with | ||
| 639 | bad data after user has changed them in memory */ | ||
| 640 | atomic_set(&cifsInfo->inUse, 1); | ||
| 641 | } | ||
| 642 | |||
| 643 | cifs_set_ops(inode, is_dfs_referral); | ||
| 644 | |||
| 645 | 542 | ||
| 543 | /* fill in remaining high mode bits e.g. SUID, VTX */ | ||
| 544 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) | ||
| 545 | cifs_sfu_mode(&fattr, full_path, cifs_sb, xid); | ||
| 646 | 546 | ||
| 547 | if (!*pinode) { | ||
| 548 | *pinode = cifs_iget(sb, &fattr); | ||
| 549 | if (!*pinode) | ||
| 550 | rc = -ENOMEM; | ||
| 551 | } else { | ||
| 552 | cifs_fattr_to_inode(*pinode, &fattr); | ||
| 553 | } | ||
| 647 | 554 | ||
| 648 | cgii_exit: | 555 | cgii_exit: |
| 649 | kfree(buf); | 556 | kfree(buf); |
| @@ -695,33 +602,78 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) | |||
| 695 | return full_path; | 602 | return full_path; |
| 696 | } | 603 | } |
| 697 | 604 | ||
| 605 | static int | ||
| 606 | cifs_find_inode(struct inode *inode, void *opaque) | ||
| 607 | { | ||
| 608 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; | ||
| 609 | |||
| 610 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) | ||
| 611 | return 0; | ||
| 612 | |||
| 613 | return 1; | ||
| 614 | } | ||
| 615 | |||
| 616 | static int | ||
| 617 | cifs_init_inode(struct inode *inode, void *opaque) | ||
| 618 | { | ||
| 619 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; | ||
| 620 | |||
| 621 | CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; | ||
| 622 | return 0; | ||
| 623 | } | ||
| 624 | |||
| 625 | /* Given fattrs, get a corresponding inode */ | ||
| 626 | struct inode * | ||
| 627 | cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) | ||
| 628 | { | ||
| 629 | unsigned long hash; | ||
| 630 | struct inode *inode; | ||
| 631 | |||
| 632 | cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid)); | ||
| 633 | |||
| 634 | /* hash down to 32-bits on 32-bit arch */ | ||
| 635 | hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid); | ||
| 636 | |||
| 637 | inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); | ||
| 638 | |||
| 639 | /* we have fattrs in hand, update the inode */ | ||
| 640 | if (inode) { | ||
| 641 | cifs_fattr_to_inode(inode, fattr); | ||
| 642 | if (sb->s_flags & MS_NOATIME) | ||
| 643 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | ||
| 644 | if (inode->i_state & I_NEW) { | ||
| 645 | inode->i_ino = hash; | ||
| 646 | unlock_new_inode(inode); | ||
| 647 | } | ||
| 648 | } | ||
| 649 | |||
| 650 | return inode; | ||
| 651 | } | ||
| 652 | |||
| 698 | /* gets root inode */ | 653 | /* gets root inode */ |
| 699 | struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) | 654 | struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) |
| 700 | { | 655 | { |
| 701 | int xid; | 656 | int xid; |
| 702 | struct cifs_sb_info *cifs_sb; | 657 | struct cifs_sb_info *cifs_sb; |
| 703 | struct inode *inode; | 658 | struct inode *inode = NULL; |
| 704 | long rc; | 659 | long rc; |
| 705 | char *full_path; | 660 | char *full_path; |
| 706 | 661 | ||
| 707 | inode = iget_locked(sb, ino); | 662 | cifs_sb = CIFS_SB(sb); |
| 708 | if (!inode) | ||
| 709 | return ERR_PTR(-ENOMEM); | ||
| 710 | if (!(inode->i_state & I_NEW)) | ||
| 711 | return inode; | ||
| 712 | |||
| 713 | cifs_sb = CIFS_SB(inode->i_sb); | ||
| 714 | full_path = cifs_build_path_to_root(cifs_sb); | 663 | full_path = cifs_build_path_to_root(cifs_sb); |
| 715 | if (full_path == NULL) | 664 | if (full_path == NULL) |
| 716 | return ERR_PTR(-ENOMEM); | 665 | return ERR_PTR(-ENOMEM); |
| 717 | 666 | ||
| 718 | xid = GetXid(); | 667 | xid = GetXid(); |
| 719 | if (cifs_sb->tcon->unix_ext) | 668 | if (cifs_sb->tcon->unix_ext) |
| 720 | rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, | 669 | rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); |
| 721 | xid); | ||
| 722 | else | 670 | else |
| 723 | rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb, | 671 | rc = cifs_get_inode_info(&inode, full_path, NULL, sb, |
| 724 | xid, NULL); | 672 | xid, NULL); |
| 673 | |||
| 674 | if (!inode) | ||
| 675 | return ERR_PTR(-ENOMEM); | ||
| 676 | |||
| 725 | if (rc && cifs_sb->tcon->ipc) { | 677 | if (rc && cifs_sb->tcon->ipc) { |
| 726 | cFYI(1, ("ipc connection - fake read inode")); | 678 | cFYI(1, ("ipc connection - fake read inode")); |
| 727 | inode->i_mode |= S_IFDIR; | 679 | inode->i_mode |= S_IFDIR; |
| @@ -737,7 +689,6 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) | |||
| 737 | return ERR_PTR(rc); | 689 | return ERR_PTR(rc); |
| 738 | } | 690 | } |
| 739 | 691 | ||
| 740 | unlock_new_inode(inode); | ||
| 741 | 692 | ||
| 742 | kfree(full_path); | 693 | kfree(full_path); |
| 743 | /* can not call macro FreeXid here since in a void func | 694 | /* can not call macro FreeXid here since in a void func |
| @@ -988,8 +939,9 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 988 | * sb->s_vfs_rename_mutex here */ | 939 | * sb->s_vfs_rename_mutex here */ |
| 989 | full_path = build_path_from_dentry(dentry); | 940 | full_path = build_path_from_dentry(dentry); |
| 990 | if (full_path == NULL) { | 941 | if (full_path == NULL) { |
| 942 | rc = -ENOMEM; | ||
| 991 | FreeXid(xid); | 943 | FreeXid(xid); |
| 992 | return -ENOMEM; | 944 | return rc; |
| 993 | } | 945 | } |
| 994 | 946 | ||
| 995 | if ((tcon->ses->capabilities & CAP_UNIX) && | 947 | if ((tcon->ses->capabilities & CAP_UNIX) && |
| @@ -1062,44 +1014,6 @@ out_reval: | |||
| 1062 | return rc; | 1014 | return rc; |
| 1063 | } | 1015 | } |
| 1064 | 1016 | ||
| 1065 | void posix_fill_in_inode(struct inode *tmp_inode, | ||
| 1066 | FILE_UNIX_BASIC_INFO *pData, int isNewInode) | ||
| 1067 | { | ||
| 1068 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); | ||
| 1069 | loff_t local_size; | ||
| 1070 | struct timespec local_mtime; | ||
| 1071 | |||
| 1072 | cifsInfo->time = jiffies; | ||
| 1073 | atomic_inc(&cifsInfo->inUse); | ||
| 1074 | |||
| 1075 | /* save mtime and size */ | ||
| 1076 | local_mtime = tmp_inode->i_mtime; | ||
| 1077 | local_size = tmp_inode->i_size; | ||
| 1078 | |||
| 1079 | cifs_unix_info_to_inode(tmp_inode, pData, 1); | ||
| 1080 | cifs_set_ops(tmp_inode, false); | ||
| 1081 | |||
| 1082 | if (!S_ISREG(tmp_inode->i_mode)) | ||
| 1083 | return; | ||
| 1084 | |||
| 1085 | /* | ||
| 1086 | * No sense invalidating pages for new inode | ||
| 1087 | * since we we have not started caching | ||
| 1088 | * readahead file data yet. | ||
| 1089 | */ | ||
| 1090 | if (isNewInode) | ||
| 1091 | return; | ||
| 1092 | |||
| 1093 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && | ||
| 1094 | (local_size == tmp_inode->i_size)) { | ||
| 1095 | cFYI(1, ("inode exists but unchanged")); | ||
| 1096 | } else { | ||
| 1097 | /* file may have changed on server */ | ||
| 1098 | cFYI(1, ("invalidate inode, readdir detected change")); | ||
| 1099 | invalidate_remote_inode(tmp_inode); | ||
| 1100 | } | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | 1017 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) |
| 1104 | { | 1018 | { |
| 1105 | int rc = 0, tmprc; | 1019 | int rc = 0, tmprc; |
| @@ -1108,6 +1022,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
| 1108 | struct cifsTconInfo *pTcon; | 1022 | struct cifsTconInfo *pTcon; |
| 1109 | char *full_path = NULL; | 1023 | char *full_path = NULL; |
| 1110 | struct inode *newinode = NULL; | 1024 | struct inode *newinode = NULL; |
| 1025 | struct cifs_fattr fattr; | ||
| 1111 | 1026 | ||
| 1112 | cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode)); | 1027 | cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode)); |
| 1113 | 1028 | ||
| @@ -1118,8 +1033,9 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
| 1118 | 1033 | ||
| 1119 | full_path = build_path_from_dentry(direntry); | 1034 | full_path = build_path_from_dentry(direntry); |
| 1120 | if (full_path == NULL) { | 1035 | if (full_path == NULL) { |
| 1036 | rc = -ENOMEM; | ||
| 1121 | FreeXid(xid); | 1037 | FreeXid(xid); |
| 1122 | return -ENOMEM; | 1038 | return rc; |
| 1123 | } | 1039 | } |
| 1124 | 1040 | ||
| 1125 | if ((pTcon->ses->capabilities & CAP_UNIX) && | 1041 | if ((pTcon->ses->capabilities & CAP_UNIX) && |
| @@ -1146,7 +1062,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
| 1146 | cFYI(1, ("posix mkdir returned 0x%x", rc)); | 1062 | cFYI(1, ("posix mkdir returned 0x%x", rc)); |
| 1147 | d_drop(direntry); | 1063 | d_drop(direntry); |
| 1148 | } else { | 1064 | } else { |
| 1149 | __u64 unique_id; | ||
| 1150 | if (pInfo->Type == cpu_to_le32(-1)) { | 1065 | if (pInfo->Type == cpu_to_le32(-1)) { |
| 1151 | /* no return info, go query for it */ | 1066 | /* no return info, go query for it */ |
| 1152 | kfree(pInfo); | 1067 | kfree(pInfo); |
| @@ -1160,20 +1075,15 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
| 1160 | else | 1075 | else |
| 1161 | direntry->d_op = &cifs_dentry_ops; | 1076 | direntry->d_op = &cifs_dentry_ops; |
| 1162 | 1077 | ||
| 1163 | unique_id = le64_to_cpu(pInfo->UniqueId); | 1078 | cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); |
| 1164 | newinode = cifs_new_inode(inode->i_sb, &unique_id); | 1079 | newinode = cifs_iget(inode->i_sb, &fattr); |
| 1165 | if (newinode == NULL) { | 1080 | if (!newinode) { |
| 1166 | kfree(pInfo); | 1081 | kfree(pInfo); |
| 1167 | goto mkdir_get_info; | 1082 | goto mkdir_get_info; |
| 1168 | } | 1083 | } |
| 1169 | 1084 | ||
| 1170 | newinode->i_nlink = 2; | ||
| 1171 | d_instantiate(direntry, newinode); | 1085 | d_instantiate(direntry, newinode); |
| 1172 | 1086 | ||
| 1173 | /* we already checked in POSIXCreate whether | ||
| 1174 | frame was long enough */ | ||
| 1175 | posix_fill_in_inode(direntry->d_inode, | ||
| 1176 | pInfo, 1 /* NewInode */); | ||
| 1177 | #ifdef CONFIG_CIFS_DEBUG2 | 1087 | #ifdef CONFIG_CIFS_DEBUG2 |
| 1178 | cFYI(1, ("instantiated dentry %p %s to inode %p", | 1088 | cFYI(1, ("instantiated dentry %p %s to inode %p", |
| 1179 | direntry, direntry->d_name.name, newinode)); | 1089 | direntry, direntry->d_name.name, newinode)); |
| @@ -1236,10 +1146,10 @@ mkdir_get_info: | |||
| 1236 | args.uid = NO_CHANGE_64; | 1146 | args.uid = NO_CHANGE_64; |
| 1237 | args.gid = NO_CHANGE_64; | 1147 | args.gid = NO_CHANGE_64; |
| 1238 | } | 1148 | } |
| 1239 | CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args, | 1149 | CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args, |
| 1240 | cifs_sb->local_nls, | 1150 | cifs_sb->local_nls, |
| 1241 | cifs_sb->mnt_cifs_flags & | 1151 | cifs_sb->mnt_cifs_flags & |
| 1242 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1152 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 1243 | } else { | 1153 | } else { |
| 1244 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && | 1154 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && |
| 1245 | (mode & S_IWUGO) == 0) { | 1155 | (mode & S_IWUGO) == 0) { |
| @@ -1303,8 +1213,9 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) | |||
| 1303 | 1213 | ||
| 1304 | full_path = build_path_from_dentry(direntry); | 1214 | full_path = build_path_from_dentry(direntry); |
| 1305 | if (full_path == NULL) { | 1215 | if (full_path == NULL) { |
| 1216 | rc = -ENOMEM; | ||
| 1306 | FreeXid(xid); | 1217 | FreeXid(xid); |
| 1307 | return -ENOMEM; | 1218 | return rc; |
| 1308 | } | 1219 | } |
| 1309 | 1220 | ||
| 1310 | rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, | 1221 | rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, |
| @@ -1508,8 +1419,9 @@ int cifs_revalidate(struct dentry *direntry) | |||
| 1508 | since that would deadlock */ | 1419 | since that would deadlock */ |
| 1509 | full_path = build_path_from_dentry(direntry); | 1420 | full_path = build_path_from_dentry(direntry); |
| 1510 | if (full_path == NULL) { | 1421 | if (full_path == NULL) { |
| 1422 | rc = -ENOMEM; | ||
| 1511 | FreeXid(xid); | 1423 | FreeXid(xid); |
| 1512 | return -ENOMEM; | 1424 | return rc; |
| 1513 | } | 1425 | } |
| 1514 | cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld " | 1426 | cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld " |
| 1515 | "jiffies %ld", full_path, direntry->d_inode, | 1427 | "jiffies %ld", full_path, direntry->d_inode, |
| @@ -1618,6 +1530,7 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
| 1618 | if (!err) { | 1530 | if (!err) { |
| 1619 | generic_fillattr(dentry->d_inode, stat); | 1531 | generic_fillattr(dentry->d_inode, stat); |
| 1620 | stat->blksize = CIFS_MAX_MSGSIZE; | 1532 | stat->blksize = CIFS_MAX_MSGSIZE; |
| 1533 | stat->ino = CIFS_I(dentry->d_inode)->uniqueid; | ||
| 1621 | } | 1534 | } |
| 1622 | return err; | 1535 | return err; |
| 1623 | } | 1536 | } |
| @@ -1782,6 +1695,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
| 1782 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 1695 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
| 1783 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | 1696 | struct cifsTconInfo *pTcon = cifs_sb->tcon; |
| 1784 | struct cifs_unix_set_info_args *args = NULL; | 1697 | struct cifs_unix_set_info_args *args = NULL; |
| 1698 | struct cifsFileInfo *open_file; | ||
| 1785 | 1699 | ||
| 1786 | cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x", | 1700 | cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x", |
| 1787 | direntry->d_name.name, attrs->ia_valid)); | 1701 | direntry->d_name.name, attrs->ia_valid)); |
| @@ -1868,10 +1782,18 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
| 1868 | args->ctime = NO_CHANGE_64; | 1782 | args->ctime = NO_CHANGE_64; |
| 1869 | 1783 | ||
| 1870 | args->device = 0; | 1784 | args->device = 0; |
| 1871 | rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, args, | 1785 | open_file = find_writable_file(cifsInode); |
| 1872 | cifs_sb->local_nls, | 1786 | if (open_file) { |
| 1873 | cifs_sb->mnt_cifs_flags & | 1787 | u16 nfid = open_file->netfid; |
| 1874 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1788 | u32 npid = open_file->pid; |
| 1789 | rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); | ||
| 1790 | atomic_dec(&open_file->wrtPending); | ||
| 1791 | } else { | ||
| 1792 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, | ||
| 1793 | cifs_sb->local_nls, | ||
| 1794 | cifs_sb->mnt_cifs_flags & | ||
| 1795 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1796 | } | ||
| 1875 | 1797 | ||
| 1876 | if (!rc) | 1798 | if (!rc) |
| 1877 | rc = inode_setattr(inode, attrs); | 1799 | rc = inode_setattr(inode, attrs); |
| @@ -1911,8 +1833,9 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
| 1911 | 1833 | ||
| 1912 | full_path = build_path_from_dentry(direntry); | 1834 | full_path = build_path_from_dentry(direntry); |
| 1913 | if (full_path == NULL) { | 1835 | if (full_path == NULL) { |
| 1836 | rc = -ENOMEM; | ||
| 1914 | FreeXid(xid); | 1837 | FreeXid(xid); |
| 1915 | return -ENOMEM; | 1838 | return rc; |
| 1916 | } | 1839 | } |
| 1917 | 1840 | ||
| 1918 | /* | 1841 | /* |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index cd83c53fcbb..fc1e0487eae 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 32d6baa0a54..bd6d6895730 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/readdir.c b/fs/cifs/readdir.c index 86d0055dc52..f823a4a208a 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
| @@ -63,374 +63,123 @@ static inline void dump_cifs_file_struct(struct file *file, char *label) | |||
| 63 | } | 63 | } |
| 64 | #endif /* DEBUG2 */ | 64 | #endif /* DEBUG2 */ |
| 65 | 65 | ||
| 66 | /* Returns 1 if new inode created, 2 if both dentry and inode were */ | 66 | /* |
| 67 | /* Might check in the future if inode number changed so we can rehash inode */ | 67 | * Find the dentry that matches "name". If there isn't one, create one. If it's |
| 68 | static int | 68 | * a negative dentry or the uniqueid changed, then drop it and recreate it. |
| 69 | construct_dentry(struct qstr *qstring, struct file *file, | 69 | */ |
| 70 | struct inode **ptmp_inode, struct dentry **pnew_dentry, | 70 | static struct dentry * |
| 71 | __u64 *inum) | 71 | cifs_readdir_lookup(struct dentry *parent, struct qstr *name, |
| 72 | struct cifs_fattr *fattr) | ||
| 72 | { | 73 | { |
| 73 | struct dentry *tmp_dentry = NULL; | 74 | struct dentry *dentry, *alias; |
| 74 | struct super_block *sb = file->f_path.dentry->d_sb; | 75 | struct inode *inode; |
| 75 | int rc = 0; | 76 | struct super_block *sb = parent->d_inode->i_sb; |
| 77 | |||
| 78 | cFYI(1, ("For %s", name->name)); | ||
| 79 | |||
| 80 | dentry = d_lookup(parent, name); | ||
| 81 | if (dentry) { | ||
| 82 | /* FIXME: check for inode number changes? */ | ||
| 83 | if (dentry->d_inode != NULL) | ||
| 84 | return dentry; | ||
| 85 | d_drop(dentry); | ||
| 86 | dput(dentry); | ||
| 87 | } | ||
| 76 | 88 | ||
| 77 | cFYI(1, ("For %s", qstring->name)); | 89 | dentry = d_alloc(parent, name); |
| 78 | 90 | if (dentry == NULL) | |
| 79 | qstring->hash = full_name_hash(qstring->name, qstring->len); | 91 | return NULL; |
| 80 | tmp_dentry = d_lookup(file->f_path.dentry, qstring); | ||
| 81 | if (tmp_dentry) { | ||
| 82 | /* BB: overwrite old name? i.e. tmp_dentry->d_name and | ||
| 83 | * tmp_dentry->d_name.len?? | ||
| 84 | */ | ||
| 85 | cFYI(0, ("existing dentry with inode 0x%p", | ||
| 86 | tmp_dentry->d_inode)); | ||
| 87 | *ptmp_inode = tmp_dentry->d_inode; | ||
| 88 | if (*ptmp_inode == NULL) { | ||
| 89 | *ptmp_inode = cifs_new_inode(sb, inum); | ||
| 90 | if (*ptmp_inode == NULL) | ||
| 91 | return rc; | ||
| 92 | rc = 1; | ||
| 93 | } | ||
| 94 | } else { | ||
| 95 | tmp_dentry = d_alloc(file->f_path.dentry, qstring); | ||
| 96 | if (tmp_dentry == NULL) { | ||
| 97 | cERROR(1, ("Failed allocating dentry")); | ||
| 98 | *ptmp_inode = NULL; | ||
| 99 | return rc; | ||
| 100 | } | ||
| 101 | 92 | ||
| 102 | if (CIFS_SB(sb)->tcon->nocase) | 93 | inode = cifs_iget(sb, fattr); |
| 103 | tmp_dentry->d_op = &cifs_ci_dentry_ops; | 94 | if (!inode) { |
| 104 | else | 95 | dput(dentry); |
| 105 | tmp_dentry->d_op = &cifs_dentry_ops; | 96 | return NULL; |
| 97 | } | ||
| 106 | 98 | ||
| 107 | *ptmp_inode = cifs_new_inode(sb, inum); | 99 | if (CIFS_SB(sb)->tcon->nocase) |
| 108 | if (*ptmp_inode == NULL) | 100 | dentry->d_op = &cifs_ci_dentry_ops; |
| 109 | return rc; | 101 | else |
| 110 | rc = 2; | 102 | dentry->d_op = &cifs_dentry_ops; |
| 103 | |||
| 104 | alias = d_materialise_unique(dentry, inode); | ||
| 105 | if (alias != NULL) { | ||
| 106 | dput(dentry); | ||
| 107 | if (IS_ERR(alias)) | ||
| 108 | return NULL; | ||
| 109 | dentry = alias; | ||
| 111 | } | 110 | } |
| 112 | 111 | ||
| 113 | tmp_dentry->d_time = jiffies; | 112 | return dentry; |
| 114 | *pnew_dentry = tmp_dentry; | ||
| 115 | return rc; | ||
| 116 | } | 113 | } |
| 117 | 114 | ||
| 118 | static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, | 115 | static void |
| 119 | char *buf, unsigned int *pobject_type, int isNewInode) | 116 | cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) |
| 120 | { | 117 | { |
| 121 | loff_t local_size; | 118 | fattr->cf_uid = cifs_sb->mnt_uid; |
| 122 | struct timespec local_mtime; | 119 | fattr->cf_gid = cifs_sb->mnt_gid; |
| 123 | |||
| 124 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); | ||
| 125 | struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); | ||
| 126 | __u32 attr; | ||
| 127 | __u64 allocation_size; | ||
| 128 | __u64 end_of_file; | ||
| 129 | umode_t default_mode; | ||
| 130 | |||
| 131 | /* save mtime and size */ | ||
| 132 | local_mtime = tmp_inode->i_mtime; | ||
| 133 | local_size = tmp_inode->i_size; | ||
| 134 | |||
| 135 | if (new_buf_type) { | ||
| 136 | FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf; | ||
| 137 | |||
| 138 | attr = le32_to_cpu(pfindData->ExtFileAttributes); | ||
| 139 | allocation_size = le64_to_cpu(pfindData->AllocationSize); | ||
| 140 | end_of_file = le64_to_cpu(pfindData->EndOfFile); | ||
| 141 | tmp_inode->i_atime = | ||
| 142 | cifs_NTtimeToUnix(pfindData->LastAccessTime); | ||
| 143 | tmp_inode->i_mtime = | ||
| 144 | cifs_NTtimeToUnix(pfindData->LastWriteTime); | ||
| 145 | tmp_inode->i_ctime = | ||
| 146 | cifs_NTtimeToUnix(pfindData->ChangeTime); | ||
| 147 | } else { /* legacy, OS2 and DOS style */ | ||
| 148 | int offset = cifs_sb->tcon->ses->server->timeAdj; | ||
| 149 | FIND_FILE_STANDARD_INFO *pfindData = | ||
| 150 | (FIND_FILE_STANDARD_INFO *)buf; | ||
| 151 | |||
| 152 | tmp_inode->i_mtime = cnvrtDosUnixTm(pfindData->LastWriteDate, | ||
| 153 | pfindData->LastWriteTime, | ||
| 154 | offset); | ||
| 155 | tmp_inode->i_atime = cnvrtDosUnixTm(pfindData->LastAccessDate, | ||
| 156 | pfindData->LastAccessTime, | ||
| 157 | offset); | ||
| 158 | tmp_inode->i_ctime = cnvrtDosUnixTm(pfindData->LastWriteDate, | ||
| 159 | pfindData->LastWriteTime, | ||
| 160 | offset); | ||
| 161 | attr = le16_to_cpu(pfindData->Attributes); | ||
| 162 | allocation_size = le32_to_cpu(pfindData->AllocationSize); | ||
| 163 | end_of_file = le32_to_cpu(pfindData->DataSize); | ||
| 164 | } | ||
| 165 | 120 | ||
| 166 | /* Linux can not store file creation time unfortunately so ignore it */ | 121 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { |
| 167 | 122 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; | |
| 168 | cifsInfo->cifsAttrs = attr; | 123 | fattr->cf_dtype = DT_DIR; |
| 169 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 124 | } else { |
| 170 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | 125 | fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; |
| 171 | /* get more accurate mode via ACL - so force inode refresh */ | 126 | fattr->cf_dtype = DT_REG; |
| 172 | cifsInfo->time = 0; | ||
| 173 | } else | ||
| 174 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
| 175 | cifsInfo->time = jiffies; | ||
| 176 | |||
| 177 | /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ | ||
| 178 | /* 2767 perms - indicate mandatory locking */ | ||
| 179 | /* BB fill in uid and gid here? with help from winbind? | ||
| 180 | or retrieve from NTFS stream extended attribute */ | ||
| 181 | if (atomic_read(&cifsInfo->inUse) == 0) { | ||
| 182 | tmp_inode->i_uid = cifs_sb->mnt_uid; | ||
| 183 | tmp_inode->i_gid = cifs_sb->mnt_gid; | ||
| 184 | } | ||
| 185 | |||
| 186 | if (attr & ATTR_DIRECTORY) | ||
| 187 | default_mode = cifs_sb->mnt_dir_mode; | ||
| 188 | else | ||
| 189 | default_mode = cifs_sb->mnt_file_mode; | ||
| 190 | |||
| 191 | /* set initial permissions */ | ||
| 192 | if ((atomic_read(&cifsInfo->inUse) == 0) || | ||
| 193 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) | ||
| 194 | tmp_inode->i_mode = default_mode; | ||
| 195 | else { | ||
| 196 | /* just reenable write bits if !ATTR_READONLY */ | ||
| 197 | if ((tmp_inode->i_mode & S_IWUGO) == 0 && | ||
| 198 | (attr & ATTR_READONLY) == 0) | ||
| 199 | tmp_inode->i_mode |= (S_IWUGO & default_mode); | ||
| 200 | |||
| 201 | tmp_inode->i_mode &= ~S_IFMT; | ||
| 202 | } | 127 | } |
| 203 | 128 | ||
| 204 | /* clear write bits if ATTR_READONLY is set */ | 129 | if (fattr->cf_cifsattrs & ATTR_READONLY) |
| 205 | if (attr & ATTR_READONLY) | 130 | fattr->cf_mode &= ~S_IWUGO; |
| 206 | tmp_inode->i_mode &= ~S_IWUGO; | ||
| 207 | 131 | ||
| 208 | /* set inode type */ | 132 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL && |
| 209 | if ((attr & ATTR_SYSTEM) && | 133 | fattr->cf_cifsattrs & ATTR_SYSTEM) { |
| 210 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { | 134 | if (fattr->cf_eof == 0) { |
| 211 | if (end_of_file == 0) { | 135 | fattr->cf_mode &= ~S_IFMT; |
| 212 | tmp_inode->i_mode |= S_IFIFO; | 136 | fattr->cf_mode |= S_IFIFO; |
| 213 | *pobject_type = DT_FIFO; | 137 | fattr->cf_dtype = DT_FIFO; |
| 214 | } else { | 138 | } else { |
| 215 | /* | 139 | /* |
| 216 | * trying to get the type can be slow, so just call | 140 | * trying to get the type and mode via SFU can be slow, |
| 217 | * this a regular file for now, and mark for reval | 141 | * so just call those regular files for now, and mark |
| 142 | * for reval | ||
| 218 | */ | 143 | */ |
| 219 | tmp_inode->i_mode |= S_IFREG; | 144 | fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; |
| 220 | *pobject_type = DT_REG; | ||
| 221 | cifsInfo->time = 0; | ||
| 222 | } | ||
| 223 | } else { | ||
| 224 | if (attr & ATTR_DIRECTORY) { | ||
| 225 | tmp_inode->i_mode |= S_IFDIR; | ||
| 226 | *pobject_type = DT_DIR; | ||
| 227 | } else { | ||
| 228 | tmp_inode->i_mode |= S_IFREG; | ||
| 229 | *pobject_type = DT_REG; | ||
| 230 | } | 145 | } |
| 231 | } | 146 | } |
| 147 | } | ||
| 232 | 148 | ||
| 233 | /* can not fill in nlink here as in qpathinfo version and Unx search */ | 149 | void |
| 234 | if (atomic_read(&cifsInfo->inUse) == 0) | 150 | cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info, |
| 235 | atomic_set(&cifsInfo->inUse, 1); | 151 | struct cifs_sb_info *cifs_sb) |
| 236 | 152 | { | |
| 237 | cifsInfo->server_eof = end_of_file; | 153 | memset(fattr, 0, sizeof(*fattr)); |
| 238 | spin_lock(&tmp_inode->i_lock); | 154 | fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes); |
| 239 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | 155 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
| 240 | /* can not safely change the file size here if the | 156 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
| 241 | client is writing to it due to potential races */ | 157 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
| 242 | i_size_write(tmp_inode, end_of_file); | 158 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
| 243 | 159 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); | |
| 244 | /* 512 bytes (2**9) is the fake blocksize that must be used */ | 160 | |
| 245 | /* for this calculation, even though the reported blocksize is larger */ | 161 | cifs_fill_common_info(fattr, cifs_sb); |
| 246 | tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; | ||
| 247 | } | ||
| 248 | spin_unlock(&tmp_inode->i_lock); | ||
| 249 | |||
| 250 | if (allocation_size < end_of_file) | ||
| 251 | cFYI(1, ("May be sparse file, allocation less than file size")); | ||
| 252 | cFYI(1, ("File Size %ld and blocks %llu", | ||
| 253 | (unsigned long)tmp_inode->i_size, | ||
| 254 | (unsigned long long)tmp_inode->i_blocks)); | ||
| 255 | if (S_ISREG(tmp_inode->i_mode)) { | ||
| 256 | cFYI(1, ("File inode")); | ||
| 257 | tmp_inode->i_op = &cifs_file_inode_ops; | ||
| 258 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { | ||
| 259 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
| 260 | tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; | ||
| 261 | else | ||
| 262 | tmp_inode->i_fop = &cifs_file_direct_ops; | ||
| 263 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
| 264 | tmp_inode->i_fop = &cifs_file_nobrl_ops; | ||
| 265 | else | ||
| 266 | tmp_inode->i_fop = &cifs_file_ops; | ||
| 267 | |||
| 268 | if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | ||
| 269 | (cifs_sb->tcon->ses->server->maxBuf < | ||
| 270 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) | ||
| 271 | tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; | ||
| 272 | else | ||
| 273 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | ||
| 274 | |||
| 275 | if (isNewInode) | ||
| 276 | return; /* No sense invalidating pages for new inode | ||
| 277 | since have not started caching readahead file | ||
| 278 | data yet */ | ||
| 279 | |||
| 280 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && | ||
| 281 | (local_size == tmp_inode->i_size)) { | ||
| 282 | cFYI(1, ("inode exists but unchanged")); | ||
| 283 | } else { | ||
| 284 | /* file may have changed on server */ | ||
| 285 | cFYI(1, ("invalidate inode, readdir detected change")); | ||
| 286 | invalidate_remote_inode(tmp_inode); | ||
| 287 | } | ||
| 288 | } else if (S_ISDIR(tmp_inode->i_mode)) { | ||
| 289 | cFYI(1, ("Directory inode")); | ||
| 290 | tmp_inode->i_op = &cifs_dir_inode_ops; | ||
| 291 | tmp_inode->i_fop = &cifs_dir_ops; | ||
| 292 | } else if (S_ISLNK(tmp_inode->i_mode)) { | ||
| 293 | cFYI(1, ("Symbolic Link inode")); | ||
| 294 | tmp_inode->i_op = &cifs_symlink_inode_ops; | ||
| 295 | } else { | ||
| 296 | cFYI(1, ("Init special inode")); | ||
| 297 | init_special_inode(tmp_inode, tmp_inode->i_mode, | ||
| 298 | tmp_inode->i_rdev); | ||
| 299 | } | ||
| 300 | } | 162 | } |
| 301 | 163 | ||
| 302 | static void unix_fill_in_inode(struct inode *tmp_inode, | 164 | void |
| 303 | FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode) | 165 | cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, |
| 166 | struct cifs_sb_info *cifs_sb) | ||
| 304 | { | 167 | { |
| 305 | loff_t local_size; | 168 | int offset = cifs_sb->tcon->ses->server->timeAdj; |
| 306 | struct timespec local_mtime; | ||
| 307 | |||
| 308 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); | ||
| 309 | struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); | ||
| 310 | |||
| 311 | __u32 type = le32_to_cpu(pfindData->Type); | ||
| 312 | __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes); | ||
| 313 | __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); | ||
| 314 | cifsInfo->time = jiffies; | ||
| 315 | atomic_inc(&cifsInfo->inUse); | ||
| 316 | |||
| 317 | /* save mtime and size */ | ||
| 318 | local_mtime = tmp_inode->i_mtime; | ||
| 319 | local_size = tmp_inode->i_size; | ||
| 320 | |||
| 321 | tmp_inode->i_atime = | ||
| 322 | cifs_NTtimeToUnix(pfindData->LastAccessTime); | ||
| 323 | tmp_inode->i_mtime = | ||
| 324 | cifs_NTtimeToUnix(pfindData->LastModificationTime); | ||
| 325 | tmp_inode->i_ctime = | ||
| 326 | cifs_NTtimeToUnix(pfindData->LastStatusChange); | ||
| 327 | |||
| 328 | tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); | ||
| 329 | /* since we set the inode type below we need to mask off type | ||
| 330 | to avoid strange results if bits above were corrupt */ | ||
| 331 | tmp_inode->i_mode &= ~S_IFMT; | ||
| 332 | if (type == UNIX_FILE) { | ||
| 333 | *pobject_type = DT_REG; | ||
| 334 | tmp_inode->i_mode |= S_IFREG; | ||
| 335 | } else if (type == UNIX_SYMLINK) { | ||
| 336 | *pobject_type = DT_LNK; | ||
| 337 | tmp_inode->i_mode |= S_IFLNK; | ||
| 338 | } else if (type == UNIX_DIR) { | ||
| 339 | *pobject_type = DT_DIR; | ||
| 340 | tmp_inode->i_mode |= S_IFDIR; | ||
| 341 | } else if (type == UNIX_CHARDEV) { | ||
| 342 | *pobject_type = DT_CHR; | ||
| 343 | tmp_inode->i_mode |= S_IFCHR; | ||
| 344 | tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), | ||
| 345 | le64_to_cpu(pfindData->DevMinor) & MINORMASK); | ||
| 346 | } else if (type == UNIX_BLOCKDEV) { | ||
| 347 | *pobject_type = DT_BLK; | ||
| 348 | tmp_inode->i_mode |= S_IFBLK; | ||
| 349 | tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), | ||
| 350 | le64_to_cpu(pfindData->DevMinor) & MINORMASK); | ||
| 351 | } else if (type == UNIX_FIFO) { | ||
| 352 | *pobject_type = DT_FIFO; | ||
| 353 | tmp_inode->i_mode |= S_IFIFO; | ||
| 354 | } else if (type == UNIX_SOCKET) { | ||
| 355 | *pobject_type = DT_SOCK; | ||
| 356 | tmp_inode->i_mode |= S_IFSOCK; | ||
| 357 | } else { | ||
| 358 | /* safest to just call it a file */ | ||
| 359 | *pobject_type = DT_REG; | ||
| 360 | tmp_inode->i_mode |= S_IFREG; | ||
| 361 | cFYI(1, ("unknown inode type %d", type)); | ||
| 362 | } | ||
| 363 | 169 | ||
| 364 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) | 170 | memset(fattr, 0, sizeof(*fattr)); |
| 365 | tmp_inode->i_uid = cifs_sb->mnt_uid; | 171 | fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, |
| 366 | else | 172 | info->LastAccessTime, offset); |
| 367 | tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); | 173 | fattr->cf_ctime = cnvrtDosUnixTm(info->LastWriteDate, |
| 368 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) | 174 | info->LastWriteTime, offset); |
| 369 | tmp_inode->i_gid = cifs_sb->mnt_gid; | 175 | fattr->cf_mtime = cnvrtDosUnixTm(info->LastWriteDate, |
| 370 | else | 176 | info->LastWriteTime, offset); |
| 371 | tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); | ||
| 372 | tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); | ||
| 373 | |||
| 374 | cifsInfo->server_eof = end_of_file; | ||
| 375 | spin_lock(&tmp_inode->i_lock); | ||
| 376 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | ||
| 377 | /* can not safely change the file size here if the | ||
| 378 | client is writing to it due to potential races */ | ||
| 379 | i_size_write(tmp_inode, end_of_file); | ||
| 380 | |||
| 381 | /* 512 bytes (2**9) is the fake blocksize that must be used */ | ||
| 382 | /* for this calculation, not the real blocksize */ | ||
| 383 | tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; | ||
| 384 | } | ||
| 385 | spin_unlock(&tmp_inode->i_lock); | ||
| 386 | 177 | ||
| 387 | if (S_ISREG(tmp_inode->i_mode)) { | 178 | fattr->cf_cifsattrs = le16_to_cpu(info->Attributes); |
| 388 | cFYI(1, ("File inode")); | 179 | fattr->cf_bytes = le32_to_cpu(info->AllocationSize); |
| 389 | tmp_inode->i_op = &cifs_file_inode_ops; | 180 | fattr->cf_eof = le32_to_cpu(info->DataSize); |
| 390 | 181 | ||
| 391 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { | 182 | cifs_fill_common_info(fattr, cifs_sb); |
| 392 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
| 393 | tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; | ||
| 394 | else | ||
| 395 | tmp_inode->i_fop = &cifs_file_direct_ops; | ||
| 396 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
| 397 | tmp_inode->i_fop = &cifs_file_nobrl_ops; | ||
| 398 | else | ||
| 399 | tmp_inode->i_fop = &cifs_file_ops; | ||
| 400 | |||
| 401 | if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | ||
| 402 | (cifs_sb->tcon->ses->server->maxBuf < | ||
| 403 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) | ||
| 404 | tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; | ||
| 405 | else | ||
| 406 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | ||
| 407 | |||
| 408 | if (isNewInode) | ||
| 409 | return; /* No sense invalidating pages for new inode | ||
| 410 | since we have not started caching readahead | ||
| 411 | file data for it yet */ | ||
| 412 | |||
| 413 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && | ||
| 414 | (local_size == tmp_inode->i_size)) { | ||
| 415 | cFYI(1, ("inode exists but unchanged")); | ||
| 416 | } else { | ||
| 417 | /* file may have changed on server */ | ||
| 418 | cFYI(1, ("invalidate inode, readdir detected change")); | ||
| 419 | invalidate_remote_inode(tmp_inode); | ||
| 420 | } | ||
| 421 | } else if (S_ISDIR(tmp_inode->i_mode)) { | ||
| 422 | cFYI(1, ("Directory inode")); | ||
| 423 | tmp_inode->i_op = &cifs_dir_inode_ops; | ||
| 424 | tmp_inode->i_fop = &cifs_dir_ops; | ||
| 425 | } else if (S_ISLNK(tmp_inode->i_mode)) { | ||
| 426 | cFYI(1, ("Symbolic Link inode")); | ||
| 427 | tmp_inode->i_op = &cifs_symlink_inode_ops; | ||
| 428 | /* tmp_inode->i_fop = *//* do not need to set to anything */ | ||
| 429 | } else { | ||
| 430 | cFYI(1, ("Special inode")); | ||
| 431 | init_special_inode(tmp_inode, tmp_inode->i_mode, | ||
| 432 | tmp_inode->i_rdev); | ||
| 433 | } | ||
| 434 | } | 183 | } |
| 435 | 184 | ||
| 436 | /* BB eventually need to add the following helper function to | 185 | /* BB eventually need to add the following helper function to |
| @@ -872,7 +621,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
| 872 | len = strnlen(filename, PATH_MAX); | 621 | len = strnlen(filename, PATH_MAX); |
| 873 | } | 622 | } |
| 874 | 623 | ||
| 875 | *pinum = le64_to_cpu(pFindData->UniqueId); | 624 | *pinum = le64_to_cpu(pFindData->basic.UniqueId); |
| 876 | } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { | 625 | } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { |
| 877 | FILE_DIRECTORY_INFO *pFindData = | 626 | FILE_DIRECTORY_INFO *pFindData = |
| 878 | (FILE_DIRECTORY_INFO *)current_entry; | 627 | (FILE_DIRECTORY_INFO *)current_entry; |
| @@ -932,11 +681,12 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, | |||
| 932 | int rc = 0; | 681 | int rc = 0; |
| 933 | struct qstr qstring; | 682 | struct qstr qstring; |
| 934 | struct cifsFileInfo *pCifsF; | 683 | struct cifsFileInfo *pCifsF; |
| 935 | unsigned int obj_type; | 684 | u64 inum; |
| 936 | __u64 inum; | 685 | ino_t ino; |
| 686 | struct super_block *sb; | ||
| 937 | struct cifs_sb_info *cifs_sb; | 687 | struct cifs_sb_info *cifs_sb; |
| 938 | struct inode *tmp_inode; | ||
| 939 | struct dentry *tmp_dentry; | 688 | struct dentry *tmp_dentry; |
| 689 | struct cifs_fattr fattr; | ||
| 940 | 690 | ||
| 941 | /* get filename and len into qstring */ | 691 | /* get filename and len into qstring */ |
| 942 | /* get dentry */ | 692 | /* get dentry */ |
| @@ -954,60 +704,53 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, | |||
| 954 | if (rc != 0) | 704 | if (rc != 0) |
| 955 | return 0; | 705 | return 0; |
| 956 | 706 | ||
| 957 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 707 | sb = file->f_path.dentry->d_sb; |
| 708 | cifs_sb = CIFS_SB(sb); | ||
| 958 | 709 | ||
| 959 | qstring.name = scratch_buf; | 710 | qstring.name = scratch_buf; |
| 960 | rc = cifs_get_name_from_search_buf(&qstring, pfindEntry, | 711 | rc = cifs_get_name_from_search_buf(&qstring, pfindEntry, |
| 961 | pCifsF->srch_inf.info_level, | 712 | pCifsF->srch_inf.info_level, |
| 962 | pCifsF->srch_inf.unicode, cifs_sb, | 713 | pCifsF->srch_inf.unicode, cifs_sb, |
| 963 | max_len, | 714 | max_len, &inum /* returned */); |
| 964 | &inum /* returned */); | ||
| 965 | 715 | ||
| 966 | if (rc) | 716 | if (rc) |
| 967 | return rc; | 717 | return rc; |
| 968 | 718 | ||
| 969 | /* only these two infolevels return valid inode numbers */ | ||
| 970 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX || | ||
| 971 | pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO) | ||
| 972 | rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry, | ||
| 973 | &inum); | ||
| 974 | else | ||
| 975 | rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry, | ||
| 976 | NULL); | ||
| 977 | |||
| 978 | if ((tmp_inode == NULL) || (tmp_dentry == NULL)) | ||
| 979 | return -ENOMEM; | ||
| 980 | |||
| 981 | /* we pass in rc below, indicating whether it is a new inode, | ||
| 982 | so we can figure out whether to invalidate the inode cached | ||
| 983 | data if the file has changed */ | ||
| 984 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) | 719 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) |
| 985 | unix_fill_in_inode(tmp_inode, | 720 | cifs_unix_basic_to_fattr(&fattr, |
| 986 | (FILE_UNIX_INFO *)pfindEntry, | 721 | &((FILE_UNIX_INFO *) pfindEntry)->basic, |
| 987 | &obj_type, rc); | 722 | cifs_sb); |
| 988 | else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) | 723 | else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) |
| 989 | fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */, | 724 | cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *) |
| 990 | pfindEntry, &obj_type, rc); | 725 | pfindEntry, cifs_sb); |
| 991 | else | 726 | else |
| 992 | fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc); | 727 | cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *) |
| 728 | pfindEntry, cifs_sb); | ||
| 993 | 729 | ||
| 994 | if (rc) /* new inode - needs to be tied to dentry */ { | 730 | /* FIXME: make _to_fattr functions fill this out */ |
| 995 | d_instantiate(tmp_dentry, tmp_inode); | 731 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO) |
| 996 | if (rc == 2) | 732 | fattr.cf_uniqueid = inum; |
| 997 | d_rehash(tmp_dentry); | 733 | else |
| 998 | } | 734 | fattr.cf_uniqueid = iunique(sb, ROOT_I); |
| 999 | 735 | ||
| 736 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); | ||
| 737 | tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); | ||
| 1000 | 738 | ||
| 1001 | rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, | 739 | rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, |
| 1002 | tmp_inode->i_ino, obj_type); | 740 | ino, fattr.cf_dtype); |
| 741 | |||
| 742 | /* | ||
| 743 | * we can not return filldir errors to the caller since they are | ||
| 744 | * "normal" when the stat blocksize is too small - we return remapped | ||
| 745 | * error instead | ||
| 746 | * | ||
| 747 | * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above | ||
| 748 | * case already. Why should we be clobbering other errors from it? | ||
| 749 | */ | ||
| 1003 | if (rc) { | 750 | if (rc) { |
| 1004 | cFYI(1, ("filldir rc = %d", rc)); | 751 | cFYI(1, ("filldir rc = %d", rc)); |
| 1005 | /* we can not return filldir errors to the caller | ||
| 1006 | since they are "normal" when the stat blocksize | ||
| 1007 | is too small - we return remapped error instead */ | ||
| 1008 | rc = -EOVERFLOW; | 752 | rc = -EOVERFLOW; |
| 1009 | } | 753 | } |
| 1010 | |||
| 1011 | dput(tmp_dentry); | 754 | dput(tmp_dentry); |
| 1012 | return rc; | 755 | return rc; |
| 1013 | } | 756 | } |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 897a052270f..7085a6275c4 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 e9527eedc63..a75afa3dd9e 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.c b/fs/compat.c index cdd51a3a7c5..fbadb947727 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -1486,8 +1486,8 @@ int compat_do_execve(char * filename, | |||
| 1486 | if (!bprm) | 1486 | if (!bprm) |
| 1487 | goto out_files; | 1487 | goto out_files; |
| 1488 | 1488 | ||
| 1489 | retval = mutex_lock_interruptible(¤t->cred_guard_mutex); | 1489 | retval = -ERESTARTNOINTR; |
| 1490 | if (retval < 0) | 1490 | if (mutex_lock_interruptible(¤t->cred_guard_mutex)) |
| 1491 | goto out_free; | 1491 | goto out_free; |
| 1492 | current->in_execve = 1; | 1492 | current->in_execve = 1; |
| 1493 | 1493 | ||
diff --git a/fs/eventfd.c b/fs/eventfd.c index 3f0e1974abd..31d12de83a2 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; |
| @@ -1277,8 +1277,8 @@ int do_execve(char * filename, | |||
| 1277 | if (!bprm) | 1277 | if (!bprm) |
| 1278 | goto out_files; | 1278 | goto out_files; |
| 1279 | 1279 | ||
| 1280 | retval = mutex_lock_interruptible(¤t->cred_guard_mutex); | 1280 | retval = -ERESTARTNOINTR; |
| 1281 | if (retval < 0) | 1281 | if (mutex_lock_interruptible(¤t->cred_guard_mutex)) |
| 1282 | goto out_free; | 1282 | goto out_free; |
| 1283 | current->in_execve = 1; | 1283 | current->in_execve = 1; |
| 1284 | 1284 | ||
diff --git a/fs/exofs/common.h b/fs/exofs/common.h index 24667eedc02..c6718e4817f 100644 --- a/fs/exofs/common.h +++ b/fs/exofs/common.h | |||
| @@ -2,9 +2,7 @@ | |||
| 2 | * common.h - Common definitions for both Kernel and user-mode utilities | 2 | * common.h - Common definitions for both Kernel and user-mode utilities |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2005, 2006 | 4 | * Copyright (C) 2005, 2006 |
| 5 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 5 | * Avishay Traeger (avishay@gmail.com) |
| 6 | * Copyright (C) 2005, 2006 | ||
| 7 | * International Business Machines | ||
| 8 | * Copyright (C) 2008, 2009 | 6 | * Copyright (C) 2008, 2009 |
| 9 | * Boaz Harrosh <bharrosh@panasas.com> | 7 | * Boaz Harrosh <bharrosh@panasas.com> |
| 10 | * | 8 | * |
diff --git a/fs/exofs/dir.c b/fs/exofs/dir.c index 65b0c8c776a..4cfab1cc75c 100644 --- a/fs/exofs/dir.c +++ b/fs/exofs/dir.c | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
| 3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
| 4 | * Copyright (C) 2005, 2006 | ||
| 5 | * International Business Machines | ||
| 6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
| 7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
| 8 | * | 6 | * |
diff --git a/fs/exofs/exofs.h b/fs/exofs/exofs.h index 0fd4c785967..5ec72e020b2 100644 --- a/fs/exofs/exofs.h +++ b/fs/exofs/exofs.h | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
| 3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
| 4 | * Copyright (C) 2005, 2006 | ||
| 5 | * International Business Machines | ||
| 6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
| 7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
| 8 | * | 6 | * |
| @@ -156,6 +154,9 @@ ino_t exofs_parent_ino(struct dentry *child); | |||
| 156 | int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *, | 154 | int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *, |
| 157 | struct inode *); | 155 | struct inode *); |
| 158 | 156 | ||
| 157 | /* super.c */ | ||
| 158 | int exofs_sync_fs(struct super_block *sb, int wait); | ||
| 159 | |||
| 159 | /********************* | 160 | /********************* |
| 160 | * operation vectors * | 161 | * operation vectors * |
| 161 | *********************/ | 162 | *********************/ |
diff --git a/fs/exofs/file.c b/fs/exofs/file.c index 6ed7fe48475..839b9dc1e70 100644 --- a/fs/exofs/file.c +++ b/fs/exofs/file.c | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
| 3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
| 4 | * Copyright (C) 2005, 2006 | ||
| 5 | * International Business Machines | ||
| 6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
| 7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
| 8 | * | 6 | * |
| @@ -47,16 +45,23 @@ static int exofs_file_fsync(struct file *filp, struct dentry *dentry, | |||
| 47 | { | 45 | { |
| 48 | int ret; | 46 | int ret; |
| 49 | struct address_space *mapping = filp->f_mapping; | 47 | struct address_space *mapping = filp->f_mapping; |
| 48 | struct inode *inode = dentry->d_inode; | ||
| 49 | struct super_block *sb; | ||
| 50 | 50 | ||
| 51 | ret = filemap_write_and_wait(mapping); | 51 | ret = filemap_write_and_wait(mapping); |
| 52 | if (ret) | 52 | if (ret) |
| 53 | return ret; | 53 | return ret; |
| 54 | 54 | ||
| 55 | /*Note: file_fsync below also calles sync_blockdev, which is a no-op | 55 | /* sync the inode attributes */ |
| 56 | * for exofs, but other then that it does sync_inode and | 56 | ret = write_inode_now(inode, 1); |
| 57 | * sync_superblock which is what we need here. | 57 | |
| 58 | */ | 58 | /* This is a good place to write the sb */ |
| 59 | return file_fsync(filp, dentry, datasync); | 59 | /* TODO: Sechedule an sb-sync on create */ |
| 60 | sb = inode->i_sb; | ||
| 61 | if (sb->s_dirt) | ||
| 62 | exofs_sync_fs(sb, 1); | ||
| 63 | |||
| 64 | return ret; | ||
| 60 | } | 65 | } |
| 61 | 66 | ||
| 62 | static int exofs_flush(struct file *file, fl_owner_t id) | 67 | static int exofs_flush(struct file *file, fl_owner_t id) |
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index 77d0a295eb1..6c10f747669 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
| 3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
| 4 | * Copyright (C) 2005, 2006 | ||
| 5 | * International Business Machines | ||
| 6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
| 7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
| 8 | * | 6 | * |
| @@ -295,6 +293,9 @@ static int read_exec(struct page_collect *pcol, bool is_sync) | |||
| 295 | err: | 293 | err: |
| 296 | if (!is_sync) | 294 | if (!is_sync) |
| 297 | _unlock_pcol_pages(pcol, ret, READ); | 295 | _unlock_pcol_pages(pcol, ret, READ); |
| 296 | else /* Pages unlocked by caller in sync mode only free bio */ | ||
| 297 | pcol_free(pcol); | ||
| 298 | |||
| 298 | kfree(pcol_copy); | 299 | kfree(pcol_copy); |
| 299 | if (or) | 300 | if (or) |
| 300 | osd_end_request(or); | 301 | osd_end_request(or); |
diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c index 77fdd765e76..b7dd0c23686 100644 --- a/fs/exofs/namei.c +++ b/fs/exofs/namei.c | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
| 3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
| 4 | * Copyright (C) 2005, 2006 | ||
| 5 | * International Business Machines | ||
| 6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
| 7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
| 8 | * | 6 | * |
diff --git a/fs/exofs/osd.c b/fs/exofs/osd.c index b3d2ccb87aa..4372542df28 100644 --- a/fs/exofs/osd.c +++ b/fs/exofs/osd.c | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
| 3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
| 4 | * Copyright (C) 2005, 2006 | ||
| 5 | * International Business Machines | ||
| 6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
| 7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
| 8 | * | 6 | * |
diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 8216c5b77b5..a343b4ea62f 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
| 3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
| 4 | * Copyright (C) 2005, 2006 | ||
| 5 | * International Business Machines | ||
| 6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
| 7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
| 8 | * | 6 | * |
| @@ -200,7 +198,7 @@ static const struct export_operations exofs_export_ops; | |||
| 200 | /* | 198 | /* |
| 201 | * Write the superblock to the OSD | 199 | * Write the superblock to the OSD |
| 202 | */ | 200 | */ |
| 203 | static int exofs_sync_fs(struct super_block *sb, int wait) | 201 | int exofs_sync_fs(struct super_block *sb, int wait) |
| 204 | { | 202 | { |
| 205 | struct exofs_sb_info *sbi; | 203 | struct exofs_sb_info *sbi; |
| 206 | struct exofs_fscb *fscb; | 204 | struct exofs_fscb *fscb; |
diff --git a/fs/exofs/symlink.c b/fs/exofs/symlink.c index 36e2d7bc7f7..4dd687c3e74 100644 --- a/fs/exofs/symlink.c +++ b/fs/exofs/symlink.c | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
| 3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
| 4 | * Copyright (C) 2005, 2006 | ||
| 5 | * International Business Machines | ||
| 6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
| 7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
| 8 | * | 6 | * |
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 6524ecaebb7..e1dedb0f787 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/fat/file.c b/fs/fat/file.c index b28ea646ff6..f042b965c95 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
| @@ -134,7 +134,7 @@ static int fat_file_release(struct inode *inode, struct file *filp) | |||
| 134 | if ((filp->f_mode & FMODE_WRITE) && | 134 | if ((filp->f_mode & FMODE_WRITE) && |
| 135 | MSDOS_SB(inode->i_sb)->options.flush) { | 135 | MSDOS_SB(inode->i_sb)->options.flush) { |
| 136 | fat_flush_inodes(inode->i_sb, inode, NULL); | 136 | fat_flush_inodes(inode->i_sb, inode, NULL); |
| 137 | congestion_wait(WRITE, HZ/10); | 137 | congestion_wait(BLK_RW_ASYNC, HZ/10); |
| 138 | } | 138 | } |
| 139 | return 0; | 139 | return 0; |
| 140 | } | 140 | } |
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 8fed2ed12f3..cbceacbc0bf 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/pagemap.h> | 16 | #include <linux/pagemap.h> |
| 17 | #include <linux/file.h> | 17 | #include <linux/file.h> |
| 18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 19 | #include <linux/blkdev.h> | ||
| 19 | 20 | ||
| 20 | MODULE_ALIAS_MISCDEV(FUSE_MINOR); | 21 | MODULE_ALIAS_MISCDEV(FUSE_MINOR); |
| 21 | 22 | ||
| @@ -286,8 +287,8 @@ __releases(&fc->lock) | |||
| 286 | } | 287 | } |
| 287 | if (fc->num_background == FUSE_CONGESTION_THRESHOLD && | 288 | if (fc->num_background == FUSE_CONGESTION_THRESHOLD && |
| 288 | fc->connected && fc->bdi_initialized) { | 289 | fc->connected && fc->bdi_initialized) { |
| 289 | clear_bdi_congested(&fc->bdi, READ); | 290 | clear_bdi_congested(&fc->bdi, BLK_RW_SYNC); |
| 290 | clear_bdi_congested(&fc->bdi, WRITE); | 291 | clear_bdi_congested(&fc->bdi, BLK_RW_ASYNC); |
| 291 | } | 292 | } |
| 292 | fc->num_background--; | 293 | fc->num_background--; |
| 293 | fc->active_background--; | 294 | fc->active_background--; |
| @@ -414,8 +415,8 @@ static void fuse_request_send_nowait_locked(struct fuse_conn *fc, | |||
| 414 | fc->blocked = 1; | 415 | fc->blocked = 1; |
| 415 | if (fc->num_background == FUSE_CONGESTION_THRESHOLD && | 416 | if (fc->num_background == FUSE_CONGESTION_THRESHOLD && |
| 416 | fc->bdi_initialized) { | 417 | fc->bdi_initialized) { |
| 417 | set_bdi_congested(&fc->bdi, READ); | 418 | set_bdi_congested(&fc->bdi, BLK_RW_SYNC); |
| 418 | set_bdi_congested(&fc->bdi, WRITE); | 419 | set_bdi_congested(&fc->bdi, BLK_RW_ASYNC); |
| 419 | } | 420 | } |
| 420 | list_add_tail(&req->list, &fc->bg_queue); | 421 | list_add_tail(&req->list, &fc->bg_queue); |
| 421 | flush_bg_queue(fc); | 422 | flush_bg_queue(fc); |
| @@ -849,6 +850,81 @@ err: | |||
| 849 | return err; | 850 | return err; |
| 850 | } | 851 | } |
| 851 | 852 | ||
| 853 | static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size, | ||
| 854 | struct fuse_copy_state *cs) | ||
| 855 | { | ||
| 856 | struct fuse_notify_inval_inode_out outarg; | ||
| 857 | int err = -EINVAL; | ||
| 858 | |||
| 859 | if (size != sizeof(outarg)) | ||
| 860 | goto err; | ||
| 861 | |||
| 862 | err = fuse_copy_one(cs, &outarg, sizeof(outarg)); | ||
| 863 | if (err) | ||
| 864 | goto err; | ||
| 865 | fuse_copy_finish(cs); | ||
| 866 | |||
| 867 | down_read(&fc->killsb); | ||
| 868 | err = -ENOENT; | ||
| 869 | if (!fc->sb) | ||
| 870 | goto err_unlock; | ||
| 871 | |||
| 872 | err = fuse_reverse_inval_inode(fc->sb, outarg.ino, | ||
| 873 | outarg.off, outarg.len); | ||
| 874 | |||
| 875 | err_unlock: | ||
| 876 | up_read(&fc->killsb); | ||
| 877 | return err; | ||
| 878 | |||
| 879 | err: | ||
| 880 | fuse_copy_finish(cs); | ||
| 881 | return err; | ||
| 882 | } | ||
| 883 | |||
| 884 | static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, | ||
| 885 | struct fuse_copy_state *cs) | ||
| 886 | { | ||
| 887 | struct fuse_notify_inval_entry_out outarg; | ||
| 888 | int err = -EINVAL; | ||
| 889 | char buf[FUSE_NAME_MAX+1]; | ||
| 890 | struct qstr name; | ||
| 891 | |||
| 892 | if (size < sizeof(outarg)) | ||
| 893 | goto err; | ||
| 894 | |||
| 895 | err = fuse_copy_one(cs, &outarg, sizeof(outarg)); | ||
| 896 | if (err) | ||
| 897 | goto err; | ||
| 898 | |||
| 899 | err = -ENAMETOOLONG; | ||
| 900 | if (outarg.namelen > FUSE_NAME_MAX) | ||
| 901 | goto err; | ||
| 902 | |||
| 903 | name.name = buf; | ||
| 904 | name.len = outarg.namelen; | ||
| 905 | err = fuse_copy_one(cs, buf, outarg.namelen + 1); | ||
| 906 | if (err) | ||
| 907 | goto err; | ||
| 908 | fuse_copy_finish(cs); | ||
| 909 | buf[outarg.namelen] = 0; | ||
| 910 | name.hash = full_name_hash(name.name, name.len); | ||
| 911 | |||
| 912 | down_read(&fc->killsb); | ||
| 913 | err = -ENOENT; | ||
| 914 | if (!fc->sb) | ||
| 915 | goto err_unlock; | ||
| 916 | |||
| 917 | err = fuse_reverse_inval_entry(fc->sb, outarg.parent, &name); | ||
| 918 | |||
| 919 | err_unlock: | ||
| 920 | up_read(&fc->killsb); | ||
| 921 | return err; | ||
| 922 | |||
| 923 | err: | ||
| 924 | fuse_copy_finish(cs); | ||
| 925 | return err; | ||
| 926 | } | ||
| 927 | |||
| 852 | static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, | 928 | static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, |
| 853 | unsigned int size, struct fuse_copy_state *cs) | 929 | unsigned int size, struct fuse_copy_state *cs) |
| 854 | { | 930 | { |
| @@ -856,6 +932,12 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, | |||
| 856 | case FUSE_NOTIFY_POLL: | 932 | case FUSE_NOTIFY_POLL: |
| 857 | return fuse_notify_poll(fc, size, cs); | 933 | return fuse_notify_poll(fc, size, cs); |
| 858 | 934 | ||
| 935 | case FUSE_NOTIFY_INVAL_INODE: | ||
| 936 | return fuse_notify_inval_inode(fc, size, cs); | ||
| 937 | |||
| 938 | case FUSE_NOTIFY_INVAL_ENTRY: | ||
| 939 | return fuse_notify_inval_entry(fc, size, cs); | ||
| 940 | |||
| 859 | default: | 941 | default: |
| 860 | fuse_copy_finish(cs); | 942 | fuse_copy_finish(cs); |
| 861 | return -EINVAL; | 943 | return -EINVAL; |
| @@ -910,7 +992,7 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 910 | unsigned long nr_segs, loff_t pos) | 992 | unsigned long nr_segs, loff_t pos) |
| 911 | { | 993 | { |
| 912 | int err; | 994 | int err; |
| 913 | unsigned nbytes = iov_length(iov, nr_segs); | 995 | size_t nbytes = iov_length(iov, nr_segs); |
| 914 | struct fuse_req *req; | 996 | struct fuse_req *req; |
| 915 | struct fuse_out_header oh; | 997 | struct fuse_out_header oh; |
| 916 | struct fuse_copy_state cs; | 998 | struct fuse_copy_state cs; |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index b3089a083d3..e703654e7f4 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 fce6ce694fd..cbc464043b6 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 aaf2f9ff970..52b641fc0fa 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 d8673ccf90b..f91ccc4a189 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 fe02ad4740e..032604e5ef2 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/isofs/inode.c b/fs/isofs/inode.c index 58a7963e168..85f96bc651c 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
| @@ -142,6 +142,7 @@ static const struct dentry_operations isofs_dentry_ops[] = { | |||
| 142 | 142 | ||
| 143 | struct iso9660_options{ | 143 | struct iso9660_options{ |
| 144 | unsigned int rock:1; | 144 | unsigned int rock:1; |
| 145 | unsigned int joliet:1; | ||
| 145 | unsigned int cruft:1; | 146 | unsigned int cruft:1; |
| 146 | unsigned int hide:1; | 147 | unsigned int hide:1; |
| 147 | unsigned int showassoc:1; | 148 | unsigned int showassoc:1; |
| @@ -151,7 +152,6 @@ struct iso9660_options{ | |||
| 151 | unsigned int gid_set:1; | 152 | unsigned int gid_set:1; |
| 152 | unsigned int utf8:1; | 153 | unsigned int utf8:1; |
| 153 | unsigned char map; | 154 | unsigned char map; |
| 154 | char joliet; | ||
| 155 | unsigned char check; | 155 | unsigned char check; |
| 156 | unsigned int blocksize; | 156 | unsigned int blocksize; |
| 157 | mode_t fmode; | 157 | mode_t fmode; |
| @@ -632,7 +632,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) | |||
| 632 | else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) { | 632 | else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) { |
| 633 | sec = (struct iso_supplementary_descriptor *)vdp; | 633 | sec = (struct iso_supplementary_descriptor *)vdp; |
| 634 | if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) { | 634 | if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) { |
| 635 | if (opt.joliet == 'y') { | 635 | if (opt.joliet) { |
| 636 | if (sec->escape[2] == 0x40) | 636 | if (sec->escape[2] == 0x40) |
| 637 | joliet_level = 1; | 637 | joliet_level = 1; |
| 638 | else if (sec->escape[2] == 0x43) | 638 | else if (sec->escape[2] == 0x43) |
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index a0244740b75..b47679be118 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
| @@ -270,19 +270,21 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, | |||
| 270 | D2({ | 270 | D2({ |
| 271 | int i=0; | 271 | int i=0; |
| 272 | struct jffs2_raw_node_ref *this; | 272 | struct jffs2_raw_node_ref *this; |
| 273 | printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG); | 273 | printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n"); |
| 274 | 274 | ||
| 275 | this = ic->nodes; | 275 | this = ic->nodes; |
| 276 | 276 | ||
| 277 | printk(KERN_DEBUG); | ||
| 277 | while(this) { | 278 | while(this) { |
| 278 | printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this)); | 279 | printk(KERN_CONT "0x%08x(%d)->", |
| 280 | ref_offset(this), ref_flags(this)); | ||
| 279 | if (++i == 5) { | 281 | if (++i == 5) { |
| 280 | printk("\n" KERN_DEBUG); | 282 | printk(KERN_DEBUG); |
| 281 | i=0; | 283 | i=0; |
| 282 | } | 284 | } |
| 283 | this = this->next_in_ino; | 285 | this = this->next_in_ino; |
| 284 | } | 286 | } |
| 285 | printk("\n"); | 287 | printk(KERN_CONT "\n"); |
| 286 | }); | 288 | }); |
| 287 | 289 | ||
| 288 | switch (ic->class) { | 290 | switch (ic->class) { |
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 7515e73e2bf..696686cc206 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 | ||
diff --git a/fs/namei.c b/fs/namei.c index 5b961eb71cb..f3c5b278895 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -1761,6 +1761,10 @@ do_last: | |||
| 1761 | goto exit; | 1761 | goto exit; |
| 1762 | } | 1762 | } |
| 1763 | 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)); | ||
| 1764 | mnt_drop_write(nd.path.mnt); | 1768 | mnt_drop_write(nd.path.mnt); |
| 1765 | if (nd.root.mnt) | 1769 | if (nd.root.mnt) |
| 1766 | path_put(&nd.root); | 1770 | path_put(&nd.root); |
| @@ -1817,6 +1821,9 @@ ok: | |||
| 1817 | goto exit; | 1821 | goto exit; |
| 1818 | } | 1822 | } |
| 1819 | 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)); | ||
| 1820 | /* | 1827 | /* |
| 1821 | * It is now safe to drop the mnt write | 1828 | * It is now safe to drop the mnt write |
| 1822 | * because the filp has had a write taken | 1829 | * because the filp has had a write taken |
diff --git a/fs/namespace.c b/fs/namespace.c index 3dc283fd471..277c28a63ea 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
| 23 | #include <linux/mnt_namespace.h> | 23 | #include <linux/mnt_namespace.h> |
| 24 | #include <linux/namei.h> | 24 | #include <linux/namei.h> |
| 25 | #include <linux/nsproxy.h> | ||
| 25 | #include <linux/security.h> | 26 | #include <linux/security.h> |
| 26 | #include <linux/mount.h> | 27 | #include <linux/mount.h> |
| 27 | #include <linux/ramfs.h> | 28 | #include <linux/ramfs.h> |
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 46177cb8706..b35d2a61606 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
| @@ -30,7 +30,6 @@ | |||
| 30 | #include <linux/nfs_idmap.h> | 30 | #include <linux/nfs_idmap.h> |
| 31 | #include <linux/vfs.h> | 31 | #include <linux/vfs.h> |
| 32 | #include <linux/namei.h> | 32 | #include <linux/namei.h> |
| 33 | #include <linux/mnt_namespace.h> | ||
| 34 | #include <linux/security.h> | 33 | #include <linux/security.h> |
| 35 | 34 | ||
| 36 | #include <asm/system.h> | 35 | #include <asm/system.h> |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index ce728829f79..35d81316163 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/nfs_mount.h> | 19 | #include <linux/nfs_mount.h> |
| 20 | #include <linux/nfs_page.h> | 20 | #include <linux/nfs_page.h> |
| 21 | #include <linux/backing-dev.h> | 21 | #include <linux/backing-dev.h> |
| 22 | #include <linux/blkdev.h> | ||
| 22 | 23 | ||
| 23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
| 24 | 25 | ||
| @@ -202,8 +203,10 @@ static int nfs_set_page_writeback(struct page *page) | |||
| 202 | struct nfs_server *nfss = NFS_SERVER(inode); | 203 | struct nfs_server *nfss = NFS_SERVER(inode); |
| 203 | 204 | ||
| 204 | if (atomic_long_inc_return(&nfss->writeback) > | 205 | if (atomic_long_inc_return(&nfss->writeback) > |
| 205 | NFS_CONGESTION_ON_THRESH) | 206 | NFS_CONGESTION_ON_THRESH) { |
| 206 | set_bdi_congested(&nfss->backing_dev_info, WRITE); | 207 | set_bdi_congested(&nfss->backing_dev_info, |
| 208 | BLK_RW_ASYNC); | ||
| 209 | } | ||
| 207 | } | 210 | } |
| 208 | return ret; | 211 | return ret; |
| 209 | } | 212 | } |
| @@ -215,7 +218,7 @@ static void nfs_end_page_writeback(struct page *page) | |||
| 215 | 218 | ||
| 216 | end_page_writeback(page); | 219 | end_page_writeback(page); |
| 217 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) | 220 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) |
| 218 | clear_bdi_congested(&nfss->backing_dev_info, WRITE); | 221 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
| 219 | } | 222 | } |
| 220 | 223 | ||
| 221 | /* | 224 | /* |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 4145083dcf8..23341c1063b 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -678,7 +678,6 @@ __be32 | |||
| 678 | nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | 678 | nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, |
| 679 | int access, struct file **filp) | 679 | int access, struct file **filp) |
| 680 | { | 680 | { |
| 681 | const struct cred *cred = current_cred(); | ||
| 682 | struct dentry *dentry; | 681 | struct dentry *dentry; |
| 683 | struct inode *inode; | 682 | struct inode *inode; |
| 684 | int flags = O_RDONLY|O_LARGEFILE; | 683 | int flags = O_RDONLY|O_LARGEFILE; |
| @@ -733,7 +732,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 733 | vfs_dq_init(inode); | 732 | vfs_dq_init(inode); |
| 734 | } | 733 | } |
| 735 | *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), | 734 | *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), |
| 736 | flags, cred); | 735 | flags, current_cred()); |
| 737 | if (IS_ERR(*filp)) | 736 | if (IS_ERR(*filp)) |
| 738 | host_err = PTR_ERR(*filp); | 737 | host_err = PTR_ERR(*filp); |
| 739 | else | 738 | else |
diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index 36df60b6d8a..99d58a028b9 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c | |||
| @@ -568,6 +568,7 @@ void nilfs_bmap_abort_update_v(struct nilfs_bmap *bmap, | |||
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | static struct lock_class_key nilfs_bmap_dat_lock_key; | 570 | static struct lock_class_key nilfs_bmap_dat_lock_key; |
| 571 | static struct lock_class_key nilfs_bmap_mdt_lock_key; | ||
| 571 | 572 | ||
| 572 | /** | 573 | /** |
| 573 | * nilfs_bmap_read - read a bmap from an inode | 574 | * nilfs_bmap_read - read a bmap from an inode |
| @@ -603,7 +604,11 @@ int nilfs_bmap_read(struct nilfs_bmap *bmap, struct nilfs_inode *raw_inode) | |||
| 603 | bmap->b_ptr_type = NILFS_BMAP_PTR_VS; | 604 | bmap->b_ptr_type = NILFS_BMAP_PTR_VS; |
| 604 | bmap->b_last_allocated_key = 0; | 605 | bmap->b_last_allocated_key = 0; |
| 605 | bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; | 606 | bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; |
| 607 | lockdep_set_class(&bmap->b_sem, &nilfs_bmap_mdt_lock_key); | ||
| 606 | break; | 608 | break; |
| 609 | case NILFS_IFILE_INO: | ||
| 610 | lockdep_set_class(&bmap->b_sem, &nilfs_bmap_mdt_lock_key); | ||
| 611 | /* Fall through */ | ||
| 607 | default: | 612 | default: |
| 608 | bmap->b_ptr_type = NILFS_BMAP_PTR_VM; | 613 | bmap->b_ptr_type = NILFS_BMAP_PTR_VM; |
| 609 | bmap->b_last_allocated_key = 0; | 614 | bmap->b_last_allocated_key = 0; |
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 7d49813f66d..aec942cf79e 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c | |||
| @@ -307,7 +307,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, | |||
| 307 | ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); | 307 | ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); |
| 308 | if (ret < 0) { | 308 | if (ret < 0) { |
| 309 | if (ret != -ENOENT) | 309 | if (ret != -ENOENT) |
| 310 | goto out_header; | 310 | break; |
| 311 | /* skip hole */ | 311 | /* skip hole */ |
| 312 | ret = 0; | 312 | ret = 0; |
| 313 | continue; | 313 | continue; |
| @@ -340,7 +340,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, | |||
| 340 | continue; | 340 | continue; |
| 341 | printk(KERN_ERR "%s: cannot delete block\n", | 341 | printk(KERN_ERR "%s: cannot delete block\n", |
| 342 | __func__); | 342 | __func__); |
| 343 | goto out_header; | 343 | break; |
| 344 | } | 344 | } |
| 345 | } | 345 | } |
| 346 | 346 | ||
| @@ -358,7 +358,6 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, | |||
| 358 | kunmap_atomic(kaddr, KM_USER0); | 358 | kunmap_atomic(kaddr, KM_USER0); |
| 359 | } | 359 | } |
| 360 | 360 | ||
| 361 | out_header: | ||
| 362 | brelse(header_bh); | 361 | brelse(header_bh); |
| 363 | 362 | ||
| 364 | out_sem: | 363 | out_sem: |
diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index 0b2710e2d56..8927ca27e6f 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c | |||
| @@ -134,15 +134,6 @@ void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req, | |||
| 134 | entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, | 134 | entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, |
| 135 | req->pr_entry_bh, kaddr); | 135 | req->pr_entry_bh, kaddr); |
| 136 | entry->de_start = cpu_to_le64(nilfs_mdt_cno(dat)); | 136 | entry->de_start = cpu_to_le64(nilfs_mdt_cno(dat)); |
| 137 | if (entry->de_blocknr != cpu_to_le64(0) || | ||
| 138 | entry->de_end != cpu_to_le64(NILFS_CNO_MAX)) { | ||
| 139 | printk(KERN_CRIT | ||
| 140 | "%s: vbn = %llu, start = %llu, end = %llu, pbn = %llu\n", | ||
| 141 | __func__, (unsigned long long)req->pr_entry_nr, | ||
| 142 | (unsigned long long)le64_to_cpu(entry->de_start), | ||
| 143 | (unsigned long long)le64_to_cpu(entry->de_end), | ||
| 144 | (unsigned long long)le64_to_cpu(entry->de_blocknr)); | ||
| 145 | } | ||
| 146 | entry->de_blocknr = cpu_to_le64(blocknr); | 137 | entry->de_blocknr = cpu_to_le64(blocknr); |
| 147 | kunmap_atomic(kaddr, KM_USER0); | 138 | kunmap_atomic(kaddr, KM_USER0); |
| 148 | 139 | ||
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index aa977549919..8b5e4778cf2 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c | |||
| @@ -1829,26 +1829,13 @@ static int nilfs_segctor_write(struct nilfs_sc_info *sci, | |||
| 1829 | err = nilfs_segbuf_write(segbuf, &wi); | 1829 | err = nilfs_segbuf_write(segbuf, &wi); |
| 1830 | 1830 | ||
| 1831 | res = nilfs_segbuf_wait(segbuf, &wi); | 1831 | res = nilfs_segbuf_wait(segbuf, &wi); |
| 1832 | err = unlikely(err) ? : res; | 1832 | err = err ? : res; |
| 1833 | if (unlikely(err)) | 1833 | if (err) |
| 1834 | return err; | 1834 | return err; |
| 1835 | } | 1835 | } |
| 1836 | return 0; | 1836 | return 0; |
| 1837 | } | 1837 | } |
| 1838 | 1838 | ||
| 1839 | static int nilfs_page_has_uncleared_buffer(struct page *page) | ||
| 1840 | { | ||
| 1841 | struct buffer_head *head, *bh; | ||
| 1842 | |||
| 1843 | head = bh = page_buffers(page); | ||
| 1844 | do { | ||
| 1845 | if (buffer_dirty(bh) && !list_empty(&bh->b_assoc_buffers)) | ||
| 1846 | return 1; | ||
| 1847 | bh = bh->b_this_page; | ||
| 1848 | } while (bh != head); | ||
| 1849 | return 0; | ||
| 1850 | } | ||
| 1851 | |||
| 1852 | static void __nilfs_end_page_io(struct page *page, int err) | 1839 | static void __nilfs_end_page_io(struct page *page, int err) |
| 1853 | { | 1840 | { |
| 1854 | if (!err) { | 1841 | if (!err) { |
| @@ -1872,12 +1859,11 @@ static void nilfs_end_page_io(struct page *page, int err) | |||
| 1872 | if (!page) | 1859 | if (!page) |
| 1873 | return; | 1860 | return; |
| 1874 | 1861 | ||
| 1875 | if (buffer_nilfs_node(page_buffers(page)) && | 1862 | if (buffer_nilfs_node(page_buffers(page)) && !PageWriteback(page)) |
| 1876 | nilfs_page_has_uncleared_buffer(page)) | 1863 | /* |
| 1877 | /* For b-tree node pages, this function may be called twice | 1864 | * For b-tree node pages, this function may be called twice |
| 1878 | or more because they might be split in a segment. | 1865 | * or more because they might be split in a segment. |
| 1879 | This check assures that cleanup has been done for all | 1866 | */ |
| 1880 | buffers in a split btnode page. */ | ||
| 1881 | return; | 1867 | return; |
| 1882 | 1868 | ||
| 1883 | __nilfs_end_page_io(page, err); | 1869 | __nilfs_end_page_io(page, err); |
| @@ -1940,7 +1926,7 @@ static void nilfs_segctor_abort_write(struct nilfs_sc_info *sci, | |||
| 1940 | } | 1926 | } |
| 1941 | if (bh->b_page != fs_page) { | 1927 | if (bh->b_page != fs_page) { |
| 1942 | nilfs_end_page_io(fs_page, err); | 1928 | nilfs_end_page_io(fs_page, err); |
| 1943 | if (unlikely(fs_page == failed_page)) | 1929 | if (fs_page && fs_page == failed_page) |
| 1944 | goto done; | 1930 | goto done; |
| 1945 | fs_page = bh->b_page; | 1931 | fs_page = bh->b_page; |
| 1946 | } | 1932 | } |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index ff231ad2389..ff27a296584 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/quota/dquot.c b/fs/quota/dquot.c index 607c579e5ec..70f36c043d6 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
| @@ -2042,8 +2042,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, | |||
| 2042 | * changes */ | 2042 | * changes */ |
| 2043 | invalidate_bdev(sb->s_bdev); | 2043 | invalidate_bdev(sb->s_bdev); |
| 2044 | } | 2044 | } |
| 2045 | mutex_lock(&inode->i_mutex); | ||
| 2046 | mutex_lock(&dqopt->dqonoff_mutex); | 2045 | mutex_lock(&dqopt->dqonoff_mutex); |
| 2046 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); | ||
| 2047 | if (sb_has_quota_loaded(sb, type)) { | 2047 | if (sb_has_quota_loaded(sb, type)) { |
| 2048 | error = -EBUSY; | 2048 | error = -EBUSY; |
| 2049 | goto out_lock; | 2049 | goto out_lock; |
| @@ -2094,7 +2094,6 @@ out_file_init: | |||
| 2094 | dqopt->files[type] = NULL; | 2094 | dqopt->files[type] = NULL; |
| 2095 | iput(inode); | 2095 | iput(inode); |
| 2096 | out_lock: | 2096 | out_lock: |
| 2097 | mutex_unlock(&dqopt->dqonoff_mutex); | ||
| 2098 | if (oldflags != -1) { | 2097 | if (oldflags != -1) { |
| 2099 | down_write(&dqopt->dqptr_sem); | 2098 | down_write(&dqopt->dqptr_sem); |
| 2100 | /* Set the flags back (in the case of accidental quotaon() | 2099 | /* Set the flags back (in the case of accidental quotaon() |
| @@ -2104,6 +2103,7 @@ out_lock: | |||
| 2104 | up_write(&dqopt->dqptr_sem); | 2103 | up_write(&dqopt->dqptr_sem); |
| 2105 | } | 2104 | } |
| 2106 | mutex_unlock(&inode->i_mutex); | 2105 | mutex_unlock(&inode->i_mutex); |
| 2106 | mutex_unlock(&dqopt->dqonoff_mutex); | ||
| 2107 | out_fmt: | 2107 | out_fmt: |
| 2108 | put_quota_format(fmt); | 2108 | put_quota_format(fmt); |
| 2109 | 2109 | ||
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 77f5bb746bf..90622200b39 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c | |||
| @@ -997,7 +997,7 @@ static int reiserfs_async_progress_wait(struct super_block *s) | |||
| 997 | DEFINE_WAIT(wait); | 997 | DEFINE_WAIT(wait); |
| 998 | struct reiserfs_journal *j = SB_JOURNAL(s); | 998 | struct reiserfs_journal *j = SB_JOURNAL(s); |
| 999 | if (atomic_read(&j->j_async_throttle)) | 999 | if (atomic_read(&j->j_async_throttle)) |
| 1000 | congestion_wait(WRITE, HZ / 10); | 1000 | congestion_wait(BLK_RW_ASYNC, HZ / 10); |
| 1001 | return 0; | 1001 | return 0; |
| 1002 | } | 1002 | } |
| 1003 | 1003 | ||
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index d3aeb061612..7adea74d6a8 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include <linux/exportfs.h> | 24 | #include <linux/exportfs.h> |
| 25 | #include <linux/quotaops.h> | 25 | #include <linux/quotaops.h> |
| 26 | #include <linux/vfs.h> | 26 | #include <linux/vfs.h> |
| 27 | #include <linux/mnt_namespace.h> | ||
| 28 | #include <linux/mount.h> | 27 | #include <linux/mount.h> |
| 29 | #include <linux/namei.h> | 28 | #include <linux/namei.h> |
| 30 | #include <linux/crc32.h> | 29 | #include <linux/crc32.h> |
| @@ -112,8 +112,13 @@ restart: | |||
| 112 | mutex_unlock(&mutex); | 112 | mutex_unlock(&mutex); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | /* | ||
| 116 | * sync everything. Start out by waking pdflush, because that writes back | ||
| 117 | * all queues in parallel. | ||
| 118 | */ | ||
| 115 | SYSCALL_DEFINE0(sync) | 119 | SYSCALL_DEFINE0(sync) |
| 116 | { | 120 | { |
| 121 | wakeup_pdflush(0); | ||
| 117 | sync_filesystems(0); | 122 | sync_filesystems(0); |
| 118 | sync_filesystems(1); | 123 | sync_filesystems(1); |
| 119 | if (unlikely(laptop_mode)) | 124 | if (unlikely(laptop_mode)) |
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 9345806c885..2524714bece 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c | |||
| @@ -171,6 +171,7 @@ static ssize_t write(struct file *file, const char __user *userbuf, | |||
| 171 | if (count > 0) | 171 | if (count > 0) |
| 172 | *off = offs + count; | 172 | *off = offs + count; |
| 173 | 173 | ||
| 174 | kfree(temp); | ||
| 174 | return count; | 175 | return count; |
| 175 | } | 176 | } |
| 176 | 177 | ||
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index bc5857199ec..762a7d6cec7 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c | |||
| @@ -297,6 +297,7 @@ static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer) | |||
| 297 | { | 297 | { |
| 298 | struct ubifs_wbuf *wbuf = container_of(timer, struct ubifs_wbuf, timer); | 298 | struct ubifs_wbuf *wbuf = container_of(timer, struct ubifs_wbuf, timer); |
| 299 | 299 | ||
| 300 | dbg_io("jhead %d", wbuf->jhead); | ||
| 300 | wbuf->need_sync = 1; | 301 | wbuf->need_sync = 1; |
| 301 | wbuf->c->need_wbuf_sync = 1; | 302 | wbuf->c->need_wbuf_sync = 1; |
| 302 | ubifs_wake_up_bgt(wbuf->c); | 303 | ubifs_wake_up_bgt(wbuf->c); |
| @@ -311,8 +312,12 @@ static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) | |||
| 311 | { | 312 | { |
| 312 | ubifs_assert(!hrtimer_active(&wbuf->timer)); | 313 | ubifs_assert(!hrtimer_active(&wbuf->timer)); |
| 313 | 314 | ||
| 314 | if (!ktime_to_ns(wbuf->softlimit)) | 315 | if (wbuf->no_timer) |
| 315 | return; | 316 | return; |
| 317 | dbg_io("set timer for jhead %d, %llu-%llu millisecs", wbuf->jhead, | ||
| 318 | div_u64(ktime_to_ns(wbuf->softlimit), USEC_PER_SEC), | ||
| 319 | div_u64(ktime_to_ns(wbuf->softlimit) + wbuf->delta, | ||
| 320 | USEC_PER_SEC)); | ||
| 316 | hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta, | 321 | hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta, |
| 317 | HRTIMER_MODE_REL); | 322 | HRTIMER_MODE_REL); |
| 318 | } | 323 | } |
| @@ -323,11 +328,8 @@ static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) | |||
| 323 | */ | 328 | */ |
| 324 | static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) | 329 | static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) |
| 325 | { | 330 | { |
| 326 | /* | 331 | if (wbuf->no_timer) |
| 327 | * If the syncer is waiting for the lock (from the background thread's | 332 | return; |
| 328 | * context) and another task is changing write-buffer then the syncing | ||
| 329 | * should be canceled. | ||
| 330 | */ | ||
| 331 | wbuf->need_sync = 0; | 333 | wbuf->need_sync = 0; |
| 332 | hrtimer_cancel(&wbuf->timer); | 334 | hrtimer_cancel(&wbuf->timer); |
| 333 | } | 335 | } |
| @@ -349,8 +351,8 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf) | |||
| 349 | /* Write-buffer is empty or not seeked */ | 351 | /* Write-buffer is empty or not seeked */ |
| 350 | return 0; | 352 | return 0; |
| 351 | 353 | ||
| 352 | dbg_io("LEB %d:%d, %d bytes", | 354 | dbg_io("LEB %d:%d, %d bytes, jhead %d", |
| 353 | wbuf->lnum, wbuf->offs, wbuf->used); | 355 | wbuf->lnum, wbuf->offs, wbuf->used, wbuf->jhead); |
| 354 | ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY)); | 356 | ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY)); |
| 355 | ubifs_assert(!(wbuf->avail & 7)); | 357 | ubifs_assert(!(wbuf->avail & 7)); |
| 356 | ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size); | 358 | ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size); |
| @@ -390,7 +392,7 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf) | |||
| 390 | * @offs: logical eraseblock offset to seek to | 392 | * @offs: logical eraseblock offset to seek to |
| 391 | * @dtype: data type | 393 | * @dtype: data type |
| 392 | * | 394 | * |
| 393 | * This function targets the write buffer to logical eraseblock @lnum:@offs. | 395 | * This function targets the write-buffer to logical eraseblock @lnum:@offs. |
| 394 | * The write-buffer is synchronized if it is not empty. Returns zero in case of | 396 | * The write-buffer is synchronized if it is not empty. Returns zero in case of |
| 395 | * success and a negative error code in case of failure. | 397 | * success and a negative error code in case of failure. |
| 396 | */ | 398 | */ |
| @@ -399,7 +401,7 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs, | |||
| 399 | { | 401 | { |
| 400 | const struct ubifs_info *c = wbuf->c; | 402 | const struct ubifs_info *c = wbuf->c; |
| 401 | 403 | ||
| 402 | dbg_io("LEB %d:%d", lnum, offs); | 404 | dbg_io("LEB %d:%d, jhead %d", lnum, offs, wbuf->jhead); |
| 403 | ubifs_assert(lnum >= 0 && lnum < c->leb_cnt); | 405 | ubifs_assert(lnum >= 0 && lnum < c->leb_cnt); |
| 404 | ubifs_assert(offs >= 0 && offs <= c->leb_size); | 406 | ubifs_assert(offs >= 0 && offs <= c->leb_size); |
| 405 | ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7)); | 407 | ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7)); |
| @@ -506,9 +508,9 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) | |||
| 506 | struct ubifs_info *c = wbuf->c; | 508 | struct ubifs_info *c = wbuf->c; |
| 507 | int err, written, n, aligned_len = ALIGN(len, 8), offs; | 509 | int err, written, n, aligned_len = ALIGN(len, 8), offs; |
| 508 | 510 | ||
| 509 | dbg_io("%d bytes (%s) to wbuf at LEB %d:%d", len, | 511 | dbg_io("%d bytes (%s) to jhead %d wbuf at LEB %d:%d", len, |
| 510 | dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->lnum, | 512 | dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->jhead, |
| 511 | wbuf->offs + wbuf->used); | 513 | wbuf->lnum, wbuf->offs + wbuf->used); |
| 512 | ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt); | 514 | ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt); |
| 513 | ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0); | 515 | ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0); |
| 514 | ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size); | 516 | ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size); |
| @@ -533,8 +535,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) | |||
| 533 | memcpy(wbuf->buf + wbuf->used, buf, len); | 535 | memcpy(wbuf->buf + wbuf->used, buf, len); |
| 534 | 536 | ||
| 535 | if (aligned_len == wbuf->avail) { | 537 | if (aligned_len == wbuf->avail) { |
| 536 | dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum, | 538 | dbg_io("flush jhead %d wbuf to LEB %d:%d", |
| 537 | wbuf->offs); | 539 | wbuf->jhead, wbuf->lnum, wbuf->offs); |
| 538 | err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, | 540 | err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, |
| 539 | wbuf->offs, c->min_io_size, | 541 | wbuf->offs, c->min_io_size, |
| 540 | wbuf->dtype); | 542 | wbuf->dtype); |
| @@ -562,7 +564,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) | |||
| 562 | * minimal I/O unit. We have to fill and flush write-buffer and switch | 564 | * minimal I/O unit. We have to fill and flush write-buffer and switch |
| 563 | * to the next min. I/O unit. | 565 | * to the next min. I/O unit. |
| 564 | */ | 566 | */ |
| 565 | dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum, wbuf->offs); | 567 | dbg_io("flush jhead %d wbuf to LEB %d:%d", |
| 568 | wbuf->jhead, wbuf->lnum, wbuf->offs); | ||
| 566 | memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail); | 569 | memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail); |
| 567 | err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, | 570 | err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, |
| 568 | c->min_io_size, wbuf->dtype); | 571 | c->min_io_size, wbuf->dtype); |
| @@ -695,7 +698,8 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len, | |||
| 695 | int err, rlen, overlap; | 698 | int err, rlen, overlap; |
| 696 | struct ubifs_ch *ch = buf; | 699 | struct ubifs_ch *ch = buf; |
| 697 | 700 | ||
| 698 | dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len); | 701 | dbg_io("LEB %d:%d, %s, length %d, jhead %d", lnum, offs, |
| 702 | dbg_ntype(type), len, wbuf->jhead); | ||
| 699 | ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0); | 703 | ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0); |
| 700 | ubifs_assert(!(offs & 7) && offs < c->leb_size); | 704 | ubifs_assert(!(offs & 7) && offs < c->leb_size); |
| 701 | ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT); | 705 | ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT); |
| @@ -819,13 +823,12 @@ out: | |||
| 819 | * @c: UBIFS file-system description object | 823 | * @c: UBIFS file-system description object |
| 820 | * @wbuf: write-buffer to initialize | 824 | * @wbuf: write-buffer to initialize |
| 821 | * | 825 | * |
| 822 | * This function initializes write buffer. Returns zero in case of success | 826 | * This function initializes write-buffer. Returns zero in case of success |
| 823 | * %-ENOMEM in case of failure. | 827 | * %-ENOMEM in case of failure. |
| 824 | */ | 828 | */ |
| 825 | int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf) | 829 | int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf) |
| 826 | { | 830 | { |
| 827 | size_t size; | 831 | size_t size; |
| 828 | ktime_t hardlimit; | ||
| 829 | 832 | ||
| 830 | wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL); | 833 | wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL); |
| 831 | if (!wbuf->buf) | 834 | if (!wbuf->buf) |
| @@ -851,22 +854,16 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf) | |||
| 851 | 854 | ||
| 852 | hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | 855 | hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| 853 | wbuf->timer.function = wbuf_timer_callback_nolock; | 856 | wbuf->timer.function = wbuf_timer_callback_nolock; |
| 854 | /* | 857 | wbuf->softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0); |
| 855 | * Make write-buffer soft limit to be 20% of the hard limit. The | 858 | wbuf->delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT; |
| 856 | * write-buffer timer is allowed to expire any time between the soft | 859 | wbuf->delta *= 1000000000ULL; |
| 857 | * and hard limits. | 860 | ubifs_assert(wbuf->delta <= ULONG_MAX); |
| 858 | */ | ||
| 859 | hardlimit = ktime_set(DEFAULT_WBUF_TIMEOUT_SECS, 0); | ||
| 860 | wbuf->delta = (DEFAULT_WBUF_TIMEOUT_SECS * NSEC_PER_SEC) * 2 / 10; | ||
| 861 | wbuf->softlimit = ktime_sub_ns(hardlimit, wbuf->delta); | ||
| 862 | hrtimer_set_expires_range_ns(&wbuf->timer, wbuf->softlimit, | ||
| 863 | wbuf->delta); | ||
| 864 | return 0; | 861 | return 0; |
| 865 | } | 862 | } |
| 866 | 863 | ||
| 867 | /** | 864 | /** |
| 868 | * ubifs_wbuf_add_ino_nolock - add an inode number into the wbuf inode array. | 865 | * ubifs_wbuf_add_ino_nolock - add an inode number into the wbuf inode array. |
| 869 | * @wbuf: the write-buffer whereto add | 866 | * @wbuf: the write-buffer where to add |
| 870 | * @inum: the inode number | 867 | * @inum: the inode number |
| 871 | * | 868 | * |
| 872 | * This function adds an inode number to the inode array of the write-buffer. | 869 | * This function adds an inode number to the inode array of the write-buffer. |
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index 805605250f1..e5f6cf8a115 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c | |||
| @@ -53,6 +53,25 @@ static int is_empty(void *buf, int len) | |||
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | /** | 55 | /** |
| 56 | * first_non_ff - find offset of the first non-0xff byte. | ||
| 57 | * @buf: buffer to search in | ||
| 58 | * @len: length of buffer | ||
| 59 | * | ||
| 60 | * This function returns offset of the first non-0xff byte in @buf or %-1 if | ||
| 61 | * the buffer contains only 0xff bytes. | ||
| 62 | */ | ||
| 63 | static int first_non_ff(void *buf, int len) | ||
| 64 | { | ||
| 65 | uint8_t *p = buf; | ||
| 66 | int i; | ||
| 67 | |||
| 68 | for (i = 0; i < len; i++) | ||
| 69 | if (*p++ != 0xff) | ||
| 70 | return i; | ||
| 71 | return -1; | ||
| 72 | } | ||
| 73 | |||
| 74 | /** | ||
| 56 | * get_master_node - get the last valid master node allowing for corruption. | 75 | * get_master_node - get the last valid master node allowing for corruption. |
| 57 | * @c: UBIFS file-system description object | 76 | * @c: UBIFS file-system description object |
| 58 | * @lnum: LEB number | 77 | * @lnum: LEB number |
| @@ -357,11 +376,7 @@ static int is_last_write(const struct ubifs_info *c, void *buf, int offs) | |||
| 357 | empty_offs = ALIGN(offs + 1, c->min_io_size); | 376 | empty_offs = ALIGN(offs + 1, c->min_io_size); |
| 358 | check_len = c->leb_size - empty_offs; | 377 | check_len = c->leb_size - empty_offs; |
| 359 | p = buf + empty_offs - offs; | 378 | p = buf + empty_offs - offs; |
| 360 | 379 | return is_empty(p, check_len); | |
| 361 | for (; check_len > 0; check_len--) | ||
| 362 | if (*p++ != 0xff) | ||
| 363 | return 0; | ||
| 364 | return 1; | ||
| 365 | } | 380 | } |
| 366 | 381 | ||
| 367 | /** | 382 | /** |
| @@ -543,8 +558,8 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs) | |||
| 543 | * | 558 | * |
| 544 | * This function does a scan of a LEB, but caters for errors that might have | 559 | * This function does a scan of a LEB, but caters for errors that might have |
| 545 | * been caused by the unclean unmount from which we are attempting to recover. | 560 | * been caused by the unclean unmount from which we are attempting to recover. |
| 546 | * | 561 | * Returns %0 in case of success, %-EUCLEAN if an unrecoverable corruption is |
| 547 | * This function returns %0 on success and a negative error code on failure. | 562 | * found, and a negative error code in case of failure. |
| 548 | */ | 563 | */ |
| 549 | struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, | 564 | struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, |
| 550 | int offs, void *sbuf, int grouped) | 565 | int offs, void *sbuf, int grouped) |
| @@ -643,7 +658,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, | |||
| 643 | goto corrupted; | 658 | goto corrupted; |
| 644 | default: | 659 | default: |
| 645 | dbg_err("unknown"); | 660 | dbg_err("unknown"); |
| 646 | goto corrupted; | 661 | err = -EINVAL; |
| 662 | goto error; | ||
| 647 | } | 663 | } |
| 648 | } | 664 | } |
| 649 | 665 | ||
| @@ -652,8 +668,13 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, | |||
| 652 | clean_buf(c, &buf, lnum, &offs, &len); | 668 | clean_buf(c, &buf, lnum, &offs, &len); |
| 653 | need_clean = 1; | 669 | need_clean = 1; |
| 654 | } else { | 670 | } else { |
| 655 | ubifs_err("corrupt empty space at LEB %d:%d", | 671 | int corruption = first_non_ff(buf, len); |
| 656 | lnum, offs); | 672 | |
| 673 | ubifs_err("corrupt empty space LEB %d:%d, corruption " | ||
| 674 | "starts at %d", lnum, offs, corruption); | ||
| 675 | /* Make sure we dump interesting non-0xFF data */ | ||
| 676 | offs = corruption; | ||
| 677 | buf += corruption; | ||
| 657 | goto corrupted; | 678 | goto corrupted; |
| 658 | } | 679 | } |
| 659 | } | 680 | } |
| @@ -813,7 +834,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum, | |||
| 813 | static int recover_head(const struct ubifs_info *c, int lnum, int offs, | 834 | static int recover_head(const struct ubifs_info *c, int lnum, int offs, |
| 814 | void *sbuf) | 835 | void *sbuf) |
| 815 | { | 836 | { |
| 816 | int len, err, need_clean = 0; | 837 | int len, err; |
| 817 | 838 | ||
| 818 | if (c->min_io_size > 1) | 839 | if (c->min_io_size > 1) |
| 819 | len = c->min_io_size; | 840 | len = c->min_io_size; |
| @@ -827,19 +848,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs, | |||
| 827 | 848 | ||
| 828 | /* Read at the head location and check it is empty flash */ | 849 | /* Read at the head location and check it is empty flash */ |
| 829 | err = ubi_read(c->ubi, lnum, sbuf, offs, len); | 850 | err = ubi_read(c->ubi, lnum, sbuf, offs, len); |
| 830 | if (err) | 851 | if (err || !is_empty(sbuf, len)) { |
| 831 | need_clean = 1; | ||
| 832 | else { | ||
| 833 | uint8_t *p = sbuf; | ||
| 834 | |||
| 835 | while (len--) | ||
| 836 | if (*p++ != 0xff) { | ||
| 837 | need_clean = 1; | ||
| 838 | break; | ||
| 839 | } | ||
| 840 | } | ||
| 841 | |||
| 842 | if (need_clean) { | ||
| 843 | dbg_rcvry("cleaning head at %d:%d", lnum, offs); | 852 | dbg_rcvry("cleaning head at %d:%d", lnum, offs); |
| 844 | if (offs == 0) | 853 | if (offs == 0) |
| 845 | return ubifs_leb_unmap(c, lnum); | 854 | return ubifs_leb_unmap(c, lnum); |
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c index 11cc80125a4..2970500f32d 100644 --- a/fs/ubifs/replay.c +++ b/fs/ubifs/replay.c | |||
| @@ -837,9 +837,10 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf) | |||
| 837 | 837 | ||
| 838 | dbg_mnt("replay log LEB %d:%d", lnum, offs); | 838 | dbg_mnt("replay log LEB %d:%d", lnum, offs); |
| 839 | sleb = ubifs_scan(c, lnum, offs, sbuf); | 839 | sleb = ubifs_scan(c, lnum, offs, sbuf); |
| 840 | if (IS_ERR(sleb)) { | 840 | if (IS_ERR(sleb) ) { |
| 841 | if (c->need_recovery) | 841 | if (PTR_ERR(sleb) != -EUCLEAN || !c->need_recovery) |
| 842 | sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf); | 842 | return PTR_ERR(sleb); |
| 843 | sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf); | ||
| 843 | if (IS_ERR(sleb)) | 844 | if (IS_ERR(sleb)) |
| 844 | return PTR_ERR(sleb); | 845 | return PTR_ERR(sleb); |
| 845 | } | 846 | } |
| @@ -957,7 +958,7 @@ out: | |||
| 957 | return err; | 958 | return err; |
| 958 | 959 | ||
| 959 | out_dump: | 960 | out_dump: |
| 960 | ubifs_err("log error detected while replying the log at LEB %d:%d", | 961 | ubifs_err("log error detected while replaying the log at LEB %d:%d", |
| 961 | lnum, offs + snod->offs); | 962 | lnum, offs + snod->offs); |
| 962 | dbg_dump_node(c, snod->node); | 963 | dbg_dump_node(c, snod->node); |
| 963 | ubifs_scan_destroy(sleb); | 964 | ubifs_scan_destroy(sleb); |
diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c index 0ed82479b44..892ebfee4fe 100644 --- a/fs/ubifs/scan.c +++ b/fs/ubifs/scan.c | |||
| @@ -238,12 +238,12 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs, | |||
| 238 | { | 238 | { |
| 239 | int len; | 239 | int len; |
| 240 | 240 | ||
| 241 | ubifs_err("corrupted data at LEB %d:%d", lnum, offs); | 241 | ubifs_err("corruption at LEB %d:%d", lnum, offs); |
| 242 | if (dbg_failure_mode) | 242 | if (dbg_failure_mode) |
| 243 | return; | 243 | return; |
| 244 | len = c->leb_size - offs; | 244 | len = c->leb_size - offs; |
| 245 | if (len > 4096) | 245 | if (len > 8192) |
| 246 | len = 4096; | 246 | len = 8192; |
| 247 | dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs); | 247 | dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs); |
| 248 | print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1); | 248 | print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1); |
| 249 | } | 249 | } |
| @@ -256,7 +256,9 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs, | |||
| 256 | * @sbuf: scan buffer (must be c->leb_size) | 256 | * @sbuf: scan buffer (must be c->leb_size) |
| 257 | * | 257 | * |
| 258 | * This function scans LEB number @lnum and returns complete information about | 258 | * This function scans LEB number @lnum and returns complete information about |
| 259 | * its contents. Returns an error code in case of failure. | 259 | * its contents. Returns the scaned information in case of success and, |
| 260 | * %-EUCLEAN if the LEB neads recovery, and other negative error codes in case | ||
| 261 | * of failure. | ||
| 260 | */ | 262 | */ |
| 261 | struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, | 263 | struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, |
| 262 | int offs, void *sbuf) | 264 | int offs, void *sbuf) |
| @@ -279,7 +281,6 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, | |||
| 279 | cond_resched(); | 281 | cond_resched(); |
| 280 | 282 | ||
| 281 | ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0); | 283 | ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0); |
| 282 | |||
| 283 | if (ret > 0) { | 284 | if (ret > 0) { |
| 284 | /* Padding bytes or a valid padding node */ | 285 | /* Padding bytes or a valid padding node */ |
| 285 | offs += ret; | 286 | offs += ret; |
| @@ -304,7 +305,8 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, | |||
| 304 | goto corrupted; | 305 | goto corrupted; |
| 305 | default: | 306 | default: |
| 306 | dbg_err("unknown"); | 307 | dbg_err("unknown"); |
| 307 | goto corrupted; | 308 | err = -EINVAL; |
| 309 | goto error; | ||
| 308 | } | 310 | } |
| 309 | 311 | ||
| 310 | err = ubifs_add_snod(c, sleb, buf, offs); | 312 | err = ubifs_add_snod(c, sleb, buf, offs); |
| @@ -317,8 +319,10 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, | |||
| 317 | len -= node_len; | 319 | len -= node_len; |
| 318 | } | 320 | } |
| 319 | 321 | ||
| 320 | if (offs % c->min_io_size) | 322 | if (offs % c->min_io_size) { |
| 321 | goto corrupted; | 323 | ubifs_err("empty space starts at non-aligned offset %d", offs); |
| 324 | goto corrupted;; | ||
| 325 | } | ||
| 322 | 326 | ||
| 323 | ubifs_end_scan(c, sleb, lnum, offs); | 327 | ubifs_end_scan(c, sleb, lnum, offs); |
| 324 | 328 | ||
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 79fad43f3c5..26d2e0d8046 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
| @@ -797,7 +797,7 @@ static int alloc_wbufs(struct ubifs_info *c) | |||
| 797 | * does not need to be synchronized by timer. | 797 | * does not need to be synchronized by timer. |
| 798 | */ | 798 | */ |
| 799 | c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM; | 799 | c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM; |
| 800 | c->jheads[GCHD].wbuf.softlimit = ktime_set(0, 0); | 800 | c->jheads[GCHD].wbuf.no_timer = 1; |
| 801 | 801 | ||
| 802 | return 0; | 802 | return 0; |
| 803 | } | 803 | } |
| @@ -986,7 +986,7 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options, | |||
| 986 | switch (token) { | 986 | switch (token) { |
| 987 | /* | 987 | /* |
| 988 | * %Opt_fast_unmount and %Opt_norm_unmount options are ignored. | 988 | * %Opt_fast_unmount and %Opt_norm_unmount options are ignored. |
| 989 | * We accepte them in order to be backware-compatible. But this | 989 | * We accept them in order to be backward-compatible. But this |
| 990 | * should be removed at some point. | 990 | * should be removed at some point. |
| 991 | */ | 991 | */ |
| 992 | case Opt_fast_unmount: | 992 | case Opt_fast_unmount: |
| @@ -1287,6 +1287,9 @@ static int mount_ubifs(struct ubifs_info *c) | |||
| 1287 | if (err) | 1287 | if (err) |
| 1288 | goto out_journal; | 1288 | goto out_journal; |
| 1289 | 1289 | ||
| 1290 | /* Calculate 'min_idx_lebs' after journal replay */ | ||
| 1291 | c->min_idx_lebs = ubifs_calc_min_idx_lebs(c); | ||
| 1292 | |||
| 1290 | err = ubifs_mount_orphans(c, c->need_recovery, mounted_read_only); | 1293 | err = ubifs_mount_orphans(c, c->need_recovery, mounted_read_only); |
| 1291 | if (err) | 1294 | if (err) |
| 1292 | goto out_orphans; | 1295 | goto out_orphans; |
| @@ -1754,10 +1757,8 @@ static void ubifs_put_super(struct super_block *sb) | |||
| 1754 | 1757 | ||
| 1755 | /* Synchronize write-buffers */ | 1758 | /* Synchronize write-buffers */ |
| 1756 | if (c->jheads) | 1759 | if (c->jheads) |
| 1757 | for (i = 0; i < c->jhead_cnt; i++) { | 1760 | for (i = 0; i < c->jhead_cnt; i++) |
| 1758 | ubifs_wbuf_sync(&c->jheads[i].wbuf); | 1761 | ubifs_wbuf_sync(&c->jheads[i].wbuf); |
| 1759 | hrtimer_cancel(&c->jheads[i].wbuf.timer); | ||
| 1760 | } | ||
| 1761 | 1762 | ||
| 1762 | /* | 1763 | /* |
| 1763 | * On fatal errors c->ro_media is set to 1, in which case we do | 1764 | * On fatal errors c->ro_media is set to 1, in which case we do |
| @@ -1975,7 +1976,8 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1975 | err = bdi_init(&c->bdi); | 1976 | err = bdi_init(&c->bdi); |
| 1976 | if (err) | 1977 | if (err) |
| 1977 | goto out_close; | 1978 | goto out_close; |
| 1978 | err = bdi_register(&c->bdi, NULL, "ubifs"); | 1979 | err = bdi_register(&c->bdi, NULL, "ubifs_%d_%d", |
| 1980 | c->vi.ubi_num, c->vi.vol_id); | ||
| 1979 | if (err) | 1981 | if (err) |
| 1980 | goto out_bdi; | 1982 | goto out_bdi; |
| 1981 | 1983 | ||
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 1bf01d82006..a2934909442 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
| @@ -95,8 +95,9 @@ | |||
| 95 | */ | 95 | */ |
| 96 | #define BGT_NAME_PATTERN "ubifs_bgt%d_%d" | 96 | #define BGT_NAME_PATTERN "ubifs_bgt%d_%d" |
| 97 | 97 | ||
| 98 | /* Default write-buffer synchronization timeout in seconds */ | 98 | /* Write-buffer synchronization timeout interval in seconds */ |
| 99 | #define DEFAULT_WBUF_TIMEOUT_SECS 5 | 99 | #define WBUF_TIMEOUT_SOFTLIMIT 3 |
| 100 | #define WBUF_TIMEOUT_HARDLIMIT 5 | ||
| 100 | 101 | ||
| 101 | /* Maximum possible inode number (only 32-bit inodes are supported now) */ | 102 | /* Maximum possible inode number (only 32-bit inodes are supported now) */ |
| 102 | #define MAX_INUM 0xFFFFFFFF | 103 | #define MAX_INUM 0xFFFFFFFF |
| @@ -654,7 +655,8 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c, | |||
| 654 | * @delta: hard and soft timeouts delta (the timer expire inteval is @softlimit | 655 | * @delta: hard and soft timeouts delta (the timer expire inteval is @softlimit |
| 655 | * and @softlimit + @delta) | 656 | * and @softlimit + @delta) |
| 656 | * @timer: write-buffer timer | 657 | * @timer: write-buffer timer |
| 657 | * @need_sync: it is set if its timer expired and needs sync | 658 | * @no_timer: non-zero if this write-buffer does not have a timer |
| 659 | * @need_sync: non-zero if the timer expired and the wbuf needs sync'ing | ||
| 658 | * @next_ino: points to the next position of the following inode number | 660 | * @next_ino: points to the next position of the following inode number |
| 659 | * @inodes: stores the inode numbers of the nodes which are in wbuf | 661 | * @inodes: stores the inode numbers of the nodes which are in wbuf |
| 660 | * | 662 | * |
| @@ -683,7 +685,8 @@ struct ubifs_wbuf { | |||
| 683 | ktime_t softlimit; | 685 | ktime_t softlimit; |
| 684 | unsigned long long delta; | 686 | unsigned long long delta; |
| 685 | struct hrtimer timer; | 687 | struct hrtimer timer; |
| 686 | int need_sync; | 688 | unsigned int no_timer:1; |
| 689 | unsigned int need_sync:1; | ||
| 687 | int next_ino; | 690 | int next_ino; |
| 688 | ino_t *inodes; | 691 | ino_t *inodes; |
| 689 | }; | 692 | }; |
diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c index 1cd3b55ee3d..2d3f90afe5f 100644 --- a/fs/xfs/linux-2.6/kmem.c +++ b/fs/xfs/linux-2.6/kmem.c | |||
| @@ -53,7 +53,7 @@ kmem_alloc(size_t size, unsigned int __nocast flags) | |||
| 53 | printk(KERN_ERR "XFS: possible memory allocation " | 53 | printk(KERN_ERR "XFS: possible memory allocation " |
| 54 | "deadlock in %s (mode:0x%x)\n", | 54 | "deadlock in %s (mode:0x%x)\n", |
| 55 | __func__, lflags); | 55 | __func__, lflags); |
| 56 | congestion_wait(WRITE, HZ/50); | 56 | congestion_wait(BLK_RW_ASYNC, HZ/50); |
| 57 | } while (1); | 57 | } while (1); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| @@ -130,7 +130,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags) | |||
| 130 | printk(KERN_ERR "XFS: possible memory allocation " | 130 | printk(KERN_ERR "XFS: possible memory allocation " |
| 131 | "deadlock in %s (mode:0x%x)\n", | 131 | "deadlock in %s (mode:0x%x)\n", |
| 132 | __func__, lflags); | 132 | __func__, lflags); |
| 133 | congestion_wait(WRITE, HZ/50); | 133 | congestion_wait(BLK_RW_ASYNC, HZ/50); |
| 134 | } while (1); | 134 | } while (1); |
| 135 | } | 135 | } |
| 136 | 136 | ||
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 1418b916fc2..0c93c7ef3d1 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
| @@ -412,7 +412,7 @@ _xfs_buf_lookup_pages( | |||
| 412 | 412 | ||
| 413 | XFS_STATS_INC(xb_page_retries); | 413 | XFS_STATS_INC(xb_page_retries); |
| 414 | xfsbufd_wakeup(0, gfp_mask); | 414 | xfsbufd_wakeup(0, gfp_mask); |
| 415 | congestion_wait(WRITE, HZ/50); | 415 | congestion_wait(BLK_RW_ASYNC, HZ/50); |
| 416 | goto retry; | 416 | goto retry; |
| 417 | } | 417 | } |
| 418 | 418 | ||
