diff options
Diffstat (limited to 'fs')
157 files changed, 4790 insertions, 2910 deletions
diff --git a/fs/9p/cache.c b/fs/9p/cache.c index 51c94e26a346..e777961939f3 100644 --- a/fs/9p/cache.c +++ b/fs/9p/cache.c | |||
@@ -343,18 +343,7 @@ int __v9fs_fscache_release_page(struct page *page, gfp_t gfp) | |||
343 | 343 | ||
344 | BUG_ON(!vcookie->fscache); | 344 | BUG_ON(!vcookie->fscache); |
345 | 345 | ||
346 | if (PageFsCache(page)) { | 346 | return fscache_maybe_release_page(vcookie->fscache, page, gfp); |
347 | if (fscache_check_page_write(vcookie->fscache, page)) { | ||
348 | if (!(gfp & __GFP_WAIT)) | ||
349 | return 0; | ||
350 | fscache_wait_on_page_write(vcookie->fscache, page); | ||
351 | } | ||
352 | |||
353 | fscache_uncache_page(vcookie->fscache, page); | ||
354 | ClearPageFsCache(page); | ||
355 | } | ||
356 | |||
357 | return 1; | ||
358 | } | 347 | } |
359 | 348 | ||
360 | void __v9fs_fscache_invalidate_page(struct page *page) | 349 | void __v9fs_fscache_invalidate_page(struct page *page) |
@@ -368,7 +357,6 @@ void __v9fs_fscache_invalidate_page(struct page *page) | |||
368 | fscache_wait_on_page_write(vcookie->fscache, page); | 357 | fscache_wait_on_page_write(vcookie->fscache, page); |
369 | BUG_ON(!PageLocked(page)); | 358 | BUG_ON(!PageLocked(page)); |
370 | fscache_uncache_page(vcookie->fscache, page); | 359 | fscache_uncache_page(vcookie->fscache, page); |
371 | ClearPageFsCache(page); | ||
372 | } | 360 | } |
373 | } | 361 | } |
374 | 362 | ||
diff --git a/fs/afs/file.c b/fs/afs/file.c index 681c2a7b013f..39b301662f22 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
@@ -315,7 +315,6 @@ static void afs_invalidatepage(struct page *page, unsigned long offset) | |||
315 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); | 315 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); |
316 | fscache_wait_on_page_write(vnode->cache, page); | 316 | fscache_wait_on_page_write(vnode->cache, page); |
317 | fscache_uncache_page(vnode->cache, page); | 317 | fscache_uncache_page(vnode->cache, page); |
318 | ClearPageFsCache(page); | ||
319 | } | 318 | } |
320 | #endif | 319 | #endif |
321 | 320 | ||
@@ -349,17 +348,9 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags) | |||
349 | /* deny if page is being written to the cache and the caller hasn't | 348 | /* deny if page is being written to the cache and the caller hasn't |
350 | * elected to wait */ | 349 | * elected to wait */ |
351 | #ifdef CONFIG_AFS_FSCACHE | 350 | #ifdef CONFIG_AFS_FSCACHE |
352 | if (PageFsCache(page)) { | 351 | if (!fscache_maybe_release_page(vnode->cache, page, gfp_flags)) { |
353 | if (fscache_check_page_write(vnode->cache, page)) { | 352 | _leave(" = F [cache busy]"); |
354 | if (!(gfp_flags & __GFP_WAIT)) { | 353 | return 0; |
355 | _leave(" = F [cache busy]"); | ||
356 | return 0; | ||
357 | } | ||
358 | fscache_wait_on_page_write(vnode->cache, page); | ||
359 | } | ||
360 | |||
361 | fscache_uncache_page(vnode->cache, page); | ||
362 | ClearPageFsCache(page); | ||
363 | } | 354 | } |
364 | #endif | 355 | #endif |
365 | 356 | ||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/aio_abi.h> | 15 | #include <linux/aio_abi.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/syscalls.h> | 17 | #include <linux/syscalls.h> |
18 | #include <linux/backing-dev.h> | ||
18 | #include <linux/uio.h> | 19 | #include <linux/uio.h> |
19 | 20 | ||
20 | #define DEBUG 0 | 21 | #define DEBUG 0 |
@@ -32,6 +33,9 @@ | |||
32 | #include <linux/workqueue.h> | 33 | #include <linux/workqueue.h> |
33 | #include <linux/security.h> | 34 | #include <linux/security.h> |
34 | #include <linux/eventfd.h> | 35 | #include <linux/eventfd.h> |
36 | #include <linux/blkdev.h> | ||
37 | #include <linux/mempool.h> | ||
38 | #include <linux/hash.h> | ||
35 | 39 | ||
36 | #include <asm/kmap_types.h> | 40 | #include <asm/kmap_types.h> |
37 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
@@ -60,6 +64,14 @@ static DECLARE_WORK(fput_work, aio_fput_routine); | |||
60 | static DEFINE_SPINLOCK(fput_lock); | 64 | static DEFINE_SPINLOCK(fput_lock); |
61 | static LIST_HEAD(fput_head); | 65 | static LIST_HEAD(fput_head); |
62 | 66 | ||
67 | #define AIO_BATCH_HASH_BITS 3 /* allocated on-stack, so don't go crazy */ | ||
68 | #define AIO_BATCH_HASH_SIZE (1 << AIO_BATCH_HASH_BITS) | ||
69 | struct aio_batch_entry { | ||
70 | struct hlist_node list; | ||
71 | struct address_space *mapping; | ||
72 | }; | ||
73 | mempool_t *abe_pool; | ||
74 | |||
63 | static void aio_kick_handler(struct work_struct *); | 75 | static void aio_kick_handler(struct work_struct *); |
64 | static void aio_queue_work(struct kioctx *); | 76 | static void aio_queue_work(struct kioctx *); |
65 | 77 | ||
@@ -73,6 +85,8 @@ static int __init aio_setup(void) | |||
73 | kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC); | 85 | kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC); |
74 | 86 | ||
75 | aio_wq = create_workqueue("aio"); | 87 | aio_wq = create_workqueue("aio"); |
88 | abe_pool = mempool_create_kmalloc_pool(1, sizeof(struct aio_batch_entry)); | ||
89 | BUG_ON(!abe_pool); | ||
76 | 90 | ||
77 | pr_debug("aio_setup: sizeof(struct page) = %d\n", (int)sizeof(struct page)); | 91 | pr_debug("aio_setup: sizeof(struct page) = %d\n", (int)sizeof(struct page)); |
78 | 92 | ||
@@ -1531,8 +1545,44 @@ static int aio_wake_function(wait_queue_t *wait, unsigned mode, | |||
1531 | return 1; | 1545 | return 1; |
1532 | } | 1546 | } |
1533 | 1547 | ||
1548 | static void aio_batch_add(struct address_space *mapping, | ||
1549 | struct hlist_head *batch_hash) | ||
1550 | { | ||
1551 | struct aio_batch_entry *abe; | ||
1552 | struct hlist_node *pos; | ||
1553 | unsigned bucket; | ||
1554 | |||
1555 | bucket = hash_ptr(mapping, AIO_BATCH_HASH_BITS); | ||
1556 | hlist_for_each_entry(abe, pos, &batch_hash[bucket], list) { | ||
1557 | if (abe->mapping == mapping) | ||
1558 | return; | ||
1559 | } | ||
1560 | |||
1561 | abe = mempool_alloc(abe_pool, GFP_KERNEL); | ||
1562 | BUG_ON(!igrab(mapping->host)); | ||
1563 | abe->mapping = mapping; | ||
1564 | hlist_add_head(&abe->list, &batch_hash[bucket]); | ||
1565 | return; | ||
1566 | } | ||
1567 | |||
1568 | static void aio_batch_free(struct hlist_head *batch_hash) | ||
1569 | { | ||
1570 | struct aio_batch_entry *abe; | ||
1571 | struct hlist_node *pos, *n; | ||
1572 | int i; | ||
1573 | |||
1574 | for (i = 0; i < AIO_BATCH_HASH_SIZE; i++) { | ||
1575 | hlist_for_each_entry_safe(abe, pos, n, &batch_hash[i], list) { | ||
1576 | blk_run_address_space(abe->mapping); | ||
1577 | iput(abe->mapping->host); | ||
1578 | hlist_del(&abe->list); | ||
1579 | mempool_free(abe, abe_pool); | ||
1580 | } | ||
1581 | } | ||
1582 | } | ||
1583 | |||
1534 | static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | 1584 | static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, |
1535 | struct iocb *iocb) | 1585 | struct iocb *iocb, struct hlist_head *batch_hash) |
1536 | { | 1586 | { |
1537 | struct kiocb *req; | 1587 | struct kiocb *req; |
1538 | struct file *file; | 1588 | struct file *file; |
@@ -1608,6 +1658,12 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1608 | ; | 1658 | ; |
1609 | } | 1659 | } |
1610 | spin_unlock_irq(&ctx->ctx_lock); | 1660 | spin_unlock_irq(&ctx->ctx_lock); |
1661 | if (req->ki_opcode == IOCB_CMD_PREAD || | ||
1662 | req->ki_opcode == IOCB_CMD_PREADV || | ||
1663 | req->ki_opcode == IOCB_CMD_PWRITE || | ||
1664 | req->ki_opcode == IOCB_CMD_PWRITEV) | ||
1665 | aio_batch_add(file->f_mapping, batch_hash); | ||
1666 | |||
1611 | aio_put_req(req); /* drop extra ref to req */ | 1667 | aio_put_req(req); /* drop extra ref to req */ |
1612 | return 0; | 1668 | return 0; |
1613 | 1669 | ||
@@ -1635,6 +1691,7 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr, | |||
1635 | struct kioctx *ctx; | 1691 | struct kioctx *ctx; |
1636 | long ret = 0; | 1692 | long ret = 0; |
1637 | int i; | 1693 | int i; |
1694 | struct hlist_head batch_hash[AIO_BATCH_HASH_SIZE] = { { 0, }, }; | ||
1638 | 1695 | ||
1639 | if (unlikely(nr < 0)) | 1696 | if (unlikely(nr < 0)) |
1640 | return -EINVAL; | 1697 | return -EINVAL; |
@@ -1666,10 +1723,11 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr, | |||
1666 | break; | 1723 | break; |
1667 | } | 1724 | } |
1668 | 1725 | ||
1669 | ret = io_submit_one(ctx, user_iocb, &tmp); | 1726 | ret = io_submit_one(ctx, user_iocb, &tmp, batch_hash); |
1670 | if (ret) | 1727 | if (ret) |
1671 | break; | 1728 | break; |
1672 | } | 1729 | } |
1730 | aio_batch_free(batch_hash); | ||
1673 | 1731 | ||
1674 | put_ioctx(ctx); | 1732 | put_ioctx(ctx); |
1675 | return i ? i : ret; | 1733 | return i ? i : ret; |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index b9b3bb51b1e4..d15ea1790bfb 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -767,7 +767,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
767 | 767 | ||
768 | current->mm->start_stack = bprm->p; | 768 | current->mm->start_stack = bprm->p; |
769 | 769 | ||
770 | /* Now we do a little grungy work by mmaping the ELF image into | 770 | /* Now we do a little grungy work by mmapping the ELF image into |
771 | the correct location in memory. */ | 771 | the correct location in memory. */ |
772 | for(i = 0, elf_ppnt = elf_phdata; | 772 | for(i = 0, elf_ppnt = elf_phdata; |
773 | i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { | 773 | i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { |
@@ -272,7 +272,7 @@ EXPORT_SYMBOL(bio_init); | |||
272 | * for a &struct bio to become free. If a %NULL @bs is passed in, we will | 272 | * for a &struct bio to become free. If a %NULL @bs is passed in, we will |
273 | * fall back to just using @kmalloc to allocate the required memory. | 273 | * fall back to just using @kmalloc to allocate the required memory. |
274 | * | 274 | * |
275 | * Note that the caller must set ->bi_destructor on succesful return | 275 | * Note that the caller must set ->bi_destructor on successful return |
276 | * of a bio, to do the appropriate freeing of the bio once the reference | 276 | * of a bio, to do the appropriate freeing of the bio once the reference |
277 | * count drops to zero. | 277 | * count drops to zero. |
278 | **/ | 278 | **/ |
@@ -1393,6 +1393,18 @@ void bio_check_pages_dirty(struct bio *bio) | |||
1393 | } | 1393 | } |
1394 | } | 1394 | } |
1395 | 1395 | ||
1396 | #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE | ||
1397 | void bio_flush_dcache_pages(struct bio *bi) | ||
1398 | { | ||
1399 | int i; | ||
1400 | struct bio_vec *bvec; | ||
1401 | |||
1402 | bio_for_each_segment(bvec, bi, i) | ||
1403 | flush_dcache_page(bvec->bv_page); | ||
1404 | } | ||
1405 | EXPORT_SYMBOL(bio_flush_dcache_pages); | ||
1406 | #endif | ||
1407 | |||
1396 | /** | 1408 | /** |
1397 | * bio_endio - end I/O on a bio | 1409 | * bio_endio - end I/O on a bio |
1398 | * @bio: bio | 1410 | * @bio: bio |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 8bed0557d88c..73d6a735b8f3 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -405,7 +405,17 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin) | |||
405 | 405 | ||
406 | static int block_fsync(struct file *filp, struct dentry *dentry, int datasync) | 406 | static int block_fsync(struct file *filp, struct dentry *dentry, int datasync) |
407 | { | 407 | { |
408 | return sync_blockdev(I_BDEV(filp->f_mapping->host)); | 408 | struct block_device *bdev = I_BDEV(filp->f_mapping->host); |
409 | int error; | ||
410 | |||
411 | error = sync_blockdev(bdev); | ||
412 | if (error) | ||
413 | return error; | ||
414 | |||
415 | error = blkdev_issue_flush(bdev, NULL); | ||
416 | if (error == -EOPNOTSUPP) | ||
417 | error = 0; | ||
418 | return error; | ||
409 | } | 419 | } |
410 | 420 | ||
411 | /* | 421 | /* |
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index ccbdcb54ec5d..46bea0f4dc7b 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -256,7 +256,7 @@ out: | |||
256 | * Insert @em into @tree or perform a simple forward/backward merge with | 256 | * Insert @em into @tree or perform a simple forward/backward merge with |
257 | * existing mappings. The extent_map struct passed in will be inserted | 257 | * existing mappings. The extent_map struct passed in will be inserted |
258 | * into the tree directly, with an additional reference taken, or a | 258 | * into the tree directly, with an additional reference taken, or a |
259 | * reference dropped if the merge attempt was sucessfull. | 259 | * reference dropped if the merge attempt was successfull. |
260 | */ | 260 | */ |
261 | int add_extent_mapping(struct extent_map_tree *tree, | 261 | int add_extent_mapping(struct extent_map_tree *tree, |
262 | struct extent_map *em) | 262 | struct extent_map *em) |
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 431accd475a7..27089311fbea 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c | |||
@@ -114,8 +114,9 @@ nomem_lookup_data: | |||
114 | 114 | ||
115 | /* | 115 | /* |
116 | * attempt to look up the nominated node in this cache | 116 | * attempt to look up the nominated node in this cache |
117 | * - return -ETIMEDOUT to be scheduled again | ||
117 | */ | 118 | */ |
118 | static void cachefiles_lookup_object(struct fscache_object *_object) | 119 | static int cachefiles_lookup_object(struct fscache_object *_object) |
119 | { | 120 | { |
120 | struct cachefiles_lookup_data *lookup_data; | 121 | struct cachefiles_lookup_data *lookup_data; |
121 | struct cachefiles_object *parent, *object; | 122 | struct cachefiles_object *parent, *object; |
@@ -145,13 +146,15 @@ static void cachefiles_lookup_object(struct fscache_object *_object) | |||
145 | object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) | 146 | object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) |
146 | cachefiles_attr_changed(&object->fscache); | 147 | cachefiles_attr_changed(&object->fscache); |
147 | 148 | ||
148 | if (ret < 0) { | 149 | if (ret < 0 && ret != -ETIMEDOUT) { |
149 | printk(KERN_WARNING "CacheFiles: Lookup failed error %d\n", | 150 | if (ret != -ENOBUFS) |
150 | ret); | 151 | printk(KERN_WARNING |
152 | "CacheFiles: Lookup failed error %d\n", ret); | ||
151 | fscache_object_lookup_error(&object->fscache); | 153 | fscache_object_lookup_error(&object->fscache); |
152 | } | 154 | } |
153 | 155 | ||
154 | _leave(" [%d]", ret); | 156 | _leave(" [%d]", ret); |
157 | return ret; | ||
155 | } | 158 | } |
156 | 159 | ||
157 | /* | 160 | /* |
@@ -331,6 +334,7 @@ static void cachefiles_put_object(struct fscache_object *_object) | |||
331 | } | 334 | } |
332 | 335 | ||
333 | cache = object->fscache.cache; | 336 | cache = object->fscache.cache; |
337 | fscache_object_destroy(&object->fscache); | ||
334 | kmem_cache_free(cachefiles_object_jar, object); | 338 | kmem_cache_free(cachefiles_object_jar, object); |
335 | fscache_object_destroyed(cache); | 339 | fscache_object_destroyed(cache); |
336 | } | 340 | } |
@@ -403,12 +407,26 @@ static int cachefiles_attr_changed(struct fscache_object *_object) | |||
403 | if (oi_size == ni_size) | 407 | if (oi_size == ni_size) |
404 | return 0; | 408 | return 0; |
405 | 409 | ||
406 | newattrs.ia_size = ni_size; | ||
407 | newattrs.ia_valid = ATTR_SIZE; | ||
408 | |||
409 | cachefiles_begin_secure(cache, &saved_cred); | 410 | cachefiles_begin_secure(cache, &saved_cred); |
410 | mutex_lock(&object->backer->d_inode->i_mutex); | 411 | mutex_lock(&object->backer->d_inode->i_mutex); |
412 | |||
413 | /* if there's an extension to a partial page at the end of the backing | ||
414 | * file, we need to discard the partial page so that we pick up new | ||
415 | * data after it */ | ||
416 | if (oi_size & ~PAGE_MASK && ni_size > oi_size) { | ||
417 | _debug("discard tail %llx", oi_size); | ||
418 | newattrs.ia_valid = ATTR_SIZE; | ||
419 | newattrs.ia_size = oi_size & PAGE_MASK; | ||
420 | ret = notify_change(object->backer, &newattrs); | ||
421 | if (ret < 0) | ||
422 | goto truncate_failed; | ||
423 | } | ||
424 | |||
425 | newattrs.ia_valid = ATTR_SIZE; | ||
426 | newattrs.ia_size = ni_size; | ||
411 | ret = notify_change(object->backer, &newattrs); | 427 | ret = notify_change(object->backer, &newattrs); |
428 | |||
429 | truncate_failed: | ||
412 | mutex_unlock(&object->backer->d_inode->i_mutex); | 430 | mutex_unlock(&object->backer->d_inode->i_mutex); |
413 | cachefiles_end_secure(cache, saved_cred); | 431 | cachefiles_end_secure(cache, saved_cred); |
414 | 432 | ||
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 4ce818ae39ea..14ac4806e291 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c | |||
@@ -21,17 +21,81 @@ | |||
21 | #include <linux/security.h> | 21 | #include <linux/security.h> |
22 | #include "internal.h" | 22 | #include "internal.h" |
23 | 23 | ||
24 | static int cachefiles_wait_bit(void *flags) | 24 | #define CACHEFILES_KEYBUF_SIZE 512 |
25 | |||
26 | /* | ||
27 | * dump debugging info about an object | ||
28 | */ | ||
29 | static noinline | ||
30 | void __cachefiles_printk_object(struct cachefiles_object *object, | ||
31 | const char *prefix, | ||
32 | u8 *keybuf) | ||
25 | { | 33 | { |
26 | schedule(); | 34 | struct fscache_cookie *cookie; |
27 | return 0; | 35 | unsigned keylen, loop; |
36 | |||
37 | printk(KERN_ERR "%sobject: OBJ%x\n", | ||
38 | prefix, object->fscache.debug_id); | ||
39 | printk(KERN_ERR "%sobjstate=%s fl=%lx swfl=%lx ev=%lx[%lx]\n", | ||
40 | prefix, fscache_object_states[object->fscache.state], | ||
41 | object->fscache.flags, object->fscache.work.flags, | ||
42 | object->fscache.events, | ||
43 | object->fscache.event_mask & FSCACHE_OBJECT_EVENTS_MASK); | ||
44 | printk(KERN_ERR "%sops=%u inp=%u exc=%u\n", | ||
45 | prefix, object->fscache.n_ops, object->fscache.n_in_progress, | ||
46 | object->fscache.n_exclusive); | ||
47 | printk(KERN_ERR "%sparent=%p\n", | ||
48 | prefix, object->fscache.parent); | ||
49 | |||
50 | spin_lock(&object->fscache.lock); | ||
51 | cookie = object->fscache.cookie; | ||
52 | if (cookie) { | ||
53 | printk(KERN_ERR "%scookie=%p [pr=%p nd=%p fl=%lx]\n", | ||
54 | prefix, | ||
55 | object->fscache.cookie, | ||
56 | object->fscache.cookie->parent, | ||
57 | object->fscache.cookie->netfs_data, | ||
58 | object->fscache.cookie->flags); | ||
59 | if (keybuf) | ||
60 | keylen = cookie->def->get_key(cookie->netfs_data, keybuf, | ||
61 | CACHEFILES_KEYBUF_SIZE); | ||
62 | else | ||
63 | keylen = 0; | ||
64 | } else { | ||
65 | printk(KERN_ERR "%scookie=NULL\n", prefix); | ||
66 | keylen = 0; | ||
67 | } | ||
68 | spin_unlock(&object->fscache.lock); | ||
69 | |||
70 | if (keylen) { | ||
71 | printk(KERN_ERR "%skey=[%u] '", prefix, keylen); | ||
72 | for (loop = 0; loop < keylen; loop++) | ||
73 | printk("%02x", keybuf[loop]); | ||
74 | printk("'\n"); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * dump debugging info about a pair of objects | ||
80 | */ | ||
81 | static noinline void cachefiles_printk_object(struct cachefiles_object *object, | ||
82 | struct cachefiles_object *xobject) | ||
83 | { | ||
84 | u8 *keybuf; | ||
85 | |||
86 | keybuf = kmalloc(CACHEFILES_KEYBUF_SIZE, GFP_NOIO); | ||
87 | if (object) | ||
88 | __cachefiles_printk_object(object, "", keybuf); | ||
89 | if (xobject) | ||
90 | __cachefiles_printk_object(xobject, "x", keybuf); | ||
91 | kfree(keybuf); | ||
28 | } | 92 | } |
29 | 93 | ||
30 | /* | 94 | /* |
31 | * record the fact that an object is now active | 95 | * record the fact that an object is now active |
32 | */ | 96 | */ |
33 | static void cachefiles_mark_object_active(struct cachefiles_cache *cache, | 97 | static int cachefiles_mark_object_active(struct cachefiles_cache *cache, |
34 | struct cachefiles_object *object) | 98 | struct cachefiles_object *object) |
35 | { | 99 | { |
36 | struct cachefiles_object *xobject; | 100 | struct cachefiles_object *xobject; |
37 | struct rb_node **_p, *_parent = NULL; | 101 | struct rb_node **_p, *_parent = NULL; |
@@ -42,8 +106,11 @@ static void cachefiles_mark_object_active(struct cachefiles_cache *cache, | |||
42 | try_again: | 106 | try_again: |
43 | write_lock(&cache->active_lock); | 107 | write_lock(&cache->active_lock); |
44 | 108 | ||
45 | if (test_and_set_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) | 109 | if (test_and_set_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) { |
110 | printk(KERN_ERR "CacheFiles: Error: Object already active\n"); | ||
111 | cachefiles_printk_object(object, NULL); | ||
46 | BUG(); | 112 | BUG(); |
113 | } | ||
47 | 114 | ||
48 | dentry = object->dentry; | 115 | dentry = object->dentry; |
49 | _p = &cache->active_nodes.rb_node; | 116 | _p = &cache->active_nodes.rb_node; |
@@ -66,8 +133,8 @@ try_again: | |||
66 | rb_insert_color(&object->active_node, &cache->active_nodes); | 133 | rb_insert_color(&object->active_node, &cache->active_nodes); |
67 | 134 | ||
68 | write_unlock(&cache->active_lock); | 135 | write_unlock(&cache->active_lock); |
69 | _leave(""); | 136 | _leave(" = 0"); |
70 | return; | 137 | return 0; |
71 | 138 | ||
72 | /* an old object from a previous incarnation is hogging the slot - we | 139 | /* an old object from a previous incarnation is hogging the slot - we |
73 | * need to wait for it to be destroyed */ | 140 | * need to wait for it to be destroyed */ |
@@ -76,44 +143,70 @@ wait_for_old_object: | |||
76 | printk(KERN_ERR "\n"); | 143 | printk(KERN_ERR "\n"); |
77 | printk(KERN_ERR "CacheFiles: Error:" | 144 | printk(KERN_ERR "CacheFiles: Error:" |
78 | " Unexpected object collision\n"); | 145 | " Unexpected object collision\n"); |
79 | printk(KERN_ERR "xobject: OBJ%x\n", | 146 | cachefiles_printk_object(object, xobject); |
80 | xobject->fscache.debug_id); | ||
81 | printk(KERN_ERR "xobjstate=%s\n", | ||
82 | fscache_object_states[xobject->fscache.state]); | ||
83 | printk(KERN_ERR "xobjflags=%lx\n", xobject->fscache.flags); | ||
84 | printk(KERN_ERR "xobjevent=%lx [%lx]\n", | ||
85 | xobject->fscache.events, xobject->fscache.event_mask); | ||
86 | printk(KERN_ERR "xops=%u inp=%u exc=%u\n", | ||
87 | xobject->fscache.n_ops, xobject->fscache.n_in_progress, | ||
88 | xobject->fscache.n_exclusive); | ||
89 | printk(KERN_ERR "xcookie=%p [pr=%p nd=%p fl=%lx]\n", | ||
90 | xobject->fscache.cookie, | ||
91 | xobject->fscache.cookie->parent, | ||
92 | xobject->fscache.cookie->netfs_data, | ||
93 | xobject->fscache.cookie->flags); | ||
94 | printk(KERN_ERR "xparent=%p\n", | ||
95 | xobject->fscache.parent); | ||
96 | printk(KERN_ERR "object: OBJ%x\n", | ||
97 | object->fscache.debug_id); | ||
98 | printk(KERN_ERR "cookie=%p [pr=%p nd=%p fl=%lx]\n", | ||
99 | object->fscache.cookie, | ||
100 | object->fscache.cookie->parent, | ||
101 | object->fscache.cookie->netfs_data, | ||
102 | object->fscache.cookie->flags); | ||
103 | printk(KERN_ERR "parent=%p\n", | ||
104 | object->fscache.parent); | ||
105 | BUG(); | 147 | BUG(); |
106 | } | 148 | } |
107 | atomic_inc(&xobject->usage); | 149 | atomic_inc(&xobject->usage); |
108 | write_unlock(&cache->active_lock); | 150 | write_unlock(&cache->active_lock); |
109 | 151 | ||
110 | _debug(">>> wait"); | 152 | if (test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { |
111 | wait_on_bit(&xobject->flags, CACHEFILES_OBJECT_ACTIVE, | 153 | wait_queue_head_t *wq; |
112 | cachefiles_wait_bit, TASK_UNINTERRUPTIBLE); | 154 | |
113 | _debug("<<< waited"); | 155 | signed long timeout = 60 * HZ; |
156 | wait_queue_t wait; | ||
157 | bool requeue; | ||
158 | |||
159 | /* if the object we're waiting for is queued for processing, | ||
160 | * then just put ourselves on the queue behind it */ | ||
161 | if (slow_work_is_queued(&xobject->fscache.work)) { | ||
162 | _debug("queue OBJ%x behind OBJ%x immediately", | ||
163 | object->fscache.debug_id, | ||
164 | xobject->fscache.debug_id); | ||
165 | goto requeue; | ||
166 | } | ||
167 | |||
168 | /* otherwise we sleep until either the object we're waiting for | ||
169 | * is done, or the slow-work facility wants the thread back to | ||
170 | * do other work */ | ||
171 | wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE); | ||
172 | init_wait(&wait); | ||
173 | requeue = false; | ||
174 | do { | ||
175 | prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); | ||
176 | if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) | ||
177 | break; | ||
178 | requeue = slow_work_sleep_till_thread_needed( | ||
179 | &object->fscache.work, &timeout); | ||
180 | } while (timeout > 0 && !requeue); | ||
181 | finish_wait(wq, &wait); | ||
182 | |||
183 | if (requeue && | ||
184 | test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { | ||
185 | _debug("queue OBJ%x behind OBJ%x after wait", | ||
186 | object->fscache.debug_id, | ||
187 | xobject->fscache.debug_id); | ||
188 | goto requeue; | ||
189 | } | ||
190 | |||
191 | if (timeout <= 0) { | ||
192 | printk(KERN_ERR "\n"); | ||
193 | printk(KERN_ERR "CacheFiles: Error: Overlong" | ||
194 | " wait for old active object to go away\n"); | ||
195 | cachefiles_printk_object(object, xobject); | ||
196 | goto requeue; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)); | ||
114 | 201 | ||
115 | cache->cache.ops->put_object(&xobject->fscache); | 202 | cache->cache.ops->put_object(&xobject->fscache); |
116 | goto try_again; | 203 | goto try_again; |
204 | |||
205 | requeue: | ||
206 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); | ||
207 | cache->cache.ops->put_object(&xobject->fscache); | ||
208 | _leave(" = -ETIMEDOUT"); | ||
209 | return -ETIMEDOUT; | ||
117 | } | 210 | } |
118 | 211 | ||
119 | /* | 212 | /* |
@@ -254,7 +347,7 @@ int cachefiles_delete_object(struct cachefiles_cache *cache, | |||
254 | 347 | ||
255 | dir = dget_parent(object->dentry); | 348 | dir = dget_parent(object->dentry); |
256 | 349 | ||
257 | mutex_lock(&dir->d_inode->i_mutex); | 350 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
258 | ret = cachefiles_bury_object(cache, dir, object->dentry); | 351 | ret = cachefiles_bury_object(cache, dir, object->dentry); |
259 | 352 | ||
260 | dput(dir); | 353 | dput(dir); |
@@ -307,7 +400,7 @@ lookup_again: | |||
307 | /* search the current directory for the element name */ | 400 | /* search the current directory for the element name */ |
308 | _debug("lookup '%s'", name); | 401 | _debug("lookup '%s'", name); |
309 | 402 | ||
310 | mutex_lock(&dir->d_inode->i_mutex); | 403 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
311 | 404 | ||
312 | start = jiffies; | 405 | start = jiffies; |
313 | next = lookup_one_len(name, dir, nlen); | 406 | next = lookup_one_len(name, dir, nlen); |
@@ -418,12 +511,15 @@ lookup_again: | |||
418 | } | 511 | } |
419 | 512 | ||
420 | /* note that we're now using this object */ | 513 | /* note that we're now using this object */ |
421 | cachefiles_mark_object_active(cache, object); | 514 | ret = cachefiles_mark_object_active(cache, object); |
422 | 515 | ||
423 | mutex_unlock(&dir->d_inode->i_mutex); | 516 | mutex_unlock(&dir->d_inode->i_mutex); |
424 | dput(dir); | 517 | dput(dir); |
425 | dir = NULL; | 518 | dir = NULL; |
426 | 519 | ||
520 | if (ret == -ETIMEDOUT) | ||
521 | goto mark_active_timed_out; | ||
522 | |||
427 | _debug("=== OBTAINED_OBJECT ==="); | 523 | _debug("=== OBTAINED_OBJECT ==="); |
428 | 524 | ||
429 | if (object->new) { | 525 | if (object->new) { |
@@ -467,6 +563,10 @@ create_error: | |||
467 | cachefiles_io_error(cache, "Create/mkdir failed"); | 563 | cachefiles_io_error(cache, "Create/mkdir failed"); |
468 | goto error; | 564 | goto error; |
469 | 565 | ||
566 | mark_active_timed_out: | ||
567 | _debug("mark active timed out"); | ||
568 | goto release_dentry; | ||
569 | |||
470 | check_error: | 570 | check_error: |
471 | _debug("check error %d", ret); | 571 | _debug("check error %d", ret); |
472 | write_lock(&cache->active_lock); | 572 | write_lock(&cache->active_lock); |
@@ -474,7 +574,7 @@ check_error: | |||
474 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); | 574 | clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); |
475 | wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE); | 575 | wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE); |
476 | write_unlock(&cache->active_lock); | 576 | write_unlock(&cache->active_lock); |
477 | 577 | release_dentry: | |
478 | dput(object->dentry); | 578 | dput(object->dentry); |
479 | object->dentry = NULL; | 579 | object->dentry = NULL; |
480 | goto error_out; | 580 | goto error_out; |
@@ -495,9 +595,6 @@ error: | |||
495 | error_out2: | 595 | error_out2: |
496 | dput(dir); | 596 | dput(dir); |
497 | error_out: | 597 | error_out: |
498 | if (ret == -ENOSPC) | ||
499 | ret = -ENOBUFS; | ||
500 | |||
501 | _leave(" = error %d", -ret); | 598 | _leave(" = error %d", -ret); |
502 | return ret; | 599 | return ret; |
503 | } | 600 | } |
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c index a69787e7dd96..a6c8c6fe8df9 100644 --- a/fs/cachefiles/rdwr.c +++ b/fs/cachefiles/rdwr.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/mount.h> | 12 | #include <linux/mount.h> |
13 | #include <linux/file.h> | 13 | #include <linux/file.h> |
14 | #include <linux/ima.h> | ||
14 | #include "internal.h" | 15 | #include "internal.h" |
15 | 16 | ||
16 | /* | 17 | /* |
@@ -40,8 +41,10 @@ static int cachefiles_read_waiter(wait_queue_t *wait, unsigned mode, | |||
40 | 41 | ||
41 | _debug("--- monitor %p %lx ---", page, page->flags); | 42 | _debug("--- monitor %p %lx ---", page, page->flags); |
42 | 43 | ||
43 | if (!PageUptodate(page) && !PageError(page)) | 44 | if (!PageUptodate(page) && !PageError(page)) { |
44 | dump_stack(); | 45 | /* unlocked, not uptodate and not erronous? */ |
46 | _debug("page probably truncated"); | ||
47 | } | ||
45 | 48 | ||
46 | /* remove from the waitqueue */ | 49 | /* remove from the waitqueue */ |
47 | list_del(&wait->task_list); | 50 | list_del(&wait->task_list); |
@@ -61,6 +64,84 @@ static int cachefiles_read_waiter(wait_queue_t *wait, unsigned mode, | |||
61 | } | 64 | } |
62 | 65 | ||
63 | /* | 66 | /* |
67 | * handle a probably truncated page | ||
68 | * - check to see if the page is still relevant and reissue the read if | ||
69 | * possible | ||
70 | * - return -EIO on error, -ENODATA if the page is gone, -EINPROGRESS if we | ||
71 | * must wait again and 0 if successful | ||
72 | */ | ||
73 | static int cachefiles_read_reissue(struct cachefiles_object *object, | ||
74 | struct cachefiles_one_read *monitor) | ||
75 | { | ||
76 | struct address_space *bmapping = object->backer->d_inode->i_mapping; | ||
77 | struct page *backpage = monitor->back_page, *backpage2; | ||
78 | int ret; | ||
79 | |||
80 | kenter("{ino=%lx},{%lx,%lx}", | ||
81 | object->backer->d_inode->i_ino, | ||
82 | backpage->index, backpage->flags); | ||
83 | |||
84 | /* skip if the page was truncated away completely */ | ||
85 | if (backpage->mapping != bmapping) { | ||
86 | kleave(" = -ENODATA [mapping]"); | ||
87 | return -ENODATA; | ||
88 | } | ||
89 | |||
90 | backpage2 = find_get_page(bmapping, backpage->index); | ||
91 | if (!backpage2) { | ||
92 | kleave(" = -ENODATA [gone]"); | ||
93 | return -ENODATA; | ||
94 | } | ||
95 | |||
96 | if (backpage != backpage2) { | ||
97 | put_page(backpage2); | ||
98 | kleave(" = -ENODATA [different]"); | ||
99 | return -ENODATA; | ||
100 | } | ||
101 | |||
102 | /* the page is still there and we already have a ref on it, so we don't | ||
103 | * need a second */ | ||
104 | put_page(backpage2); | ||
105 | |||
106 | INIT_LIST_HEAD(&monitor->op_link); | ||
107 | add_page_wait_queue(backpage, &monitor->monitor); | ||
108 | |||
109 | if (trylock_page(backpage)) { | ||
110 | ret = -EIO; | ||
111 | if (PageError(backpage)) | ||
112 | goto unlock_discard; | ||
113 | ret = 0; | ||
114 | if (PageUptodate(backpage)) | ||
115 | goto unlock_discard; | ||
116 | |||
117 | kdebug("reissue read"); | ||
118 | ret = bmapping->a_ops->readpage(NULL, backpage); | ||
119 | if (ret < 0) | ||
120 | goto unlock_discard; | ||
121 | } | ||
122 | |||
123 | /* but the page may have been read before the monitor was installed, so | ||
124 | * the monitor may miss the event - so we have to ensure that we do get | ||
125 | * one in such a case */ | ||
126 | if (trylock_page(backpage)) { | ||
127 | _debug("jumpstart %p {%lx}", backpage, backpage->flags); | ||
128 | unlock_page(backpage); | ||
129 | } | ||
130 | |||
131 | /* it'll reappear on the todo list */ | ||
132 | kleave(" = -EINPROGRESS"); | ||
133 | return -EINPROGRESS; | ||
134 | |||
135 | unlock_discard: | ||
136 | unlock_page(backpage); | ||
137 | spin_lock_irq(&object->work_lock); | ||
138 | list_del(&monitor->op_link); | ||
139 | spin_unlock_irq(&object->work_lock); | ||
140 | kleave(" = %d", ret); | ||
141 | return ret; | ||
142 | } | ||
143 | |||
144 | /* | ||
64 | * copy data from backing pages to netfs pages to complete a read operation | 145 | * copy data from backing pages to netfs pages to complete a read operation |
65 | * - driven by FS-Cache's thread pool | 146 | * - driven by FS-Cache's thread pool |
66 | */ | 147 | */ |
@@ -92,20 +173,26 @@ static void cachefiles_read_copier(struct fscache_operation *_op) | |||
92 | 173 | ||
93 | _debug("- copy {%lu}", monitor->back_page->index); | 174 | _debug("- copy {%lu}", monitor->back_page->index); |
94 | 175 | ||
95 | error = -EIO; | 176 | recheck: |
96 | if (PageUptodate(monitor->back_page)) { | 177 | if (PageUptodate(monitor->back_page)) { |
97 | copy_highpage(monitor->netfs_page, monitor->back_page); | 178 | copy_highpage(monitor->netfs_page, monitor->back_page); |
98 | 179 | ||
99 | pagevec_add(&pagevec, monitor->netfs_page); | 180 | pagevec_add(&pagevec, monitor->netfs_page); |
100 | fscache_mark_pages_cached(monitor->op, &pagevec); | 181 | fscache_mark_pages_cached(monitor->op, &pagevec); |
101 | error = 0; | 182 | error = 0; |
102 | } | 183 | } else if (!PageError(monitor->back_page)) { |
103 | 184 | /* the page has probably been truncated */ | |
104 | if (error) | 185 | error = cachefiles_read_reissue(object, monitor); |
186 | if (error == -EINPROGRESS) | ||
187 | goto next; | ||
188 | goto recheck; | ||
189 | } else { | ||
105 | cachefiles_io_error_obj( | 190 | cachefiles_io_error_obj( |
106 | object, | 191 | object, |
107 | "Readpage failed on backing file %lx", | 192 | "Readpage failed on backing file %lx", |
108 | (unsigned long) monitor->back_page->flags); | 193 | (unsigned long) monitor->back_page->flags); |
194 | error = -EIO; | ||
195 | } | ||
109 | 196 | ||
110 | page_cache_release(monitor->back_page); | 197 | page_cache_release(monitor->back_page); |
111 | 198 | ||
@@ -114,6 +201,7 @@ static void cachefiles_read_copier(struct fscache_operation *_op) | |||
114 | fscache_put_retrieval(op); | 201 | fscache_put_retrieval(op); |
115 | kfree(monitor); | 202 | kfree(monitor); |
116 | 203 | ||
204 | next: | ||
117 | /* let the thread pool have some air occasionally */ | 205 | /* let the thread pool have some air occasionally */ |
118 | max--; | 206 | max--; |
119 | if (max < 0 || need_resched()) { | 207 | if (max < 0 || need_resched()) { |
@@ -333,7 +421,8 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
333 | 421 | ||
334 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; | 422 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; |
335 | 423 | ||
336 | op->op.flags = FSCACHE_OP_FAST; | 424 | op->op.flags &= FSCACHE_OP_KEEP_FLAGS; |
425 | op->op.flags |= FSCACHE_OP_FAST; | ||
337 | op->op.processor = cachefiles_read_copier; | 426 | op->op.processor = cachefiles_read_copier; |
338 | 427 | ||
339 | pagevec_init(&pagevec, 0); | 428 | pagevec_init(&pagevec, 0); |
@@ -639,7 +728,8 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
639 | 728 | ||
640 | pagevec_init(&pagevec, 0); | 729 | pagevec_init(&pagevec, 0); |
641 | 730 | ||
642 | op->op.flags = FSCACHE_OP_FAST; | 731 | op->op.flags &= FSCACHE_OP_KEEP_FLAGS; |
732 | op->op.flags |= FSCACHE_OP_FAST; | ||
643 | op->op.processor = cachefiles_read_copier; | 733 | op->op.processor = cachefiles_read_copier; |
644 | 734 | ||
645 | INIT_LIST_HEAD(&backpages); | 735 | INIT_LIST_HEAD(&backpages); |
@@ -801,7 +891,8 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page) | |||
801 | struct cachefiles_cache *cache; | 891 | struct cachefiles_cache *cache; |
802 | mm_segment_t old_fs; | 892 | mm_segment_t old_fs; |
803 | struct file *file; | 893 | struct file *file; |
804 | loff_t pos; | 894 | loff_t pos, eof; |
895 | size_t len; | ||
805 | void *data; | 896 | void *data; |
806 | int ret; | 897 | int ret; |
807 | 898 | ||
@@ -832,18 +923,33 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page) | |||
832 | if (IS_ERR(file)) { | 923 | if (IS_ERR(file)) { |
833 | ret = PTR_ERR(file); | 924 | ret = PTR_ERR(file); |
834 | } else { | 925 | } else { |
926 | ima_counts_get(file); | ||
835 | ret = -EIO; | 927 | ret = -EIO; |
836 | if (file->f_op->write) { | 928 | if (file->f_op->write) { |
837 | pos = (loff_t) page->index << PAGE_SHIFT; | 929 | pos = (loff_t) page->index << PAGE_SHIFT; |
930 | |||
931 | /* we mustn't write more data than we have, so we have | ||
932 | * to beware of a partial page at EOF */ | ||
933 | eof = object->fscache.store_limit_l; | ||
934 | len = PAGE_SIZE; | ||
935 | if (eof & ~PAGE_MASK) { | ||
936 | ASSERTCMP(pos, <, eof); | ||
937 | if (eof - pos < PAGE_SIZE) { | ||
938 | _debug("cut short %llx to %llx", | ||
939 | pos, eof); | ||
940 | len = eof - pos; | ||
941 | ASSERTCMP(pos + len, ==, eof); | ||
942 | } | ||
943 | } | ||
944 | |||
838 | data = kmap(page); | 945 | data = kmap(page); |
839 | old_fs = get_fs(); | 946 | old_fs = get_fs(); |
840 | set_fs(KERNEL_DS); | 947 | set_fs(KERNEL_DS); |
841 | ret = file->f_op->write( | 948 | ret = file->f_op->write( |
842 | file, (const void __user *) data, PAGE_SIZE, | 949 | file, (const void __user *) data, len, &pos); |
843 | &pos); | ||
844 | set_fs(old_fs); | 950 | set_fs(old_fs); |
845 | kunmap(page); | 951 | kunmap(page); |
846 | if (ret != PAGE_SIZE) | 952 | if (ret != len) |
847 | ret = -EIO; | 953 | ret = -EIO; |
848 | } | 954 | } |
849 | fput(file); | 955 | fput(file); |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 145540a316ab..094ea65afc85 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,3 +1,12 @@ | |||
1 | Version 1.61 | ||
2 | ------------ | ||
3 | Fix append problem to Samba servers (files opened with O_APPEND could | ||
4 | have duplicated data). Fix oops in cifs_lookup. Workaround problem | ||
5 | mounting to OS/400 Netserve. Fix oops in cifs_get_tcp_session. | ||
6 | Disable use of server inode numbers when server only | ||
7 | partially supports them (e.g. for one server querying inode numbers on | ||
8 | FindFirst fails but QPathInfo queries works). | ||
9 | |||
1 | Version 1.60 | 10 | Version 1.60 |
2 | ------------- | 11 | ------------- |
3 | Fix memory leak in reconnect. Fix oops in DFS mount error path. | 12 | Fix memory leak in reconnect. Fix oops in DFS mount error path. |
diff --git a/fs/cifs/README b/fs/cifs/README index 79c1a93400be..a727b7cb075f 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -423,7 +423,7 @@ A partial list of the supported mount options follows: | |||
423 | source name to use to represent the client netbios machine | 423 | source name to use to represent the client netbios machine |
424 | name when doing the RFC1001 netbios session initialize. | 424 | name when doing the RFC1001 netbios session initialize. |
425 | direct Do not do inode data caching on files opened on this mount. | 425 | direct Do not do inode data caching on files opened on this mount. |
426 | This precludes mmaping files on this mount. In some cases | 426 | This precludes mmapping files on this mount. In some cases |
427 | with fast networks and little or no caching benefits on the | 427 | with fast networks and little or no caching benefits on the |
428 | client (e.g. when the application is doing large sequential | 428 | client (e.g. when the application is doing large sequential |
429 | reads bigger than page size without rereading the same data) | 429 | reads bigger than page size without rereading the same data) |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 9a5e4f5f3122..29f1da761bbf 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -1037,7 +1037,7 @@ init_cifs(void) | |||
1037 | if (rc) | 1037 | if (rc) |
1038 | goto out_unregister_key_type; | 1038 | goto out_unregister_key_type; |
1039 | #endif | 1039 | #endif |
1040 | rc = slow_work_register_user(); | 1040 | rc = slow_work_register_user(THIS_MODULE); |
1041 | if (rc) | 1041 | if (rc) |
1042 | goto out_unregister_resolver_key; | 1042 | goto out_unregister_resolver_key; |
1043 | 1043 | ||
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 5d0fde18039c..4b35f7ec0583 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -39,7 +39,7 @@ | |||
39 | 39 | ||
40 | /* | 40 | /* |
41 | * MAX_REQ is the maximum number of requests that WE will send | 41 | * MAX_REQ is the maximum number of requests that WE will send |
42 | * on one socket concurently. It also matches the most common | 42 | * on one socket concurrently. It also matches the most common |
43 | * value of max multiplex returned by servers. We may | 43 | * value of max multiplex returned by servers. We may |
44 | * eventually want to use the negotiated value (in case | 44 | * eventually want to use the negotiated value (in case |
45 | * future servers can handle more) when we are more confident that | 45 | * future servers can handle more) when we are more confident that |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 2d07f890a842..3877737f96a6 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -1227,7 +1227,7 @@ typedef struct smb_com_setattr_rsp { | |||
1227 | /* empty wct response to setattr */ | 1227 | /* empty wct response to setattr */ |
1228 | 1228 | ||
1229 | /*******************************************************/ | 1229 | /*******************************************************/ |
1230 | /* NT Transact structure defintions follow */ | 1230 | /* NT Transact structure definitions follow */ |
1231 | /* Currently only ioctl, acl (get security descriptor) */ | 1231 | /* Currently only ioctl, acl (get security descriptor) */ |
1232 | /* and notify are implemented */ | 1232 | /* and notify are implemented */ |
1233 | /*******************************************************/ | 1233 | /*******************************************************/ |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 627a60a6c1b1..1f42f772865a 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -214,8 +214,6 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
214 | posix_flags |= SMB_O_EXCL; | 214 | posix_flags |= SMB_O_EXCL; |
215 | if (oflags & O_TRUNC) | 215 | if (oflags & O_TRUNC) |
216 | posix_flags |= SMB_O_TRUNC; | 216 | posix_flags |= SMB_O_TRUNC; |
217 | if (oflags & O_APPEND) | ||
218 | posix_flags |= SMB_O_APPEND; | ||
219 | if (oflags & O_SYNC) | 217 | if (oflags & O_SYNC) |
220 | posix_flags |= SMB_O_SYNC; | 218 | posix_flags |= SMB_O_SYNC; |
221 | if (oflags & O_DIRECTORY) | 219 | if (oflags & O_DIRECTORY) |
@@ -643,9 +641,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
643 | * O_EXCL: optimize away the lookup, but don't hash the dentry. Let | 641 | * O_EXCL: optimize away the lookup, but don't hash the dentry. Let |
644 | * the VFS handle the create. | 642 | * the VFS handle the create. |
645 | */ | 643 | */ |
646 | if (nd->flags & LOOKUP_EXCL) { | 644 | if (nd && (nd->flags & LOOKUP_EXCL)) { |
647 | d_instantiate(direntry, NULL); | 645 | d_instantiate(direntry, NULL); |
648 | return 0; | 646 | return NULL; |
649 | } | 647 | } |
650 | 648 | ||
651 | /* can not grab the rename sem here since it would | 649 | /* can not grab the rename sem here since it would |
@@ -675,7 +673,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
675 | * reduction in network traffic in the other paths. | 673 | * reduction in network traffic in the other paths. |
676 | */ | 674 | */ |
677 | if (pTcon->unix_ext) { | 675 | if (pTcon->unix_ext) { |
678 | if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && | 676 | if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && |
679 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && | 677 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && |
680 | (nd->intent.open.flags & O_CREAT)) { | 678 | (nd->intent.open.flags & O_CREAT)) { |
681 | rc = cifs_posix_open(full_path, &newInode, nd->path.mnt, | 679 | rc = cifs_posix_open(full_path, &newInode, nd->path.mnt, |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index cababd8a52df..cf18ee765590 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -914,8 +914,8 @@ undo_setattr: | |||
914 | /* | 914 | /* |
915 | * If dentry->d_inode is null (usually meaning the cached dentry | 915 | * If dentry->d_inode is null (usually meaning the cached dentry |
916 | * is a negative dentry) then we would attempt a standard SMB delete, but | 916 | * is a negative dentry) then we would attempt a standard SMB delete, but |
917 | * if that fails we can not attempt the fall back mechanisms on EACESS | 917 | * if that fails we can not attempt the fall back mechanisms on EACCESS |
918 | * but will return the EACESS to the caller. Note that the VFS does not call | 918 | * but will return the EACCESS to the caller. Note that the VFS does not call |
919 | * unlink on negative dentries currently. | 919 | * unlink on negative dentries currently. |
920 | */ | 920 | */ |
921 | int cifs_unlink(struct inode *dir, struct dentry *dentry) | 921 | int cifs_unlink(struct inode *dir, struct dentry *dentry) |
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c index 224a1f478966..b6b6dcb500bf 100644 --- a/fs/cifs/smbdes.c +++ b/fs/cifs/smbdes.c | |||
@@ -371,7 +371,7 @@ E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) | |||
371 | smbhash(p24 + 16, c8, p21 + 14, 1); | 371 | smbhash(p24 + 16, c8, p21 + 14, 1); |
372 | } | 372 | } |
373 | 373 | ||
374 | #if 0 /* currently unsued */ | 374 | #if 0 /* currently unused */ |
375 | static void | 375 | static void |
376 | D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) | 376 | D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) |
377 | { | 377 | { |
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c index 43c96ce29614..c6405ce3c50e 100644 --- a/fs/coda/sysctl.c +++ b/fs/coda/sysctl.c | |||
@@ -17,28 +17,25 @@ static struct ctl_table_header *fs_table_header; | |||
17 | 17 | ||
18 | static ctl_table coda_table[] = { | 18 | static ctl_table coda_table[] = { |
19 | { | 19 | { |
20 | .ctl_name = CTL_UNNUMBERED, | ||
21 | .procname = "timeout", | 20 | .procname = "timeout", |
22 | .data = &coda_timeout, | 21 | .data = &coda_timeout, |
23 | .maxlen = sizeof(int), | 22 | .maxlen = sizeof(int), |
24 | .mode = 0644, | 23 | .mode = 0644, |
25 | .proc_handler = &proc_dointvec | 24 | .proc_handler = proc_dointvec |
26 | }, | 25 | }, |
27 | { | 26 | { |
28 | .ctl_name = CTL_UNNUMBERED, | ||
29 | .procname = "hard", | 27 | .procname = "hard", |
30 | .data = &coda_hard, | 28 | .data = &coda_hard, |
31 | .maxlen = sizeof(int), | 29 | .maxlen = sizeof(int), |
32 | .mode = 0644, | 30 | .mode = 0644, |
33 | .proc_handler = &proc_dointvec | 31 | .proc_handler = proc_dointvec |
34 | }, | 32 | }, |
35 | { | 33 | { |
36 | .ctl_name = CTL_UNNUMBERED, | ||
37 | .procname = "fake_statfs", | 34 | .procname = "fake_statfs", |
38 | .data = &coda_fake_statfs, | 35 | .data = &coda_fake_statfs, |
39 | .maxlen = sizeof(int), | 36 | .maxlen = sizeof(int), |
40 | .mode = 0600, | 37 | .mode = 0600, |
41 | .proc_handler = &proc_dointvec | 38 | .proc_handler = proc_dointvec |
42 | }, | 39 | }, |
43 | {} | 40 | {} |
44 | }; | 41 | }; |
@@ -46,7 +43,6 @@ static ctl_table coda_table[] = { | |||
46 | #ifdef CONFIG_SYSCTL | 43 | #ifdef CONFIG_SYSCTL |
47 | static ctl_table fs_table[] = { | 44 | static ctl_table fs_table[] = { |
48 | { | 45 | { |
49 | .ctl_name = CTL_UNNUMBERED, | ||
50 | .procname = "coda", | 46 | .procname = "coda", |
51 | .mode = 0555, | 47 | .mode = 0555, |
52 | .child = coda_table | 48 | .child = coda_table |
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index d84e7058c298..2346895b3a77 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
@@ -246,428 +246,6 @@ static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd, unsigned | |||
246 | return err; | 246 | return err; |
247 | } | 247 | } |
248 | 248 | ||
249 | #ifdef CONFIG_NET | ||
250 | static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
251 | { | ||
252 | struct compat_timeval __user *up = compat_ptr(arg); | ||
253 | struct timeval ktv; | ||
254 | mm_segment_t old_fs = get_fs(); | ||
255 | int err; | ||
256 | |||
257 | set_fs(KERNEL_DS); | ||
258 | err = sys_ioctl(fd, cmd, (unsigned long)&ktv); | ||
259 | set_fs(old_fs); | ||
260 | if(!err) { | ||
261 | err = put_user(ktv.tv_sec, &up->tv_sec); | ||
262 | err |= __put_user(ktv.tv_usec, &up->tv_usec); | ||
263 | } | ||
264 | return err; | ||
265 | } | ||
266 | |||
267 | static int do_siocgstampns(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
268 | { | ||
269 | struct compat_timespec __user *up = compat_ptr(arg); | ||
270 | struct timespec kts; | ||
271 | mm_segment_t old_fs = get_fs(); | ||
272 | int err; | ||
273 | |||
274 | set_fs(KERNEL_DS); | ||
275 | err = sys_ioctl(fd, cmd, (unsigned long)&kts); | ||
276 | set_fs(old_fs); | ||
277 | if (!err) { | ||
278 | err = put_user(kts.tv_sec, &up->tv_sec); | ||
279 | err |= __put_user(kts.tv_nsec, &up->tv_nsec); | ||
280 | } | ||
281 | return err; | ||
282 | } | ||
283 | |||
284 | struct ifmap32 { | ||
285 | compat_ulong_t mem_start; | ||
286 | compat_ulong_t mem_end; | ||
287 | unsigned short base_addr; | ||
288 | unsigned char irq; | ||
289 | unsigned char dma; | ||
290 | unsigned char port; | ||
291 | }; | ||
292 | |||
293 | struct ifreq32 { | ||
294 | #define IFHWADDRLEN 6 | ||
295 | #define IFNAMSIZ 16 | ||
296 | union { | ||
297 | char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ | ||
298 | } ifr_ifrn; | ||
299 | union { | ||
300 | struct sockaddr ifru_addr; | ||
301 | struct sockaddr ifru_dstaddr; | ||
302 | struct sockaddr ifru_broadaddr; | ||
303 | struct sockaddr ifru_netmask; | ||
304 | struct sockaddr ifru_hwaddr; | ||
305 | short ifru_flags; | ||
306 | compat_int_t ifru_ivalue; | ||
307 | compat_int_t ifru_mtu; | ||
308 | struct ifmap32 ifru_map; | ||
309 | char ifru_slave[IFNAMSIZ]; /* Just fits the size */ | ||
310 | char ifru_newname[IFNAMSIZ]; | ||
311 | compat_caddr_t ifru_data; | ||
312 | /* XXXX? ifru_settings should be here */ | ||
313 | } ifr_ifru; | ||
314 | }; | ||
315 | |||
316 | struct ifconf32 { | ||
317 | compat_int_t ifc_len; /* size of buffer */ | ||
318 | compat_caddr_t ifcbuf; | ||
319 | }; | ||
320 | |||
321 | static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
322 | { | ||
323 | struct ifreq __user *uifr; | ||
324 | int err; | ||
325 | |||
326 | uifr = compat_alloc_user_space(sizeof(struct ifreq)); | ||
327 | if (copy_in_user(uifr, compat_ptr(arg), sizeof(struct ifreq32))) | ||
328 | return -EFAULT; | ||
329 | |||
330 | err = sys_ioctl(fd, SIOCGIFNAME, (unsigned long)uifr); | ||
331 | if (err) | ||
332 | return err; | ||
333 | |||
334 | if (copy_in_user(compat_ptr(arg), uifr, sizeof(struct ifreq32))) | ||
335 | return -EFAULT; | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
341 | { | ||
342 | struct ifconf32 ifc32; | ||
343 | struct ifconf ifc; | ||
344 | struct ifconf __user *uifc; | ||
345 | struct ifreq32 __user *ifr32; | ||
346 | struct ifreq __user *ifr; | ||
347 | unsigned int i, j; | ||
348 | int err; | ||
349 | |||
350 | if (copy_from_user(&ifc32, compat_ptr(arg), sizeof(struct ifconf32))) | ||
351 | return -EFAULT; | ||
352 | |||
353 | if (ifc32.ifcbuf == 0) { | ||
354 | ifc32.ifc_len = 0; | ||
355 | ifc.ifc_len = 0; | ||
356 | ifc.ifc_req = NULL; | ||
357 | uifc = compat_alloc_user_space(sizeof(struct ifconf)); | ||
358 | } else { | ||
359 | size_t len =((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * | ||
360 | sizeof (struct ifreq); | ||
361 | uifc = compat_alloc_user_space(sizeof(struct ifconf) + len); | ||
362 | ifc.ifc_len = len; | ||
363 | ifr = ifc.ifc_req = (void __user *)(uifc + 1); | ||
364 | ifr32 = compat_ptr(ifc32.ifcbuf); | ||
365 | for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { | ||
366 | if (copy_in_user(ifr, ifr32, sizeof(struct ifreq32))) | ||
367 | return -EFAULT; | ||
368 | ifr++; | ||
369 | ifr32++; | ||
370 | } | ||
371 | } | ||
372 | if (copy_to_user(uifc, &ifc, sizeof(struct ifconf))) | ||
373 | return -EFAULT; | ||
374 | |||
375 | err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)uifc); | ||
376 | if (err) | ||
377 | return err; | ||
378 | |||
379 | if (copy_from_user(&ifc, uifc, sizeof(struct ifconf))) | ||
380 | return -EFAULT; | ||
381 | |||
382 | ifr = ifc.ifc_req; | ||
383 | ifr32 = compat_ptr(ifc32.ifcbuf); | ||
384 | for (i = 0, j = 0; | ||
385 | i + sizeof (struct ifreq32) <= ifc32.ifc_len && j < ifc.ifc_len; | ||
386 | i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { | ||
387 | if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32))) | ||
388 | return -EFAULT; | ||
389 | ifr32++; | ||
390 | ifr++; | ||
391 | } | ||
392 | |||
393 | if (ifc32.ifcbuf == 0) { | ||
394 | /* Translate from 64-bit structure multiple to | ||
395 | * a 32-bit one. | ||
396 | */ | ||
397 | i = ifc.ifc_len; | ||
398 | i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); | ||
399 | ifc32.ifc_len = i; | ||
400 | } else { | ||
401 | ifc32.ifc_len = i; | ||
402 | } | ||
403 | if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32))) | ||
404 | return -EFAULT; | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
410 | { | ||
411 | struct ifreq __user *ifr; | ||
412 | struct ifreq32 __user *ifr32; | ||
413 | u32 data; | ||
414 | void __user *datap; | ||
415 | |||
416 | ifr = compat_alloc_user_space(sizeof(*ifr)); | ||
417 | ifr32 = compat_ptr(arg); | ||
418 | |||
419 | if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) | ||
420 | return -EFAULT; | ||
421 | |||
422 | if (get_user(data, &ifr32->ifr_ifru.ifru_data)) | ||
423 | return -EFAULT; | ||
424 | |||
425 | datap = compat_ptr(data); | ||
426 | if (put_user(datap, &ifr->ifr_ifru.ifru_data)) | ||
427 | return -EFAULT; | ||
428 | |||
429 | return sys_ioctl(fd, cmd, (unsigned long) ifr); | ||
430 | } | ||
431 | |||
432 | static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
433 | { | ||
434 | struct ifreq kifr; | ||
435 | struct ifreq __user *uifr; | ||
436 | struct ifreq32 __user *ifr32 = compat_ptr(arg); | ||
437 | mm_segment_t old_fs; | ||
438 | int err; | ||
439 | u32 data; | ||
440 | void __user *datap; | ||
441 | |||
442 | switch (cmd) { | ||
443 | case SIOCBONDENSLAVE: | ||
444 | case SIOCBONDRELEASE: | ||
445 | case SIOCBONDSETHWADDR: | ||
446 | case SIOCBONDCHANGEACTIVE: | ||
447 | if (copy_from_user(&kifr, ifr32, sizeof(struct ifreq32))) | ||
448 | return -EFAULT; | ||
449 | |||
450 | old_fs = get_fs(); | ||
451 | set_fs (KERNEL_DS); | ||
452 | err = sys_ioctl (fd, cmd, (unsigned long)&kifr); | ||
453 | set_fs (old_fs); | ||
454 | |||
455 | return err; | ||
456 | case SIOCBONDSLAVEINFOQUERY: | ||
457 | case SIOCBONDINFOQUERY: | ||
458 | uifr = compat_alloc_user_space(sizeof(*uifr)); | ||
459 | if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) | ||
460 | return -EFAULT; | ||
461 | |||
462 | if (get_user(data, &ifr32->ifr_ifru.ifru_data)) | ||
463 | return -EFAULT; | ||
464 | |||
465 | datap = compat_ptr(data); | ||
466 | if (put_user(datap, &uifr->ifr_ifru.ifru_data)) | ||
467 | return -EFAULT; | ||
468 | |||
469 | return sys_ioctl (fd, cmd, (unsigned long)uifr); | ||
470 | default: | ||
471 | return -EINVAL; | ||
472 | }; | ||
473 | } | ||
474 | |||
475 | static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
476 | { | ||
477 | struct ifreq __user *u_ifreq64; | ||
478 | struct ifreq32 __user *u_ifreq32 = compat_ptr(arg); | ||
479 | char tmp_buf[IFNAMSIZ]; | ||
480 | void __user *data64; | ||
481 | u32 data32; | ||
482 | |||
483 | if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), | ||
484 | IFNAMSIZ)) | ||
485 | return -EFAULT; | ||
486 | if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) | ||
487 | return -EFAULT; | ||
488 | data64 = compat_ptr(data32); | ||
489 | |||
490 | u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); | ||
491 | |||
492 | /* Don't check these user accesses, just let that get trapped | ||
493 | * in the ioctl handler instead. | ||
494 | */ | ||
495 | if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], | ||
496 | IFNAMSIZ)) | ||
497 | return -EFAULT; | ||
498 | if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) | ||
499 | return -EFAULT; | ||
500 | |||
501 | return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64); | ||
502 | } | ||
503 | |||
504 | static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
505 | { | ||
506 | struct ifreq ifr; | ||
507 | struct ifreq32 __user *uifr32; | ||
508 | struct ifmap32 __user *uifmap32; | ||
509 | mm_segment_t old_fs; | ||
510 | int err; | ||
511 | |||
512 | uifr32 = compat_ptr(arg); | ||
513 | uifmap32 = &uifr32->ifr_ifru.ifru_map; | ||
514 | switch (cmd) { | ||
515 | case SIOCSIFMAP: | ||
516 | err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name)); | ||
517 | err |= __get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); | ||
518 | err |= __get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); | ||
519 | err |= __get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); | ||
520 | err |= __get_user(ifr.ifr_map.irq, &uifmap32->irq); | ||
521 | err |= __get_user(ifr.ifr_map.dma, &uifmap32->dma); | ||
522 | err |= __get_user(ifr.ifr_map.port, &uifmap32->port); | ||
523 | if (err) | ||
524 | return -EFAULT; | ||
525 | break; | ||
526 | case SIOCSHWTSTAMP: | ||
527 | if (copy_from_user(&ifr, uifr32, sizeof(*uifr32))) | ||
528 | return -EFAULT; | ||
529 | ifr.ifr_data = compat_ptr(uifr32->ifr_ifru.ifru_data); | ||
530 | break; | ||
531 | default: | ||
532 | if (copy_from_user(&ifr, uifr32, sizeof(*uifr32))) | ||
533 | return -EFAULT; | ||
534 | break; | ||
535 | } | ||
536 | old_fs = get_fs(); | ||
537 | set_fs (KERNEL_DS); | ||
538 | err = sys_ioctl (fd, cmd, (unsigned long)&ifr); | ||
539 | set_fs (old_fs); | ||
540 | if (!err) { | ||
541 | switch (cmd) { | ||
542 | /* TUNSETIFF is defined as _IOW, it should be _IORW | ||
543 | * as the data is copied back to user space, but that | ||
544 | * cannot be fixed without breaking all existing apps. | ||
545 | */ | ||
546 | case TUNSETIFF: | ||
547 | case TUNGETIFF: | ||
548 | case SIOCGIFFLAGS: | ||
549 | case SIOCGIFMETRIC: | ||
550 | case SIOCGIFMTU: | ||
551 | case SIOCGIFMEM: | ||
552 | case SIOCGIFHWADDR: | ||
553 | case SIOCGIFINDEX: | ||
554 | case SIOCGIFADDR: | ||
555 | case SIOCGIFBRDADDR: | ||
556 | case SIOCGIFDSTADDR: | ||
557 | case SIOCGIFNETMASK: | ||
558 | case SIOCGIFTXQLEN: | ||
559 | if (copy_to_user(uifr32, &ifr, sizeof(*uifr32))) | ||
560 | return -EFAULT; | ||
561 | break; | ||
562 | case SIOCGIFMAP: | ||
563 | err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name)); | ||
564 | err |= __put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); | ||
565 | err |= __put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); | ||
566 | err |= __put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); | ||
567 | err |= __put_user(ifr.ifr_map.irq, &uifmap32->irq); | ||
568 | err |= __put_user(ifr.ifr_map.dma, &uifmap32->dma); | ||
569 | err |= __put_user(ifr.ifr_map.port, &uifmap32->port); | ||
570 | if (err) | ||
571 | err = -EFAULT; | ||
572 | break; | ||
573 | } | ||
574 | } | ||
575 | return err; | ||
576 | } | ||
577 | |||
578 | struct rtentry32 { | ||
579 | u32 rt_pad1; | ||
580 | struct sockaddr rt_dst; /* target address */ | ||
581 | struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ | ||
582 | struct sockaddr rt_genmask; /* target network mask (IP) */ | ||
583 | unsigned short rt_flags; | ||
584 | short rt_pad2; | ||
585 | u32 rt_pad3; | ||
586 | unsigned char rt_tos; | ||
587 | unsigned char rt_class; | ||
588 | short rt_pad4; | ||
589 | short rt_metric; /* +1 for binary compatibility! */ | ||
590 | /* char * */ u32 rt_dev; /* forcing the device at add */ | ||
591 | u32 rt_mtu; /* per route MTU/Window */ | ||
592 | u32 rt_window; /* Window clamping */ | ||
593 | unsigned short rt_irtt; /* Initial RTT */ | ||
594 | |||
595 | }; | ||
596 | |||
597 | struct in6_rtmsg32 { | ||
598 | struct in6_addr rtmsg_dst; | ||
599 | struct in6_addr rtmsg_src; | ||
600 | struct in6_addr rtmsg_gateway; | ||
601 | u32 rtmsg_type; | ||
602 | u16 rtmsg_dst_len; | ||
603 | u16 rtmsg_src_len; | ||
604 | u32 rtmsg_metric; | ||
605 | u32 rtmsg_info; | ||
606 | u32 rtmsg_flags; | ||
607 | s32 rtmsg_ifindex; | ||
608 | }; | ||
609 | |||
610 | static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
611 | { | ||
612 | int ret; | ||
613 | void *r = NULL; | ||
614 | struct in6_rtmsg r6; | ||
615 | struct rtentry r4; | ||
616 | char devname[16]; | ||
617 | u32 rtdev; | ||
618 | mm_segment_t old_fs = get_fs(); | ||
619 | |||
620 | struct socket *mysock = sockfd_lookup(fd, &ret); | ||
621 | |||
622 | if (mysock && mysock->sk && mysock->sk->sk_family == AF_INET6) { /* ipv6 */ | ||
623 | struct in6_rtmsg32 __user *ur6 = compat_ptr(arg); | ||
624 | ret = copy_from_user (&r6.rtmsg_dst, &(ur6->rtmsg_dst), | ||
625 | 3 * sizeof(struct in6_addr)); | ||
626 | ret |= __get_user (r6.rtmsg_type, &(ur6->rtmsg_type)); | ||
627 | ret |= __get_user (r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len)); | ||
628 | ret |= __get_user (r6.rtmsg_src_len, &(ur6->rtmsg_src_len)); | ||
629 | ret |= __get_user (r6.rtmsg_metric, &(ur6->rtmsg_metric)); | ||
630 | ret |= __get_user (r6.rtmsg_info, &(ur6->rtmsg_info)); | ||
631 | ret |= __get_user (r6.rtmsg_flags, &(ur6->rtmsg_flags)); | ||
632 | ret |= __get_user (r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex)); | ||
633 | |||
634 | r = (void *) &r6; | ||
635 | } else { /* ipv4 */ | ||
636 | struct rtentry32 __user *ur4 = compat_ptr(arg); | ||
637 | ret = copy_from_user (&r4.rt_dst, &(ur4->rt_dst), | ||
638 | 3 * sizeof(struct sockaddr)); | ||
639 | ret |= __get_user (r4.rt_flags, &(ur4->rt_flags)); | ||
640 | ret |= __get_user (r4.rt_metric, &(ur4->rt_metric)); | ||
641 | ret |= __get_user (r4.rt_mtu, &(ur4->rt_mtu)); | ||
642 | ret |= __get_user (r4.rt_window, &(ur4->rt_window)); | ||
643 | ret |= __get_user (r4.rt_irtt, &(ur4->rt_irtt)); | ||
644 | ret |= __get_user (rtdev, &(ur4->rt_dev)); | ||
645 | if (rtdev) { | ||
646 | ret |= copy_from_user (devname, compat_ptr(rtdev), 15); | ||
647 | r4.rt_dev = devname; devname[15] = 0; | ||
648 | } else | ||
649 | r4.rt_dev = NULL; | ||
650 | |||
651 | r = (void *) &r4; | ||
652 | } | ||
653 | |||
654 | if (ret) { | ||
655 | ret = -EFAULT; | ||
656 | goto out; | ||
657 | } | ||
658 | |||
659 | set_fs (KERNEL_DS); | ||
660 | ret = sys_ioctl (fd, cmd, (unsigned long) r); | ||
661 | set_fs (old_fs); | ||
662 | |||
663 | out: | ||
664 | if (mysock) | ||
665 | sockfd_put(mysock); | ||
666 | |||
667 | return ret; | ||
668 | } | ||
669 | #endif | ||
670 | |||
671 | #ifdef CONFIG_BLOCK | 249 | #ifdef CONFIG_BLOCK |
672 | typedef struct sg_io_hdr32 { | 250 | typedef struct sg_io_hdr32 { |
673 | compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ | 251 | compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ |
@@ -1212,170 +790,6 @@ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long a | |||
1212 | return err; | 790 | return err; |
1213 | } | 791 | } |
1214 | 792 | ||
1215 | struct atmif_sioc32 { | ||
1216 | compat_int_t number; | ||
1217 | compat_int_t length; | ||
1218 | compat_caddr_t arg; | ||
1219 | }; | ||
1220 | |||
1221 | struct atm_iobuf32 { | ||
1222 | compat_int_t length; | ||
1223 | compat_caddr_t buffer; | ||
1224 | }; | ||
1225 | |||
1226 | #define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32) | ||
1227 | #define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32) | ||
1228 | #define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32) | ||
1229 | #define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32) | ||
1230 | #define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32) | ||
1231 | #define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32) | ||
1232 | #define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32) | ||
1233 | #define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32) | ||
1234 | #define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32) | ||
1235 | #define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32) | ||
1236 | #define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32) | ||
1237 | #define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32) | ||
1238 | #define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32) | ||
1239 | #define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32) | ||
1240 | #define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32) | ||
1241 | #define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32) | ||
1242 | #define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32) | ||
1243 | |||
1244 | static struct { | ||
1245 | unsigned int cmd32; | ||
1246 | unsigned int cmd; | ||
1247 | } atm_ioctl_map[] = { | ||
1248 | { ATM_GETLINKRATE32, ATM_GETLINKRATE }, | ||
1249 | { ATM_GETNAMES32, ATM_GETNAMES }, | ||
1250 | { ATM_GETTYPE32, ATM_GETTYPE }, | ||
1251 | { ATM_GETESI32, ATM_GETESI }, | ||
1252 | { ATM_GETADDR32, ATM_GETADDR }, | ||
1253 | { ATM_RSTADDR32, ATM_RSTADDR }, | ||
1254 | { ATM_ADDADDR32, ATM_ADDADDR }, | ||
1255 | { ATM_DELADDR32, ATM_DELADDR }, | ||
1256 | { ATM_GETCIRANGE32, ATM_GETCIRANGE }, | ||
1257 | { ATM_SETCIRANGE32, ATM_SETCIRANGE }, | ||
1258 | { ATM_SETESI32, ATM_SETESI }, | ||
1259 | { ATM_SETESIF32, ATM_SETESIF }, | ||
1260 | { ATM_GETSTAT32, ATM_GETSTAT }, | ||
1261 | { ATM_GETSTATZ32, ATM_GETSTATZ }, | ||
1262 | { ATM_GETLOOP32, ATM_GETLOOP }, | ||
1263 | { ATM_SETLOOP32, ATM_SETLOOP }, | ||
1264 | { ATM_QUERYLOOP32, ATM_QUERYLOOP } | ||
1265 | }; | ||
1266 | |||
1267 | #define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map) | ||
1268 | |||
1269 | static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
1270 | { | ||
1271 | struct atm_iobuf __user *iobuf; | ||
1272 | struct atm_iobuf32 __user *iobuf32; | ||
1273 | u32 data; | ||
1274 | void __user *datap; | ||
1275 | int len, err; | ||
1276 | |||
1277 | iobuf = compat_alloc_user_space(sizeof(*iobuf)); | ||
1278 | iobuf32 = compat_ptr(arg); | ||
1279 | |||
1280 | if (get_user(len, &iobuf32->length) || | ||
1281 | get_user(data, &iobuf32->buffer)) | ||
1282 | return -EFAULT; | ||
1283 | datap = compat_ptr(data); | ||
1284 | if (put_user(len, &iobuf->length) || | ||
1285 | put_user(datap, &iobuf->buffer)) | ||
1286 | return -EFAULT; | ||
1287 | |||
1288 | err = sys_ioctl(fd, cmd, (unsigned long)iobuf); | ||
1289 | |||
1290 | if (!err) { | ||
1291 | if (copy_in_user(&iobuf32->length, &iobuf->length, | ||
1292 | sizeof(int))) | ||
1293 | err = -EFAULT; | ||
1294 | } | ||
1295 | |||
1296 | return err; | ||
1297 | } | ||
1298 | |||
1299 | static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
1300 | { | ||
1301 | struct atmif_sioc __user *sioc; | ||
1302 | struct atmif_sioc32 __user *sioc32; | ||
1303 | u32 data; | ||
1304 | void __user *datap; | ||
1305 | int err; | ||
1306 | |||
1307 | sioc = compat_alloc_user_space(sizeof(*sioc)); | ||
1308 | sioc32 = compat_ptr(arg); | ||
1309 | |||
1310 | if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) || | ||
1311 | get_user(data, &sioc32->arg)) | ||
1312 | return -EFAULT; | ||
1313 | datap = compat_ptr(data); | ||
1314 | if (put_user(datap, &sioc->arg)) | ||
1315 | return -EFAULT; | ||
1316 | |||
1317 | err = sys_ioctl(fd, cmd, (unsigned long) sioc); | ||
1318 | |||
1319 | if (!err) { | ||
1320 | if (copy_in_user(&sioc32->length, &sioc->length, | ||
1321 | sizeof(int))) | ||
1322 | err = -EFAULT; | ||
1323 | } | ||
1324 | return err; | ||
1325 | } | ||
1326 | |||
1327 | static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) | ||
1328 | { | ||
1329 | int i; | ||
1330 | unsigned int cmd = 0; | ||
1331 | |||
1332 | switch (cmd32) { | ||
1333 | case SONET_GETSTAT: | ||
1334 | case SONET_GETSTATZ: | ||
1335 | case SONET_GETDIAG: | ||
1336 | case SONET_SETDIAG: | ||
1337 | case SONET_CLRDIAG: | ||
1338 | case SONET_SETFRAMING: | ||
1339 | case SONET_GETFRAMING: | ||
1340 | case SONET_GETFRSENSE: | ||
1341 | return do_atmif_sioc(fd, cmd32, arg); | ||
1342 | } | ||
1343 | |||
1344 | for (i = 0; i < NR_ATM_IOCTL; i++) { | ||
1345 | if (cmd32 == atm_ioctl_map[i].cmd32) { | ||
1346 | cmd = atm_ioctl_map[i].cmd; | ||
1347 | break; | ||
1348 | } | ||
1349 | } | ||
1350 | if (i == NR_ATM_IOCTL) | ||
1351 | return -EINVAL; | ||
1352 | |||
1353 | switch (cmd) { | ||
1354 | case ATM_GETNAMES: | ||
1355 | return do_atm_iobuf(fd, cmd, arg); | ||
1356 | |||
1357 | case ATM_GETLINKRATE: | ||
1358 | case ATM_GETTYPE: | ||
1359 | case ATM_GETESI: | ||
1360 | case ATM_GETADDR: | ||
1361 | case ATM_RSTADDR: | ||
1362 | case ATM_ADDADDR: | ||
1363 | case ATM_DELADDR: | ||
1364 | case ATM_GETCIRANGE: | ||
1365 | case ATM_SETCIRANGE: | ||
1366 | case ATM_SETESI: | ||
1367 | case ATM_SETESIF: | ||
1368 | case ATM_GETSTAT: | ||
1369 | case ATM_GETSTATZ: | ||
1370 | case ATM_GETLOOP: | ||
1371 | case ATM_SETLOOP: | ||
1372 | case ATM_QUERYLOOP: | ||
1373 | return do_atmif_sioc(fd, cmd, arg); | ||
1374 | } | ||
1375 | |||
1376 | return -EINVAL; | ||
1377 | } | ||
1378 | |||
1379 | static __used int | 793 | static __used int |
1380 | ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) | 794 | ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) |
1381 | { | 795 | { |
@@ -1718,21 +1132,6 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a | |||
1718 | return sys_ioctl(fd, cmd, (unsigned long)tdata); | 1132 | return sys_ioctl(fd, cmd, (unsigned long)tdata); |
1719 | } | 1133 | } |
1720 | 1134 | ||
1721 | /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE | ||
1722 | * for some operations; this forces use of the newer bridge-utils that | ||
1723 | * use compatible ioctls | ||
1724 | */ | ||
1725 | static int old_bridge_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
1726 | { | ||
1727 | u32 tmp; | ||
1728 | |||
1729 | if (get_user(tmp, (u32 __user *) arg)) | ||
1730 | return -EFAULT; | ||
1731 | if (tmp == BRCTL_GET_VERSION) | ||
1732 | return BRCTL_VERSION + 1; | ||
1733 | return -EINVAL; | ||
1734 | } | ||
1735 | |||
1736 | #define RTC_IRQP_READ32 _IOR('p', 0x0b, compat_ulong_t) | 1135 | #define RTC_IRQP_READ32 _IOR('p', 0x0b, compat_ulong_t) |
1737 | #define RTC_IRQP_SET32 _IOW('p', 0x0c, compat_ulong_t) | 1136 | #define RTC_IRQP_SET32 _IOW('p', 0x0c, compat_ulong_t) |
1738 | #define RTC_EPOCH_READ32 _IOR('p', 0x0d, compat_ulong_t) | 1137 | #define RTC_EPOCH_READ32 _IOR('p', 0x0d, compat_ulong_t) |
@@ -1979,18 +1378,6 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND) | |||
1979 | COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST) | 1378 | COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST) |
1980 | COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI) | 1379 | COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI) |
1981 | #endif | 1380 | #endif |
1982 | /* Big T */ | ||
1983 | COMPATIBLE_IOCTL(TUNSETNOCSUM) | ||
1984 | COMPATIBLE_IOCTL(TUNSETDEBUG) | ||
1985 | COMPATIBLE_IOCTL(TUNSETPERSIST) | ||
1986 | COMPATIBLE_IOCTL(TUNSETOWNER) | ||
1987 | COMPATIBLE_IOCTL(TUNSETLINK) | ||
1988 | COMPATIBLE_IOCTL(TUNSETGROUP) | ||
1989 | COMPATIBLE_IOCTL(TUNGETFEATURES) | ||
1990 | COMPATIBLE_IOCTL(TUNSETOFFLOAD) | ||
1991 | COMPATIBLE_IOCTL(TUNSETTXFILTER) | ||
1992 | COMPATIBLE_IOCTL(TUNGETSNDBUF) | ||
1993 | COMPATIBLE_IOCTL(TUNSETSNDBUF) | ||
1994 | /* Big V */ | 1381 | /* Big V */ |
1995 | COMPATIBLE_IOCTL(VT_SETMODE) | 1382 | COMPATIBLE_IOCTL(VT_SETMODE) |
1996 | COMPATIBLE_IOCTL(VT_GETMODE) | 1383 | COMPATIBLE_IOCTL(VT_GETMODE) |
@@ -2032,30 +1419,6 @@ COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */ | |||
2032 | COMPATIBLE_IOCTL(MTIOCTOP) | 1419 | COMPATIBLE_IOCTL(MTIOCTOP) |
2033 | /* Socket level stuff */ | 1420 | /* Socket level stuff */ |
2034 | COMPATIBLE_IOCTL(FIOQSIZE) | 1421 | COMPATIBLE_IOCTL(FIOQSIZE) |
2035 | COMPATIBLE_IOCTL(FIOSETOWN) | ||
2036 | COMPATIBLE_IOCTL(SIOCSPGRP) | ||
2037 | COMPATIBLE_IOCTL(FIOGETOWN) | ||
2038 | COMPATIBLE_IOCTL(SIOCGPGRP) | ||
2039 | COMPATIBLE_IOCTL(SIOCATMARK) | ||
2040 | COMPATIBLE_IOCTL(SIOCSIFLINK) | ||
2041 | COMPATIBLE_IOCTL(SIOCSIFENCAP) | ||
2042 | COMPATIBLE_IOCTL(SIOCGIFENCAP) | ||
2043 | COMPATIBLE_IOCTL(SIOCSIFNAME) | ||
2044 | COMPATIBLE_IOCTL(SIOCSARP) | ||
2045 | COMPATIBLE_IOCTL(SIOCGARP) | ||
2046 | COMPATIBLE_IOCTL(SIOCDARP) | ||
2047 | COMPATIBLE_IOCTL(SIOCSRARP) | ||
2048 | COMPATIBLE_IOCTL(SIOCGRARP) | ||
2049 | COMPATIBLE_IOCTL(SIOCDRARP) | ||
2050 | COMPATIBLE_IOCTL(SIOCADDDLCI) | ||
2051 | COMPATIBLE_IOCTL(SIOCDELDLCI) | ||
2052 | COMPATIBLE_IOCTL(SIOCGMIIPHY) | ||
2053 | COMPATIBLE_IOCTL(SIOCGMIIREG) | ||
2054 | COMPATIBLE_IOCTL(SIOCSMIIREG) | ||
2055 | COMPATIBLE_IOCTL(SIOCGIFVLAN) | ||
2056 | COMPATIBLE_IOCTL(SIOCSIFVLAN) | ||
2057 | COMPATIBLE_IOCTL(SIOCBRADDBR) | ||
2058 | COMPATIBLE_IOCTL(SIOCBRDELBR) | ||
2059 | #ifdef CONFIG_BLOCK | 1422 | #ifdef CONFIG_BLOCK |
2060 | /* SG stuff */ | 1423 | /* SG stuff */ |
2061 | COMPATIBLE_IOCTL(SG_SET_TIMEOUT) | 1424 | COMPATIBLE_IOCTL(SG_SET_TIMEOUT) |
@@ -2311,22 +1674,6 @@ COMPATIBLE_IOCTL(RAW_SETBIND) | |||
2311 | COMPATIBLE_IOCTL(RAW_GETBIND) | 1674 | COMPATIBLE_IOCTL(RAW_GETBIND) |
2312 | /* SMB ioctls which do not need any translations */ | 1675 | /* SMB ioctls which do not need any translations */ |
2313 | COMPATIBLE_IOCTL(SMB_IOC_NEWCONN) | 1676 | COMPATIBLE_IOCTL(SMB_IOC_NEWCONN) |
2314 | /* Little a */ | ||
2315 | COMPATIBLE_IOCTL(ATMSIGD_CTRL) | ||
2316 | COMPATIBLE_IOCTL(ATMARPD_CTRL) | ||
2317 | COMPATIBLE_IOCTL(ATMLEC_CTRL) | ||
2318 | COMPATIBLE_IOCTL(ATMLEC_MCAST) | ||
2319 | COMPATIBLE_IOCTL(ATMLEC_DATA) | ||
2320 | COMPATIBLE_IOCTL(ATM_SETSC) | ||
2321 | COMPATIBLE_IOCTL(SIOCSIFATMTCP) | ||
2322 | COMPATIBLE_IOCTL(SIOCMKCLIP) | ||
2323 | COMPATIBLE_IOCTL(ATMARP_MKIP) | ||
2324 | COMPATIBLE_IOCTL(ATMARP_SETENTRY) | ||
2325 | COMPATIBLE_IOCTL(ATMARP_ENCAP) | ||
2326 | COMPATIBLE_IOCTL(ATMTCP_CREATE) | ||
2327 | COMPATIBLE_IOCTL(ATMTCP_REMOVE) | ||
2328 | COMPATIBLE_IOCTL(ATMMPC_CTRL) | ||
2329 | COMPATIBLE_IOCTL(ATMMPC_DATA) | ||
2330 | /* Watchdog */ | 1677 | /* Watchdog */ |
2331 | COMPATIBLE_IOCTL(WDIOC_GETSUPPORT) | 1678 | COMPATIBLE_IOCTL(WDIOC_GETSUPPORT) |
2332 | COMPATIBLE_IOCTL(WDIOC_GETSTATUS) | 1679 | COMPATIBLE_IOCTL(WDIOC_GETSTATUS) |
@@ -2532,63 +1879,6 @@ COMPATIBLE_IOCTL(JSIOCGBUTTONS) | |||
2532 | COMPATIBLE_IOCTL(JSIOCGNAME(0)) | 1879 | COMPATIBLE_IOCTL(JSIOCGNAME(0)) |
2533 | 1880 | ||
2534 | /* now things that need handlers */ | 1881 | /* now things that need handlers */ |
2535 | #ifdef CONFIG_NET | ||
2536 | HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) | ||
2537 | HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) | ||
2538 | HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc) | ||
2539 | HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc) | ||
2540 | HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc) | ||
2541 | HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc) | ||
2542 | HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc) | ||
2543 | HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc) | ||
2544 | HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc) | ||
2545 | HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc) | ||
2546 | HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc) | ||
2547 | HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc) | ||
2548 | HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc) | ||
2549 | HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc) | ||
2550 | HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc) | ||
2551 | HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc) | ||
2552 | HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc) | ||
2553 | HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc) | ||
2554 | HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc) | ||
2555 | HANDLE_IOCTL(SIOCSIFHWBROADCAST, dev_ifsioc) | ||
2556 | HANDLE_IOCTL(SIOCSHWTSTAMP, dev_ifsioc) | ||
2557 | |||
2558 | /* ioctls used by appletalk ddp.c */ | ||
2559 | HANDLE_IOCTL(SIOCATALKDIFADDR, dev_ifsioc) | ||
2560 | HANDLE_IOCTL(SIOCDIFADDR, dev_ifsioc) | ||
2561 | HANDLE_IOCTL(SIOCSARP, dev_ifsioc) | ||
2562 | HANDLE_IOCTL(SIOCDARP, dev_ifsioc) | ||
2563 | |||
2564 | HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc) | ||
2565 | HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc) | ||
2566 | HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc) | ||
2567 | HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc) | ||
2568 | HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc) | ||
2569 | HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc) | ||
2570 | HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc) | ||
2571 | HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc) | ||
2572 | HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) | ||
2573 | HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) | ||
2574 | HANDLE_IOCTL(TUNSETIFF, dev_ifsioc) | ||
2575 | HANDLE_IOCTL(TUNGETIFF, dev_ifsioc) | ||
2576 | HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl) | ||
2577 | HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl) | ||
2578 | HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl) | ||
2579 | HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl) | ||
2580 | HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl) | ||
2581 | HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl) | ||
2582 | HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl) | ||
2583 | HANDLE_IOCTL(SIOCADDRT, routing_ioctl) | ||
2584 | HANDLE_IOCTL(SIOCDELRT, routing_ioctl) | ||
2585 | HANDLE_IOCTL(SIOCBRADDIF, dev_ifsioc) | ||
2586 | HANDLE_IOCTL(SIOCBRDELIF, dev_ifsioc) | ||
2587 | /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ | ||
2588 | HANDLE_IOCTL(SIOCRTMSG, ret_einval) | ||
2589 | HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) | ||
2590 | HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns) | ||
2591 | #endif | ||
2592 | #ifdef CONFIG_BLOCK | 1882 | #ifdef CONFIG_BLOCK |
2593 | HANDLE_IOCTL(SG_IO,sg_ioctl_trans) | 1883 | HANDLE_IOCTL(SG_IO,sg_ioctl_trans) |
2594 | HANDLE_IOCTL(SG_GET_REQUEST_TABLE, sg_grt_trans) | 1884 | HANDLE_IOCTL(SG_GET_REQUEST_TABLE, sg_grt_trans) |
@@ -2613,31 +1903,6 @@ HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl) | |||
2613 | /* One SMB ioctl needs translations. */ | 1903 | /* One SMB ioctl needs translations. */ |
2614 | #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t) | 1904 | #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t) |
2615 | HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid) | 1905 | HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid) |
2616 | HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl) | ||
2617 | HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl) | ||
2618 | HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl) | ||
2619 | HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl) | ||
2620 | HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl) | ||
2621 | HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl) | ||
2622 | HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl) | ||
2623 | HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl) | ||
2624 | HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl) | ||
2625 | HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl) | ||
2626 | HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl) | ||
2627 | HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl) | ||
2628 | HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl) | ||
2629 | HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl) | ||
2630 | HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl) | ||
2631 | HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl) | ||
2632 | HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl) | ||
2633 | HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl) | ||
2634 | HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl) | ||
2635 | HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl) | ||
2636 | HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl) | ||
2637 | HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl) | ||
2638 | HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl) | ||
2639 | HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) | ||
2640 | HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) | ||
2641 | /* block stuff */ | 1906 | /* block stuff */ |
2642 | #ifdef CONFIG_BLOCK | 1907 | #ifdef CONFIG_BLOCK |
2643 | /* loop */ | 1908 | /* loop */ |
@@ -2655,7 +1920,7 @@ COMPATIBLE_IOCTL(TIOCSLTC) | |||
2655 | #endif | 1920 | #endif |
2656 | #ifdef TIOCSTART | 1921 | #ifdef TIOCSTART |
2657 | /* | 1922 | /* |
2658 | * For these two we have defintions in ioctls.h and/or termios.h on | 1923 | * For these two we have definitions in ioctls.h and/or termios.h on |
2659 | * some architectures but no actual implemention. Some applications | 1924 | * some architectures but no actual implemention. Some applications |
2660 | * like bash call them if they are defined in the headers, so we provide | 1925 | * like bash call them if they are defined in the headers, so we provide |
2661 | * entries here to avoid syslog message spew. | 1926 | * entries here to avoid syslog message spew. |
@@ -2672,11 +1937,7 @@ COMPATIBLE_IOCTL(USBDEVFS_IOCTL32) | |||
2672 | HANDLE_IOCTL(I2C_FUNCS, w_long) | 1937 | HANDLE_IOCTL(I2C_FUNCS, w_long) |
2673 | HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl) | 1938 | HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl) |
2674 | HANDLE_IOCTL(I2C_SMBUS, do_i2c_smbus_ioctl) | 1939 | HANDLE_IOCTL(I2C_SMBUS, do_i2c_smbus_ioctl) |
2675 | /* bridge */ | ||
2676 | HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl) | ||
2677 | HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl) | ||
2678 | /* Not implemented in the native kernel */ | 1940 | /* Not implemented in the native kernel */ |
2679 | IGNORE_IOCTL(SIOCGIFCOUNT) | ||
2680 | HANDLE_IOCTL(RTC_IRQP_READ32, rtc_ioctl) | 1941 | HANDLE_IOCTL(RTC_IRQP_READ32, rtc_ioctl) |
2681 | HANDLE_IOCTL(RTC_IRQP_SET32, rtc_ioctl) | 1942 | HANDLE_IOCTL(RTC_IRQP_SET32, rtc_ioctl) |
2682 | HANDLE_IOCTL(RTC_EPOCH_READ32, rtc_ioctl) | 1943 | HANDLE_IOCTL(RTC_EPOCH_READ32, rtc_ioctl) |
@@ -2831,12 +2092,6 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, | |||
2831 | goto found_handler; | 2092 | goto found_handler; |
2832 | } | 2093 | } |
2833 | 2094 | ||
2834 | #ifdef CONFIG_NET | ||
2835 | if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) && | ||
2836 | cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { | ||
2837 | error = siocdevprivate_ioctl(fd, cmd, arg); | ||
2838 | } else | ||
2839 | #endif | ||
2840 | { | 2095 | { |
2841 | static int count; | 2096 | static int count; |
2842 | 2097 | ||
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index d22438ef7674..0d23b52dd22c 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -184,7 +184,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode, | |||
184 | /** | 184 | /** |
185 | * debugfs_create_file - create a file in the debugfs filesystem | 185 | * debugfs_create_file - create a file in the debugfs filesystem |
186 | * @name: a pointer to a string containing the name of the file to create. | 186 | * @name: a pointer to a string containing the name of the file to create. |
187 | * @mode: the permission that the file should have | 187 | * @mode: the permission that the file should have. |
188 | * @parent: a pointer to the parent dentry for this file. This should be a | 188 | * @parent: a pointer to the parent dentry for this file. This should be a |
189 | * directory dentry if set. If this paramater is NULL, then the | 189 | * directory dentry if set. If this paramater is NULL, then the |
190 | * file will be created in the root of the debugfs filesystem. | 190 | * file will be created in the root of the debugfs filesystem. |
@@ -195,8 +195,8 @@ static int debugfs_create_by_name(const char *name, mode_t mode, | |||
195 | * this file. | 195 | * this file. |
196 | * | 196 | * |
197 | * This is the basic "create a file" function for debugfs. It allows for a | 197 | * This is the basic "create a file" function for debugfs. It allows for a |
198 | * wide range of flexibility in createing a file, or a directory (if you | 198 | * wide range of flexibility in creating a file, or a directory (if you want |
199 | * want to create a directory, the debugfs_create_dir() function is | 199 | * to create a directory, the debugfs_create_dir() function is |
200 | * recommended to be used instead.) | 200 | * recommended to be used instead.) |
201 | * | 201 | * |
202 | * This function will return a pointer to a dentry if it succeeds. This | 202 | * This function will return a pointer to a dentry if it succeeds. This |
diff --git a/fs/direct-io.c b/fs/direct-io.c index 8b10b87dc01a..b912270942fa 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
@@ -1028,9 +1028,6 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, | |||
1028 | if (dio->bio) | 1028 | if (dio->bio) |
1029 | dio_bio_submit(dio); | 1029 | dio_bio_submit(dio); |
1030 | 1030 | ||
1031 | /* All IO is now issued, send it on its way */ | ||
1032 | blk_run_address_space(inode->i_mapping); | ||
1033 | |||
1034 | /* | 1031 | /* |
1035 | * It is possible that, we return short IO due to end of file. | 1032 | * It is possible that, we return short IO due to end of file. |
1036 | * In that case, we need to release all the pages we got hold on. | 1033 | * In that case, we need to release all the pages we got hold on. |
@@ -1057,8 +1054,11 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, | |||
1057 | ((rw & READ) || (dio->result == dio->size))) | 1054 | ((rw & READ) || (dio->result == dio->size))) |
1058 | ret = -EIOCBQUEUED; | 1055 | ret = -EIOCBQUEUED; |
1059 | 1056 | ||
1060 | if (ret != -EIOCBQUEUED) | 1057 | if (ret != -EIOCBQUEUED) { |
1058 | /* All IO is now issued, send it on its way */ | ||
1059 | blk_run_address_space(inode->i_mapping); | ||
1061 | dio_await_completion(dio); | 1060 | dio_await_completion(dio); |
1061 | } | ||
1062 | 1062 | ||
1063 | /* | 1063 | /* |
1064 | * Sync will always be dropping the final ref and completing the | 1064 | * Sync will always be dropping the final ref and completing the |
@@ -1124,7 +1124,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, | |||
1124 | int acquire_i_mutex = 0; | 1124 | int acquire_i_mutex = 0; |
1125 | 1125 | ||
1126 | if (rw & WRITE) | 1126 | if (rw & WRITE) |
1127 | rw = WRITE_ODIRECT; | 1127 | rw = WRITE_ODIRECT_PLUG; |
1128 | 1128 | ||
1129 | if (bdev) | 1129 | if (bdev) |
1130 | bdev_blkbits = blksize_bits(bdev_logical_block_size(bdev)); | 1130 | bdev_blkbits = blksize_bits(bdev_logical_block_size(bdev)); |
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index 2863deb178e2..b5f89aef3b29 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c | |||
@@ -143,7 +143,7 @@ out: | |||
143 | } | 143 | } |
144 | EXPORT_SYMBOL_GPL(dlm_posix_lock); | 144 | EXPORT_SYMBOL_GPL(dlm_posix_lock); |
145 | 145 | ||
146 | /* Returns failure iff a succesful lock operation should be canceled */ | 146 | /* Returns failure iff a successful lock operation should be canceled */ |
147 | static int dlm_plock_callback(struct plock_op *op) | 147 | static int dlm_plock_callback(struct plock_op *op) |
148 | { | 148 | { |
149 | struct file *file; | 149 | struct file *file; |
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 085c5c063420..366c503f9657 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
@@ -251,10 +251,10 @@ ctl_table epoll_table[] = { | |||
251 | .data = &max_user_watches, | 251 | .data = &max_user_watches, |
252 | .maxlen = sizeof(int), | 252 | .maxlen = sizeof(int), |
253 | .mode = 0644, | 253 | .mode = 0644, |
254 | .proc_handler = &proc_dointvec_minmax, | 254 | .proc_handler = proc_dointvec_minmax, |
255 | .extra1 = &zero, | 255 | .extra1 = &zero, |
256 | }, | 256 | }, |
257 | { .ctl_name = 0 } | 257 | { } |
258 | }; | 258 | }; |
259 | #endif /* CONFIG_SYSCTL */ | 259 | #endif /* CONFIG_SYSCTL */ |
260 | 260 | ||
@@ -46,7 +46,6 @@ | |||
46 | #include <linux/proc_fs.h> | 46 | #include <linux/proc_fs.h> |
47 | #include <linux/mount.h> | 47 | #include <linux/mount.h> |
48 | #include <linux/security.h> | 48 | #include <linux/security.h> |
49 | #include <linux/ima.h> | ||
50 | #include <linux/syscalls.h> | 49 | #include <linux/syscalls.h> |
51 | #include <linux/tsacct_kern.h> | 50 | #include <linux/tsacct_kern.h> |
52 | #include <linux/cn_proc.h> | 51 | #include <linux/cn_proc.h> |
@@ -1209,9 +1208,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
1209 | retval = security_bprm_check(bprm); | 1208 | retval = security_bprm_check(bprm); |
1210 | if (retval) | 1209 | if (retval) |
1211 | return retval; | 1210 | return retval; |
1212 | retval = ima_bprm_check(bprm); | ||
1213 | if (retval) | ||
1214 | return retval; | ||
1215 | 1211 | ||
1216 | /* kernel module loader fixup */ | 1212 | /* kernel module loader fixup */ |
1217 | /* so we don't try to load run modprobe in kernel space. */ | 1213 | /* so we don't try to load run modprobe in kernel space. */ |
diff --git a/fs/exofs/Kbuild b/fs/exofs/Kbuild index cc2d22db119c..2d0f757fda3e 100644 --- a/fs/exofs/Kbuild +++ b/fs/exofs/Kbuild | |||
@@ -12,5 +12,5 @@ | |||
12 | # Kbuild - Gets included from the Kernels Makefile and build system | 12 | # Kbuild - Gets included from the Kernels Makefile and build system |
13 | # | 13 | # |
14 | 14 | ||
15 | exofs-y := osd.o inode.o file.o symlink.o namei.o dir.o super.o | 15 | exofs-y := ios.o inode.o file.o symlink.o namei.o dir.o super.o |
16 | obj-$(CONFIG_EXOFS_FS) += exofs.o | 16 | obj-$(CONFIG_EXOFS_FS) += exofs.o |
diff --git a/fs/exofs/common.h b/fs/exofs/common.h index c6718e4817fe..b1b178e61718 100644 --- a/fs/exofs/common.h +++ b/fs/exofs/common.h | |||
@@ -49,6 +49,7 @@ | |||
49 | #define EXOFS_MIN_PID 0x10000 /* Smallest partition ID */ | 49 | #define EXOFS_MIN_PID 0x10000 /* Smallest partition ID */ |
50 | #define EXOFS_OBJ_OFF 0x10000 /* offset for objects */ | 50 | #define EXOFS_OBJ_OFF 0x10000 /* offset for objects */ |
51 | #define EXOFS_SUPER_ID 0x10000 /* object ID for on-disk superblock */ | 51 | #define EXOFS_SUPER_ID 0x10000 /* object ID for on-disk superblock */ |
52 | #define EXOFS_DEVTABLE_ID 0x10001 /* object ID for on-disk device table */ | ||
52 | #define EXOFS_ROOT_ID 0x10002 /* object ID for root directory */ | 53 | #define EXOFS_ROOT_ID 0x10002 /* object ID for root directory */ |
53 | 54 | ||
54 | /* exofs Application specific page/attribute */ | 55 | /* exofs Application specific page/attribute */ |
@@ -78,17 +79,67 @@ enum { | |||
78 | #define EXOFS_SUPER_MAGIC 0x5DF5 | 79 | #define EXOFS_SUPER_MAGIC 0x5DF5 |
79 | 80 | ||
80 | /* | 81 | /* |
81 | * The file system control block - stored in an object's data (mainly, the one | 82 | * The file system control block - stored in object EXOFS_SUPER_ID's data. |
82 | * with ID EXOFS_SUPER_ID). This is where the in-memory superblock is stored | 83 | * This is where the in-memory superblock is stored on disk. |
83 | * on disk. Right now it just has a magic value, which is basically a sanity | ||
84 | * check on our ability to communicate with the object store. | ||
85 | */ | 84 | */ |
85 | enum {EXOFS_FSCB_VER = 1, EXOFS_DT_VER = 1}; | ||
86 | struct exofs_fscb { | 86 | struct exofs_fscb { |
87 | __le64 s_nextid; /* Highest object ID used */ | 87 | __le64 s_nextid; /* Highest object ID used */ |
88 | __le32 s_numfiles; /* Number of files on fs */ | 88 | __le64 s_numfiles; /* Number of files on fs */ |
89 | __le32 s_version; /* == EXOFS_FSCB_VER */ | ||
89 | __le16 s_magic; /* Magic signature */ | 90 | __le16 s_magic; /* Magic signature */ |
90 | __le16 s_newfs; /* Non-zero if this is a new fs */ | 91 | __le16 s_newfs; /* Non-zero if this is a new fs */ |
91 | }; | 92 | |
93 | /* From here on it's a static part, only written by mkexofs */ | ||
94 | __le64 s_dev_table_oid; /* Resurved, not used */ | ||
95 | __le64 s_dev_table_count; /* == 0 means no dev_table */ | ||
96 | } __packed; | ||
97 | |||
98 | /* | ||
99 | * Describes the raid used in the FS. It is part of the device table. | ||
100 | * This here is taken from the pNFS-objects definition. In exofs we | ||
101 | * use one raid policy through-out the filesystem. (NOTE: the funny | ||
102 | * alignment at begining. We take care of it at exofs_device_table. | ||
103 | */ | ||
104 | struct exofs_dt_data_map { | ||
105 | __le32 cb_num_comps; | ||
106 | __le64 cb_stripe_unit; | ||
107 | __le32 cb_group_width; | ||
108 | __le32 cb_group_depth; | ||
109 | __le32 cb_mirror_cnt; | ||
110 | __le32 cb_raid_algorithm; | ||
111 | } __packed; | ||
112 | |||
113 | /* | ||
114 | * This is an osd device information descriptor. It is a single entry in | ||
115 | * the exofs device table. It describes an osd target lun which | ||
116 | * contains data belonging to this FS. (Same partition_id on all devices) | ||
117 | */ | ||
118 | struct exofs_dt_device_info { | ||
119 | __le32 systemid_len; | ||
120 | u8 systemid[OSD_SYSTEMID_LEN]; | ||
121 | __le64 long_name_offset; /* If !0 then offset-in-file */ | ||
122 | __le32 osdname_len; /* */ | ||
123 | u8 osdname[44]; /* Embbeded, Ususally an asci uuid */ | ||
124 | } __packed; | ||
125 | |||
126 | /* | ||
127 | * The EXOFS device table - stored in object EXOFS_DEVTABLE_ID's data. | ||
128 | * It contains the raid used for this multy-device FS and an array of | ||
129 | * participating devices. | ||
130 | */ | ||
131 | struct exofs_device_table { | ||
132 | __le32 dt_version; /* == EXOFS_DT_VER */ | ||
133 | struct exofs_dt_data_map dt_data_map; /* Raid policy to use */ | ||
134 | |||
135 | /* Resurved space For future use. Total includeing this: | ||
136 | * (8 * sizeof(le64)) | ||
137 | */ | ||
138 | __le64 __Resurved[4]; | ||
139 | |||
140 | __le64 dt_num_devices; /* Array size */ | ||
141 | struct exofs_dt_device_info dt_dev_table[]; /* Array of devices */ | ||
142 | } __packed; | ||
92 | 143 | ||
93 | /**************************************************************************** | 144 | /**************************************************************************** |
94 | * inode-related things | 145 | * inode-related things |
@@ -155,22 +206,4 @@ enum { | |||
155 | (((name_len) + offsetof(struct exofs_dir_entry, name) + \ | 206 | (((name_len) + offsetof(struct exofs_dir_entry, name) + \ |
156 | EXOFS_DIR_ROUND) & ~EXOFS_DIR_ROUND) | 207 | EXOFS_DIR_ROUND) & ~EXOFS_DIR_ROUND) |
157 | 208 | ||
158 | /************************* | ||
159 | * function declarations * | ||
160 | *************************/ | ||
161 | /* osd.c */ | ||
162 | void exofs_make_credential(u8 cred_a[OSD_CAP_LEN], | ||
163 | const struct osd_obj_id *obj); | ||
164 | |||
165 | int exofs_check_ok_resid(struct osd_request *or, u64 *in_resid, u64 *out_resid); | ||
166 | static inline int exofs_check_ok(struct osd_request *or) | ||
167 | { | ||
168 | return exofs_check_ok_resid(or, NULL, NULL); | ||
169 | } | ||
170 | int exofs_sync_op(struct osd_request *or, int timeout, u8 *cred); | ||
171 | int exofs_async_op(struct osd_request *or, | ||
172 | osd_req_done_fn *async_done, void *caller_context, u8 *cred); | ||
173 | |||
174 | int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr); | ||
175 | |||
176 | #endif /*ifndef __EXOFS_COM_H__*/ | 209 | #endif /*ifndef __EXOFS_COM_H__*/ |
diff --git a/fs/exofs/exofs.h b/fs/exofs/exofs.h index 5ec72e020b22..c35fd4623986 100644 --- a/fs/exofs/exofs.h +++ b/fs/exofs/exofs.h | |||
@@ -30,13 +30,17 @@ | |||
30 | * along with exofs; if not, write to the Free Software | 30 | * along with exofs; if not, write to the Free Software |
31 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 31 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
32 | */ | 32 | */ |
33 | #ifndef __EXOFS_H__ | ||
34 | #define __EXOFS_H__ | ||
33 | 35 | ||
34 | #include <linux/fs.h> | 36 | #include <linux/fs.h> |
35 | #include <linux/time.h> | 37 | #include <linux/time.h> |
36 | #include "common.h" | 38 | #include "common.h" |
37 | 39 | ||
38 | #ifndef __EXOFS_H__ | 40 | /* FIXME: Remove once pnfs hits mainline |
39 | #define __EXOFS_H__ | 41 | * #include <linux/exportfs/pnfs_osd_xdr.h> |
42 | */ | ||
43 | #include "pnfs.h" | ||
40 | 44 | ||
41 | #define EXOFS_ERR(fmt, a...) printk(KERN_ERR "exofs: " fmt, ##a) | 45 | #define EXOFS_ERR(fmt, a...) printk(KERN_ERR "exofs: " fmt, ##a) |
42 | 46 | ||
@@ -55,7 +59,7 @@ | |||
55 | * our extension to the in-memory superblock | 59 | * our extension to the in-memory superblock |
56 | */ | 60 | */ |
57 | struct exofs_sb_info { | 61 | struct exofs_sb_info { |
58 | struct osd_dev *s_dev; /* returned by get_osd_dev */ | 62 | struct exofs_fscb s_fscb; /* Written often, pre-allocate*/ |
59 | osd_id s_pid; /* partition ID of file system*/ | 63 | osd_id s_pid; /* partition ID of file system*/ |
60 | int s_timeout; /* timeout for OSD operations */ | 64 | int s_timeout; /* timeout for OSD operations */ |
61 | uint64_t s_nextid; /* highest object ID used */ | 65 | uint64_t s_nextid; /* highest object ID used */ |
@@ -63,7 +67,11 @@ struct exofs_sb_info { | |||
63 | spinlock_t s_next_gen_lock; /* spinlock for gen # update */ | 67 | spinlock_t s_next_gen_lock; /* spinlock for gen # update */ |
64 | u32 s_next_generation; /* next gen # to use */ | 68 | u32 s_next_generation; /* next gen # to use */ |
65 | atomic_t s_curr_pending; /* number of pending commands */ | 69 | atomic_t s_curr_pending; /* number of pending commands */ |
66 | uint8_t s_cred[OSD_CAP_LEN]; /* all-powerful credential */ | 70 | uint8_t s_cred[OSD_CAP_LEN]; /* credential for the fscb */ |
71 | |||
72 | struct pnfs_osd_data_map data_map; /* Default raid to use */ | ||
73 | unsigned s_numdevs; /* Num of devices in array */ | ||
74 | struct osd_dev *s_ods[1]; /* Variable length, minimum 1 */ | ||
67 | }; | 75 | }; |
68 | 76 | ||
69 | /* | 77 | /* |
@@ -79,6 +87,50 @@ struct exofs_i_info { | |||
79 | struct inode vfs_inode; /* normal in-memory inode */ | 87 | struct inode vfs_inode; /* normal in-memory inode */ |
80 | }; | 88 | }; |
81 | 89 | ||
90 | static inline osd_id exofs_oi_objno(struct exofs_i_info *oi) | ||
91 | { | ||
92 | return oi->vfs_inode.i_ino + EXOFS_OBJ_OFF; | ||
93 | } | ||
94 | |||
95 | struct exofs_io_state; | ||
96 | typedef void (*exofs_io_done_fn)(struct exofs_io_state *or, void *private); | ||
97 | |||
98 | struct exofs_io_state { | ||
99 | struct kref kref; | ||
100 | |||
101 | void *private; | ||
102 | exofs_io_done_fn done; | ||
103 | |||
104 | struct exofs_sb_info *sbi; | ||
105 | struct osd_obj_id obj; | ||
106 | u8 *cred; | ||
107 | |||
108 | /* Global read/write IO*/ | ||
109 | loff_t offset; | ||
110 | unsigned long length; | ||
111 | void *kern_buff; | ||
112 | struct bio *bio; | ||
113 | |||
114 | /* Attributes */ | ||
115 | unsigned in_attr_len; | ||
116 | struct osd_attr *in_attr; | ||
117 | unsigned out_attr_len; | ||
118 | struct osd_attr *out_attr; | ||
119 | |||
120 | /* Variable array of size numdevs */ | ||
121 | unsigned numdevs; | ||
122 | struct exofs_per_dev_state { | ||
123 | struct osd_request *or; | ||
124 | struct bio *bio; | ||
125 | } per_dev[]; | ||
126 | }; | ||
127 | |||
128 | static inline unsigned exofs_io_state_size(unsigned numdevs) | ||
129 | { | ||
130 | return sizeof(struct exofs_io_state) + | ||
131 | sizeof(struct exofs_per_dev_state) * numdevs; | ||
132 | } | ||
133 | |||
82 | /* | 134 | /* |
83 | * our inode flags | 135 | * our inode flags |
84 | */ | 136 | */ |
@@ -130,6 +182,42 @@ static inline struct exofs_i_info *exofs_i(struct inode *inode) | |||
130 | /************************* | 182 | /************************* |
131 | * function declarations * | 183 | * function declarations * |
132 | *************************/ | 184 | *************************/ |
185 | |||
186 | /* ios.c */ | ||
187 | void exofs_make_credential(u8 cred_a[OSD_CAP_LEN], | ||
188 | const struct osd_obj_id *obj); | ||
189 | int exofs_read_kern(struct osd_dev *od, u8 *cred, struct osd_obj_id *obj, | ||
190 | u64 offset, void *p, unsigned length); | ||
191 | |||
192 | int exofs_get_io_state(struct exofs_sb_info *sbi, struct exofs_io_state** ios); | ||
193 | void exofs_put_io_state(struct exofs_io_state *ios); | ||
194 | |||
195 | int exofs_check_io(struct exofs_io_state *ios, u64 *resid); | ||
196 | |||
197 | int exofs_sbi_create(struct exofs_io_state *ios); | ||
198 | int exofs_sbi_remove(struct exofs_io_state *ios); | ||
199 | int exofs_sbi_write(struct exofs_io_state *ios); | ||
200 | int exofs_sbi_read(struct exofs_io_state *ios); | ||
201 | |||
202 | int extract_attr_from_ios(struct exofs_io_state *ios, struct osd_attr *attr); | ||
203 | |||
204 | int exofs_oi_truncate(struct exofs_i_info *oi, u64 new_len); | ||
205 | static inline int exofs_oi_write(struct exofs_i_info *oi, | ||
206 | struct exofs_io_state *ios) | ||
207 | { | ||
208 | ios->obj.id = exofs_oi_objno(oi); | ||
209 | ios->cred = oi->i_cred; | ||
210 | return exofs_sbi_write(ios); | ||
211 | } | ||
212 | |||
213 | static inline int exofs_oi_read(struct exofs_i_info *oi, | ||
214 | struct exofs_io_state *ios) | ||
215 | { | ||
216 | ios->obj.id = exofs_oi_objno(oi); | ||
217 | ios->cred = oi->i_cred; | ||
218 | return exofs_sbi_read(ios); | ||
219 | } | ||
220 | |||
133 | /* inode.c */ | 221 | /* inode.c */ |
134 | void exofs_truncate(struct inode *inode); | 222 | void exofs_truncate(struct inode *inode); |
135 | int exofs_setattr(struct dentry *, struct iattr *); | 223 | int exofs_setattr(struct dentry *, struct iattr *); |
@@ -169,6 +257,7 @@ extern const struct file_operations exofs_file_operations; | |||
169 | 257 | ||
170 | /* inode.c */ | 258 | /* inode.c */ |
171 | extern const struct address_space_operations exofs_aops; | 259 | extern const struct address_space_operations exofs_aops; |
260 | extern const struct osd_attr g_attr_logical_length; | ||
172 | 261 | ||
173 | /* namei.c */ | 262 | /* namei.c */ |
174 | extern const struct inode_operations exofs_dir_inode_operations; | 263 | extern const struct inode_operations exofs_dir_inode_operations; |
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index 6c10f7476699..698a8636d39c 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c | |||
@@ -37,15 +37,18 @@ | |||
37 | 37 | ||
38 | #include "exofs.h" | 38 | #include "exofs.h" |
39 | 39 | ||
40 | #ifdef CONFIG_EXOFS_DEBUG | 40 | #define EXOFS_DBGMSG2(M...) do {} while (0) |
41 | # define EXOFS_DEBUG_OBJ_ISIZE 1 | 41 | |
42 | #endif | 42 | enum { BIO_MAX_PAGES_KMALLOC = |
43 | (PAGE_SIZE - sizeof(struct bio)) / sizeof(struct bio_vec), | ||
44 | }; | ||
43 | 45 | ||
44 | struct page_collect { | 46 | struct page_collect { |
45 | struct exofs_sb_info *sbi; | 47 | struct exofs_sb_info *sbi; |
46 | struct request_queue *req_q; | 48 | struct request_queue *req_q; |
47 | struct inode *inode; | 49 | struct inode *inode; |
48 | unsigned expected_pages; | 50 | unsigned expected_pages; |
51 | struct exofs_io_state *ios; | ||
49 | 52 | ||
50 | struct bio *bio; | 53 | struct bio *bio; |
51 | unsigned nr_pages; | 54 | unsigned nr_pages; |
@@ -54,22 +57,23 @@ struct page_collect { | |||
54 | }; | 57 | }; |
55 | 58 | ||
56 | static void _pcol_init(struct page_collect *pcol, unsigned expected_pages, | 59 | static void _pcol_init(struct page_collect *pcol, unsigned expected_pages, |
57 | struct inode *inode) | 60 | struct inode *inode) |
58 | { | 61 | { |
59 | struct exofs_sb_info *sbi = inode->i_sb->s_fs_info; | 62 | struct exofs_sb_info *sbi = inode->i_sb->s_fs_info; |
60 | 63 | ||
61 | pcol->sbi = sbi; | 64 | pcol->sbi = sbi; |
62 | pcol->req_q = osd_request_queue(sbi->s_dev); | 65 | /* Create master bios on first Q, later on cloning, each clone will be |
66 | * allocated on it's destination Q | ||
67 | */ | ||
68 | pcol->req_q = osd_request_queue(sbi->s_ods[0]); | ||
63 | pcol->inode = inode; | 69 | pcol->inode = inode; |
64 | pcol->expected_pages = expected_pages; | 70 | pcol->expected_pages = expected_pages; |
65 | 71 | ||
72 | pcol->ios = NULL; | ||
66 | pcol->bio = NULL; | 73 | pcol->bio = NULL; |
67 | pcol->nr_pages = 0; | 74 | pcol->nr_pages = 0; |
68 | pcol->length = 0; | 75 | pcol->length = 0; |
69 | pcol->pg_first = -1; | 76 | pcol->pg_first = -1; |
70 | |||
71 | EXOFS_DBGMSG("_pcol_init ino=0x%lx expected_pages=%u\n", inode->i_ino, | ||
72 | expected_pages); | ||
73 | } | 77 | } |
74 | 78 | ||
75 | static void _pcol_reset(struct page_collect *pcol) | 79 | static void _pcol_reset(struct page_collect *pcol) |
@@ -80,35 +84,49 @@ static void _pcol_reset(struct page_collect *pcol) | |||
80 | pcol->nr_pages = 0; | 84 | pcol->nr_pages = 0; |
81 | pcol->length = 0; | 85 | pcol->length = 0; |
82 | pcol->pg_first = -1; | 86 | pcol->pg_first = -1; |
83 | EXOFS_DBGMSG("_pcol_reset ino=0x%lx expected_pages=%u\n", | 87 | pcol->ios = NULL; |
84 | pcol->inode->i_ino, pcol->expected_pages); | ||
85 | 88 | ||
86 | /* this is probably the end of the loop but in writes | 89 | /* this is probably the end of the loop but in writes |
87 | * it might not end here. don't be left with nothing | 90 | * it might not end here. don't be left with nothing |
88 | */ | 91 | */ |
89 | if (!pcol->expected_pages) | 92 | if (!pcol->expected_pages) |
90 | pcol->expected_pages = 128; | 93 | pcol->expected_pages = BIO_MAX_PAGES_KMALLOC; |
91 | } | 94 | } |
92 | 95 | ||
93 | static int pcol_try_alloc(struct page_collect *pcol) | 96 | static int pcol_try_alloc(struct page_collect *pcol) |
94 | { | 97 | { |
95 | int pages = min_t(unsigned, pcol->expected_pages, BIO_MAX_PAGES); | 98 | int pages = min_t(unsigned, pcol->expected_pages, |
99 | BIO_MAX_PAGES_KMALLOC); | ||
100 | |||
101 | if (!pcol->ios) { /* First time allocate io_state */ | ||
102 | int ret = exofs_get_io_state(pcol->sbi, &pcol->ios); | ||
103 | |||
104 | if (ret) | ||
105 | return ret; | ||
106 | } | ||
96 | 107 | ||
97 | for (; pages; pages >>= 1) { | 108 | for (; pages; pages >>= 1) { |
98 | pcol->bio = bio_alloc(GFP_KERNEL, pages); | 109 | pcol->bio = bio_kmalloc(GFP_KERNEL, pages); |
99 | if (likely(pcol->bio)) | 110 | if (likely(pcol->bio)) |
100 | return 0; | 111 | return 0; |
101 | } | 112 | } |
102 | 113 | ||
103 | EXOFS_ERR("Failed to kcalloc expected_pages=%u\n", | 114 | EXOFS_ERR("Failed to bio_kmalloc expected_pages=%u\n", |
104 | pcol->expected_pages); | 115 | pcol->expected_pages); |
105 | return -ENOMEM; | 116 | return -ENOMEM; |
106 | } | 117 | } |
107 | 118 | ||
108 | static void pcol_free(struct page_collect *pcol) | 119 | static void pcol_free(struct page_collect *pcol) |
109 | { | 120 | { |
110 | bio_put(pcol->bio); | 121 | if (pcol->bio) { |
111 | pcol->bio = NULL; | 122 | bio_put(pcol->bio); |
123 | pcol->bio = NULL; | ||
124 | } | ||
125 | |||
126 | if (pcol->ios) { | ||
127 | exofs_put_io_state(pcol->ios); | ||
128 | pcol->ios = NULL; | ||
129 | } | ||
112 | } | 130 | } |
113 | 131 | ||
114 | static int pcol_add_page(struct page_collect *pcol, struct page *page, | 132 | static int pcol_add_page(struct page_collect *pcol, struct page *page, |
@@ -161,22 +179,17 @@ static void update_write_page(struct page *page, int ret) | |||
161 | /* Called at the end of reads, to optionally unlock pages and update their | 179 | /* Called at the end of reads, to optionally unlock pages and update their |
162 | * status. | 180 | * status. |
163 | */ | 181 | */ |
164 | static int __readpages_done(struct osd_request *or, struct page_collect *pcol, | 182 | static int __readpages_done(struct page_collect *pcol, bool do_unlock) |
165 | bool do_unlock) | ||
166 | { | 183 | { |
167 | struct bio_vec *bvec; | 184 | struct bio_vec *bvec; |
168 | int i; | 185 | int i; |
169 | u64 resid; | 186 | u64 resid; |
170 | u64 good_bytes; | 187 | u64 good_bytes; |
171 | u64 length = 0; | 188 | u64 length = 0; |
172 | int ret = exofs_check_ok_resid(or, &resid, NULL); | 189 | int ret = exofs_check_io(pcol->ios, &resid); |
173 | |||
174 | osd_end_request(or); | ||
175 | 190 | ||
176 | if (likely(!ret)) | 191 | if (likely(!ret)) |
177 | good_bytes = pcol->length; | 192 | good_bytes = pcol->length; |
178 | else if (!resid) | ||
179 | good_bytes = 0; | ||
180 | else | 193 | else |
181 | good_bytes = pcol->length - resid; | 194 | good_bytes = pcol->length - resid; |
182 | 195 | ||
@@ -198,7 +211,7 @@ static int __readpages_done(struct osd_request *or, struct page_collect *pcol, | |||
198 | else | 211 | else |
199 | page_stat = ret; | 212 | page_stat = ret; |
200 | 213 | ||
201 | EXOFS_DBGMSG(" readpages_done(0x%lx, 0x%lx) %s\n", | 214 | EXOFS_DBGMSG2(" readpages_done(0x%lx, 0x%lx) %s\n", |
202 | inode->i_ino, page->index, | 215 | inode->i_ino, page->index, |
203 | page_stat ? "bad_bytes" : "good_bytes"); | 216 | page_stat ? "bad_bytes" : "good_bytes"); |
204 | 217 | ||
@@ -214,13 +227,13 @@ static int __readpages_done(struct osd_request *or, struct page_collect *pcol, | |||
214 | } | 227 | } |
215 | 228 | ||
216 | /* callback of async reads */ | 229 | /* callback of async reads */ |
217 | static void readpages_done(struct osd_request *or, void *p) | 230 | static void readpages_done(struct exofs_io_state *ios, void *p) |
218 | { | 231 | { |
219 | struct page_collect *pcol = p; | 232 | struct page_collect *pcol = p; |
220 | 233 | ||
221 | __readpages_done(or, pcol, true); | 234 | __readpages_done(pcol, true); |
222 | atomic_dec(&pcol->sbi->s_curr_pending); | 235 | atomic_dec(&pcol->sbi->s_curr_pending); |
223 | kfree(p); | 236 | kfree(pcol); |
224 | } | 237 | } |
225 | 238 | ||
226 | static void _unlock_pcol_pages(struct page_collect *pcol, int ret, int rw) | 239 | static void _unlock_pcol_pages(struct page_collect *pcol, int ret, int rw) |
@@ -238,17 +251,13 @@ static void _unlock_pcol_pages(struct page_collect *pcol, int ret, int rw) | |||
238 | 251 | ||
239 | unlock_page(page); | 252 | unlock_page(page); |
240 | } | 253 | } |
241 | pcol_free(pcol); | ||
242 | } | 254 | } |
243 | 255 | ||
244 | static int read_exec(struct page_collect *pcol, bool is_sync) | 256 | static int read_exec(struct page_collect *pcol, bool is_sync) |
245 | { | 257 | { |
246 | struct exofs_i_info *oi = exofs_i(pcol->inode); | 258 | struct exofs_i_info *oi = exofs_i(pcol->inode); |
247 | struct osd_obj_id obj = {pcol->sbi->s_pid, | 259 | struct exofs_io_state *ios = pcol->ios; |
248 | pcol->inode->i_ino + EXOFS_OBJ_OFF}; | ||
249 | struct osd_request *or = NULL; | ||
250 | struct page_collect *pcol_copy = NULL; | 260 | struct page_collect *pcol_copy = NULL; |
251 | loff_t i_start = pcol->pg_first << PAGE_CACHE_SHIFT; | ||
252 | int ret; | 261 | int ret; |
253 | 262 | ||
254 | if (!pcol->bio) | 263 | if (!pcol->bio) |
@@ -257,17 +266,13 @@ static int read_exec(struct page_collect *pcol, bool is_sync) | |||
257 | /* see comment in _readpage() about sync reads */ | 266 | /* see comment in _readpage() about sync reads */ |
258 | WARN_ON(is_sync && (pcol->nr_pages != 1)); | 267 | WARN_ON(is_sync && (pcol->nr_pages != 1)); |
259 | 268 | ||
260 | or = osd_start_request(pcol->sbi->s_dev, GFP_KERNEL); | 269 | ios->bio = pcol->bio; |
261 | if (unlikely(!or)) { | 270 | ios->length = pcol->length; |
262 | ret = -ENOMEM; | 271 | ios->offset = pcol->pg_first << PAGE_CACHE_SHIFT; |
263 | goto err; | ||
264 | } | ||
265 | |||
266 | osd_req_read(or, &obj, i_start, pcol->bio, pcol->length); | ||
267 | 272 | ||
268 | if (is_sync) { | 273 | if (is_sync) { |
269 | exofs_sync_op(or, pcol->sbi->s_timeout, oi->i_cred); | 274 | exofs_oi_read(oi, pcol->ios); |
270 | return __readpages_done(or, pcol, false); | 275 | return __readpages_done(pcol, false); |
271 | } | 276 | } |
272 | 277 | ||
273 | pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL); | 278 | pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL); |
@@ -277,14 +282,16 @@ static int read_exec(struct page_collect *pcol, bool is_sync) | |||
277 | } | 282 | } |
278 | 283 | ||
279 | *pcol_copy = *pcol; | 284 | *pcol_copy = *pcol; |
280 | ret = exofs_async_op(or, readpages_done, pcol_copy, oi->i_cred); | 285 | ios->done = readpages_done; |
286 | ios->private = pcol_copy; | ||
287 | ret = exofs_oi_read(oi, ios); | ||
281 | if (unlikely(ret)) | 288 | if (unlikely(ret)) |
282 | goto err; | 289 | goto err; |
283 | 290 | ||
284 | atomic_inc(&pcol->sbi->s_curr_pending); | 291 | atomic_inc(&pcol->sbi->s_curr_pending); |
285 | 292 | ||
286 | EXOFS_DBGMSG("read_exec obj=0x%llx start=0x%llx length=0x%lx\n", | 293 | EXOFS_DBGMSG("read_exec obj=0x%llx start=0x%llx length=0x%lx\n", |
287 | obj.id, _LLU(i_start), pcol->length); | 294 | ios->obj.id, _LLU(ios->offset), pcol->length); |
288 | 295 | ||
289 | /* pages ownership was passed to pcol_copy */ | 296 | /* pages ownership was passed to pcol_copy */ |
290 | _pcol_reset(pcol); | 297 | _pcol_reset(pcol); |
@@ -293,12 +300,10 @@ static int read_exec(struct page_collect *pcol, bool is_sync) | |||
293 | err: | 300 | err: |
294 | if (!is_sync) | 301 | if (!is_sync) |
295 | _unlock_pcol_pages(pcol, ret, READ); | 302 | _unlock_pcol_pages(pcol, ret, READ); |
296 | else /* Pages unlocked by caller in sync mode only free bio */ | 303 | |
297 | pcol_free(pcol); | 304 | pcol_free(pcol); |
298 | 305 | ||
299 | kfree(pcol_copy); | 306 | kfree(pcol_copy); |
300 | if (or) | ||
301 | osd_end_request(or); | ||
302 | return ret; | 307 | return ret; |
303 | } | 308 | } |
304 | 309 | ||
@@ -370,12 +375,12 @@ try_again: | |||
370 | if (len != PAGE_CACHE_SIZE) | 375 | if (len != PAGE_CACHE_SIZE) |
371 | zero_user(page, len, PAGE_CACHE_SIZE - len); | 376 | zero_user(page, len, PAGE_CACHE_SIZE - len); |
372 | 377 | ||
373 | EXOFS_DBGMSG(" readpage_strip(0x%lx, 0x%lx) len=0x%zx\n", | 378 | EXOFS_DBGMSG2(" readpage_strip(0x%lx, 0x%lx) len=0x%zx\n", |
374 | inode->i_ino, page->index, len); | 379 | inode->i_ino, page->index, len); |
375 | 380 | ||
376 | ret = pcol_add_page(pcol, page, len); | 381 | ret = pcol_add_page(pcol, page, len); |
377 | if (ret) { | 382 | if (ret) { |
378 | EXOFS_DBGMSG("Failed pcol_add_page pages[i]=%p " | 383 | EXOFS_DBGMSG2("Failed pcol_add_page pages[i]=%p " |
379 | "this_len=0x%zx nr_pages=%u length=0x%lx\n", | 384 | "this_len=0x%zx nr_pages=%u length=0x%lx\n", |
380 | page, len, pcol->nr_pages, pcol->length); | 385 | page, len, pcol->nr_pages, pcol->length); |
381 | 386 | ||
@@ -419,9 +424,8 @@ static int _readpage(struct page *page, bool is_sync) | |||
419 | 424 | ||
420 | _pcol_init(&pcol, 1, page->mapping->host); | 425 | _pcol_init(&pcol, 1, page->mapping->host); |
421 | 426 | ||
422 | /* readpage_strip might call read_exec(,async) inside at several places | 427 | /* readpage_strip might call read_exec(,is_sync==false) at several |
423 | * but this is safe for is_async=0 since read_exec will not do anything | 428 | * places but not if we have a single page. |
424 | * when we have a single page. | ||
425 | */ | 429 | */ |
426 | ret = readpage_strip(&pcol, page); | 430 | ret = readpage_strip(&pcol, page); |
427 | if (ret) { | 431 | if (ret) { |
@@ -440,8 +444,8 @@ static int exofs_readpage(struct file *file, struct page *page) | |||
440 | return _readpage(page, false); | 444 | return _readpage(page, false); |
441 | } | 445 | } |
442 | 446 | ||
443 | /* Callback for osd_write. All writes are asynchronouse */ | 447 | /* Callback for osd_write. All writes are asynchronous */ |
444 | static void writepages_done(struct osd_request *or, void *p) | 448 | static void writepages_done(struct exofs_io_state *ios, void *p) |
445 | { | 449 | { |
446 | struct page_collect *pcol = p; | 450 | struct page_collect *pcol = p; |
447 | struct bio_vec *bvec; | 451 | struct bio_vec *bvec; |
@@ -449,16 +453,12 @@ static void writepages_done(struct osd_request *or, void *p) | |||
449 | u64 resid; | 453 | u64 resid; |
450 | u64 good_bytes; | 454 | u64 good_bytes; |
451 | u64 length = 0; | 455 | u64 length = 0; |
456 | int ret = exofs_check_io(ios, &resid); | ||
452 | 457 | ||
453 | int ret = exofs_check_ok_resid(or, NULL, &resid); | ||
454 | |||
455 | osd_end_request(or); | ||
456 | atomic_dec(&pcol->sbi->s_curr_pending); | 458 | atomic_dec(&pcol->sbi->s_curr_pending); |
457 | 459 | ||
458 | if (likely(!ret)) | 460 | if (likely(!ret)) |
459 | good_bytes = pcol->length; | 461 | good_bytes = pcol->length; |
460 | else if (!resid) | ||
461 | good_bytes = 0; | ||
462 | else | 462 | else |
463 | good_bytes = pcol->length - resid; | 463 | good_bytes = pcol->length - resid; |
464 | 464 | ||
@@ -482,7 +482,7 @@ static void writepages_done(struct osd_request *or, void *p) | |||
482 | 482 | ||
483 | update_write_page(page, page_stat); | 483 | update_write_page(page, page_stat); |
484 | unlock_page(page); | 484 | unlock_page(page); |
485 | EXOFS_DBGMSG(" writepages_done(0x%lx, 0x%lx) status=%d\n", | 485 | EXOFS_DBGMSG2(" writepages_done(0x%lx, 0x%lx) status=%d\n", |
486 | inode->i_ino, page->index, page_stat); | 486 | inode->i_ino, page->index, page_stat); |
487 | 487 | ||
488 | length += bvec->bv_len; | 488 | length += bvec->bv_len; |
@@ -496,23 +496,13 @@ static void writepages_done(struct osd_request *or, void *p) | |||
496 | static int write_exec(struct page_collect *pcol) | 496 | static int write_exec(struct page_collect *pcol) |
497 | { | 497 | { |
498 | struct exofs_i_info *oi = exofs_i(pcol->inode); | 498 | struct exofs_i_info *oi = exofs_i(pcol->inode); |
499 | struct osd_obj_id obj = {pcol->sbi->s_pid, | 499 | struct exofs_io_state *ios = pcol->ios; |
500 | pcol->inode->i_ino + EXOFS_OBJ_OFF}; | ||
501 | struct osd_request *or = NULL; | ||
502 | struct page_collect *pcol_copy = NULL; | 500 | struct page_collect *pcol_copy = NULL; |
503 | loff_t i_start = pcol->pg_first << PAGE_CACHE_SHIFT; | ||
504 | int ret; | 501 | int ret; |
505 | 502 | ||
506 | if (!pcol->bio) | 503 | if (!pcol->bio) |
507 | return 0; | 504 | return 0; |
508 | 505 | ||
509 | or = osd_start_request(pcol->sbi->s_dev, GFP_KERNEL); | ||
510 | if (unlikely(!or)) { | ||
511 | EXOFS_ERR("write_exec: Faild to osd_start_request()\n"); | ||
512 | ret = -ENOMEM; | ||
513 | goto err; | ||
514 | } | ||
515 | |||
516 | pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL); | 506 | pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL); |
517 | if (!pcol_copy) { | 507 | if (!pcol_copy) { |
518 | EXOFS_ERR("write_exec: Faild to kmalloc(pcol)\n"); | 508 | EXOFS_ERR("write_exec: Faild to kmalloc(pcol)\n"); |
@@ -523,16 +513,22 @@ static int write_exec(struct page_collect *pcol) | |||
523 | *pcol_copy = *pcol; | 513 | *pcol_copy = *pcol; |
524 | 514 | ||
525 | pcol_copy->bio->bi_rw |= (1 << BIO_RW); /* FIXME: bio_set_dir() */ | 515 | pcol_copy->bio->bi_rw |= (1 << BIO_RW); /* FIXME: bio_set_dir() */ |
526 | osd_req_write(or, &obj, i_start, pcol_copy->bio, pcol_copy->length); | 516 | |
527 | ret = exofs_async_op(or, writepages_done, pcol_copy, oi->i_cred); | 517 | ios->bio = pcol_copy->bio; |
518 | ios->offset = pcol_copy->pg_first << PAGE_CACHE_SHIFT; | ||
519 | ios->length = pcol_copy->length; | ||
520 | ios->done = writepages_done; | ||
521 | ios->private = pcol_copy; | ||
522 | |||
523 | ret = exofs_oi_write(oi, ios); | ||
528 | if (unlikely(ret)) { | 524 | if (unlikely(ret)) { |
529 | EXOFS_ERR("write_exec: exofs_async_op() Faild\n"); | 525 | EXOFS_ERR("write_exec: exofs_oi_write() Faild\n"); |
530 | goto err; | 526 | goto err; |
531 | } | 527 | } |
532 | 528 | ||
533 | atomic_inc(&pcol->sbi->s_curr_pending); | 529 | atomic_inc(&pcol->sbi->s_curr_pending); |
534 | EXOFS_DBGMSG("write_exec(0x%lx, 0x%llx) start=0x%llx length=0x%lx\n", | 530 | EXOFS_DBGMSG("write_exec(0x%lx, 0x%llx) start=0x%llx length=0x%lx\n", |
535 | pcol->inode->i_ino, pcol->pg_first, _LLU(i_start), | 531 | pcol->inode->i_ino, pcol->pg_first, _LLU(ios->offset), |
536 | pcol->length); | 532 | pcol->length); |
537 | /* pages ownership was passed to pcol_copy */ | 533 | /* pages ownership was passed to pcol_copy */ |
538 | _pcol_reset(pcol); | 534 | _pcol_reset(pcol); |
@@ -540,9 +536,9 @@ static int write_exec(struct page_collect *pcol) | |||
540 | 536 | ||
541 | err: | 537 | err: |
542 | _unlock_pcol_pages(pcol, ret, WRITE); | 538 | _unlock_pcol_pages(pcol, ret, WRITE); |
539 | pcol_free(pcol); | ||
543 | kfree(pcol_copy); | 540 | kfree(pcol_copy); |
544 | if (or) | 541 | |
545 | osd_end_request(or); | ||
546 | return ret; | 542 | return ret; |
547 | } | 543 | } |
548 | 544 | ||
@@ -586,6 +582,9 @@ static int writepage_strip(struct page *page, | |||
586 | if (PageError(page)) | 582 | if (PageError(page)) |
587 | ClearPageError(page); | 583 | ClearPageError(page); |
588 | unlock_page(page); | 584 | unlock_page(page); |
585 | EXOFS_DBGMSG("writepage_strip(0x%lx, 0x%lx) " | ||
586 | "outside the limits\n", | ||
587 | inode->i_ino, page->index); | ||
589 | return 0; | 588 | return 0; |
590 | } | 589 | } |
591 | } | 590 | } |
@@ -600,6 +599,9 @@ try_again: | |||
600 | ret = write_exec(pcol); | 599 | ret = write_exec(pcol); |
601 | if (unlikely(ret)) | 600 | if (unlikely(ret)) |
602 | goto fail; | 601 | goto fail; |
602 | |||
603 | EXOFS_DBGMSG("writepage_strip(0x%lx, 0x%lx) Discontinuity\n", | ||
604 | inode->i_ino, page->index); | ||
603 | goto try_again; | 605 | goto try_again; |
604 | } | 606 | } |
605 | 607 | ||
@@ -609,7 +611,7 @@ try_again: | |||
609 | goto fail; | 611 | goto fail; |
610 | } | 612 | } |
611 | 613 | ||
612 | EXOFS_DBGMSG(" writepage_strip(0x%lx, 0x%lx) len=0x%zx\n", | 614 | EXOFS_DBGMSG2(" writepage_strip(0x%lx, 0x%lx) len=0x%zx\n", |
613 | inode->i_ino, page->index, len); | 615 | inode->i_ino, page->index, len); |
614 | 616 | ||
615 | ret = pcol_add_page(pcol, page, len); | 617 | ret = pcol_add_page(pcol, page, len); |
@@ -634,6 +636,8 @@ try_again: | |||
634 | return 0; | 636 | return 0; |
635 | 637 | ||
636 | fail: | 638 | fail: |
639 | EXOFS_DBGMSG("Error: writepage_strip(0x%lx, 0x%lx)=>%d\n", | ||
640 | inode->i_ino, page->index, ret); | ||
637 | set_bit(AS_EIO, &page->mapping->flags); | 641 | set_bit(AS_EIO, &page->mapping->flags); |
638 | unlock_page(page); | 642 | unlock_page(page); |
639 | return ret; | 643 | return ret; |
@@ -652,14 +656,17 @@ static int exofs_writepages(struct address_space *mapping, | |||
652 | wbc->range_end >> PAGE_CACHE_SHIFT; | 656 | wbc->range_end >> PAGE_CACHE_SHIFT; |
653 | 657 | ||
654 | if (start || end) | 658 | if (start || end) |
655 | expected_pages = min(end - start + 1, 32L); | 659 | expected_pages = end - start + 1; |
656 | else | 660 | else |
657 | expected_pages = mapping->nrpages; | 661 | expected_pages = mapping->nrpages; |
658 | 662 | ||
659 | EXOFS_DBGMSG("inode(0x%lx) wbc->start=0x%llx wbc->end=0x%llx" | 663 | if (expected_pages < 32L) |
660 | " m->nrpages=%lu start=0x%lx end=0x%lx\n", | 664 | expected_pages = 32L; |
665 | |||
666 | EXOFS_DBGMSG("inode(0x%lx) wbc->start=0x%llx wbc->end=0x%llx " | ||
667 | "nrpages=%lu start=0x%lx end=0x%lx expected_pages=%ld\n", | ||
661 | mapping->host->i_ino, wbc->range_start, wbc->range_end, | 668 | mapping->host->i_ino, wbc->range_start, wbc->range_end, |
662 | mapping->nrpages, start, end); | 669 | mapping->nrpages, start, end, expected_pages); |
663 | 670 | ||
664 | _pcol_init(&pcol, expected_pages, mapping->host); | 671 | _pcol_init(&pcol, expected_pages, mapping->host); |
665 | 672 | ||
@@ -771,19 +778,28 @@ static int exofs_get_block(struct inode *inode, sector_t iblock, | |||
771 | const struct osd_attr g_attr_logical_length = ATTR_DEF( | 778 | const struct osd_attr g_attr_logical_length = ATTR_DEF( |
772 | OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8); | 779 | OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8); |
773 | 780 | ||
781 | static int _do_truncate(struct inode *inode) | ||
782 | { | ||
783 | struct exofs_i_info *oi = exofs_i(inode); | ||
784 | loff_t isize = i_size_read(inode); | ||
785 | int ret; | ||
786 | |||
787 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
788 | |||
789 | nobh_truncate_page(inode->i_mapping, isize, exofs_get_block); | ||
790 | |||
791 | ret = exofs_oi_truncate(oi, (u64)isize); | ||
792 | EXOFS_DBGMSG("(0x%lx) size=0x%llx\n", inode->i_ino, isize); | ||
793 | return ret; | ||
794 | } | ||
795 | |||
774 | /* | 796 | /* |
775 | * Truncate a file to the specified size - all we have to do is set the size | 797 | * Truncate a file to the specified size - all we have to do is set the size |
776 | * attribute. We make sure the object exists first. | 798 | * attribute. We make sure the object exists first. |
777 | */ | 799 | */ |
778 | void exofs_truncate(struct inode *inode) | 800 | void exofs_truncate(struct inode *inode) |
779 | { | 801 | { |
780 | struct exofs_sb_info *sbi = inode->i_sb->s_fs_info; | ||
781 | struct exofs_i_info *oi = exofs_i(inode); | 802 | struct exofs_i_info *oi = exofs_i(inode); |
782 | struct osd_obj_id obj = {sbi->s_pid, inode->i_ino + EXOFS_OBJ_OFF}; | ||
783 | struct osd_request *or; | ||
784 | struct osd_attr attr; | ||
785 | loff_t isize = i_size_read(inode); | ||
786 | __be64 newsize; | ||
787 | int ret; | 803 | int ret; |
788 | 804 | ||
789 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) | 805 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) |
@@ -793,22 +809,6 @@ void exofs_truncate(struct inode *inode) | |||
793 | return; | 809 | return; |
794 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | 810 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) |
795 | return; | 811 | return; |
796 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
797 | |||
798 | nobh_truncate_page(inode->i_mapping, isize, exofs_get_block); | ||
799 | |||
800 | or = osd_start_request(sbi->s_dev, GFP_KERNEL); | ||
801 | if (unlikely(!or)) { | ||
802 | EXOFS_ERR("ERROR: exofs_truncate: osd_start_request failed\n"); | ||
803 | goto fail; | ||
804 | } | ||
805 | |||
806 | osd_req_set_attributes(or, &obj); | ||
807 | |||
808 | newsize = cpu_to_be64((u64)isize); | ||
809 | attr = g_attr_logical_length; | ||
810 | attr.val_ptr = &newsize; | ||
811 | osd_req_add_set_attr_list(or, &attr, 1); | ||
812 | 812 | ||
813 | /* if we are about to truncate an object, and it hasn't been | 813 | /* if we are about to truncate an object, and it hasn't been |
814 | * created yet, wait | 814 | * created yet, wait |
@@ -816,8 +816,7 @@ void exofs_truncate(struct inode *inode) | |||
816 | if (unlikely(wait_obj_created(oi))) | 816 | if (unlikely(wait_obj_created(oi))) |
817 | goto fail; | 817 | goto fail; |
818 | 818 | ||
819 | ret = exofs_sync_op(or, sbi->s_timeout, oi->i_cred); | 819 | ret = _do_truncate(inode); |
820 | osd_end_request(or); | ||
821 | if (ret) | 820 | if (ret) |
822 | goto fail; | 821 | goto fail; |
823 | 822 | ||
@@ -847,65 +846,62 @@ int exofs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
847 | 846 | ||
848 | /* | 847 | /* |
849 | * Read an inode from the OSD, and return it as is. We also return the size | 848 | * Read an inode from the OSD, and return it as is. We also return the size |
850 | * attribute in the 'sanity' argument if we got compiled with debugging turned | 849 | * attribute in the 'obj_size' argument. |
851 | * on. | ||
852 | */ | 850 | */ |
853 | static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi, | 851 | static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi, |
854 | struct exofs_fcb *inode, uint64_t *sanity) | 852 | struct exofs_fcb *inode, uint64_t *obj_size) |
855 | { | 853 | { |
856 | struct exofs_sb_info *sbi = sb->s_fs_info; | 854 | struct exofs_sb_info *sbi = sb->s_fs_info; |
857 | struct osd_request *or; | 855 | struct osd_attr attrs[2]; |
858 | struct osd_attr attr; | 856 | struct exofs_io_state *ios; |
859 | struct osd_obj_id obj = {sbi->s_pid, | ||
860 | oi->vfs_inode.i_ino + EXOFS_OBJ_OFF}; | ||
861 | int ret; | 857 | int ret; |
862 | 858 | ||
863 | exofs_make_credential(oi->i_cred, &obj); | 859 | *obj_size = ~0; |
864 | 860 | ret = exofs_get_io_state(sbi, &ios); | |
865 | or = osd_start_request(sbi->s_dev, GFP_KERNEL); | 861 | if (unlikely(ret)) { |
866 | if (unlikely(!or)) { | 862 | EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__); |
867 | EXOFS_ERR("exofs_get_inode: osd_start_request failed.\n"); | 863 | return ret; |
868 | return -ENOMEM; | ||
869 | } | 864 | } |
870 | osd_req_get_attributes(or, &obj); | ||
871 | 865 | ||
872 | /* we need the inode attribute */ | 866 | ios->obj.id = exofs_oi_objno(oi); |
873 | osd_req_add_get_attr_list(or, &g_attr_inode_data, 1); | 867 | exofs_make_credential(oi->i_cred, &ios->obj); |
868 | ios->cred = oi->i_cred; | ||
874 | 869 | ||
875 | #ifdef EXOFS_DEBUG_OBJ_ISIZE | 870 | attrs[0] = g_attr_inode_data; |
876 | /* we get the size attributes to do a sanity check */ | 871 | attrs[1] = g_attr_logical_length; |
877 | osd_req_add_get_attr_list(or, &g_attr_logical_length, 1); | 872 | ios->in_attr = attrs; |
878 | #endif | 873 | ios->in_attr_len = ARRAY_SIZE(attrs); |
879 | 874 | ||
880 | ret = exofs_sync_op(or, sbi->s_timeout, oi->i_cred); | 875 | ret = exofs_sbi_read(ios); |
881 | if (ret) | 876 | if (ret) |
882 | goto out; | 877 | goto out; |
883 | 878 | ||
884 | attr = g_attr_inode_data; | 879 | ret = extract_attr_from_ios(ios, &attrs[0]); |
885 | ret = extract_attr_from_req(or, &attr); | ||
886 | if (ret) { | 880 | if (ret) { |
887 | EXOFS_ERR("exofs_get_inode: extract_attr_from_req failed\n"); | 881 | EXOFS_ERR("%s: extract_attr of inode_data failed\n", __func__); |
888 | goto out; | 882 | goto out; |
889 | } | 883 | } |
884 | WARN_ON(attrs[0].len != EXOFS_INO_ATTR_SIZE); | ||
885 | memcpy(inode, attrs[0].val_ptr, EXOFS_INO_ATTR_SIZE); | ||
890 | 886 | ||
891 | WARN_ON(attr.len != EXOFS_INO_ATTR_SIZE); | 887 | ret = extract_attr_from_ios(ios, &attrs[1]); |
892 | memcpy(inode, attr.val_ptr, EXOFS_INO_ATTR_SIZE); | ||
893 | |||
894 | #ifdef EXOFS_DEBUG_OBJ_ISIZE | ||
895 | attr = g_attr_logical_length; | ||
896 | ret = extract_attr_from_req(or, &attr); | ||
897 | if (ret) { | 888 | if (ret) { |
898 | EXOFS_ERR("ERROR: extract attr from or failed\n"); | 889 | EXOFS_ERR("%s: extract_attr of logical_length failed\n", |
890 | __func__); | ||
899 | goto out; | 891 | goto out; |
900 | } | 892 | } |
901 | *sanity = get_unaligned_be64(attr.val_ptr); | 893 | *obj_size = get_unaligned_be64(attrs[1].val_ptr); |
902 | #endif | ||
903 | 894 | ||
904 | out: | 895 | out: |
905 | osd_end_request(or); | 896 | exofs_put_io_state(ios); |
906 | return ret; | 897 | return ret; |
907 | } | 898 | } |
908 | 899 | ||
900 | static void __oi_init(struct exofs_i_info *oi) | ||
901 | { | ||
902 | init_waitqueue_head(&oi->i_wq); | ||
903 | oi->i_flags = 0; | ||
904 | } | ||
909 | /* | 905 | /* |
910 | * Fill in an inode read from the OSD and set it up for use | 906 | * Fill in an inode read from the OSD and set it up for use |
911 | */ | 907 | */ |
@@ -914,7 +910,7 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino) | |||
914 | struct exofs_i_info *oi; | 910 | struct exofs_i_info *oi; |
915 | struct exofs_fcb fcb; | 911 | struct exofs_fcb fcb; |
916 | struct inode *inode; | 912 | struct inode *inode; |
917 | uint64_t uninitialized_var(sanity); | 913 | uint64_t obj_size; |
918 | int ret; | 914 | int ret; |
919 | 915 | ||
920 | inode = iget_locked(sb, ino); | 916 | inode = iget_locked(sb, ino); |
@@ -923,13 +919,13 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino) | |||
923 | if (!(inode->i_state & I_NEW)) | 919 | if (!(inode->i_state & I_NEW)) |
924 | return inode; | 920 | return inode; |
925 | oi = exofs_i(inode); | 921 | oi = exofs_i(inode); |
922 | __oi_init(oi); | ||
926 | 923 | ||
927 | /* read the inode from the osd */ | 924 | /* read the inode from the osd */ |
928 | ret = exofs_get_inode(sb, oi, &fcb, &sanity); | 925 | ret = exofs_get_inode(sb, oi, &fcb, &obj_size); |
929 | if (ret) | 926 | if (ret) |
930 | goto bad_inode; | 927 | goto bad_inode; |
931 | 928 | ||
932 | init_waitqueue_head(&oi->i_wq); | ||
933 | set_obj_created(oi); | 929 | set_obj_created(oi); |
934 | 930 | ||
935 | /* copy stuff from on-disk struct to in-memory struct */ | 931 | /* copy stuff from on-disk struct to in-memory struct */ |
@@ -947,14 +943,12 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino) | |||
947 | inode->i_blkbits = EXOFS_BLKSHIFT; | 943 | inode->i_blkbits = EXOFS_BLKSHIFT; |
948 | inode->i_generation = le32_to_cpu(fcb.i_generation); | 944 | inode->i_generation = le32_to_cpu(fcb.i_generation); |
949 | 945 | ||
950 | #ifdef EXOFS_DEBUG_OBJ_ISIZE | 946 | if ((inode->i_size != obj_size) && |
951 | if ((inode->i_size != sanity) && | ||
952 | (!exofs_inode_is_fast_symlink(inode))) { | 947 | (!exofs_inode_is_fast_symlink(inode))) { |
953 | EXOFS_ERR("WARNING: Size of object from inode and " | 948 | EXOFS_ERR("WARNING: Size of inode=%llu != object=%llu\n", |
954 | "attributes differ (%lld != %llu)\n", | 949 | inode->i_size, _LLU(obj_size)); |
955 | inode->i_size, _LLU(sanity)); | 950 | /* FIXME: call exofs_inode_recovery() */ |
956 | } | 951 | } |
957 | #endif | ||
958 | 952 | ||
959 | oi->i_dir_start_lookup = 0; | 953 | oi->i_dir_start_lookup = 0; |
960 | 954 | ||
@@ -1020,23 +1014,30 @@ int __exofs_wait_obj_created(struct exofs_i_info *oi) | |||
1020 | * set the obj_created flag so that other methods know that the object exists on | 1014 | * set the obj_created flag so that other methods know that the object exists on |
1021 | * the OSD. | 1015 | * the OSD. |
1022 | */ | 1016 | */ |
1023 | static void create_done(struct osd_request *or, void *p) | 1017 | static void create_done(struct exofs_io_state *ios, void *p) |
1024 | { | 1018 | { |
1025 | struct inode *inode = p; | 1019 | struct inode *inode = p; |
1026 | struct exofs_i_info *oi = exofs_i(inode); | 1020 | struct exofs_i_info *oi = exofs_i(inode); |
1027 | struct exofs_sb_info *sbi = inode->i_sb->s_fs_info; | 1021 | struct exofs_sb_info *sbi = inode->i_sb->s_fs_info; |
1028 | int ret; | 1022 | int ret; |
1029 | 1023 | ||
1030 | ret = exofs_check_ok(or); | 1024 | ret = exofs_check_io(ios, NULL); |
1031 | osd_end_request(or); | 1025 | exofs_put_io_state(ios); |
1026 | |||
1032 | atomic_dec(&sbi->s_curr_pending); | 1027 | atomic_dec(&sbi->s_curr_pending); |
1033 | 1028 | ||
1034 | if (unlikely(ret)) { | 1029 | if (unlikely(ret)) { |
1035 | EXOFS_ERR("object=0x%llx creation faild in pid=0x%llx", | 1030 | EXOFS_ERR("object=0x%llx creation faild in pid=0x%llx", |
1036 | _LLU(sbi->s_pid), _LLU(inode->i_ino + EXOFS_OBJ_OFF)); | 1031 | _LLU(exofs_oi_objno(oi)), _LLU(sbi->s_pid)); |
1037 | make_bad_inode(inode); | 1032 | /*TODO: When FS is corrupted creation can fail, object already |
1038 | } else | 1033 | * exist. Get rid of this asynchronous creation, if exist |
1039 | set_obj_created(oi); | 1034 | * increment the obj counter and try the next object. Until we |
1035 | * succeed. All these dangling objects will be made into lost | ||
1036 | * files by chkfs.exofs | ||
1037 | */ | ||
1038 | } | ||
1039 | |||
1040 | set_obj_created(oi); | ||
1040 | 1041 | ||
1041 | atomic_dec(&inode->i_count); | 1042 | atomic_dec(&inode->i_count); |
1042 | wake_up(&oi->i_wq); | 1043 | wake_up(&oi->i_wq); |
@@ -1051,8 +1052,7 @@ struct inode *exofs_new_inode(struct inode *dir, int mode) | |||
1051 | struct inode *inode; | 1052 | struct inode *inode; |
1052 | struct exofs_i_info *oi; | 1053 | struct exofs_i_info *oi; |
1053 | struct exofs_sb_info *sbi; | 1054 | struct exofs_sb_info *sbi; |
1054 | struct osd_request *or; | 1055 | struct exofs_io_state *ios; |
1055 | struct osd_obj_id obj; | ||
1056 | int ret; | 1056 | int ret; |
1057 | 1057 | ||
1058 | sb = dir->i_sb; | 1058 | sb = dir->i_sb; |
@@ -1061,8 +1061,8 @@ struct inode *exofs_new_inode(struct inode *dir, int mode) | |||
1061 | return ERR_PTR(-ENOMEM); | 1061 | return ERR_PTR(-ENOMEM); |
1062 | 1062 | ||
1063 | oi = exofs_i(inode); | 1063 | oi = exofs_i(inode); |
1064 | __oi_init(oi); | ||
1064 | 1065 | ||
1065 | init_waitqueue_head(&oi->i_wq); | ||
1066 | set_obj_2bcreated(oi); | 1066 | set_obj_2bcreated(oi); |
1067 | 1067 | ||
1068 | sbi = sb->s_fs_info; | 1068 | sbi = sb->s_fs_info; |
@@ -1089,28 +1089,28 @@ struct inode *exofs_new_inode(struct inode *dir, int mode) | |||
1089 | 1089 | ||
1090 | mark_inode_dirty(inode); | 1090 | mark_inode_dirty(inode); |
1091 | 1091 | ||
1092 | obj.partition = sbi->s_pid; | 1092 | ret = exofs_get_io_state(sbi, &ios); |
1093 | obj.id = inode->i_ino + EXOFS_OBJ_OFF; | 1093 | if (unlikely(ret)) { |
1094 | exofs_make_credential(oi->i_cred, &obj); | 1094 | EXOFS_ERR("exofs_new_inode: exofs_get_io_state failed\n"); |
1095 | 1095 | return ERR_PTR(ret); | |
1096 | or = osd_start_request(sbi->s_dev, GFP_KERNEL); | ||
1097 | if (unlikely(!or)) { | ||
1098 | EXOFS_ERR("exofs_new_inode: osd_start_request failed\n"); | ||
1099 | return ERR_PTR(-ENOMEM); | ||
1100 | } | 1096 | } |
1101 | 1097 | ||
1102 | osd_req_create_object(or, &obj); | 1098 | ios->obj.id = exofs_oi_objno(oi); |
1099 | exofs_make_credential(oi->i_cred, &ios->obj); | ||
1103 | 1100 | ||
1104 | /* increment the refcount so that the inode will still be around when we | 1101 | /* increment the refcount so that the inode will still be around when we |
1105 | * reach the callback | 1102 | * reach the callback |
1106 | */ | 1103 | */ |
1107 | atomic_inc(&inode->i_count); | 1104 | atomic_inc(&inode->i_count); |
1108 | 1105 | ||
1109 | ret = exofs_async_op(or, create_done, inode, oi->i_cred); | 1106 | ios->done = create_done; |
1107 | ios->private = inode; | ||
1108 | ios->cred = oi->i_cred; | ||
1109 | ret = exofs_sbi_create(ios); | ||
1110 | if (ret) { | 1110 | if (ret) { |
1111 | atomic_dec(&inode->i_count); | 1111 | atomic_dec(&inode->i_count); |
1112 | osd_end_request(or); | 1112 | exofs_put_io_state(ios); |
1113 | return ERR_PTR(-EIO); | 1113 | return ERR_PTR(ret); |
1114 | } | 1114 | } |
1115 | atomic_inc(&sbi->s_curr_pending); | 1115 | atomic_inc(&sbi->s_curr_pending); |
1116 | 1116 | ||
@@ -1128,11 +1128,11 @@ struct updatei_args { | |||
1128 | /* | 1128 | /* |
1129 | * Callback function from exofs_update_inode(). | 1129 | * Callback function from exofs_update_inode(). |
1130 | */ | 1130 | */ |
1131 | static void updatei_done(struct osd_request *or, void *p) | 1131 | static void updatei_done(struct exofs_io_state *ios, void *p) |
1132 | { | 1132 | { |
1133 | struct updatei_args *args = p; | 1133 | struct updatei_args *args = p; |
1134 | 1134 | ||
1135 | osd_end_request(or); | 1135 | exofs_put_io_state(ios); |
1136 | 1136 | ||
1137 | atomic_dec(&args->sbi->s_curr_pending); | 1137 | atomic_dec(&args->sbi->s_curr_pending); |
1138 | 1138 | ||
@@ -1148,8 +1148,7 @@ static int exofs_update_inode(struct inode *inode, int do_sync) | |||
1148 | struct exofs_i_info *oi = exofs_i(inode); | 1148 | struct exofs_i_info *oi = exofs_i(inode); |
1149 | struct super_block *sb = inode->i_sb; | 1149 | struct super_block *sb = inode->i_sb; |
1150 | struct exofs_sb_info *sbi = sb->s_fs_info; | 1150 | struct exofs_sb_info *sbi = sb->s_fs_info; |
1151 | struct osd_obj_id obj = {sbi->s_pid, inode->i_ino + EXOFS_OBJ_OFF}; | 1151 | struct exofs_io_state *ios; |
1152 | struct osd_request *or; | ||
1153 | struct osd_attr attr; | 1152 | struct osd_attr attr; |
1154 | struct exofs_fcb *fcb; | 1153 | struct exofs_fcb *fcb; |
1155 | struct updatei_args *args; | 1154 | struct updatei_args *args; |
@@ -1186,18 +1185,16 @@ static int exofs_update_inode(struct inode *inode, int do_sync) | |||
1186 | } else | 1185 | } else |
1187 | memcpy(fcb->i_data, oi->i_data, sizeof(fcb->i_data)); | 1186 | memcpy(fcb->i_data, oi->i_data, sizeof(fcb->i_data)); |
1188 | 1187 | ||
1189 | or = osd_start_request(sbi->s_dev, GFP_KERNEL); | 1188 | ret = exofs_get_io_state(sbi, &ios); |
1190 | if (unlikely(!or)) { | 1189 | if (unlikely(ret)) { |
1191 | EXOFS_ERR("exofs_update_inode: osd_start_request failed.\n"); | 1190 | EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__); |
1192 | ret = -ENOMEM; | ||
1193 | goto free_args; | 1191 | goto free_args; |
1194 | } | 1192 | } |
1195 | 1193 | ||
1196 | osd_req_set_attributes(or, &obj); | ||
1197 | |||
1198 | attr = g_attr_inode_data; | 1194 | attr = g_attr_inode_data; |
1199 | attr.val_ptr = fcb; | 1195 | attr.val_ptr = fcb; |
1200 | osd_req_add_set_attr_list(or, &attr, 1); | 1196 | ios->out_attr_len = 1; |
1197 | ios->out_attr = &attr; | ||
1201 | 1198 | ||
1202 | if (!obj_created(oi)) { | 1199 | if (!obj_created(oi)) { |
1203 | EXOFS_DBGMSG("!obj_created\n"); | 1200 | EXOFS_DBGMSG("!obj_created\n"); |
@@ -1206,22 +1203,19 @@ static int exofs_update_inode(struct inode *inode, int do_sync) | |||
1206 | EXOFS_DBGMSG("wait_event done\n"); | 1203 | EXOFS_DBGMSG("wait_event done\n"); |
1207 | } | 1204 | } |
1208 | 1205 | ||
1209 | if (do_sync) { | 1206 | if (!do_sync) { |
1210 | ret = exofs_sync_op(or, sbi->s_timeout, oi->i_cred); | ||
1211 | osd_end_request(or); | ||
1212 | goto free_args; | ||
1213 | } else { | ||
1214 | args->sbi = sbi; | 1207 | args->sbi = sbi; |
1208 | ios->done = updatei_done; | ||
1209 | ios->private = args; | ||
1210 | } | ||
1215 | 1211 | ||
1216 | ret = exofs_async_op(or, updatei_done, args, oi->i_cred); | 1212 | ret = exofs_oi_write(oi, ios); |
1217 | if (ret) { | 1213 | if (!do_sync && !ret) { |
1218 | osd_end_request(or); | ||
1219 | goto free_args; | ||
1220 | } | ||
1221 | atomic_inc(&sbi->s_curr_pending); | 1214 | atomic_inc(&sbi->s_curr_pending); |
1222 | goto out; /* deallocation in updatei_done */ | 1215 | goto out; /* deallocation in updatei_done */ |
1223 | } | 1216 | } |
1224 | 1217 | ||
1218 | exofs_put_io_state(ios); | ||
1225 | free_args: | 1219 | free_args: |
1226 | kfree(args); | 1220 | kfree(args); |
1227 | out: | 1221 | out: |
@@ -1238,11 +1232,12 @@ int exofs_write_inode(struct inode *inode, int wait) | |||
1238 | * Callback function from exofs_delete_inode() - don't have much cleaning up to | 1232 | * Callback function from exofs_delete_inode() - don't have much cleaning up to |
1239 | * do. | 1233 | * do. |
1240 | */ | 1234 | */ |
1241 | static void delete_done(struct osd_request *or, void *p) | 1235 | static void delete_done(struct exofs_io_state *ios, void *p) |
1242 | { | 1236 | { |
1243 | struct exofs_sb_info *sbi; | 1237 | struct exofs_sb_info *sbi = p; |
1244 | osd_end_request(or); | 1238 | |
1245 | sbi = p; | 1239 | exofs_put_io_state(ios); |
1240 | |||
1246 | atomic_dec(&sbi->s_curr_pending); | 1241 | atomic_dec(&sbi->s_curr_pending); |
1247 | } | 1242 | } |
1248 | 1243 | ||
@@ -1256,8 +1251,7 @@ void exofs_delete_inode(struct inode *inode) | |||
1256 | struct exofs_i_info *oi = exofs_i(inode); | 1251 | struct exofs_i_info *oi = exofs_i(inode); |
1257 | struct super_block *sb = inode->i_sb; | 1252 | struct super_block *sb = inode->i_sb; |
1258 | struct exofs_sb_info *sbi = sb->s_fs_info; | 1253 | struct exofs_sb_info *sbi = sb->s_fs_info; |
1259 | struct osd_obj_id obj = {sbi->s_pid, inode->i_ino + EXOFS_OBJ_OFF}; | 1254 | struct exofs_io_state *ios; |
1260 | struct osd_request *or; | ||
1261 | int ret; | 1255 | int ret; |
1262 | 1256 | ||
1263 | truncate_inode_pages(&inode->i_data, 0); | 1257 | truncate_inode_pages(&inode->i_data, 0); |
@@ -1274,25 +1268,26 @@ void exofs_delete_inode(struct inode *inode) | |||
1274 | 1268 | ||
1275 | clear_inode(inode); | 1269 | clear_inode(inode); |
1276 | 1270 | ||
1277 | or = osd_start_request(sbi->s_dev, GFP_KERNEL); | 1271 | ret = exofs_get_io_state(sbi, &ios); |
1278 | if (unlikely(!or)) { | 1272 | if (unlikely(ret)) { |
1279 | EXOFS_ERR("exofs_delete_inode: osd_start_request failed\n"); | 1273 | EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__); |
1280 | return; | 1274 | return; |
1281 | } | 1275 | } |
1282 | 1276 | ||
1283 | osd_req_remove_object(or, &obj); | ||
1284 | |||
1285 | /* if we are deleting an obj that hasn't been created yet, wait */ | 1277 | /* if we are deleting an obj that hasn't been created yet, wait */ |
1286 | if (!obj_created(oi)) { | 1278 | if (!obj_created(oi)) { |
1287 | BUG_ON(!obj_2bcreated(oi)); | 1279 | BUG_ON(!obj_2bcreated(oi)); |
1288 | wait_event(oi->i_wq, obj_created(oi)); | 1280 | wait_event(oi->i_wq, obj_created(oi)); |
1289 | } | 1281 | } |
1290 | 1282 | ||
1291 | ret = exofs_async_op(or, delete_done, sbi, oi->i_cred); | 1283 | ios->obj.id = exofs_oi_objno(oi); |
1284 | ios->done = delete_done; | ||
1285 | ios->private = sbi; | ||
1286 | ios->cred = oi->i_cred; | ||
1287 | ret = exofs_sbi_remove(ios); | ||
1292 | if (ret) { | 1288 | if (ret) { |
1293 | EXOFS_ERR( | 1289 | EXOFS_ERR("%s: exofs_sbi_remove failed\n", __func__); |
1294 | "ERROR: @exofs_delete_inode exofs_async_op failed\n"); | 1290 | exofs_put_io_state(ios); |
1295 | osd_end_request(or); | ||
1296 | return; | 1291 | return; |
1297 | } | 1292 | } |
1298 | atomic_inc(&sbi->s_curr_pending); | 1293 | atomic_inc(&sbi->s_curr_pending); |
diff --git a/fs/exofs/ios.c b/fs/exofs/ios.c new file mode 100644 index 000000000000..5bad01fa1f9f --- /dev/null +++ b/fs/exofs/ios.c | |||
@@ -0,0 +1,421 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005, 2006 | ||
3 | * Avishay Traeger (avishay@gmail.com) | ||
4 | * Copyright (C) 2008, 2009 | ||
5 | * Boaz Harrosh <bharrosh@panasas.com> | ||
6 | * | ||
7 | * This file is part of exofs. | ||
8 | * | ||
9 | * exofs is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation. Since it is based on ext2, and the only | ||
12 | * valid version of GPL for the Linux kernel is version 2, the only valid | ||
13 | * version of GPL for exofs is version 2. | ||
14 | * | ||
15 | * exofs is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with exofs; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
23 | */ | ||
24 | |||
25 | #include <scsi/scsi_device.h> | ||
26 | |||
27 | #include "exofs.h" | ||
28 | |||
29 | void exofs_make_credential(u8 cred_a[OSD_CAP_LEN], const struct osd_obj_id *obj) | ||
30 | { | ||
31 | osd_sec_init_nosec_doall_caps(cred_a, obj, false, true); | ||
32 | } | ||
33 | |||
34 | int exofs_read_kern(struct osd_dev *od, u8 *cred, struct osd_obj_id *obj, | ||
35 | u64 offset, void *p, unsigned length) | ||
36 | { | ||
37 | struct osd_request *or = osd_start_request(od, GFP_KERNEL); | ||
38 | /* struct osd_sense_info osi = {.key = 0};*/ | ||
39 | int ret; | ||
40 | |||
41 | if (unlikely(!or)) { | ||
42 | EXOFS_DBGMSG("%s: osd_start_request failed.\n", __func__); | ||
43 | return -ENOMEM; | ||
44 | } | ||
45 | ret = osd_req_read_kern(or, obj, offset, p, length); | ||
46 | if (unlikely(ret)) { | ||
47 | EXOFS_DBGMSG("%s: osd_req_read_kern failed.\n", __func__); | ||
48 | goto out; | ||
49 | } | ||
50 | |||
51 | ret = osd_finalize_request(or, 0, cred, NULL); | ||
52 | if (unlikely(ret)) { | ||
53 | EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret); | ||
54 | goto out; | ||
55 | } | ||
56 | |||
57 | ret = osd_execute_request(or); | ||
58 | if (unlikely(ret)) | ||
59 | EXOFS_DBGMSG("osd_execute_request() => %d\n", ret); | ||
60 | /* osd_req_decode_sense(or, ret); */ | ||
61 | |||
62 | out: | ||
63 | osd_end_request(or); | ||
64 | return ret; | ||
65 | } | ||
66 | |||
67 | int exofs_get_io_state(struct exofs_sb_info *sbi, struct exofs_io_state** pios) | ||
68 | { | ||
69 | struct exofs_io_state *ios; | ||
70 | |||
71 | /*TODO: Maybe use kmem_cach per sbi of size | ||
72 | * exofs_io_state_size(sbi->s_numdevs) | ||
73 | */ | ||
74 | ios = kzalloc(exofs_io_state_size(sbi->s_numdevs), GFP_KERNEL); | ||
75 | if (unlikely(!ios)) { | ||
76 | *pios = NULL; | ||
77 | return -ENOMEM; | ||
78 | } | ||
79 | |||
80 | ios->sbi = sbi; | ||
81 | ios->obj.partition = sbi->s_pid; | ||
82 | *pios = ios; | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | void exofs_put_io_state(struct exofs_io_state *ios) | ||
87 | { | ||
88 | if (ios) { | ||
89 | unsigned i; | ||
90 | |||
91 | for (i = 0; i < ios->numdevs; i++) { | ||
92 | struct exofs_per_dev_state *per_dev = &ios->per_dev[i]; | ||
93 | |||
94 | if (per_dev->or) | ||
95 | osd_end_request(per_dev->or); | ||
96 | if (per_dev->bio) | ||
97 | bio_put(per_dev->bio); | ||
98 | } | ||
99 | |||
100 | kfree(ios); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | static void _sync_done(struct exofs_io_state *ios, void *p) | ||
105 | { | ||
106 | struct completion *waiting = p; | ||
107 | |||
108 | complete(waiting); | ||
109 | } | ||
110 | |||
111 | static void _last_io(struct kref *kref) | ||
112 | { | ||
113 | struct exofs_io_state *ios = container_of( | ||
114 | kref, struct exofs_io_state, kref); | ||
115 | |||
116 | ios->done(ios, ios->private); | ||
117 | } | ||
118 | |||
119 | static void _done_io(struct osd_request *or, void *p) | ||
120 | { | ||
121 | struct exofs_io_state *ios = p; | ||
122 | |||
123 | kref_put(&ios->kref, _last_io); | ||
124 | } | ||
125 | |||
126 | static int exofs_io_execute(struct exofs_io_state *ios) | ||
127 | { | ||
128 | DECLARE_COMPLETION_ONSTACK(wait); | ||
129 | bool sync = (ios->done == NULL); | ||
130 | int i, ret; | ||
131 | |||
132 | if (sync) { | ||
133 | ios->done = _sync_done; | ||
134 | ios->private = &wait; | ||
135 | } | ||
136 | |||
137 | for (i = 0; i < ios->numdevs; i++) { | ||
138 | struct osd_request *or = ios->per_dev[i].or; | ||
139 | if (unlikely(!or)) | ||
140 | continue; | ||
141 | |||
142 | ret = osd_finalize_request(or, 0, ios->cred, NULL); | ||
143 | if (unlikely(ret)) { | ||
144 | EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", | ||
145 | ret); | ||
146 | return ret; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | kref_init(&ios->kref); | ||
151 | |||
152 | for (i = 0; i < ios->numdevs; i++) { | ||
153 | struct osd_request *or = ios->per_dev[i].or; | ||
154 | if (unlikely(!or)) | ||
155 | continue; | ||
156 | |||
157 | kref_get(&ios->kref); | ||
158 | osd_execute_request_async(or, _done_io, ios); | ||
159 | } | ||
160 | |||
161 | kref_put(&ios->kref, _last_io); | ||
162 | ret = 0; | ||
163 | |||
164 | if (sync) { | ||
165 | wait_for_completion(&wait); | ||
166 | ret = exofs_check_io(ios, NULL); | ||
167 | } | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | int exofs_check_io(struct exofs_io_state *ios, u64 *resid) | ||
172 | { | ||
173 | enum osd_err_priority acumulated_osd_err = 0; | ||
174 | int acumulated_lin_err = 0; | ||
175 | int i; | ||
176 | |||
177 | for (i = 0; i < ios->numdevs; i++) { | ||
178 | struct osd_sense_info osi; | ||
179 | int ret = osd_req_decode_sense(ios->per_dev[i].or, &osi); | ||
180 | |||
181 | if (likely(!ret)) | ||
182 | continue; | ||
183 | |||
184 | if (unlikely(ret == -EFAULT)) { | ||
185 | EXOFS_DBGMSG("%s: EFAULT Need page clear\n", __func__); | ||
186 | /*FIXME: All the pages in this device range should: | ||
187 | * clear_highpage(page); | ||
188 | */ | ||
189 | } | ||
190 | |||
191 | if (osi.osd_err_pri >= acumulated_osd_err) { | ||
192 | acumulated_osd_err = osi.osd_err_pri; | ||
193 | acumulated_lin_err = ret; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /* TODO: raid specific residual calculations */ | ||
198 | if (resid) { | ||
199 | if (likely(!acumulated_lin_err)) | ||
200 | *resid = 0; | ||
201 | else | ||
202 | *resid = ios->length; | ||
203 | } | ||
204 | |||
205 | return acumulated_lin_err; | ||
206 | } | ||
207 | |||
208 | int exofs_sbi_create(struct exofs_io_state *ios) | ||
209 | { | ||
210 | int i, ret; | ||
211 | |||
212 | for (i = 0; i < ios->sbi->s_numdevs; i++) { | ||
213 | struct osd_request *or; | ||
214 | |||
215 | or = osd_start_request(ios->sbi->s_ods[i], GFP_KERNEL); | ||
216 | if (unlikely(!or)) { | ||
217 | EXOFS_ERR("%s: osd_start_request failed\n", __func__); | ||
218 | ret = -ENOMEM; | ||
219 | goto out; | ||
220 | } | ||
221 | ios->per_dev[i].or = or; | ||
222 | ios->numdevs++; | ||
223 | |||
224 | osd_req_create_object(or, &ios->obj); | ||
225 | } | ||
226 | ret = exofs_io_execute(ios); | ||
227 | |||
228 | out: | ||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | int exofs_sbi_remove(struct exofs_io_state *ios) | ||
233 | { | ||
234 | int i, ret; | ||
235 | |||
236 | for (i = 0; i < ios->sbi->s_numdevs; i++) { | ||
237 | struct osd_request *or; | ||
238 | |||
239 | or = osd_start_request(ios->sbi->s_ods[i], GFP_KERNEL); | ||
240 | if (unlikely(!or)) { | ||
241 | EXOFS_ERR("%s: osd_start_request failed\n", __func__); | ||
242 | ret = -ENOMEM; | ||
243 | goto out; | ||
244 | } | ||
245 | ios->per_dev[i].or = or; | ||
246 | ios->numdevs++; | ||
247 | |||
248 | osd_req_remove_object(or, &ios->obj); | ||
249 | } | ||
250 | ret = exofs_io_execute(ios); | ||
251 | |||
252 | out: | ||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | int exofs_sbi_write(struct exofs_io_state *ios) | ||
257 | { | ||
258 | int i, ret; | ||
259 | |||
260 | for (i = 0; i < ios->sbi->s_numdevs; i++) { | ||
261 | struct osd_request *or; | ||
262 | |||
263 | or = osd_start_request(ios->sbi->s_ods[i], GFP_KERNEL); | ||
264 | if (unlikely(!or)) { | ||
265 | EXOFS_ERR("%s: osd_start_request failed\n", __func__); | ||
266 | ret = -ENOMEM; | ||
267 | goto out; | ||
268 | } | ||
269 | ios->per_dev[i].or = or; | ||
270 | ios->numdevs++; | ||
271 | |||
272 | if (ios->bio) { | ||
273 | struct bio *bio; | ||
274 | |||
275 | if (i != 0) { | ||
276 | bio = bio_kmalloc(GFP_KERNEL, | ||
277 | ios->bio->bi_max_vecs); | ||
278 | if (unlikely(!bio)) { | ||
279 | ret = -ENOMEM; | ||
280 | goto out; | ||
281 | } | ||
282 | |||
283 | __bio_clone(bio, ios->bio); | ||
284 | bio->bi_bdev = NULL; | ||
285 | bio->bi_next = NULL; | ||
286 | ios->per_dev[i].bio = bio; | ||
287 | } else { | ||
288 | bio = ios->bio; | ||
289 | } | ||
290 | |||
291 | osd_req_write(or, &ios->obj, ios->offset, bio, | ||
292 | ios->length); | ||
293 | /* EXOFS_DBGMSG("write sync=%d\n", sync);*/ | ||
294 | } else if (ios->kern_buff) { | ||
295 | osd_req_write_kern(or, &ios->obj, ios->offset, | ||
296 | ios->kern_buff, ios->length); | ||
297 | /* EXOFS_DBGMSG("write_kern sync=%d\n", sync);*/ | ||
298 | } else { | ||
299 | osd_req_set_attributes(or, &ios->obj); | ||
300 | /* EXOFS_DBGMSG("set_attributes sync=%d\n", sync);*/ | ||
301 | } | ||
302 | |||
303 | if (ios->out_attr) | ||
304 | osd_req_add_set_attr_list(or, ios->out_attr, | ||
305 | ios->out_attr_len); | ||
306 | |||
307 | if (ios->in_attr) | ||
308 | osd_req_add_get_attr_list(or, ios->in_attr, | ||
309 | ios->in_attr_len); | ||
310 | } | ||
311 | ret = exofs_io_execute(ios); | ||
312 | |||
313 | out: | ||
314 | return ret; | ||
315 | } | ||
316 | |||
317 | int exofs_sbi_read(struct exofs_io_state *ios) | ||
318 | { | ||
319 | int i, ret; | ||
320 | |||
321 | for (i = 0; i < 1; i++) { | ||
322 | struct osd_request *or; | ||
323 | unsigned first_dev = (unsigned)ios->obj.id; | ||
324 | |||
325 | first_dev %= ios->sbi->s_numdevs; | ||
326 | or = osd_start_request(ios->sbi->s_ods[first_dev], GFP_KERNEL); | ||
327 | if (unlikely(!or)) { | ||
328 | EXOFS_ERR("%s: osd_start_request failed\n", __func__); | ||
329 | ret = -ENOMEM; | ||
330 | goto out; | ||
331 | } | ||
332 | ios->per_dev[i].or = or; | ||
333 | ios->numdevs++; | ||
334 | |||
335 | if (ios->bio) { | ||
336 | osd_req_read(or, &ios->obj, ios->offset, ios->bio, | ||
337 | ios->length); | ||
338 | /* EXOFS_DBGMSG("read sync=%d\n", sync);*/ | ||
339 | } else if (ios->kern_buff) { | ||
340 | osd_req_read_kern(or, &ios->obj, ios->offset, | ||
341 | ios->kern_buff, ios->length); | ||
342 | /* EXOFS_DBGMSG("read_kern sync=%d\n", sync);*/ | ||
343 | } else { | ||
344 | osd_req_get_attributes(or, &ios->obj); | ||
345 | /* EXOFS_DBGMSG("get_attributes sync=%d\n", sync);*/ | ||
346 | } | ||
347 | |||
348 | if (ios->out_attr) | ||
349 | osd_req_add_set_attr_list(or, ios->out_attr, | ||
350 | ios->out_attr_len); | ||
351 | |||
352 | if (ios->in_attr) | ||
353 | osd_req_add_get_attr_list(or, ios->in_attr, | ||
354 | ios->in_attr_len); | ||
355 | } | ||
356 | ret = exofs_io_execute(ios); | ||
357 | |||
358 | out: | ||
359 | return ret; | ||
360 | } | ||
361 | |||
362 | int extract_attr_from_ios(struct exofs_io_state *ios, struct osd_attr *attr) | ||
363 | { | ||
364 | struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */ | ||
365 | void *iter = NULL; | ||
366 | int nelem; | ||
367 | |||
368 | do { | ||
369 | nelem = 1; | ||
370 | osd_req_decode_get_attr_list(ios->per_dev[0].or, | ||
371 | &cur_attr, &nelem, &iter); | ||
372 | if ((cur_attr.attr_page == attr->attr_page) && | ||
373 | (cur_attr.attr_id == attr->attr_id)) { | ||
374 | attr->len = cur_attr.len; | ||
375 | attr->val_ptr = cur_attr.val_ptr; | ||
376 | return 0; | ||
377 | } | ||
378 | } while (iter); | ||
379 | |||
380 | return -EIO; | ||
381 | } | ||
382 | |||
383 | int exofs_oi_truncate(struct exofs_i_info *oi, u64 size) | ||
384 | { | ||
385 | struct exofs_sb_info *sbi = oi->vfs_inode.i_sb->s_fs_info; | ||
386 | struct exofs_io_state *ios; | ||
387 | struct osd_attr attr; | ||
388 | __be64 newsize; | ||
389 | int i, ret; | ||
390 | |||
391 | if (exofs_get_io_state(sbi, &ios)) | ||
392 | return -ENOMEM; | ||
393 | |||
394 | ios->obj.id = exofs_oi_objno(oi); | ||
395 | ios->cred = oi->i_cred; | ||
396 | |||
397 | newsize = cpu_to_be64(size); | ||
398 | attr = g_attr_logical_length; | ||
399 | attr.val_ptr = &newsize; | ||
400 | |||
401 | for (i = 0; i < sbi->s_numdevs; i++) { | ||
402 | struct osd_request *or; | ||
403 | |||
404 | or = osd_start_request(sbi->s_ods[i], GFP_KERNEL); | ||
405 | if (unlikely(!or)) { | ||
406 | EXOFS_ERR("%s: osd_start_request failed\n", __func__); | ||
407 | ret = -ENOMEM; | ||
408 | goto out; | ||
409 | } | ||
410 | ios->per_dev[i].or = or; | ||
411 | ios->numdevs++; | ||
412 | |||
413 | osd_req_set_attributes(or, &ios->obj); | ||
414 | osd_req_add_set_attr_list(or, &attr, 1); | ||
415 | } | ||
416 | ret = exofs_io_execute(ios); | ||
417 | |||
418 | out: | ||
419 | exofs_put_io_state(ios); | ||
420 | return ret; | ||
421 | } | ||
diff --git a/fs/exofs/osd.c b/fs/exofs/osd.c deleted file mode 100644 index 4372542df284..000000000000 --- a/fs/exofs/osd.c +++ /dev/null | |||
@@ -1,125 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005, 2006 | ||
3 | * Avishay Traeger (avishay@gmail.com) | ||
4 | * Copyright (C) 2008, 2009 | ||
5 | * Boaz Harrosh <bharrosh@panasas.com> | ||
6 | * | ||
7 | * This file is part of exofs. | ||
8 | * | ||
9 | * exofs is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation. Since it is based on ext2, and the only | ||
12 | * valid version of GPL for the Linux kernel is version 2, the only valid | ||
13 | * version of GPL for exofs is version 2. | ||
14 | * | ||
15 | * exofs is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with exofs; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
23 | */ | ||
24 | |||
25 | #include <scsi/scsi_device.h> | ||
26 | #include <scsi/osd_sense.h> | ||
27 | |||
28 | #include "exofs.h" | ||
29 | |||
30 | int exofs_check_ok_resid(struct osd_request *or, u64 *in_resid, u64 *out_resid) | ||
31 | { | ||
32 | struct osd_sense_info osi; | ||
33 | int ret = osd_req_decode_sense(or, &osi); | ||
34 | |||
35 | if (ret) { /* translate to Linux codes */ | ||
36 | if (osi.additional_code == scsi_invalid_field_in_cdb) { | ||
37 | if (osi.cdb_field_offset == OSD_CFO_STARTING_BYTE) | ||
38 | ret = -EFAULT; | ||
39 | if (osi.cdb_field_offset == OSD_CFO_OBJECT_ID) | ||
40 | ret = -ENOENT; | ||
41 | else | ||
42 | ret = -EINVAL; | ||
43 | } else if (osi.additional_code == osd_quota_error) | ||
44 | ret = -ENOSPC; | ||
45 | else | ||
46 | ret = -EIO; | ||
47 | } | ||
48 | |||
49 | /* FIXME: should be include in osd_sense_info */ | ||
50 | if (in_resid) | ||
51 | *in_resid = or->in.req ? or->in.req->resid_len : 0; | ||
52 | |||
53 | if (out_resid) | ||
54 | *out_resid = or->out.req ? or->out.req->resid_len : 0; | ||
55 | |||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | void exofs_make_credential(u8 cred_a[OSD_CAP_LEN], const struct osd_obj_id *obj) | ||
60 | { | ||
61 | osd_sec_init_nosec_doall_caps(cred_a, obj, false, true); | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * Perform a synchronous OSD operation. | ||
66 | */ | ||
67 | int exofs_sync_op(struct osd_request *or, int timeout, uint8_t *credential) | ||
68 | { | ||
69 | int ret; | ||
70 | |||
71 | or->timeout = timeout; | ||
72 | ret = osd_finalize_request(or, 0, credential, NULL); | ||
73 | if (ret) { | ||
74 | EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret); | ||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | ret = osd_execute_request(or); | ||
79 | |||
80 | if (ret) | ||
81 | EXOFS_DBGMSG("osd_execute_request() => %d\n", ret); | ||
82 | /* osd_req_decode_sense(or, ret); */ | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * Perform an asynchronous OSD operation. | ||
88 | */ | ||
89 | int exofs_async_op(struct osd_request *or, osd_req_done_fn *async_done, | ||
90 | void *caller_context, u8 *cred) | ||
91 | { | ||
92 | int ret; | ||
93 | |||
94 | ret = osd_finalize_request(or, 0, cred, NULL); | ||
95 | if (ret) { | ||
96 | EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret); | ||
97 | return ret; | ||
98 | } | ||
99 | |||
100 | ret = osd_execute_request_async(or, async_done, caller_context); | ||
101 | |||
102 | if (ret) | ||
103 | EXOFS_DBGMSG("osd_execute_request_async() => %d\n", ret); | ||
104 | return ret; | ||
105 | } | ||
106 | |||
107 | int extract_attr_from_req(struct osd_request *or, struct osd_attr *attr) | ||
108 | { | ||
109 | struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */ | ||
110 | void *iter = NULL; | ||
111 | int nelem; | ||
112 | |||
113 | do { | ||
114 | nelem = 1; | ||
115 | osd_req_decode_get_attr_list(or, &cur_attr, &nelem, &iter); | ||
116 | if ((cur_attr.attr_page == attr->attr_page) && | ||
117 | (cur_attr.attr_id == attr->attr_id)) { | ||
118 | attr->len = cur_attr.len; | ||
119 | attr->val_ptr = cur_attr.val_ptr; | ||
120 | return 0; | ||
121 | } | ||
122 | } while (iter); | ||
123 | |||
124 | return -EIO; | ||
125 | } | ||
diff --git a/fs/exofs/pnfs.h b/fs/exofs/pnfs.h new file mode 100644 index 000000000000..423033addd1f --- /dev/null +++ b/fs/exofs/pnfs.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008, 2009 | ||
3 | * Boaz Harrosh <bharrosh@panasas.com> | ||
4 | * | ||
5 | * This file is part of exofs. | ||
6 | * | ||
7 | * exofs is free software; you can redistribute it and/or modify it under the | ||
8 | * terms of the GNU General Public License version 2 as published by the Free | ||
9 | * Software Foundation. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | /* FIXME: Remove this file once pnfs hits mainline */ | ||
14 | |||
15 | #ifndef __EXOFS_PNFS_H__ | ||
16 | #define __EXOFS_PNFS_H__ | ||
17 | |||
18 | #if defined(CONFIG_PNFS) | ||
19 | |||
20 | |||
21 | /* FIXME: move this file to: linux/exportfs/pnfs_osd_xdr.h */ | ||
22 | #include "../nfs/objlayout/pnfs_osd_xdr.h" | ||
23 | |||
24 | #else /* defined(CONFIG_PNFS) */ | ||
25 | |||
26 | enum pnfs_iomode { | ||
27 | IOMODE_READ = 1, | ||
28 | IOMODE_RW = 2, | ||
29 | IOMODE_ANY = 3, | ||
30 | }; | ||
31 | |||
32 | /* Layout Structure */ | ||
33 | enum pnfs_osd_raid_algorithm4 { | ||
34 | PNFS_OSD_RAID_0 = 1, | ||
35 | PNFS_OSD_RAID_4 = 2, | ||
36 | PNFS_OSD_RAID_5 = 3, | ||
37 | PNFS_OSD_RAID_PQ = 4 /* Reed-Solomon P+Q */ | ||
38 | }; | ||
39 | |||
40 | struct pnfs_osd_data_map { | ||
41 | u32 odm_num_comps; | ||
42 | u64 odm_stripe_unit; | ||
43 | u32 odm_group_width; | ||
44 | u32 odm_group_depth; | ||
45 | u32 odm_mirror_cnt; | ||
46 | u32 odm_raid_algorithm; | ||
47 | }; | ||
48 | |||
49 | #endif /* else defined(CONFIG_PNFS) */ | ||
50 | |||
51 | #endif /* __EXOFS_PNFS_H__ */ | ||
diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 9f500dec3b59..a1d1e77b12eb 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c | |||
@@ -203,49 +203,45 @@ int exofs_sync_fs(struct super_block *sb, int wait) | |||
203 | { | 203 | { |
204 | struct exofs_sb_info *sbi; | 204 | struct exofs_sb_info *sbi; |
205 | struct exofs_fscb *fscb; | 205 | struct exofs_fscb *fscb; |
206 | struct osd_request *or; | 206 | struct exofs_io_state *ios; |
207 | struct osd_obj_id obj; | ||
208 | int ret = -ENOMEM; | 207 | int ret = -ENOMEM; |
209 | 208 | ||
210 | fscb = kzalloc(sizeof(struct exofs_fscb), GFP_KERNEL); | ||
211 | if (!fscb) { | ||
212 | EXOFS_ERR("exofs_write_super: memory allocation failed.\n"); | ||
213 | return -ENOMEM; | ||
214 | } | ||
215 | |||
216 | lock_super(sb); | 209 | lock_super(sb); |
217 | sbi = sb->s_fs_info; | 210 | sbi = sb->s_fs_info; |
211 | fscb = &sbi->s_fscb; | ||
212 | |||
213 | ret = exofs_get_io_state(sbi, &ios); | ||
214 | if (ret) | ||
215 | goto out; | ||
216 | |||
217 | /* Note: We only write the changing part of the fscb. .i.e upto the | ||
218 | * the fscb->s_dev_table_oid member. There is no read-modify-write | ||
219 | * here. | ||
220 | */ | ||
221 | ios->length = offsetof(struct exofs_fscb, s_dev_table_oid); | ||
222 | memset(fscb, 0, ios->length); | ||
218 | fscb->s_nextid = cpu_to_le64(sbi->s_nextid); | 223 | fscb->s_nextid = cpu_to_le64(sbi->s_nextid); |
219 | fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles); | 224 | fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles); |
220 | fscb->s_magic = cpu_to_le16(sb->s_magic); | 225 | fscb->s_magic = cpu_to_le16(sb->s_magic); |
221 | fscb->s_newfs = 0; | 226 | fscb->s_newfs = 0; |
227 | fscb->s_version = EXOFS_FSCB_VER; | ||
222 | 228 | ||
223 | or = osd_start_request(sbi->s_dev, GFP_KERNEL); | 229 | ios->obj.id = EXOFS_SUPER_ID; |
224 | if (unlikely(!or)) { | 230 | ios->offset = 0; |
225 | EXOFS_ERR("exofs_write_super: osd_start_request failed.\n"); | 231 | ios->kern_buff = fscb; |
226 | goto out; | 232 | ios->cred = sbi->s_cred; |
227 | } | ||
228 | 233 | ||
229 | obj.partition = sbi->s_pid; | 234 | ret = exofs_sbi_write(ios); |
230 | obj.id = EXOFS_SUPER_ID; | ||
231 | ret = osd_req_write_kern(or, &obj, 0, fscb, sizeof(*fscb)); | ||
232 | if (unlikely(ret)) { | 235 | if (unlikely(ret)) { |
233 | EXOFS_ERR("exofs_write_super: osd_req_write_kern failed.\n"); | 236 | EXOFS_ERR("%s: exofs_sbi_write failed.\n", __func__); |
234 | goto out; | ||
235 | } | ||
236 | |||
237 | ret = exofs_sync_op(or, sbi->s_timeout, sbi->s_cred); | ||
238 | if (unlikely(ret)) { | ||
239 | EXOFS_ERR("exofs_write_super: exofs_sync_op failed.\n"); | ||
240 | goto out; | 237 | goto out; |
241 | } | 238 | } |
242 | sb->s_dirt = 0; | 239 | sb->s_dirt = 0; |
243 | 240 | ||
244 | out: | 241 | out: |
245 | if (or) | 242 | EXOFS_DBGMSG("s_nextid=0x%llx ret=%d\n", _LLU(sbi->s_nextid), ret); |
246 | osd_end_request(or); | 243 | exofs_put_io_state(ios); |
247 | unlock_super(sb); | 244 | unlock_super(sb); |
248 | kfree(fscb); | ||
249 | return ret; | 245 | return ret; |
250 | } | 246 | } |
251 | 247 | ||
@@ -257,6 +253,29 @@ static void exofs_write_super(struct super_block *sb) | |||
257 | sb->s_dirt = 0; | 253 | sb->s_dirt = 0; |
258 | } | 254 | } |
259 | 255 | ||
256 | static void _exofs_print_device(const char *msg, const char *dev_path, | ||
257 | struct osd_dev *od, u64 pid) | ||
258 | { | ||
259 | const struct osd_dev_info *odi = osduld_device_info(od); | ||
260 | |||
261 | printk(KERN_NOTICE "exofs: %s %s osd_name-%s pid-0x%llx\n", | ||
262 | msg, dev_path ?: "", odi->osdname, _LLU(pid)); | ||
263 | } | ||
264 | |||
265 | void exofs_free_sbi(struct exofs_sb_info *sbi) | ||
266 | { | ||
267 | while (sbi->s_numdevs) { | ||
268 | int i = --sbi->s_numdevs; | ||
269 | struct osd_dev *od = sbi->s_ods[i]; | ||
270 | |||
271 | if (od) { | ||
272 | sbi->s_ods[i] = NULL; | ||
273 | osduld_put_device(od); | ||
274 | } | ||
275 | } | ||
276 | kfree(sbi); | ||
277 | } | ||
278 | |||
260 | /* | 279 | /* |
261 | * This function is called when the vfs is freeing the superblock. We just | 280 | * This function is called when the vfs is freeing the superblock. We just |
262 | * need to free our own part. | 281 | * need to free our own part. |
@@ -279,11 +298,182 @@ static void exofs_put_super(struct super_block *sb) | |||
279 | msecs_to_jiffies(100)); | 298 | msecs_to_jiffies(100)); |
280 | } | 299 | } |
281 | 300 | ||
282 | osduld_put_device(sbi->s_dev); | 301 | _exofs_print_device("Unmounting", NULL, sbi->s_ods[0], sbi->s_pid); |
283 | kfree(sb->s_fs_info); | 302 | |
303 | exofs_free_sbi(sbi); | ||
284 | sb->s_fs_info = NULL; | 304 | sb->s_fs_info = NULL; |
285 | } | 305 | } |
286 | 306 | ||
307 | static int _read_and_match_data_map(struct exofs_sb_info *sbi, unsigned numdevs, | ||
308 | struct exofs_device_table *dt) | ||
309 | { | ||
310 | sbi->data_map.odm_num_comps = | ||
311 | le32_to_cpu(dt->dt_data_map.cb_num_comps); | ||
312 | sbi->data_map.odm_stripe_unit = | ||
313 | le64_to_cpu(dt->dt_data_map.cb_stripe_unit); | ||
314 | sbi->data_map.odm_group_width = | ||
315 | le32_to_cpu(dt->dt_data_map.cb_group_width); | ||
316 | sbi->data_map.odm_group_depth = | ||
317 | le32_to_cpu(dt->dt_data_map.cb_group_depth); | ||
318 | sbi->data_map.odm_mirror_cnt = | ||
319 | le32_to_cpu(dt->dt_data_map.cb_mirror_cnt); | ||
320 | sbi->data_map.odm_raid_algorithm = | ||
321 | le32_to_cpu(dt->dt_data_map.cb_raid_algorithm); | ||
322 | |||
323 | /* FIXME: Hard coded mirror only for now. if not so do not mount */ | ||
324 | if ((sbi->data_map.odm_num_comps != numdevs) || | ||
325 | (sbi->data_map.odm_stripe_unit != EXOFS_BLKSIZE) || | ||
326 | (sbi->data_map.odm_raid_algorithm != PNFS_OSD_RAID_0) || | ||
327 | (sbi->data_map.odm_mirror_cnt != (numdevs - 1))) | ||
328 | return -EINVAL; | ||
329 | else | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | /* @odi is valid only as long as @fscb_dev is valid */ | ||
334 | static int exofs_devs_2_odi(struct exofs_dt_device_info *dt_dev, | ||
335 | struct osd_dev_info *odi) | ||
336 | { | ||
337 | odi->systemid_len = le32_to_cpu(dt_dev->systemid_len); | ||
338 | memcpy(odi->systemid, dt_dev->systemid, odi->systemid_len); | ||
339 | |||
340 | odi->osdname_len = le32_to_cpu(dt_dev->osdname_len); | ||
341 | odi->osdname = dt_dev->osdname; | ||
342 | |||
343 | /* FIXME support long names. Will need a _put function */ | ||
344 | if (dt_dev->long_name_offset) | ||
345 | return -EINVAL; | ||
346 | |||
347 | /* Make sure osdname is printable! | ||
348 | * mkexofs should give us space for a null-terminator else the | ||
349 | * device-table is invalid. | ||
350 | */ | ||
351 | if (unlikely(odi->osdname_len >= sizeof(dt_dev->osdname))) | ||
352 | odi->osdname_len = sizeof(dt_dev->osdname) - 1; | ||
353 | dt_dev->osdname[odi->osdname_len] = 0; | ||
354 | |||
355 | /* If it's all zeros something is bad we read past end-of-obj */ | ||
356 | return !(odi->systemid_len || odi->osdname_len); | ||
357 | } | ||
358 | |||
359 | static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi, | ||
360 | unsigned table_count) | ||
361 | { | ||
362 | struct exofs_sb_info *sbi = *psbi; | ||
363 | struct osd_dev *fscb_od; | ||
364 | struct osd_obj_id obj = {.partition = sbi->s_pid, | ||
365 | .id = EXOFS_DEVTABLE_ID}; | ||
366 | struct exofs_device_table *dt; | ||
367 | unsigned table_bytes = table_count * sizeof(dt->dt_dev_table[0]) + | ||
368 | sizeof(*dt); | ||
369 | unsigned numdevs, i; | ||
370 | int ret; | ||
371 | |||
372 | dt = kmalloc(table_bytes, GFP_KERNEL); | ||
373 | if (unlikely(!dt)) { | ||
374 | EXOFS_ERR("ERROR: allocating %x bytes for device table\n", | ||
375 | table_bytes); | ||
376 | return -ENOMEM; | ||
377 | } | ||
378 | |||
379 | fscb_od = sbi->s_ods[0]; | ||
380 | sbi->s_ods[0] = NULL; | ||
381 | sbi->s_numdevs = 0; | ||
382 | ret = exofs_read_kern(fscb_od, sbi->s_cred, &obj, 0, dt, table_bytes); | ||
383 | if (unlikely(ret)) { | ||
384 | EXOFS_ERR("ERROR: reading device table\n"); | ||
385 | goto out; | ||
386 | } | ||
387 | |||
388 | numdevs = le64_to_cpu(dt->dt_num_devices); | ||
389 | if (unlikely(!numdevs)) { | ||
390 | ret = -EINVAL; | ||
391 | goto out; | ||
392 | } | ||
393 | WARN_ON(table_count != numdevs); | ||
394 | |||
395 | ret = _read_and_match_data_map(sbi, numdevs, dt); | ||
396 | if (unlikely(ret)) | ||
397 | goto out; | ||
398 | |||
399 | if (likely(numdevs > 1)) { | ||
400 | unsigned size = numdevs * sizeof(sbi->s_ods[0]); | ||
401 | |||
402 | sbi = krealloc(sbi, sizeof(*sbi) + size, GFP_KERNEL); | ||
403 | if (unlikely(!sbi)) { | ||
404 | ret = -ENOMEM; | ||
405 | goto out; | ||
406 | } | ||
407 | memset(&sbi->s_ods[1], 0, size - sizeof(sbi->s_ods[0])); | ||
408 | *psbi = sbi; | ||
409 | } | ||
410 | |||
411 | for (i = 0; i < numdevs; i++) { | ||
412 | struct exofs_fscb fscb; | ||
413 | struct osd_dev_info odi; | ||
414 | struct osd_dev *od; | ||
415 | |||
416 | if (exofs_devs_2_odi(&dt->dt_dev_table[i], &odi)) { | ||
417 | EXOFS_ERR("ERROR: Read all-zeros device entry\n"); | ||
418 | ret = -EINVAL; | ||
419 | goto out; | ||
420 | } | ||
421 | |||
422 | printk(KERN_NOTICE "Add device[%d]: osd_name-%s\n", | ||
423 | i, odi.osdname); | ||
424 | |||
425 | /* On all devices the device table is identical. The user can | ||
426 | * specify any one of the participating devices on the command | ||
427 | * line. We always keep them in device-table order. | ||
428 | */ | ||
429 | if (fscb_od && osduld_device_same(fscb_od, &odi)) { | ||
430 | sbi->s_ods[i] = fscb_od; | ||
431 | ++sbi->s_numdevs; | ||
432 | fscb_od = NULL; | ||
433 | continue; | ||
434 | } | ||
435 | |||
436 | od = osduld_info_lookup(&odi); | ||
437 | if (unlikely(IS_ERR(od))) { | ||
438 | ret = PTR_ERR(od); | ||
439 | EXOFS_ERR("ERROR: device requested is not found " | ||
440 | "osd_name-%s =>%d\n", odi.osdname, ret); | ||
441 | goto out; | ||
442 | } | ||
443 | |||
444 | sbi->s_ods[i] = od; | ||
445 | ++sbi->s_numdevs; | ||
446 | |||
447 | /* Read the fscb of the other devices to make sure the FS | ||
448 | * partition is there. | ||
449 | */ | ||
450 | ret = exofs_read_kern(od, sbi->s_cred, &obj, 0, &fscb, | ||
451 | sizeof(fscb)); | ||
452 | if (unlikely(ret)) { | ||
453 | EXOFS_ERR("ERROR: Malformed participating device " | ||
454 | "error reading fscb osd_name-%s\n", | ||
455 | odi.osdname); | ||
456 | goto out; | ||
457 | } | ||
458 | |||
459 | /* TODO: verify other information is correct and FS-uuid | ||
460 | * matches. Benny what did you say about device table | ||
461 | * generation and old devices? | ||
462 | */ | ||
463 | } | ||
464 | |||
465 | out: | ||
466 | kfree(dt); | ||
467 | if (unlikely(!ret && fscb_od)) { | ||
468 | EXOFS_ERR( | ||
469 | "ERROR: Bad device-table container device not present\n"); | ||
470 | osduld_put_device(fscb_od); | ||
471 | ret = -EINVAL; | ||
472 | } | ||
473 | |||
474 | return ret; | ||
475 | } | ||
476 | |||
287 | /* | 477 | /* |
288 | * Read the superblock from the OSD and fill in the fields | 478 | * Read the superblock from the OSD and fill in the fields |
289 | */ | 479 | */ |
@@ -292,24 +482,25 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) | |||
292 | struct inode *root; | 482 | struct inode *root; |
293 | struct exofs_mountopt *opts = data; | 483 | struct exofs_mountopt *opts = data; |
294 | struct exofs_sb_info *sbi; /*extended info */ | 484 | struct exofs_sb_info *sbi; /*extended info */ |
485 | struct osd_dev *od; /* Master device */ | ||
295 | struct exofs_fscb fscb; /*on-disk superblock info */ | 486 | struct exofs_fscb fscb; /*on-disk superblock info */ |
296 | struct osd_request *or = NULL; | ||
297 | struct osd_obj_id obj; | 487 | struct osd_obj_id obj; |
488 | unsigned table_count; | ||
298 | int ret; | 489 | int ret; |
299 | 490 | ||
300 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); | 491 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); |
301 | if (!sbi) | 492 | if (!sbi) |
302 | return -ENOMEM; | 493 | return -ENOMEM; |
303 | sb->s_fs_info = sbi; | ||
304 | 494 | ||
305 | /* use mount options to fill superblock */ | 495 | /* use mount options to fill superblock */ |
306 | sbi->s_dev = osduld_path_lookup(opts->dev_name); | 496 | od = osduld_path_lookup(opts->dev_name); |
307 | if (IS_ERR(sbi->s_dev)) { | 497 | if (IS_ERR(od)) { |
308 | ret = PTR_ERR(sbi->s_dev); | 498 | ret = PTR_ERR(od); |
309 | sbi->s_dev = NULL; | ||
310 | goto free_sbi; | 499 | goto free_sbi; |
311 | } | 500 | } |
312 | 501 | ||
502 | sbi->s_ods[0] = od; | ||
503 | sbi->s_numdevs = 1; | ||
313 | sbi->s_pid = opts->pid; | 504 | sbi->s_pid = opts->pid; |
314 | sbi->s_timeout = opts->timeout; | 505 | sbi->s_timeout = opts->timeout; |
315 | 506 | ||
@@ -323,35 +514,13 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) | |||
323 | sb->s_bdev = NULL; | 514 | sb->s_bdev = NULL; |
324 | sb->s_dev = 0; | 515 | sb->s_dev = 0; |
325 | 516 | ||
326 | /* read data from on-disk superblock object */ | ||
327 | obj.partition = sbi->s_pid; | 517 | obj.partition = sbi->s_pid; |
328 | obj.id = EXOFS_SUPER_ID; | 518 | obj.id = EXOFS_SUPER_ID; |
329 | exofs_make_credential(sbi->s_cred, &obj); | 519 | exofs_make_credential(sbi->s_cred, &obj); |
330 | 520 | ||
331 | or = osd_start_request(sbi->s_dev, GFP_KERNEL); | 521 | ret = exofs_read_kern(od, sbi->s_cred, &obj, 0, &fscb, sizeof(fscb)); |
332 | if (unlikely(!or)) { | 522 | if (unlikely(ret)) |
333 | if (!silent) | ||
334 | EXOFS_ERR( | ||
335 | "exofs_fill_super: osd_start_request failed.\n"); | ||
336 | ret = -ENOMEM; | ||
337 | goto free_sbi; | ||
338 | } | ||
339 | ret = osd_req_read_kern(or, &obj, 0, &fscb, sizeof(fscb)); | ||
340 | if (unlikely(ret)) { | ||
341 | if (!silent) | ||
342 | EXOFS_ERR( | ||
343 | "exofs_fill_super: osd_req_read_kern failed.\n"); | ||
344 | ret = -ENOMEM; | ||
345 | goto free_sbi; | ||
346 | } | ||
347 | |||
348 | ret = exofs_sync_op(or, sbi->s_timeout, sbi->s_cred); | ||
349 | if (unlikely(ret)) { | ||
350 | if (!silent) | ||
351 | EXOFS_ERR("exofs_fill_super: exofs_sync_op failed.\n"); | ||
352 | ret = -EIO; | ||
353 | goto free_sbi; | 523 | goto free_sbi; |
354 | } | ||
355 | 524 | ||
356 | sb->s_magic = le16_to_cpu(fscb.s_magic); | 525 | sb->s_magic = le16_to_cpu(fscb.s_magic); |
357 | sbi->s_nextid = le64_to_cpu(fscb.s_nextid); | 526 | sbi->s_nextid = le64_to_cpu(fscb.s_nextid); |
@@ -364,12 +533,26 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) | |||
364 | ret = -EINVAL; | 533 | ret = -EINVAL; |
365 | goto free_sbi; | 534 | goto free_sbi; |
366 | } | 535 | } |
536 | if (le32_to_cpu(fscb.s_version) != EXOFS_FSCB_VER) { | ||
537 | EXOFS_ERR("ERROR: Bad FSCB version expected-%d got-%d\n", | ||
538 | EXOFS_FSCB_VER, le32_to_cpu(fscb.s_version)); | ||
539 | ret = -EINVAL; | ||
540 | goto free_sbi; | ||
541 | } | ||
367 | 542 | ||
368 | /* start generation numbers from a random point */ | 543 | /* start generation numbers from a random point */ |
369 | get_random_bytes(&sbi->s_next_generation, sizeof(u32)); | 544 | get_random_bytes(&sbi->s_next_generation, sizeof(u32)); |
370 | spin_lock_init(&sbi->s_next_gen_lock); | 545 | spin_lock_init(&sbi->s_next_gen_lock); |
371 | 546 | ||
547 | table_count = le64_to_cpu(fscb.s_dev_table_count); | ||
548 | if (table_count) { | ||
549 | ret = exofs_read_lookup_dev_table(&sbi, table_count); | ||
550 | if (unlikely(ret)) | ||
551 | goto free_sbi; | ||
552 | } | ||
553 | |||
372 | /* set up operation vectors */ | 554 | /* set up operation vectors */ |
555 | sb->s_fs_info = sbi; | ||
373 | sb->s_op = &exofs_sops; | 556 | sb->s_op = &exofs_sops; |
374 | sb->s_export_op = &exofs_export_ops; | 557 | sb->s_export_op = &exofs_export_ops; |
375 | root = exofs_iget(sb, EXOFS_ROOT_ID - EXOFS_OBJ_OFF); | 558 | root = exofs_iget(sb, EXOFS_ROOT_ID - EXOFS_OBJ_OFF); |
@@ -395,16 +578,15 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) | |||
395 | goto free_sbi; | 578 | goto free_sbi; |
396 | } | 579 | } |
397 | 580 | ||
398 | ret = 0; | 581 | _exofs_print_device("Mounting", opts->dev_name, sbi->s_ods[0], |
399 | out: | 582 | sbi->s_pid); |
400 | if (or) | 583 | return 0; |
401 | osd_end_request(or); | ||
402 | return ret; | ||
403 | 584 | ||
404 | free_sbi: | 585 | free_sbi: |
405 | osduld_put_device(sbi->s_dev); /* NULL safe */ | 586 | EXOFS_ERR("Unable to mount exofs on %s pid=0x%llx err=%d\n", |
406 | kfree(sbi); | 587 | opts->dev_name, sbi->s_pid, ret); |
407 | goto out; | 588 | exofs_free_sbi(sbi); |
589 | return ret; | ||
408 | } | 590 | } |
409 | 591 | ||
410 | /* | 592 | /* |
@@ -433,7 +615,7 @@ static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
433 | { | 615 | { |
434 | struct super_block *sb = dentry->d_sb; | 616 | struct super_block *sb = dentry->d_sb; |
435 | struct exofs_sb_info *sbi = sb->s_fs_info; | 617 | struct exofs_sb_info *sbi = sb->s_fs_info; |
436 | struct osd_obj_id obj = {sbi->s_pid, 0}; | 618 | struct exofs_io_state *ios; |
437 | struct osd_attr attrs[] = { | 619 | struct osd_attr attrs[] = { |
438 | ATTR_DEF(OSD_APAGE_PARTITION_QUOTAS, | 620 | ATTR_DEF(OSD_APAGE_PARTITION_QUOTAS, |
439 | OSD_ATTR_PQ_CAPACITY_QUOTA, sizeof(__be64)), | 621 | OSD_ATTR_PQ_CAPACITY_QUOTA, sizeof(__be64)), |
@@ -442,32 +624,33 @@ static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
442 | }; | 624 | }; |
443 | uint64_t capacity = ULLONG_MAX; | 625 | uint64_t capacity = ULLONG_MAX; |
444 | uint64_t used = ULLONG_MAX; | 626 | uint64_t used = ULLONG_MAX; |
445 | struct osd_request *or; | ||
446 | uint8_t cred_a[OSD_CAP_LEN]; | 627 | uint8_t cred_a[OSD_CAP_LEN]; |
447 | int ret; | 628 | int ret; |
448 | 629 | ||
449 | /* get used/capacity attributes */ | 630 | ret = exofs_get_io_state(sbi, &ios); |
450 | exofs_make_credential(cred_a, &obj); | 631 | if (ret) { |
451 | 632 | EXOFS_DBGMSG("exofs_get_io_state failed.\n"); | |
452 | or = osd_start_request(sbi->s_dev, GFP_KERNEL); | 633 | return ret; |
453 | if (unlikely(!or)) { | ||
454 | EXOFS_DBGMSG("exofs_statfs: osd_start_request failed.\n"); | ||
455 | return -ENOMEM; | ||
456 | } | 634 | } |
457 | 635 | ||
458 | osd_req_get_attributes(or, &obj); | 636 | exofs_make_credential(cred_a, &ios->obj); |
459 | osd_req_add_get_attr_list(or, attrs, ARRAY_SIZE(attrs)); | 637 | ios->cred = sbi->s_cred; |
460 | ret = exofs_sync_op(or, sbi->s_timeout, cred_a); | 638 | ios->in_attr = attrs; |
639 | ios->in_attr_len = ARRAY_SIZE(attrs); | ||
640 | |||
641 | ret = exofs_sbi_read(ios); | ||
461 | if (unlikely(ret)) | 642 | if (unlikely(ret)) |
462 | goto out; | 643 | goto out; |
463 | 644 | ||
464 | ret = extract_attr_from_req(or, &attrs[0]); | 645 | ret = extract_attr_from_ios(ios, &attrs[0]); |
465 | if (likely(!ret)) | 646 | if (likely(!ret)) { |
466 | capacity = get_unaligned_be64(attrs[0].val_ptr); | 647 | capacity = get_unaligned_be64(attrs[0].val_ptr); |
467 | else | 648 | if (unlikely(!capacity)) |
649 | capacity = ULLONG_MAX; | ||
650 | } else | ||
468 | EXOFS_DBGMSG("exofs_statfs: get capacity failed.\n"); | 651 | EXOFS_DBGMSG("exofs_statfs: get capacity failed.\n"); |
469 | 652 | ||
470 | ret = extract_attr_from_req(or, &attrs[1]); | 653 | ret = extract_attr_from_ios(ios, &attrs[1]); |
471 | if (likely(!ret)) | 654 | if (likely(!ret)) |
472 | used = get_unaligned_be64(attrs[1].val_ptr); | 655 | used = get_unaligned_be64(attrs[1].val_ptr); |
473 | else | 656 | else |
@@ -476,15 +659,15 @@ static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
476 | /* fill in the stats buffer */ | 659 | /* fill in the stats buffer */ |
477 | buf->f_type = EXOFS_SUPER_MAGIC; | 660 | buf->f_type = EXOFS_SUPER_MAGIC; |
478 | buf->f_bsize = EXOFS_BLKSIZE; | 661 | buf->f_bsize = EXOFS_BLKSIZE; |
479 | buf->f_blocks = (capacity >> EXOFS_BLKSHIFT); | 662 | buf->f_blocks = capacity >> 9; |
480 | buf->f_bfree = ((capacity - used) >> EXOFS_BLKSHIFT); | 663 | buf->f_bfree = (capacity - used) >> 9; |
481 | buf->f_bavail = buf->f_bfree; | 664 | buf->f_bavail = buf->f_bfree; |
482 | buf->f_files = sbi->s_numfiles; | 665 | buf->f_files = sbi->s_numfiles; |
483 | buf->f_ffree = EXOFS_MAX_ID - sbi->s_numfiles; | 666 | buf->f_ffree = EXOFS_MAX_ID - sbi->s_numfiles; |
484 | buf->f_namelen = EXOFS_NAME_LEN; | 667 | buf->f_namelen = EXOFS_NAME_LEN; |
485 | 668 | ||
486 | out: | 669 | out: |
487 | osd_end_request(or); | 670 | exofs_put_io_state(ios); |
488 | return ret; | 671 | return ret; |
489 | } | 672 | } |
490 | 673 | ||
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 354ed3b47b30..2db957778903 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -2033,7 +2033,7 @@ static Indirect *ext3_find_shared(struct inode *inode, int depth, | |||
2033 | int k, err; | 2033 | int k, err; |
2034 | 2034 | ||
2035 | *top = 0; | 2035 | *top = 0; |
2036 | /* Make k index the deepest non-null offest + 1 */ | 2036 | /* Make k index the deepest non-null offset + 1 */ |
2037 | for (k = depth; k > 1 && !offsets[k-1]; k--) | 2037 | for (k = depth; k > 1 && !offsets[k-1]; k--) |
2038 | ; | 2038 | ; |
2039 | partial = ext3_get_branch(inode, k, offsets, chain, &err); | 2039 | partial = ext3_get_branch(inode, k, offsets, chain, &err); |
diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig index 9f2d45d75b1a..9acf7e808139 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig | |||
@@ -26,6 +26,16 @@ config EXT4_FS | |||
26 | 26 | ||
27 | If unsure, say N. | 27 | If unsure, say N. |
28 | 28 | ||
29 | config EXT4_USE_FOR_EXT23 | ||
30 | bool "Use ext4 for ext2/ext3 file systems" | ||
31 | depends on EXT3_FS=n || EXT2_FS=n | ||
32 | default y | ||
33 | help | ||
34 | Allow the ext4 file system driver code to be used for ext2 or | ||
35 | ext3 file system mounts. This allows users to reduce their | ||
36 | compiled kernel size by using one file system driver for | ||
37 | ext2, ext3, and ext4 file systems. | ||
38 | |||
29 | config EXT4_FS_XATTR | 39 | config EXT4_FS_XATTR |
30 | bool "Ext4 extended attributes" | 40 | bool "Ext4 extended attributes" |
31 | depends on EXT4_FS | 41 | depends on EXT4_FS |
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 1d0418980f8d..22bc7435d913 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -499,44 +499,6 @@ error_return: | |||
499 | } | 499 | } |
500 | 500 | ||
501 | /** | 501 | /** |
502 | * ext4_free_blocks() -- Free given blocks and update quota | ||
503 | * @handle: handle for this transaction | ||
504 | * @inode: inode | ||
505 | * @block: start physical block to free | ||
506 | * @count: number of blocks to count | ||
507 | * @metadata: Are these metadata blocks | ||
508 | */ | ||
509 | void ext4_free_blocks(handle_t *handle, struct inode *inode, | ||
510 | ext4_fsblk_t block, unsigned long count, | ||
511 | int metadata) | ||
512 | { | ||
513 | struct super_block *sb; | ||
514 | unsigned long dquot_freed_blocks; | ||
515 | |||
516 | /* this isn't the right place to decide whether block is metadata | ||
517 | * inode.c/extents.c knows better, but for safety ... */ | ||
518 | if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) | ||
519 | metadata = 1; | ||
520 | |||
521 | /* We need to make sure we don't reuse | ||
522 | * block released untill the transaction commit. | ||
523 | * writeback mode have weak data consistency so | ||
524 | * don't force data as metadata when freeing block | ||
525 | * for writeback mode. | ||
526 | */ | ||
527 | if (metadata == 0 && !ext4_should_writeback_data(inode)) | ||
528 | metadata = 1; | ||
529 | |||
530 | sb = inode->i_sb; | ||
531 | |||
532 | ext4_mb_free_blocks(handle, inode, block, count, | ||
533 | metadata, &dquot_freed_blocks); | ||
534 | if (dquot_freed_blocks) | ||
535 | vfs_dq_free_block(inode, dquot_freed_blocks); | ||
536 | return; | ||
537 | } | ||
538 | |||
539 | /** | ||
540 | * ext4_has_free_blocks() | 502 | * ext4_has_free_blocks() |
541 | * @sbi: in-core super block structure. | 503 | * @sbi: in-core super block structure. |
542 | * @nblocks: number of needed blocks | 504 | * @nblocks: number of needed blocks |
@@ -761,7 +723,13 @@ static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb, | |||
761 | static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb, | 723 | static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb, |
762 | ext4_group_t group) | 724 | ext4_group_t group) |
763 | { | 725 | { |
764 | return ext4_bg_has_super(sb, group) ? EXT4_SB(sb)->s_gdb_count : 0; | 726 | if (!ext4_bg_has_super(sb, group)) |
727 | return 0; | ||
728 | |||
729 | if (EXT4_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG)) | ||
730 | return le32_to_cpu(EXT4_SB(sb)->s_es->s_first_meta_bg); | ||
731 | else | ||
732 | return EXT4_SB(sb)->s_gdb_count; | ||
765 | } | 733 | } |
766 | 734 | ||
767 | /** | 735 | /** |
diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c index 50784ef07563..4df8621ec31c 100644 --- a/fs/ext4/block_validity.c +++ b/fs/ext4/block_validity.c | |||
@@ -160,7 +160,7 @@ int ext4_setup_system_zone(struct super_block *sb) | |||
160 | if (ext4_bg_has_super(sb, i) && | 160 | if (ext4_bg_has_super(sb, i) && |
161 | ((i < 5) || ((i % flex_size) == 0))) | 161 | ((i < 5) || ((i % flex_size) == 0))) |
162 | add_system_zone(sbi, ext4_group_first_block_no(sb, i), | 162 | add_system_zone(sbi, ext4_group_first_block_no(sb, i), |
163 | sbi->s_gdb_count + 1); | 163 | ext4_bg_num_gdb(sb, i) + 1); |
164 | gdp = ext4_get_group_desc(sb, i, NULL); | 164 | gdp = ext4_get_group_desc(sb, i, NULL); |
165 | ret = add_system_zone(sbi, ext4_block_bitmap(sb, gdp), 1); | 165 | ret = add_system_zone(sbi, ext4_block_bitmap(sb, gdp), 1); |
166 | if (ret) | 166 | if (ret) |
@@ -228,6 +228,7 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk, | |||
228 | struct rb_node *n = sbi->system_blks.rb_node; | 228 | struct rb_node *n = sbi->system_blks.rb_node; |
229 | 229 | ||
230 | if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || | 230 | if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || |
231 | (start_blk + count < start_blk) || | ||
231 | (start_blk + count > ext4_blocks_count(sbi->s_es))) | 232 | (start_blk + count > ext4_blocks_count(sbi->s_es))) |
232 | return 0; | 233 | return 0; |
233 | while (n) { | 234 | while (n) { |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 8825515eeddd..ab31e65d46d0 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -376,6 +376,12 @@ struct ext4_new_group_data { | |||
376 | EXT4_GET_BLOCKS_DIO_CREATE_EXT) | 376 | EXT4_GET_BLOCKS_DIO_CREATE_EXT) |
377 | 377 | ||
378 | /* | 378 | /* |
379 | * Flags used by ext4_free_blocks | ||
380 | */ | ||
381 | #define EXT4_FREE_BLOCKS_METADATA 0x0001 | ||
382 | #define EXT4_FREE_BLOCKS_FORGET 0x0002 | ||
383 | |||
384 | /* | ||
379 | * ioctl commands | 385 | * ioctl commands |
380 | */ | 386 | */ |
381 | #define EXT4_IOC_GETFLAGS FS_IOC_GETFLAGS | 387 | #define EXT4_IOC_GETFLAGS FS_IOC_GETFLAGS |
@@ -703,6 +709,13 @@ struct ext4_inode_info { | |||
703 | struct list_head i_aio_dio_complete_list; | 709 | struct list_head i_aio_dio_complete_list; |
704 | /* current io_end structure for async DIO write*/ | 710 | /* current io_end structure for async DIO write*/ |
705 | ext4_io_end_t *cur_aio_dio; | 711 | ext4_io_end_t *cur_aio_dio; |
712 | |||
713 | /* | ||
714 | * Transactions that contain inode's metadata needed to complete | ||
715 | * fsync and fdatasync, respectively. | ||
716 | */ | ||
717 | tid_t i_sync_tid; | ||
718 | tid_t i_datasync_tid; | ||
706 | }; | 719 | }; |
707 | 720 | ||
708 | /* | 721 | /* |
@@ -750,6 +763,7 @@ struct ext4_inode_info { | |||
750 | #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ | 763 | #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ |
751 | #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ | 764 | #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ |
752 | #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ | 765 | #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ |
766 | #define EXT4_MOUNT_DISCARD 0x40000000 /* Issue DISCARD requests */ | ||
753 | 767 | ||
754 | #define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt | 768 | #define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt |
755 | #define set_opt(o, opt) o |= EXT4_MOUNT_##opt | 769 | #define set_opt(o, opt) o |= EXT4_MOUNT_##opt |
@@ -1324,8 +1338,6 @@ extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, | |||
1324 | ext4_fsblk_t goal, unsigned long *count, int *errp); | 1338 | ext4_fsblk_t goal, unsigned long *count, int *errp); |
1325 | extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); | 1339 | extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); |
1326 | extern int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); | 1340 | extern int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); |
1327 | extern void ext4_free_blocks(handle_t *handle, struct inode *inode, | ||
1328 | ext4_fsblk_t block, unsigned long count, int metadata); | ||
1329 | extern void ext4_add_groupblocks(handle_t *handle, struct super_block *sb, | 1341 | extern void ext4_add_groupblocks(handle_t *handle, struct super_block *sb, |
1330 | ext4_fsblk_t block, unsigned long count); | 1342 | ext4_fsblk_t block, unsigned long count); |
1331 | extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *); | 1343 | extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *); |
@@ -1384,16 +1396,15 @@ extern int ext4_mb_reserve_blocks(struct super_block *, int); | |||
1384 | extern void ext4_discard_preallocations(struct inode *); | 1396 | extern void ext4_discard_preallocations(struct inode *); |
1385 | extern int __init init_ext4_mballoc(void); | 1397 | extern int __init init_ext4_mballoc(void); |
1386 | extern void exit_ext4_mballoc(void); | 1398 | extern void exit_ext4_mballoc(void); |
1387 | extern void ext4_mb_free_blocks(handle_t *, struct inode *, | 1399 | extern void ext4_free_blocks(handle_t *handle, struct inode *inode, |
1388 | ext4_fsblk_t, unsigned long, int, unsigned long *); | 1400 | struct buffer_head *bh, ext4_fsblk_t block, |
1401 | unsigned long count, int flags); | ||
1389 | extern int ext4_mb_add_groupinfo(struct super_block *sb, | 1402 | extern int ext4_mb_add_groupinfo(struct super_block *sb, |
1390 | ext4_group_t i, struct ext4_group_desc *desc); | 1403 | ext4_group_t i, struct ext4_group_desc *desc); |
1391 | extern int ext4_mb_get_buddy_cache_lock(struct super_block *, ext4_group_t); | 1404 | extern int ext4_mb_get_buddy_cache_lock(struct super_block *, ext4_group_t); |
1392 | extern void ext4_mb_put_buddy_cache_lock(struct super_block *, | 1405 | extern void ext4_mb_put_buddy_cache_lock(struct super_block *, |
1393 | ext4_group_t, int); | 1406 | ext4_group_t, int); |
1394 | /* inode.c */ | 1407 | /* inode.c */ |
1395 | int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, | ||
1396 | struct buffer_head *bh, ext4_fsblk_t blocknr); | ||
1397 | struct buffer_head *ext4_getblk(handle_t *, struct inode *, | 1408 | struct buffer_head *ext4_getblk(handle_t *, struct inode *, |
1398 | ext4_lblk_t, int, int *); | 1409 | ext4_lblk_t, int, int *); |
1399 | struct buffer_head *ext4_bread(handle_t *, struct inode *, | 1410 | struct buffer_head *ext4_bread(handle_t *, struct inode *, |
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index 6a9409920dee..b57e5c711b6d 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c | |||
@@ -4,6 +4,8 @@ | |||
4 | 4 | ||
5 | #include "ext4_jbd2.h" | 5 | #include "ext4_jbd2.h" |
6 | 6 | ||
7 | #include <trace/events/ext4.h> | ||
8 | |||
7 | int __ext4_journal_get_undo_access(const char *where, handle_t *handle, | 9 | int __ext4_journal_get_undo_access(const char *where, handle_t *handle, |
8 | struct buffer_head *bh) | 10 | struct buffer_head *bh) |
9 | { | 11 | { |
@@ -32,35 +34,69 @@ int __ext4_journal_get_write_access(const char *where, handle_t *handle, | |||
32 | return err; | 34 | return err; |
33 | } | 35 | } |
34 | 36 | ||
35 | int __ext4_journal_forget(const char *where, handle_t *handle, | 37 | /* |
36 | struct buffer_head *bh) | 38 | * The ext4 forget function must perform a revoke if we are freeing data |
39 | * which has been journaled. Metadata (eg. indirect blocks) must be | ||
40 | * revoked in all cases. | ||
41 | * | ||
42 | * "bh" may be NULL: a metadata block may have been freed from memory | ||
43 | * but there may still be a record of it in the journal, and that record | ||
44 | * still needs to be revoked. | ||
45 | * | ||
46 | * If the handle isn't valid we're not journaling, but we still need to | ||
47 | * call into ext4_journal_revoke() to put the buffer head. | ||
48 | */ | ||
49 | int __ext4_forget(const char *where, handle_t *handle, int is_metadata, | ||
50 | struct inode *inode, struct buffer_head *bh, | ||
51 | ext4_fsblk_t blocknr) | ||
37 | { | 52 | { |
38 | int err = 0; | 53 | int err; |
39 | 54 | ||
40 | if (ext4_handle_valid(handle)) { | 55 | might_sleep(); |
41 | err = jbd2_journal_forget(handle, bh); | 56 | |
42 | if (err) | 57 | trace_ext4_forget(inode, is_metadata, blocknr); |
43 | ext4_journal_abort_handle(where, __func__, bh, | 58 | BUFFER_TRACE(bh, "enter"); |
44 | handle, err); | 59 | |
45 | } | 60 | jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " |
46 | else | 61 | "data mode %x\n", |
62 | bh, is_metadata, inode->i_mode, | ||
63 | test_opt(inode->i_sb, DATA_FLAGS)); | ||
64 | |||
65 | /* In the no journal case, we can just do a bforget and return */ | ||
66 | if (!ext4_handle_valid(handle)) { | ||
47 | bforget(bh); | 67 | bforget(bh); |
48 | return err; | 68 | return 0; |
49 | } | 69 | } |
50 | 70 | ||
51 | int __ext4_journal_revoke(const char *where, handle_t *handle, | 71 | /* Never use the revoke function if we are doing full data |
52 | ext4_fsblk_t blocknr, struct buffer_head *bh) | 72 | * journaling: there is no need to, and a V1 superblock won't |
53 | { | 73 | * support it. Otherwise, only skip the revoke on un-journaled |
54 | int err = 0; | 74 | * data blocks. */ |
55 | 75 | ||
56 | if (ext4_handle_valid(handle)) { | 76 | if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA || |
57 | err = jbd2_journal_revoke(handle, blocknr, bh); | 77 | (!is_metadata && !ext4_should_journal_data(inode))) { |
58 | if (err) | 78 | if (bh) { |
59 | ext4_journal_abort_handle(where, __func__, bh, | 79 | BUFFER_TRACE(bh, "call jbd2_journal_forget"); |
60 | handle, err); | 80 | err = jbd2_journal_forget(handle, bh); |
81 | if (err) | ||
82 | ext4_journal_abort_handle(where, __func__, bh, | ||
83 | handle, err); | ||
84 | return err; | ||
85 | } | ||
86 | return 0; | ||
61 | } | 87 | } |
62 | else | 88 | |
63 | bforget(bh); | 89 | /* |
90 | * data!=journal && (is_metadata || should_journal_data(inode)) | ||
91 | */ | ||
92 | BUFFER_TRACE(bh, "call jbd2_journal_revoke"); | ||
93 | err = jbd2_journal_revoke(handle, blocknr, bh); | ||
94 | if (err) { | ||
95 | ext4_journal_abort_handle(where, __func__, bh, handle, err); | ||
96 | ext4_abort(inode->i_sb, __func__, | ||
97 | "error %d when attempting revoke", err); | ||
98 | } | ||
99 | BUFFER_TRACE(bh, "exit"); | ||
64 | return err; | 100 | return err; |
65 | } | 101 | } |
66 | 102 | ||
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index a2865980342f..05eca817d704 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h | |||
@@ -49,7 +49,7 @@ | |||
49 | 49 | ||
50 | #define EXT4_DATA_TRANS_BLOCKS(sb) (EXT4_SINGLEDATA_TRANS_BLOCKS(sb) + \ | 50 | #define EXT4_DATA_TRANS_BLOCKS(sb) (EXT4_SINGLEDATA_TRANS_BLOCKS(sb) + \ |
51 | EXT4_XATTR_TRANS_BLOCKS - 2 + \ | 51 | EXT4_XATTR_TRANS_BLOCKS - 2 + \ |
52 | 2*EXT4_QUOTA_TRANS_BLOCKS(sb)) | 52 | EXT4_MAXQUOTAS_TRANS_BLOCKS(sb)) |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * Define the number of metadata blocks we need to account to modify data. | 55 | * Define the number of metadata blocks we need to account to modify data. |
@@ -57,7 +57,7 @@ | |||
57 | * This include super block, inode block, quota blocks and xattr blocks | 57 | * This include super block, inode block, quota blocks and xattr blocks |
58 | */ | 58 | */ |
59 | #define EXT4_META_TRANS_BLOCKS(sb) (EXT4_XATTR_TRANS_BLOCKS + \ | 59 | #define EXT4_META_TRANS_BLOCKS(sb) (EXT4_XATTR_TRANS_BLOCKS + \ |
60 | 2*EXT4_QUOTA_TRANS_BLOCKS(sb)) | 60 | EXT4_MAXQUOTAS_TRANS_BLOCKS(sb)) |
61 | 61 | ||
62 | /* Delete operations potentially hit one directory's namespace plus an | 62 | /* Delete operations potentially hit one directory's namespace plus an |
63 | * entire inode, plus arbitrary amounts of bitmap/indirection data. Be | 63 | * entire inode, plus arbitrary amounts of bitmap/indirection data. Be |
@@ -92,6 +92,7 @@ | |||
92 | * but inode, sb and group updates are done only once */ | 92 | * but inode, sb and group updates are done only once */ |
93 | #define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ | 93 | #define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ |
94 | (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_INIT_REWRITE) : 0) | 94 | (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_INIT_REWRITE) : 0) |
95 | |||
95 | #define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\ | 96 | #define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\ |
96 | (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_DEL_REWRITE) : 0) | 97 | (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_DEL_REWRITE) : 0) |
97 | #else | 98 | #else |
@@ -99,6 +100,9 @@ | |||
99 | #define EXT4_QUOTA_INIT_BLOCKS(sb) 0 | 100 | #define EXT4_QUOTA_INIT_BLOCKS(sb) 0 |
100 | #define EXT4_QUOTA_DEL_BLOCKS(sb) 0 | 101 | #define EXT4_QUOTA_DEL_BLOCKS(sb) 0 |
101 | #endif | 102 | #endif |
103 | #define EXT4_MAXQUOTAS_TRANS_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_TRANS_BLOCKS(sb)) | ||
104 | #define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb)) | ||
105 | #define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb)) | ||
102 | 106 | ||
103 | int | 107 | int |
104 | ext4_mark_iloc_dirty(handle_t *handle, | 108 | ext4_mark_iloc_dirty(handle_t *handle, |
@@ -116,12 +120,8 @@ int ext4_reserve_inode_write(handle_t *handle, struct inode *inode, | |||
116 | int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode); | 120 | int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode); |
117 | 121 | ||
118 | /* | 122 | /* |
119 | * Wrapper functions with which ext4 calls into JBD. The intent here is | 123 | * Wrapper functions with which ext4 calls into JBD. |
120 | * to allow these to be turned into appropriate stubs so ext4 can control | ||
121 | * ext2 filesystems, so ext2+ext4 systems only nee one fs. This work hasn't | ||
122 | * been done yet. | ||
123 | */ | 124 | */ |
124 | |||
125 | void ext4_journal_abort_handle(const char *caller, const char *err_fn, | 125 | void ext4_journal_abort_handle(const char *caller, const char *err_fn, |
126 | struct buffer_head *bh, handle_t *handle, int err); | 126 | struct buffer_head *bh, handle_t *handle, int err); |
127 | 127 | ||
@@ -131,13 +131,9 @@ int __ext4_journal_get_undo_access(const char *where, handle_t *handle, | |||
131 | int __ext4_journal_get_write_access(const char *where, handle_t *handle, | 131 | int __ext4_journal_get_write_access(const char *where, handle_t *handle, |
132 | struct buffer_head *bh); | 132 | struct buffer_head *bh); |
133 | 133 | ||
134 | /* When called with an invalid handle, this will still do a put on the BH */ | 134 | int __ext4_forget(const char *where, handle_t *handle, int is_metadata, |
135 | int __ext4_journal_forget(const char *where, handle_t *handle, | 135 | struct inode *inode, struct buffer_head *bh, |
136 | struct buffer_head *bh); | 136 | ext4_fsblk_t blocknr); |
137 | |||
138 | /* When called with an invalid handle, this will still do a put on the BH */ | ||
139 | int __ext4_journal_revoke(const char *where, handle_t *handle, | ||
140 | ext4_fsblk_t blocknr, struct buffer_head *bh); | ||
141 | 137 | ||
142 | int __ext4_journal_get_create_access(const char *where, | 138 | int __ext4_journal_get_create_access(const char *where, |
143 | handle_t *handle, struct buffer_head *bh); | 139 | handle_t *handle, struct buffer_head *bh); |
@@ -149,12 +145,11 @@ int __ext4_handle_dirty_metadata(const char *where, handle_t *handle, | |||
149 | __ext4_journal_get_undo_access(__func__, (handle), (bh)) | 145 | __ext4_journal_get_undo_access(__func__, (handle), (bh)) |
150 | #define ext4_journal_get_write_access(handle, bh) \ | 146 | #define ext4_journal_get_write_access(handle, bh) \ |
151 | __ext4_journal_get_write_access(__func__, (handle), (bh)) | 147 | __ext4_journal_get_write_access(__func__, (handle), (bh)) |
152 | #define ext4_journal_revoke(handle, blocknr, bh) \ | 148 | #define ext4_forget(handle, is_metadata, inode, bh, block_nr) \ |
153 | __ext4_journal_revoke(__func__, (handle), (blocknr), (bh)) | 149 | __ext4_forget(__func__, (handle), (is_metadata), (inode), (bh),\ |
150 | (block_nr)) | ||
154 | #define ext4_journal_get_create_access(handle, bh) \ | 151 | #define ext4_journal_get_create_access(handle, bh) \ |
155 | __ext4_journal_get_create_access(__func__, (handle), (bh)) | 152 | __ext4_journal_get_create_access(__func__, (handle), (bh)) |
156 | #define ext4_journal_forget(handle, bh) \ | ||
157 | __ext4_journal_forget(__func__, (handle), (bh)) | ||
158 | #define ext4_handle_dirty_metadata(handle, inode, bh) \ | 153 | #define ext4_handle_dirty_metadata(handle, inode, bh) \ |
159 | __ext4_handle_dirty_metadata(__func__, (handle), (inode), (bh)) | 154 | __ext4_handle_dirty_metadata(__func__, (handle), (inode), (bh)) |
160 | 155 | ||
@@ -254,6 +249,19 @@ static inline int ext4_jbd2_file_inode(handle_t *handle, struct inode *inode) | |||
254 | return 0; | 249 | return 0; |
255 | } | 250 | } |
256 | 251 | ||
252 | static inline void ext4_update_inode_fsync_trans(handle_t *handle, | ||
253 | struct inode *inode, | ||
254 | int datasync) | ||
255 | { | ||
256 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
257 | |||
258 | if (ext4_handle_valid(handle)) { | ||
259 | ei->i_sync_tid = handle->h_transaction->t_tid; | ||
260 | if (datasync) | ||
261 | ei->i_datasync_tid = handle->h_transaction->t_tid; | ||
262 | } | ||
263 | } | ||
264 | |||
257 | /* super.c */ | 265 | /* super.c */ |
258 | int ext4_force_commit(struct super_block *sb); | 266 | int ext4_force_commit(struct super_block *sb); |
259 | 267 | ||
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 715264b4bae4..3a7928f825e4 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -1007,7 +1007,8 @@ cleanup: | |||
1007 | for (i = 0; i < depth; i++) { | 1007 | for (i = 0; i < depth; i++) { |
1008 | if (!ablocks[i]) | 1008 | if (!ablocks[i]) |
1009 | continue; | 1009 | continue; |
1010 | ext4_free_blocks(handle, inode, ablocks[i], 1, 1); | 1010 | ext4_free_blocks(handle, inode, 0, ablocks[i], 1, |
1011 | EXT4_FREE_BLOCKS_METADATA); | ||
1011 | } | 1012 | } |
1012 | } | 1013 | } |
1013 | kfree(ablocks); | 1014 | kfree(ablocks); |
@@ -1761,7 +1762,9 @@ int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block, | |||
1761 | while (block < last && block != EXT_MAX_BLOCK) { | 1762 | while (block < last && block != EXT_MAX_BLOCK) { |
1762 | num = last - block; | 1763 | num = last - block; |
1763 | /* find extent for this block */ | 1764 | /* find extent for this block */ |
1765 | down_read(&EXT4_I(inode)->i_data_sem); | ||
1764 | path = ext4_ext_find_extent(inode, block, path); | 1766 | path = ext4_ext_find_extent(inode, block, path); |
1767 | up_read(&EXT4_I(inode)->i_data_sem); | ||
1765 | if (IS_ERR(path)) { | 1768 | if (IS_ERR(path)) { |
1766 | err = PTR_ERR(path); | 1769 | err = PTR_ERR(path); |
1767 | path = NULL; | 1770 | path = NULL; |
@@ -1957,7 +1960,6 @@ errout: | |||
1957 | static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, | 1960 | static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, |
1958 | struct ext4_ext_path *path) | 1961 | struct ext4_ext_path *path) |
1959 | { | 1962 | { |
1960 | struct buffer_head *bh; | ||
1961 | int err; | 1963 | int err; |
1962 | ext4_fsblk_t leaf; | 1964 | ext4_fsblk_t leaf; |
1963 | 1965 | ||
@@ -1973,9 +1975,8 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, | |||
1973 | if (err) | 1975 | if (err) |
1974 | return err; | 1976 | return err; |
1975 | ext_debug("index is empty, remove it, free block %llu\n", leaf); | 1977 | ext_debug("index is empty, remove it, free block %llu\n", leaf); |
1976 | bh = sb_find_get_block(inode->i_sb, leaf); | 1978 | ext4_free_blocks(handle, inode, 0, leaf, 1, |
1977 | ext4_forget(handle, 1, inode, bh, leaf); | 1979 | EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); |
1978 | ext4_free_blocks(handle, inode, leaf, 1, 1); | ||
1979 | return err; | 1980 | return err; |
1980 | } | 1981 | } |
1981 | 1982 | ||
@@ -2042,12 +2043,11 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode, | |||
2042 | struct ext4_extent *ex, | 2043 | struct ext4_extent *ex, |
2043 | ext4_lblk_t from, ext4_lblk_t to) | 2044 | ext4_lblk_t from, ext4_lblk_t to) |
2044 | { | 2045 | { |
2045 | struct buffer_head *bh; | ||
2046 | unsigned short ee_len = ext4_ext_get_actual_len(ex); | 2046 | unsigned short ee_len = ext4_ext_get_actual_len(ex); |
2047 | int i, metadata = 0; | 2047 | int flags = EXT4_FREE_BLOCKS_FORGET; |
2048 | 2048 | ||
2049 | if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) | 2049 | if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) |
2050 | metadata = 1; | 2050 | flags |= EXT4_FREE_BLOCKS_METADATA; |
2051 | #ifdef EXTENTS_STATS | 2051 | #ifdef EXTENTS_STATS |
2052 | { | 2052 | { |
2053 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | 2053 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); |
@@ -2072,11 +2072,7 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode, | |||
2072 | num = le32_to_cpu(ex->ee_block) + ee_len - from; | 2072 | num = le32_to_cpu(ex->ee_block) + ee_len - from; |
2073 | start = ext_pblock(ex) + ee_len - num; | 2073 | start = ext_pblock(ex) + ee_len - num; |
2074 | ext_debug("free last %u blocks starting %llu\n", num, start); | 2074 | ext_debug("free last %u blocks starting %llu\n", num, start); |
2075 | for (i = 0; i < num; i++) { | 2075 | ext4_free_blocks(handle, inode, 0, start, num, flags); |
2076 | bh = sb_find_get_block(inode->i_sb, start + i); | ||
2077 | ext4_forget(handle, 0, inode, bh, start + i); | ||
2078 | } | ||
2079 | ext4_free_blocks(handle, inode, start, num, metadata); | ||
2080 | } else if (from == le32_to_cpu(ex->ee_block) | 2076 | } else if (from == le32_to_cpu(ex->ee_block) |
2081 | && to <= le32_to_cpu(ex->ee_block) + ee_len - 1) { | 2077 | && to <= le32_to_cpu(ex->ee_block) + ee_len - 1) { |
2082 | printk(KERN_INFO "strange request: removal %u-%u from %u:%u\n", | 2078 | printk(KERN_INFO "strange request: removal %u-%u from %u:%u\n", |
@@ -2167,7 +2163,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, | |||
2167 | correct_index = 1; | 2163 | correct_index = 1; |
2168 | credits += (ext_depth(inode)) + 1; | 2164 | credits += (ext_depth(inode)) + 1; |
2169 | } | 2165 | } |
2170 | credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); | 2166 | credits += EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb); |
2171 | 2167 | ||
2172 | err = ext4_ext_truncate_extend_restart(handle, inode, credits); | 2168 | err = ext4_ext_truncate_extend_restart(handle, inode, credits); |
2173 | if (err) | 2169 | if (err) |
@@ -3064,6 +3060,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, | |||
3064 | if (flags == EXT4_GET_BLOCKS_DIO_CONVERT_EXT) { | 3060 | if (flags == EXT4_GET_BLOCKS_DIO_CONVERT_EXT) { |
3065 | ret = ext4_convert_unwritten_extents_dio(handle, inode, | 3061 | ret = ext4_convert_unwritten_extents_dio(handle, inode, |
3066 | path); | 3062 | path); |
3063 | if (ret >= 0) | ||
3064 | ext4_update_inode_fsync_trans(handle, inode, 1); | ||
3067 | goto out2; | 3065 | goto out2; |
3068 | } | 3066 | } |
3069 | /* buffered IO case */ | 3067 | /* buffered IO case */ |
@@ -3091,6 +3089,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, | |||
3091 | ret = ext4_ext_convert_to_initialized(handle, inode, | 3089 | ret = ext4_ext_convert_to_initialized(handle, inode, |
3092 | path, iblock, | 3090 | path, iblock, |
3093 | max_blocks); | 3091 | max_blocks); |
3092 | if (ret >= 0) | ||
3093 | ext4_update_inode_fsync_trans(handle, inode, 1); | ||
3094 | out: | 3094 | out: |
3095 | if (ret <= 0) { | 3095 | if (ret <= 0) { |
3096 | err = ret; | 3096 | err = ret; |
@@ -3319,8 +3319,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
3319 | /* not a good idea to call discard here directly, | 3319 | /* not a good idea to call discard here directly, |
3320 | * but otherwise we'd need to call it every free() */ | 3320 | * but otherwise we'd need to call it every free() */ |
3321 | ext4_discard_preallocations(inode); | 3321 | ext4_discard_preallocations(inode); |
3322 | ext4_free_blocks(handle, inode, ext_pblock(&newex), | 3322 | ext4_free_blocks(handle, inode, 0, ext_pblock(&newex), |
3323 | ext4_ext_get_actual_len(&newex), 0); | 3323 | ext4_ext_get_actual_len(&newex), 0); |
3324 | goto out2; | 3324 | goto out2; |
3325 | } | 3325 | } |
3326 | 3326 | ||
@@ -3329,10 +3329,16 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
3329 | allocated = ext4_ext_get_actual_len(&newex); | 3329 | allocated = ext4_ext_get_actual_len(&newex); |
3330 | set_buffer_new(bh_result); | 3330 | set_buffer_new(bh_result); |
3331 | 3331 | ||
3332 | /* Cache only when it is _not_ an uninitialized extent */ | 3332 | /* |
3333 | if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) | 3333 | * Cache the extent and update transaction to commit on fdatasync only |
3334 | * when it is _not_ an uninitialized extent. | ||
3335 | */ | ||
3336 | if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) { | ||
3334 | ext4_ext_put_in_cache(inode, iblock, allocated, newblock, | 3337 | ext4_ext_put_in_cache(inode, iblock, allocated, newblock, |
3335 | EXT4_EXT_CACHE_EXTENT); | 3338 | EXT4_EXT_CACHE_EXTENT); |
3339 | ext4_update_inode_fsync_trans(handle, inode, 1); | ||
3340 | } else | ||
3341 | ext4_update_inode_fsync_trans(handle, inode, 0); | ||
3336 | out: | 3342 | out: |
3337 | if (allocated > max_blocks) | 3343 | if (allocated > max_blocks) |
3338 | allocated = max_blocks; | 3344 | allocated = max_blocks; |
@@ -3720,10 +3726,8 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
3720 | * Walk the extent tree gathering extent information. | 3726 | * Walk the extent tree gathering extent information. |
3721 | * ext4_ext_fiemap_cb will push extents back to user. | 3727 | * ext4_ext_fiemap_cb will push extents back to user. |
3722 | */ | 3728 | */ |
3723 | down_read(&EXT4_I(inode)->i_data_sem); | ||
3724 | error = ext4_ext_walk_space(inode, start_blk, len_blks, | 3729 | error = ext4_ext_walk_space(inode, start_blk, len_blks, |
3725 | ext4_ext_fiemap_cb, fieinfo); | 3730 | ext4_ext_fiemap_cb, fieinfo); |
3726 | up_read(&EXT4_I(inode)->i_data_sem); | ||
3727 | } | 3731 | } |
3728 | 3732 | ||
3729 | return error; | 3733 | return error; |
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 2b1531266ee2..0b22497d92e1 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
@@ -51,25 +51,30 @@ | |||
51 | int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) | 51 | int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) |
52 | { | 52 | { |
53 | struct inode *inode = dentry->d_inode; | 53 | struct inode *inode = dentry->d_inode; |
54 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
54 | journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; | 55 | journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; |
55 | int err, ret = 0; | 56 | int ret; |
57 | tid_t commit_tid; | ||
56 | 58 | ||
57 | J_ASSERT(ext4_journal_current_handle() == NULL); | 59 | J_ASSERT(ext4_journal_current_handle() == NULL); |
58 | 60 | ||
59 | trace_ext4_sync_file(file, dentry, datasync); | 61 | trace_ext4_sync_file(file, dentry, datasync); |
60 | 62 | ||
63 | if (inode->i_sb->s_flags & MS_RDONLY) | ||
64 | return 0; | ||
65 | |||
61 | ret = flush_aio_dio_completed_IO(inode); | 66 | ret = flush_aio_dio_completed_IO(inode); |
62 | if (ret < 0) | 67 | if (ret < 0) |
63 | goto out; | 68 | return ret; |
69 | |||
70 | if (!journal) | ||
71 | return simple_fsync(file, dentry, datasync); | ||
72 | |||
64 | /* | 73 | /* |
65 | * data=writeback: | 74 | * data=writeback,ordered: |
66 | * The caller's filemap_fdatawrite()/wait will sync the data. | 75 | * The caller's filemap_fdatawrite()/wait will sync the data. |
67 | * sync_inode() will sync the metadata | 76 | * Metadata is in the journal, we wait for proper transaction to |
68 | * | 77 | * commit here. |
69 | * data=ordered: | ||
70 | * The caller's filemap_fdatawrite() will write the data and | ||
71 | * sync_inode() will write the inode if it is dirty. Then the caller's | ||
72 | * filemap_fdatawait() will wait on the pages. | ||
73 | * | 78 | * |
74 | * data=journal: | 79 | * data=journal: |
75 | * filemap_fdatawrite won't do anything (the buffers are clean). | 80 | * filemap_fdatawrite won't do anything (the buffers are clean). |
@@ -79,32 +84,13 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) | |||
79 | * (they were dirtied by commit). But that's OK - the blocks are | 84 | * (they were dirtied by commit). But that's OK - the blocks are |
80 | * safe in-journal, which is all fsync() needs to ensure. | 85 | * safe in-journal, which is all fsync() needs to ensure. |
81 | */ | 86 | */ |
82 | if (ext4_should_journal_data(inode)) { | 87 | if (ext4_should_journal_data(inode)) |
83 | ret = ext4_force_commit(inode->i_sb); | 88 | return ext4_force_commit(inode->i_sb); |
84 | goto out; | ||
85 | } | ||
86 | 89 | ||
87 | if (!journal) | 90 | commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid; |
88 | ret = sync_mapping_buffers(inode->i_mapping); | 91 | if (jbd2_log_start_commit(journal, commit_tid)) |
89 | 92 | jbd2_log_wait_commit(journal, commit_tid); | |
90 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | 93 | else if (journal->j_flags & JBD2_BARRIER) |
91 | goto out; | ||
92 | |||
93 | /* | ||
94 | * The VFS has written the file data. If the inode is unaltered | ||
95 | * then we need not start a commit. | ||
96 | */ | ||
97 | if (inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC)) { | ||
98 | struct writeback_control wbc = { | ||
99 | .sync_mode = WB_SYNC_ALL, | ||
100 | .nr_to_write = 0, /* sys_fsync did this */ | ||
101 | }; | ||
102 | err = sync_inode(inode, &wbc); | ||
103 | if (ret == 0) | ||
104 | ret = err; | ||
105 | } | ||
106 | out: | ||
107 | if (journal && (journal->j_flags & JBD2_BARRIER)) | ||
108 | blkdev_issue_flush(inode->i_sb->s_bdev, NULL); | 94 | blkdev_issue_flush(inode->i_sb->s_bdev, NULL); |
109 | return ret; | 95 | return ret; |
110 | } | 96 | } |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 2c8caa51addb..5352db1a3086 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -71,58 +71,6 @@ static int ext4_inode_is_fast_symlink(struct inode *inode) | |||
71 | } | 71 | } |
72 | 72 | ||
73 | /* | 73 | /* |
74 | * The ext4 forget function must perform a revoke if we are freeing data | ||
75 | * which has been journaled. Metadata (eg. indirect blocks) must be | ||
76 | * revoked in all cases. | ||
77 | * | ||
78 | * "bh" may be NULL: a metadata block may have been freed from memory | ||
79 | * but there may still be a record of it in the journal, and that record | ||
80 | * still needs to be revoked. | ||
81 | * | ||
82 | * If the handle isn't valid we're not journaling, but we still need to | ||
83 | * call into ext4_journal_revoke() to put the buffer head. | ||
84 | */ | ||
85 | int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, | ||
86 | struct buffer_head *bh, ext4_fsblk_t blocknr) | ||
87 | { | ||
88 | int err; | ||
89 | |||
90 | might_sleep(); | ||
91 | |||
92 | BUFFER_TRACE(bh, "enter"); | ||
93 | |||
94 | jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " | ||
95 | "data mode %x\n", | ||
96 | bh, is_metadata, inode->i_mode, | ||
97 | test_opt(inode->i_sb, DATA_FLAGS)); | ||
98 | |||
99 | /* Never use the revoke function if we are doing full data | ||
100 | * journaling: there is no need to, and a V1 superblock won't | ||
101 | * support it. Otherwise, only skip the revoke on un-journaled | ||
102 | * data blocks. */ | ||
103 | |||
104 | if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA || | ||
105 | (!is_metadata && !ext4_should_journal_data(inode))) { | ||
106 | if (bh) { | ||
107 | BUFFER_TRACE(bh, "call jbd2_journal_forget"); | ||
108 | return ext4_journal_forget(handle, bh); | ||
109 | } | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * data!=journal && (is_metadata || should_journal_data(inode)) | ||
115 | */ | ||
116 | BUFFER_TRACE(bh, "call ext4_journal_revoke"); | ||
117 | err = ext4_journal_revoke(handle, blocknr, bh); | ||
118 | if (err) | ||
119 | ext4_abort(inode->i_sb, __func__, | ||
120 | "error %d when attempting revoke", err); | ||
121 | BUFFER_TRACE(bh, "exit"); | ||
122 | return err; | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * Work out how many blocks we need to proceed with the next chunk of a | 74 | * Work out how many blocks we need to proceed with the next chunk of a |
127 | * truncate transaction. | 75 | * truncate transaction. |
128 | */ | 76 | */ |
@@ -721,7 +669,7 @@ allocated: | |||
721 | return ret; | 669 | return ret; |
722 | failed_out: | 670 | failed_out: |
723 | for (i = 0; i < index; i++) | 671 | for (i = 0; i < index; i++) |
724 | ext4_free_blocks(handle, inode, new_blocks[i], 1, 0); | 672 | ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, 0); |
725 | return ret; | 673 | return ret; |
726 | } | 674 | } |
727 | 675 | ||
@@ -817,14 +765,20 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | |||
817 | return err; | 765 | return err; |
818 | failed: | 766 | failed: |
819 | /* Allocation failed, free what we already allocated */ | 767 | /* Allocation failed, free what we already allocated */ |
768 | ext4_free_blocks(handle, inode, 0, new_blocks[0], 1, 0); | ||
820 | for (i = 1; i <= n ; i++) { | 769 | for (i = 1; i <= n ; i++) { |
821 | BUFFER_TRACE(branch[i].bh, "call jbd2_journal_forget"); | 770 | /* |
822 | ext4_journal_forget(handle, branch[i].bh); | 771 | * branch[i].bh is newly allocated, so there is no |
772 | * need to revoke the block, which is why we don't | ||
773 | * need to set EXT4_FREE_BLOCKS_METADATA. | ||
774 | */ | ||
775 | ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, | ||
776 | EXT4_FREE_BLOCKS_FORGET); | ||
823 | } | 777 | } |
824 | for (i = 0; i < indirect_blks; i++) | 778 | for (i = n+1; i < indirect_blks; i++) |
825 | ext4_free_blocks(handle, inode, new_blocks[i], 1, 0); | 779 | ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, 0); |
826 | 780 | ||
827 | ext4_free_blocks(handle, inode, new_blocks[i], num, 0); | 781 | ext4_free_blocks(handle, inode, 0, new_blocks[i], num, 0); |
828 | 782 | ||
829 | return err; | 783 | return err; |
830 | } | 784 | } |
@@ -903,12 +857,16 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode, | |||
903 | 857 | ||
904 | err_out: | 858 | err_out: |
905 | for (i = 1; i <= num; i++) { | 859 | for (i = 1; i <= num; i++) { |
906 | BUFFER_TRACE(where[i].bh, "call jbd2_journal_forget"); | 860 | /* |
907 | ext4_journal_forget(handle, where[i].bh); | 861 | * branch[i].bh is newly allocated, so there is no |
908 | ext4_free_blocks(handle, inode, | 862 | * need to revoke the block, which is why we don't |
909 | le32_to_cpu(where[i-1].key), 1, 0); | 863 | * need to set EXT4_FREE_BLOCKS_METADATA. |
864 | */ | ||
865 | ext4_free_blocks(handle, inode, where[i].bh, 0, 1, | ||
866 | EXT4_FREE_BLOCKS_FORGET); | ||
910 | } | 867 | } |
911 | ext4_free_blocks(handle, inode, le32_to_cpu(where[num].key), blks, 0); | 868 | ext4_free_blocks(handle, inode, 0, le32_to_cpu(where[num].key), |
869 | blks, 0); | ||
912 | 870 | ||
913 | return err; | 871 | return err; |
914 | } | 872 | } |
@@ -1021,10 +979,12 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, | |||
1021 | if (!err) | 979 | if (!err) |
1022 | err = ext4_splice_branch(handle, inode, iblock, | 980 | err = ext4_splice_branch(handle, inode, iblock, |
1023 | partial, indirect_blks, count); | 981 | partial, indirect_blks, count); |
1024 | else | 982 | if (err) |
1025 | goto cleanup; | 983 | goto cleanup; |
1026 | 984 | ||
1027 | set_buffer_new(bh_result); | 985 | set_buffer_new(bh_result); |
986 | |||
987 | ext4_update_inode_fsync_trans(handle, inode, 1); | ||
1028 | got_it: | 988 | got_it: |
1029 | map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); | 989 | map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); |
1030 | if (count > blocks_to_boundary) | 990 | if (count > blocks_to_boundary) |
@@ -1052,7 +1012,7 @@ qsize_t ext4_get_reserved_space(struct inode *inode) | |||
1052 | EXT4_I(inode)->i_reserved_meta_blocks; | 1012 | EXT4_I(inode)->i_reserved_meta_blocks; |
1053 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | 1013 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); |
1054 | 1014 | ||
1055 | return total; | 1015 | return (total << inode->i_blkbits); |
1056 | } | 1016 | } |
1057 | /* | 1017 | /* |
1058 | * Calculate the number of metadata blocks need to reserve | 1018 | * Calculate the number of metadata blocks need to reserve |
@@ -1534,6 +1494,16 @@ static int do_journal_get_write_access(handle_t *handle, | |||
1534 | return ext4_journal_get_write_access(handle, bh); | 1494 | return ext4_journal_get_write_access(handle, bh); |
1535 | } | 1495 | } |
1536 | 1496 | ||
1497 | /* | ||
1498 | * Truncate blocks that were not used by write. We have to truncate the | ||
1499 | * pagecache as well so that corresponding buffers get properly unmapped. | ||
1500 | */ | ||
1501 | static void ext4_truncate_failed_write(struct inode *inode) | ||
1502 | { | ||
1503 | truncate_inode_pages(inode->i_mapping, inode->i_size); | ||
1504 | ext4_truncate(inode); | ||
1505 | } | ||
1506 | |||
1537 | static int ext4_write_begin(struct file *file, struct address_space *mapping, | 1507 | static int ext4_write_begin(struct file *file, struct address_space *mapping, |
1538 | loff_t pos, unsigned len, unsigned flags, | 1508 | loff_t pos, unsigned len, unsigned flags, |
1539 | struct page **pagep, void **fsdata) | 1509 | struct page **pagep, void **fsdata) |
@@ -1599,7 +1569,7 @@ retry: | |||
1599 | 1569 | ||
1600 | ext4_journal_stop(handle); | 1570 | ext4_journal_stop(handle); |
1601 | if (pos + len > inode->i_size) { | 1571 | if (pos + len > inode->i_size) { |
1602 | ext4_truncate(inode); | 1572 | ext4_truncate_failed_write(inode); |
1603 | /* | 1573 | /* |
1604 | * If truncate failed early the inode might | 1574 | * If truncate failed early the inode might |
1605 | * still be on the orphan list; we need to | 1575 | * still be on the orphan list; we need to |
@@ -1709,7 +1679,7 @@ static int ext4_ordered_write_end(struct file *file, | |||
1709 | ret = ret2; | 1679 | ret = ret2; |
1710 | 1680 | ||
1711 | if (pos + len > inode->i_size) { | 1681 | if (pos + len > inode->i_size) { |
1712 | ext4_truncate(inode); | 1682 | ext4_truncate_failed_write(inode); |
1713 | /* | 1683 | /* |
1714 | * If truncate failed early the inode might still be | 1684 | * If truncate failed early the inode might still be |
1715 | * on the orphan list; we need to make sure the inode | 1685 | * on the orphan list; we need to make sure the inode |
@@ -1751,7 +1721,7 @@ static int ext4_writeback_write_end(struct file *file, | |||
1751 | ret = ret2; | 1721 | ret = ret2; |
1752 | 1722 | ||
1753 | if (pos + len > inode->i_size) { | 1723 | if (pos + len > inode->i_size) { |
1754 | ext4_truncate(inode); | 1724 | ext4_truncate_failed_write(inode); |
1755 | /* | 1725 | /* |
1756 | * If truncate failed early the inode might still be | 1726 | * If truncate failed early the inode might still be |
1757 | * on the orphan list; we need to make sure the inode | 1727 | * on the orphan list; we need to make sure the inode |
@@ -1814,7 +1784,7 @@ static int ext4_journalled_write_end(struct file *file, | |||
1814 | if (!ret) | 1784 | if (!ret) |
1815 | ret = ret2; | 1785 | ret = ret2; |
1816 | if (pos + len > inode->i_size) { | 1786 | if (pos + len > inode->i_size) { |
1817 | ext4_truncate(inode); | 1787 | ext4_truncate_failed_write(inode); |
1818 | /* | 1788 | /* |
1819 | * If truncate failed early the inode might still be | 1789 | * If truncate failed early the inode might still be |
1820 | * on the orphan list; we need to make sure the inode | 1790 | * on the orphan list; we need to make sure the inode |
@@ -2600,7 +2570,6 @@ static int bput_one(handle_t *handle, struct buffer_head *bh) | |||
2600 | } | 2570 | } |
2601 | 2571 | ||
2602 | static int __ext4_journalled_writepage(struct page *page, | 2572 | static int __ext4_journalled_writepage(struct page *page, |
2603 | struct writeback_control *wbc, | ||
2604 | unsigned int len) | 2573 | unsigned int len) |
2605 | { | 2574 | { |
2606 | struct address_space *mapping = page->mapping; | 2575 | struct address_space *mapping = page->mapping; |
@@ -2758,7 +2727,7 @@ static int ext4_writepage(struct page *page, | |||
2758 | * doesn't seem much point in redirtying the page here. | 2727 | * doesn't seem much point in redirtying the page here. |
2759 | */ | 2728 | */ |
2760 | ClearPageChecked(page); | 2729 | ClearPageChecked(page); |
2761 | return __ext4_journalled_writepage(page, wbc, len); | 2730 | return __ext4_journalled_writepage(page, len); |
2762 | } | 2731 | } |
2763 | 2732 | ||
2764 | if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) | 2733 | if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) |
@@ -2788,7 +2757,7 @@ static int ext4_da_writepages_trans_blocks(struct inode *inode) | |||
2788 | * number of contiguous block. So we will limit | 2757 | * number of contiguous block. So we will limit |
2789 | * number of contiguous block to a sane value | 2758 | * number of contiguous block to a sane value |
2790 | */ | 2759 | */ |
2791 | if (!(inode->i_flags & EXT4_EXTENTS_FL) && | 2760 | if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) && |
2792 | (max_blocks > EXT4_MAX_TRANS_DATA)) | 2761 | (max_blocks > EXT4_MAX_TRANS_DATA)) |
2793 | max_blocks = EXT4_MAX_TRANS_DATA; | 2762 | max_blocks = EXT4_MAX_TRANS_DATA; |
2794 | 2763 | ||
@@ -2933,7 +2902,7 @@ retry: | |||
2933 | ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, | 2902 | ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, |
2934 | &mpd); | 2903 | &mpd); |
2935 | /* | 2904 | /* |
2936 | * If we have a contigous extent of pages and we | 2905 | * If we have a contiguous extent of pages and we |
2937 | * haven't done the I/O yet, map the blocks and submit | 2906 | * haven't done the I/O yet, map the blocks and submit |
2938 | * them for I/O. | 2907 | * them for I/O. |
2939 | */ | 2908 | */ |
@@ -3091,7 +3060,7 @@ retry: | |||
3091 | * i_size_read because we hold i_mutex. | 3060 | * i_size_read because we hold i_mutex. |
3092 | */ | 3061 | */ |
3093 | if (pos + len > inode->i_size) | 3062 | if (pos + len > inode->i_size) |
3094 | ext4_truncate(inode); | 3063 | ext4_truncate_failed_write(inode); |
3095 | } | 3064 | } |
3096 | 3065 | ||
3097 | if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) | 3066 | if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) |
@@ -4064,7 +4033,7 @@ static Indirect *ext4_find_shared(struct inode *inode, int depth, | |||
4064 | int k, err; | 4033 | int k, err; |
4065 | 4034 | ||
4066 | *top = 0; | 4035 | *top = 0; |
4067 | /* Make k index the deepest non-null offest + 1 */ | 4036 | /* Make k index the deepest non-null offset + 1 */ |
4068 | for (k = depth; k > 1 && !offsets[k-1]; k--) | 4037 | for (k = depth; k > 1 && !offsets[k-1]; k--) |
4069 | ; | 4038 | ; |
4070 | partial = ext4_get_branch(inode, k, offsets, chain, &err); | 4039 | partial = ext4_get_branch(inode, k, offsets, chain, &err); |
@@ -4120,6 +4089,11 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode, | |||
4120 | __le32 *last) | 4089 | __le32 *last) |
4121 | { | 4090 | { |
4122 | __le32 *p; | 4091 | __le32 *p; |
4092 | int flags = EXT4_FREE_BLOCKS_FORGET; | ||
4093 | |||
4094 | if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) | ||
4095 | flags |= EXT4_FREE_BLOCKS_METADATA; | ||
4096 | |||
4123 | if (try_to_extend_transaction(handle, inode)) { | 4097 | if (try_to_extend_transaction(handle, inode)) { |
4124 | if (bh) { | 4098 | if (bh) { |
4125 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | 4099 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); |
@@ -4134,27 +4108,10 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode, | |||
4134 | } | 4108 | } |
4135 | } | 4109 | } |
4136 | 4110 | ||
4137 | /* | 4111 | for (p = first; p < last; p++) |
4138 | * Any buffers which are on the journal will be in memory. We | 4112 | *p = 0; |
4139 | * find them on the hash table so jbd2_journal_revoke() will | ||
4140 | * run jbd2_journal_forget() on them. We've already detached | ||
4141 | * each block from the file, so bforget() in | ||
4142 | * jbd2_journal_forget() should be safe. | ||
4143 | * | ||
4144 | * AKPM: turn on bforget in jbd2_journal_forget()!!! | ||
4145 | */ | ||
4146 | for (p = first; p < last; p++) { | ||
4147 | u32 nr = le32_to_cpu(*p); | ||
4148 | if (nr) { | ||
4149 | struct buffer_head *tbh; | ||
4150 | |||
4151 | *p = 0; | ||
4152 | tbh = sb_find_get_block(inode->i_sb, nr); | ||
4153 | ext4_forget(handle, 0, inode, tbh, nr); | ||
4154 | } | ||
4155 | } | ||
4156 | 4113 | ||
4157 | ext4_free_blocks(handle, inode, block_to_free, count, 0); | 4114 | ext4_free_blocks(handle, inode, 0, block_to_free, count, flags); |
4158 | } | 4115 | } |
4159 | 4116 | ||
4160 | /** | 4117 | /** |
@@ -4342,7 +4299,8 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode, | |||
4342 | blocks_for_truncate(inode)); | 4299 | blocks_for_truncate(inode)); |
4343 | } | 4300 | } |
4344 | 4301 | ||
4345 | ext4_free_blocks(handle, inode, nr, 1, 1); | 4302 | ext4_free_blocks(handle, inode, 0, nr, 1, |
4303 | EXT4_FREE_BLOCKS_METADATA); | ||
4346 | 4304 | ||
4347 | if (parent_bh) { | 4305 | if (parent_bh) { |
4348 | /* | 4306 | /* |
@@ -4781,8 +4739,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4781 | struct ext4_iloc iloc; | 4739 | struct ext4_iloc iloc; |
4782 | struct ext4_inode *raw_inode; | 4740 | struct ext4_inode *raw_inode; |
4783 | struct ext4_inode_info *ei; | 4741 | struct ext4_inode_info *ei; |
4784 | struct buffer_head *bh; | ||
4785 | struct inode *inode; | 4742 | struct inode *inode; |
4743 | journal_t *journal = EXT4_SB(sb)->s_journal; | ||
4786 | long ret; | 4744 | long ret; |
4787 | int block; | 4745 | int block; |
4788 | 4746 | ||
@@ -4793,11 +4751,11 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4793 | return inode; | 4751 | return inode; |
4794 | 4752 | ||
4795 | ei = EXT4_I(inode); | 4753 | ei = EXT4_I(inode); |
4754 | iloc.bh = 0; | ||
4796 | 4755 | ||
4797 | ret = __ext4_get_inode_loc(inode, &iloc, 0); | 4756 | ret = __ext4_get_inode_loc(inode, &iloc, 0); |
4798 | if (ret < 0) | 4757 | if (ret < 0) |
4799 | goto bad_inode; | 4758 | goto bad_inode; |
4800 | bh = iloc.bh; | ||
4801 | raw_inode = ext4_raw_inode(&iloc); | 4759 | raw_inode = ext4_raw_inode(&iloc); |
4802 | inode->i_mode = le16_to_cpu(raw_inode->i_mode); | 4760 | inode->i_mode = le16_to_cpu(raw_inode->i_mode); |
4803 | inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); | 4761 | inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); |
@@ -4820,7 +4778,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4820 | if (inode->i_mode == 0 || | 4778 | if (inode->i_mode == 0 || |
4821 | !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) { | 4779 | !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) { |
4822 | /* this inode is deleted */ | 4780 | /* this inode is deleted */ |
4823 | brelse(bh); | ||
4824 | ret = -ESTALE; | 4781 | ret = -ESTALE; |
4825 | goto bad_inode; | 4782 | goto bad_inode; |
4826 | } | 4783 | } |
@@ -4848,11 +4805,35 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4848 | ei->i_data[block] = raw_inode->i_block[block]; | 4805 | ei->i_data[block] = raw_inode->i_block[block]; |
4849 | INIT_LIST_HEAD(&ei->i_orphan); | 4806 | INIT_LIST_HEAD(&ei->i_orphan); |
4850 | 4807 | ||
4808 | /* | ||
4809 | * Set transaction id's of transactions that have to be committed | ||
4810 | * to finish f[data]sync. We set them to currently running transaction | ||
4811 | * as we cannot be sure that the inode or some of its metadata isn't | ||
4812 | * part of the transaction - the inode could have been reclaimed and | ||
4813 | * now it is reread from disk. | ||
4814 | */ | ||
4815 | if (journal) { | ||
4816 | transaction_t *transaction; | ||
4817 | tid_t tid; | ||
4818 | |||
4819 | spin_lock(&journal->j_state_lock); | ||
4820 | if (journal->j_running_transaction) | ||
4821 | transaction = journal->j_running_transaction; | ||
4822 | else | ||
4823 | transaction = journal->j_committing_transaction; | ||
4824 | if (transaction) | ||
4825 | tid = transaction->t_tid; | ||
4826 | else | ||
4827 | tid = journal->j_commit_sequence; | ||
4828 | spin_unlock(&journal->j_state_lock); | ||
4829 | ei->i_sync_tid = tid; | ||
4830 | ei->i_datasync_tid = tid; | ||
4831 | } | ||
4832 | |||
4851 | if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { | 4833 | if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { |
4852 | ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); | 4834 | ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); |
4853 | if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > | 4835 | if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > |
4854 | EXT4_INODE_SIZE(inode->i_sb)) { | 4836 | EXT4_INODE_SIZE(inode->i_sb)) { |
4855 | brelse(bh); | ||
4856 | ret = -EIO; | 4837 | ret = -EIO; |
4857 | goto bad_inode; | 4838 | goto bad_inode; |
4858 | } | 4839 | } |
@@ -4884,10 +4865,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4884 | 4865 | ||
4885 | ret = 0; | 4866 | ret = 0; |
4886 | if (ei->i_file_acl && | 4867 | if (ei->i_file_acl && |
4887 | ((ei->i_file_acl < | 4868 | !ext4_data_block_valid(EXT4_SB(sb), ei->i_file_acl, 1)) { |
4888 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) + | ||
4889 | EXT4_SB(sb)->s_gdb_count)) || | ||
4890 | (ei->i_file_acl >= ext4_blocks_count(EXT4_SB(sb)->s_es)))) { | ||
4891 | ext4_error(sb, __func__, | 4869 | ext4_error(sb, __func__, |
4892 | "bad extended attribute block %llu in inode #%lu", | 4870 | "bad extended attribute block %llu in inode #%lu", |
4893 | ei->i_file_acl, inode->i_ino); | 4871 | ei->i_file_acl, inode->i_ino); |
@@ -4905,10 +4883,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4905 | /* Validate block references which are part of inode */ | 4883 | /* Validate block references which are part of inode */ |
4906 | ret = ext4_check_inode_blockref(inode); | 4884 | ret = ext4_check_inode_blockref(inode); |
4907 | } | 4885 | } |
4908 | if (ret) { | 4886 | if (ret) |
4909 | brelse(bh); | ||
4910 | goto bad_inode; | 4887 | goto bad_inode; |
4911 | } | ||
4912 | 4888 | ||
4913 | if (S_ISREG(inode->i_mode)) { | 4889 | if (S_ISREG(inode->i_mode)) { |
4914 | inode->i_op = &ext4_file_inode_operations; | 4890 | inode->i_op = &ext4_file_inode_operations; |
@@ -4936,7 +4912,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4936 | init_special_inode(inode, inode->i_mode, | 4912 | init_special_inode(inode, inode->i_mode, |
4937 | new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); | 4913 | new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); |
4938 | } else { | 4914 | } else { |
4939 | brelse(bh); | ||
4940 | ret = -EIO; | 4915 | ret = -EIO; |
4941 | ext4_error(inode->i_sb, __func__, | 4916 | ext4_error(inode->i_sb, __func__, |
4942 | "bogus i_mode (%o) for inode=%lu", | 4917 | "bogus i_mode (%o) for inode=%lu", |
@@ -4949,6 +4924,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4949 | return inode; | 4924 | return inode; |
4950 | 4925 | ||
4951 | bad_inode: | 4926 | bad_inode: |
4927 | brelse(iloc.bh); | ||
4952 | iget_failed(inode); | 4928 | iget_failed(inode); |
4953 | return ERR_PTR(ret); | 4929 | return ERR_PTR(ret); |
4954 | } | 4930 | } |
@@ -5108,6 +5084,7 @@ static int ext4_do_update_inode(handle_t *handle, | |||
5108 | err = rc; | 5084 | err = rc; |
5109 | ei->i_state &= ~EXT4_STATE_NEW; | 5085 | ei->i_state &= ~EXT4_STATE_NEW; |
5110 | 5086 | ||
5087 | ext4_update_inode_fsync_trans(handle, inode, 0); | ||
5111 | out_brelse: | 5088 | out_brelse: |
5112 | brelse(bh); | 5089 | brelse(bh); |
5113 | ext4_std_error(inode->i_sb, err); | 5090 | ext4_std_error(inode->i_sb, err); |
@@ -5227,8 +5204,8 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) | |||
5227 | 5204 | ||
5228 | /* (user+group)*(old+new) structure, inode write (sb, | 5205 | /* (user+group)*(old+new) structure, inode write (sb, |
5229 | * inode block, ? - but truncate inode update has it) */ | 5206 | * inode block, ? - but truncate inode update has it) */ |
5230 | handle = ext4_journal_start(inode, 2*(EXT4_QUOTA_INIT_BLOCKS(inode->i_sb)+ | 5207 | handle = ext4_journal_start(inode, (EXT4_MAXQUOTAS_INIT_BLOCKS(inode->i_sb)+ |
5231 | EXT4_QUOTA_DEL_BLOCKS(inode->i_sb))+3); | 5208 | EXT4_MAXQUOTAS_DEL_BLOCKS(inode->i_sb))+3); |
5232 | if (IS_ERR(handle)) { | 5209 | if (IS_ERR(handle)) { |
5233 | error = PTR_ERR(handle); | 5210 | error = PTR_ERR(handle); |
5234 | goto err_out; | 5211 | goto err_out; |
@@ -5376,7 +5353,7 @@ static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk) | |||
5376 | * worse case, the indexs blocks spread over different block groups | 5353 | * worse case, the indexs blocks spread over different block groups |
5377 | * | 5354 | * |
5378 | * If datablocks are discontiguous, they are possible to spread over | 5355 | * If datablocks are discontiguous, they are possible to spread over |
5379 | * different block groups too. If they are contiugous, with flexbg, | 5356 | * different block groups too. If they are contiuguous, with flexbg, |
5380 | * they could still across block group boundary. | 5357 | * they could still across block group boundary. |
5381 | * | 5358 | * |
5382 | * Also account for superblock, inode, quota and xattr blocks | 5359 | * Also account for superblock, inode, quota and xattr blocks |
@@ -5452,7 +5429,7 @@ int ext4_writepage_trans_blocks(struct inode *inode) | |||
5452 | * Calculate the journal credits for a chunk of data modification. | 5429 | * Calculate the journal credits for a chunk of data modification. |
5453 | * | 5430 | * |
5454 | * This is called from DIO, fallocate or whoever calling | 5431 | * This is called from DIO, fallocate or whoever calling |
5455 | * ext4_get_blocks() to map/allocate a chunk of contigous disk blocks. | 5432 | * ext4_get_blocks() to map/allocate a chunk of contiguous disk blocks. |
5456 | * | 5433 | * |
5457 | * journal buffers for data blocks are not included here, as DIO | 5434 | * journal buffers for data blocks are not included here, as DIO |
5458 | * and fallocate do no need to journal data buffers. | 5435 | * and fallocate do no need to journal data buffers. |
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index c1cdf613e725..b63d193126db 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -221,31 +221,38 @@ setversion_out: | |||
221 | struct file *donor_filp; | 221 | struct file *donor_filp; |
222 | int err; | 222 | int err; |
223 | 223 | ||
224 | if (!(filp->f_mode & FMODE_READ) || | ||
225 | !(filp->f_mode & FMODE_WRITE)) | ||
226 | return -EBADF; | ||
227 | |||
224 | if (copy_from_user(&me, | 228 | if (copy_from_user(&me, |
225 | (struct move_extent __user *)arg, sizeof(me))) | 229 | (struct move_extent __user *)arg, sizeof(me))) |
226 | return -EFAULT; | 230 | return -EFAULT; |
231 | me.moved_len = 0; | ||
227 | 232 | ||
228 | donor_filp = fget(me.donor_fd); | 233 | donor_filp = fget(me.donor_fd); |
229 | if (!donor_filp) | 234 | if (!donor_filp) |
230 | return -EBADF; | 235 | return -EBADF; |
231 | 236 | ||
232 | if (!capable(CAP_DAC_OVERRIDE)) { | 237 | if (!(donor_filp->f_mode & FMODE_WRITE)) { |
233 | if ((current->real_cred->fsuid != inode->i_uid) || | 238 | err = -EBADF; |
234 | !(inode->i_mode & S_IRUSR) || | 239 | goto mext_out; |
235 | !(donor_filp->f_dentry->d_inode->i_mode & | ||
236 | S_IRUSR)) { | ||
237 | fput(donor_filp); | ||
238 | return -EACCES; | ||
239 | } | ||
240 | } | 240 | } |
241 | 241 | ||
242 | err = mnt_want_write(filp->f_path.mnt); | ||
243 | if (err) | ||
244 | goto mext_out; | ||
245 | |||
242 | err = ext4_move_extents(filp, donor_filp, me.orig_start, | 246 | err = ext4_move_extents(filp, donor_filp, me.orig_start, |
243 | me.donor_start, me.len, &me.moved_len); | 247 | me.donor_start, me.len, &me.moved_len); |
244 | fput(donor_filp); | 248 | mnt_drop_write(filp->f_path.mnt); |
249 | if (me.moved_len > 0) | ||
250 | file_remove_suid(donor_filp); | ||
245 | 251 | ||
246 | if (copy_to_user((struct move_extent *)arg, &me, sizeof(me))) | 252 | if (copy_to_user((struct move_extent *)arg, &me, sizeof(me))) |
247 | return -EFAULT; | 253 | err = -EFAULT; |
248 | 254 | mext_out: | |
255 | fput(donor_filp); | ||
249 | return err; | 256 | return err; |
250 | } | 257 | } |
251 | 258 | ||
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index bba12824defa..c1e19d5b5985 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -142,7 +142,7 @@ | |||
142 | * 2 blocks and the order of allocation is >= sbi->s_mb_order2_reqs. The | 142 | * 2 blocks and the order of allocation is >= sbi->s_mb_order2_reqs. The |
143 | * value of s_mb_order2_reqs can be tuned via | 143 | * value of s_mb_order2_reqs can be tuned via |
144 | * /sys/fs/ext4/<partition>/mb_order2_req. If the request len is equal to | 144 | * /sys/fs/ext4/<partition>/mb_order2_req. If the request len is equal to |
145 | * stripe size (sbi->s_stripe), we try to search for contigous block in | 145 | * stripe size (sbi->s_stripe), we try to search for contiguous block in |
146 | * stripe size. This should result in better allocation on RAID setups. If | 146 | * stripe size. This should result in better allocation on RAID setups. If |
147 | * not, we search in the specific group using bitmap for best extents. The | 147 | * not, we search in the specific group using bitmap for best extents. The |
148 | * tunable min_to_scan and max_to_scan control the behaviour here. | 148 | * tunable min_to_scan and max_to_scan control the behaviour here. |
@@ -2529,7 +2529,6 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn) | |||
2529 | struct ext4_group_info *db; | 2529 | struct ext4_group_info *db; |
2530 | int err, count = 0, count2 = 0; | 2530 | int err, count = 0, count2 = 0; |
2531 | struct ext4_free_data *entry; | 2531 | struct ext4_free_data *entry; |
2532 | ext4_fsblk_t discard_block; | ||
2533 | struct list_head *l, *ltmp; | 2532 | struct list_head *l, *ltmp; |
2534 | 2533 | ||
2535 | list_for_each_safe(l, ltmp, &txn->t_private_list) { | 2534 | list_for_each_safe(l, ltmp, &txn->t_private_list) { |
@@ -2559,13 +2558,19 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn) | |||
2559 | page_cache_release(e4b.bd_bitmap_page); | 2558 | page_cache_release(e4b.bd_bitmap_page); |
2560 | } | 2559 | } |
2561 | ext4_unlock_group(sb, entry->group); | 2560 | ext4_unlock_group(sb, entry->group); |
2562 | discard_block = (ext4_fsblk_t) entry->group * EXT4_BLOCKS_PER_GROUP(sb) | 2561 | if (test_opt(sb, DISCARD)) { |
2563 | + entry->start_blk | 2562 | ext4_fsblk_t discard_block; |
2564 | + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); | 2563 | struct ext4_super_block *es = EXT4_SB(sb)->s_es; |
2565 | trace_ext4_discard_blocks(sb, (unsigned long long)discard_block, | 2564 | |
2566 | entry->count); | 2565 | discard_block = (ext4_fsblk_t)entry->group * |
2567 | sb_issue_discard(sb, discard_block, entry->count); | 2566 | EXT4_BLOCKS_PER_GROUP(sb) |
2568 | 2567 | + entry->start_blk | |
2568 | + le32_to_cpu(es->s_first_data_block); | ||
2569 | trace_ext4_discard_blocks(sb, | ||
2570 | (unsigned long long)discard_block, | ||
2571 | entry->count); | ||
2572 | sb_issue_discard(sb, discard_block, entry->count); | ||
2573 | } | ||
2569 | kmem_cache_free(ext4_free_ext_cachep, entry); | 2574 | kmem_cache_free(ext4_free_ext_cachep, entry); |
2570 | ext4_mb_release_desc(&e4b); | 2575 | ext4_mb_release_desc(&e4b); |
2571 | } | 2576 | } |
@@ -3006,6 +3011,24 @@ static void ext4_mb_collect_stats(struct ext4_allocation_context *ac) | |||
3006 | } | 3011 | } |
3007 | 3012 | ||
3008 | /* | 3013 | /* |
3014 | * Called on failure; free up any blocks from the inode PA for this | ||
3015 | * context. We don't need this for MB_GROUP_PA because we only change | ||
3016 | * pa_free in ext4_mb_release_context(), but on failure, we've already | ||
3017 | * zeroed out ac->ac_b_ex.fe_len, so group_pa->pa_free is not changed. | ||
3018 | */ | ||
3019 | static void ext4_discard_allocated_blocks(struct ext4_allocation_context *ac) | ||
3020 | { | ||
3021 | struct ext4_prealloc_space *pa = ac->ac_pa; | ||
3022 | int len; | ||
3023 | |||
3024 | if (pa && pa->pa_type == MB_INODE_PA) { | ||
3025 | len = ac->ac_b_ex.fe_len; | ||
3026 | pa->pa_free += len; | ||
3027 | } | ||
3028 | |||
3029 | } | ||
3030 | |||
3031 | /* | ||
3009 | * use blocks preallocated to inode | 3032 | * use blocks preallocated to inode |
3010 | */ | 3033 | */ |
3011 | static void ext4_mb_use_inode_pa(struct ext4_allocation_context *ac, | 3034 | static void ext4_mb_use_inode_pa(struct ext4_allocation_context *ac, |
@@ -4290,6 +4313,7 @@ repeat: | |||
4290 | ac->ac_status = AC_STATUS_CONTINUE; | 4313 | ac->ac_status = AC_STATUS_CONTINUE; |
4291 | goto repeat; | 4314 | goto repeat; |
4292 | } else if (*errp) { | 4315 | } else if (*errp) { |
4316 | ext4_discard_allocated_blocks(ac); | ||
4293 | ac->ac_b_ex.fe_len = 0; | 4317 | ac->ac_b_ex.fe_len = 0; |
4294 | ar->len = 0; | 4318 | ar->len = 0; |
4295 | ext4_mb_show_ac(ac); | 4319 | ext4_mb_show_ac(ac); |
@@ -4422,18 +4446,24 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, | |||
4422 | return 0; | 4446 | return 0; |
4423 | } | 4447 | } |
4424 | 4448 | ||
4425 | /* | 4449 | /** |
4426 | * Main entry point into mballoc to free blocks | 4450 | * ext4_free_blocks() -- Free given blocks and update quota |
4451 | * @handle: handle for this transaction | ||
4452 | * @inode: inode | ||
4453 | * @block: start physical block to free | ||
4454 | * @count: number of blocks to count | ||
4455 | * @metadata: Are these metadata blocks | ||
4427 | */ | 4456 | */ |
4428 | void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, | 4457 | void ext4_free_blocks(handle_t *handle, struct inode *inode, |
4429 | ext4_fsblk_t block, unsigned long count, | 4458 | struct buffer_head *bh, ext4_fsblk_t block, |
4430 | int metadata, unsigned long *freed) | 4459 | unsigned long count, int flags) |
4431 | { | 4460 | { |
4432 | struct buffer_head *bitmap_bh = NULL; | 4461 | struct buffer_head *bitmap_bh = NULL; |
4433 | struct super_block *sb = inode->i_sb; | 4462 | struct super_block *sb = inode->i_sb; |
4434 | struct ext4_allocation_context *ac = NULL; | 4463 | struct ext4_allocation_context *ac = NULL; |
4435 | struct ext4_group_desc *gdp; | 4464 | struct ext4_group_desc *gdp; |
4436 | struct ext4_super_block *es; | 4465 | struct ext4_super_block *es; |
4466 | unsigned long freed = 0; | ||
4437 | unsigned int overflow; | 4467 | unsigned int overflow; |
4438 | ext4_grpblk_t bit; | 4468 | ext4_grpblk_t bit; |
4439 | struct buffer_head *gd_bh; | 4469 | struct buffer_head *gd_bh; |
@@ -4443,13 +4473,16 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, | |||
4443 | int err = 0; | 4473 | int err = 0; |
4444 | int ret; | 4474 | int ret; |
4445 | 4475 | ||
4446 | *freed = 0; | 4476 | if (bh) { |
4477 | if (block) | ||
4478 | BUG_ON(block != bh->b_blocknr); | ||
4479 | else | ||
4480 | block = bh->b_blocknr; | ||
4481 | } | ||
4447 | 4482 | ||
4448 | sbi = EXT4_SB(sb); | 4483 | sbi = EXT4_SB(sb); |
4449 | es = EXT4_SB(sb)->s_es; | 4484 | es = EXT4_SB(sb)->s_es; |
4450 | if (block < le32_to_cpu(es->s_first_data_block) || | 4485 | if (!ext4_data_block_valid(sbi, block, count)) { |
4451 | block + count < block || | ||
4452 | block + count > ext4_blocks_count(es)) { | ||
4453 | ext4_error(sb, __func__, | 4486 | ext4_error(sb, __func__, |
4454 | "Freeing blocks not in datazone - " | 4487 | "Freeing blocks not in datazone - " |
4455 | "block = %llu, count = %lu", block, count); | 4488 | "block = %llu, count = %lu", block, count); |
@@ -4457,7 +4490,32 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, | |||
4457 | } | 4490 | } |
4458 | 4491 | ||
4459 | ext4_debug("freeing block %llu\n", block); | 4492 | ext4_debug("freeing block %llu\n", block); |
4460 | trace_ext4_free_blocks(inode, block, count, metadata); | 4493 | trace_ext4_free_blocks(inode, block, count, flags); |
4494 | |||
4495 | if (flags & EXT4_FREE_BLOCKS_FORGET) { | ||
4496 | struct buffer_head *tbh = bh; | ||
4497 | int i; | ||
4498 | |||
4499 | BUG_ON(bh && (count > 1)); | ||
4500 | |||
4501 | for (i = 0; i < count; i++) { | ||
4502 | if (!bh) | ||
4503 | tbh = sb_find_get_block(inode->i_sb, | ||
4504 | block + i); | ||
4505 | ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA, | ||
4506 | inode, tbh, block + i); | ||
4507 | } | ||
4508 | } | ||
4509 | |||
4510 | /* | ||
4511 | * We need to make sure we don't reuse the freed block until | ||
4512 | * after the transaction is committed, which we can do by | ||
4513 | * treating the block as metadata, below. We make an | ||
4514 | * exception if the inode is to be written in writeback mode | ||
4515 | * since writeback mode has weak data consistency guarantees. | ||
4516 | */ | ||
4517 | if (!ext4_should_writeback_data(inode)) | ||
4518 | flags |= EXT4_FREE_BLOCKS_METADATA; | ||
4461 | 4519 | ||
4462 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 4520 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
4463 | if (ac) { | 4521 | if (ac) { |
@@ -4533,7 +4591,8 @@ do_more: | |||
4533 | err = ext4_mb_load_buddy(sb, block_group, &e4b); | 4591 | err = ext4_mb_load_buddy(sb, block_group, &e4b); |
4534 | if (err) | 4592 | if (err) |
4535 | goto error_return; | 4593 | goto error_return; |
4536 | if (metadata && ext4_handle_valid(handle)) { | 4594 | |
4595 | if ((flags & EXT4_FREE_BLOCKS_METADATA) && ext4_handle_valid(handle)) { | ||
4537 | struct ext4_free_data *new_entry; | 4596 | struct ext4_free_data *new_entry; |
4538 | /* | 4597 | /* |
4539 | * blocks being freed are metadata. these blocks shouldn't | 4598 | * blocks being freed are metadata. these blocks shouldn't |
@@ -4572,7 +4631,7 @@ do_more: | |||
4572 | 4631 | ||
4573 | ext4_mb_release_desc(&e4b); | 4632 | ext4_mb_release_desc(&e4b); |
4574 | 4633 | ||
4575 | *freed += count; | 4634 | freed += count; |
4576 | 4635 | ||
4577 | /* We dirtied the bitmap block */ | 4636 | /* We dirtied the bitmap block */ |
4578 | BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); | 4637 | BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); |
@@ -4592,6 +4651,8 @@ do_more: | |||
4592 | } | 4651 | } |
4593 | sb->s_dirt = 1; | 4652 | sb->s_dirt = 1; |
4594 | error_return: | 4653 | error_return: |
4654 | if (freed) | ||
4655 | vfs_dq_free_block(inode, freed); | ||
4595 | brelse(bitmap_bh); | 4656 | brelse(bitmap_bh); |
4596 | ext4_std_error(sb, err); | 4657 | ext4_std_error(sb, err); |
4597 | if (ac) | 4658 | if (ac) |
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index a93d5b80f3e2..81415814b00b 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c | |||
@@ -238,7 +238,7 @@ static int extend_credit_for_blkdel(handle_t *handle, struct inode *inode) | |||
238 | * So allocate a credit of 3. We may update | 238 | * So allocate a credit of 3. We may update |
239 | * quota (user and group). | 239 | * quota (user and group). |
240 | */ | 240 | */ |
241 | needed = 3 + 2*EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); | 241 | needed = 3 + EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb); |
242 | 242 | ||
243 | if (ext4_journal_extend(handle, needed) != 0) | 243 | if (ext4_journal_extend(handle, needed) != 0) |
244 | retval = ext4_journal_restart(handle, needed); | 244 | retval = ext4_journal_restart(handle, needed); |
@@ -262,13 +262,17 @@ static int free_dind_blocks(handle_t *handle, | |||
262 | for (i = 0; i < max_entries; i++) { | 262 | for (i = 0; i < max_entries; i++) { |
263 | if (tmp_idata[i]) { | 263 | if (tmp_idata[i]) { |
264 | extend_credit_for_blkdel(handle, inode); | 264 | extend_credit_for_blkdel(handle, inode); |
265 | ext4_free_blocks(handle, inode, | 265 | ext4_free_blocks(handle, inode, 0, |
266 | le32_to_cpu(tmp_idata[i]), 1, 1); | 266 | le32_to_cpu(tmp_idata[i]), 1, |
267 | EXT4_FREE_BLOCKS_METADATA | | ||
268 | EXT4_FREE_BLOCKS_FORGET); | ||
267 | } | 269 | } |
268 | } | 270 | } |
269 | put_bh(bh); | 271 | put_bh(bh); |
270 | extend_credit_for_blkdel(handle, inode); | 272 | extend_credit_for_blkdel(handle, inode); |
271 | ext4_free_blocks(handle, inode, le32_to_cpu(i_data), 1, 1); | 273 | ext4_free_blocks(handle, inode, 0, le32_to_cpu(i_data), 1, |
274 | EXT4_FREE_BLOCKS_METADATA | | ||
275 | EXT4_FREE_BLOCKS_FORGET); | ||
272 | return 0; | 276 | return 0; |
273 | } | 277 | } |
274 | 278 | ||
@@ -297,7 +301,9 @@ static int free_tind_blocks(handle_t *handle, | |||
297 | } | 301 | } |
298 | put_bh(bh); | 302 | put_bh(bh); |
299 | extend_credit_for_blkdel(handle, inode); | 303 | extend_credit_for_blkdel(handle, inode); |
300 | ext4_free_blocks(handle, inode, le32_to_cpu(i_data), 1, 1); | 304 | ext4_free_blocks(handle, inode, 0, le32_to_cpu(i_data), 1, |
305 | EXT4_FREE_BLOCKS_METADATA | | ||
306 | EXT4_FREE_BLOCKS_FORGET); | ||
301 | return 0; | 307 | return 0; |
302 | } | 308 | } |
303 | 309 | ||
@@ -308,8 +314,10 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data) | |||
308 | /* ei->i_data[EXT4_IND_BLOCK] */ | 314 | /* ei->i_data[EXT4_IND_BLOCK] */ |
309 | if (i_data[0]) { | 315 | if (i_data[0]) { |
310 | extend_credit_for_blkdel(handle, inode); | 316 | extend_credit_for_blkdel(handle, inode); |
311 | ext4_free_blocks(handle, inode, | 317 | ext4_free_blocks(handle, inode, 0, |
312 | le32_to_cpu(i_data[0]), 1, 1); | 318 | le32_to_cpu(i_data[0]), 1, |
319 | EXT4_FREE_BLOCKS_METADATA | | ||
320 | EXT4_FREE_BLOCKS_FORGET); | ||
313 | } | 321 | } |
314 | 322 | ||
315 | /* ei->i_data[EXT4_DIND_BLOCK] */ | 323 | /* ei->i_data[EXT4_DIND_BLOCK] */ |
@@ -419,7 +427,8 @@ static int free_ext_idx(handle_t *handle, struct inode *inode, | |||
419 | } | 427 | } |
420 | put_bh(bh); | 428 | put_bh(bh); |
421 | extend_credit_for_blkdel(handle, inode); | 429 | extend_credit_for_blkdel(handle, inode); |
422 | ext4_free_blocks(handle, inode, block, 1, 1); | 430 | ext4_free_blocks(handle, inode, 0, block, 1, |
431 | EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); | ||
423 | return retval; | 432 | return retval; |
424 | } | 433 | } |
425 | 434 | ||
@@ -477,7 +486,7 @@ int ext4_ext_migrate(struct inode *inode) | |||
477 | handle = ext4_journal_start(inode, | 486 | handle = ext4_journal_start(inode, |
478 | EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + | 487 | EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + |
479 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 488 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + |
480 | 2 * EXT4_QUOTA_INIT_BLOCKS(inode->i_sb) | 489 | EXT4_MAXQUOTAS_INIT_BLOCKS(inode->i_sb) |
481 | + 1); | 490 | + 1); |
482 | if (IS_ERR(handle)) { | 491 | if (IS_ERR(handle)) { |
483 | retval = PTR_ERR(handle); | 492 | retval = PTR_ERR(handle); |
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index 25b6b1457360..82c415be87a4 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c | |||
@@ -77,12 +77,14 @@ static int | |||
77 | mext_next_extent(struct inode *inode, struct ext4_ext_path *path, | 77 | mext_next_extent(struct inode *inode, struct ext4_ext_path *path, |
78 | struct ext4_extent **extent) | 78 | struct ext4_extent **extent) |
79 | { | 79 | { |
80 | struct ext4_extent_header *eh; | ||
80 | int ppos, leaf_ppos = path->p_depth; | 81 | int ppos, leaf_ppos = path->p_depth; |
81 | 82 | ||
82 | ppos = leaf_ppos; | 83 | ppos = leaf_ppos; |
83 | if (EXT_LAST_EXTENT(path[ppos].p_hdr) > path[ppos].p_ext) { | 84 | if (EXT_LAST_EXTENT(path[ppos].p_hdr) > path[ppos].p_ext) { |
84 | /* leaf block */ | 85 | /* leaf block */ |
85 | *extent = ++path[ppos].p_ext; | 86 | *extent = ++path[ppos].p_ext; |
87 | path[ppos].p_block = ext_pblock(path[ppos].p_ext); | ||
86 | return 0; | 88 | return 0; |
87 | } | 89 | } |
88 | 90 | ||
@@ -119,9 +121,18 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path, | |||
119 | ext_block_hdr(path[cur_ppos+1].p_bh); | 121 | ext_block_hdr(path[cur_ppos+1].p_bh); |
120 | } | 122 | } |
121 | 123 | ||
124 | path[leaf_ppos].p_ext = *extent = NULL; | ||
125 | |||
126 | eh = path[leaf_ppos].p_hdr; | ||
127 | if (le16_to_cpu(eh->eh_entries) == 0) | ||
128 | /* empty leaf is found */ | ||
129 | return -ENODATA; | ||
130 | |||
122 | /* leaf block */ | 131 | /* leaf block */ |
123 | path[leaf_ppos].p_ext = *extent = | 132 | path[leaf_ppos].p_ext = *extent = |
124 | EXT_FIRST_EXTENT(path[leaf_ppos].p_hdr); | 133 | EXT_FIRST_EXTENT(path[leaf_ppos].p_hdr); |
134 | path[leaf_ppos].p_block = | ||
135 | ext_pblock(path[leaf_ppos].p_ext); | ||
125 | return 0; | 136 | return 0; |
126 | } | 137 | } |
127 | } | 138 | } |
@@ -155,40 +166,15 @@ mext_check_null_inode(struct inode *inode1, struct inode *inode2, | |||
155 | } | 166 | } |
156 | 167 | ||
157 | /** | 168 | /** |
158 | * mext_double_down_read - Acquire two inodes' read semaphore | 169 | * double_down_write_data_sem - Acquire two inodes' write lock of i_data_sem |
159 | * | ||
160 | * @orig_inode: original inode structure | ||
161 | * @donor_inode: donor inode structure | ||
162 | * Acquire read semaphore of the two inodes (orig and donor) by i_ino order. | ||
163 | */ | ||
164 | static void | ||
165 | mext_double_down_read(struct inode *orig_inode, struct inode *donor_inode) | ||
166 | { | ||
167 | struct inode *first = orig_inode, *second = donor_inode; | ||
168 | |||
169 | /* | ||
170 | * Use the inode number to provide the stable locking order instead | ||
171 | * of its address, because the C language doesn't guarantee you can | ||
172 | * compare pointers that don't come from the same array. | ||
173 | */ | ||
174 | if (donor_inode->i_ino < orig_inode->i_ino) { | ||
175 | first = donor_inode; | ||
176 | second = orig_inode; | ||
177 | } | ||
178 | |||
179 | down_read(&EXT4_I(first)->i_data_sem); | ||
180 | down_read(&EXT4_I(second)->i_data_sem); | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * mext_double_down_write - Acquire two inodes' write semaphore | ||
185 | * | 170 | * |
186 | * @orig_inode: original inode structure | 171 | * @orig_inode: original inode structure |
187 | * @donor_inode: donor inode structure | 172 | * @donor_inode: donor inode structure |
188 | * Acquire write semaphore of the two inodes (orig and donor) by i_ino order. | 173 | * Acquire write lock of i_data_sem of the two inodes (orig and donor) by |
174 | * i_ino order. | ||
189 | */ | 175 | */ |
190 | static void | 176 | static void |
191 | mext_double_down_write(struct inode *orig_inode, struct inode *donor_inode) | 177 | double_down_write_data_sem(struct inode *orig_inode, struct inode *donor_inode) |
192 | { | 178 | { |
193 | struct inode *first = orig_inode, *second = donor_inode; | 179 | struct inode *first = orig_inode, *second = donor_inode; |
194 | 180 | ||
@@ -203,32 +189,18 @@ mext_double_down_write(struct inode *orig_inode, struct inode *donor_inode) | |||
203 | } | 189 | } |
204 | 190 | ||
205 | down_write(&EXT4_I(first)->i_data_sem); | 191 | down_write(&EXT4_I(first)->i_data_sem); |
206 | down_write(&EXT4_I(second)->i_data_sem); | 192 | down_write_nested(&EXT4_I(second)->i_data_sem, SINGLE_DEPTH_NESTING); |
207 | } | 193 | } |
208 | 194 | ||
209 | /** | 195 | /** |
210 | * mext_double_up_read - Release two inodes' read semaphore | 196 | * double_up_write_data_sem - Release two inodes' write lock of i_data_sem |
211 | * | 197 | * |
212 | * @orig_inode: original inode structure to be released its lock first | 198 | * @orig_inode: original inode structure to be released its lock first |
213 | * @donor_inode: donor inode structure to be released its lock second | 199 | * @donor_inode: donor inode structure to be released its lock second |
214 | * Release read semaphore of two inodes (orig and donor). | 200 | * Release write lock of i_data_sem of two inodes (orig and donor). |
215 | */ | 201 | */ |
216 | static void | 202 | static void |
217 | mext_double_up_read(struct inode *orig_inode, struct inode *donor_inode) | 203 | double_up_write_data_sem(struct inode *orig_inode, struct inode *donor_inode) |
218 | { | ||
219 | up_read(&EXT4_I(orig_inode)->i_data_sem); | ||
220 | up_read(&EXT4_I(donor_inode)->i_data_sem); | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * mext_double_up_write - Release two inodes' write semaphore | ||
225 | * | ||
226 | * @orig_inode: original inode structure to be released its lock first | ||
227 | * @donor_inode: donor inode structure to be released its lock second | ||
228 | * Release write semaphore of two inodes (orig and donor). | ||
229 | */ | ||
230 | static void | ||
231 | mext_double_up_write(struct inode *orig_inode, struct inode *donor_inode) | ||
232 | { | 204 | { |
233 | up_write(&EXT4_I(orig_inode)->i_data_sem); | 205 | up_write(&EXT4_I(orig_inode)->i_data_sem); |
234 | up_write(&EXT4_I(donor_inode)->i_data_sem); | 206 | up_write(&EXT4_I(donor_inode)->i_data_sem); |
@@ -596,7 +568,7 @@ out: | |||
596 | * @tmp_oext: the extent that will belong to the donor inode | 568 | * @tmp_oext: the extent that will belong to the donor inode |
597 | * @orig_off: block offset of original inode | 569 | * @orig_off: block offset of original inode |
598 | * @donor_off: block offset of donor inode | 570 | * @donor_off: block offset of donor inode |
599 | * @max_count: the maximun length of extents | 571 | * @max_count: the maximum length of extents |
600 | * | 572 | * |
601 | * Return 0 on success, or a negative error value on failure. | 573 | * Return 0 on success, or a negative error value on failure. |
602 | */ | 574 | */ |
@@ -661,6 +633,7 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext, | |||
661 | * @donor_inode: donor inode | 633 | * @donor_inode: donor inode |
662 | * @from: block offset of orig_inode | 634 | * @from: block offset of orig_inode |
663 | * @count: block count to be replaced | 635 | * @count: block count to be replaced |
636 | * @err: pointer to save return value | ||
664 | * | 637 | * |
665 | * Replace original inode extents and donor inode extents page by page. | 638 | * Replace original inode extents and donor inode extents page by page. |
666 | * We implement this replacement in the following three steps: | 639 | * We implement this replacement in the following three steps: |
@@ -671,33 +644,33 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext, | |||
671 | * 3. Change the block information of donor inode to point at the saved | 644 | * 3. Change the block information of donor inode to point at the saved |
672 | * original inode blocks in the dummy extents. | 645 | * original inode blocks in the dummy extents. |
673 | * | 646 | * |
674 | * Return 0 on success, or a negative error value on failure. | 647 | * Return replaced block count. |
675 | */ | 648 | */ |
676 | static int | 649 | static int |
677 | mext_replace_branches(handle_t *handle, struct inode *orig_inode, | 650 | mext_replace_branches(handle_t *handle, struct inode *orig_inode, |
678 | struct inode *donor_inode, ext4_lblk_t from, | 651 | struct inode *donor_inode, ext4_lblk_t from, |
679 | ext4_lblk_t count) | 652 | ext4_lblk_t count, int *err) |
680 | { | 653 | { |
681 | struct ext4_ext_path *orig_path = NULL; | 654 | struct ext4_ext_path *orig_path = NULL; |
682 | struct ext4_ext_path *donor_path = NULL; | 655 | struct ext4_ext_path *donor_path = NULL; |
683 | struct ext4_extent *oext, *dext; | 656 | struct ext4_extent *oext, *dext; |
684 | struct ext4_extent tmp_dext, tmp_oext; | 657 | struct ext4_extent tmp_dext, tmp_oext; |
685 | ext4_lblk_t orig_off = from, donor_off = from; | 658 | ext4_lblk_t orig_off = from, donor_off = from; |
686 | int err = 0; | ||
687 | int depth; | 659 | int depth; |
688 | int replaced_count = 0; | 660 | int replaced_count = 0; |
689 | int dext_alen; | 661 | int dext_alen; |
690 | 662 | ||
691 | mext_double_down_write(orig_inode, donor_inode); | 663 | /* Protect extent trees against block allocations via delalloc */ |
664 | double_down_write_data_sem(orig_inode, donor_inode); | ||
692 | 665 | ||
693 | /* Get the original extent for the block "orig_off" */ | 666 | /* Get the original extent for the block "orig_off" */ |
694 | err = get_ext_path(orig_inode, orig_off, &orig_path); | 667 | *err = get_ext_path(orig_inode, orig_off, &orig_path); |
695 | if (err) | 668 | if (*err) |
696 | goto out; | 669 | goto out; |
697 | 670 | ||
698 | /* Get the donor extent for the head */ | 671 | /* Get the donor extent for the head */ |
699 | err = get_ext_path(donor_inode, donor_off, &donor_path); | 672 | *err = get_ext_path(donor_inode, donor_off, &donor_path); |
700 | if (err) | 673 | if (*err) |
701 | goto out; | 674 | goto out; |
702 | depth = ext_depth(orig_inode); | 675 | depth = ext_depth(orig_inode); |
703 | oext = orig_path[depth].p_ext; | 676 | oext = orig_path[depth].p_ext; |
@@ -707,9 +680,9 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
707 | dext = donor_path[depth].p_ext; | 680 | dext = donor_path[depth].p_ext; |
708 | tmp_dext = *dext; | 681 | tmp_dext = *dext; |
709 | 682 | ||
710 | err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, | 683 | *err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, |
711 | donor_off, count); | 684 | donor_off, count); |
712 | if (err) | 685 | if (*err) |
713 | goto out; | 686 | goto out; |
714 | 687 | ||
715 | /* Loop for the donor extents */ | 688 | /* Loop for the donor extents */ |
@@ -718,7 +691,7 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
718 | if (!dext) { | 691 | if (!dext) { |
719 | ext4_error(donor_inode->i_sb, __func__, | 692 | ext4_error(donor_inode->i_sb, __func__, |
720 | "The extent for donor must be found"); | 693 | "The extent for donor must be found"); |
721 | err = -EIO; | 694 | *err = -EIO; |
722 | goto out; | 695 | goto out; |
723 | } else if (donor_off != le32_to_cpu(tmp_dext.ee_block)) { | 696 | } else if (donor_off != le32_to_cpu(tmp_dext.ee_block)) { |
724 | ext4_error(donor_inode->i_sb, __func__, | 697 | ext4_error(donor_inode->i_sb, __func__, |
@@ -726,20 +699,20 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
726 | "extent(%u) should be equal", | 699 | "extent(%u) should be equal", |
727 | donor_off, | 700 | donor_off, |
728 | le32_to_cpu(tmp_dext.ee_block)); | 701 | le32_to_cpu(tmp_dext.ee_block)); |
729 | err = -EIO; | 702 | *err = -EIO; |
730 | goto out; | 703 | goto out; |
731 | } | 704 | } |
732 | 705 | ||
733 | /* Set donor extent to orig extent */ | 706 | /* Set donor extent to orig extent */ |
734 | err = mext_leaf_block(handle, orig_inode, | 707 | *err = mext_leaf_block(handle, orig_inode, |
735 | orig_path, &tmp_dext, &orig_off); | 708 | orig_path, &tmp_dext, &orig_off); |
736 | if (err < 0) | 709 | if (*err) |
737 | goto out; | 710 | goto out; |
738 | 711 | ||
739 | /* Set orig extent to donor extent */ | 712 | /* Set orig extent to donor extent */ |
740 | err = mext_leaf_block(handle, donor_inode, | 713 | *err = mext_leaf_block(handle, donor_inode, |
741 | donor_path, &tmp_oext, &donor_off); | 714 | donor_path, &tmp_oext, &donor_off); |
742 | if (err < 0) | 715 | if (*err) |
743 | goto out; | 716 | goto out; |
744 | 717 | ||
745 | dext_alen = ext4_ext_get_actual_len(&tmp_dext); | 718 | dext_alen = ext4_ext_get_actual_len(&tmp_dext); |
@@ -753,35 +726,25 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
753 | 726 | ||
754 | if (orig_path) | 727 | if (orig_path) |
755 | ext4_ext_drop_refs(orig_path); | 728 | ext4_ext_drop_refs(orig_path); |
756 | err = get_ext_path(orig_inode, orig_off, &orig_path); | 729 | *err = get_ext_path(orig_inode, orig_off, &orig_path); |
757 | if (err) | 730 | if (*err) |
758 | goto out; | 731 | goto out; |
759 | depth = ext_depth(orig_inode); | 732 | depth = ext_depth(orig_inode); |
760 | oext = orig_path[depth].p_ext; | 733 | oext = orig_path[depth].p_ext; |
761 | if (le32_to_cpu(oext->ee_block) + | ||
762 | ext4_ext_get_actual_len(oext) <= orig_off) { | ||
763 | err = 0; | ||
764 | goto out; | ||
765 | } | ||
766 | tmp_oext = *oext; | 734 | tmp_oext = *oext; |
767 | 735 | ||
768 | if (donor_path) | 736 | if (donor_path) |
769 | ext4_ext_drop_refs(donor_path); | 737 | ext4_ext_drop_refs(donor_path); |
770 | err = get_ext_path(donor_inode, donor_off, &donor_path); | 738 | *err = get_ext_path(donor_inode, donor_off, &donor_path); |
771 | if (err) | 739 | if (*err) |
772 | goto out; | 740 | goto out; |
773 | depth = ext_depth(donor_inode); | 741 | depth = ext_depth(donor_inode); |
774 | dext = donor_path[depth].p_ext; | 742 | dext = donor_path[depth].p_ext; |
775 | if (le32_to_cpu(dext->ee_block) + | ||
776 | ext4_ext_get_actual_len(dext) <= donor_off) { | ||
777 | err = 0; | ||
778 | goto out; | ||
779 | } | ||
780 | tmp_dext = *dext; | 743 | tmp_dext = *dext; |
781 | 744 | ||
782 | err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, | 745 | *err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, |
783 | donor_off, count - replaced_count); | 746 | donor_off, count - replaced_count); |
784 | if (err) | 747 | if (*err) |
785 | goto out; | 748 | goto out; |
786 | } | 749 | } |
787 | 750 | ||
@@ -795,8 +758,12 @@ out: | |||
795 | kfree(donor_path); | 758 | kfree(donor_path); |
796 | } | 759 | } |
797 | 760 | ||
798 | mext_double_up_write(orig_inode, donor_inode); | 761 | ext4_ext_invalidate_cache(orig_inode); |
799 | return err; | 762 | ext4_ext_invalidate_cache(donor_inode); |
763 | |||
764 | double_up_write_data_sem(orig_inode, donor_inode); | ||
765 | |||
766 | return replaced_count; | ||
800 | } | 767 | } |
801 | 768 | ||
802 | /** | 769 | /** |
@@ -808,16 +775,17 @@ out: | |||
808 | * @data_offset_in_page: block index where data swapping starts | 775 | * @data_offset_in_page: block index where data swapping starts |
809 | * @block_len_in_page: the number of blocks to be swapped | 776 | * @block_len_in_page: the number of blocks to be swapped |
810 | * @uninit: orig extent is uninitialized or not | 777 | * @uninit: orig extent is uninitialized or not |
778 | * @err: pointer to save return value | ||
811 | * | 779 | * |
812 | * Save the data in original inode blocks and replace original inode extents | 780 | * Save the data in original inode blocks and replace original inode extents |
813 | * with donor inode extents by calling mext_replace_branches(). | 781 | * with donor inode extents by calling mext_replace_branches(). |
814 | * Finally, write out the saved data in new original inode blocks. Return 0 | 782 | * Finally, write out the saved data in new original inode blocks. Return |
815 | * on success, or a negative error value on failure. | 783 | * replaced block count. |
816 | */ | 784 | */ |
817 | static int | 785 | static int |
818 | move_extent_per_page(struct file *o_filp, struct inode *donor_inode, | 786 | move_extent_per_page(struct file *o_filp, struct inode *donor_inode, |
819 | pgoff_t orig_page_offset, int data_offset_in_page, | 787 | pgoff_t orig_page_offset, int data_offset_in_page, |
820 | int block_len_in_page, int uninit) | 788 | int block_len_in_page, int uninit, int *err) |
821 | { | 789 | { |
822 | struct inode *orig_inode = o_filp->f_dentry->d_inode; | 790 | struct inode *orig_inode = o_filp->f_dentry->d_inode; |
823 | struct address_space *mapping = orig_inode->i_mapping; | 791 | struct address_space *mapping = orig_inode->i_mapping; |
@@ -829,9 +797,11 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, | |||
829 | long long offs = orig_page_offset << PAGE_CACHE_SHIFT; | 797 | long long offs = orig_page_offset << PAGE_CACHE_SHIFT; |
830 | unsigned long blocksize = orig_inode->i_sb->s_blocksize; | 798 | unsigned long blocksize = orig_inode->i_sb->s_blocksize; |
831 | unsigned int w_flags = 0; | 799 | unsigned int w_flags = 0; |
832 | unsigned int tmp_data_len, data_len; | 800 | unsigned int tmp_data_size, data_size, replaced_size; |
833 | void *fsdata; | 801 | void *fsdata; |
834 | int ret, i, jblocks; | 802 | int i, jblocks; |
803 | int err2 = 0; | ||
804 | int replaced_count = 0; | ||
835 | int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; | 805 | int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; |
836 | 806 | ||
837 | /* | 807 | /* |
@@ -841,8 +811,8 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, | |||
841 | jblocks = ext4_writepage_trans_blocks(orig_inode) * 2; | 811 | jblocks = ext4_writepage_trans_blocks(orig_inode) * 2; |
842 | handle = ext4_journal_start(orig_inode, jblocks); | 812 | handle = ext4_journal_start(orig_inode, jblocks); |
843 | if (IS_ERR(handle)) { | 813 | if (IS_ERR(handle)) { |
844 | ret = PTR_ERR(handle); | 814 | *err = PTR_ERR(handle); |
845 | return ret; | 815 | return 0; |
846 | } | 816 | } |
847 | 817 | ||
848 | if (segment_eq(get_fs(), KERNEL_DS)) | 818 | if (segment_eq(get_fs(), KERNEL_DS)) |
@@ -858,39 +828,36 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, | |||
858 | * Just swap data blocks between orig and donor. | 828 | * Just swap data blocks between orig and donor. |
859 | */ | 829 | */ |
860 | if (uninit) { | 830 | if (uninit) { |
861 | ret = mext_replace_branches(handle, orig_inode, | 831 | replaced_count = mext_replace_branches(handle, orig_inode, |
862 | donor_inode, orig_blk_offset, | 832 | donor_inode, orig_blk_offset, |
863 | block_len_in_page); | 833 | block_len_in_page, err); |
864 | |||
865 | /* Clear the inode cache not to refer to the old data */ | ||
866 | ext4_ext_invalidate_cache(orig_inode); | ||
867 | ext4_ext_invalidate_cache(donor_inode); | ||
868 | goto out2; | 834 | goto out2; |
869 | } | 835 | } |
870 | 836 | ||
871 | offs = (long long)orig_blk_offset << orig_inode->i_blkbits; | 837 | offs = (long long)orig_blk_offset << orig_inode->i_blkbits; |
872 | 838 | ||
873 | /* Calculate data_len */ | 839 | /* Calculate data_size */ |
874 | if ((orig_blk_offset + block_len_in_page - 1) == | 840 | if ((orig_blk_offset + block_len_in_page - 1) == |
875 | ((orig_inode->i_size - 1) >> orig_inode->i_blkbits)) { | 841 | ((orig_inode->i_size - 1) >> orig_inode->i_blkbits)) { |
876 | /* Replace the last block */ | 842 | /* Replace the last block */ |
877 | tmp_data_len = orig_inode->i_size & (blocksize - 1); | 843 | tmp_data_size = orig_inode->i_size & (blocksize - 1); |
878 | /* | 844 | /* |
879 | * If data_len equal zero, it shows data_len is multiples of | 845 | * If data_size equal zero, it shows data_size is multiples of |
880 | * blocksize. So we set appropriate value. | 846 | * blocksize. So we set appropriate value. |
881 | */ | 847 | */ |
882 | if (tmp_data_len == 0) | 848 | if (tmp_data_size == 0) |
883 | tmp_data_len = blocksize; | 849 | tmp_data_size = blocksize; |
884 | 850 | ||
885 | data_len = tmp_data_len + | 851 | data_size = tmp_data_size + |
886 | ((block_len_in_page - 1) << orig_inode->i_blkbits); | 852 | ((block_len_in_page - 1) << orig_inode->i_blkbits); |
887 | } else { | 853 | } else |
888 | data_len = block_len_in_page << orig_inode->i_blkbits; | 854 | data_size = block_len_in_page << orig_inode->i_blkbits; |
889 | } | 855 | |
856 | replaced_size = data_size; | ||
890 | 857 | ||
891 | ret = a_ops->write_begin(o_filp, mapping, offs, data_len, w_flags, | 858 | *err = a_ops->write_begin(o_filp, mapping, offs, data_size, w_flags, |
892 | &page, &fsdata); | 859 | &page, &fsdata); |
893 | if (unlikely(ret < 0)) | 860 | if (unlikely(*err < 0)) |
894 | goto out; | 861 | goto out; |
895 | 862 | ||
896 | if (!PageUptodate(page)) { | 863 | if (!PageUptodate(page)) { |
@@ -911,14 +878,17 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, | |||
911 | /* Release old bh and drop refs */ | 878 | /* Release old bh and drop refs */ |
912 | try_to_release_page(page, 0); | 879 | try_to_release_page(page, 0); |
913 | 880 | ||
914 | ret = mext_replace_branches(handle, orig_inode, donor_inode, | 881 | replaced_count = mext_replace_branches(handle, orig_inode, donor_inode, |
915 | orig_blk_offset, block_len_in_page); | 882 | orig_blk_offset, block_len_in_page, |
916 | if (ret < 0) | 883 | &err2); |
917 | goto out; | 884 | if (err2) { |
918 | 885 | if (replaced_count) { | |
919 | /* Clear the inode cache not to refer to the old data */ | 886 | block_len_in_page = replaced_count; |
920 | ext4_ext_invalidate_cache(orig_inode); | 887 | replaced_size = |
921 | ext4_ext_invalidate_cache(donor_inode); | 888 | block_len_in_page << orig_inode->i_blkbits; |
889 | } else | ||
890 | goto out; | ||
891 | } | ||
922 | 892 | ||
923 | if (!page_has_buffers(page)) | 893 | if (!page_has_buffers(page)) |
924 | create_empty_buffers(page, 1 << orig_inode->i_blkbits, 0); | 894 | create_empty_buffers(page, 1 << orig_inode->i_blkbits, 0); |
@@ -928,16 +898,16 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, | |||
928 | bh = bh->b_this_page; | 898 | bh = bh->b_this_page; |
929 | 899 | ||
930 | for (i = 0; i < block_len_in_page; i++) { | 900 | for (i = 0; i < block_len_in_page; i++) { |
931 | ret = ext4_get_block(orig_inode, | 901 | *err = ext4_get_block(orig_inode, |
932 | (sector_t)(orig_blk_offset + i), bh, 0); | 902 | (sector_t)(orig_blk_offset + i), bh, 0); |
933 | if (ret < 0) | 903 | if (*err < 0) |
934 | goto out; | 904 | goto out; |
935 | 905 | ||
936 | if (bh->b_this_page != NULL) | 906 | if (bh->b_this_page != NULL) |
937 | bh = bh->b_this_page; | 907 | bh = bh->b_this_page; |
938 | } | 908 | } |
939 | 909 | ||
940 | ret = a_ops->write_end(o_filp, mapping, offs, data_len, data_len, | 910 | *err = a_ops->write_end(o_filp, mapping, offs, data_size, replaced_size, |
941 | page, fsdata); | 911 | page, fsdata); |
942 | page = NULL; | 912 | page = NULL; |
943 | 913 | ||
@@ -951,7 +921,10 @@ out: | |||
951 | out2: | 921 | out2: |
952 | ext4_journal_stop(handle); | 922 | ext4_journal_stop(handle); |
953 | 923 | ||
954 | return ret < 0 ? ret : 0; | 924 | if (err2) |
925 | *err = err2; | ||
926 | |||
927 | return replaced_count; | ||
955 | } | 928 | } |
956 | 929 | ||
957 | /** | 930 | /** |
@@ -962,7 +935,6 @@ out2: | |||
962 | * @orig_start: logical start offset in block for orig | 935 | * @orig_start: logical start offset in block for orig |
963 | * @donor_start: logical start offset in block for donor | 936 | * @donor_start: logical start offset in block for donor |
964 | * @len: the number of blocks to be moved | 937 | * @len: the number of blocks to be moved |
965 | * @moved_len: moved block length | ||
966 | * | 938 | * |
967 | * Check the arguments of ext4_move_extents() whether the files can be | 939 | * Check the arguments of ext4_move_extents() whether the files can be |
968 | * exchanged with each other. | 940 | * exchanged with each other. |
@@ -970,8 +942,8 @@ out2: | |||
970 | */ | 942 | */ |
971 | static int | 943 | static int |
972 | mext_check_arguments(struct inode *orig_inode, | 944 | mext_check_arguments(struct inode *orig_inode, |
973 | struct inode *donor_inode, __u64 orig_start, | 945 | struct inode *donor_inode, __u64 orig_start, |
974 | __u64 donor_start, __u64 *len, __u64 moved_len) | 946 | __u64 donor_start, __u64 *len) |
975 | { | 947 | { |
976 | ext4_lblk_t orig_blocks, donor_blocks; | 948 | ext4_lblk_t orig_blocks, donor_blocks; |
977 | unsigned int blkbits = orig_inode->i_blkbits; | 949 | unsigned int blkbits = orig_inode->i_blkbits; |
@@ -985,6 +957,13 @@ mext_check_arguments(struct inode *orig_inode, | |||
985 | return -EINVAL; | 957 | return -EINVAL; |
986 | } | 958 | } |
987 | 959 | ||
960 | if (donor_inode->i_mode & (S_ISUID|S_ISGID)) { | ||
961 | ext4_debug("ext4 move extent: suid or sgid is set" | ||
962 | " to donor file [ino:orig %lu, donor %lu]\n", | ||
963 | orig_inode->i_ino, donor_inode->i_ino); | ||
964 | return -EINVAL; | ||
965 | } | ||
966 | |||
988 | /* Ext4 move extent does not support swapfile */ | 967 | /* Ext4 move extent does not support swapfile */ |
989 | if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) { | 968 | if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) { |
990 | ext4_debug("ext4 move extent: The argument files should " | 969 | ext4_debug("ext4 move extent: The argument files should " |
@@ -1025,13 +1004,6 @@ mext_check_arguments(struct inode *orig_inode, | |||
1025 | return -EINVAL; | 1004 | return -EINVAL; |
1026 | } | 1005 | } |
1027 | 1006 | ||
1028 | if (moved_len) { | ||
1029 | ext4_debug("ext4 move extent: moved_len should be 0 " | ||
1030 | "[ino:orig %lu, donor %lu]\n", orig_inode->i_ino, | ||
1031 | donor_inode->i_ino); | ||
1032 | return -EINVAL; | ||
1033 | } | ||
1034 | |||
1035 | if ((orig_start > EXT_MAX_BLOCK) || | 1007 | if ((orig_start > EXT_MAX_BLOCK) || |
1036 | (donor_start > EXT_MAX_BLOCK) || | 1008 | (donor_start > EXT_MAX_BLOCK) || |
1037 | (*len > EXT_MAX_BLOCK) || | 1009 | (*len > EXT_MAX_BLOCK) || |
@@ -1088,7 +1060,7 @@ mext_check_arguments(struct inode *orig_inode, | |||
1088 | } | 1060 | } |
1089 | 1061 | ||
1090 | if (!*len) { | 1062 | if (!*len) { |
1091 | ext4_debug("ext4 move extent: len shoudld not be 0 " | 1063 | ext4_debug("ext4 move extent: len should not be 0 " |
1092 | "[ino:orig %lu, donor %lu]\n", orig_inode->i_ino, | 1064 | "[ino:orig %lu, donor %lu]\n", orig_inode->i_ino, |
1093 | donor_inode->i_ino); | 1065 | donor_inode->i_ino); |
1094 | return -EINVAL; | 1066 | return -EINVAL; |
@@ -1232,16 +1204,16 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1232 | return -EINVAL; | 1204 | return -EINVAL; |
1233 | } | 1205 | } |
1234 | 1206 | ||
1235 | /* protect orig and donor against a truncate */ | 1207 | /* Protect orig and donor inodes against a truncate */ |
1236 | ret1 = mext_inode_double_lock(orig_inode, donor_inode); | 1208 | ret1 = mext_inode_double_lock(orig_inode, donor_inode); |
1237 | if (ret1 < 0) | 1209 | if (ret1 < 0) |
1238 | return ret1; | 1210 | return ret1; |
1239 | 1211 | ||
1240 | mext_double_down_read(orig_inode, donor_inode); | 1212 | /* Protect extent tree against block allocations via delalloc */ |
1213 | double_down_write_data_sem(orig_inode, donor_inode); | ||
1241 | /* Check the filesystem environment whether move_extent can be done */ | 1214 | /* Check the filesystem environment whether move_extent can be done */ |
1242 | ret1 = mext_check_arguments(orig_inode, donor_inode, orig_start, | 1215 | ret1 = mext_check_arguments(orig_inode, donor_inode, orig_start, |
1243 | donor_start, &len, *moved_len); | 1216 | donor_start, &len); |
1244 | mext_double_up_read(orig_inode, donor_inode); | ||
1245 | if (ret1) | 1217 | if (ret1) |
1246 | goto out; | 1218 | goto out; |
1247 | 1219 | ||
@@ -1355,36 +1327,39 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1355 | seq_start = le32_to_cpu(ext_cur->ee_block); | 1327 | seq_start = le32_to_cpu(ext_cur->ee_block); |
1356 | rest_blocks = seq_blocks; | 1328 | rest_blocks = seq_blocks; |
1357 | 1329 | ||
1358 | /* Discard preallocations of two inodes */ | 1330 | /* |
1359 | down_write(&EXT4_I(orig_inode)->i_data_sem); | 1331 | * Up semaphore to avoid following problems: |
1360 | ext4_discard_preallocations(orig_inode); | 1332 | * a. transaction deadlock among ext4_journal_start, |
1361 | up_write(&EXT4_I(orig_inode)->i_data_sem); | 1333 | * ->write_begin via pagefault, and jbd2_journal_commit |
1362 | 1334 | * b. racing with ->readpage, ->write_begin, and ext4_get_block | |
1363 | down_write(&EXT4_I(donor_inode)->i_data_sem); | 1335 | * in move_extent_per_page |
1364 | ext4_discard_preallocations(donor_inode); | 1336 | */ |
1365 | up_write(&EXT4_I(donor_inode)->i_data_sem); | 1337 | double_up_write_data_sem(orig_inode, donor_inode); |
1366 | 1338 | ||
1367 | while (orig_page_offset <= seq_end_page) { | 1339 | while (orig_page_offset <= seq_end_page) { |
1368 | 1340 | ||
1369 | /* Swap original branches with new branches */ | 1341 | /* Swap original branches with new branches */ |
1370 | ret1 = move_extent_per_page(o_filp, donor_inode, | 1342 | block_len_in_page = move_extent_per_page( |
1343 | o_filp, donor_inode, | ||
1371 | orig_page_offset, | 1344 | orig_page_offset, |
1372 | data_offset_in_page, | 1345 | data_offset_in_page, |
1373 | block_len_in_page, uninit); | 1346 | block_len_in_page, uninit, |
1374 | if (ret1 < 0) | 1347 | &ret1); |
1375 | goto out; | 1348 | |
1376 | orig_page_offset++; | ||
1377 | /* Count how many blocks we have exchanged */ | 1349 | /* Count how many blocks we have exchanged */ |
1378 | *moved_len += block_len_in_page; | 1350 | *moved_len += block_len_in_page; |
1351 | if (ret1 < 0) | ||
1352 | break; | ||
1379 | if (*moved_len > len) { | 1353 | if (*moved_len > len) { |
1380 | ext4_error(orig_inode->i_sb, __func__, | 1354 | ext4_error(orig_inode->i_sb, __func__, |
1381 | "We replaced blocks too much! " | 1355 | "We replaced blocks too much! " |
1382 | "sum of replaced: %llu requested: %llu", | 1356 | "sum of replaced: %llu requested: %llu", |
1383 | *moved_len, len); | 1357 | *moved_len, len); |
1384 | ret1 = -EIO; | 1358 | ret1 = -EIO; |
1385 | goto out; | 1359 | break; |
1386 | } | 1360 | } |
1387 | 1361 | ||
1362 | orig_page_offset++; | ||
1388 | data_offset_in_page = 0; | 1363 | data_offset_in_page = 0; |
1389 | rest_blocks -= block_len_in_page; | 1364 | rest_blocks -= block_len_in_page; |
1390 | if (rest_blocks > blocks_per_page) | 1365 | if (rest_blocks > blocks_per_page) |
@@ -1393,6 +1368,10 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1393 | block_len_in_page = rest_blocks; | 1368 | block_len_in_page = rest_blocks; |
1394 | } | 1369 | } |
1395 | 1370 | ||
1371 | double_down_write_data_sem(orig_inode, donor_inode); | ||
1372 | if (ret1 < 0) | ||
1373 | break; | ||
1374 | |||
1396 | /* Decrease buffer counter */ | 1375 | /* Decrease buffer counter */ |
1397 | if (holecheck_path) | 1376 | if (holecheck_path) |
1398 | ext4_ext_drop_refs(holecheck_path); | 1377 | ext4_ext_drop_refs(holecheck_path); |
@@ -1414,6 +1393,11 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
1414 | 1393 | ||
1415 | } | 1394 | } |
1416 | out: | 1395 | out: |
1396 | if (*moved_len) { | ||
1397 | ext4_discard_preallocations(orig_inode); | ||
1398 | ext4_discard_preallocations(donor_inode); | ||
1399 | } | ||
1400 | |||
1417 | if (orig_path) { | 1401 | if (orig_path) { |
1418 | ext4_ext_drop_refs(orig_path); | 1402 | ext4_ext_drop_refs(orig_path); |
1419 | kfree(orig_path); | 1403 | kfree(orig_path); |
@@ -1422,7 +1406,7 @@ out: | |||
1422 | ext4_ext_drop_refs(holecheck_path); | 1406 | ext4_ext_drop_refs(holecheck_path); |
1423 | kfree(holecheck_path); | 1407 | kfree(holecheck_path); |
1424 | } | 1408 | } |
1425 | 1409 | double_up_write_data_sem(orig_inode, donor_inode); | |
1426 | ret2 = mext_inode_double_unlock(orig_inode, donor_inode); | 1410 | ret2 = mext_inode_double_unlock(orig_inode, donor_inode); |
1427 | 1411 | ||
1428 | if (ret1) | 1412 | if (ret1) |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 6d2c1b897fc7..17a17e10dd60 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -1292,9 +1292,6 @@ errout: | |||
1292 | * add_dirent_to_buf will attempt search the directory block for | 1292 | * add_dirent_to_buf will attempt search the directory block for |
1293 | * space. It will return -ENOSPC if no space is available, and -EIO | 1293 | * space. It will return -ENOSPC if no space is available, and -EIO |
1294 | * and -EEXIST if directory entry already exists. | 1294 | * and -EEXIST if directory entry already exists. |
1295 | * | ||
1296 | * NOTE! bh is NOT released in the case where ENOSPC is returned. In | ||
1297 | * all other cases bh is released. | ||
1298 | */ | 1295 | */ |
1299 | static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | 1296 | static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, |
1300 | struct inode *inode, struct ext4_dir_entry_2 *de, | 1297 | struct inode *inode, struct ext4_dir_entry_2 *de, |
@@ -1315,14 +1312,10 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1315 | top = bh->b_data + blocksize - reclen; | 1312 | top = bh->b_data + blocksize - reclen; |
1316 | while ((char *) de <= top) { | 1313 | while ((char *) de <= top) { |
1317 | if (!ext4_check_dir_entry("ext4_add_entry", dir, de, | 1314 | if (!ext4_check_dir_entry("ext4_add_entry", dir, de, |
1318 | bh, offset)) { | 1315 | bh, offset)) |
1319 | brelse(bh); | ||
1320 | return -EIO; | 1316 | return -EIO; |
1321 | } | 1317 | if (ext4_match(namelen, name, de)) |
1322 | if (ext4_match(namelen, name, de)) { | ||
1323 | brelse(bh); | ||
1324 | return -EEXIST; | 1318 | return -EEXIST; |
1325 | } | ||
1326 | nlen = EXT4_DIR_REC_LEN(de->name_len); | 1319 | nlen = EXT4_DIR_REC_LEN(de->name_len); |
1327 | rlen = ext4_rec_len_from_disk(de->rec_len, blocksize); | 1320 | rlen = ext4_rec_len_from_disk(de->rec_len, blocksize); |
1328 | if ((de->inode? rlen - nlen: rlen) >= reclen) | 1321 | if ((de->inode? rlen - nlen: rlen) >= reclen) |
@@ -1337,7 +1330,6 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1337 | err = ext4_journal_get_write_access(handle, bh); | 1330 | err = ext4_journal_get_write_access(handle, bh); |
1338 | if (err) { | 1331 | if (err) { |
1339 | ext4_std_error(dir->i_sb, err); | 1332 | ext4_std_error(dir->i_sb, err); |
1340 | brelse(bh); | ||
1341 | return err; | 1333 | return err; |
1342 | } | 1334 | } |
1343 | 1335 | ||
@@ -1377,7 +1369,6 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1377 | err = ext4_handle_dirty_metadata(handle, dir, bh); | 1369 | err = ext4_handle_dirty_metadata(handle, dir, bh); |
1378 | if (err) | 1370 | if (err) |
1379 | ext4_std_error(dir->i_sb, err); | 1371 | ext4_std_error(dir->i_sb, err); |
1380 | brelse(bh); | ||
1381 | return 0; | 1372 | return 0; |
1382 | } | 1373 | } |
1383 | 1374 | ||
@@ -1471,7 +1462,9 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1471 | if (!(de)) | 1462 | if (!(de)) |
1472 | return retval; | 1463 | return retval; |
1473 | 1464 | ||
1474 | return add_dirent_to_buf(handle, dentry, inode, de, bh); | 1465 | retval = add_dirent_to_buf(handle, dentry, inode, de, bh); |
1466 | brelse(bh); | ||
1467 | return retval; | ||
1475 | } | 1468 | } |
1476 | 1469 | ||
1477 | /* | 1470 | /* |
@@ -1514,8 +1507,10 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1514 | if(!bh) | 1507 | if(!bh) |
1515 | return retval; | 1508 | return retval; |
1516 | retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); | 1509 | retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); |
1517 | if (retval != -ENOSPC) | 1510 | if (retval != -ENOSPC) { |
1511 | brelse(bh); | ||
1518 | return retval; | 1512 | return retval; |
1513 | } | ||
1519 | 1514 | ||
1520 | if (blocks == 1 && !dx_fallback && | 1515 | if (blocks == 1 && !dx_fallback && |
1521 | EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) | 1516 | EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) |
@@ -1528,7 +1523,9 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1528 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 1523 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1529 | de->inode = 0; | 1524 | de->inode = 0; |
1530 | de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize); | 1525 | de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize); |
1531 | return add_dirent_to_buf(handle, dentry, inode, de, bh); | 1526 | retval = add_dirent_to_buf(handle, dentry, inode, de, bh); |
1527 | brelse(bh); | ||
1528 | return retval; | ||
1532 | } | 1529 | } |
1533 | 1530 | ||
1534 | /* | 1531 | /* |
@@ -1561,10 +1558,8 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1561 | goto journal_error; | 1558 | goto journal_error; |
1562 | 1559 | ||
1563 | err = add_dirent_to_buf(handle, dentry, inode, NULL, bh); | 1560 | err = add_dirent_to_buf(handle, dentry, inode, NULL, bh); |
1564 | if (err != -ENOSPC) { | 1561 | if (err != -ENOSPC) |
1565 | bh = NULL; | ||
1566 | goto cleanup; | 1562 | goto cleanup; |
1567 | } | ||
1568 | 1563 | ||
1569 | /* Block full, should compress but for now just split */ | 1564 | /* Block full, should compress but for now just split */ |
1570 | dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n", | 1565 | dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n", |
@@ -1657,7 +1652,6 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1657 | if (!de) | 1652 | if (!de) |
1658 | goto cleanup; | 1653 | goto cleanup; |
1659 | err = add_dirent_to_buf(handle, dentry, inode, de, bh); | 1654 | err = add_dirent_to_buf(handle, dentry, inode, de, bh); |
1660 | bh = NULL; | ||
1661 | goto cleanup; | 1655 | goto cleanup; |
1662 | 1656 | ||
1663 | journal_error: | 1657 | journal_error: |
@@ -1775,7 +1769,7 @@ static int ext4_create(struct inode *dir, struct dentry *dentry, int mode, | |||
1775 | retry: | 1769 | retry: |
1776 | handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | 1770 | handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + |
1777 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 1771 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + |
1778 | 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb)); | 1772 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); |
1779 | if (IS_ERR(handle)) | 1773 | if (IS_ERR(handle)) |
1780 | return PTR_ERR(handle); | 1774 | return PTR_ERR(handle); |
1781 | 1775 | ||
@@ -1809,7 +1803,7 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry, | |||
1809 | retry: | 1803 | retry: |
1810 | handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | 1804 | handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + |
1811 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 1805 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + |
1812 | 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb)); | 1806 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); |
1813 | if (IS_ERR(handle)) | 1807 | if (IS_ERR(handle)) |
1814 | return PTR_ERR(handle); | 1808 | return PTR_ERR(handle); |
1815 | 1809 | ||
@@ -1846,7 +1840,7 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1846 | retry: | 1840 | retry: |
1847 | handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | 1841 | handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + |
1848 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 1842 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + |
1849 | 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb)); | 1843 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); |
1850 | if (IS_ERR(handle)) | 1844 | if (IS_ERR(handle)) |
1851 | return PTR_ERR(handle); | 1845 | return PTR_ERR(handle); |
1852 | 1846 | ||
@@ -2259,7 +2253,7 @@ static int ext4_symlink(struct inode *dir, | |||
2259 | retry: | 2253 | retry: |
2260 | handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | 2254 | handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + |
2261 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 5 + | 2255 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 5 + |
2262 | 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb)); | 2256 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); |
2263 | if (IS_ERR(handle)) | 2257 | if (IS_ERR(handle)) |
2264 | return PTR_ERR(handle); | 2258 | return PTR_ERR(handle); |
2265 | 2259 | ||
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 3cfc343c41b5..3b2c5541d8a6 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
@@ -247,7 +247,7 @@ static int setup_new_group_blocks(struct super_block *sb, | |||
247 | goto exit_bh; | 247 | goto exit_bh; |
248 | 248 | ||
249 | if (IS_ERR(gdb = bclean(handle, sb, block))) { | 249 | if (IS_ERR(gdb = bclean(handle, sb, block))) { |
250 | err = PTR_ERR(bh); | 250 | err = PTR_ERR(gdb); |
251 | goto exit_bh; | 251 | goto exit_bh; |
252 | } | 252 | } |
253 | ext4_handle_dirty_metadata(handle, NULL, gdb); | 253 | ext4_handle_dirty_metadata(handle, NULL, gdb); |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index d4ca92aab514..8b58a144c31b 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -603,10 +603,6 @@ static void ext4_put_super(struct super_block *sb) | |||
603 | if (sb->s_dirt) | 603 | if (sb->s_dirt) |
604 | ext4_commit_super(sb, 1); | 604 | ext4_commit_super(sb, 1); |
605 | 605 | ||
606 | ext4_release_system_zone(sb); | ||
607 | ext4_mb_release(sb); | ||
608 | ext4_ext_release(sb); | ||
609 | ext4_xattr_put_super(sb); | ||
610 | if (sbi->s_journal) { | 606 | if (sbi->s_journal) { |
611 | err = jbd2_journal_destroy(sbi->s_journal); | 607 | err = jbd2_journal_destroy(sbi->s_journal); |
612 | sbi->s_journal = NULL; | 608 | sbi->s_journal = NULL; |
@@ -614,6 +610,12 @@ static void ext4_put_super(struct super_block *sb) | |||
614 | ext4_abort(sb, __func__, | 610 | ext4_abort(sb, __func__, |
615 | "Couldn't clean up the journal"); | 611 | "Couldn't clean up the journal"); |
616 | } | 612 | } |
613 | |||
614 | ext4_release_system_zone(sb); | ||
615 | ext4_mb_release(sb); | ||
616 | ext4_ext_release(sb); | ||
617 | ext4_xattr_put_super(sb); | ||
618 | |||
617 | if (!(sb->s_flags & MS_RDONLY)) { | 619 | if (!(sb->s_flags & MS_RDONLY)) { |
618 | EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); | 620 | EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); |
619 | es->s_state = cpu_to_le16(sbi->s_mount_state); | 621 | es->s_state = cpu_to_le16(sbi->s_mount_state); |
@@ -704,6 +706,8 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) | |||
704 | spin_lock_init(&(ei->i_block_reservation_lock)); | 706 | spin_lock_init(&(ei->i_block_reservation_lock)); |
705 | INIT_LIST_HEAD(&ei->i_aio_dio_complete_list); | 707 | INIT_LIST_HEAD(&ei->i_aio_dio_complete_list); |
706 | ei->cur_aio_dio = NULL; | 708 | ei->cur_aio_dio = NULL; |
709 | ei->i_sync_tid = 0; | ||
710 | ei->i_datasync_tid = 0; | ||
707 | 711 | ||
708 | return &ei->vfs_inode; | 712 | return &ei->vfs_inode; |
709 | } | 713 | } |
@@ -899,6 +903,12 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
899 | if (test_opt(sb, NO_AUTO_DA_ALLOC)) | 903 | if (test_opt(sb, NO_AUTO_DA_ALLOC)) |
900 | seq_puts(seq, ",noauto_da_alloc"); | 904 | seq_puts(seq, ",noauto_da_alloc"); |
901 | 905 | ||
906 | if (test_opt(sb, DISCARD)) | ||
907 | seq_puts(seq, ",discard"); | ||
908 | |||
909 | if (test_opt(sb, NOLOAD)) | ||
910 | seq_puts(seq, ",norecovery"); | ||
911 | |||
902 | ext4_show_quota_options(seq, sb); | 912 | ext4_show_quota_options(seq, sb); |
903 | 913 | ||
904 | return 0; | 914 | return 0; |
@@ -1079,7 +1089,8 @@ enum { | |||
1079 | Opt_usrquota, Opt_grpquota, Opt_i_version, | 1089 | Opt_usrquota, Opt_grpquota, Opt_i_version, |
1080 | Opt_stripe, Opt_delalloc, Opt_nodelalloc, | 1090 | Opt_stripe, Opt_delalloc, Opt_nodelalloc, |
1081 | Opt_block_validity, Opt_noblock_validity, | 1091 | Opt_block_validity, Opt_noblock_validity, |
1082 | Opt_inode_readahead_blks, Opt_journal_ioprio | 1092 | Opt_inode_readahead_blks, Opt_journal_ioprio, |
1093 | Opt_discard, Opt_nodiscard, | ||
1083 | }; | 1094 | }; |
1084 | 1095 | ||
1085 | static const match_table_t tokens = { | 1096 | static const match_table_t tokens = { |
@@ -1104,6 +1115,7 @@ static const match_table_t tokens = { | |||
1104 | {Opt_acl, "acl"}, | 1115 | {Opt_acl, "acl"}, |
1105 | {Opt_noacl, "noacl"}, | 1116 | {Opt_noacl, "noacl"}, |
1106 | {Opt_noload, "noload"}, | 1117 | {Opt_noload, "noload"}, |
1118 | {Opt_noload, "norecovery"}, | ||
1107 | {Opt_nobh, "nobh"}, | 1119 | {Opt_nobh, "nobh"}, |
1108 | {Opt_bh, "bh"}, | 1120 | {Opt_bh, "bh"}, |
1109 | {Opt_commit, "commit=%u"}, | 1121 | {Opt_commit, "commit=%u"}, |
@@ -1144,6 +1156,8 @@ static const match_table_t tokens = { | |||
1144 | {Opt_auto_da_alloc, "auto_da_alloc=%u"}, | 1156 | {Opt_auto_da_alloc, "auto_da_alloc=%u"}, |
1145 | {Opt_auto_da_alloc, "auto_da_alloc"}, | 1157 | {Opt_auto_da_alloc, "auto_da_alloc"}, |
1146 | {Opt_noauto_da_alloc, "noauto_da_alloc"}, | 1158 | {Opt_noauto_da_alloc, "noauto_da_alloc"}, |
1159 | {Opt_discard, "discard"}, | ||
1160 | {Opt_nodiscard, "nodiscard"}, | ||
1147 | {Opt_err, NULL}, | 1161 | {Opt_err, NULL}, |
1148 | }; | 1162 | }; |
1149 | 1163 | ||
@@ -1565,6 +1579,12 @@ set_qf_format: | |||
1565 | else | 1579 | else |
1566 | set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC); | 1580 | set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC); |
1567 | break; | 1581 | break; |
1582 | case Opt_discard: | ||
1583 | set_opt(sbi->s_mount_opt, DISCARD); | ||
1584 | break; | ||
1585 | case Opt_nodiscard: | ||
1586 | clear_opt(sbi->s_mount_opt, DISCARD); | ||
1587 | break; | ||
1568 | default: | 1588 | default: |
1569 | ext4_msg(sb, KERN_ERR, | 1589 | ext4_msg(sb, KERN_ERR, |
1570 | "Unrecognized mount option \"%s\" " | 1590 | "Unrecognized mount option \"%s\" " |
@@ -1673,14 +1693,14 @@ static int ext4_fill_flex_info(struct super_block *sb) | |||
1673 | size_t size; | 1693 | size_t size; |
1674 | int i; | 1694 | int i; |
1675 | 1695 | ||
1676 | if (!sbi->s_es->s_log_groups_per_flex) { | 1696 | sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex; |
1697 | groups_per_flex = 1 << sbi->s_log_groups_per_flex; | ||
1698 | |||
1699 | if (groups_per_flex < 2) { | ||
1677 | sbi->s_log_groups_per_flex = 0; | 1700 | sbi->s_log_groups_per_flex = 0; |
1678 | return 1; | 1701 | return 1; |
1679 | } | 1702 | } |
1680 | 1703 | ||
1681 | sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex; | ||
1682 | groups_per_flex = 1 << sbi->s_log_groups_per_flex; | ||
1683 | |||
1684 | /* We allocate both existing and potentially added groups */ | 1704 | /* We allocate both existing and potentially added groups */ |
1685 | flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) + | 1705 | flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) + |
1686 | ((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) << | 1706 | ((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) << |
@@ -2721,26 +2741,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2721 | EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) { | 2741 | EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) { |
2722 | if (ext4_load_journal(sb, es, journal_devnum)) | 2742 | if (ext4_load_journal(sb, es, journal_devnum)) |
2723 | goto failed_mount3; | 2743 | goto failed_mount3; |
2724 | if (!(sb->s_flags & MS_RDONLY) && | ||
2725 | EXT4_SB(sb)->s_journal->j_failed_commit) { | ||
2726 | ext4_msg(sb, KERN_CRIT, "error: " | ||
2727 | "ext4_fill_super: Journal transaction " | ||
2728 | "%u is corrupt", | ||
2729 | EXT4_SB(sb)->s_journal->j_failed_commit); | ||
2730 | if (test_opt(sb, ERRORS_RO)) { | ||
2731 | ext4_msg(sb, KERN_CRIT, | ||
2732 | "Mounting filesystem read-only"); | ||
2733 | sb->s_flags |= MS_RDONLY; | ||
2734 | EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; | ||
2735 | es->s_state |= cpu_to_le16(EXT4_ERROR_FS); | ||
2736 | } | ||
2737 | if (test_opt(sb, ERRORS_PANIC)) { | ||
2738 | EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; | ||
2739 | es->s_state |= cpu_to_le16(EXT4_ERROR_FS); | ||
2740 | ext4_commit_super(sb, 1); | ||
2741 | goto failed_mount4; | ||
2742 | } | ||
2743 | } | ||
2744 | } else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) && | 2744 | } else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) && |
2745 | EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) { | 2745 | EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) { |
2746 | ext4_msg(sb, KERN_ERR, "required journal recovery " | 2746 | ext4_msg(sb, KERN_ERR, "required journal recovery " |
@@ -3668,13 +3668,11 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
3668 | buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last; | 3668 | buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last; |
3669 | buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter) - | 3669 | buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter) - |
3670 | percpu_counter_sum_positive(&sbi->s_dirtyblocks_counter); | 3670 | percpu_counter_sum_positive(&sbi->s_dirtyblocks_counter); |
3671 | ext4_free_blocks_count_set(es, buf->f_bfree); | ||
3672 | buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es); | 3671 | buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es); |
3673 | if (buf->f_bfree < ext4_r_blocks_count(es)) | 3672 | if (buf->f_bfree < ext4_r_blocks_count(es)) |
3674 | buf->f_bavail = 0; | 3673 | buf->f_bavail = 0; |
3675 | buf->f_files = le32_to_cpu(es->s_inodes_count); | 3674 | buf->f_files = le32_to_cpu(es->s_inodes_count); |
3676 | buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter); | 3675 | buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter); |
3677 | es->s_free_inodes_count = cpu_to_le32(buf->f_ffree); | ||
3678 | buf->f_namelen = EXT4_NAME_LEN; | 3676 | buf->f_namelen = EXT4_NAME_LEN; |
3679 | fsid = le64_to_cpup((void *)es->s_uuid) ^ | 3677 | fsid = le64_to_cpup((void *)es->s_uuid) ^ |
3680 | le64_to_cpup((void *)es->s_uuid + sizeof(u64)); | 3678 | le64_to_cpup((void *)es->s_uuid + sizeof(u64)); |
@@ -3966,6 +3964,58 @@ static int ext4_get_sb(struct file_system_type *fs_type, int flags, | |||
3966 | return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super,mnt); | 3964 | return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super,mnt); |
3967 | } | 3965 | } |
3968 | 3966 | ||
3967 | #if !defined(CONTIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) | ||
3968 | static struct file_system_type ext2_fs_type = { | ||
3969 | .owner = THIS_MODULE, | ||
3970 | .name = "ext2", | ||
3971 | .get_sb = ext4_get_sb, | ||
3972 | .kill_sb = kill_block_super, | ||
3973 | .fs_flags = FS_REQUIRES_DEV, | ||
3974 | }; | ||
3975 | |||
3976 | static inline void register_as_ext2(void) | ||
3977 | { | ||
3978 | int err = register_filesystem(&ext2_fs_type); | ||
3979 | if (err) | ||
3980 | printk(KERN_WARNING | ||
3981 | "EXT4-fs: Unable to register as ext2 (%d)\n", err); | ||
3982 | } | ||
3983 | |||
3984 | static inline void unregister_as_ext2(void) | ||
3985 | { | ||
3986 | unregister_filesystem(&ext2_fs_type); | ||
3987 | } | ||
3988 | #else | ||
3989 | static inline void register_as_ext2(void) { } | ||
3990 | static inline void unregister_as_ext2(void) { } | ||
3991 | #endif | ||
3992 | |||
3993 | #if !defined(CONTIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) | ||
3994 | static struct file_system_type ext3_fs_type = { | ||
3995 | .owner = THIS_MODULE, | ||
3996 | .name = "ext3", | ||
3997 | .get_sb = ext4_get_sb, | ||
3998 | .kill_sb = kill_block_super, | ||
3999 | .fs_flags = FS_REQUIRES_DEV, | ||
4000 | }; | ||
4001 | |||
4002 | static inline void register_as_ext3(void) | ||
4003 | { | ||
4004 | int err = register_filesystem(&ext3_fs_type); | ||
4005 | if (err) | ||
4006 | printk(KERN_WARNING | ||
4007 | "EXT4-fs: Unable to register as ext3 (%d)\n", err); | ||
4008 | } | ||
4009 | |||
4010 | static inline void unregister_as_ext3(void) | ||
4011 | { | ||
4012 | unregister_filesystem(&ext3_fs_type); | ||
4013 | } | ||
4014 | #else | ||
4015 | static inline void register_as_ext3(void) { } | ||
4016 | static inline void unregister_as_ext3(void) { } | ||
4017 | #endif | ||
4018 | |||
3969 | static struct file_system_type ext4_fs_type = { | 4019 | static struct file_system_type ext4_fs_type = { |
3970 | .owner = THIS_MODULE, | 4020 | .owner = THIS_MODULE, |
3971 | .name = "ext4", | 4021 | .name = "ext4", |
@@ -3995,11 +4045,15 @@ static int __init init_ext4_fs(void) | |||
3995 | err = init_inodecache(); | 4045 | err = init_inodecache(); |
3996 | if (err) | 4046 | if (err) |
3997 | goto out1; | 4047 | goto out1; |
4048 | register_as_ext2(); | ||
4049 | register_as_ext3(); | ||
3998 | err = register_filesystem(&ext4_fs_type); | 4050 | err = register_filesystem(&ext4_fs_type); |
3999 | if (err) | 4051 | if (err) |
4000 | goto out; | 4052 | goto out; |
4001 | return 0; | 4053 | return 0; |
4002 | out: | 4054 | out: |
4055 | unregister_as_ext2(); | ||
4056 | unregister_as_ext3(); | ||
4003 | destroy_inodecache(); | 4057 | destroy_inodecache(); |
4004 | out1: | 4058 | out1: |
4005 | exit_ext4_xattr(); | 4059 | exit_ext4_xattr(); |
@@ -4015,6 +4069,8 @@ out4: | |||
4015 | 4069 | ||
4016 | static void __exit exit_ext4_fs(void) | 4070 | static void __exit exit_ext4_fs(void) |
4017 | { | 4071 | { |
4072 | unregister_as_ext2(); | ||
4073 | unregister_as_ext3(); | ||
4018 | unregister_filesystem(&ext4_fs_type); | 4074 | unregister_filesystem(&ext4_fs_type); |
4019 | destroy_inodecache(); | 4075 | destroy_inodecache(); |
4020 | exit_ext4_xattr(); | 4076 | exit_ext4_xattr(); |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index fed5b01d7a8d..910bf9a59cb3 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -482,9 +482,10 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, | |||
482 | ea_bdebug(bh, "refcount now=0; freeing"); | 482 | ea_bdebug(bh, "refcount now=0; freeing"); |
483 | if (ce) | 483 | if (ce) |
484 | mb_cache_entry_free(ce); | 484 | mb_cache_entry_free(ce); |
485 | ext4_free_blocks(handle, inode, bh->b_blocknr, 1, 1); | ||
486 | get_bh(bh); | 485 | get_bh(bh); |
487 | ext4_forget(handle, 1, inode, bh, bh->b_blocknr); | 486 | ext4_free_blocks(handle, inode, bh, 0, 1, |
487 | EXT4_FREE_BLOCKS_METADATA | | ||
488 | EXT4_FREE_BLOCKS_FORGET); | ||
488 | } else { | 489 | } else { |
489 | le32_add_cpu(&BHDR(bh)->h_refcount, -1); | 490 | le32_add_cpu(&BHDR(bh)->h_refcount, -1); |
490 | error = ext4_handle_dirty_metadata(handle, inode, bh); | 491 | error = ext4_handle_dirty_metadata(handle, inode, bh); |
@@ -832,7 +833,8 @@ inserted: | |||
832 | new_bh = sb_getblk(sb, block); | 833 | new_bh = sb_getblk(sb, block); |
833 | if (!new_bh) { | 834 | if (!new_bh) { |
834 | getblk_failed: | 835 | getblk_failed: |
835 | ext4_free_blocks(handle, inode, block, 1, 1); | 836 | ext4_free_blocks(handle, inode, 0, block, 1, |
837 | EXT4_FREE_BLOCKS_METADATA); | ||
836 | error = -EIO; | 838 | error = -EIO; |
837 | goto cleanup; | 839 | goto cleanup; |
838 | } | 840 | } |
@@ -988,6 +990,10 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, | |||
988 | if (error) | 990 | if (error) |
989 | goto cleanup; | 991 | goto cleanup; |
990 | 992 | ||
993 | error = ext4_journal_get_write_access(handle, is.iloc.bh); | ||
994 | if (error) | ||
995 | goto cleanup; | ||
996 | |||
991 | if (EXT4_I(inode)->i_state & EXT4_STATE_NEW) { | 997 | if (EXT4_I(inode)->i_state & EXT4_STATE_NEW) { |
992 | struct ext4_inode *raw_inode = ext4_raw_inode(&is.iloc); | 998 | struct ext4_inode *raw_inode = ext4_raw_inode(&is.iloc); |
993 | memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); | 999 | memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); |
@@ -1013,9 +1019,6 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, | |||
1013 | if (flags & XATTR_CREATE) | 1019 | if (flags & XATTR_CREATE) |
1014 | goto cleanup; | 1020 | goto cleanup; |
1015 | } | 1021 | } |
1016 | error = ext4_journal_get_write_access(handle, is.iloc.bh); | ||
1017 | if (error) | ||
1018 | goto cleanup; | ||
1019 | if (!value) { | 1022 | if (!value) { |
1020 | if (!is.s.not_found) | 1023 | if (!is.s.not_found) |
1021 | error = ext4_xattr_ibody_set(handle, inode, &i, &is); | 1024 | error = ext4_xattr_ibody_set(handle, inode, &i, &is); |
diff --git a/fs/file_table.c b/fs/file_table.c index 8eb44042e009..4bef4c01ec6f 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
15 | #include <linux/security.h> | 15 | #include <linux/security.h> |
16 | #include <linux/ima.h> | ||
17 | #include <linux/eventpoll.h> | 16 | #include <linux/eventpoll.h> |
18 | #include <linux/rcupdate.h> | 17 | #include <linux/rcupdate.h> |
19 | #include <linux/mount.h> | 18 | #include <linux/mount.h> |
@@ -280,7 +279,6 @@ void __fput(struct file *file) | |||
280 | if (file->f_op && file->f_op->release) | 279 | if (file->f_op && file->f_op->release) |
281 | file->f_op->release(inode, file); | 280 | file->f_op->release(inode, file); |
282 | security_file_free(file); | 281 | security_file_free(file); |
283 | ima_file_free(file); | ||
284 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) | 282 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) |
285 | cdev_put(inode->i_cdev); | 283 | cdev_put(inode->i_cdev); |
286 | fops_put(file->f_op); | 284 | fops_put(file->f_op); |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 9d5360c4c2af..49bc1b8e8f19 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -614,7 +614,6 @@ static void writeback_inodes_wb(struct bdi_writeback *wb, | |||
614 | struct writeback_control *wbc) | 614 | struct writeback_control *wbc) |
615 | { | 615 | { |
616 | struct super_block *sb = wbc->sb, *pin_sb = NULL; | 616 | struct super_block *sb = wbc->sb, *pin_sb = NULL; |
617 | const int is_blkdev_sb = sb_is_blkdev_sb(sb); | ||
618 | const unsigned long start = jiffies; /* livelock avoidance */ | 617 | const unsigned long start = jiffies; /* livelock avoidance */ |
619 | 618 | ||
620 | spin_lock(&inode_lock); | 619 | spin_lock(&inode_lock); |
@@ -635,36 +634,11 @@ static void writeback_inodes_wb(struct bdi_writeback *wb, | |||
635 | continue; | 634 | continue; |
636 | } | 635 | } |
637 | 636 | ||
638 | if (!bdi_cap_writeback_dirty(wb->bdi)) { | ||
639 | redirty_tail(inode); | ||
640 | if (is_blkdev_sb) { | ||
641 | /* | ||
642 | * Dirty memory-backed blockdev: the ramdisk | ||
643 | * driver does this. Skip just this inode | ||
644 | */ | ||
645 | continue; | ||
646 | } | ||
647 | /* | ||
648 | * Dirty memory-backed inode against a filesystem other | ||
649 | * than the kernel-internal bdev filesystem. Skip the | ||
650 | * entire superblock. | ||
651 | */ | ||
652 | break; | ||
653 | } | ||
654 | |||
655 | if (inode->i_state & (I_NEW | I_WILL_FREE)) { | 637 | if (inode->i_state & (I_NEW | I_WILL_FREE)) { |
656 | requeue_io(inode); | 638 | requeue_io(inode); |
657 | continue; | 639 | continue; |
658 | } | 640 | } |
659 | 641 | ||
660 | if (wbc->nonblocking && bdi_write_congested(wb->bdi)) { | ||
661 | wbc->encountered_congestion = 1; | ||
662 | if (!is_blkdev_sb) | ||
663 | break; /* Skip a congested fs */ | ||
664 | requeue_io(inode); | ||
665 | continue; /* Skip a congested blockdev */ | ||
666 | } | ||
667 | |||
668 | /* | 642 | /* |
669 | * Was this inode dirtied after sync_sb_inodes was called? | 643 | * Was this inode dirtied after sync_sb_inodes was called? |
670 | * This keeps sync from extra jobs and livelock. | 644 | * This keeps sync from extra jobs and livelock. |
@@ -756,6 +730,7 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
756 | .sync_mode = args->sync_mode, | 730 | .sync_mode = args->sync_mode, |
757 | .older_than_this = NULL, | 731 | .older_than_this = NULL, |
758 | .for_kupdate = args->for_kupdate, | 732 | .for_kupdate = args->for_kupdate, |
733 | .for_background = args->for_background, | ||
759 | .range_cyclic = args->range_cyclic, | 734 | .range_cyclic = args->range_cyclic, |
760 | }; | 735 | }; |
761 | unsigned long oldest_jif; | 736 | unsigned long oldest_jif; |
@@ -787,7 +762,6 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
787 | break; | 762 | break; |
788 | 763 | ||
789 | wbc.more_io = 0; | 764 | wbc.more_io = 0; |
790 | wbc.encountered_congestion = 0; | ||
791 | wbc.nr_to_write = MAX_WRITEBACK_PAGES; | 765 | wbc.nr_to_write = MAX_WRITEBACK_PAGES; |
792 | wbc.pages_skipped = 0; | 766 | wbc.pages_skipped = 0; |
793 | writeback_inodes_wb(wb, &wbc); | 767 | writeback_inodes_wb(wb, &wbc); |
diff --git a/fs/fscache/Kconfig b/fs/fscache/Kconfig index 9bbb8ce7bea0..864dac20a242 100644 --- a/fs/fscache/Kconfig +++ b/fs/fscache/Kconfig | |||
@@ -54,3 +54,10 @@ config FSCACHE_DEBUG | |||
54 | enabled by setting bits in /sys/modules/fscache/parameter/debug. | 54 | enabled by setting bits in /sys/modules/fscache/parameter/debug. |
55 | 55 | ||
56 | See Documentation/filesystems/caching/fscache.txt for more information. | 56 | See Documentation/filesystems/caching/fscache.txt for more information. |
57 | |||
58 | config FSCACHE_OBJECT_LIST | ||
59 | bool "Maintain global object list for debugging purposes" | ||
60 | depends on FSCACHE && PROC_FS | ||
61 | help | ||
62 | Maintain a global list of active fscache objects that can be | ||
63 | retrieved through /proc/fs/fscache/objects for debugging purposes | ||
diff --git a/fs/fscache/Makefile b/fs/fscache/Makefile index 91571b95aacc..6d561531cb36 100644 --- a/fs/fscache/Makefile +++ b/fs/fscache/Makefile | |||
@@ -15,5 +15,6 @@ fscache-y := \ | |||
15 | fscache-$(CONFIG_PROC_FS) += proc.o | 15 | fscache-$(CONFIG_PROC_FS) += proc.o |
16 | fscache-$(CONFIG_FSCACHE_STATS) += stats.o | 16 | fscache-$(CONFIG_FSCACHE_STATS) += stats.o |
17 | fscache-$(CONFIG_FSCACHE_HISTOGRAM) += histogram.o | 17 | fscache-$(CONFIG_FSCACHE_HISTOGRAM) += histogram.o |
18 | fscache-$(CONFIG_FSCACHE_OBJECT_LIST) += object-list.o | ||
18 | 19 | ||
19 | obj-$(CONFIG_FSCACHE) := fscache.o | 20 | obj-$(CONFIG_FSCACHE) := fscache.o |
diff --git a/fs/fscache/cache.c b/fs/fscache/cache.c index e21985bbb1fb..6a3c48abd677 100644 --- a/fs/fscache/cache.c +++ b/fs/fscache/cache.c | |||
@@ -263,6 +263,7 @@ int fscache_add_cache(struct fscache_cache *cache, | |||
263 | spin_lock(&cache->object_list_lock); | 263 | spin_lock(&cache->object_list_lock); |
264 | list_add_tail(&ifsdef->cache_link, &cache->object_list); | 264 | list_add_tail(&ifsdef->cache_link, &cache->object_list); |
265 | spin_unlock(&cache->object_list_lock); | 265 | spin_unlock(&cache->object_list_lock); |
266 | fscache_objlist_add(ifsdef); | ||
266 | 267 | ||
267 | /* add the cache's netfs definition index object to the top level index | 268 | /* add the cache's netfs definition index object to the top level index |
268 | * cookie as a known backing object */ | 269 | * cookie as a known backing object */ |
@@ -380,11 +381,15 @@ void fscache_withdraw_cache(struct fscache_cache *cache) | |||
380 | 381 | ||
381 | /* make sure all pages pinned by operations on behalf of the netfs are | 382 | /* make sure all pages pinned by operations on behalf of the netfs are |
382 | * written to disk */ | 383 | * written to disk */ |
384 | fscache_stat(&fscache_n_cop_sync_cache); | ||
383 | cache->ops->sync_cache(cache); | 385 | cache->ops->sync_cache(cache); |
386 | fscache_stat_d(&fscache_n_cop_sync_cache); | ||
384 | 387 | ||
385 | /* dissociate all the netfs pages backed by this cache from the block | 388 | /* dissociate all the netfs pages backed by this cache from the block |
386 | * mappings in the cache */ | 389 | * mappings in the cache */ |
390 | fscache_stat(&fscache_n_cop_dissociate_pages); | ||
387 | cache->ops->dissociate_pages(cache); | 391 | cache->ops->dissociate_pages(cache); |
392 | fscache_stat_d(&fscache_n_cop_dissociate_pages); | ||
388 | 393 | ||
389 | /* we now have to destroy all the active objects pertaining to this | 394 | /* we now have to destroy all the active objects pertaining to this |
390 | * cache - which we do by passing them off to thread pool to be | 395 | * cache - which we do by passing them off to thread pool to be |
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 72fd18f6c71f..990535071a8a 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c | |||
@@ -36,6 +36,7 @@ void fscache_cookie_init_once(void *_cookie) | |||
36 | 36 | ||
37 | memset(cookie, 0, sizeof(*cookie)); | 37 | memset(cookie, 0, sizeof(*cookie)); |
38 | spin_lock_init(&cookie->lock); | 38 | spin_lock_init(&cookie->lock); |
39 | spin_lock_init(&cookie->stores_lock); | ||
39 | INIT_HLIST_HEAD(&cookie->backing_objects); | 40 | INIT_HLIST_HEAD(&cookie->backing_objects); |
40 | } | 41 | } |
41 | 42 | ||
@@ -102,7 +103,9 @@ struct fscache_cookie *__fscache_acquire_cookie( | |||
102 | cookie->netfs_data = netfs_data; | 103 | cookie->netfs_data = netfs_data; |
103 | cookie->flags = 0; | 104 | cookie->flags = 0; |
104 | 105 | ||
105 | INIT_RADIX_TREE(&cookie->stores, GFP_NOFS); | 106 | /* radix tree insertion won't use the preallocation pool unless it's |
107 | * told it may not wait */ | ||
108 | INIT_RADIX_TREE(&cookie->stores, GFP_NOFS & ~__GFP_WAIT); | ||
106 | 109 | ||
107 | switch (cookie->def->type) { | 110 | switch (cookie->def->type) { |
108 | case FSCACHE_COOKIE_TYPE_INDEX: | 111 | case FSCACHE_COOKIE_TYPE_INDEX: |
@@ -249,7 +252,9 @@ static int fscache_alloc_object(struct fscache_cache *cache, | |||
249 | 252 | ||
250 | /* ask the cache to allocate an object (we may end up with duplicate | 253 | /* ask the cache to allocate an object (we may end up with duplicate |
251 | * objects at this stage, but we sort that out later) */ | 254 | * objects at this stage, but we sort that out later) */ |
255 | fscache_stat(&fscache_n_cop_alloc_object); | ||
252 | object = cache->ops->alloc_object(cache, cookie); | 256 | object = cache->ops->alloc_object(cache, cookie); |
257 | fscache_stat_d(&fscache_n_cop_alloc_object); | ||
253 | if (IS_ERR(object)) { | 258 | if (IS_ERR(object)) { |
254 | fscache_stat(&fscache_n_object_no_alloc); | 259 | fscache_stat(&fscache_n_object_no_alloc); |
255 | ret = PTR_ERR(object); | 260 | ret = PTR_ERR(object); |
@@ -270,8 +275,11 @@ static int fscache_alloc_object(struct fscache_cache *cache, | |||
270 | /* only attach if we managed to allocate all we needed, otherwise | 275 | /* only attach if we managed to allocate all we needed, otherwise |
271 | * discard the object we just allocated and instead use the one | 276 | * discard the object we just allocated and instead use the one |
272 | * attached to the cookie */ | 277 | * attached to the cookie */ |
273 | if (fscache_attach_object(cookie, object) < 0) | 278 | if (fscache_attach_object(cookie, object) < 0) { |
279 | fscache_stat(&fscache_n_cop_put_object); | ||
274 | cache->ops->put_object(object); | 280 | cache->ops->put_object(object); |
281 | fscache_stat_d(&fscache_n_cop_put_object); | ||
282 | } | ||
275 | 283 | ||
276 | _leave(" = 0"); | 284 | _leave(" = 0"); |
277 | return 0; | 285 | return 0; |
@@ -287,7 +295,9 @@ object_already_extant: | |||
287 | return 0; | 295 | return 0; |
288 | 296 | ||
289 | error_put: | 297 | error_put: |
298 | fscache_stat(&fscache_n_cop_put_object); | ||
290 | cache->ops->put_object(object); | 299 | cache->ops->put_object(object); |
300 | fscache_stat_d(&fscache_n_cop_put_object); | ||
291 | error: | 301 | error: |
292 | _leave(" = %d", ret); | 302 | _leave(" = %d", ret); |
293 | return ret; | 303 | return ret; |
@@ -349,6 +359,8 @@ static int fscache_attach_object(struct fscache_cookie *cookie, | |||
349 | object->cookie = cookie; | 359 | object->cookie = cookie; |
350 | atomic_inc(&cookie->usage); | 360 | atomic_inc(&cookie->usage); |
351 | hlist_add_head(&object->cookie_link, &cookie->backing_objects); | 361 | hlist_add_head(&object->cookie_link, &cookie->backing_objects); |
362 | |||
363 | fscache_objlist_add(object); | ||
352 | ret = 0; | 364 | ret = 0; |
353 | 365 | ||
354 | cant_attach_object: | 366 | cant_attach_object: |
@@ -403,6 +415,8 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
403 | unsigned long event; | 415 | unsigned long event; |
404 | 416 | ||
405 | fscache_stat(&fscache_n_relinquishes); | 417 | fscache_stat(&fscache_n_relinquishes); |
418 | if (retire) | ||
419 | fscache_stat(&fscache_n_relinquishes_retire); | ||
406 | 420 | ||
407 | if (!cookie) { | 421 | if (!cookie) { |
408 | fscache_stat(&fscache_n_relinquishes_null); | 422 | fscache_stat(&fscache_n_relinquishes_null); |
@@ -428,12 +442,8 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
428 | 442 | ||
429 | event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE; | 443 | event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE; |
430 | 444 | ||
431 | /* detach pointers back to the netfs */ | ||
432 | spin_lock(&cookie->lock); | 445 | spin_lock(&cookie->lock); |
433 | 446 | ||
434 | cookie->netfs_data = NULL; | ||
435 | cookie->def = NULL; | ||
436 | |||
437 | /* break links with all the active objects */ | 447 | /* break links with all the active objects */ |
438 | while (!hlist_empty(&cookie->backing_objects)) { | 448 | while (!hlist_empty(&cookie->backing_objects)) { |
439 | object = hlist_entry(cookie->backing_objects.first, | 449 | object = hlist_entry(cookie->backing_objects.first, |
@@ -456,6 +466,10 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
456 | BUG(); | 466 | BUG(); |
457 | } | 467 | } |
458 | 468 | ||
469 | /* detach pointers back to the netfs */ | ||
470 | cookie->netfs_data = NULL; | ||
471 | cookie->def = NULL; | ||
472 | |||
459 | spin_unlock(&cookie->lock); | 473 | spin_unlock(&cookie->lock); |
460 | 474 | ||
461 | if (cookie->parent) { | 475 | if (cookie->parent) { |
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index 1c341304621f..edd7434ab6e5 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -17,6 +17,7 @@ | |||
17 | * - cache->object_list_lock | 17 | * - cache->object_list_lock |
18 | * - object->lock | 18 | * - object->lock |
19 | * - object->parent->lock | 19 | * - object->parent->lock |
20 | * - cookie->stores_lock | ||
20 | * - fscache_thread_lock | 21 | * - fscache_thread_lock |
21 | * | 22 | * |
22 | */ | 23 | */ |
@@ -88,17 +89,31 @@ extern int fscache_wait_bit_interruptible(void *); | |||
88 | /* | 89 | /* |
89 | * object.c | 90 | * object.c |
90 | */ | 91 | */ |
92 | extern const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5]; | ||
93 | |||
91 | extern void fscache_withdrawing_object(struct fscache_cache *, | 94 | extern void fscache_withdrawing_object(struct fscache_cache *, |
92 | struct fscache_object *); | 95 | struct fscache_object *); |
93 | extern void fscache_enqueue_object(struct fscache_object *); | 96 | extern void fscache_enqueue_object(struct fscache_object *); |
94 | 97 | ||
95 | /* | 98 | /* |
99 | * object-list.c | ||
100 | */ | ||
101 | #ifdef CONFIG_FSCACHE_OBJECT_LIST | ||
102 | extern const struct file_operations fscache_objlist_fops; | ||
103 | |||
104 | extern void fscache_objlist_add(struct fscache_object *); | ||
105 | #else | ||
106 | #define fscache_objlist_add(object) do {} while(0) | ||
107 | #endif | ||
108 | |||
109 | /* | ||
96 | * operation.c | 110 | * operation.c |
97 | */ | 111 | */ |
98 | extern int fscache_submit_exclusive_op(struct fscache_object *, | 112 | extern int fscache_submit_exclusive_op(struct fscache_object *, |
99 | struct fscache_operation *); | 113 | struct fscache_operation *); |
100 | extern int fscache_submit_op(struct fscache_object *, | 114 | extern int fscache_submit_op(struct fscache_object *, |
101 | struct fscache_operation *); | 115 | struct fscache_operation *); |
116 | extern int fscache_cancel_op(struct fscache_operation *); | ||
102 | extern void fscache_abort_object(struct fscache_object *); | 117 | extern void fscache_abort_object(struct fscache_object *); |
103 | extern void fscache_start_operations(struct fscache_object *); | 118 | extern void fscache_start_operations(struct fscache_object *); |
104 | extern void fscache_operation_gc(struct work_struct *); | 119 | extern void fscache_operation_gc(struct work_struct *); |
@@ -127,6 +142,8 @@ extern atomic_t fscache_n_op_enqueue; | |||
127 | extern atomic_t fscache_n_op_deferred_release; | 142 | extern atomic_t fscache_n_op_deferred_release; |
128 | extern atomic_t fscache_n_op_release; | 143 | extern atomic_t fscache_n_op_release; |
129 | extern atomic_t fscache_n_op_gc; | 144 | extern atomic_t fscache_n_op_gc; |
145 | extern atomic_t fscache_n_op_cancelled; | ||
146 | extern atomic_t fscache_n_op_rejected; | ||
130 | 147 | ||
131 | extern atomic_t fscache_n_attr_changed; | 148 | extern atomic_t fscache_n_attr_changed; |
132 | extern atomic_t fscache_n_attr_changed_ok; | 149 | extern atomic_t fscache_n_attr_changed_ok; |
@@ -138,6 +155,8 @@ extern atomic_t fscache_n_allocs; | |||
138 | extern atomic_t fscache_n_allocs_ok; | 155 | extern atomic_t fscache_n_allocs_ok; |
139 | extern atomic_t fscache_n_allocs_wait; | 156 | extern atomic_t fscache_n_allocs_wait; |
140 | extern atomic_t fscache_n_allocs_nobufs; | 157 | extern atomic_t fscache_n_allocs_nobufs; |
158 | extern atomic_t fscache_n_allocs_intr; | ||
159 | extern atomic_t fscache_n_allocs_object_dead; | ||
141 | extern atomic_t fscache_n_alloc_ops; | 160 | extern atomic_t fscache_n_alloc_ops; |
142 | extern atomic_t fscache_n_alloc_op_waits; | 161 | extern atomic_t fscache_n_alloc_op_waits; |
143 | 162 | ||
@@ -148,6 +167,7 @@ extern atomic_t fscache_n_retrievals_nodata; | |||
148 | extern atomic_t fscache_n_retrievals_nobufs; | 167 | extern atomic_t fscache_n_retrievals_nobufs; |
149 | extern atomic_t fscache_n_retrievals_intr; | 168 | extern atomic_t fscache_n_retrievals_intr; |
150 | extern atomic_t fscache_n_retrievals_nomem; | 169 | extern atomic_t fscache_n_retrievals_nomem; |
170 | extern atomic_t fscache_n_retrievals_object_dead; | ||
151 | extern atomic_t fscache_n_retrieval_ops; | 171 | extern atomic_t fscache_n_retrieval_ops; |
152 | extern atomic_t fscache_n_retrieval_op_waits; | 172 | extern atomic_t fscache_n_retrieval_op_waits; |
153 | 173 | ||
@@ -158,6 +178,14 @@ extern atomic_t fscache_n_stores_nobufs; | |||
158 | extern atomic_t fscache_n_stores_oom; | 178 | extern atomic_t fscache_n_stores_oom; |
159 | extern atomic_t fscache_n_store_ops; | 179 | extern atomic_t fscache_n_store_ops; |
160 | extern atomic_t fscache_n_store_calls; | 180 | extern atomic_t fscache_n_store_calls; |
181 | extern atomic_t fscache_n_store_pages; | ||
182 | extern atomic_t fscache_n_store_radix_deletes; | ||
183 | extern atomic_t fscache_n_store_pages_over_limit; | ||
184 | |||
185 | extern atomic_t fscache_n_store_vmscan_not_storing; | ||
186 | extern atomic_t fscache_n_store_vmscan_gone; | ||
187 | extern atomic_t fscache_n_store_vmscan_busy; | ||
188 | extern atomic_t fscache_n_store_vmscan_cancelled; | ||
161 | 189 | ||
162 | extern atomic_t fscache_n_marks; | 190 | extern atomic_t fscache_n_marks; |
163 | extern atomic_t fscache_n_uncaches; | 191 | extern atomic_t fscache_n_uncaches; |
@@ -176,6 +204,7 @@ extern atomic_t fscache_n_updates_run; | |||
176 | extern atomic_t fscache_n_relinquishes; | 204 | extern atomic_t fscache_n_relinquishes; |
177 | extern atomic_t fscache_n_relinquishes_null; | 205 | extern atomic_t fscache_n_relinquishes_null; |
178 | extern atomic_t fscache_n_relinquishes_waitcrt; | 206 | extern atomic_t fscache_n_relinquishes_waitcrt; |
207 | extern atomic_t fscache_n_relinquishes_retire; | ||
179 | 208 | ||
180 | extern atomic_t fscache_n_cookie_index; | 209 | extern atomic_t fscache_n_cookie_index; |
181 | extern atomic_t fscache_n_cookie_data; | 210 | extern atomic_t fscache_n_cookie_data; |
@@ -186,6 +215,7 @@ extern atomic_t fscache_n_object_no_alloc; | |||
186 | extern atomic_t fscache_n_object_lookups; | 215 | extern atomic_t fscache_n_object_lookups; |
187 | extern atomic_t fscache_n_object_lookups_negative; | 216 | extern atomic_t fscache_n_object_lookups_negative; |
188 | extern atomic_t fscache_n_object_lookups_positive; | 217 | extern atomic_t fscache_n_object_lookups_positive; |
218 | extern atomic_t fscache_n_object_lookups_timed_out; | ||
189 | extern atomic_t fscache_n_object_created; | 219 | extern atomic_t fscache_n_object_created; |
190 | extern atomic_t fscache_n_object_avail; | 220 | extern atomic_t fscache_n_object_avail; |
191 | extern atomic_t fscache_n_object_dead; | 221 | extern atomic_t fscache_n_object_dead; |
@@ -195,15 +225,41 @@ extern atomic_t fscache_n_checkaux_okay; | |||
195 | extern atomic_t fscache_n_checkaux_update; | 225 | extern atomic_t fscache_n_checkaux_update; |
196 | extern atomic_t fscache_n_checkaux_obsolete; | 226 | extern atomic_t fscache_n_checkaux_obsolete; |
197 | 227 | ||
228 | extern atomic_t fscache_n_cop_alloc_object; | ||
229 | extern atomic_t fscache_n_cop_lookup_object; | ||
230 | extern atomic_t fscache_n_cop_lookup_complete; | ||
231 | extern atomic_t fscache_n_cop_grab_object; | ||
232 | extern atomic_t fscache_n_cop_update_object; | ||
233 | extern atomic_t fscache_n_cop_drop_object; | ||
234 | extern atomic_t fscache_n_cop_put_object; | ||
235 | extern atomic_t fscache_n_cop_sync_cache; | ||
236 | extern atomic_t fscache_n_cop_attr_changed; | ||
237 | extern atomic_t fscache_n_cop_read_or_alloc_page; | ||
238 | extern atomic_t fscache_n_cop_read_or_alloc_pages; | ||
239 | extern atomic_t fscache_n_cop_allocate_page; | ||
240 | extern atomic_t fscache_n_cop_allocate_pages; | ||
241 | extern atomic_t fscache_n_cop_write_page; | ||
242 | extern atomic_t fscache_n_cop_uncache_page; | ||
243 | extern atomic_t fscache_n_cop_dissociate_pages; | ||
244 | |||
198 | static inline void fscache_stat(atomic_t *stat) | 245 | static inline void fscache_stat(atomic_t *stat) |
199 | { | 246 | { |
200 | atomic_inc(stat); | 247 | atomic_inc(stat); |
201 | } | 248 | } |
202 | 249 | ||
250 | static inline void fscache_stat_d(atomic_t *stat) | ||
251 | { | ||
252 | atomic_dec(stat); | ||
253 | } | ||
254 | |||
255 | #define __fscache_stat(stat) (stat) | ||
256 | |||
203 | extern const struct file_operations fscache_stats_fops; | 257 | extern const struct file_operations fscache_stats_fops; |
204 | #else | 258 | #else |
205 | 259 | ||
260 | #define __fscache_stat(stat) (NULL) | ||
206 | #define fscache_stat(stat) do {} while (0) | 261 | #define fscache_stat(stat) do {} while (0) |
262 | #define fscache_stat_d(stat) do {} while (0) | ||
207 | #endif | 263 | #endif |
208 | 264 | ||
209 | /* | 265 | /* |
diff --git a/fs/fscache/main.c b/fs/fscache/main.c index 4de41b597499..add6bdb53f04 100644 --- a/fs/fscache/main.c +++ b/fs/fscache/main.c | |||
@@ -48,7 +48,7 @@ static int __init fscache_init(void) | |||
48 | { | 48 | { |
49 | int ret; | 49 | int ret; |
50 | 50 | ||
51 | ret = slow_work_register_user(); | 51 | ret = slow_work_register_user(THIS_MODULE); |
52 | if (ret < 0) | 52 | if (ret < 0) |
53 | goto error_slow_work; | 53 | goto error_slow_work; |
54 | 54 | ||
@@ -80,7 +80,7 @@ error_kobj: | |||
80 | error_cookie_jar: | 80 | error_cookie_jar: |
81 | fscache_proc_cleanup(); | 81 | fscache_proc_cleanup(); |
82 | error_proc: | 82 | error_proc: |
83 | slow_work_unregister_user(); | 83 | slow_work_unregister_user(THIS_MODULE); |
84 | error_slow_work: | 84 | error_slow_work: |
85 | return ret; | 85 | return ret; |
86 | } | 86 | } |
@@ -97,7 +97,7 @@ static void __exit fscache_exit(void) | |||
97 | kobject_put(fscache_root); | 97 | kobject_put(fscache_root); |
98 | kmem_cache_destroy(fscache_cookie_jar); | 98 | kmem_cache_destroy(fscache_cookie_jar); |
99 | fscache_proc_cleanup(); | 99 | fscache_proc_cleanup(); |
100 | slow_work_unregister_user(); | 100 | slow_work_unregister_user(THIS_MODULE); |
101 | printk(KERN_NOTICE "FS-Cache: Unloaded\n"); | 101 | printk(KERN_NOTICE "FS-Cache: Unloaded\n"); |
102 | } | 102 | } |
103 | 103 | ||
diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c new file mode 100644 index 000000000000..e590242fa41a --- /dev/null +++ b/fs/fscache/object-list.c | |||
@@ -0,0 +1,432 @@ | |||
1 | /* Global fscache object list maintainer and viewer | ||
2 | * | ||
3 | * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define FSCACHE_DEBUG_LEVEL COOKIE | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/seq_file.h> | ||
15 | #include <linux/key.h> | ||
16 | #include <keys/user-type.h> | ||
17 | #include "internal.h" | ||
18 | |||
19 | static struct rb_root fscache_object_list; | ||
20 | static DEFINE_RWLOCK(fscache_object_list_lock); | ||
21 | |||
22 | struct fscache_objlist_data { | ||
23 | unsigned long config; /* display configuration */ | ||
24 | #define FSCACHE_OBJLIST_CONFIG_KEY 0x00000001 /* show object keys */ | ||
25 | #define FSCACHE_OBJLIST_CONFIG_AUX 0x00000002 /* show object auxdata */ | ||
26 | #define FSCACHE_OBJLIST_CONFIG_COOKIE 0x00000004 /* show objects with cookies */ | ||
27 | #define FSCACHE_OBJLIST_CONFIG_NOCOOKIE 0x00000008 /* show objects without cookies */ | ||
28 | #define FSCACHE_OBJLIST_CONFIG_BUSY 0x00000010 /* show busy objects */ | ||
29 | #define FSCACHE_OBJLIST_CONFIG_IDLE 0x00000020 /* show idle objects */ | ||
30 | #define FSCACHE_OBJLIST_CONFIG_PENDWR 0x00000040 /* show objects with pending writes */ | ||
31 | #define FSCACHE_OBJLIST_CONFIG_NOPENDWR 0x00000080 /* show objects without pending writes */ | ||
32 | #define FSCACHE_OBJLIST_CONFIG_READS 0x00000100 /* show objects with active reads */ | ||
33 | #define FSCACHE_OBJLIST_CONFIG_NOREADS 0x00000200 /* show objects without active reads */ | ||
34 | #define FSCACHE_OBJLIST_CONFIG_EVENTS 0x00000400 /* show objects with events */ | ||
35 | #define FSCACHE_OBJLIST_CONFIG_NOEVENTS 0x00000800 /* show objects without no events */ | ||
36 | #define FSCACHE_OBJLIST_CONFIG_WORK 0x00001000 /* show objects with slow work */ | ||
37 | #define FSCACHE_OBJLIST_CONFIG_NOWORK 0x00002000 /* show objects without slow work */ | ||
38 | |||
39 | u8 buf[512]; /* key and aux data buffer */ | ||
40 | }; | ||
41 | |||
42 | /* | ||
43 | * Add an object to the object list | ||
44 | * - we use the address of the fscache_object structure as the key into the | ||
45 | * tree | ||
46 | */ | ||
47 | void fscache_objlist_add(struct fscache_object *obj) | ||
48 | { | ||
49 | struct fscache_object *xobj; | ||
50 | struct rb_node **p = &fscache_object_list.rb_node, *parent = NULL; | ||
51 | |||
52 | write_lock(&fscache_object_list_lock); | ||
53 | |||
54 | while (*p) { | ||
55 | parent = *p; | ||
56 | xobj = rb_entry(parent, struct fscache_object, objlist_link); | ||
57 | |||
58 | if (obj < xobj) | ||
59 | p = &(*p)->rb_left; | ||
60 | else if (obj > xobj) | ||
61 | p = &(*p)->rb_right; | ||
62 | else | ||
63 | BUG(); | ||
64 | } | ||
65 | |||
66 | rb_link_node(&obj->objlist_link, parent, p); | ||
67 | rb_insert_color(&obj->objlist_link, &fscache_object_list); | ||
68 | |||
69 | write_unlock(&fscache_object_list_lock); | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * fscache_object_destroy - Note that a cache object is about to be destroyed | ||
74 | * @object: The object to be destroyed | ||
75 | * | ||
76 | * Note the imminent destruction and deallocation of a cache object record. | ||
77 | */ | ||
78 | void fscache_object_destroy(struct fscache_object *obj) | ||
79 | { | ||
80 | write_lock(&fscache_object_list_lock); | ||
81 | |||
82 | BUG_ON(RB_EMPTY_ROOT(&fscache_object_list)); | ||
83 | rb_erase(&obj->objlist_link, &fscache_object_list); | ||
84 | |||
85 | write_unlock(&fscache_object_list_lock); | ||
86 | } | ||
87 | EXPORT_SYMBOL(fscache_object_destroy); | ||
88 | |||
89 | /* | ||
90 | * find the object in the tree on or after the specified index | ||
91 | */ | ||
92 | static struct fscache_object *fscache_objlist_lookup(loff_t *_pos) | ||
93 | { | ||
94 | struct fscache_object *pobj, *obj, *minobj = NULL; | ||
95 | struct rb_node *p; | ||
96 | unsigned long pos; | ||
97 | |||
98 | if (*_pos >= (unsigned long) ERR_PTR(-ENOENT)) | ||
99 | return NULL; | ||
100 | pos = *_pos; | ||
101 | |||
102 | /* banners (can't represent line 0 by pos 0 as that would involve | ||
103 | * returning a NULL pointer) */ | ||
104 | if (pos == 0) | ||
105 | return (struct fscache_object *) ++(*_pos); | ||
106 | if (pos < 3) | ||
107 | return (struct fscache_object *)pos; | ||
108 | |||
109 | pobj = (struct fscache_object *)pos; | ||
110 | p = fscache_object_list.rb_node; | ||
111 | while (p) { | ||
112 | obj = rb_entry(p, struct fscache_object, objlist_link); | ||
113 | if (pobj < obj) { | ||
114 | if (!minobj || minobj > obj) | ||
115 | minobj = obj; | ||
116 | p = p->rb_left; | ||
117 | } else if (pobj > obj) { | ||
118 | p = p->rb_right; | ||
119 | } else { | ||
120 | minobj = obj; | ||
121 | break; | ||
122 | } | ||
123 | obj = NULL; | ||
124 | } | ||
125 | |||
126 | if (!minobj) | ||
127 | *_pos = (unsigned long) ERR_PTR(-ENOENT); | ||
128 | else if (minobj != obj) | ||
129 | *_pos = (unsigned long) minobj; | ||
130 | return minobj; | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * set up the iterator to start reading from the first line | ||
135 | */ | ||
136 | static void *fscache_objlist_start(struct seq_file *m, loff_t *_pos) | ||
137 | __acquires(&fscache_object_list_lock) | ||
138 | { | ||
139 | read_lock(&fscache_object_list_lock); | ||
140 | return fscache_objlist_lookup(_pos); | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * move to the next line | ||
145 | */ | ||
146 | static void *fscache_objlist_next(struct seq_file *m, void *v, loff_t *_pos) | ||
147 | { | ||
148 | (*_pos)++; | ||
149 | return fscache_objlist_lookup(_pos); | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * clean up after reading | ||
154 | */ | ||
155 | static void fscache_objlist_stop(struct seq_file *m, void *v) | ||
156 | __releases(&fscache_object_list_lock) | ||
157 | { | ||
158 | read_unlock(&fscache_object_list_lock); | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * display an object | ||
163 | */ | ||
164 | static int fscache_objlist_show(struct seq_file *m, void *v) | ||
165 | { | ||
166 | struct fscache_objlist_data *data = m->private; | ||
167 | struct fscache_object *obj = v; | ||
168 | unsigned long config = data->config; | ||
169 | uint16_t keylen, auxlen; | ||
170 | char _type[3], *type; | ||
171 | bool no_cookie; | ||
172 | u8 *buf = data->buf, *p; | ||
173 | |||
174 | if ((unsigned long) v == 1) { | ||
175 | seq_puts(m, "OBJECT PARENT STAT CHLDN OPS OOP IPR EX READS" | ||
176 | " EM EV F S" | ||
177 | " | NETFS_COOKIE_DEF TY FL NETFS_DATA"); | ||
178 | if (config & (FSCACHE_OBJLIST_CONFIG_KEY | | ||
179 | FSCACHE_OBJLIST_CONFIG_AUX)) | ||
180 | seq_puts(m, " "); | ||
181 | if (config & FSCACHE_OBJLIST_CONFIG_KEY) | ||
182 | seq_puts(m, "OBJECT_KEY"); | ||
183 | if ((config & (FSCACHE_OBJLIST_CONFIG_KEY | | ||
184 | FSCACHE_OBJLIST_CONFIG_AUX)) == | ||
185 | (FSCACHE_OBJLIST_CONFIG_KEY | FSCACHE_OBJLIST_CONFIG_AUX)) | ||
186 | seq_puts(m, ", "); | ||
187 | if (config & FSCACHE_OBJLIST_CONFIG_AUX) | ||
188 | seq_puts(m, "AUX_DATA"); | ||
189 | seq_puts(m, "\n"); | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | if ((unsigned long) v == 2) { | ||
194 | seq_puts(m, "======== ======== ==== ===== === === === == =====" | ||
195 | " == == = =" | ||
196 | " | ================ == == ================"); | ||
197 | if (config & (FSCACHE_OBJLIST_CONFIG_KEY | | ||
198 | FSCACHE_OBJLIST_CONFIG_AUX)) | ||
199 | seq_puts(m, " ================"); | ||
200 | seq_puts(m, "\n"); | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | /* filter out any unwanted objects */ | ||
205 | #define FILTER(criterion, _yes, _no) \ | ||
206 | do { \ | ||
207 | unsigned long yes = FSCACHE_OBJLIST_CONFIG_##_yes; \ | ||
208 | unsigned long no = FSCACHE_OBJLIST_CONFIG_##_no; \ | ||
209 | if (criterion) { \ | ||
210 | if (!(config & yes)) \ | ||
211 | return 0; \ | ||
212 | } else { \ | ||
213 | if (!(config & no)) \ | ||
214 | return 0; \ | ||
215 | } \ | ||
216 | } while(0) | ||
217 | |||
218 | if (~config) { | ||
219 | FILTER(obj->cookie, | ||
220 | COOKIE, NOCOOKIE); | ||
221 | FILTER(obj->state != FSCACHE_OBJECT_ACTIVE || | ||
222 | obj->n_ops != 0 || | ||
223 | obj->n_obj_ops != 0 || | ||
224 | obj->flags || | ||
225 | !list_empty(&obj->dependents), | ||
226 | BUSY, IDLE); | ||
227 | FILTER(test_bit(FSCACHE_OBJECT_PENDING_WRITE, &obj->flags), | ||
228 | PENDWR, NOPENDWR); | ||
229 | FILTER(atomic_read(&obj->n_reads), | ||
230 | READS, NOREADS); | ||
231 | FILTER(obj->events & obj->event_mask, | ||
232 | EVENTS, NOEVENTS); | ||
233 | FILTER(obj->work.flags & ~(1UL << SLOW_WORK_VERY_SLOW), | ||
234 | WORK, NOWORK); | ||
235 | } | ||
236 | |||
237 | seq_printf(m, | ||
238 | "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1lx | ", | ||
239 | obj->debug_id, | ||
240 | obj->parent ? obj->parent->debug_id : -1, | ||
241 | fscache_object_states_short[obj->state], | ||
242 | obj->n_children, | ||
243 | obj->n_ops, | ||
244 | obj->n_obj_ops, | ||
245 | obj->n_in_progress, | ||
246 | obj->n_exclusive, | ||
247 | atomic_read(&obj->n_reads), | ||
248 | obj->event_mask & FSCACHE_OBJECT_EVENTS_MASK, | ||
249 | obj->events, | ||
250 | obj->flags, | ||
251 | obj->work.flags); | ||
252 | |||
253 | no_cookie = true; | ||
254 | keylen = auxlen = 0; | ||
255 | if (obj->cookie) { | ||
256 | spin_lock(&obj->lock); | ||
257 | if (obj->cookie) { | ||
258 | switch (obj->cookie->def->type) { | ||
259 | case 0: | ||
260 | type = "IX"; | ||
261 | break; | ||
262 | case 1: | ||
263 | type = "DT"; | ||
264 | break; | ||
265 | default: | ||
266 | sprintf(_type, "%02u", | ||
267 | obj->cookie->def->type); | ||
268 | type = _type; | ||
269 | break; | ||
270 | } | ||
271 | |||
272 | seq_printf(m, "%-16s %s %2lx %16p", | ||
273 | obj->cookie->def->name, | ||
274 | type, | ||
275 | obj->cookie->flags, | ||
276 | obj->cookie->netfs_data); | ||
277 | |||
278 | if (obj->cookie->def->get_key && | ||
279 | config & FSCACHE_OBJLIST_CONFIG_KEY) | ||
280 | keylen = obj->cookie->def->get_key( | ||
281 | obj->cookie->netfs_data, | ||
282 | buf, 400); | ||
283 | |||
284 | if (obj->cookie->def->get_aux && | ||
285 | config & FSCACHE_OBJLIST_CONFIG_AUX) | ||
286 | auxlen = obj->cookie->def->get_aux( | ||
287 | obj->cookie->netfs_data, | ||
288 | buf + keylen, 512 - keylen); | ||
289 | |||
290 | no_cookie = false; | ||
291 | } | ||
292 | spin_unlock(&obj->lock); | ||
293 | |||
294 | if (!no_cookie && (keylen > 0 || auxlen > 0)) { | ||
295 | seq_printf(m, " "); | ||
296 | for (p = buf; keylen > 0; keylen--) | ||
297 | seq_printf(m, "%02x", *p++); | ||
298 | if (auxlen > 0) { | ||
299 | if (config & FSCACHE_OBJLIST_CONFIG_KEY) | ||
300 | seq_printf(m, ", "); | ||
301 | for (; auxlen > 0; auxlen--) | ||
302 | seq_printf(m, "%02x", *p++); | ||
303 | } | ||
304 | } | ||
305 | } | ||
306 | |||
307 | if (no_cookie) | ||
308 | seq_printf(m, "<no_cookie>\n"); | ||
309 | else | ||
310 | seq_printf(m, "\n"); | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static const struct seq_operations fscache_objlist_ops = { | ||
315 | .start = fscache_objlist_start, | ||
316 | .stop = fscache_objlist_stop, | ||
317 | .next = fscache_objlist_next, | ||
318 | .show = fscache_objlist_show, | ||
319 | }; | ||
320 | |||
321 | /* | ||
322 | * get the configuration for filtering the list | ||
323 | */ | ||
324 | static void fscache_objlist_config(struct fscache_objlist_data *data) | ||
325 | { | ||
326 | #ifdef CONFIG_KEYS | ||
327 | struct user_key_payload *confkey; | ||
328 | unsigned long config; | ||
329 | struct key *key; | ||
330 | const char *buf; | ||
331 | int len; | ||
332 | |||
333 | key = request_key(&key_type_user, "fscache:objlist", NULL); | ||
334 | if (IS_ERR(key)) | ||
335 | goto no_config; | ||
336 | |||
337 | config = 0; | ||
338 | rcu_read_lock(); | ||
339 | |||
340 | confkey = key->payload.data; | ||
341 | buf = confkey->data; | ||
342 | |||
343 | for (len = confkey->datalen - 1; len >= 0; len--) { | ||
344 | switch (buf[len]) { | ||
345 | case 'K': config |= FSCACHE_OBJLIST_CONFIG_KEY; break; | ||
346 | case 'A': config |= FSCACHE_OBJLIST_CONFIG_AUX; break; | ||
347 | case 'C': config |= FSCACHE_OBJLIST_CONFIG_COOKIE; break; | ||
348 | case 'c': config |= FSCACHE_OBJLIST_CONFIG_NOCOOKIE; break; | ||
349 | case 'B': config |= FSCACHE_OBJLIST_CONFIG_BUSY; break; | ||
350 | case 'b': config |= FSCACHE_OBJLIST_CONFIG_IDLE; break; | ||
351 | case 'W': config |= FSCACHE_OBJLIST_CONFIG_PENDWR; break; | ||
352 | case 'w': config |= FSCACHE_OBJLIST_CONFIG_NOPENDWR; break; | ||
353 | case 'R': config |= FSCACHE_OBJLIST_CONFIG_READS; break; | ||
354 | case 'r': config |= FSCACHE_OBJLIST_CONFIG_NOREADS; break; | ||
355 | case 'S': config |= FSCACHE_OBJLIST_CONFIG_WORK; break; | ||
356 | case 's': config |= FSCACHE_OBJLIST_CONFIG_NOWORK; break; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | rcu_read_unlock(); | ||
361 | key_put(key); | ||
362 | |||
363 | if (!(config & (FSCACHE_OBJLIST_CONFIG_COOKIE | FSCACHE_OBJLIST_CONFIG_NOCOOKIE))) | ||
364 | config |= FSCACHE_OBJLIST_CONFIG_COOKIE | FSCACHE_OBJLIST_CONFIG_NOCOOKIE; | ||
365 | if (!(config & (FSCACHE_OBJLIST_CONFIG_BUSY | FSCACHE_OBJLIST_CONFIG_IDLE))) | ||
366 | config |= FSCACHE_OBJLIST_CONFIG_BUSY | FSCACHE_OBJLIST_CONFIG_IDLE; | ||
367 | if (!(config & (FSCACHE_OBJLIST_CONFIG_PENDWR | FSCACHE_OBJLIST_CONFIG_NOPENDWR))) | ||
368 | config |= FSCACHE_OBJLIST_CONFIG_PENDWR | FSCACHE_OBJLIST_CONFIG_NOPENDWR; | ||
369 | if (!(config & (FSCACHE_OBJLIST_CONFIG_READS | FSCACHE_OBJLIST_CONFIG_NOREADS))) | ||
370 | config |= FSCACHE_OBJLIST_CONFIG_READS | FSCACHE_OBJLIST_CONFIG_NOREADS; | ||
371 | if (!(config & (FSCACHE_OBJLIST_CONFIG_EVENTS | FSCACHE_OBJLIST_CONFIG_NOEVENTS))) | ||
372 | config |= FSCACHE_OBJLIST_CONFIG_EVENTS | FSCACHE_OBJLIST_CONFIG_NOEVENTS; | ||
373 | if (!(config & (FSCACHE_OBJLIST_CONFIG_WORK | FSCACHE_OBJLIST_CONFIG_NOWORK))) | ||
374 | config |= FSCACHE_OBJLIST_CONFIG_WORK | FSCACHE_OBJLIST_CONFIG_NOWORK; | ||
375 | |||
376 | data->config = config; | ||
377 | return; | ||
378 | |||
379 | no_config: | ||
380 | #endif | ||
381 | data->config = ULONG_MAX; | ||
382 | } | ||
383 | |||
384 | /* | ||
385 | * open "/proc/fs/fscache/objects" to provide a list of active objects | ||
386 | * - can be configured by a user-defined key added to the caller's keyrings | ||
387 | */ | ||
388 | static int fscache_objlist_open(struct inode *inode, struct file *file) | ||
389 | { | ||
390 | struct fscache_objlist_data *data; | ||
391 | struct seq_file *m; | ||
392 | int ret; | ||
393 | |||
394 | ret = seq_open(file, &fscache_objlist_ops); | ||
395 | if (ret < 0) | ||
396 | return ret; | ||
397 | |||
398 | m = file->private_data; | ||
399 | |||
400 | /* buffer for key extraction */ | ||
401 | data = kmalloc(sizeof(struct fscache_objlist_data), GFP_KERNEL); | ||
402 | if (!data) { | ||
403 | seq_release(inode, file); | ||
404 | return -ENOMEM; | ||
405 | } | ||
406 | |||
407 | /* get the configuration key */ | ||
408 | fscache_objlist_config(data); | ||
409 | |||
410 | m->private = data; | ||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | /* | ||
415 | * clean up on close | ||
416 | */ | ||
417 | static int fscache_objlist_release(struct inode *inode, struct file *file) | ||
418 | { | ||
419 | struct seq_file *m = file->private_data; | ||
420 | |||
421 | kfree(m->private); | ||
422 | m->private = NULL; | ||
423 | return seq_release(inode, file); | ||
424 | } | ||
425 | |||
426 | const struct file_operations fscache_objlist_fops = { | ||
427 | .owner = THIS_MODULE, | ||
428 | .open = fscache_objlist_open, | ||
429 | .read = seq_read, | ||
430 | .llseek = seq_lseek, | ||
431 | .release = fscache_objlist_release, | ||
432 | }; | ||
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 392a41b1b79d..e513ac599c8e 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -14,9 +14,10 @@ | |||
14 | 14 | ||
15 | #define FSCACHE_DEBUG_LEVEL COOKIE | 15 | #define FSCACHE_DEBUG_LEVEL COOKIE |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/seq_file.h> | ||
17 | #include "internal.h" | 18 | #include "internal.h" |
18 | 19 | ||
19 | const char *fscache_object_states[] = { | 20 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { |
20 | [FSCACHE_OBJECT_INIT] = "OBJECT_INIT", | 21 | [FSCACHE_OBJECT_INIT] = "OBJECT_INIT", |
21 | [FSCACHE_OBJECT_LOOKING_UP] = "OBJECT_LOOKING_UP", | 22 | [FSCACHE_OBJECT_LOOKING_UP] = "OBJECT_LOOKING_UP", |
22 | [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", | 23 | [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", |
@@ -33,9 +34,28 @@ const char *fscache_object_states[] = { | |||
33 | }; | 34 | }; |
34 | EXPORT_SYMBOL(fscache_object_states); | 35 | EXPORT_SYMBOL(fscache_object_states); |
35 | 36 | ||
37 | const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = { | ||
38 | [FSCACHE_OBJECT_INIT] = "INIT", | ||
39 | [FSCACHE_OBJECT_LOOKING_UP] = "LOOK", | ||
40 | [FSCACHE_OBJECT_CREATING] = "CRTN", | ||
41 | [FSCACHE_OBJECT_AVAILABLE] = "AVBL", | ||
42 | [FSCACHE_OBJECT_ACTIVE] = "ACTV", | ||
43 | [FSCACHE_OBJECT_UPDATING] = "UPDT", | ||
44 | [FSCACHE_OBJECT_DYING] = "DYNG", | ||
45 | [FSCACHE_OBJECT_LC_DYING] = "LCDY", | ||
46 | [FSCACHE_OBJECT_ABORT_INIT] = "ABTI", | ||
47 | [FSCACHE_OBJECT_RELEASING] = "RELS", | ||
48 | [FSCACHE_OBJECT_RECYCLING] = "RCYC", | ||
49 | [FSCACHE_OBJECT_WITHDRAWING] = "WTHD", | ||
50 | [FSCACHE_OBJECT_DEAD] = "DEAD", | ||
51 | }; | ||
52 | |||
36 | static void fscache_object_slow_work_put_ref(struct slow_work *); | 53 | static void fscache_object_slow_work_put_ref(struct slow_work *); |
37 | static int fscache_object_slow_work_get_ref(struct slow_work *); | 54 | static int fscache_object_slow_work_get_ref(struct slow_work *); |
38 | static void fscache_object_slow_work_execute(struct slow_work *); | 55 | static void fscache_object_slow_work_execute(struct slow_work *); |
56 | #ifdef CONFIG_SLOW_WORK_PROC | ||
57 | static void fscache_object_slow_work_desc(struct slow_work *, struct seq_file *); | ||
58 | #endif | ||
39 | static void fscache_initialise_object(struct fscache_object *); | 59 | static void fscache_initialise_object(struct fscache_object *); |
40 | static void fscache_lookup_object(struct fscache_object *); | 60 | static void fscache_lookup_object(struct fscache_object *); |
41 | static void fscache_object_available(struct fscache_object *); | 61 | static void fscache_object_available(struct fscache_object *); |
@@ -45,9 +65,13 @@ static void fscache_enqueue_dependents(struct fscache_object *); | |||
45 | static void fscache_dequeue_object(struct fscache_object *); | 65 | static void fscache_dequeue_object(struct fscache_object *); |
46 | 66 | ||
47 | const struct slow_work_ops fscache_object_slow_work_ops = { | 67 | const struct slow_work_ops fscache_object_slow_work_ops = { |
68 | .owner = THIS_MODULE, | ||
48 | .get_ref = fscache_object_slow_work_get_ref, | 69 | .get_ref = fscache_object_slow_work_get_ref, |
49 | .put_ref = fscache_object_slow_work_put_ref, | 70 | .put_ref = fscache_object_slow_work_put_ref, |
50 | .execute = fscache_object_slow_work_execute, | 71 | .execute = fscache_object_slow_work_execute, |
72 | #ifdef CONFIG_SLOW_WORK_PROC | ||
73 | .desc = fscache_object_slow_work_desc, | ||
74 | #endif | ||
51 | }; | 75 | }; |
52 | EXPORT_SYMBOL(fscache_object_slow_work_ops); | 76 | EXPORT_SYMBOL(fscache_object_slow_work_ops); |
53 | 77 | ||
@@ -81,6 +105,7 @@ static inline void fscache_done_parent_op(struct fscache_object *object) | |||
81 | static void fscache_object_state_machine(struct fscache_object *object) | 105 | static void fscache_object_state_machine(struct fscache_object *object) |
82 | { | 106 | { |
83 | enum fscache_object_state new_state; | 107 | enum fscache_object_state new_state; |
108 | struct fscache_cookie *cookie; | ||
84 | 109 | ||
85 | ASSERT(object != NULL); | 110 | ASSERT(object != NULL); |
86 | 111 | ||
@@ -120,20 +145,31 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
120 | case FSCACHE_OBJECT_UPDATING: | 145 | case FSCACHE_OBJECT_UPDATING: |
121 | clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); | 146 | clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); |
122 | fscache_stat(&fscache_n_updates_run); | 147 | fscache_stat(&fscache_n_updates_run); |
148 | fscache_stat(&fscache_n_cop_update_object); | ||
123 | object->cache->ops->update_object(object); | 149 | object->cache->ops->update_object(object); |
150 | fscache_stat_d(&fscache_n_cop_update_object); | ||
124 | goto active_transit; | 151 | goto active_transit; |
125 | 152 | ||
126 | /* handle an object dying during lookup or creation */ | 153 | /* handle an object dying during lookup or creation */ |
127 | case FSCACHE_OBJECT_LC_DYING: | 154 | case FSCACHE_OBJECT_LC_DYING: |
128 | object->event_mask &= ~(1 << FSCACHE_OBJECT_EV_UPDATE); | 155 | object->event_mask &= ~(1 << FSCACHE_OBJECT_EV_UPDATE); |
156 | fscache_stat(&fscache_n_cop_lookup_complete); | ||
129 | object->cache->ops->lookup_complete(object); | 157 | object->cache->ops->lookup_complete(object); |
158 | fscache_stat_d(&fscache_n_cop_lookup_complete); | ||
130 | 159 | ||
131 | spin_lock(&object->lock); | 160 | spin_lock(&object->lock); |
132 | object->state = FSCACHE_OBJECT_DYING; | 161 | object->state = FSCACHE_OBJECT_DYING; |
133 | if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, | 162 | cookie = object->cookie; |
134 | &object->cookie->flags)) | 163 | if (cookie) { |
135 | wake_up_bit(&object->cookie->flags, | 164 | if (test_and_clear_bit(FSCACHE_COOKIE_LOOKING_UP, |
136 | FSCACHE_COOKIE_CREATING); | 165 | &cookie->flags)) |
166 | wake_up_bit(&cookie->flags, | ||
167 | FSCACHE_COOKIE_LOOKING_UP); | ||
168 | if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, | ||
169 | &cookie->flags)) | ||
170 | wake_up_bit(&cookie->flags, | ||
171 | FSCACHE_COOKIE_CREATING); | ||
172 | } | ||
137 | spin_unlock(&object->lock); | 173 | spin_unlock(&object->lock); |
138 | 174 | ||
139 | fscache_done_parent_op(object); | 175 | fscache_done_parent_op(object); |
@@ -165,6 +201,7 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
165 | } | 201 | } |
166 | spin_unlock(&object->lock); | 202 | spin_unlock(&object->lock); |
167 | fscache_enqueue_dependents(object); | 203 | fscache_enqueue_dependents(object); |
204 | fscache_start_operations(object); | ||
168 | goto terminal_transit; | 205 | goto terminal_transit; |
169 | 206 | ||
170 | /* handle an abort during initialisation */ | 207 | /* handle an abort during initialisation */ |
@@ -316,14 +353,29 @@ static void fscache_object_slow_work_execute(struct slow_work *work) | |||
316 | 353 | ||
317 | _enter("{OBJ%x}", object->debug_id); | 354 | _enter("{OBJ%x}", object->debug_id); |
318 | 355 | ||
319 | clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | ||
320 | |||
321 | start = jiffies; | 356 | start = jiffies; |
322 | fscache_object_state_machine(object); | 357 | fscache_object_state_machine(object); |
323 | fscache_hist(fscache_objs_histogram, start); | 358 | fscache_hist(fscache_objs_histogram, start); |
324 | if (object->events & object->event_mask) | 359 | if (object->events & object->event_mask) |
325 | fscache_enqueue_object(object); | 360 | fscache_enqueue_object(object); |
361 | clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * describe an object for slow-work debugging | ||
366 | */ | ||
367 | #ifdef CONFIG_SLOW_WORK_PROC | ||
368 | static void fscache_object_slow_work_desc(struct slow_work *work, | ||
369 | struct seq_file *m) | ||
370 | { | ||
371 | struct fscache_object *object = | ||
372 | container_of(work, struct fscache_object, work); | ||
373 | |||
374 | seq_printf(m, "FSC: OBJ%x: %s", | ||
375 | object->debug_id, | ||
376 | fscache_object_states_short[object->state]); | ||
326 | } | 377 | } |
378 | #endif | ||
327 | 379 | ||
328 | /* | 380 | /* |
329 | * initialise an object | 381 | * initialise an object |
@@ -376,7 +428,9 @@ static void fscache_initialise_object(struct fscache_object *object) | |||
376 | * binding on to us, so we need to make sure we don't | 428 | * binding on to us, so we need to make sure we don't |
377 | * add ourself to the list multiple times */ | 429 | * add ourself to the list multiple times */ |
378 | if (list_empty(&object->dep_link)) { | 430 | if (list_empty(&object->dep_link)) { |
431 | fscache_stat(&fscache_n_cop_grab_object); | ||
379 | object->cache->ops->grab_object(object); | 432 | object->cache->ops->grab_object(object); |
433 | fscache_stat_d(&fscache_n_cop_grab_object); | ||
380 | list_add(&object->dep_link, | 434 | list_add(&object->dep_link, |
381 | &parent->dependents); | 435 | &parent->dependents); |
382 | 436 | ||
@@ -414,6 +468,7 @@ static void fscache_lookup_object(struct fscache_object *object) | |||
414 | { | 468 | { |
415 | struct fscache_cookie *cookie = object->cookie; | 469 | struct fscache_cookie *cookie = object->cookie; |
416 | struct fscache_object *parent; | 470 | struct fscache_object *parent; |
471 | int ret; | ||
417 | 472 | ||
418 | _enter(""); | 473 | _enter(""); |
419 | 474 | ||
@@ -438,11 +493,20 @@ static void fscache_lookup_object(struct fscache_object *object) | |||
438 | object->cache->tag->name); | 493 | object->cache->tag->name); |
439 | 494 | ||
440 | fscache_stat(&fscache_n_object_lookups); | 495 | fscache_stat(&fscache_n_object_lookups); |
441 | object->cache->ops->lookup_object(object); | 496 | fscache_stat(&fscache_n_cop_lookup_object); |
497 | ret = object->cache->ops->lookup_object(object); | ||
498 | fscache_stat_d(&fscache_n_cop_lookup_object); | ||
442 | 499 | ||
443 | if (test_bit(FSCACHE_OBJECT_EV_ERROR, &object->events)) | 500 | if (test_bit(FSCACHE_OBJECT_EV_ERROR, &object->events)) |
444 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); | 501 | set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); |
445 | 502 | ||
503 | if (ret == -ETIMEDOUT) { | ||
504 | /* probably stuck behind another object, so move this one to | ||
505 | * the back of the queue */ | ||
506 | fscache_stat(&fscache_n_object_lookups_timed_out); | ||
507 | set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); | ||
508 | } | ||
509 | |||
446 | _leave(""); | 510 | _leave(""); |
447 | } | 511 | } |
448 | 512 | ||
@@ -546,7 +610,8 @@ static void fscache_object_available(struct fscache_object *object) | |||
546 | 610 | ||
547 | spin_lock(&object->lock); | 611 | spin_lock(&object->lock); |
548 | 612 | ||
549 | if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, &object->cookie->flags)) | 613 | if (object->cookie && |
614 | test_and_clear_bit(FSCACHE_COOKIE_CREATING, &object->cookie->flags)) | ||
550 | wake_up_bit(&object->cookie->flags, FSCACHE_COOKIE_CREATING); | 615 | wake_up_bit(&object->cookie->flags, FSCACHE_COOKIE_CREATING); |
551 | 616 | ||
552 | fscache_done_parent_op(object); | 617 | fscache_done_parent_op(object); |
@@ -562,7 +627,9 @@ static void fscache_object_available(struct fscache_object *object) | |||
562 | } | 627 | } |
563 | spin_unlock(&object->lock); | 628 | spin_unlock(&object->lock); |
564 | 629 | ||
630 | fscache_stat(&fscache_n_cop_lookup_complete); | ||
565 | object->cache->ops->lookup_complete(object); | 631 | object->cache->ops->lookup_complete(object); |
632 | fscache_stat_d(&fscache_n_cop_lookup_complete); | ||
566 | fscache_enqueue_dependents(object); | 633 | fscache_enqueue_dependents(object); |
567 | 634 | ||
568 | fscache_hist(fscache_obj_instantiate_histogram, object->lookup_jif); | 635 | fscache_hist(fscache_obj_instantiate_histogram, object->lookup_jif); |
@@ -581,11 +648,16 @@ static void fscache_drop_object(struct fscache_object *object) | |||
581 | 648 | ||
582 | _enter("{OBJ%x,%d}", object->debug_id, object->n_children); | 649 | _enter("{OBJ%x,%d}", object->debug_id, object->n_children); |
583 | 650 | ||
651 | ASSERTCMP(object->cookie, ==, NULL); | ||
652 | ASSERT(hlist_unhashed(&object->cookie_link)); | ||
653 | |||
584 | spin_lock(&cache->object_list_lock); | 654 | spin_lock(&cache->object_list_lock); |
585 | list_del_init(&object->cache_link); | 655 | list_del_init(&object->cache_link); |
586 | spin_unlock(&cache->object_list_lock); | 656 | spin_unlock(&cache->object_list_lock); |
587 | 657 | ||
658 | fscache_stat(&fscache_n_cop_drop_object); | ||
588 | cache->ops->drop_object(object); | 659 | cache->ops->drop_object(object); |
660 | fscache_stat_d(&fscache_n_cop_drop_object); | ||
589 | 661 | ||
590 | if (parent) { | 662 | if (parent) { |
591 | _debug("release parent OBJ%x {%d}", | 663 | _debug("release parent OBJ%x {%d}", |
@@ -600,7 +672,9 @@ static void fscache_drop_object(struct fscache_object *object) | |||
600 | } | 672 | } |
601 | 673 | ||
602 | /* this just shifts the object release to the slow work processor */ | 674 | /* this just shifts the object release to the slow work processor */ |
675 | fscache_stat(&fscache_n_cop_put_object); | ||
603 | object->cache->ops->put_object(object); | 676 | object->cache->ops->put_object(object); |
677 | fscache_stat_d(&fscache_n_cop_put_object); | ||
604 | 678 | ||
605 | _leave(""); | 679 | _leave(""); |
606 | } | 680 | } |
@@ -690,8 +764,12 @@ static int fscache_object_slow_work_get_ref(struct slow_work *work) | |||
690 | { | 764 | { |
691 | struct fscache_object *object = | 765 | struct fscache_object *object = |
692 | container_of(work, struct fscache_object, work); | 766 | container_of(work, struct fscache_object, work); |
767 | int ret; | ||
693 | 768 | ||
694 | return object->cache->ops->grab_object(object) ? 0 : -EAGAIN; | 769 | fscache_stat(&fscache_n_cop_grab_object); |
770 | ret = object->cache->ops->grab_object(object) ? 0 : -EAGAIN; | ||
771 | fscache_stat_d(&fscache_n_cop_grab_object); | ||
772 | return ret; | ||
695 | } | 773 | } |
696 | 774 | ||
697 | /* | 775 | /* |
@@ -702,7 +780,9 @@ static void fscache_object_slow_work_put_ref(struct slow_work *work) | |||
702 | struct fscache_object *object = | 780 | struct fscache_object *object = |
703 | container_of(work, struct fscache_object, work); | 781 | container_of(work, struct fscache_object, work); |
704 | 782 | ||
705 | return object->cache->ops->put_object(object); | 783 | fscache_stat(&fscache_n_cop_put_object); |
784 | object->cache->ops->put_object(object); | ||
785 | fscache_stat_d(&fscache_n_cop_put_object); | ||
706 | } | 786 | } |
707 | 787 | ||
708 | /* | 788 | /* |
@@ -739,7 +819,9 @@ static void fscache_enqueue_dependents(struct fscache_object *object) | |||
739 | 819 | ||
740 | /* sort onto appropriate lists */ | 820 | /* sort onto appropriate lists */ |
741 | fscache_enqueue_object(dep); | 821 | fscache_enqueue_object(dep); |
822 | fscache_stat(&fscache_n_cop_put_object); | ||
742 | dep->cache->ops->put_object(dep); | 823 | dep->cache->ops->put_object(dep); |
824 | fscache_stat_d(&fscache_n_cop_put_object); | ||
743 | 825 | ||
744 | if (!list_empty(&object->dependents)) | 826 | if (!list_empty(&object->dependents)) |
745 | cond_resched_lock(&object->lock); | 827 | cond_resched_lock(&object->lock); |
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index e7f8d53b8b6b..313e79a14266 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #define FSCACHE_DEBUG_LEVEL OPERATION | 14 | #define FSCACHE_DEBUG_LEVEL OPERATION |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/seq_file.h> | ||
16 | #include "internal.h" | 17 | #include "internal.h" |
17 | 18 | ||
18 | atomic_t fscache_op_debug_id; | 19 | atomic_t fscache_op_debug_id; |
@@ -31,32 +32,33 @@ void fscache_enqueue_operation(struct fscache_operation *op) | |||
31 | _enter("{OBJ%x OP%x,%u}", | 32 | _enter("{OBJ%x OP%x,%u}", |
32 | op->object->debug_id, op->debug_id, atomic_read(&op->usage)); | 33 | op->object->debug_id, op->debug_id, atomic_read(&op->usage)); |
33 | 34 | ||
35 | fscache_set_op_state(op, "EnQ"); | ||
36 | |||
37 | ASSERT(list_empty(&op->pend_link)); | ||
34 | ASSERT(op->processor != NULL); | 38 | ASSERT(op->processor != NULL); |
35 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); | 39 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); |
36 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 40 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
37 | 41 | ||
38 | if (list_empty(&op->pend_link)) { | 42 | fscache_stat(&fscache_n_op_enqueue); |
39 | switch (op->flags & FSCACHE_OP_TYPE) { | 43 | switch (op->flags & FSCACHE_OP_TYPE) { |
40 | case FSCACHE_OP_FAST: | 44 | case FSCACHE_OP_FAST: |
41 | _debug("queue fast"); | 45 | _debug("queue fast"); |
42 | atomic_inc(&op->usage); | 46 | atomic_inc(&op->usage); |
43 | if (!schedule_work(&op->fast_work)) | 47 | if (!schedule_work(&op->fast_work)) |
44 | fscache_put_operation(op); | 48 | fscache_put_operation(op); |
45 | break; | 49 | break; |
46 | case FSCACHE_OP_SLOW: | 50 | case FSCACHE_OP_SLOW: |
47 | _debug("queue slow"); | 51 | _debug("queue slow"); |
48 | slow_work_enqueue(&op->slow_work); | 52 | slow_work_enqueue(&op->slow_work); |
49 | break; | 53 | break; |
50 | case FSCACHE_OP_MYTHREAD: | 54 | case FSCACHE_OP_MYTHREAD: |
51 | _debug("queue for caller's attention"); | 55 | _debug("queue for caller's attention"); |
52 | break; | 56 | break; |
53 | default: | 57 | default: |
54 | printk(KERN_ERR "FS-Cache: Unexpected op type %lx", | 58 | printk(KERN_ERR "FS-Cache: Unexpected op type %lx", |
55 | op->flags); | 59 | op->flags); |
56 | BUG(); | 60 | BUG(); |
57 | break; | 61 | break; |
58 | } | ||
59 | fscache_stat(&fscache_n_op_enqueue); | ||
60 | } | 62 | } |
61 | } | 63 | } |
62 | EXPORT_SYMBOL(fscache_enqueue_operation); | 64 | EXPORT_SYMBOL(fscache_enqueue_operation); |
@@ -67,6 +69,8 @@ EXPORT_SYMBOL(fscache_enqueue_operation); | |||
67 | static void fscache_run_op(struct fscache_object *object, | 69 | static void fscache_run_op(struct fscache_object *object, |
68 | struct fscache_operation *op) | 70 | struct fscache_operation *op) |
69 | { | 71 | { |
72 | fscache_set_op_state(op, "Run"); | ||
73 | |||
70 | object->n_in_progress++; | 74 | object->n_in_progress++; |
71 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | 75 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) |
72 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | 76 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); |
@@ -87,9 +91,12 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
87 | 91 | ||
88 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); | 92 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); |
89 | 93 | ||
94 | fscache_set_op_state(op, "SubmitX"); | ||
95 | |||
90 | spin_lock(&object->lock); | 96 | spin_lock(&object->lock); |
91 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); | 97 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); |
92 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); | 98 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); |
99 | ASSERT(list_empty(&op->pend_link)); | ||
93 | 100 | ||
94 | ret = -ENOBUFS; | 101 | ret = -ENOBUFS; |
95 | if (fscache_object_is_active(object)) { | 102 | if (fscache_object_is_active(object)) { |
@@ -190,9 +197,12 @@ int fscache_submit_op(struct fscache_object *object, | |||
190 | 197 | ||
191 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 198 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
192 | 199 | ||
200 | fscache_set_op_state(op, "Submit"); | ||
201 | |||
193 | spin_lock(&object->lock); | 202 | spin_lock(&object->lock); |
194 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); | 203 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); |
195 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); | 204 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); |
205 | ASSERT(list_empty(&op->pend_link)); | ||
196 | 206 | ||
197 | ostate = object->state; | 207 | ostate = object->state; |
198 | smp_rmb(); | 208 | smp_rmb(); |
@@ -222,6 +232,11 @@ int fscache_submit_op(struct fscache_object *object, | |||
222 | list_add_tail(&op->pend_link, &object->pending_ops); | 232 | list_add_tail(&op->pend_link, &object->pending_ops); |
223 | fscache_stat(&fscache_n_op_pend); | 233 | fscache_stat(&fscache_n_op_pend); |
224 | ret = 0; | 234 | ret = 0; |
235 | } else if (object->state == FSCACHE_OBJECT_DYING || | ||
236 | object->state == FSCACHE_OBJECT_LC_DYING || | ||
237 | object->state == FSCACHE_OBJECT_WITHDRAWING) { | ||
238 | fscache_stat(&fscache_n_op_rejected); | ||
239 | ret = -ENOBUFS; | ||
225 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { | 240 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { |
226 | fscache_report_unexpected_submission(object, op, ostate); | 241 | fscache_report_unexpected_submission(object, op, ostate); |
227 | ASSERT(!fscache_object_is_active(object)); | 242 | ASSERT(!fscache_object_is_active(object)); |
@@ -264,12 +279,7 @@ void fscache_start_operations(struct fscache_object *object) | |||
264 | stop = true; | 279 | stop = true; |
265 | } | 280 | } |
266 | list_del_init(&op->pend_link); | 281 | list_del_init(&op->pend_link); |
267 | object->n_in_progress++; | 282 | fscache_run_op(object, op); |
268 | |||
269 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | ||
270 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | ||
271 | if (op->processor) | ||
272 | fscache_enqueue_operation(op); | ||
273 | 283 | ||
274 | /* the pending queue was holding a ref on the object */ | 284 | /* the pending queue was holding a ref on the object */ |
275 | fscache_put_operation(op); | 285 | fscache_put_operation(op); |
@@ -282,6 +292,36 @@ void fscache_start_operations(struct fscache_object *object) | |||
282 | } | 292 | } |
283 | 293 | ||
284 | /* | 294 | /* |
295 | * cancel an operation that's pending on an object | ||
296 | */ | ||
297 | int fscache_cancel_op(struct fscache_operation *op) | ||
298 | { | ||
299 | struct fscache_object *object = op->object; | ||
300 | int ret; | ||
301 | |||
302 | _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); | ||
303 | |||
304 | spin_lock(&object->lock); | ||
305 | |||
306 | ret = -EBUSY; | ||
307 | if (!list_empty(&op->pend_link)) { | ||
308 | fscache_stat(&fscache_n_op_cancelled); | ||
309 | list_del_init(&op->pend_link); | ||
310 | object->n_ops--; | ||
311 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | ||
312 | object->n_exclusive--; | ||
313 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | ||
314 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | ||
315 | fscache_put_operation(op); | ||
316 | ret = 0; | ||
317 | } | ||
318 | |||
319 | spin_unlock(&object->lock); | ||
320 | _leave(" = %d", ret); | ||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | /* | ||
285 | * release an operation | 325 | * release an operation |
286 | * - queues pending ops if this is the last in-progress op | 326 | * - queues pending ops if this is the last in-progress op |
287 | */ | 327 | */ |
@@ -298,6 +338,8 @@ void fscache_put_operation(struct fscache_operation *op) | |||
298 | if (!atomic_dec_and_test(&op->usage)) | 338 | if (!atomic_dec_and_test(&op->usage)) |
299 | return; | 339 | return; |
300 | 340 | ||
341 | fscache_set_op_state(op, "Put"); | ||
342 | |||
301 | _debug("PUT OP"); | 343 | _debug("PUT OP"); |
302 | if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags)) | 344 | if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags)) |
303 | BUG(); | 345 | BUG(); |
@@ -311,6 +353,9 @@ void fscache_put_operation(struct fscache_operation *op) | |||
311 | 353 | ||
312 | object = op->object; | 354 | object = op->object; |
313 | 355 | ||
356 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) | ||
357 | atomic_dec(&object->n_reads); | ||
358 | |||
314 | /* now... we may get called with the object spinlock held, so we | 359 | /* now... we may get called with the object spinlock held, so we |
315 | * complete the cleanup here only if we can immediately acquire the | 360 | * complete the cleanup here only if we can immediately acquire the |
316 | * lock, and defer it otherwise */ | 361 | * lock, and defer it otherwise */ |
@@ -452,8 +497,27 @@ static void fscache_op_execute(struct slow_work *work) | |||
452 | _leave(""); | 497 | _leave(""); |
453 | } | 498 | } |
454 | 499 | ||
500 | /* | ||
501 | * describe an operation for slow-work debugging | ||
502 | */ | ||
503 | #ifdef CONFIG_SLOW_WORK_PROC | ||
504 | static void fscache_op_desc(struct slow_work *work, struct seq_file *m) | ||
505 | { | ||
506 | struct fscache_operation *op = | ||
507 | container_of(work, struct fscache_operation, slow_work); | ||
508 | |||
509 | seq_printf(m, "FSC: OBJ%x OP%x: %s/%s fl=%lx", | ||
510 | op->object->debug_id, op->debug_id, | ||
511 | op->name, op->state, op->flags); | ||
512 | } | ||
513 | #endif | ||
514 | |||
455 | const struct slow_work_ops fscache_op_slow_work_ops = { | 515 | const struct slow_work_ops fscache_op_slow_work_ops = { |
516 | .owner = THIS_MODULE, | ||
456 | .get_ref = fscache_op_get_ref, | 517 | .get_ref = fscache_op_get_ref, |
457 | .put_ref = fscache_op_put_ref, | 518 | .put_ref = fscache_op_put_ref, |
458 | .execute = fscache_op_execute, | 519 | .execute = fscache_op_execute, |
520 | #ifdef CONFIG_SLOW_WORK_PROC | ||
521 | .desc = fscache_op_desc, | ||
522 | #endif | ||
459 | }; | 523 | }; |
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 2568e0eb644f..c598ea4c4e7d 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -43,18 +43,102 @@ void __fscache_wait_on_page_write(struct fscache_cookie *cookie, struct page *pa | |||
43 | EXPORT_SYMBOL(__fscache_wait_on_page_write); | 43 | EXPORT_SYMBOL(__fscache_wait_on_page_write); |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * note that a page has finished being written to the cache | 46 | * decide whether a page can be released, possibly by cancelling a store to it |
47 | * - we're allowed to sleep if __GFP_WAIT is flagged | ||
47 | */ | 48 | */ |
48 | static void fscache_end_page_write(struct fscache_cookie *cookie, struct page *page) | 49 | bool __fscache_maybe_release_page(struct fscache_cookie *cookie, |
50 | struct page *page, | ||
51 | gfp_t gfp) | ||
49 | { | 52 | { |
50 | struct page *xpage; | 53 | struct page *xpage; |
54 | void *val; | ||
55 | |||
56 | _enter("%p,%p,%x", cookie, page, gfp); | ||
57 | |||
58 | rcu_read_lock(); | ||
59 | val = radix_tree_lookup(&cookie->stores, page->index); | ||
60 | if (!val) { | ||
61 | rcu_read_unlock(); | ||
62 | fscache_stat(&fscache_n_store_vmscan_not_storing); | ||
63 | __fscache_uncache_page(cookie, page); | ||
64 | return true; | ||
65 | } | ||
66 | |||
67 | /* see if the page is actually undergoing storage - if so we can't get | ||
68 | * rid of it till the cache has finished with it */ | ||
69 | if (radix_tree_tag_get(&cookie->stores, page->index, | ||
70 | FSCACHE_COOKIE_STORING_TAG)) { | ||
71 | rcu_read_unlock(); | ||
72 | goto page_busy; | ||
73 | } | ||
74 | |||
75 | /* the page is pending storage, so we attempt to cancel the store and | ||
76 | * discard the store request so that the page can be reclaimed */ | ||
77 | spin_lock(&cookie->stores_lock); | ||
78 | rcu_read_unlock(); | ||
79 | |||
80 | if (radix_tree_tag_get(&cookie->stores, page->index, | ||
81 | FSCACHE_COOKIE_STORING_TAG)) { | ||
82 | /* the page started to undergo storage whilst we were looking, | ||
83 | * so now we can only wait or return */ | ||
84 | spin_unlock(&cookie->stores_lock); | ||
85 | goto page_busy; | ||
86 | } | ||
51 | 87 | ||
52 | spin_lock(&cookie->lock); | ||
53 | xpage = radix_tree_delete(&cookie->stores, page->index); | 88 | xpage = radix_tree_delete(&cookie->stores, page->index); |
54 | spin_unlock(&cookie->lock); | 89 | spin_unlock(&cookie->stores_lock); |
55 | ASSERT(xpage != NULL); | 90 | |
91 | if (xpage) { | ||
92 | fscache_stat(&fscache_n_store_vmscan_cancelled); | ||
93 | fscache_stat(&fscache_n_store_radix_deletes); | ||
94 | ASSERTCMP(xpage, ==, page); | ||
95 | } else { | ||
96 | fscache_stat(&fscache_n_store_vmscan_gone); | ||
97 | } | ||
56 | 98 | ||
57 | wake_up_bit(&cookie->flags, 0); | 99 | wake_up_bit(&cookie->flags, 0); |
100 | if (xpage) | ||
101 | page_cache_release(xpage); | ||
102 | __fscache_uncache_page(cookie, page); | ||
103 | return true; | ||
104 | |||
105 | page_busy: | ||
106 | /* we might want to wait here, but that could deadlock the allocator as | ||
107 | * the slow-work threads writing to the cache may all end up sleeping | ||
108 | * on memory allocation */ | ||
109 | fscache_stat(&fscache_n_store_vmscan_busy); | ||
110 | return false; | ||
111 | } | ||
112 | EXPORT_SYMBOL(__fscache_maybe_release_page); | ||
113 | |||
114 | /* | ||
115 | * note that a page has finished being written to the cache | ||
116 | */ | ||
117 | static void fscache_end_page_write(struct fscache_object *object, | ||
118 | struct page *page) | ||
119 | { | ||
120 | struct fscache_cookie *cookie; | ||
121 | struct page *xpage = NULL; | ||
122 | |||
123 | spin_lock(&object->lock); | ||
124 | cookie = object->cookie; | ||
125 | if (cookie) { | ||
126 | /* delete the page from the tree if it is now no longer | ||
127 | * pending */ | ||
128 | spin_lock(&cookie->stores_lock); | ||
129 | radix_tree_tag_clear(&cookie->stores, page->index, | ||
130 | FSCACHE_COOKIE_STORING_TAG); | ||
131 | if (!radix_tree_tag_get(&cookie->stores, page->index, | ||
132 | FSCACHE_COOKIE_PENDING_TAG)) { | ||
133 | fscache_stat(&fscache_n_store_radix_deletes); | ||
134 | xpage = radix_tree_delete(&cookie->stores, page->index); | ||
135 | } | ||
136 | spin_unlock(&cookie->stores_lock); | ||
137 | wake_up_bit(&cookie->flags, 0); | ||
138 | } | ||
139 | spin_unlock(&object->lock); | ||
140 | if (xpage) | ||
141 | page_cache_release(xpage); | ||
58 | } | 142 | } |
59 | 143 | ||
60 | /* | 144 | /* |
@@ -63,14 +147,21 @@ static void fscache_end_page_write(struct fscache_cookie *cookie, struct page *p | |||
63 | static void fscache_attr_changed_op(struct fscache_operation *op) | 147 | static void fscache_attr_changed_op(struct fscache_operation *op) |
64 | { | 148 | { |
65 | struct fscache_object *object = op->object; | 149 | struct fscache_object *object = op->object; |
150 | int ret; | ||
66 | 151 | ||
67 | _enter("{OBJ%x OP%x}", object->debug_id, op->debug_id); | 152 | _enter("{OBJ%x OP%x}", object->debug_id, op->debug_id); |
68 | 153 | ||
69 | fscache_stat(&fscache_n_attr_changed_calls); | 154 | fscache_stat(&fscache_n_attr_changed_calls); |
70 | 155 | ||
71 | if (fscache_object_is_active(object) && | 156 | if (fscache_object_is_active(object)) { |
72 | object->cache->ops->attr_changed(object) < 0) | 157 | fscache_set_op_state(op, "CallFS"); |
73 | fscache_abort_object(object); | 158 | fscache_stat(&fscache_n_cop_attr_changed); |
159 | ret = object->cache->ops->attr_changed(object); | ||
160 | fscache_stat_d(&fscache_n_cop_attr_changed); | ||
161 | fscache_set_op_state(op, "Done"); | ||
162 | if (ret < 0) | ||
163 | fscache_abort_object(object); | ||
164 | } | ||
74 | 165 | ||
75 | _leave(""); | 166 | _leave(""); |
76 | } | 167 | } |
@@ -99,6 +190,7 @@ int __fscache_attr_changed(struct fscache_cookie *cookie) | |||
99 | fscache_operation_init(op, NULL); | 190 | fscache_operation_init(op, NULL); |
100 | fscache_operation_init_slow(op, fscache_attr_changed_op); | 191 | fscache_operation_init_slow(op, fscache_attr_changed_op); |
101 | op->flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_EXCLUSIVE); | 192 | op->flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_EXCLUSIVE); |
193 | fscache_set_op_name(op, "Attr"); | ||
102 | 194 | ||
103 | spin_lock(&cookie->lock); | 195 | spin_lock(&cookie->lock); |
104 | 196 | ||
@@ -184,6 +276,7 @@ static struct fscache_retrieval *fscache_alloc_retrieval( | |||
184 | op->start_time = jiffies; | 276 | op->start_time = jiffies; |
185 | INIT_WORK(&op->op.fast_work, fscache_retrieval_work); | 277 | INIT_WORK(&op->op.fast_work, fscache_retrieval_work); |
186 | INIT_LIST_HEAD(&op->to_do); | 278 | INIT_LIST_HEAD(&op->to_do); |
279 | fscache_set_op_name(&op->op, "Retr"); | ||
187 | return op; | 280 | return op; |
188 | } | 281 | } |
189 | 282 | ||
@@ -221,6 +314,43 @@ static int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie) | |||
221 | } | 314 | } |
222 | 315 | ||
223 | /* | 316 | /* |
317 | * wait for an object to become active (or dead) | ||
318 | */ | ||
319 | static int fscache_wait_for_retrieval_activation(struct fscache_object *object, | ||
320 | struct fscache_retrieval *op, | ||
321 | atomic_t *stat_op_waits, | ||
322 | atomic_t *stat_object_dead) | ||
323 | { | ||
324 | int ret; | ||
325 | |||
326 | if (!test_bit(FSCACHE_OP_WAITING, &op->op.flags)) | ||
327 | goto check_if_dead; | ||
328 | |||
329 | _debug(">>> WT"); | ||
330 | fscache_stat(stat_op_waits); | ||
331 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | ||
332 | fscache_wait_bit_interruptible, | ||
333 | TASK_INTERRUPTIBLE) < 0) { | ||
334 | ret = fscache_cancel_op(&op->op); | ||
335 | if (ret == 0) | ||
336 | return -ERESTARTSYS; | ||
337 | |||
338 | /* it's been removed from the pending queue by another party, | ||
339 | * so we should get to run shortly */ | ||
340 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | ||
341 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
342 | } | ||
343 | _debug("<<< GO"); | ||
344 | |||
345 | check_if_dead: | ||
346 | if (unlikely(fscache_object_is_dead(object))) { | ||
347 | fscache_stat(stat_object_dead); | ||
348 | return -ENOBUFS; | ||
349 | } | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | /* | ||
224 | * read a page from the cache or allocate a block in which to store it | 354 | * read a page from the cache or allocate a block in which to store it |
225 | * - we return: | 355 | * - we return: |
226 | * -ENOMEM - out of memory, nothing done | 356 | * -ENOMEM - out of memory, nothing done |
@@ -257,6 +387,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
257 | _leave(" = -ENOMEM"); | 387 | _leave(" = -ENOMEM"); |
258 | return -ENOMEM; | 388 | return -ENOMEM; |
259 | } | 389 | } |
390 | fscache_set_op_name(&op->op, "RetrRA1"); | ||
260 | 391 | ||
261 | spin_lock(&cookie->lock); | 392 | spin_lock(&cookie->lock); |
262 | 393 | ||
@@ -267,6 +398,9 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
267 | 398 | ||
268 | ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP); | 399 | ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP); |
269 | 400 | ||
401 | atomic_inc(&object->n_reads); | ||
402 | set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | ||
403 | |||
270 | if (fscache_submit_op(object, &op->op) < 0) | 404 | if (fscache_submit_op(object, &op->op) < 0) |
271 | goto nobufs_unlock; | 405 | goto nobufs_unlock; |
272 | spin_unlock(&cookie->lock); | 406 | spin_unlock(&cookie->lock); |
@@ -279,23 +413,27 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
279 | 413 | ||
280 | /* we wait for the operation to become active, and then process it | 414 | /* we wait for the operation to become active, and then process it |
281 | * *here*, in this thread, and not in the thread pool */ | 415 | * *here*, in this thread, and not in the thread pool */ |
282 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { | 416 | ret = fscache_wait_for_retrieval_activation( |
283 | _debug(">>> WT"); | 417 | object, op, |
284 | fscache_stat(&fscache_n_retrieval_op_waits); | 418 | __fscache_stat(&fscache_n_retrieval_op_waits), |
285 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 419 | __fscache_stat(&fscache_n_retrievals_object_dead)); |
286 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | 420 | if (ret < 0) |
287 | _debug("<<< GO"); | 421 | goto error; |
288 | } | ||
289 | 422 | ||
290 | /* ask the cache to honour the operation */ | 423 | /* ask the cache to honour the operation */ |
291 | if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) { | 424 | if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) { |
425 | fscache_stat(&fscache_n_cop_allocate_page); | ||
292 | ret = object->cache->ops->allocate_page(op, page, gfp); | 426 | ret = object->cache->ops->allocate_page(op, page, gfp); |
427 | fscache_stat_d(&fscache_n_cop_allocate_page); | ||
293 | if (ret == 0) | 428 | if (ret == 0) |
294 | ret = -ENODATA; | 429 | ret = -ENODATA; |
295 | } else { | 430 | } else { |
431 | fscache_stat(&fscache_n_cop_read_or_alloc_page); | ||
296 | ret = object->cache->ops->read_or_alloc_page(op, page, gfp); | 432 | ret = object->cache->ops->read_or_alloc_page(op, page, gfp); |
433 | fscache_stat_d(&fscache_n_cop_read_or_alloc_page); | ||
297 | } | 434 | } |
298 | 435 | ||
436 | error: | ||
299 | if (ret == -ENOMEM) | 437 | if (ret == -ENOMEM) |
300 | fscache_stat(&fscache_n_retrievals_nomem); | 438 | fscache_stat(&fscache_n_retrievals_nomem); |
301 | else if (ret == -ERESTARTSYS) | 439 | else if (ret == -ERESTARTSYS) |
@@ -347,7 +485,6 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
347 | void *context, | 485 | void *context, |
348 | gfp_t gfp) | 486 | gfp_t gfp) |
349 | { | 487 | { |
350 | fscache_pages_retrieval_func_t func; | ||
351 | struct fscache_retrieval *op; | 488 | struct fscache_retrieval *op; |
352 | struct fscache_object *object; | 489 | struct fscache_object *object; |
353 | int ret; | 490 | int ret; |
@@ -369,6 +506,7 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
369 | op = fscache_alloc_retrieval(mapping, end_io_func, context); | 506 | op = fscache_alloc_retrieval(mapping, end_io_func, context); |
370 | if (!op) | 507 | if (!op) |
371 | return -ENOMEM; | 508 | return -ENOMEM; |
509 | fscache_set_op_name(&op->op, "RetrRAN"); | ||
372 | 510 | ||
373 | spin_lock(&cookie->lock); | 511 | spin_lock(&cookie->lock); |
374 | 512 | ||
@@ -377,6 +515,9 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
377 | object = hlist_entry(cookie->backing_objects.first, | 515 | object = hlist_entry(cookie->backing_objects.first, |
378 | struct fscache_object, cookie_link); | 516 | struct fscache_object, cookie_link); |
379 | 517 | ||
518 | atomic_inc(&object->n_reads); | ||
519 | set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | ||
520 | |||
380 | if (fscache_submit_op(object, &op->op) < 0) | 521 | if (fscache_submit_op(object, &op->op) < 0) |
381 | goto nobufs_unlock; | 522 | goto nobufs_unlock; |
382 | spin_unlock(&cookie->lock); | 523 | spin_unlock(&cookie->lock); |
@@ -389,21 +530,27 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
389 | 530 | ||
390 | /* we wait for the operation to become active, and then process it | 531 | /* we wait for the operation to become active, and then process it |
391 | * *here*, in this thread, and not in the thread pool */ | 532 | * *here*, in this thread, and not in the thread pool */ |
392 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { | 533 | ret = fscache_wait_for_retrieval_activation( |
393 | _debug(">>> WT"); | 534 | object, op, |
394 | fscache_stat(&fscache_n_retrieval_op_waits); | 535 | __fscache_stat(&fscache_n_retrieval_op_waits), |
395 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 536 | __fscache_stat(&fscache_n_retrievals_object_dead)); |
396 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | 537 | if (ret < 0) |
397 | _debug("<<< GO"); | 538 | goto error; |
398 | } | ||
399 | 539 | ||
400 | /* ask the cache to honour the operation */ | 540 | /* ask the cache to honour the operation */ |
401 | if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) | 541 | if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) { |
402 | func = object->cache->ops->allocate_pages; | 542 | fscache_stat(&fscache_n_cop_allocate_pages); |
403 | else | 543 | ret = object->cache->ops->allocate_pages( |
404 | func = object->cache->ops->read_or_alloc_pages; | 544 | op, pages, nr_pages, gfp); |
405 | ret = func(op, pages, nr_pages, gfp); | 545 | fscache_stat_d(&fscache_n_cop_allocate_pages); |
546 | } else { | ||
547 | fscache_stat(&fscache_n_cop_read_or_alloc_pages); | ||
548 | ret = object->cache->ops->read_or_alloc_pages( | ||
549 | op, pages, nr_pages, gfp); | ||
550 | fscache_stat_d(&fscache_n_cop_read_or_alloc_pages); | ||
551 | } | ||
406 | 552 | ||
553 | error: | ||
407 | if (ret == -ENOMEM) | 554 | if (ret == -ENOMEM) |
408 | fscache_stat(&fscache_n_retrievals_nomem); | 555 | fscache_stat(&fscache_n_retrievals_nomem); |
409 | else if (ret == -ERESTARTSYS) | 556 | else if (ret == -ERESTARTSYS) |
@@ -461,6 +608,7 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
461 | op = fscache_alloc_retrieval(page->mapping, NULL, NULL); | 608 | op = fscache_alloc_retrieval(page->mapping, NULL, NULL); |
462 | if (!op) | 609 | if (!op) |
463 | return -ENOMEM; | 610 | return -ENOMEM; |
611 | fscache_set_op_name(&op->op, "RetrAL1"); | ||
464 | 612 | ||
465 | spin_lock(&cookie->lock); | 613 | spin_lock(&cookie->lock); |
466 | 614 | ||
@@ -475,18 +623,22 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
475 | 623 | ||
476 | fscache_stat(&fscache_n_alloc_ops); | 624 | fscache_stat(&fscache_n_alloc_ops); |
477 | 625 | ||
478 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { | 626 | ret = fscache_wait_for_retrieval_activation( |
479 | _debug(">>> WT"); | 627 | object, op, |
480 | fscache_stat(&fscache_n_alloc_op_waits); | 628 | __fscache_stat(&fscache_n_alloc_op_waits), |
481 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 629 | __fscache_stat(&fscache_n_allocs_object_dead)); |
482 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | 630 | if (ret < 0) |
483 | _debug("<<< GO"); | 631 | goto error; |
484 | } | ||
485 | 632 | ||
486 | /* ask the cache to honour the operation */ | 633 | /* ask the cache to honour the operation */ |
634 | fscache_stat(&fscache_n_cop_allocate_page); | ||
487 | ret = object->cache->ops->allocate_page(op, page, gfp); | 635 | ret = object->cache->ops->allocate_page(op, page, gfp); |
636 | fscache_stat_d(&fscache_n_cop_allocate_page); | ||
488 | 637 | ||
489 | if (ret < 0) | 638 | error: |
639 | if (ret == -ERESTARTSYS) | ||
640 | fscache_stat(&fscache_n_allocs_intr); | ||
641 | else if (ret < 0) | ||
490 | fscache_stat(&fscache_n_allocs_nobufs); | 642 | fscache_stat(&fscache_n_allocs_nobufs); |
491 | else | 643 | else |
492 | fscache_stat(&fscache_n_allocs_ok); | 644 | fscache_stat(&fscache_n_allocs_ok); |
@@ -521,7 +673,7 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
521 | struct fscache_storage *op = | 673 | struct fscache_storage *op = |
522 | container_of(_op, struct fscache_storage, op); | 674 | container_of(_op, struct fscache_storage, op); |
523 | struct fscache_object *object = op->op.object; | 675 | struct fscache_object *object = op->op.object; |
524 | struct fscache_cookie *cookie = object->cookie; | 676 | struct fscache_cookie *cookie; |
525 | struct page *page; | 677 | struct page *page; |
526 | unsigned n; | 678 | unsigned n; |
527 | void *results[1]; | 679 | void *results[1]; |
@@ -529,16 +681,19 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
529 | 681 | ||
530 | _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage)); | 682 | _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage)); |
531 | 683 | ||
532 | spin_lock(&cookie->lock); | 684 | fscache_set_op_state(&op->op, "GetPage"); |
685 | |||
533 | spin_lock(&object->lock); | 686 | spin_lock(&object->lock); |
687 | cookie = object->cookie; | ||
534 | 688 | ||
535 | if (!fscache_object_is_active(object)) { | 689 | if (!fscache_object_is_active(object) || !cookie) { |
536 | spin_unlock(&object->lock); | 690 | spin_unlock(&object->lock); |
537 | spin_unlock(&cookie->lock); | ||
538 | _leave(""); | 691 | _leave(""); |
539 | return; | 692 | return; |
540 | } | 693 | } |
541 | 694 | ||
695 | spin_lock(&cookie->stores_lock); | ||
696 | |||
542 | fscache_stat(&fscache_n_store_calls); | 697 | fscache_stat(&fscache_n_store_calls); |
543 | 698 | ||
544 | /* find a page to store */ | 699 | /* find a page to store */ |
@@ -549,23 +704,35 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
549 | goto superseded; | 704 | goto superseded; |
550 | page = results[0]; | 705 | page = results[0]; |
551 | _debug("gang %d [%lx]", n, page->index); | 706 | _debug("gang %d [%lx]", n, page->index); |
552 | if (page->index > op->store_limit) | 707 | if (page->index > op->store_limit) { |
708 | fscache_stat(&fscache_n_store_pages_over_limit); | ||
553 | goto superseded; | 709 | goto superseded; |
710 | } | ||
554 | 711 | ||
555 | radix_tree_tag_clear(&cookie->stores, page->index, | 712 | if (page) { |
556 | FSCACHE_COOKIE_PENDING_TAG); | 713 | radix_tree_tag_set(&cookie->stores, page->index, |
714 | FSCACHE_COOKIE_STORING_TAG); | ||
715 | radix_tree_tag_clear(&cookie->stores, page->index, | ||
716 | FSCACHE_COOKIE_PENDING_TAG); | ||
717 | } | ||
557 | 718 | ||
719 | spin_unlock(&cookie->stores_lock); | ||
558 | spin_unlock(&object->lock); | 720 | spin_unlock(&object->lock); |
559 | spin_unlock(&cookie->lock); | ||
560 | 721 | ||
561 | if (page) { | 722 | if (page) { |
723 | fscache_set_op_state(&op->op, "Store"); | ||
724 | fscache_stat(&fscache_n_store_pages); | ||
725 | fscache_stat(&fscache_n_cop_write_page); | ||
562 | ret = object->cache->ops->write_page(op, page); | 726 | ret = object->cache->ops->write_page(op, page); |
563 | fscache_end_page_write(cookie, page); | 727 | fscache_stat_d(&fscache_n_cop_write_page); |
564 | page_cache_release(page); | 728 | fscache_set_op_state(&op->op, "EndWrite"); |
565 | if (ret < 0) | 729 | fscache_end_page_write(object, page); |
730 | if (ret < 0) { | ||
731 | fscache_set_op_state(&op->op, "Abort"); | ||
566 | fscache_abort_object(object); | 732 | fscache_abort_object(object); |
567 | else | 733 | } else { |
568 | fscache_enqueue_operation(&op->op); | 734 | fscache_enqueue_operation(&op->op); |
735 | } | ||
569 | } | 736 | } |
570 | 737 | ||
571 | _leave(""); | 738 | _leave(""); |
@@ -575,9 +742,9 @@ superseded: | |||
575 | /* this writer is going away and there aren't any more things to | 742 | /* this writer is going away and there aren't any more things to |
576 | * write */ | 743 | * write */ |
577 | _debug("cease"); | 744 | _debug("cease"); |
745 | spin_unlock(&cookie->stores_lock); | ||
578 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | 746 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); |
579 | spin_unlock(&object->lock); | 747 | spin_unlock(&object->lock); |
580 | spin_unlock(&cookie->lock); | ||
581 | _leave(""); | 748 | _leave(""); |
582 | } | 749 | } |
583 | 750 | ||
@@ -634,6 +801,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
634 | fscache_operation_init(&op->op, fscache_release_write_op); | 801 | fscache_operation_init(&op->op, fscache_release_write_op); |
635 | fscache_operation_init_slow(&op->op, fscache_write_op); | 802 | fscache_operation_init_slow(&op->op, fscache_write_op); |
636 | op->op.flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_WAITING); | 803 | op->op.flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_WAITING); |
804 | fscache_set_op_name(&op->op, "Write1"); | ||
637 | 805 | ||
638 | ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM); | 806 | ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM); |
639 | if (ret < 0) | 807 | if (ret < 0) |
@@ -652,6 +820,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
652 | /* add the page to the pending-storage radix tree on the backing | 820 | /* add the page to the pending-storage radix tree on the backing |
653 | * object */ | 821 | * object */ |
654 | spin_lock(&object->lock); | 822 | spin_lock(&object->lock); |
823 | spin_lock(&cookie->stores_lock); | ||
655 | 824 | ||
656 | _debug("store limit %llx", (unsigned long long) object->store_limit); | 825 | _debug("store limit %llx", (unsigned long long) object->store_limit); |
657 | 826 | ||
@@ -672,6 +841,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
672 | if (test_and_set_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags)) | 841 | if (test_and_set_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags)) |
673 | goto already_pending; | 842 | goto already_pending; |
674 | 843 | ||
844 | spin_unlock(&cookie->stores_lock); | ||
675 | spin_unlock(&object->lock); | 845 | spin_unlock(&object->lock); |
676 | 846 | ||
677 | op->op.debug_id = atomic_inc_return(&fscache_op_debug_id); | 847 | op->op.debug_id = atomic_inc_return(&fscache_op_debug_id); |
@@ -693,6 +863,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
693 | already_queued: | 863 | already_queued: |
694 | fscache_stat(&fscache_n_stores_again); | 864 | fscache_stat(&fscache_n_stores_again); |
695 | already_pending: | 865 | already_pending: |
866 | spin_unlock(&cookie->stores_lock); | ||
696 | spin_unlock(&object->lock); | 867 | spin_unlock(&object->lock); |
697 | spin_unlock(&cookie->lock); | 868 | spin_unlock(&cookie->lock); |
698 | radix_tree_preload_end(); | 869 | radix_tree_preload_end(); |
@@ -702,7 +873,9 @@ already_pending: | |||
702 | return 0; | 873 | return 0; |
703 | 874 | ||
704 | submit_failed: | 875 | submit_failed: |
876 | spin_lock(&cookie->stores_lock); | ||
705 | radix_tree_delete(&cookie->stores, page->index); | 877 | radix_tree_delete(&cookie->stores, page->index); |
878 | spin_unlock(&cookie->stores_lock); | ||
706 | page_cache_release(page); | 879 | page_cache_release(page); |
707 | ret = -ENOBUFS; | 880 | ret = -ENOBUFS; |
708 | goto nobufs; | 881 | goto nobufs; |
@@ -763,7 +936,9 @@ void __fscache_uncache_page(struct fscache_cookie *cookie, struct page *page) | |||
763 | if (TestClearPageFsCache(page) && | 936 | if (TestClearPageFsCache(page) && |
764 | object->cache->ops->uncache_page) { | 937 | object->cache->ops->uncache_page) { |
765 | /* the cache backend releases the cookie lock */ | 938 | /* the cache backend releases the cookie lock */ |
939 | fscache_stat(&fscache_n_cop_uncache_page); | ||
766 | object->cache->ops->uncache_page(object, page); | 940 | object->cache->ops->uncache_page(object, page); |
941 | fscache_stat_d(&fscache_n_cop_uncache_page); | ||
767 | goto done; | 942 | goto done; |
768 | } | 943 | } |
769 | 944 | ||
diff --git a/fs/fscache/proc.c b/fs/fscache/proc.c index beeab44bc31a..1d9e4951a597 100644 --- a/fs/fscache/proc.c +++ b/fs/fscache/proc.c | |||
@@ -37,10 +37,20 @@ int __init fscache_proc_init(void) | |||
37 | goto error_histogram; | 37 | goto error_histogram; |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | #ifdef CONFIG_FSCACHE_OBJECT_LIST | ||
41 | if (!proc_create("fs/fscache/objects", S_IFREG | 0444, NULL, | ||
42 | &fscache_objlist_fops)) | ||
43 | goto error_objects; | ||
44 | #endif | ||
45 | |||
40 | _leave(" = 0"); | 46 | _leave(" = 0"); |
41 | return 0; | 47 | return 0; |
42 | 48 | ||
49 | #ifdef CONFIG_FSCACHE_OBJECT_LIST | ||
50 | error_objects: | ||
51 | #endif | ||
43 | #ifdef CONFIG_FSCACHE_HISTOGRAM | 52 | #ifdef CONFIG_FSCACHE_HISTOGRAM |
53 | remove_proc_entry("fs/fscache/histogram", NULL); | ||
44 | error_histogram: | 54 | error_histogram: |
45 | #endif | 55 | #endif |
46 | #ifdef CONFIG_FSCACHE_STATS | 56 | #ifdef CONFIG_FSCACHE_STATS |
@@ -58,6 +68,9 @@ error_dir: | |||
58 | */ | 68 | */ |
59 | void fscache_proc_cleanup(void) | 69 | void fscache_proc_cleanup(void) |
60 | { | 70 | { |
71 | #ifdef CONFIG_FSCACHE_OBJECT_LIST | ||
72 | remove_proc_entry("fs/fscache/objects", NULL); | ||
73 | #endif | ||
61 | #ifdef CONFIG_FSCACHE_HISTOGRAM | 74 | #ifdef CONFIG_FSCACHE_HISTOGRAM |
62 | remove_proc_entry("fs/fscache/histogram", NULL); | 75 | remove_proc_entry("fs/fscache/histogram", NULL); |
63 | #endif | 76 | #endif |
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c index 65deb99e756b..46435f3aae68 100644 --- a/fs/fscache/stats.c +++ b/fs/fscache/stats.c | |||
@@ -25,6 +25,8 @@ atomic_t fscache_n_op_requeue; | |||
25 | atomic_t fscache_n_op_deferred_release; | 25 | atomic_t fscache_n_op_deferred_release; |
26 | atomic_t fscache_n_op_release; | 26 | atomic_t fscache_n_op_release; |
27 | atomic_t fscache_n_op_gc; | 27 | atomic_t fscache_n_op_gc; |
28 | atomic_t fscache_n_op_cancelled; | ||
29 | atomic_t fscache_n_op_rejected; | ||
28 | 30 | ||
29 | atomic_t fscache_n_attr_changed; | 31 | atomic_t fscache_n_attr_changed; |
30 | atomic_t fscache_n_attr_changed_ok; | 32 | atomic_t fscache_n_attr_changed_ok; |
@@ -36,6 +38,8 @@ atomic_t fscache_n_allocs; | |||
36 | atomic_t fscache_n_allocs_ok; | 38 | atomic_t fscache_n_allocs_ok; |
37 | atomic_t fscache_n_allocs_wait; | 39 | atomic_t fscache_n_allocs_wait; |
38 | atomic_t fscache_n_allocs_nobufs; | 40 | atomic_t fscache_n_allocs_nobufs; |
41 | atomic_t fscache_n_allocs_intr; | ||
42 | atomic_t fscache_n_allocs_object_dead; | ||
39 | atomic_t fscache_n_alloc_ops; | 43 | atomic_t fscache_n_alloc_ops; |
40 | atomic_t fscache_n_alloc_op_waits; | 44 | atomic_t fscache_n_alloc_op_waits; |
41 | 45 | ||
@@ -46,6 +50,7 @@ atomic_t fscache_n_retrievals_nodata; | |||
46 | atomic_t fscache_n_retrievals_nobufs; | 50 | atomic_t fscache_n_retrievals_nobufs; |
47 | atomic_t fscache_n_retrievals_intr; | 51 | atomic_t fscache_n_retrievals_intr; |
48 | atomic_t fscache_n_retrievals_nomem; | 52 | atomic_t fscache_n_retrievals_nomem; |
53 | atomic_t fscache_n_retrievals_object_dead; | ||
49 | atomic_t fscache_n_retrieval_ops; | 54 | atomic_t fscache_n_retrieval_ops; |
50 | atomic_t fscache_n_retrieval_op_waits; | 55 | atomic_t fscache_n_retrieval_op_waits; |
51 | 56 | ||
@@ -56,6 +61,14 @@ atomic_t fscache_n_stores_nobufs; | |||
56 | atomic_t fscache_n_stores_oom; | 61 | atomic_t fscache_n_stores_oom; |
57 | atomic_t fscache_n_store_ops; | 62 | atomic_t fscache_n_store_ops; |
58 | atomic_t fscache_n_store_calls; | 63 | atomic_t fscache_n_store_calls; |
64 | atomic_t fscache_n_store_pages; | ||
65 | atomic_t fscache_n_store_radix_deletes; | ||
66 | atomic_t fscache_n_store_pages_over_limit; | ||
67 | |||
68 | atomic_t fscache_n_store_vmscan_not_storing; | ||
69 | atomic_t fscache_n_store_vmscan_gone; | ||
70 | atomic_t fscache_n_store_vmscan_busy; | ||
71 | atomic_t fscache_n_store_vmscan_cancelled; | ||
59 | 72 | ||
60 | atomic_t fscache_n_marks; | 73 | atomic_t fscache_n_marks; |
61 | atomic_t fscache_n_uncaches; | 74 | atomic_t fscache_n_uncaches; |
@@ -74,6 +87,7 @@ atomic_t fscache_n_updates_run; | |||
74 | atomic_t fscache_n_relinquishes; | 87 | atomic_t fscache_n_relinquishes; |
75 | atomic_t fscache_n_relinquishes_null; | 88 | atomic_t fscache_n_relinquishes_null; |
76 | atomic_t fscache_n_relinquishes_waitcrt; | 89 | atomic_t fscache_n_relinquishes_waitcrt; |
90 | atomic_t fscache_n_relinquishes_retire; | ||
77 | 91 | ||
78 | atomic_t fscache_n_cookie_index; | 92 | atomic_t fscache_n_cookie_index; |
79 | atomic_t fscache_n_cookie_data; | 93 | atomic_t fscache_n_cookie_data; |
@@ -84,6 +98,7 @@ atomic_t fscache_n_object_no_alloc; | |||
84 | atomic_t fscache_n_object_lookups; | 98 | atomic_t fscache_n_object_lookups; |
85 | atomic_t fscache_n_object_lookups_negative; | 99 | atomic_t fscache_n_object_lookups_negative; |
86 | atomic_t fscache_n_object_lookups_positive; | 100 | atomic_t fscache_n_object_lookups_positive; |
101 | atomic_t fscache_n_object_lookups_timed_out; | ||
87 | atomic_t fscache_n_object_created; | 102 | atomic_t fscache_n_object_created; |
88 | atomic_t fscache_n_object_avail; | 103 | atomic_t fscache_n_object_avail; |
89 | atomic_t fscache_n_object_dead; | 104 | atomic_t fscache_n_object_dead; |
@@ -93,6 +108,23 @@ atomic_t fscache_n_checkaux_okay; | |||
93 | atomic_t fscache_n_checkaux_update; | 108 | atomic_t fscache_n_checkaux_update; |
94 | atomic_t fscache_n_checkaux_obsolete; | 109 | atomic_t fscache_n_checkaux_obsolete; |
95 | 110 | ||
111 | atomic_t fscache_n_cop_alloc_object; | ||
112 | atomic_t fscache_n_cop_lookup_object; | ||
113 | atomic_t fscache_n_cop_lookup_complete; | ||
114 | atomic_t fscache_n_cop_grab_object; | ||
115 | atomic_t fscache_n_cop_update_object; | ||
116 | atomic_t fscache_n_cop_drop_object; | ||
117 | atomic_t fscache_n_cop_put_object; | ||
118 | atomic_t fscache_n_cop_sync_cache; | ||
119 | atomic_t fscache_n_cop_attr_changed; | ||
120 | atomic_t fscache_n_cop_read_or_alloc_page; | ||
121 | atomic_t fscache_n_cop_read_or_alloc_pages; | ||
122 | atomic_t fscache_n_cop_allocate_page; | ||
123 | atomic_t fscache_n_cop_allocate_pages; | ||
124 | atomic_t fscache_n_cop_write_page; | ||
125 | atomic_t fscache_n_cop_uncache_page; | ||
126 | atomic_t fscache_n_cop_dissociate_pages; | ||
127 | |||
96 | /* | 128 | /* |
97 | * display the general statistics | 129 | * display the general statistics |
98 | */ | 130 | */ |
@@ -129,10 +161,11 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
129 | atomic_read(&fscache_n_acquires_nobufs), | 161 | atomic_read(&fscache_n_acquires_nobufs), |
130 | atomic_read(&fscache_n_acquires_oom)); | 162 | atomic_read(&fscache_n_acquires_oom)); |
131 | 163 | ||
132 | seq_printf(m, "Lookups: n=%u neg=%u pos=%u crt=%u\n", | 164 | seq_printf(m, "Lookups: n=%u neg=%u pos=%u crt=%u tmo=%u\n", |
133 | atomic_read(&fscache_n_object_lookups), | 165 | atomic_read(&fscache_n_object_lookups), |
134 | atomic_read(&fscache_n_object_lookups_negative), | 166 | atomic_read(&fscache_n_object_lookups_negative), |
135 | atomic_read(&fscache_n_object_lookups_positive), | 167 | atomic_read(&fscache_n_object_lookups_positive), |
168 | atomic_read(&fscache_n_object_lookups_timed_out), | ||
136 | atomic_read(&fscache_n_object_created)); | 169 | atomic_read(&fscache_n_object_created)); |
137 | 170 | ||
138 | seq_printf(m, "Updates: n=%u nul=%u run=%u\n", | 171 | seq_printf(m, "Updates: n=%u nul=%u run=%u\n", |
@@ -140,10 +173,11 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
140 | atomic_read(&fscache_n_updates_null), | 173 | atomic_read(&fscache_n_updates_null), |
141 | atomic_read(&fscache_n_updates_run)); | 174 | atomic_read(&fscache_n_updates_run)); |
142 | 175 | ||
143 | seq_printf(m, "Relinqs: n=%u nul=%u wcr=%u\n", | 176 | seq_printf(m, "Relinqs: n=%u nul=%u wcr=%u rtr=%u\n", |
144 | atomic_read(&fscache_n_relinquishes), | 177 | atomic_read(&fscache_n_relinquishes), |
145 | atomic_read(&fscache_n_relinquishes_null), | 178 | atomic_read(&fscache_n_relinquishes_null), |
146 | atomic_read(&fscache_n_relinquishes_waitcrt)); | 179 | atomic_read(&fscache_n_relinquishes_waitcrt), |
180 | atomic_read(&fscache_n_relinquishes_retire)); | ||
147 | 181 | ||
148 | seq_printf(m, "AttrChg: n=%u ok=%u nbf=%u oom=%u run=%u\n", | 182 | seq_printf(m, "AttrChg: n=%u ok=%u nbf=%u oom=%u run=%u\n", |
149 | atomic_read(&fscache_n_attr_changed), | 183 | atomic_read(&fscache_n_attr_changed), |
@@ -152,14 +186,16 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
152 | atomic_read(&fscache_n_attr_changed_nomem), | 186 | atomic_read(&fscache_n_attr_changed_nomem), |
153 | atomic_read(&fscache_n_attr_changed_calls)); | 187 | atomic_read(&fscache_n_attr_changed_calls)); |
154 | 188 | ||
155 | seq_printf(m, "Allocs : n=%u ok=%u wt=%u nbf=%u\n", | 189 | seq_printf(m, "Allocs : n=%u ok=%u wt=%u nbf=%u int=%u\n", |
156 | atomic_read(&fscache_n_allocs), | 190 | atomic_read(&fscache_n_allocs), |
157 | atomic_read(&fscache_n_allocs_ok), | 191 | atomic_read(&fscache_n_allocs_ok), |
158 | atomic_read(&fscache_n_allocs_wait), | 192 | atomic_read(&fscache_n_allocs_wait), |
159 | atomic_read(&fscache_n_allocs_nobufs)); | 193 | atomic_read(&fscache_n_allocs_nobufs), |
160 | seq_printf(m, "Allocs : ops=%u owt=%u\n", | 194 | atomic_read(&fscache_n_allocs_intr)); |
195 | seq_printf(m, "Allocs : ops=%u owt=%u abt=%u\n", | ||
161 | atomic_read(&fscache_n_alloc_ops), | 196 | atomic_read(&fscache_n_alloc_ops), |
162 | atomic_read(&fscache_n_alloc_op_waits)); | 197 | atomic_read(&fscache_n_alloc_op_waits), |
198 | atomic_read(&fscache_n_allocs_object_dead)); | ||
163 | 199 | ||
164 | seq_printf(m, "Retrvls: n=%u ok=%u wt=%u nod=%u nbf=%u" | 200 | seq_printf(m, "Retrvls: n=%u ok=%u wt=%u nod=%u nbf=%u" |
165 | " int=%u oom=%u\n", | 201 | " int=%u oom=%u\n", |
@@ -170,9 +206,10 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
170 | atomic_read(&fscache_n_retrievals_nobufs), | 206 | atomic_read(&fscache_n_retrievals_nobufs), |
171 | atomic_read(&fscache_n_retrievals_intr), | 207 | atomic_read(&fscache_n_retrievals_intr), |
172 | atomic_read(&fscache_n_retrievals_nomem)); | 208 | atomic_read(&fscache_n_retrievals_nomem)); |
173 | seq_printf(m, "Retrvls: ops=%u owt=%u\n", | 209 | seq_printf(m, "Retrvls: ops=%u owt=%u abt=%u\n", |
174 | atomic_read(&fscache_n_retrieval_ops), | 210 | atomic_read(&fscache_n_retrieval_ops), |
175 | atomic_read(&fscache_n_retrieval_op_waits)); | 211 | atomic_read(&fscache_n_retrieval_op_waits), |
212 | atomic_read(&fscache_n_retrievals_object_dead)); | ||
176 | 213 | ||
177 | seq_printf(m, "Stores : n=%u ok=%u agn=%u nbf=%u oom=%u\n", | 214 | seq_printf(m, "Stores : n=%u ok=%u agn=%u nbf=%u oom=%u\n", |
178 | atomic_read(&fscache_n_stores), | 215 | atomic_read(&fscache_n_stores), |
@@ -180,18 +217,49 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
180 | atomic_read(&fscache_n_stores_again), | 217 | atomic_read(&fscache_n_stores_again), |
181 | atomic_read(&fscache_n_stores_nobufs), | 218 | atomic_read(&fscache_n_stores_nobufs), |
182 | atomic_read(&fscache_n_stores_oom)); | 219 | atomic_read(&fscache_n_stores_oom)); |
183 | seq_printf(m, "Stores : ops=%u run=%u\n", | 220 | seq_printf(m, "Stores : ops=%u run=%u pgs=%u rxd=%u olm=%u\n", |
184 | atomic_read(&fscache_n_store_ops), | 221 | atomic_read(&fscache_n_store_ops), |
185 | atomic_read(&fscache_n_store_calls)); | 222 | atomic_read(&fscache_n_store_calls), |
223 | atomic_read(&fscache_n_store_pages), | ||
224 | atomic_read(&fscache_n_store_radix_deletes), | ||
225 | atomic_read(&fscache_n_store_pages_over_limit)); | ||
186 | 226 | ||
187 | seq_printf(m, "Ops : pend=%u run=%u enq=%u\n", | 227 | seq_printf(m, "VmScan : nos=%u gon=%u bsy=%u can=%u\n", |
228 | atomic_read(&fscache_n_store_vmscan_not_storing), | ||
229 | atomic_read(&fscache_n_store_vmscan_gone), | ||
230 | atomic_read(&fscache_n_store_vmscan_busy), | ||
231 | atomic_read(&fscache_n_store_vmscan_cancelled)); | ||
232 | |||
233 | seq_printf(m, "Ops : pend=%u run=%u enq=%u can=%u rej=%u\n", | ||
188 | atomic_read(&fscache_n_op_pend), | 234 | atomic_read(&fscache_n_op_pend), |
189 | atomic_read(&fscache_n_op_run), | 235 | atomic_read(&fscache_n_op_run), |
190 | atomic_read(&fscache_n_op_enqueue)); | 236 | atomic_read(&fscache_n_op_enqueue), |
237 | atomic_read(&fscache_n_op_cancelled), | ||
238 | atomic_read(&fscache_n_op_rejected)); | ||
191 | seq_printf(m, "Ops : dfr=%u rel=%u gc=%u\n", | 239 | seq_printf(m, "Ops : dfr=%u rel=%u gc=%u\n", |
192 | atomic_read(&fscache_n_op_deferred_release), | 240 | atomic_read(&fscache_n_op_deferred_release), |
193 | atomic_read(&fscache_n_op_release), | 241 | atomic_read(&fscache_n_op_release), |
194 | atomic_read(&fscache_n_op_gc)); | 242 | atomic_read(&fscache_n_op_gc)); |
243 | |||
244 | seq_printf(m, "CacheOp: alo=%d luo=%d luc=%d gro=%d\n", | ||
245 | atomic_read(&fscache_n_cop_alloc_object), | ||
246 | atomic_read(&fscache_n_cop_lookup_object), | ||
247 | atomic_read(&fscache_n_cop_lookup_complete), | ||
248 | atomic_read(&fscache_n_cop_grab_object)); | ||
249 | seq_printf(m, "CacheOp: upo=%d dro=%d pto=%d atc=%d syn=%d\n", | ||
250 | atomic_read(&fscache_n_cop_update_object), | ||
251 | atomic_read(&fscache_n_cop_drop_object), | ||
252 | atomic_read(&fscache_n_cop_put_object), | ||
253 | atomic_read(&fscache_n_cop_attr_changed), | ||
254 | atomic_read(&fscache_n_cop_sync_cache)); | ||
255 | seq_printf(m, "CacheOp: rap=%d ras=%d alp=%d als=%d wrp=%d ucp=%d dsp=%d\n", | ||
256 | atomic_read(&fscache_n_cop_read_or_alloc_page), | ||
257 | atomic_read(&fscache_n_cop_read_or_alloc_pages), | ||
258 | atomic_read(&fscache_n_cop_allocate_page), | ||
259 | atomic_read(&fscache_n_cop_allocate_pages), | ||
260 | atomic_read(&fscache_n_cop_write_page), | ||
261 | atomic_read(&fscache_n_cop_uncache_page), | ||
262 | atomic_read(&fscache_n_cop_dissociate_pages)); | ||
195 | return 0; | 263 | return 0; |
196 | } | 264 | } |
197 | 265 | ||
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 8ada78aade58..4787ae6c5c1c 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -385,6 +385,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
385 | if (fc->no_create) | 385 | if (fc->no_create) |
386 | return -ENOSYS; | 386 | return -ENOSYS; |
387 | 387 | ||
388 | if (flags & O_DIRECT) | ||
389 | return -EINVAL; | ||
390 | |||
388 | forget_req = fuse_get_req(fc); | 391 | forget_req = fuse_get_req(fc); |
389 | if (IS_ERR(forget_req)) | 392 | if (IS_ERR(forget_req)) |
390 | return PTR_ERR(forget_req); | 393 | return PTR_ERR(forget_req); |
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index 5971359d2090..4dcddf83326f 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig | |||
@@ -8,6 +8,8 @@ config GFS2_FS | |||
8 | select FS_POSIX_ACL | 8 | select FS_POSIX_ACL |
9 | select CRC32 | 9 | select CRC32 |
10 | select SLOW_WORK | 10 | select SLOW_WORK |
11 | select QUOTA | ||
12 | select QUOTACTL | ||
11 | help | 13 | help |
12 | A cluster filesystem. | 14 | A cluster filesystem. |
13 | 15 | ||
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 3fc4e3ac7d84..3eb1ea846173 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/spinlock.h> | 12 | #include <linux/spinlock.h> |
13 | #include <linux/completion.h> | 13 | #include <linux/completion.h> |
14 | #include <linux/buffer_head.h> | 14 | #include <linux/buffer_head.h> |
15 | #include <linux/xattr.h> | ||
15 | #include <linux/posix_acl.h> | 16 | #include <linux/posix_acl.h> |
16 | #include <linux/posix_acl_xattr.h> | 17 | #include <linux/posix_acl_xattr.h> |
17 | #include <linux/gfs2_ondisk.h> | 18 | #include <linux/gfs2_ondisk.h> |
@@ -26,108 +27,44 @@ | |||
26 | #include "trans.h" | 27 | #include "trans.h" |
27 | #include "util.h" | 28 | #include "util.h" |
28 | 29 | ||
29 | #define ACL_ACCESS 1 | 30 | static const char *gfs2_acl_name(int type) |
30 | #define ACL_DEFAULT 0 | ||
31 | |||
32 | int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, | ||
33 | struct gfs2_ea_request *er, int *remove, mode_t *mode) | ||
34 | { | 31 | { |
35 | struct posix_acl *acl; | 32 | switch (type) { |
36 | int error; | 33 | case ACL_TYPE_ACCESS: |
37 | 34 | return GFS2_POSIX_ACL_ACCESS; | |
38 | error = gfs2_acl_validate_remove(ip, access); | 35 | case ACL_TYPE_DEFAULT: |
39 | if (error) | 36 | return GFS2_POSIX_ACL_DEFAULT; |
40 | return error; | ||
41 | |||
42 | if (!er->er_data) | ||
43 | return -EINVAL; | ||
44 | |||
45 | acl = posix_acl_from_xattr(er->er_data, er->er_data_len); | ||
46 | if (IS_ERR(acl)) | ||
47 | return PTR_ERR(acl); | ||
48 | if (!acl) { | ||
49 | *remove = 1; | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | error = posix_acl_valid(acl); | ||
54 | if (error) | ||
55 | goto out; | ||
56 | |||
57 | if (access) { | ||
58 | error = posix_acl_equiv_mode(acl, mode); | ||
59 | if (!error) | ||
60 | *remove = 1; | ||
61 | else if (error > 0) | ||
62 | error = 0; | ||
63 | } | 37 | } |
64 | 38 | return NULL; | |
65 | out: | ||
66 | posix_acl_release(acl); | ||
67 | return error; | ||
68 | } | ||
69 | |||
70 | int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access) | ||
71 | { | ||
72 | if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl) | ||
73 | return -EOPNOTSUPP; | ||
74 | if (!is_owner_or_cap(&ip->i_inode)) | ||
75 | return -EPERM; | ||
76 | if (S_ISLNK(ip->i_inode.i_mode)) | ||
77 | return -EOPNOTSUPP; | ||
78 | if (!access && !S_ISDIR(ip->i_inode.i_mode)) | ||
79 | return -EACCES; | ||
80 | |||
81 | return 0; | ||
82 | } | 39 | } |
83 | 40 | ||
84 | static int acl_get(struct gfs2_inode *ip, const char *name, | 41 | static struct posix_acl *gfs2_acl_get(struct gfs2_inode *ip, int type) |
85 | struct posix_acl **acl, struct gfs2_ea_location *el, | ||
86 | char **datap, unsigned int *lenp) | ||
87 | { | 42 | { |
43 | struct posix_acl *acl; | ||
44 | const char *name; | ||
88 | char *data; | 45 | char *data; |
89 | unsigned int len; | 46 | int len; |
90 | int error; | ||
91 | |||
92 | el->el_bh = NULL; | ||
93 | 47 | ||
94 | if (!ip->i_eattr) | 48 | if (!ip->i_eattr) |
95 | return 0; | 49 | return NULL; |
96 | |||
97 | error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, el); | ||
98 | if (error) | ||
99 | return error; | ||
100 | if (!el->el_ea) | ||
101 | return 0; | ||
102 | if (!GFS2_EA_DATA_LEN(el->el_ea)) | ||
103 | goto out; | ||
104 | 50 | ||
105 | len = GFS2_EA_DATA_LEN(el->el_ea); | 51 | acl = get_cached_acl(&ip->i_inode, type); |
106 | data = kmalloc(len, GFP_NOFS); | 52 | if (acl != ACL_NOT_CACHED) |
107 | error = -ENOMEM; | 53 | return acl; |
108 | if (!data) | ||
109 | goto out; | ||
110 | 54 | ||
111 | error = gfs2_ea_get_copy(ip, el, data, len); | 55 | name = gfs2_acl_name(type); |
112 | if (error < 0) | 56 | if (name == NULL) |
113 | goto out_kfree; | 57 | return ERR_PTR(-EINVAL); |
114 | error = 0; | ||
115 | 58 | ||
116 | if (acl) { | 59 | len = gfs2_xattr_acl_get(ip, name, &data); |
117 | *acl = posix_acl_from_xattr(data, len); | 60 | if (len < 0) |
118 | if (IS_ERR(*acl)) | 61 | return ERR_PTR(len); |
119 | error = PTR_ERR(*acl); | 62 | if (len == 0) |
120 | } | 63 | return NULL; |
121 | 64 | ||
122 | out_kfree: | 65 | acl = posix_acl_from_xattr(data, len); |
123 | if (error || !datap) { | 66 | kfree(data); |
124 | kfree(data); | 67 | return acl; |
125 | } else { | ||
126 | *datap = data; | ||
127 | *lenp = len; | ||
128 | } | ||
129 | out: | ||
130 | return error; | ||
131 | } | 68 | } |
132 | 69 | ||
133 | /** | 70 | /** |
@@ -140,14 +77,12 @@ out: | |||
140 | 77 | ||
141 | int gfs2_check_acl(struct inode *inode, int mask) | 78 | int gfs2_check_acl(struct inode *inode, int mask) |
142 | { | 79 | { |
143 | struct gfs2_ea_location el; | 80 | struct posix_acl *acl; |
144 | struct posix_acl *acl = NULL; | ||
145 | int error; | 81 | int error; |
146 | 82 | ||
147 | error = acl_get(GFS2_I(inode), GFS2_POSIX_ACL_ACCESS, &acl, &el, NULL, NULL); | 83 | acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS); |
148 | brelse(el.el_bh); | 84 | if (IS_ERR(acl)) |
149 | if (error) | 85 | return PTR_ERR(acl); |
150 | return error; | ||
151 | 86 | ||
152 | if (acl) { | 87 | if (acl) { |
153 | error = posix_acl_permission(inode, acl, mask); | 88 | error = posix_acl_permission(inode, acl, mask); |
@@ -158,57 +93,75 @@ int gfs2_check_acl(struct inode *inode, int mask) | |||
158 | return -EAGAIN; | 93 | return -EAGAIN; |
159 | } | 94 | } |
160 | 95 | ||
161 | static int munge_mode(struct gfs2_inode *ip, mode_t mode) | 96 | static int gfs2_set_mode(struct inode *inode, mode_t mode) |
162 | { | 97 | { |
163 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 98 | int error = 0; |
164 | struct buffer_head *dibh; | ||
165 | int error; | ||
166 | 99 | ||
167 | error = gfs2_trans_begin(sdp, RES_DINODE, 0); | 100 | if (mode != inode->i_mode) { |
168 | if (error) | 101 | struct iattr iattr; |
169 | return error; | ||
170 | 102 | ||
171 | error = gfs2_meta_inode_buffer(ip, &dibh); | 103 | iattr.ia_valid = ATTR_MODE; |
172 | if (!error) { | 104 | iattr.ia_mode = mode; |
173 | gfs2_assert_withdraw(sdp, | 105 | |
174 | (ip->i_inode.i_mode & S_IFMT) == (mode & S_IFMT)); | 106 | error = gfs2_setattr_simple(GFS2_I(inode), &iattr); |
175 | ip->i_inode.i_mode = mode; | ||
176 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
177 | gfs2_dinode_out(ip, dibh->b_data); | ||
178 | brelse(dibh); | ||
179 | } | 107 | } |
180 | 108 | ||
181 | gfs2_trans_end(sdp); | 109 | return error; |
110 | } | ||
111 | |||
112 | static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl) | ||
113 | { | ||
114 | int error; | ||
115 | int len; | ||
116 | char *data; | ||
117 | const char *name = gfs2_acl_name(type); | ||
182 | 118 | ||
183 | return 0; | 119 | BUG_ON(name == NULL); |
120 | len = posix_acl_to_xattr(acl, NULL, 0); | ||
121 | if (len == 0) | ||
122 | return 0; | ||
123 | data = kmalloc(len, GFP_NOFS); | ||
124 | if (data == NULL) | ||
125 | return -ENOMEM; | ||
126 | error = posix_acl_to_xattr(acl, data, len); | ||
127 | if (error < 0) | ||
128 | goto out; | ||
129 | error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, data, len, 0); | ||
130 | if (!error) | ||
131 | set_cached_acl(inode, type, acl); | ||
132 | out: | ||
133 | kfree(data); | ||
134 | return error; | ||
184 | } | 135 | } |
185 | 136 | ||
186 | int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | 137 | int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode) |
187 | { | 138 | { |
188 | struct gfs2_ea_location el; | ||
189 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 139 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
190 | struct posix_acl *acl = NULL, *clone; | 140 | struct posix_acl *acl, *clone; |
191 | mode_t mode = ip->i_inode.i_mode; | 141 | mode_t mode = inode->i_mode; |
192 | char *data = NULL; | 142 | int error = 0; |
193 | unsigned int len; | ||
194 | int error; | ||
195 | 143 | ||
196 | if (!sdp->sd_args.ar_posix_acl) | 144 | if (!sdp->sd_args.ar_posix_acl) |
197 | return 0; | 145 | return 0; |
198 | if (S_ISLNK(ip->i_inode.i_mode)) | 146 | if (S_ISLNK(inode->i_mode)) |
199 | return 0; | 147 | return 0; |
200 | 148 | ||
201 | error = acl_get(dip, GFS2_POSIX_ACL_DEFAULT, &acl, &el, &data, &len); | 149 | acl = gfs2_acl_get(dip, ACL_TYPE_DEFAULT); |
202 | brelse(el.el_bh); | 150 | if (IS_ERR(acl)) |
203 | if (error) | 151 | return PTR_ERR(acl); |
204 | return error; | ||
205 | if (!acl) { | 152 | if (!acl) { |
206 | mode &= ~current_umask(); | 153 | mode &= ~current_umask(); |
207 | if (mode != ip->i_inode.i_mode) | 154 | if (mode != inode->i_mode) |
208 | error = munge_mode(ip, mode); | 155 | error = gfs2_set_mode(inode, mode); |
209 | return error; | 156 | return error; |
210 | } | 157 | } |
211 | 158 | ||
159 | if (S_ISDIR(inode->i_mode)) { | ||
160 | error = gfs2_acl_set(inode, ACL_TYPE_DEFAULT, acl); | ||
161 | if (error) | ||
162 | goto out; | ||
163 | } | ||
164 | |||
212 | clone = posix_acl_clone(acl, GFP_NOFS); | 165 | clone = posix_acl_clone(acl, GFP_NOFS); |
213 | error = -ENOMEM; | 166 | error = -ENOMEM; |
214 | if (!clone) | 167 | if (!clone) |
@@ -216,43 +169,32 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
216 | posix_acl_release(acl); | 169 | posix_acl_release(acl); |
217 | acl = clone; | 170 | acl = clone; |
218 | 171 | ||
219 | if (S_ISDIR(ip->i_inode.i_mode)) { | ||
220 | error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS, | ||
221 | GFS2_POSIX_ACL_DEFAULT, data, len, 0); | ||
222 | if (error) | ||
223 | goto out; | ||
224 | } | ||
225 | |||
226 | error = posix_acl_create_masq(acl, &mode); | 172 | error = posix_acl_create_masq(acl, &mode); |
227 | if (error < 0) | 173 | if (error < 0) |
228 | goto out; | 174 | goto out; |
229 | if (error == 0) | 175 | if (error == 0) |
230 | goto munge; | 176 | goto munge; |
231 | 177 | ||
232 | posix_acl_to_xattr(acl, data, len); | 178 | error = gfs2_acl_set(inode, ACL_TYPE_ACCESS, acl); |
233 | error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS, | ||
234 | GFS2_POSIX_ACL_ACCESS, data, len, 0); | ||
235 | if (error) | 179 | if (error) |
236 | goto out; | 180 | goto out; |
237 | munge: | 181 | munge: |
238 | error = munge_mode(ip, mode); | 182 | error = gfs2_set_mode(inode, mode); |
239 | out: | 183 | out: |
240 | posix_acl_release(acl); | 184 | posix_acl_release(acl); |
241 | kfree(data); | ||
242 | return error; | 185 | return error; |
243 | } | 186 | } |
244 | 187 | ||
245 | int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) | 188 | int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) |
246 | { | 189 | { |
247 | struct posix_acl *acl = NULL, *clone; | 190 | struct posix_acl *acl, *clone; |
248 | struct gfs2_ea_location el; | ||
249 | char *data; | 191 | char *data; |
250 | unsigned int len; | 192 | unsigned int len; |
251 | int error; | 193 | int error; |
252 | 194 | ||
253 | error = acl_get(ip, GFS2_POSIX_ACL_ACCESS, &acl, &el, &data, &len); | 195 | acl = gfs2_acl_get(ip, ACL_TYPE_ACCESS); |
254 | if (error) | 196 | if (IS_ERR(acl)) |
255 | goto out_brelse; | 197 | return PTR_ERR(acl); |
256 | if (!acl) | 198 | if (!acl) |
257 | return gfs2_setattr_simple(ip, attr); | 199 | return gfs2_setattr_simple(ip, attr); |
258 | 200 | ||
@@ -265,15 +207,134 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) | |||
265 | 207 | ||
266 | error = posix_acl_chmod_masq(acl, attr->ia_mode); | 208 | error = posix_acl_chmod_masq(acl, attr->ia_mode); |
267 | if (!error) { | 209 | if (!error) { |
210 | len = posix_acl_to_xattr(acl, NULL, 0); | ||
211 | data = kmalloc(len, GFP_NOFS); | ||
212 | error = -ENOMEM; | ||
213 | if (data == NULL) | ||
214 | goto out; | ||
268 | posix_acl_to_xattr(acl, data, len); | 215 | posix_acl_to_xattr(acl, data, len); |
269 | error = gfs2_ea_acl_chmod(ip, &el, attr, data); | 216 | error = gfs2_xattr_acl_chmod(ip, attr, data); |
217 | kfree(data); | ||
218 | set_cached_acl(&ip->i_inode, ACL_TYPE_ACCESS, acl); | ||
270 | } | 219 | } |
271 | 220 | ||
272 | out: | 221 | out: |
273 | posix_acl_release(acl); | 222 | posix_acl_release(acl); |
274 | kfree(data); | ||
275 | out_brelse: | ||
276 | brelse(el.el_bh); | ||
277 | return error; | 223 | return error; |
278 | } | 224 | } |
279 | 225 | ||
226 | static int gfs2_acl_type(const char *name) | ||
227 | { | ||
228 | if (strcmp(name, GFS2_POSIX_ACL_ACCESS) == 0) | ||
229 | return ACL_TYPE_ACCESS; | ||
230 | if (strcmp(name, GFS2_POSIX_ACL_DEFAULT) == 0) | ||
231 | return ACL_TYPE_DEFAULT; | ||
232 | return -EINVAL; | ||
233 | } | ||
234 | |||
235 | static int gfs2_xattr_system_get(struct inode *inode, const char *name, | ||
236 | void *buffer, size_t size) | ||
237 | { | ||
238 | struct posix_acl *acl; | ||
239 | int type; | ||
240 | int error; | ||
241 | |||
242 | type = gfs2_acl_type(name); | ||
243 | if (type < 0) | ||
244 | return type; | ||
245 | |||
246 | acl = gfs2_acl_get(GFS2_I(inode), type); | ||
247 | if (IS_ERR(acl)) | ||
248 | return PTR_ERR(acl); | ||
249 | if (acl == NULL) | ||
250 | return -ENODATA; | ||
251 | |||
252 | error = posix_acl_to_xattr(acl, buffer, size); | ||
253 | posix_acl_release(acl); | ||
254 | |||
255 | return error; | ||
256 | } | ||
257 | |||
258 | static int gfs2_xattr_system_set(struct inode *inode, const char *name, | ||
259 | const void *value, size_t size, int flags) | ||
260 | { | ||
261 | struct gfs2_sbd *sdp = GFS2_SB(inode); | ||
262 | struct posix_acl *acl = NULL; | ||
263 | int error = 0, type; | ||
264 | |||
265 | if (!sdp->sd_args.ar_posix_acl) | ||
266 | return -EOPNOTSUPP; | ||
267 | |||
268 | type = gfs2_acl_type(name); | ||
269 | if (type < 0) | ||
270 | return type; | ||
271 | if (flags & XATTR_CREATE) | ||
272 | return -EINVAL; | ||
273 | if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) | ||
274 | return value ? -EACCES : 0; | ||
275 | if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER)) | ||
276 | return -EPERM; | ||
277 | if (S_ISLNK(inode->i_mode)) | ||
278 | return -EOPNOTSUPP; | ||
279 | |||
280 | if (!value) | ||
281 | goto set_acl; | ||
282 | |||
283 | acl = posix_acl_from_xattr(value, size); | ||
284 | if (!acl) { | ||
285 | /* | ||
286 | * acl_set_file(3) may request that we set default ACLs with | ||
287 | * zero length -- defend (gracefully) against that here. | ||
288 | */ | ||
289 | goto out; | ||
290 | } | ||
291 | if (IS_ERR(acl)) { | ||
292 | error = PTR_ERR(acl); | ||
293 | goto out; | ||
294 | } | ||
295 | |||
296 | error = posix_acl_valid(acl); | ||
297 | if (error) | ||
298 | goto out_release; | ||
299 | |||
300 | error = -EINVAL; | ||
301 | if (acl->a_count > GFS2_ACL_MAX_ENTRIES) | ||
302 | goto out_release; | ||
303 | |||
304 | if (type == ACL_TYPE_ACCESS) { | ||
305 | mode_t mode = inode->i_mode; | ||
306 | error = posix_acl_equiv_mode(acl, &mode); | ||
307 | |||
308 | if (error <= 0) { | ||
309 | posix_acl_release(acl); | ||
310 | acl = NULL; | ||
311 | |||
312 | if (error < 0) | ||
313 | return error; | ||
314 | } | ||
315 | |||
316 | error = gfs2_set_mode(inode, mode); | ||
317 | if (error) | ||
318 | goto out_release; | ||
319 | } | ||
320 | |||
321 | set_acl: | ||
322 | error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, 0); | ||
323 | if (!error) { | ||
324 | if (acl) | ||
325 | set_cached_acl(inode, type, acl); | ||
326 | else | ||
327 | forget_cached_acl(inode, type); | ||
328 | } | ||
329 | out_release: | ||
330 | posix_acl_release(acl); | ||
331 | out: | ||
332 | return error; | ||
333 | } | ||
334 | |||
335 | struct xattr_handler gfs2_xattr_system_handler = { | ||
336 | .prefix = XATTR_SYSTEM_PREFIX, | ||
337 | .get = gfs2_xattr_system_get, | ||
338 | .set = gfs2_xattr_system_set, | ||
339 | }; | ||
340 | |||
diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h index 6751930bfb64..9306a2e6620c 100644 --- a/fs/gfs2/acl.h +++ b/fs/gfs2/acl.h | |||
@@ -13,26 +13,12 @@ | |||
13 | #include "incore.h" | 13 | #include "incore.h" |
14 | 14 | ||
15 | #define GFS2_POSIX_ACL_ACCESS "posix_acl_access" | 15 | #define GFS2_POSIX_ACL_ACCESS "posix_acl_access" |
16 | #define GFS2_POSIX_ACL_ACCESS_LEN 16 | ||
17 | #define GFS2_POSIX_ACL_DEFAULT "posix_acl_default" | 16 | #define GFS2_POSIX_ACL_DEFAULT "posix_acl_default" |
18 | #define GFS2_POSIX_ACL_DEFAULT_LEN 17 | 17 | #define GFS2_ACL_MAX_ENTRIES 25 |
19 | 18 | ||
20 | #define GFS2_ACL_IS_ACCESS(name, len) \ | 19 | extern int gfs2_check_acl(struct inode *inode, int mask); |
21 | ((len) == GFS2_POSIX_ACL_ACCESS_LEN && \ | 20 | extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode); |
22 | !memcmp(GFS2_POSIX_ACL_ACCESS, (name), (len))) | 21 | extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); |
23 | 22 | extern struct xattr_handler gfs2_xattr_system_handler; | |
24 | #define GFS2_ACL_IS_DEFAULT(name, len) \ | ||
25 | ((len) == GFS2_POSIX_ACL_DEFAULT_LEN && \ | ||
26 | !memcmp(GFS2_POSIX_ACL_DEFAULT, (name), (len))) | ||
27 | |||
28 | struct gfs2_ea_request; | ||
29 | |||
30 | int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, | ||
31 | struct gfs2_ea_request *er, | ||
32 | int *remove, mode_t *mode); | ||
33 | int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access); | ||
34 | int gfs2_check_acl(struct inode *inode, int mask); | ||
35 | int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip); | ||
36 | int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); | ||
37 | 23 | ||
38 | #endif /* __ACL_DOT_H__ */ | 24 | #endif /* __ACL_DOT_H__ */ |
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 694b5d48f036..7b8da9415267 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c | |||
@@ -269,7 +269,6 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping, | |||
269 | pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; | 269 | pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; |
270 | unsigned offset = i_size & (PAGE_CACHE_SIZE-1); | 270 | unsigned offset = i_size & (PAGE_CACHE_SIZE-1); |
271 | unsigned nrblocks = nr_pages * (PAGE_CACHE_SIZE/inode->i_sb->s_blocksize); | 271 | unsigned nrblocks = nr_pages * (PAGE_CACHE_SIZE/inode->i_sb->s_blocksize); |
272 | struct backing_dev_info *bdi = mapping->backing_dev_info; | ||
273 | int i; | 272 | int i; |
274 | int ret; | 273 | int ret; |
275 | 274 | ||
@@ -313,11 +312,6 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping, | |||
313 | 312 | ||
314 | if (ret || (--(wbc->nr_to_write) <= 0)) | 313 | if (ret || (--(wbc->nr_to_write) <= 0)) |
315 | ret = 1; | 314 | ret = 1; |
316 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | ||
317 | wbc->encountered_congestion = 1; | ||
318 | ret = 1; | ||
319 | } | ||
320 | |||
321 | } | 315 | } |
322 | gfs2_trans_end(sdp); | 316 | gfs2_trans_end(sdp); |
323 | return ret; | 317 | return ret; |
@@ -338,7 +332,6 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping, | |||
338 | static int gfs2_write_cache_jdata(struct address_space *mapping, | 332 | static int gfs2_write_cache_jdata(struct address_space *mapping, |
339 | struct writeback_control *wbc) | 333 | struct writeback_control *wbc) |
340 | { | 334 | { |
341 | struct backing_dev_info *bdi = mapping->backing_dev_info; | ||
342 | int ret = 0; | 335 | int ret = 0; |
343 | int done = 0; | 336 | int done = 0; |
344 | struct pagevec pvec; | 337 | struct pagevec pvec; |
@@ -348,11 +341,6 @@ static int gfs2_write_cache_jdata(struct address_space *mapping, | |||
348 | int scanned = 0; | 341 | int scanned = 0; |
349 | int range_whole = 0; | 342 | int range_whole = 0; |
350 | 343 | ||
351 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | ||
352 | wbc->encountered_congestion = 1; | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | pagevec_init(&pvec, 0); | 344 | pagevec_init(&pvec, 0); |
357 | if (wbc->range_cyclic) { | 345 | if (wbc->range_cyclic) { |
358 | index = mapping->writeback_index; /* Start from prev offset */ | 346 | index = mapping->writeback_index; /* Start from prev offset */ |
@@ -819,8 +807,10 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, | |||
819 | mark_inode_dirty(inode); | 807 | mark_inode_dirty(inode); |
820 | } | 808 | } |
821 | 809 | ||
822 | if (inode == sdp->sd_rindex) | 810 | if (inode == sdp->sd_rindex) { |
823 | adjust_fs_space(inode); | 811 | adjust_fs_space(inode); |
812 | ip->i_gh.gh_flags |= GL_NOCACHE; | ||
813 | } | ||
824 | 814 | ||
825 | brelse(dibh); | 815 | brelse(dibh); |
826 | gfs2_trans_end(sdp); | 816 | gfs2_trans_end(sdp); |
@@ -889,8 +879,10 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, | |||
889 | mark_inode_dirty(inode); | 879 | mark_inode_dirty(inode); |
890 | } | 880 | } |
891 | 881 | ||
892 | if (inode == sdp->sd_rindex) | 882 | if (inode == sdp->sd_rindex) { |
893 | adjust_fs_space(inode); | 883 | adjust_fs_space(inode); |
884 | ip->i_gh.gh_flags |= GL_NOCACHE; | ||
885 | } | ||
894 | 886 | ||
895 | brelse(dibh); | 887 | brelse(dibh); |
896 | gfs2_trans_end(sdp); | 888 | gfs2_trans_end(sdp); |
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 297d7e5cebad..25fddc100f18 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c | |||
@@ -525,38 +525,6 @@ consist_inode: | |||
525 | return ERR_PTR(-EIO); | 525 | return ERR_PTR(-EIO); |
526 | } | 526 | } |
527 | 527 | ||
528 | |||
529 | /** | ||
530 | * dirent_first - Return the first dirent | ||
531 | * @dip: the directory | ||
532 | * @bh: The buffer | ||
533 | * @dent: Pointer to list of dirents | ||
534 | * | ||
535 | * return first dirent whether bh points to leaf or stuffed dinode | ||
536 | * | ||
537 | * Returns: IS_LEAF, IS_DINODE, or -errno | ||
538 | */ | ||
539 | |||
540 | static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh, | ||
541 | struct gfs2_dirent **dent) | ||
542 | { | ||
543 | struct gfs2_meta_header *h = (struct gfs2_meta_header *)bh->b_data; | ||
544 | |||
545 | if (be32_to_cpu(h->mh_type) == GFS2_METATYPE_LF) { | ||
546 | if (gfs2_meta_check(GFS2_SB(&dip->i_inode), bh)) | ||
547 | return -EIO; | ||
548 | *dent = (struct gfs2_dirent *)(bh->b_data + | ||
549 | sizeof(struct gfs2_leaf)); | ||
550 | return IS_LEAF; | ||
551 | } else { | ||
552 | if (gfs2_metatype_check(GFS2_SB(&dip->i_inode), bh, GFS2_METATYPE_DI)) | ||
553 | return -EIO; | ||
554 | *dent = (struct gfs2_dirent *)(bh->b_data + | ||
555 | sizeof(struct gfs2_dinode)); | ||
556 | return IS_DINODE; | ||
557 | } | ||
558 | } | ||
559 | |||
560 | static int dirent_check_reclen(struct gfs2_inode *dip, | 528 | static int dirent_check_reclen(struct gfs2_inode *dip, |
561 | const struct gfs2_dirent *d, const void *end_p) | 529 | const struct gfs2_dirent *d, const void *end_p) |
562 | { | 530 | { |
@@ -1006,7 +974,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) | |||
1006 | divider = (start + half_len) << (32 - dip->i_depth); | 974 | divider = (start + half_len) << (32 - dip->i_depth); |
1007 | 975 | ||
1008 | /* Copy the entries */ | 976 | /* Copy the entries */ |
1009 | dirent_first(dip, obh, &dent); | 977 | dent = (struct gfs2_dirent *)(obh->b_data + sizeof(struct gfs2_leaf)); |
1010 | 978 | ||
1011 | do { | 979 | do { |
1012 | next = dent; | 980 | next = dent; |
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 8b674b1f3a55..f455a03a09e2 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -241,15 +241,14 @@ int gfs2_glock_put(struct gfs2_glock *gl) | |||
241 | int rv = 0; | 241 | int rv = 0; |
242 | 242 | ||
243 | write_lock(gl_lock_addr(gl->gl_hash)); | 243 | write_lock(gl_lock_addr(gl->gl_hash)); |
244 | if (atomic_dec_and_test(&gl->gl_ref)) { | 244 | if (atomic_dec_and_lock(&gl->gl_ref, &lru_lock)) { |
245 | hlist_del(&gl->gl_list); | 245 | hlist_del(&gl->gl_list); |
246 | write_unlock(gl_lock_addr(gl->gl_hash)); | ||
247 | spin_lock(&lru_lock); | ||
248 | if (!list_empty(&gl->gl_lru)) { | 246 | if (!list_empty(&gl->gl_lru)) { |
249 | list_del_init(&gl->gl_lru); | 247 | list_del_init(&gl->gl_lru); |
250 | atomic_dec(&lru_count); | 248 | atomic_dec(&lru_count); |
251 | } | 249 | } |
252 | spin_unlock(&lru_lock); | 250 | spin_unlock(&lru_lock); |
251 | write_unlock(gl_lock_addr(gl->gl_hash)); | ||
253 | GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); | 252 | GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); |
254 | glock_free(gl); | 253 | glock_free(gl); |
255 | rv = 1; | 254 | rv = 1; |
@@ -513,7 +512,6 @@ retry: | |||
513 | GLOCK_BUG_ON(gl, 1); | 512 | GLOCK_BUG_ON(gl, 1); |
514 | } | 513 | } |
515 | spin_unlock(&gl->gl_spin); | 514 | spin_unlock(&gl->gl_spin); |
516 | gfs2_glock_put(gl); | ||
517 | return; | 515 | return; |
518 | } | 516 | } |
519 | 517 | ||
@@ -524,8 +522,6 @@ retry: | |||
524 | if (glops->go_xmote_bh) { | 522 | if (glops->go_xmote_bh) { |
525 | spin_unlock(&gl->gl_spin); | 523 | spin_unlock(&gl->gl_spin); |
526 | rv = glops->go_xmote_bh(gl, gh); | 524 | rv = glops->go_xmote_bh(gl, gh); |
527 | if (rv == -EAGAIN) | ||
528 | return; | ||
529 | spin_lock(&gl->gl_spin); | 525 | spin_lock(&gl->gl_spin); |
530 | if (rv) { | 526 | if (rv) { |
531 | do_error(gl, rv); | 527 | do_error(gl, rv); |
@@ -540,7 +536,6 @@ out: | |||
540 | clear_bit(GLF_LOCK, &gl->gl_flags); | 536 | clear_bit(GLF_LOCK, &gl->gl_flags); |
541 | out_locked: | 537 | out_locked: |
542 | spin_unlock(&gl->gl_spin); | 538 | spin_unlock(&gl->gl_spin); |
543 | gfs2_glock_put(gl); | ||
544 | } | 539 | } |
545 | 540 | ||
546 | static unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock, | 541 | static unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock, |
@@ -600,7 +595,6 @@ __acquires(&gl->gl_spin) | |||
600 | 595 | ||
601 | if (!(ret & LM_OUT_ASYNC)) { | 596 | if (!(ret & LM_OUT_ASYNC)) { |
602 | finish_xmote(gl, ret); | 597 | finish_xmote(gl, ret); |
603 | gfs2_glock_hold(gl); | ||
604 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) | 598 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) |
605 | gfs2_glock_put(gl); | 599 | gfs2_glock_put(gl); |
606 | } else { | 600 | } else { |
@@ -672,12 +666,17 @@ out: | |||
672 | return; | 666 | return; |
673 | 667 | ||
674 | out_sched: | 668 | out_sched: |
669 | clear_bit(GLF_LOCK, &gl->gl_flags); | ||
670 | smp_mb__after_clear_bit(); | ||
675 | gfs2_glock_hold(gl); | 671 | gfs2_glock_hold(gl); |
676 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) | 672 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) |
677 | gfs2_glock_put_nolock(gl); | 673 | gfs2_glock_put_nolock(gl); |
674 | return; | ||
675 | |||
678 | out_unlock: | 676 | out_unlock: |
679 | clear_bit(GLF_LOCK, &gl->gl_flags); | 677 | clear_bit(GLF_LOCK, &gl->gl_flags); |
680 | goto out; | 678 | smp_mb__after_clear_bit(); |
679 | return; | ||
681 | } | 680 | } |
682 | 681 | ||
683 | static void delete_work_func(struct work_struct *work) | 682 | static void delete_work_func(struct work_struct *work) |
@@ -707,9 +706,12 @@ static void glock_work_func(struct work_struct *work) | |||
707 | { | 706 | { |
708 | unsigned long delay = 0; | 707 | unsigned long delay = 0; |
709 | struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work); | 708 | struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work); |
709 | int drop_ref = 0; | ||
710 | 710 | ||
711 | if (test_and_clear_bit(GLF_REPLY_PENDING, &gl->gl_flags)) | 711 | if (test_and_clear_bit(GLF_REPLY_PENDING, &gl->gl_flags)) { |
712 | finish_xmote(gl, gl->gl_reply); | 712 | finish_xmote(gl, gl->gl_reply); |
713 | drop_ref = 1; | ||
714 | } | ||
713 | down_read(&gfs2_umount_flush_sem); | 715 | down_read(&gfs2_umount_flush_sem); |
714 | spin_lock(&gl->gl_spin); | 716 | spin_lock(&gl->gl_spin); |
715 | if (test_and_clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) && | 717 | if (test_and_clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) && |
@@ -727,6 +729,8 @@ static void glock_work_func(struct work_struct *work) | |||
727 | if (!delay || | 729 | if (!delay || |
728 | queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0) | 730 | queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0) |
729 | gfs2_glock_put(gl); | 731 | gfs2_glock_put(gl); |
732 | if (drop_ref) | ||
733 | gfs2_glock_put(gl); | ||
730 | } | 734 | } |
731 | 735 | ||
732 | /** | 736 | /** |
@@ -1361,10 +1365,6 @@ static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask) | |||
1361 | list_del_init(&gl->gl_lru); | 1365 | list_del_init(&gl->gl_lru); |
1362 | atomic_dec(&lru_count); | 1366 | atomic_dec(&lru_count); |
1363 | 1367 | ||
1364 | /* Check if glock is about to be freed */ | ||
1365 | if (atomic_read(&gl->gl_ref) == 0) | ||
1366 | continue; | ||
1367 | |||
1368 | /* Test for being demotable */ | 1368 | /* Test for being demotable */ |
1369 | if (!test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { | 1369 | if (!test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { |
1370 | gfs2_glock_hold(gl); | 1370 | gfs2_glock_hold(gl); |
@@ -1375,10 +1375,11 @@ static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask) | |||
1375 | handle_callback(gl, LM_ST_UNLOCKED, 0); | 1375 | handle_callback(gl, LM_ST_UNLOCKED, 0); |
1376 | nr--; | 1376 | nr--; |
1377 | } | 1377 | } |
1378 | clear_bit(GLF_LOCK, &gl->gl_flags); | ||
1379 | smp_mb__after_clear_bit(); | ||
1378 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) | 1380 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) |
1379 | gfs2_glock_put_nolock(gl); | 1381 | gfs2_glock_put_nolock(gl); |
1380 | spin_unlock(&gl->gl_spin); | 1382 | spin_unlock(&gl->gl_spin); |
1381 | clear_bit(GLF_LOCK, &gl->gl_flags); | ||
1382 | spin_lock(&lru_lock); | 1383 | spin_lock(&lru_lock); |
1383 | continue; | 1384 | continue; |
1384 | } | 1385 | } |
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index c609894ec0d0..13f0bd228132 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h | |||
@@ -180,15 +180,6 @@ static inline int gfs2_glock_is_held_shrd(struct gfs2_glock *gl) | |||
180 | return gl->gl_state == LM_ST_SHARED; | 180 | return gl->gl_state == LM_ST_SHARED; |
181 | } | 181 | } |
182 | 182 | ||
183 | static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl) | ||
184 | { | ||
185 | int ret; | ||
186 | spin_lock(&gl->gl_spin); | ||
187 | ret = test_bit(GLF_DEMOTE, &gl->gl_flags); | ||
188 | spin_unlock(&gl->gl_spin); | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | int gfs2_glock_get(struct gfs2_sbd *sdp, | 183 | int gfs2_glock_get(struct gfs2_sbd *sdp, |
193 | u64 number, const struct gfs2_glock_operations *glops, | 184 | u64 number, const struct gfs2_glock_operations *glops, |
194 | int create, struct gfs2_glock **glp); | 185 | int create, struct gfs2_glock **glp); |
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 6985eef06c39..78554acc0605 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/buffer_head.h> | 13 | #include <linux/buffer_head.h> |
14 | #include <linux/gfs2_ondisk.h> | 14 | #include <linux/gfs2_ondisk.h> |
15 | #include <linux/bio.h> | 15 | #include <linux/bio.h> |
16 | #include <linux/posix_acl.h> | ||
16 | 17 | ||
17 | #include "gfs2.h" | 18 | #include "gfs2.h" |
18 | #include "incore.h" | 19 | #include "incore.h" |
@@ -184,8 +185,10 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) | |||
184 | if (flags & DIO_METADATA) { | 185 | if (flags & DIO_METADATA) { |
185 | struct address_space *mapping = gl->gl_aspace->i_mapping; | 186 | struct address_space *mapping = gl->gl_aspace->i_mapping; |
186 | truncate_inode_pages(mapping, 0); | 187 | truncate_inode_pages(mapping, 0); |
187 | if (ip) | 188 | if (ip) { |
188 | set_bit(GIF_INVALID, &ip->i_flags); | 189 | set_bit(GIF_INVALID, &ip->i_flags); |
190 | forget_all_cached_acls(&ip->i_inode); | ||
191 | } | ||
189 | } | 192 | } |
190 | 193 | ||
191 | if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) | 194 | if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 6edb423f90b3..4792200978c8 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -429,7 +429,11 @@ struct gfs2_args { | |||
429 | unsigned int ar_meta:1; /* mount metafs */ | 429 | unsigned int ar_meta:1; /* mount metafs */ |
430 | unsigned int ar_discard:1; /* discard requests */ | 430 | unsigned int ar_discard:1; /* discard requests */ |
431 | unsigned int ar_errors:2; /* errors=withdraw | panic */ | 431 | unsigned int ar_errors:2; /* errors=withdraw | panic */ |
432 | unsigned int ar_nobarrier:1; /* do not send barriers */ | ||
432 | int ar_commit; /* Commit interval */ | 433 | int ar_commit; /* Commit interval */ |
434 | int ar_statfs_quantum; /* The fast statfs interval */ | ||
435 | int ar_quota_quantum; /* The quota interval */ | ||
436 | int ar_statfs_percent; /* The % change to force sync */ | ||
433 | }; | 437 | }; |
434 | 438 | ||
435 | struct gfs2_tune { | 439 | struct gfs2_tune { |
@@ -558,6 +562,7 @@ struct gfs2_sbd { | |||
558 | spinlock_t sd_statfs_spin; | 562 | spinlock_t sd_statfs_spin; |
559 | struct gfs2_statfs_change_host sd_statfs_master; | 563 | struct gfs2_statfs_change_host sd_statfs_master; |
560 | struct gfs2_statfs_change_host sd_statfs_local; | 564 | struct gfs2_statfs_change_host sd_statfs_local; |
565 | int sd_statfs_force_sync; | ||
561 | 566 | ||
562 | /* Resource group stuff */ | 567 | /* Resource group stuff */ |
563 | 568 | ||
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index fb15d3b1f409..26ba2a4c4a2d 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -871,7 +871,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
871 | if (error) | 871 | if (error) |
872 | goto fail_gunlock2; | 872 | goto fail_gunlock2; |
873 | 873 | ||
874 | error = gfs2_acl_create(dip, GFS2_I(inode)); | 874 | error = gfs2_acl_create(dip, inode); |
875 | if (error) | 875 | if (error) |
876 | goto fail_gunlock2; | 876 | goto fail_gunlock2; |
877 | 877 | ||
@@ -947,9 +947,7 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) | |||
947 | 947 | ||
948 | str->di_header.mh_magic = cpu_to_be32(GFS2_MAGIC); | 948 | str->di_header.mh_magic = cpu_to_be32(GFS2_MAGIC); |
949 | str->di_header.mh_type = cpu_to_be32(GFS2_METATYPE_DI); | 949 | str->di_header.mh_type = cpu_to_be32(GFS2_METATYPE_DI); |
950 | str->di_header.__pad0 = 0; | ||
951 | str->di_header.mh_format = cpu_to_be32(GFS2_FORMAT_DI); | 950 | str->di_header.mh_format = cpu_to_be32(GFS2_FORMAT_DI); |
952 | str->di_header.__pad1 = 0; | ||
953 | str->di_num.no_addr = cpu_to_be64(ip->i_no_addr); | 951 | str->di_num.no_addr = cpu_to_be64(ip->i_no_addr); |
954 | str->di_num.no_formal_ino = cpu_to_be64(ip->i_no_formal_ino); | 952 | str->di_num.no_formal_ino = cpu_to_be64(ip->i_no_formal_ino); |
955 | str->di_mode = cpu_to_be32(ip->i_inode.i_mode); | 953 | str->di_mode = cpu_to_be32(ip->i_inode.i_mode); |
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 13c6237c5f67..4511b08fc451 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
@@ -596,7 +596,9 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) | |||
596 | memset(lh, 0, sizeof(struct gfs2_log_header)); | 596 | memset(lh, 0, sizeof(struct gfs2_log_header)); |
597 | lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); | 597 | lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); |
598 | lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); | 598 | lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); |
599 | lh->lh_header.__pad0 = cpu_to_be64(0); | ||
599 | lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); | 600 | lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); |
601 | lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid); | ||
600 | lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++); | 602 | lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++); |
601 | lh->lh_flags = cpu_to_be32(flags); | 603 | lh->lh_flags = cpu_to_be32(flags); |
602 | lh->lh_tail = cpu_to_be32(tail); | 604 | lh->lh_tail = cpu_to_be32(tail); |
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 9969ff062c5b..de97632ba32f 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c | |||
@@ -132,6 +132,7 @@ static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type) | |||
132 | static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) | 132 | static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) |
133 | { | 133 | { |
134 | struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); | 134 | struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); |
135 | struct gfs2_meta_header *mh; | ||
135 | struct gfs2_trans *tr; | 136 | struct gfs2_trans *tr; |
136 | 137 | ||
137 | lock_buffer(bd->bd_bh); | 138 | lock_buffer(bd->bd_bh); |
@@ -148,6 +149,9 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) | |||
148 | set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); | 149 | set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); |
149 | gfs2_meta_check(sdp, bd->bd_bh); | 150 | gfs2_meta_check(sdp, bd->bd_bh); |
150 | gfs2_pin(sdp, bd->bd_bh); | 151 | gfs2_pin(sdp, bd->bd_bh); |
152 | mh = (struct gfs2_meta_header *)bd->bd_bh->b_data; | ||
153 | mh->__pad0 = cpu_to_be64(0); | ||
154 | mh->mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid); | ||
151 | sdp->sd_log_num_buf++; | 155 | sdp->sd_log_num_buf++; |
152 | list_add(&le->le_list, &sdp->sd_log_le_buf); | 156 | list_add(&le->le_list, &sdp->sd_log_le_buf); |
153 | tr->tr_num_buf_new++; | 157 | tr->tr_num_buf_new++; |
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index eacd78a5d082..5b31f7741a8f 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c | |||
@@ -114,7 +114,7 @@ static int __init init_gfs2_fs(void) | |||
114 | if (error) | 114 | if (error) |
115 | goto fail_unregister; | 115 | goto fail_unregister; |
116 | 116 | ||
117 | error = slow_work_register_user(); | 117 | error = slow_work_register_user(THIS_MODULE); |
118 | if (error) | 118 | if (error) |
119 | goto fail_slow; | 119 | goto fail_slow; |
120 | 120 | ||
@@ -163,7 +163,7 @@ static void __exit exit_gfs2_fs(void) | |||
163 | gfs2_unregister_debugfs(); | 163 | gfs2_unregister_debugfs(); |
164 | unregister_filesystem(&gfs2_fs_type); | 164 | unregister_filesystem(&gfs2_fs_type); |
165 | unregister_filesystem(&gfs2meta_fs_type); | 165 | unregister_filesystem(&gfs2meta_fs_type); |
166 | slow_work_unregister_user(); | 166 | slow_work_unregister_user(THIS_MODULE); |
167 | 167 | ||
168 | kmem_cache_destroy(gfs2_quotad_cachep); | 168 | kmem_cache_destroy(gfs2_quotad_cachep); |
169 | kmem_cache_destroy(gfs2_rgrpd_cachep); | 169 | kmem_cache_destroy(gfs2_rgrpd_cachep); |
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 52fb6c048981..edfee24f3636 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/mount.h> | 18 | #include <linux/mount.h> |
19 | #include <linux/gfs2_ondisk.h> | 19 | #include <linux/gfs2_ondisk.h> |
20 | #include <linux/slow-work.h> | 20 | #include <linux/slow-work.h> |
21 | #include <linux/quotaops.h> | ||
21 | 22 | ||
22 | #include "gfs2.h" | 23 | #include "gfs2.h" |
23 | #include "incore.h" | 24 | #include "incore.h" |
@@ -62,13 +63,10 @@ static void gfs2_tune_init(struct gfs2_tune *gt) | |||
62 | gt->gt_quota_warn_period = 10; | 63 | gt->gt_quota_warn_period = 10; |
63 | gt->gt_quota_scale_num = 1; | 64 | gt->gt_quota_scale_num = 1; |
64 | gt->gt_quota_scale_den = 1; | 65 | gt->gt_quota_scale_den = 1; |
65 | gt->gt_quota_quantum = 60; | ||
66 | gt->gt_new_files_jdata = 0; | 66 | gt->gt_new_files_jdata = 0; |
67 | gt->gt_max_readahead = 1 << 18; | 67 | gt->gt_max_readahead = 1 << 18; |
68 | gt->gt_stall_secs = 600; | 68 | gt->gt_stall_secs = 600; |
69 | gt->gt_complain_secs = 10; | 69 | gt->gt_complain_secs = 10; |
70 | gt->gt_statfs_quantum = 30; | ||
71 | gt->gt_statfs_slow = 0; | ||
72 | } | 70 | } |
73 | 71 | ||
74 | static struct gfs2_sbd *init_sbd(struct super_block *sb) | 72 | static struct gfs2_sbd *init_sbd(struct super_block *sb) |
@@ -1114,7 +1112,7 @@ void gfs2_online_uevent(struct gfs2_sbd *sdp) | |||
1114 | * Returns: errno | 1112 | * Returns: errno |
1115 | */ | 1113 | */ |
1116 | 1114 | ||
1117 | static int fill_super(struct super_block *sb, void *data, int silent) | 1115 | static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent) |
1118 | { | 1116 | { |
1119 | struct gfs2_sbd *sdp; | 1117 | struct gfs2_sbd *sdp; |
1120 | struct gfs2_holder mount_gh; | 1118 | struct gfs2_holder mount_gh; |
@@ -1125,17 +1123,7 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
1125 | printk(KERN_WARNING "GFS2: can't alloc struct gfs2_sbd\n"); | 1123 | printk(KERN_WARNING "GFS2: can't alloc struct gfs2_sbd\n"); |
1126 | return -ENOMEM; | 1124 | return -ENOMEM; |
1127 | } | 1125 | } |
1128 | 1126 | sdp->sd_args = *args; | |
1129 | sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT; | ||
1130 | sdp->sd_args.ar_data = GFS2_DATA_DEFAULT; | ||
1131 | sdp->sd_args.ar_commit = 60; | ||
1132 | sdp->sd_args.ar_errors = GFS2_ERRORS_DEFAULT; | ||
1133 | |||
1134 | error = gfs2_mount_args(sdp, &sdp->sd_args, data); | ||
1135 | if (error) { | ||
1136 | printk(KERN_WARNING "GFS2: can't parse mount arguments\n"); | ||
1137 | goto fail; | ||
1138 | } | ||
1139 | 1127 | ||
1140 | if (sdp->sd_args.ar_spectator) { | 1128 | if (sdp->sd_args.ar_spectator) { |
1141 | sb->s_flags |= MS_RDONLY; | 1129 | sb->s_flags |= MS_RDONLY; |
@@ -1143,11 +1131,15 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
1143 | } | 1131 | } |
1144 | if (sdp->sd_args.ar_posix_acl) | 1132 | if (sdp->sd_args.ar_posix_acl) |
1145 | sb->s_flags |= MS_POSIXACL; | 1133 | sb->s_flags |= MS_POSIXACL; |
1134 | if (sdp->sd_args.ar_nobarrier) | ||
1135 | set_bit(SDF_NOBARRIERS, &sdp->sd_flags); | ||
1146 | 1136 | ||
1147 | sb->s_magic = GFS2_MAGIC; | 1137 | sb->s_magic = GFS2_MAGIC; |
1148 | sb->s_op = &gfs2_super_ops; | 1138 | sb->s_op = &gfs2_super_ops; |
1149 | sb->s_export_op = &gfs2_export_ops; | 1139 | sb->s_export_op = &gfs2_export_ops; |
1150 | sb->s_xattr = gfs2_xattr_handlers; | 1140 | sb->s_xattr = gfs2_xattr_handlers; |
1141 | sb->s_qcop = &gfs2_quotactl_ops; | ||
1142 | sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE; | ||
1151 | sb->s_time_gran = 1; | 1143 | sb->s_time_gran = 1; |
1152 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 1144 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
1153 | 1145 | ||
@@ -1160,6 +1152,15 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
1160 | sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift; | 1152 | sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift; |
1161 | 1153 | ||
1162 | sdp->sd_tune.gt_log_flush_secs = sdp->sd_args.ar_commit; | 1154 | sdp->sd_tune.gt_log_flush_secs = sdp->sd_args.ar_commit; |
1155 | sdp->sd_tune.gt_quota_quantum = sdp->sd_args.ar_quota_quantum; | ||
1156 | if (sdp->sd_args.ar_statfs_quantum) { | ||
1157 | sdp->sd_tune.gt_statfs_slow = 0; | ||
1158 | sdp->sd_tune.gt_statfs_quantum = sdp->sd_args.ar_statfs_quantum; | ||
1159 | } | ||
1160 | else { | ||
1161 | sdp->sd_tune.gt_statfs_slow = 1; | ||
1162 | sdp->sd_tune.gt_statfs_quantum = 30; | ||
1163 | } | ||
1163 | 1164 | ||
1164 | error = init_names(sdp, silent); | 1165 | error = init_names(sdp, silent); |
1165 | if (error) | 1166 | if (error) |
@@ -1243,18 +1244,127 @@ fail: | |||
1243 | return error; | 1244 | return error; |
1244 | } | 1245 | } |
1245 | 1246 | ||
1246 | static int gfs2_get_sb(struct file_system_type *fs_type, int flags, | 1247 | static int set_gfs2_super(struct super_block *s, void *data) |
1247 | const char *dev_name, void *data, struct vfsmount *mnt) | ||
1248 | { | 1248 | { |
1249 | return get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt); | 1249 | s->s_bdev = data; |
1250 | s->s_dev = s->s_bdev->bd_dev; | ||
1251 | |||
1252 | /* | ||
1253 | * We set the bdi here to the queue backing, file systems can | ||
1254 | * overwrite this in ->fill_super() | ||
1255 | */ | ||
1256 | s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info; | ||
1257 | return 0; | ||
1250 | } | 1258 | } |
1251 | 1259 | ||
1252 | static int test_meta_super(struct super_block *s, void *ptr) | 1260 | static int test_gfs2_super(struct super_block *s, void *ptr) |
1253 | { | 1261 | { |
1254 | struct block_device *bdev = ptr; | 1262 | struct block_device *bdev = ptr; |
1255 | return (bdev == s->s_bdev); | 1263 | return (bdev == s->s_bdev); |
1256 | } | 1264 | } |
1257 | 1265 | ||
1266 | /** | ||
1267 | * gfs2_get_sb - Get the GFS2 superblock | ||
1268 | * @fs_type: The GFS2 filesystem type | ||
1269 | * @flags: Mount flags | ||
1270 | * @dev_name: The name of the device | ||
1271 | * @data: The mount arguments | ||
1272 | * @mnt: The vfsmnt for this mount | ||
1273 | * | ||
1274 | * Q. Why not use get_sb_bdev() ? | ||
1275 | * A. We need to select one of two root directories to mount, independent | ||
1276 | * of whether this is the initial, or subsequent, mount of this sb | ||
1277 | * | ||
1278 | * Returns: 0 or -ve on error | ||
1279 | */ | ||
1280 | |||
1281 | static int gfs2_get_sb(struct file_system_type *fs_type, int flags, | ||
1282 | const char *dev_name, void *data, struct vfsmount *mnt) | ||
1283 | { | ||
1284 | struct block_device *bdev; | ||
1285 | struct super_block *s; | ||
1286 | fmode_t mode = FMODE_READ; | ||
1287 | int error; | ||
1288 | struct gfs2_args args; | ||
1289 | struct gfs2_sbd *sdp; | ||
1290 | |||
1291 | if (!(flags & MS_RDONLY)) | ||
1292 | mode |= FMODE_WRITE; | ||
1293 | |||
1294 | bdev = open_bdev_exclusive(dev_name, mode, fs_type); | ||
1295 | if (IS_ERR(bdev)) | ||
1296 | return PTR_ERR(bdev); | ||
1297 | |||
1298 | /* | ||
1299 | * once the super is inserted into the list by sget, s_umount | ||
1300 | * will protect the lockfs code from trying to start a snapshot | ||
1301 | * while we are mounting | ||
1302 | */ | ||
1303 | mutex_lock(&bdev->bd_fsfreeze_mutex); | ||
1304 | if (bdev->bd_fsfreeze_count > 0) { | ||
1305 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
1306 | error = -EBUSY; | ||
1307 | goto error_bdev; | ||
1308 | } | ||
1309 | s = sget(fs_type, test_gfs2_super, set_gfs2_super, bdev); | ||
1310 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
1311 | error = PTR_ERR(s); | ||
1312 | if (IS_ERR(s)) | ||
1313 | goto error_bdev; | ||
1314 | |||
1315 | memset(&args, 0, sizeof(args)); | ||
1316 | args.ar_quota = GFS2_QUOTA_DEFAULT; | ||
1317 | args.ar_data = GFS2_DATA_DEFAULT; | ||
1318 | args.ar_commit = 60; | ||
1319 | args.ar_statfs_quantum = 30; | ||
1320 | args.ar_quota_quantum = 60; | ||
1321 | args.ar_errors = GFS2_ERRORS_DEFAULT; | ||
1322 | |||
1323 | error = gfs2_mount_args(&args, data); | ||
1324 | if (error) { | ||
1325 | printk(KERN_WARNING "GFS2: can't parse mount arguments\n"); | ||
1326 | if (s->s_root) | ||
1327 | goto error_super; | ||
1328 | deactivate_locked_super(s); | ||
1329 | return error; | ||
1330 | } | ||
1331 | |||
1332 | if (s->s_root) { | ||
1333 | error = -EBUSY; | ||
1334 | if ((flags ^ s->s_flags) & MS_RDONLY) | ||
1335 | goto error_super; | ||
1336 | close_bdev_exclusive(bdev, mode); | ||
1337 | } else { | ||
1338 | char b[BDEVNAME_SIZE]; | ||
1339 | |||
1340 | s->s_flags = flags; | ||
1341 | s->s_mode = mode; | ||
1342 | strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id)); | ||
1343 | sb_set_blocksize(s, block_size(bdev)); | ||
1344 | error = fill_super(s, &args, flags & MS_SILENT ? 1 : 0); | ||
1345 | if (error) { | ||
1346 | deactivate_locked_super(s); | ||
1347 | return error; | ||
1348 | } | ||
1349 | s->s_flags |= MS_ACTIVE; | ||
1350 | bdev->bd_super = s; | ||
1351 | } | ||
1352 | |||
1353 | sdp = s->s_fs_info; | ||
1354 | mnt->mnt_sb = s; | ||
1355 | if (args.ar_meta) | ||
1356 | mnt->mnt_root = dget(sdp->sd_master_dir); | ||
1357 | else | ||
1358 | mnt->mnt_root = dget(sdp->sd_root_dir); | ||
1359 | return 0; | ||
1360 | |||
1361 | error_super: | ||
1362 | deactivate_locked_super(s); | ||
1363 | error_bdev: | ||
1364 | close_bdev_exclusive(bdev, mode); | ||
1365 | return error; | ||
1366 | } | ||
1367 | |||
1258 | static int set_meta_super(struct super_block *s, void *ptr) | 1368 | static int set_meta_super(struct super_block *s, void *ptr) |
1259 | { | 1369 | { |
1260 | return -EINVAL; | 1370 | return -EINVAL; |
@@ -1274,13 +1384,17 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, | |||
1274 | dev_name, error); | 1384 | dev_name, error); |
1275 | return error; | 1385 | return error; |
1276 | } | 1386 | } |
1277 | s = sget(&gfs2_fs_type, test_meta_super, set_meta_super, | 1387 | s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super, |
1278 | path.dentry->d_inode->i_sb->s_bdev); | 1388 | path.dentry->d_inode->i_sb->s_bdev); |
1279 | path_put(&path); | 1389 | path_put(&path); |
1280 | if (IS_ERR(s)) { | 1390 | if (IS_ERR(s)) { |
1281 | printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n"); | 1391 | printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n"); |
1282 | return PTR_ERR(s); | 1392 | return PTR_ERR(s); |
1283 | } | 1393 | } |
1394 | if ((flags ^ s->s_flags) & MS_RDONLY) { | ||
1395 | deactivate_locked_super(s); | ||
1396 | return -EBUSY; | ||
1397 | } | ||
1284 | sdp = s->s_fs_info; | 1398 | sdp = s->s_fs_info; |
1285 | mnt->mnt_sb = s; | 1399 | mnt->mnt_sb = s; |
1286 | mnt->mnt_root = dget(sdp->sd_master_dir); | 1400 | mnt->mnt_root = dget(sdp->sd_master_dir); |
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 2e9b9326bfc9..e3bf6eab8750 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c | |||
@@ -15,7 +15,7 @@ | |||
15 | * fuzziness in the current usage value of IDs that are being used on different | 15 | * fuzziness in the current usage value of IDs that are being used on different |
16 | * nodes in the cluster simultaneously. So, it is possible for a user on | 16 | * nodes in the cluster simultaneously. So, it is possible for a user on |
17 | * multiple nodes to overrun their quota, but that overrun is controlable. | 17 | * multiple nodes to overrun their quota, but that overrun is controlable. |
18 | * Since quota tags are part of transactions, there is no need to a quota check | 18 | * Since quota tags are part of transactions, there is no need for a quota check |
19 | * program to be run on node crashes or anything like that. | 19 | * program to be run on node crashes or anything like that. |
20 | * | 20 | * |
21 | * There are couple of knobs that let the administrator manage the quota | 21 | * There are couple of knobs that let the administrator manage the quota |
@@ -47,6 +47,8 @@ | |||
47 | #include <linux/gfs2_ondisk.h> | 47 | #include <linux/gfs2_ondisk.h> |
48 | #include <linux/kthread.h> | 48 | #include <linux/kthread.h> |
49 | #include <linux/freezer.h> | 49 | #include <linux/freezer.h> |
50 | #include <linux/quota.h> | ||
51 | #include <linux/dqblk_xfs.h> | ||
50 | 52 | ||
51 | #include "gfs2.h" | 53 | #include "gfs2.h" |
52 | #include "incore.h" | 54 | #include "incore.h" |
@@ -65,13 +67,6 @@ | |||
65 | #define QUOTA_USER 1 | 67 | #define QUOTA_USER 1 |
66 | #define QUOTA_GROUP 0 | 68 | #define QUOTA_GROUP 0 |
67 | 69 | ||
68 | struct gfs2_quota_host { | ||
69 | u64 qu_limit; | ||
70 | u64 qu_warn; | ||
71 | s64 qu_value; | ||
72 | u32 qu_ll_next; | ||
73 | }; | ||
74 | |||
75 | struct gfs2_quota_change_host { | 70 | struct gfs2_quota_change_host { |
76 | u64 qc_change; | 71 | u64 qc_change; |
77 | u32 qc_flags; /* GFS2_QCF_... */ | 72 | u32 qc_flags; /* GFS2_QCF_... */ |
@@ -164,7 +159,7 @@ fail: | |||
164 | return error; | 159 | return error; |
165 | } | 160 | } |
166 | 161 | ||
167 | static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create, | 162 | static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, |
168 | struct gfs2_quota_data **qdp) | 163 | struct gfs2_quota_data **qdp) |
169 | { | 164 | { |
170 | struct gfs2_quota_data *qd = NULL, *new_qd = NULL; | 165 | struct gfs2_quota_data *qd = NULL, *new_qd = NULL; |
@@ -202,7 +197,7 @@ static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create, | |||
202 | 197 | ||
203 | spin_unlock(&qd_lru_lock); | 198 | spin_unlock(&qd_lru_lock); |
204 | 199 | ||
205 | if (qd || !create) { | 200 | if (qd) { |
206 | if (new_qd) { | 201 | if (new_qd) { |
207 | gfs2_glock_put(new_qd->qd_gl); | 202 | gfs2_glock_put(new_qd->qd_gl); |
208 | kmem_cache_free(gfs2_quotad_cachep, new_qd); | 203 | kmem_cache_free(gfs2_quotad_cachep, new_qd); |
@@ -461,12 +456,12 @@ static void qd_unlock(struct gfs2_quota_data *qd) | |||
461 | qd_put(qd); | 456 | qd_put(qd); |
462 | } | 457 | } |
463 | 458 | ||
464 | static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id, int create, | 459 | static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id, |
465 | struct gfs2_quota_data **qdp) | 460 | struct gfs2_quota_data **qdp) |
466 | { | 461 | { |
467 | int error; | 462 | int error; |
468 | 463 | ||
469 | error = qd_get(sdp, user, id, create, qdp); | 464 | error = qd_get(sdp, user, id, qdp); |
470 | if (error) | 465 | if (error) |
471 | return error; | 466 | return error; |
472 | 467 | ||
@@ -508,20 +503,20 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid) | |||
508 | if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) | 503 | if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) |
509 | return 0; | 504 | return 0; |
510 | 505 | ||
511 | error = qdsb_get(sdp, QUOTA_USER, ip->i_inode.i_uid, CREATE, qd); | 506 | error = qdsb_get(sdp, QUOTA_USER, ip->i_inode.i_uid, qd); |
512 | if (error) | 507 | if (error) |
513 | goto out; | 508 | goto out; |
514 | al->al_qd_num++; | 509 | al->al_qd_num++; |
515 | qd++; | 510 | qd++; |
516 | 511 | ||
517 | error = qdsb_get(sdp, QUOTA_GROUP, ip->i_inode.i_gid, CREATE, qd); | 512 | error = qdsb_get(sdp, QUOTA_GROUP, ip->i_inode.i_gid, qd); |
518 | if (error) | 513 | if (error) |
519 | goto out; | 514 | goto out; |
520 | al->al_qd_num++; | 515 | al->al_qd_num++; |
521 | qd++; | 516 | qd++; |
522 | 517 | ||
523 | if (uid != NO_QUOTA_CHANGE && uid != ip->i_inode.i_uid) { | 518 | if (uid != NO_QUOTA_CHANGE && uid != ip->i_inode.i_uid) { |
524 | error = qdsb_get(sdp, QUOTA_USER, uid, CREATE, qd); | 519 | error = qdsb_get(sdp, QUOTA_USER, uid, qd); |
525 | if (error) | 520 | if (error) |
526 | goto out; | 521 | goto out; |
527 | al->al_qd_num++; | 522 | al->al_qd_num++; |
@@ -529,7 +524,7 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid) | |||
529 | } | 524 | } |
530 | 525 | ||
531 | if (gid != NO_QUOTA_CHANGE && gid != ip->i_inode.i_gid) { | 526 | if (gid != NO_QUOTA_CHANGE && gid != ip->i_inode.i_gid) { |
532 | error = qdsb_get(sdp, QUOTA_GROUP, gid, CREATE, qd); | 527 | error = qdsb_get(sdp, QUOTA_GROUP, gid, qd); |
533 | if (error) | 528 | if (error) |
534 | goto out; | 529 | goto out; |
535 | al->al_qd_num++; | 530 | al->al_qd_num++; |
@@ -617,48 +612,36 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change) | |||
617 | mutex_unlock(&sdp->sd_quota_mutex); | 612 | mutex_unlock(&sdp->sd_quota_mutex); |
618 | } | 613 | } |
619 | 614 | ||
620 | static void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf) | ||
621 | { | ||
622 | const struct gfs2_quota *str = buf; | ||
623 | |||
624 | qu->qu_limit = be64_to_cpu(str->qu_limit); | ||
625 | qu->qu_warn = be64_to_cpu(str->qu_warn); | ||
626 | qu->qu_value = be64_to_cpu(str->qu_value); | ||
627 | qu->qu_ll_next = be32_to_cpu(str->qu_ll_next); | ||
628 | } | ||
629 | |||
630 | static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf) | ||
631 | { | ||
632 | struct gfs2_quota *str = buf; | ||
633 | |||
634 | str->qu_limit = cpu_to_be64(qu->qu_limit); | ||
635 | str->qu_warn = cpu_to_be64(qu->qu_warn); | ||
636 | str->qu_value = cpu_to_be64(qu->qu_value); | ||
637 | str->qu_ll_next = cpu_to_be32(qu->qu_ll_next); | ||
638 | memset(&str->qu_reserved, 0, sizeof(str->qu_reserved)); | ||
639 | } | ||
640 | |||
641 | /** | 615 | /** |
642 | * gfs2_adjust_quota | 616 | * gfs2_adjust_quota - adjust record of current block usage |
617 | * @ip: The quota inode | ||
618 | * @loc: Offset of the entry in the quota file | ||
619 | * @change: The amount of usage change to record | ||
620 | * @qd: The quota data | ||
621 | * @fdq: The updated limits to record | ||
643 | * | 622 | * |
644 | * This function was mostly borrowed from gfs2_block_truncate_page which was | 623 | * This function was mostly borrowed from gfs2_block_truncate_page which was |
645 | * in turn mostly borrowed from ext3 | 624 | * in turn mostly borrowed from ext3 |
625 | * | ||
626 | * Returns: 0 or -ve on error | ||
646 | */ | 627 | */ |
628 | |||
647 | static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, | 629 | static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, |
648 | s64 change, struct gfs2_quota_data *qd) | 630 | s64 change, struct gfs2_quota_data *qd, |
631 | struct fs_disk_quota *fdq) | ||
649 | { | 632 | { |
650 | struct inode *inode = &ip->i_inode; | 633 | struct inode *inode = &ip->i_inode; |
651 | struct address_space *mapping = inode->i_mapping; | 634 | struct address_space *mapping = inode->i_mapping; |
652 | unsigned long index = loc >> PAGE_CACHE_SHIFT; | 635 | unsigned long index = loc >> PAGE_CACHE_SHIFT; |
653 | unsigned offset = loc & (PAGE_CACHE_SIZE - 1); | 636 | unsigned offset = loc & (PAGE_CACHE_SIZE - 1); |
654 | unsigned blocksize, iblock, pos; | 637 | unsigned blocksize, iblock, pos; |
655 | struct buffer_head *bh; | 638 | struct buffer_head *bh, *dibh; |
656 | struct page *page; | 639 | struct page *page; |
657 | void *kaddr; | 640 | void *kaddr; |
658 | char *ptr; | 641 | struct gfs2_quota *qp; |
659 | struct gfs2_quota_host qp; | ||
660 | s64 value; | 642 | s64 value; |
661 | int err = -EIO; | 643 | int err = -EIO; |
644 | u64 size; | ||
662 | 645 | ||
663 | if (gfs2_is_stuffed(ip)) | 646 | if (gfs2_is_stuffed(ip)) |
664 | gfs2_unstuff_dinode(ip, NULL); | 647 | gfs2_unstuff_dinode(ip, NULL); |
@@ -700,18 +683,38 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, | |||
700 | gfs2_trans_add_bh(ip->i_gl, bh, 0); | 683 | gfs2_trans_add_bh(ip->i_gl, bh, 0); |
701 | 684 | ||
702 | kaddr = kmap_atomic(page, KM_USER0); | 685 | kaddr = kmap_atomic(page, KM_USER0); |
703 | ptr = kaddr + offset; | 686 | qp = kaddr + offset; |
704 | gfs2_quota_in(&qp, ptr); | 687 | value = (s64)be64_to_cpu(qp->qu_value) + change; |
705 | qp.qu_value += change; | 688 | qp->qu_value = cpu_to_be64(value); |
706 | value = qp.qu_value; | 689 | qd->qd_qb.qb_value = qp->qu_value; |
707 | gfs2_quota_out(&qp, ptr); | 690 | if (fdq) { |
691 | if (fdq->d_fieldmask & FS_DQ_BSOFT) { | ||
692 | qp->qu_warn = cpu_to_be64(fdq->d_blk_softlimit); | ||
693 | qd->qd_qb.qb_warn = qp->qu_warn; | ||
694 | } | ||
695 | if (fdq->d_fieldmask & FS_DQ_BHARD) { | ||
696 | qp->qu_limit = cpu_to_be64(fdq->d_blk_hardlimit); | ||
697 | qd->qd_qb.qb_limit = qp->qu_limit; | ||
698 | } | ||
699 | } | ||
708 | flush_dcache_page(page); | 700 | flush_dcache_page(page); |
709 | kunmap_atomic(kaddr, KM_USER0); | 701 | kunmap_atomic(kaddr, KM_USER0); |
710 | err = 0; | 702 | |
711 | qd->qd_qb.qb_magic = cpu_to_be32(GFS2_MAGIC); | 703 | err = gfs2_meta_inode_buffer(ip, &dibh); |
712 | qd->qd_qb.qb_value = cpu_to_be64(value); | 704 | if (err) |
713 | ((struct gfs2_quota_lvb*)(qd->qd_gl->gl_lvb))->qb_magic = cpu_to_be32(GFS2_MAGIC); | 705 | goto unlock; |
714 | ((struct gfs2_quota_lvb*)(qd->qd_gl->gl_lvb))->qb_value = cpu_to_be64(value); | 706 | |
707 | size = loc + sizeof(struct gfs2_quota); | ||
708 | if (size > inode->i_size) { | ||
709 | ip->i_disksize = size; | ||
710 | i_size_write(inode, size); | ||
711 | } | ||
712 | inode->i_mtime = inode->i_atime = CURRENT_TIME; | ||
713 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
714 | gfs2_dinode_out(ip, dibh->b_data); | ||
715 | brelse(dibh); | ||
716 | mark_inode_dirty(inode); | ||
717 | |||
715 | unlock: | 718 | unlock: |
716 | unlock_page(page); | 719 | unlock_page(page); |
717 | page_cache_release(page); | 720 | page_cache_release(page); |
@@ -739,9 +742,9 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) | |||
739 | return -ENOMEM; | 742 | return -ENOMEM; |
740 | 743 | ||
741 | sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL); | 744 | sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL); |
745 | mutex_lock_nested(&ip->i_inode.i_mutex, I_MUTEX_QUOTA); | ||
742 | for (qx = 0; qx < num_qd; qx++) { | 746 | for (qx = 0; qx < num_qd; qx++) { |
743 | error = gfs2_glock_nq_init(qda[qx]->qd_gl, | 747 | error = gfs2_glock_nq_init(qda[qx]->qd_gl, LM_ST_EXCLUSIVE, |
744 | LM_ST_EXCLUSIVE, | ||
745 | GL_NOCACHE, &ghs[qx]); | 748 | GL_NOCACHE, &ghs[qx]); |
746 | if (error) | 749 | if (error) |
747 | goto out; | 750 | goto out; |
@@ -795,9 +798,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) | |||
795 | for (x = 0; x < num_qd; x++) { | 798 | for (x = 0; x < num_qd; x++) { |
796 | qd = qda[x]; | 799 | qd = qda[x]; |
797 | offset = qd2offset(qd); | 800 | offset = qd2offset(qd); |
798 | error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync, | 801 | error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync, qd, NULL); |
799 | (struct gfs2_quota_data *) | ||
800 | qd); | ||
801 | if (error) | 802 | if (error) |
802 | goto out_end_trans; | 803 | goto out_end_trans; |
803 | 804 | ||
@@ -817,21 +818,44 @@ out_gunlock: | |||
817 | out: | 818 | out: |
818 | while (qx--) | 819 | while (qx--) |
819 | gfs2_glock_dq_uninit(&ghs[qx]); | 820 | gfs2_glock_dq_uninit(&ghs[qx]); |
821 | mutex_unlock(&ip->i_inode.i_mutex); | ||
820 | kfree(ghs); | 822 | kfree(ghs); |
821 | gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); | 823 | gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); |
822 | return error; | 824 | return error; |
823 | } | 825 | } |
824 | 826 | ||
827 | static int update_qd(struct gfs2_sbd *sdp, struct gfs2_quota_data *qd) | ||
828 | { | ||
829 | struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); | ||
830 | struct gfs2_quota q; | ||
831 | struct gfs2_quota_lvb *qlvb; | ||
832 | loff_t pos; | ||
833 | int error; | ||
834 | |||
835 | memset(&q, 0, sizeof(struct gfs2_quota)); | ||
836 | pos = qd2offset(qd); | ||
837 | error = gfs2_internal_read(ip, NULL, (char *)&q, &pos, sizeof(q)); | ||
838 | if (error < 0) | ||
839 | return error; | ||
840 | |||
841 | qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; | ||
842 | qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC); | ||
843 | qlvb->__pad = 0; | ||
844 | qlvb->qb_limit = q.qu_limit; | ||
845 | qlvb->qb_warn = q.qu_warn; | ||
846 | qlvb->qb_value = q.qu_value; | ||
847 | qd->qd_qb = *qlvb; | ||
848 | |||
849 | return 0; | ||
850 | } | ||
851 | |||
825 | static int do_glock(struct gfs2_quota_data *qd, int force_refresh, | 852 | static int do_glock(struct gfs2_quota_data *qd, int force_refresh, |
826 | struct gfs2_holder *q_gh) | 853 | struct gfs2_holder *q_gh) |
827 | { | 854 | { |
828 | struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; | 855 | struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; |
829 | struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); | 856 | struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); |
830 | struct gfs2_holder i_gh; | 857 | struct gfs2_holder i_gh; |
831 | struct gfs2_quota_host q; | ||
832 | char buf[sizeof(struct gfs2_quota)]; | ||
833 | int error; | 858 | int error; |
834 | struct gfs2_quota_lvb *qlvb; | ||
835 | 859 | ||
836 | restart: | 860 | restart: |
837 | error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh); | 861 | error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh); |
@@ -841,11 +865,9 @@ restart: | |||
841 | qd->qd_qb = *(struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; | 865 | qd->qd_qb = *(struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; |
842 | 866 | ||
843 | if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) { | 867 | if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) { |
844 | loff_t pos; | ||
845 | gfs2_glock_dq_uninit(q_gh); | 868 | gfs2_glock_dq_uninit(q_gh); |
846 | error = gfs2_glock_nq_init(qd->qd_gl, | 869 | error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_EXCLUSIVE, |
847 | LM_ST_EXCLUSIVE, GL_NOCACHE, | 870 | GL_NOCACHE, q_gh); |
848 | q_gh); | ||
849 | if (error) | 871 | if (error) |
850 | return error; | 872 | return error; |
851 | 873 | ||
@@ -853,29 +875,14 @@ restart: | |||
853 | if (error) | 875 | if (error) |
854 | goto fail; | 876 | goto fail; |
855 | 877 | ||
856 | memset(buf, 0, sizeof(struct gfs2_quota)); | 878 | error = update_qd(sdp, qd); |
857 | pos = qd2offset(qd); | 879 | if (error) |
858 | error = gfs2_internal_read(ip, NULL, buf, &pos, | ||
859 | sizeof(struct gfs2_quota)); | ||
860 | if (error < 0) | ||
861 | goto fail_gunlock; | 880 | goto fail_gunlock; |
862 | 881 | ||
863 | gfs2_glock_dq_uninit(&i_gh); | 882 | gfs2_glock_dq_uninit(&i_gh); |
864 | 883 | gfs2_glock_dq_uninit(q_gh); | |
865 | gfs2_quota_in(&q, buf); | 884 | force_refresh = 0; |
866 | qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; | 885 | goto restart; |
867 | qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC); | ||
868 | qlvb->__pad = 0; | ||
869 | qlvb->qb_limit = cpu_to_be64(q.qu_limit); | ||
870 | qlvb->qb_warn = cpu_to_be64(q.qu_warn); | ||
871 | qlvb->qb_value = cpu_to_be64(q.qu_value); | ||
872 | qd->qd_qb = *qlvb; | ||
873 | |||
874 | if (gfs2_glock_is_blocking(qd->qd_gl)) { | ||
875 | gfs2_glock_dq_uninit(q_gh); | ||
876 | force_refresh = 0; | ||
877 | goto restart; | ||
878 | } | ||
879 | } | 886 | } |
880 | 887 | ||
881 | return 0; | 888 | return 0; |
@@ -995,7 +1002,7 @@ static int print_message(struct gfs2_quota_data *qd, char *type) | |||
995 | { | 1002 | { |
996 | struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; | 1003 | struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; |
997 | 1004 | ||
998 | printk(KERN_INFO "GFS2: fsid=%s: quota %s for %s %u\r\n", | 1005 | printk(KERN_INFO "GFS2: fsid=%s: quota %s for %s %u\n", |
999 | sdp->sd_fsname, type, | 1006 | sdp->sd_fsname, type, |
1000 | (test_bit(QDF_USER, &qd->qd_flags)) ? "user" : "group", | 1007 | (test_bit(QDF_USER, &qd->qd_flags)) ? "user" : "group", |
1001 | qd->qd_id); | 1008 | qd->qd_id); |
@@ -1032,6 +1039,10 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid) | |||
1032 | 1039 | ||
1033 | if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) { | 1040 | if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) { |
1034 | print_message(qd, "exceeded"); | 1041 | print_message(qd, "exceeded"); |
1042 | quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ? | ||
1043 | USRQUOTA : GRPQUOTA, qd->qd_id, | ||
1044 | sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN); | ||
1045 | |||
1035 | error = -EDQUOT; | 1046 | error = -EDQUOT; |
1036 | break; | 1047 | break; |
1037 | } else if (be64_to_cpu(qd->qd_qb.qb_warn) && | 1048 | } else if (be64_to_cpu(qd->qd_qb.qb_warn) && |
@@ -1039,6 +1050,9 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid) | |||
1039 | time_after_eq(jiffies, qd->qd_last_warn + | 1050 | time_after_eq(jiffies, qd->qd_last_warn + |
1040 | gfs2_tune_get(sdp, | 1051 | gfs2_tune_get(sdp, |
1041 | gt_quota_warn_period) * HZ)) { | 1052 | gt_quota_warn_period) * HZ)) { |
1053 | quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ? | ||
1054 | USRQUOTA : GRPQUOTA, qd->qd_id, | ||
1055 | sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN); | ||
1042 | error = print_message(qd, "warning"); | 1056 | error = print_message(qd, "warning"); |
1043 | qd->qd_last_warn = jiffies; | 1057 | qd->qd_last_warn = jiffies; |
1044 | } | 1058 | } |
@@ -1069,8 +1083,9 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change, | |||
1069 | } | 1083 | } |
1070 | } | 1084 | } |
1071 | 1085 | ||
1072 | int gfs2_quota_sync(struct gfs2_sbd *sdp) | 1086 | int gfs2_quota_sync(struct super_block *sb, int type) |
1073 | { | 1087 | { |
1088 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
1074 | struct gfs2_quota_data **qda; | 1089 | struct gfs2_quota_data **qda; |
1075 | unsigned int max_qd = gfs2_tune_get(sdp, gt_quota_simul_sync); | 1090 | unsigned int max_qd = gfs2_tune_get(sdp, gt_quota_simul_sync); |
1076 | unsigned int num_qd; | 1091 | unsigned int num_qd; |
@@ -1118,7 +1133,7 @@ int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id) | |||
1118 | struct gfs2_holder q_gh; | 1133 | struct gfs2_holder q_gh; |
1119 | int error; | 1134 | int error; |
1120 | 1135 | ||
1121 | error = qd_get(sdp, user, id, CREATE, &qd); | 1136 | error = qd_get(sdp, user, id, &qd); |
1122 | if (error) | 1137 | if (error) |
1123 | return error; | 1138 | return error; |
1124 | 1139 | ||
@@ -1127,7 +1142,6 @@ int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id) | |||
1127 | gfs2_glock_dq_uninit(&q_gh); | 1142 | gfs2_glock_dq_uninit(&q_gh); |
1128 | 1143 | ||
1129 | qd_put(qd); | 1144 | qd_put(qd); |
1130 | |||
1131 | return error; | 1145 | return error; |
1132 | } | 1146 | } |
1133 | 1147 | ||
@@ -1298,12 +1312,12 @@ static void quotad_error(struct gfs2_sbd *sdp, const char *msg, int error) | |||
1298 | } | 1312 | } |
1299 | 1313 | ||
1300 | static void quotad_check_timeo(struct gfs2_sbd *sdp, const char *msg, | 1314 | static void quotad_check_timeo(struct gfs2_sbd *sdp, const char *msg, |
1301 | int (*fxn)(struct gfs2_sbd *sdp), | 1315 | int (*fxn)(struct super_block *sb, int type), |
1302 | unsigned long t, unsigned long *timeo, | 1316 | unsigned long t, unsigned long *timeo, |
1303 | unsigned int *new_timeo) | 1317 | unsigned int *new_timeo) |
1304 | { | 1318 | { |
1305 | if (t >= *timeo) { | 1319 | if (t >= *timeo) { |
1306 | int error = fxn(sdp); | 1320 | int error = fxn(sdp->sd_vfs, 0); |
1307 | quotad_error(sdp, msg, error); | 1321 | quotad_error(sdp, msg, error); |
1308 | *timeo = gfs2_tune_get_i(&sdp->sd_tune, new_timeo) * HZ; | 1322 | *timeo = gfs2_tune_get_i(&sdp->sd_tune, new_timeo) * HZ; |
1309 | } else { | 1323 | } else { |
@@ -1330,6 +1344,14 @@ static void quotad_check_trunc_list(struct gfs2_sbd *sdp) | |||
1330 | } | 1344 | } |
1331 | } | 1345 | } |
1332 | 1346 | ||
1347 | void gfs2_wake_up_statfs(struct gfs2_sbd *sdp) { | ||
1348 | if (!sdp->sd_statfs_force_sync) { | ||
1349 | sdp->sd_statfs_force_sync = 1; | ||
1350 | wake_up(&sdp->sd_quota_wait); | ||
1351 | } | ||
1352 | } | ||
1353 | |||
1354 | |||
1333 | /** | 1355 | /** |
1334 | * gfs2_quotad - Write cached quota changes into the quota file | 1356 | * gfs2_quotad - Write cached quota changes into the quota file |
1335 | * @sdp: Pointer to GFS2 superblock | 1357 | * @sdp: Pointer to GFS2 superblock |
@@ -1349,8 +1371,15 @@ int gfs2_quotad(void *data) | |||
1349 | while (!kthread_should_stop()) { | 1371 | while (!kthread_should_stop()) { |
1350 | 1372 | ||
1351 | /* Update the master statfs file */ | 1373 | /* Update the master statfs file */ |
1352 | quotad_check_timeo(sdp, "statfs", gfs2_statfs_sync, t, | 1374 | if (sdp->sd_statfs_force_sync) { |
1353 | &statfs_timeo, &tune->gt_statfs_quantum); | 1375 | int error = gfs2_statfs_sync(sdp->sd_vfs, 0); |
1376 | quotad_error(sdp, "statfs", error); | ||
1377 | statfs_timeo = gfs2_tune_get(sdp, gt_statfs_quantum) * HZ; | ||
1378 | } | ||
1379 | else | ||
1380 | quotad_check_timeo(sdp, "statfs", gfs2_statfs_sync, t, | ||
1381 | &statfs_timeo, | ||
1382 | &tune->gt_statfs_quantum); | ||
1354 | 1383 | ||
1355 | /* Update quota file */ | 1384 | /* Update quota file */ |
1356 | quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t, | 1385 | quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t, |
@@ -1367,7 +1396,7 @@ int gfs2_quotad(void *data) | |||
1367 | spin_lock(&sdp->sd_trunc_lock); | 1396 | spin_lock(&sdp->sd_trunc_lock); |
1368 | empty = list_empty(&sdp->sd_trunc_list); | 1397 | empty = list_empty(&sdp->sd_trunc_list); |
1369 | spin_unlock(&sdp->sd_trunc_lock); | 1398 | spin_unlock(&sdp->sd_trunc_lock); |
1370 | if (empty) | 1399 | if (empty && !sdp->sd_statfs_force_sync) |
1371 | t -= schedule_timeout(t); | 1400 | t -= schedule_timeout(t); |
1372 | else | 1401 | else |
1373 | t = 0; | 1402 | t = 0; |
@@ -1377,3 +1406,181 @@ int gfs2_quotad(void *data) | |||
1377 | return 0; | 1406 | return 0; |
1378 | } | 1407 | } |
1379 | 1408 | ||
1409 | static int gfs2_quota_get_xstate(struct super_block *sb, | ||
1410 | struct fs_quota_stat *fqs) | ||
1411 | { | ||
1412 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
1413 | |||
1414 | memset(fqs, 0, sizeof(struct fs_quota_stat)); | ||
1415 | fqs->qs_version = FS_QSTAT_VERSION; | ||
1416 | if (sdp->sd_args.ar_quota == GFS2_QUOTA_ON) | ||
1417 | fqs->qs_flags = (XFS_QUOTA_UDQ_ENFD | XFS_QUOTA_GDQ_ENFD); | ||
1418 | else if (sdp->sd_args.ar_quota == GFS2_QUOTA_ACCOUNT) | ||
1419 | fqs->qs_flags = (XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_GDQ_ACCT); | ||
1420 | if (sdp->sd_quota_inode) { | ||
1421 | fqs->qs_uquota.qfs_ino = GFS2_I(sdp->sd_quota_inode)->i_no_addr; | ||
1422 | fqs->qs_uquota.qfs_nblks = sdp->sd_quota_inode->i_blocks; | ||
1423 | } | ||
1424 | fqs->qs_uquota.qfs_nextents = 1; /* unsupported */ | ||
1425 | fqs->qs_gquota = fqs->qs_uquota; /* its the same inode in both cases */ | ||
1426 | fqs->qs_incoredqs = atomic_read(&qd_lru_count); | ||
1427 | return 0; | ||
1428 | } | ||
1429 | |||
1430 | static int gfs2_xquota_get(struct super_block *sb, int type, qid_t id, | ||
1431 | struct fs_disk_quota *fdq) | ||
1432 | { | ||
1433 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
1434 | struct gfs2_quota_lvb *qlvb; | ||
1435 | struct gfs2_quota_data *qd; | ||
1436 | struct gfs2_holder q_gh; | ||
1437 | int error; | ||
1438 | |||
1439 | memset(fdq, 0, sizeof(struct fs_disk_quota)); | ||
1440 | |||
1441 | if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) | ||
1442 | return -ESRCH; /* Crazy XFS error code */ | ||
1443 | |||
1444 | if (type == USRQUOTA) | ||
1445 | type = QUOTA_USER; | ||
1446 | else if (type == GRPQUOTA) | ||
1447 | type = QUOTA_GROUP; | ||
1448 | else | ||
1449 | return -EINVAL; | ||
1450 | |||
1451 | error = qd_get(sdp, type, id, &qd); | ||
1452 | if (error) | ||
1453 | return error; | ||
1454 | error = do_glock(qd, FORCE, &q_gh); | ||
1455 | if (error) | ||
1456 | goto out; | ||
1457 | |||
1458 | qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; | ||
1459 | fdq->d_version = FS_DQUOT_VERSION; | ||
1460 | fdq->d_flags = (type == QUOTA_USER) ? XFS_USER_QUOTA : XFS_GROUP_QUOTA; | ||
1461 | fdq->d_id = id; | ||
1462 | fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit); | ||
1463 | fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn); | ||
1464 | fdq->d_bcount = be64_to_cpu(qlvb->qb_value); | ||
1465 | |||
1466 | gfs2_glock_dq_uninit(&q_gh); | ||
1467 | out: | ||
1468 | qd_put(qd); | ||
1469 | return error; | ||
1470 | } | ||
1471 | |||
1472 | /* GFS2 only supports a subset of the XFS fields */ | ||
1473 | #define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD) | ||
1474 | |||
1475 | static int gfs2_xquota_set(struct super_block *sb, int type, qid_t id, | ||
1476 | struct fs_disk_quota *fdq) | ||
1477 | { | ||
1478 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
1479 | struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); | ||
1480 | struct gfs2_quota_data *qd; | ||
1481 | struct gfs2_holder q_gh, i_gh; | ||
1482 | unsigned int data_blocks, ind_blocks; | ||
1483 | unsigned int blocks = 0; | ||
1484 | int alloc_required; | ||
1485 | struct gfs2_alloc *al; | ||
1486 | loff_t offset; | ||
1487 | int error; | ||
1488 | |||
1489 | if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) | ||
1490 | return -ESRCH; /* Crazy XFS error code */ | ||
1491 | |||
1492 | switch(type) { | ||
1493 | case USRQUOTA: | ||
1494 | type = QUOTA_USER; | ||
1495 | if (fdq->d_flags != XFS_USER_QUOTA) | ||
1496 | return -EINVAL; | ||
1497 | break; | ||
1498 | case GRPQUOTA: | ||
1499 | type = QUOTA_GROUP; | ||
1500 | if (fdq->d_flags != XFS_GROUP_QUOTA) | ||
1501 | return -EINVAL; | ||
1502 | break; | ||
1503 | default: | ||
1504 | return -EINVAL; | ||
1505 | } | ||
1506 | |||
1507 | if (fdq->d_fieldmask & ~GFS2_FIELDMASK) | ||
1508 | return -EINVAL; | ||
1509 | if (fdq->d_id != id) | ||
1510 | return -EINVAL; | ||
1511 | |||
1512 | error = qd_get(sdp, type, id, &qd); | ||
1513 | if (error) | ||
1514 | return error; | ||
1515 | |||
1516 | mutex_lock(&ip->i_inode.i_mutex); | ||
1517 | error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_EXCLUSIVE, 0, &q_gh); | ||
1518 | if (error) | ||
1519 | goto out_put; | ||
1520 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); | ||
1521 | if (error) | ||
1522 | goto out_q; | ||
1523 | |||
1524 | /* Check for existing entry, if none then alloc new blocks */ | ||
1525 | error = update_qd(sdp, qd); | ||
1526 | if (error) | ||
1527 | goto out_i; | ||
1528 | |||
1529 | /* If nothing has changed, this is a no-op */ | ||
1530 | if ((fdq->d_fieldmask & FS_DQ_BSOFT) && | ||
1531 | (fdq->d_blk_softlimit == be64_to_cpu(qd->qd_qb.qb_warn))) | ||
1532 | fdq->d_fieldmask ^= FS_DQ_BSOFT; | ||
1533 | if ((fdq->d_fieldmask & FS_DQ_BHARD) && | ||
1534 | (fdq->d_blk_hardlimit == be64_to_cpu(qd->qd_qb.qb_limit))) | ||
1535 | fdq->d_fieldmask ^= FS_DQ_BHARD; | ||
1536 | if (fdq->d_fieldmask == 0) | ||
1537 | goto out_i; | ||
1538 | |||
1539 | offset = qd2offset(qd); | ||
1540 | error = gfs2_write_alloc_required(ip, offset, sizeof(struct gfs2_quota), | ||
1541 | &alloc_required); | ||
1542 | if (error) | ||
1543 | goto out_i; | ||
1544 | if (alloc_required) { | ||
1545 | al = gfs2_alloc_get(ip); | ||
1546 | if (al == NULL) | ||
1547 | goto out_i; | ||
1548 | gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota), | ||
1549 | &data_blocks, &ind_blocks); | ||
1550 | blocks = al->al_requested = 1 + data_blocks + ind_blocks; | ||
1551 | error = gfs2_inplace_reserve(ip); | ||
1552 | if (error) | ||
1553 | goto out_alloc; | ||
1554 | } | ||
1555 | |||
1556 | error = gfs2_trans_begin(sdp, blocks + RES_DINODE + 1, 0); | ||
1557 | if (error) | ||
1558 | goto out_release; | ||
1559 | |||
1560 | /* Apply changes */ | ||
1561 | error = gfs2_adjust_quota(ip, offset, 0, qd, fdq); | ||
1562 | |||
1563 | gfs2_trans_end(sdp); | ||
1564 | out_release: | ||
1565 | if (alloc_required) { | ||
1566 | gfs2_inplace_release(ip); | ||
1567 | out_alloc: | ||
1568 | gfs2_alloc_put(ip); | ||
1569 | } | ||
1570 | out_i: | ||
1571 | gfs2_glock_dq_uninit(&i_gh); | ||
1572 | out_q: | ||
1573 | gfs2_glock_dq_uninit(&q_gh); | ||
1574 | out_put: | ||
1575 | mutex_unlock(&ip->i_inode.i_mutex); | ||
1576 | qd_put(qd); | ||
1577 | return error; | ||
1578 | } | ||
1579 | |||
1580 | const struct quotactl_ops gfs2_quotactl_ops = { | ||
1581 | .quota_sync = gfs2_quota_sync, | ||
1582 | .get_xstate = gfs2_quota_get_xstate, | ||
1583 | .get_xquota = gfs2_xquota_get, | ||
1584 | .set_xquota = gfs2_xquota_set, | ||
1585 | }; | ||
1586 | |||
diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index 0fa5fa63d0e8..e271fa07ad02 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h | |||
@@ -25,13 +25,15 @@ extern int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid); | |||
25 | extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change, | 25 | extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change, |
26 | u32 uid, u32 gid); | 26 | u32 uid, u32 gid); |
27 | 27 | ||
28 | extern int gfs2_quota_sync(struct gfs2_sbd *sdp); | 28 | extern int gfs2_quota_sync(struct super_block *sb, int type); |
29 | extern int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id); | 29 | extern int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id); |
30 | 30 | ||
31 | extern int gfs2_quota_init(struct gfs2_sbd *sdp); | 31 | extern int gfs2_quota_init(struct gfs2_sbd *sdp); |
32 | extern void gfs2_quota_cleanup(struct gfs2_sbd *sdp); | 32 | extern void gfs2_quota_cleanup(struct gfs2_sbd *sdp); |
33 | extern int gfs2_quotad(void *data); | 33 | extern int gfs2_quotad(void *data); |
34 | 34 | ||
35 | extern void gfs2_wake_up_statfs(struct gfs2_sbd *sdp); | ||
36 | |||
35 | static inline int gfs2_quota_lock_check(struct gfs2_inode *ip) | 37 | static inline int gfs2_quota_lock_check(struct gfs2_inode *ip) |
36 | { | 38 | { |
37 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 39 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
@@ -50,5 +52,6 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip) | |||
50 | } | 52 | } |
51 | 53 | ||
52 | extern int gfs2_shrink_qd_memory(int nr, gfp_t gfp_mask); | 54 | extern int gfs2_shrink_qd_memory(int nr, gfp_t gfp_mask); |
55 | extern const struct quotactl_ops gfs2_quotactl_ops; | ||
53 | 56 | ||
54 | #endif /* __QUOTA_DOT_H__ */ | 57 | #endif /* __QUOTA_DOT_H__ */ |
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 59d2695509d3..4b9bece3d437 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * of the GNU General Public License version 2. | 7 | * of the GNU General Public License version 2. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/module.h> | ||
10 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
11 | #include <linux/spinlock.h> | 12 | #include <linux/spinlock.h> |
12 | #include <linux/completion.h> | 13 | #include <linux/completion.h> |
@@ -409,7 +410,9 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *hea | |||
409 | memset(lh, 0, sizeof(struct gfs2_log_header)); | 410 | memset(lh, 0, sizeof(struct gfs2_log_header)); |
410 | lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); | 411 | lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); |
411 | lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); | 412 | lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); |
413 | lh->lh_header.__pad0 = cpu_to_be64(0); | ||
412 | lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); | 414 | lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); |
415 | lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid); | ||
413 | lh->lh_sequence = cpu_to_be64(head->lh_sequence + 1); | 416 | lh->lh_sequence = cpu_to_be64(head->lh_sequence + 1); |
414 | lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT); | 417 | lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT); |
415 | lh->lh_blkno = cpu_to_be32(lblock); | 418 | lh->lh_blkno = cpu_to_be32(lblock); |
@@ -593,6 +596,7 @@ fail: | |||
593 | } | 596 | } |
594 | 597 | ||
595 | struct slow_work_ops gfs2_recover_ops = { | 598 | struct slow_work_ops gfs2_recover_ops = { |
599 | .owner = THIS_MODULE, | ||
596 | .get_ref = gfs2_recover_get_ref, | 600 | .get_ref = gfs2_recover_get_ref, |
597 | .put_ref = gfs2_recover_put_ref, | 601 | .put_ref = gfs2_recover_put_ref, |
598 | .execute = gfs2_recover_work, | 602 | .execute = gfs2_recover_work, |
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 8f1cfb02a6cb..0608f490c295 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -1710,11 +1710,16 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type) | |||
1710 | { | 1710 | { |
1711 | struct gfs2_rgrpd *rgd; | 1711 | struct gfs2_rgrpd *rgd; |
1712 | struct gfs2_holder ri_gh, rgd_gh; | 1712 | struct gfs2_holder ri_gh, rgd_gh; |
1713 | struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex); | ||
1714 | int ri_locked = 0; | ||
1713 | int error; | 1715 | int error; |
1714 | 1716 | ||
1715 | error = gfs2_rindex_hold(sdp, &ri_gh); | 1717 | if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { |
1716 | if (error) | 1718 | error = gfs2_rindex_hold(sdp, &ri_gh); |
1717 | goto fail; | 1719 | if (error) |
1720 | goto fail; | ||
1721 | ri_locked = 1; | ||
1722 | } | ||
1718 | 1723 | ||
1719 | error = -EINVAL; | 1724 | error = -EINVAL; |
1720 | rgd = gfs2_blk2rgrpd(sdp, no_addr); | 1725 | rgd = gfs2_blk2rgrpd(sdp, no_addr); |
@@ -1730,7 +1735,8 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type) | |||
1730 | 1735 | ||
1731 | gfs2_glock_dq_uninit(&rgd_gh); | 1736 | gfs2_glock_dq_uninit(&rgd_gh); |
1732 | fail_rindex: | 1737 | fail_rindex: |
1733 | gfs2_glock_dq_uninit(&ri_gh); | 1738 | if (ri_locked) |
1739 | gfs2_glock_dq_uninit(&ri_gh); | ||
1734 | fail: | 1740 | fail: |
1735 | return error; | 1741 | return error; |
1736 | } | 1742 | } |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 0ec3ec672de1..c282ad41f3d1 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
@@ -70,6 +70,11 @@ enum { | |||
70 | Opt_commit, | 70 | Opt_commit, |
71 | Opt_err_withdraw, | 71 | Opt_err_withdraw, |
72 | Opt_err_panic, | 72 | Opt_err_panic, |
73 | Opt_statfs_quantum, | ||
74 | Opt_statfs_percent, | ||
75 | Opt_quota_quantum, | ||
76 | Opt_barrier, | ||
77 | Opt_nobarrier, | ||
73 | Opt_error, | 78 | Opt_error, |
74 | }; | 79 | }; |
75 | 80 | ||
@@ -101,18 +106,23 @@ static const match_table_t tokens = { | |||
101 | {Opt_commit, "commit=%d"}, | 106 | {Opt_commit, "commit=%d"}, |
102 | {Opt_err_withdraw, "errors=withdraw"}, | 107 | {Opt_err_withdraw, "errors=withdraw"}, |
103 | {Opt_err_panic, "errors=panic"}, | 108 | {Opt_err_panic, "errors=panic"}, |
109 | {Opt_statfs_quantum, "statfs_quantum=%d"}, | ||
110 | {Opt_statfs_percent, "statfs_percent=%d"}, | ||
111 | {Opt_quota_quantum, "quota_quantum=%d"}, | ||
112 | {Opt_barrier, "barrier"}, | ||
113 | {Opt_nobarrier, "nobarrier"}, | ||
104 | {Opt_error, NULL} | 114 | {Opt_error, NULL} |
105 | }; | 115 | }; |
106 | 116 | ||
107 | /** | 117 | /** |
108 | * gfs2_mount_args - Parse mount options | 118 | * gfs2_mount_args - Parse mount options |
109 | * @sdp: | 119 | * @args: The structure into which the parsed options will be written |
110 | * @data: | 120 | * @options: The options to parse |
111 | * | 121 | * |
112 | * Return: errno | 122 | * Return: errno |
113 | */ | 123 | */ |
114 | 124 | ||
115 | int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) | 125 | int gfs2_mount_args(struct gfs2_args *args, char *options) |
116 | { | 126 | { |
117 | char *o; | 127 | char *o; |
118 | int token; | 128 | int token; |
@@ -157,7 +167,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) | |||
157 | break; | 167 | break; |
158 | case Opt_debug: | 168 | case Opt_debug: |
159 | if (args->ar_errors == GFS2_ERRORS_PANIC) { | 169 | if (args->ar_errors == GFS2_ERRORS_PANIC) { |
160 | fs_info(sdp, "-o debug and -o errors=panic " | 170 | printk(KERN_WARNING "GFS2: -o debug and -o errors=panic " |
161 | "are mutually exclusive.\n"); | 171 | "are mutually exclusive.\n"); |
162 | return -EINVAL; | 172 | return -EINVAL; |
163 | } | 173 | } |
@@ -210,7 +220,29 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) | |||
210 | case Opt_commit: | 220 | case Opt_commit: |
211 | rv = match_int(&tmp[0], &args->ar_commit); | 221 | rv = match_int(&tmp[0], &args->ar_commit); |
212 | if (rv || args->ar_commit <= 0) { | 222 | if (rv || args->ar_commit <= 0) { |
213 | fs_info(sdp, "commit mount option requires a positive numeric argument\n"); | 223 | printk(KERN_WARNING "GFS2: commit mount option requires a positive numeric argument\n"); |
224 | return rv ? rv : -EINVAL; | ||
225 | } | ||
226 | break; | ||
227 | case Opt_statfs_quantum: | ||
228 | rv = match_int(&tmp[0], &args->ar_statfs_quantum); | ||
229 | if (rv || args->ar_statfs_quantum < 0) { | ||
230 | printk(KERN_WARNING "GFS2: statfs_quantum mount option requires a non-negative numeric argument\n"); | ||
231 | return rv ? rv : -EINVAL; | ||
232 | } | ||
233 | break; | ||
234 | case Opt_quota_quantum: | ||
235 | rv = match_int(&tmp[0], &args->ar_quota_quantum); | ||
236 | if (rv || args->ar_quota_quantum <= 0) { | ||
237 | printk(KERN_WARNING "GFS2: quota_quantum mount option requires a positive numeric argument\n"); | ||
238 | return rv ? rv : -EINVAL; | ||
239 | } | ||
240 | break; | ||
241 | case Opt_statfs_percent: | ||
242 | rv = match_int(&tmp[0], &args->ar_statfs_percent); | ||
243 | if (rv || args->ar_statfs_percent < 0 || | ||
244 | args->ar_statfs_percent > 100) { | ||
245 | printk(KERN_WARNING "statfs_percent mount option requires a numeric argument between 0 and 100\n"); | ||
214 | return rv ? rv : -EINVAL; | 246 | return rv ? rv : -EINVAL; |
215 | } | 247 | } |
216 | break; | 248 | break; |
@@ -219,15 +251,21 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) | |||
219 | break; | 251 | break; |
220 | case Opt_err_panic: | 252 | case Opt_err_panic: |
221 | if (args->ar_debug) { | 253 | if (args->ar_debug) { |
222 | fs_info(sdp, "-o debug and -o errors=panic " | 254 | printk(KERN_WARNING "GFS2: -o debug and -o errors=panic " |
223 | "are mutually exclusive.\n"); | 255 | "are mutually exclusive.\n"); |
224 | return -EINVAL; | 256 | return -EINVAL; |
225 | } | 257 | } |
226 | args->ar_errors = GFS2_ERRORS_PANIC; | 258 | args->ar_errors = GFS2_ERRORS_PANIC; |
227 | break; | 259 | break; |
260 | case Opt_barrier: | ||
261 | args->ar_nobarrier = 0; | ||
262 | break; | ||
263 | case Opt_nobarrier: | ||
264 | args->ar_nobarrier = 1; | ||
265 | break; | ||
228 | case Opt_error: | 266 | case Opt_error: |
229 | default: | 267 | default: |
230 | fs_info(sdp, "invalid mount option: %s\n", o); | 268 | printk(KERN_WARNING "GFS2: invalid mount option: %s\n", o); |
231 | return -EINVAL; | 269 | return -EINVAL; |
232 | } | 270 | } |
233 | } | 271 | } |
@@ -442,7 +480,10 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, | |||
442 | { | 480 | { |
443 | struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); | 481 | struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); |
444 | struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; | 482 | struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; |
483 | struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; | ||
445 | struct buffer_head *l_bh; | 484 | struct buffer_head *l_bh; |
485 | s64 x, y; | ||
486 | int need_sync = 0; | ||
446 | int error; | 487 | int error; |
447 | 488 | ||
448 | error = gfs2_meta_inode_buffer(l_ip, &l_bh); | 489 | error = gfs2_meta_inode_buffer(l_ip, &l_bh); |
@@ -456,9 +497,17 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, | |||
456 | l_sc->sc_free += free; | 497 | l_sc->sc_free += free; |
457 | l_sc->sc_dinodes += dinodes; | 498 | l_sc->sc_dinodes += dinodes; |
458 | gfs2_statfs_change_out(l_sc, l_bh->b_data + sizeof(struct gfs2_dinode)); | 499 | gfs2_statfs_change_out(l_sc, l_bh->b_data + sizeof(struct gfs2_dinode)); |
500 | if (sdp->sd_args.ar_statfs_percent) { | ||
501 | x = 100 * l_sc->sc_free; | ||
502 | y = m_sc->sc_free * sdp->sd_args.ar_statfs_percent; | ||
503 | if (x >= y || x <= -y) | ||
504 | need_sync = 1; | ||
505 | } | ||
459 | spin_unlock(&sdp->sd_statfs_spin); | 506 | spin_unlock(&sdp->sd_statfs_spin); |
460 | 507 | ||
461 | brelse(l_bh); | 508 | brelse(l_bh); |
509 | if (need_sync) | ||
510 | gfs2_wake_up_statfs(sdp); | ||
462 | } | 511 | } |
463 | 512 | ||
464 | void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, | 513 | void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, |
@@ -484,8 +533,9 @@ void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, | |||
484 | gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); | 533 | gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); |
485 | } | 534 | } |
486 | 535 | ||
487 | int gfs2_statfs_sync(struct gfs2_sbd *sdp) | 536 | int gfs2_statfs_sync(struct super_block *sb, int type) |
488 | { | 537 | { |
538 | struct gfs2_sbd *sdp = sb->s_fs_info; | ||
489 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | 539 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); |
490 | struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); | 540 | struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); |
491 | struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; | 541 | struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; |
@@ -521,6 +571,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp) | |||
521 | goto out_bh2; | 571 | goto out_bh2; |
522 | 572 | ||
523 | update_statfs(sdp, m_bh, l_bh); | 573 | update_statfs(sdp, m_bh, l_bh); |
574 | sdp->sd_statfs_force_sync = 0; | ||
524 | 575 | ||
525 | gfs2_trans_end(sdp); | 576 | gfs2_trans_end(sdp); |
526 | 577 | ||
@@ -712,8 +763,8 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) | |||
712 | int error; | 763 | int error; |
713 | 764 | ||
714 | flush_workqueue(gfs2_delete_workqueue); | 765 | flush_workqueue(gfs2_delete_workqueue); |
715 | gfs2_quota_sync(sdp); | 766 | gfs2_quota_sync(sdp->sd_vfs, 0); |
716 | gfs2_statfs_sync(sdp); | 767 | gfs2_statfs_sync(sdp->sd_vfs, 0); |
717 | 768 | ||
718 | error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE, | 769 | error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE, |
719 | &t_gh); | 770 | &t_gh); |
@@ -1061,8 +1112,13 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) | |||
1061 | 1112 | ||
1062 | spin_lock(>->gt_spin); | 1113 | spin_lock(>->gt_spin); |
1063 | args.ar_commit = gt->gt_log_flush_secs; | 1114 | args.ar_commit = gt->gt_log_flush_secs; |
1115 | args.ar_quota_quantum = gt->gt_quota_quantum; | ||
1116 | if (gt->gt_statfs_slow) | ||
1117 | args.ar_statfs_quantum = 0; | ||
1118 | else | ||
1119 | args.ar_statfs_quantum = gt->gt_statfs_quantum; | ||
1064 | spin_unlock(>->gt_spin); | 1120 | spin_unlock(>->gt_spin); |
1065 | error = gfs2_mount_args(sdp, &args, data); | 1121 | error = gfs2_mount_args(&args, data); |
1066 | if (error) | 1122 | if (error) |
1067 | return error; | 1123 | return error; |
1068 | 1124 | ||
@@ -1097,8 +1153,21 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) | |||
1097 | sb->s_flags |= MS_POSIXACL; | 1153 | sb->s_flags |= MS_POSIXACL; |
1098 | else | 1154 | else |
1099 | sb->s_flags &= ~MS_POSIXACL; | 1155 | sb->s_flags &= ~MS_POSIXACL; |
1156 | if (sdp->sd_args.ar_nobarrier) | ||
1157 | set_bit(SDF_NOBARRIERS, &sdp->sd_flags); | ||
1158 | else | ||
1159 | clear_bit(SDF_NOBARRIERS, &sdp->sd_flags); | ||
1100 | spin_lock(>->gt_spin); | 1160 | spin_lock(>->gt_spin); |
1101 | gt->gt_log_flush_secs = args.ar_commit; | 1161 | gt->gt_log_flush_secs = args.ar_commit; |
1162 | gt->gt_quota_quantum = args.ar_quota_quantum; | ||
1163 | if (args.ar_statfs_quantum) { | ||
1164 | gt->gt_statfs_slow = 0; | ||
1165 | gt->gt_statfs_quantum = args.ar_statfs_quantum; | ||
1166 | } | ||
1167 | else { | ||
1168 | gt->gt_statfs_slow = 1; | ||
1169 | gt->gt_statfs_quantum = 30; | ||
1170 | } | ||
1102 | spin_unlock(>->gt_spin); | 1171 | spin_unlock(>->gt_spin); |
1103 | 1172 | ||
1104 | gfs2_online_uevent(sdp); | 1173 | gfs2_online_uevent(sdp); |
@@ -1179,7 +1248,7 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
1179 | { | 1248 | { |
1180 | struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info; | 1249 | struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info; |
1181 | struct gfs2_args *args = &sdp->sd_args; | 1250 | struct gfs2_args *args = &sdp->sd_args; |
1182 | int lfsecs; | 1251 | int val; |
1183 | 1252 | ||
1184 | if (is_ancestor(mnt->mnt_root, sdp->sd_master_dir)) | 1253 | if (is_ancestor(mnt->mnt_root, sdp->sd_master_dir)) |
1185 | seq_printf(s, ",meta"); | 1254 | seq_printf(s, ",meta"); |
@@ -1240,9 +1309,17 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
1240 | } | 1309 | } |
1241 | if (args->ar_discard) | 1310 | if (args->ar_discard) |
1242 | seq_printf(s, ",discard"); | 1311 | seq_printf(s, ",discard"); |
1243 | lfsecs = sdp->sd_tune.gt_log_flush_secs; | 1312 | val = sdp->sd_tune.gt_log_flush_secs; |
1244 | if (lfsecs != 60) | 1313 | if (val != 60) |
1245 | seq_printf(s, ",commit=%d", lfsecs); | 1314 | seq_printf(s, ",commit=%d", val); |
1315 | val = sdp->sd_tune.gt_statfs_quantum; | ||
1316 | if (val != 30) | ||
1317 | seq_printf(s, ",statfs_quantum=%d", val); | ||
1318 | val = sdp->sd_tune.gt_quota_quantum; | ||
1319 | if (val != 60) | ||
1320 | seq_printf(s, ",quota_quantum=%d", val); | ||
1321 | if (args->ar_statfs_percent) | ||
1322 | seq_printf(s, ",statfs_percent=%d", args->ar_statfs_percent); | ||
1246 | if (args->ar_errors != GFS2_ERRORS_DEFAULT) { | 1323 | if (args->ar_errors != GFS2_ERRORS_DEFAULT) { |
1247 | const char *state; | 1324 | const char *state; |
1248 | 1325 | ||
@@ -1259,6 +1336,9 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
1259 | } | 1336 | } |
1260 | seq_printf(s, ",errors=%s", state); | 1337 | seq_printf(s, ",errors=%s", state); |
1261 | } | 1338 | } |
1339 | if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) | ||
1340 | seq_printf(s, ",nobarrier"); | ||
1341 | |||
1262 | return 0; | 1342 | return 0; |
1263 | } | 1343 | } |
1264 | 1344 | ||
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 235db3682885..3df60f2d84e3 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h | |||
@@ -27,7 +27,7 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) | |||
27 | 27 | ||
28 | extern void gfs2_jindex_free(struct gfs2_sbd *sdp); | 28 | extern void gfs2_jindex_free(struct gfs2_sbd *sdp); |
29 | 29 | ||
30 | extern int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *data); | 30 | extern int gfs2_mount_args(struct gfs2_args *args, char *data); |
31 | 31 | ||
32 | extern struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); | 32 | extern struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); |
33 | extern int gfs2_jdesc_check(struct gfs2_jdesc *jd); | 33 | extern int gfs2_jdesc_check(struct gfs2_jdesc *jd); |
@@ -44,7 +44,7 @@ extern void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, | |||
44 | const void *buf); | 44 | const void *buf); |
45 | extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, | 45 | extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, |
46 | struct buffer_head *l_bh); | 46 | struct buffer_head *l_bh); |
47 | extern int gfs2_statfs_sync(struct gfs2_sbd *sdp); | 47 | extern int gfs2_statfs_sync(struct super_block *sb, int type); |
48 | 48 | ||
49 | extern int gfs2_freeze_fs(struct gfs2_sbd *sdp); | 49 | extern int gfs2_freeze_fs(struct gfs2_sbd *sdp); |
50 | extern void gfs2_unfreeze_fs(struct gfs2_sbd *sdp); | 50 | extern void gfs2_unfreeze_fs(struct gfs2_sbd *sdp); |
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 446329728d52..c5dad1eb7b91 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c | |||
@@ -158,7 +158,7 @@ static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf, | |||
158 | if (simple_strtol(buf, NULL, 0) != 1) | 158 | if (simple_strtol(buf, NULL, 0) != 1) |
159 | return -EINVAL; | 159 | return -EINVAL; |
160 | 160 | ||
161 | gfs2_statfs_sync(sdp); | 161 | gfs2_statfs_sync(sdp->sd_vfs, 0); |
162 | return len; | 162 | return len; |
163 | } | 163 | } |
164 | 164 | ||
@@ -171,13 +171,14 @@ static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf, | |||
171 | if (simple_strtol(buf, NULL, 0) != 1) | 171 | if (simple_strtol(buf, NULL, 0) != 1) |
172 | return -EINVAL; | 172 | return -EINVAL; |
173 | 173 | ||
174 | gfs2_quota_sync(sdp); | 174 | gfs2_quota_sync(sdp->sd_vfs, 0); |
175 | return len; | 175 | return len; |
176 | } | 176 | } |
177 | 177 | ||
178 | static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf, | 178 | static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf, |
179 | size_t len) | 179 | size_t len) |
180 | { | 180 | { |
181 | int error; | ||
181 | u32 id; | 182 | u32 id; |
182 | 183 | ||
183 | if (!capable(CAP_SYS_ADMIN)) | 184 | if (!capable(CAP_SYS_ADMIN)) |
@@ -185,13 +186,14 @@ static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf, | |||
185 | 186 | ||
186 | id = simple_strtoul(buf, NULL, 0); | 187 | id = simple_strtoul(buf, NULL, 0); |
187 | 188 | ||
188 | gfs2_quota_refresh(sdp, 1, id); | 189 | error = gfs2_quota_refresh(sdp, 1, id); |
189 | return len; | 190 | return error ? error : len; |
190 | } | 191 | } |
191 | 192 | ||
192 | static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf, | 193 | static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf, |
193 | size_t len) | 194 | size_t len) |
194 | { | 195 | { |
196 | int error; | ||
195 | u32 id; | 197 | u32 id; |
196 | 198 | ||
197 | if (!capable(CAP_SYS_ADMIN)) | 199 | if (!capable(CAP_SYS_ADMIN)) |
@@ -199,8 +201,8 @@ static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf, | |||
199 | 201 | ||
200 | id = simple_strtoul(buf, NULL, 0); | 202 | id = simple_strtoul(buf, NULL, 0); |
201 | 203 | ||
202 | gfs2_quota_refresh(sdp, 0, id); | 204 | error = gfs2_quota_refresh(sdp, 0, id); |
203 | return len; | 205 | return error ? error : len; |
204 | } | 206 | } |
205 | 207 | ||
206 | static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len) | 208 | static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len) |
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index 8a0f8ef6ee27..912f5cbc4740 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c | |||
@@ -186,8 +186,8 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
186 | return 0; | 186 | return 0; |
187 | } | 187 | } |
188 | 188 | ||
189 | int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, | 189 | static int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, |
190 | struct gfs2_ea_location *el) | 190 | struct gfs2_ea_location *el) |
191 | { | 191 | { |
192 | struct ea_find ef; | 192 | struct ea_find ef; |
193 | int error; | 193 | int error; |
@@ -516,8 +516,8 @@ out: | |||
516 | return error; | 516 | return error; |
517 | } | 517 | } |
518 | 518 | ||
519 | int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, | 519 | static int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, |
520 | char *data, size_t size) | 520 | char *data, size_t size) |
521 | { | 521 | { |
522 | int ret; | 522 | int ret; |
523 | size_t len = GFS2_EA_DATA_LEN(el->el_ea); | 523 | size_t len = GFS2_EA_DATA_LEN(el->el_ea); |
@@ -534,6 +534,36 @@ int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, | |||
534 | return len; | 534 | return len; |
535 | } | 535 | } |
536 | 536 | ||
537 | int gfs2_xattr_acl_get(struct gfs2_inode *ip, const char *name, char **ppdata) | ||
538 | { | ||
539 | struct gfs2_ea_location el; | ||
540 | int error; | ||
541 | int len; | ||
542 | char *data; | ||
543 | |||
544 | error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, &el); | ||
545 | if (error) | ||
546 | return error; | ||
547 | if (!el.el_ea) | ||
548 | goto out; | ||
549 | if (!GFS2_EA_DATA_LEN(el.el_ea)) | ||
550 | goto out; | ||
551 | |||
552 | len = GFS2_EA_DATA_LEN(el.el_ea); | ||
553 | data = kmalloc(len, GFP_NOFS); | ||
554 | error = -ENOMEM; | ||
555 | if (data == NULL) | ||
556 | goto out; | ||
557 | |||
558 | error = gfs2_ea_get_copy(ip, &el, data, len); | ||
559 | if (error == 0) | ||
560 | error = len; | ||
561 | *ppdata = data; | ||
562 | out: | ||
563 | brelse(el.el_bh); | ||
564 | return error; | ||
565 | } | ||
566 | |||
537 | /** | 567 | /** |
538 | * gfs2_xattr_get - Get a GFS2 extended attribute | 568 | * gfs2_xattr_get - Get a GFS2 extended attribute |
539 | * @inode: The inode | 569 | * @inode: The inode |
@@ -1259,22 +1289,26 @@ fail: | |||
1259 | return error; | 1289 | return error; |
1260 | } | 1290 | } |
1261 | 1291 | ||
1262 | int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, | 1292 | int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) |
1263 | struct iattr *attr, char *data) | ||
1264 | { | 1293 | { |
1294 | struct gfs2_ea_location el; | ||
1265 | struct buffer_head *dibh; | 1295 | struct buffer_head *dibh; |
1266 | int error; | 1296 | int error; |
1267 | 1297 | ||
1268 | if (GFS2_EA_IS_STUFFED(el->el_ea)) { | 1298 | error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, GFS2_POSIX_ACL_ACCESS, &el); |
1299 | if (error) | ||
1300 | return error; | ||
1301 | |||
1302 | if (GFS2_EA_IS_STUFFED(el.el_ea)) { | ||
1269 | error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0); | 1303 | error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0); |
1270 | if (error) | 1304 | if (error) |
1271 | return error; | 1305 | return error; |
1272 | 1306 | ||
1273 | gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1); | 1307 | gfs2_trans_add_bh(ip->i_gl, el.el_bh, 1); |
1274 | memcpy(GFS2_EA2DATA(el->el_ea), data, | 1308 | memcpy(GFS2_EA2DATA(el.el_ea), data, |
1275 | GFS2_EA_DATA_LEN(el->el_ea)); | 1309 | GFS2_EA_DATA_LEN(el.el_ea)); |
1276 | } else | 1310 | } else |
1277 | error = ea_acl_chmod_unstuffed(ip, el->el_ea, data); | 1311 | error = ea_acl_chmod_unstuffed(ip, el.el_ea, data); |
1278 | 1312 | ||
1279 | if (error) | 1313 | if (error) |
1280 | return error; | 1314 | return error; |
@@ -1507,18 +1541,6 @@ static int gfs2_xattr_user_set(struct inode *inode, const char *name, | |||
1507 | return gfs2_xattr_set(inode, GFS2_EATYPE_USR, name, value, size, flags); | 1541 | return gfs2_xattr_set(inode, GFS2_EATYPE_USR, name, value, size, flags); |
1508 | } | 1542 | } |
1509 | 1543 | ||
1510 | static int gfs2_xattr_system_get(struct inode *inode, const char *name, | ||
1511 | void *buffer, size_t size) | ||
1512 | { | ||
1513 | return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size); | ||
1514 | } | ||
1515 | |||
1516 | static int gfs2_xattr_system_set(struct inode *inode, const char *name, | ||
1517 | const void *value, size_t size, int flags) | ||
1518 | { | ||
1519 | return gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, flags); | ||
1520 | } | ||
1521 | |||
1522 | static int gfs2_xattr_security_get(struct inode *inode, const char *name, | 1544 | static int gfs2_xattr_security_get(struct inode *inode, const char *name, |
1523 | void *buffer, size_t size) | 1545 | void *buffer, size_t size) |
1524 | { | 1546 | { |
@@ -1543,12 +1565,6 @@ static struct xattr_handler gfs2_xattr_security_handler = { | |||
1543 | .set = gfs2_xattr_security_set, | 1565 | .set = gfs2_xattr_security_set, |
1544 | }; | 1566 | }; |
1545 | 1567 | ||
1546 | static struct xattr_handler gfs2_xattr_system_handler = { | ||
1547 | .prefix = XATTR_SYSTEM_PREFIX, | ||
1548 | .get = gfs2_xattr_system_get, | ||
1549 | .set = gfs2_xattr_system_set, | ||
1550 | }; | ||
1551 | |||
1552 | struct xattr_handler *gfs2_xattr_handlers[] = { | 1568 | struct xattr_handler *gfs2_xattr_handlers[] = { |
1553 | &gfs2_xattr_user_handler, | 1569 | &gfs2_xattr_user_handler, |
1554 | &gfs2_xattr_security_handler, | 1570 | &gfs2_xattr_security_handler, |
diff --git a/fs/gfs2/xattr.h b/fs/gfs2/xattr.h index cbdfd7743733..8d6ae5813c4d 100644 --- a/fs/gfs2/xattr.h +++ b/fs/gfs2/xattr.h | |||
@@ -62,11 +62,7 @@ extern int gfs2_ea_dealloc(struct gfs2_inode *ip); | |||
62 | 62 | ||
63 | /* Exported to acl.c */ | 63 | /* Exported to acl.c */ |
64 | 64 | ||
65 | extern int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, | 65 | extern int gfs2_xattr_acl_get(struct gfs2_inode *ip, const char *name, char **data); |
66 | struct gfs2_ea_location *el); | 66 | extern int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data); |
67 | extern int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, | ||
68 | char *data, size_t size); | ||
69 | extern int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, | ||
70 | struct iattr *attr, char *data); | ||
71 | 67 | ||
72 | #endif /* __EATTR_DOT_H__ */ | 68 | #endif /* __EATTR_DOT_H__ */ |
diff --git a/fs/inode.c b/fs/inode.c index 4d8e3be55976..06c1f02de611 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/hash.h> | 18 | #include <linux/hash.h> |
19 | #include <linux/swap.h> | 19 | #include <linux/swap.h> |
20 | #include <linux/security.h> | 20 | #include <linux/security.h> |
21 | #include <linux/ima.h> | ||
22 | #include <linux/pagemap.h> | 21 | #include <linux/pagemap.h> |
23 | #include <linux/cdev.h> | 22 | #include <linux/cdev.h> |
24 | #include <linux/bootmem.h> | 23 | #include <linux/bootmem.h> |
@@ -157,11 +156,6 @@ int inode_init_always(struct super_block *sb, struct inode *inode) | |||
157 | 156 | ||
158 | if (security_inode_alloc(inode)) | 157 | if (security_inode_alloc(inode)) |
159 | goto out; | 158 | goto out; |
160 | |||
161 | /* allocate and initialize an i_integrity */ | ||
162 | if (ima_inode_alloc(inode)) | ||
163 | goto out_free_security; | ||
164 | |||
165 | spin_lock_init(&inode->i_lock); | 159 | spin_lock_init(&inode->i_lock); |
166 | lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key); | 160 | lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key); |
167 | 161 | ||
@@ -201,9 +195,6 @@ int inode_init_always(struct super_block *sb, struct inode *inode) | |||
201 | #endif | 195 | #endif |
202 | 196 | ||
203 | return 0; | 197 | return 0; |
204 | |||
205 | out_free_security: | ||
206 | security_inode_free(inode); | ||
207 | out: | 198 | out: |
208 | return -ENOMEM; | 199 | return -ENOMEM; |
209 | } | 200 | } |
@@ -235,7 +226,6 @@ static struct inode *alloc_inode(struct super_block *sb) | |||
235 | void __destroy_inode(struct inode *inode) | 226 | void __destroy_inode(struct inode *inode) |
236 | { | 227 | { |
237 | BUG_ON(inode_has_buffers(inode)); | 228 | BUG_ON(inode_has_buffers(inode)); |
238 | ima_inode_free(inode); | ||
239 | security_inode_free(inode); | 229 | security_inode_free(inode); |
240 | fsnotify_inode_delete(inode); | 230 | fsnotify_inode_delete(inode); |
241 | #ifdef CONFIG_FS_POSIX_ACL | 231 | #ifdef CONFIG_FS_POSIX_ACL |
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index d4cfd6d2779e..8896c1d4febe 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -636,6 +636,10 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
636 | JBUFFER_TRACE(jh, "ph3: write metadata"); | 636 | JBUFFER_TRACE(jh, "ph3: write metadata"); |
637 | flags = jbd2_journal_write_metadata_buffer(commit_transaction, | 637 | flags = jbd2_journal_write_metadata_buffer(commit_transaction, |
638 | jh, &new_jh, blocknr); | 638 | jh, &new_jh, blocknr); |
639 | if (flags < 0) { | ||
640 | jbd2_journal_abort(journal, flags); | ||
641 | continue; | ||
642 | } | ||
639 | set_bit(BH_JWrite, &jh2bh(new_jh)->b_state); | 643 | set_bit(BH_JWrite, &jh2bh(new_jh)->b_state); |
640 | wbuf[bufs++] = jh2bh(new_jh); | 644 | wbuf[bufs++] = jh2bh(new_jh); |
641 | 645 | ||
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index fed85388ee86..b7ca3a92a4db 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -78,6 +78,7 @@ EXPORT_SYMBOL(jbd2_journal_errno); | |||
78 | EXPORT_SYMBOL(jbd2_journal_ack_err); | 78 | EXPORT_SYMBOL(jbd2_journal_ack_err); |
79 | EXPORT_SYMBOL(jbd2_journal_clear_err); | 79 | EXPORT_SYMBOL(jbd2_journal_clear_err); |
80 | EXPORT_SYMBOL(jbd2_log_wait_commit); | 80 | EXPORT_SYMBOL(jbd2_log_wait_commit); |
81 | EXPORT_SYMBOL(jbd2_log_start_commit); | ||
81 | EXPORT_SYMBOL(jbd2_journal_start_commit); | 82 | EXPORT_SYMBOL(jbd2_journal_start_commit); |
82 | EXPORT_SYMBOL(jbd2_journal_force_commit_nested); | 83 | EXPORT_SYMBOL(jbd2_journal_force_commit_nested); |
83 | EXPORT_SYMBOL(jbd2_journal_wipe); | 84 | EXPORT_SYMBOL(jbd2_journal_wipe); |
@@ -358,6 +359,10 @@ repeat: | |||
358 | 359 | ||
359 | jbd_unlock_bh_state(bh_in); | 360 | jbd_unlock_bh_state(bh_in); |
360 | tmp = jbd2_alloc(bh_in->b_size, GFP_NOFS); | 361 | tmp = jbd2_alloc(bh_in->b_size, GFP_NOFS); |
362 | if (!tmp) { | ||
363 | jbd2_journal_put_journal_head(new_jh); | ||
364 | return -ENOMEM; | ||
365 | } | ||
361 | jbd_lock_bh_state(bh_in); | 366 | jbd_lock_bh_state(bh_in); |
362 | if (jh_in->b_frozen_data) { | 367 | if (jh_in->b_frozen_data) { |
363 | jbd2_free(tmp, bh_in->b_size); | 368 | jbd2_free(tmp, bh_in->b_size); |
@@ -1248,6 +1253,13 @@ int jbd2_journal_load(journal_t *journal) | |||
1248 | if (jbd2_journal_recover(journal)) | 1253 | if (jbd2_journal_recover(journal)) |
1249 | goto recovery_error; | 1254 | goto recovery_error; |
1250 | 1255 | ||
1256 | if (journal->j_failed_commit) { | ||
1257 | printk(KERN_ERR "JBD2: journal transaction %u on %s " | ||
1258 | "is corrupt.\n", journal->j_failed_commit, | ||
1259 | journal->j_devname); | ||
1260 | return -EIO; | ||
1261 | } | ||
1262 | |||
1251 | /* OK, we've finished with the dynamic journal bits: | 1263 | /* OK, we've finished with the dynamic journal bits: |
1252 | * reinitialise the dynamic contents of the superblock in memory | 1264 | * reinitialise the dynamic contents of the superblock in memory |
1253 | * and reset them on disk. */ | 1265 | * and reset them on disk. */ |
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index f25e70c1b51c..f0294410868d 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c | |||
@@ -177,7 +177,7 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
177 | spin_unlock(&jffs2_compressor_list_lock); | 177 | spin_unlock(&jffs2_compressor_list_lock); |
178 | break; | 178 | break; |
179 | default: | 179 | default: |
180 | printk(KERN_ERR "JFFS2: unknow compression mode.\n"); | 180 | printk(KERN_ERR "JFFS2: unknown compression mode.\n"); |
181 | } | 181 | } |
182 | out: | 182 | out: |
183 | if (ret == JFFS2_COMPR_NONE) { | 183 | if (ret == JFFS2_COMPR_NONE) { |
diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c index cfe05c1966a5..3f39be1b0455 100644 --- a/fs/jffs2/read.c +++ b/fs/jffs2/read.c | |||
@@ -164,12 +164,15 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
164 | 164 | ||
165 | /* XXX FIXME: Where a single physical node actually shows up in two | 165 | /* XXX FIXME: Where a single physical node actually shows up in two |
166 | frags, we read it twice. Don't do that. */ | 166 | frags, we read it twice. Don't do that. */ |
167 | /* Now we're pointing at the first frag which overlaps our page */ | 167 | /* Now we're pointing at the first frag which overlaps our page |
168 | * (or perhaps is before it, if we've been asked to read off the | ||
169 | * end of the file). */ | ||
168 | while(offset < end) { | 170 | while(offset < end) { |
169 | D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end)); | 171 | D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end)); |
170 | if (unlikely(!frag || frag->ofs > offset)) { | 172 | if (unlikely(!frag || frag->ofs > offset || |
173 | frag->ofs + frag->size <= offset)) { | ||
171 | uint32_t holesize = end - offset; | 174 | uint32_t holesize = end - offset; |
172 | if (frag) { | 175 | if (frag && frag->ofs > offset) { |
173 | D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset)); | 176 | D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset)); |
174 | holesize = min(holesize, frag->ofs - offset); | 177 | holesize = min(holesize, frag->ofs - offset); |
175 | } | 178 | } |
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 1a80301004b8..378991cfe40f 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -931,7 +931,7 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re | |||
931 | * Helper function for jffs2_get_inode_nodes(). | 931 | * Helper function for jffs2_get_inode_nodes(). |
932 | * The function detects whether more data should be read and reads it if yes. | 932 | * The function detects whether more data should be read and reads it if yes. |
933 | * | 933 | * |
934 | * Returns: 0 on succes; | 934 | * Returns: 0 on success; |
935 | * negative error code on failure. | 935 | * negative error code on failure. |
936 | */ | 936 | */ |
937 | static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, | 937 | static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, |
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 082e844ab2db..4b107881acd5 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c | |||
@@ -31,7 +31,7 @@ | |||
31 | * is used to release xattr name/value pair and detach from c->xattrindex. | 31 | * is used to release xattr name/value pair and detach from c->xattrindex. |
32 | * reclaim_xattr_datum(c) | 32 | * reclaim_xattr_datum(c) |
33 | * is used to reclaim xattr name/value pairs on the xattr name/value pair cache when | 33 | * is used to reclaim xattr name/value pairs on the xattr name/value pair cache when |
34 | * memory usage by cache is over c->xdatum_mem_threshold. Currentry, this threshold | 34 | * memory usage by cache is over c->xdatum_mem_threshold. Currently, this threshold |
35 | * is hard coded as 32KiB. | 35 | * is hard coded as 32KiB. |
36 | * do_verify_xattr_datum(c, xd) | 36 | * do_verify_xattr_datum(c, xd) |
37 | * is used to load the xdatum informations without name/value pair from the medium. | 37 | * is used to load the xdatum informations without name/value pair from the medium. |
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 2bc7d8aa5740..d9b031cf69f5 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c | |||
@@ -755,7 +755,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) | |||
755 | * allocation group. | 755 | * allocation group. |
756 | */ | 756 | */ |
757 | if ((blkno & (bmp->db_agsize - 1)) == 0) | 757 | if ((blkno & (bmp->db_agsize - 1)) == 0) |
758 | /* check if the AG is currenly being written to. | 758 | /* check if the AG is currently being written to. |
759 | * if so, call dbNextAG() to find a non-busy | 759 | * if so, call dbNextAG() to find a non-busy |
760 | * AG with sufficient free space. | 760 | * AG with sufficient free space. |
761 | */ | 761 | */ |
@@ -3337,7 +3337,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) | |||
3337 | for (i = 0, n = 0; i < agno; n++) { | 3337 | for (i = 0, n = 0; i < agno; n++) { |
3338 | bmp->db_agfree[n] = 0; /* init collection point */ | 3338 | bmp->db_agfree[n] = 0; /* init collection point */ |
3339 | 3339 | ||
3340 | /* coalesce cotiguous k AGs; */ | 3340 | /* coalesce contiguous k AGs; */ |
3341 | for (j = 0; j < k && i < agno; j++, i++) { | 3341 | for (j = 0; j < k && i < agno; j++, i++) { |
3342 | /* merge AGi to AGn */ | 3342 | /* merge AGi to AGn */ |
3343 | bmp->db_agfree[n] += bmp->db_agfree[i]; | 3343 | bmp->db_agfree[n] += bmp->db_agfree[i]; |
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 1a54ae14a192..e50cfa3d9654 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -371,82 +371,74 @@ EXPORT_SYMBOL_GPL(lockd_down); | |||
371 | 371 | ||
372 | static ctl_table nlm_sysctls[] = { | 372 | static ctl_table nlm_sysctls[] = { |
373 | { | 373 | { |
374 | .ctl_name = CTL_UNNUMBERED, | ||
375 | .procname = "nlm_grace_period", | 374 | .procname = "nlm_grace_period", |
376 | .data = &nlm_grace_period, | 375 | .data = &nlm_grace_period, |
377 | .maxlen = sizeof(unsigned long), | 376 | .maxlen = sizeof(unsigned long), |
378 | .mode = 0644, | 377 | .mode = 0644, |
379 | .proc_handler = &proc_doulongvec_minmax, | 378 | .proc_handler = proc_doulongvec_minmax, |
380 | .extra1 = (unsigned long *) &nlm_grace_period_min, | 379 | .extra1 = (unsigned long *) &nlm_grace_period_min, |
381 | .extra2 = (unsigned long *) &nlm_grace_period_max, | 380 | .extra2 = (unsigned long *) &nlm_grace_period_max, |
382 | }, | 381 | }, |
383 | { | 382 | { |
384 | .ctl_name = CTL_UNNUMBERED, | ||
385 | .procname = "nlm_timeout", | 383 | .procname = "nlm_timeout", |
386 | .data = &nlm_timeout, | 384 | .data = &nlm_timeout, |
387 | .maxlen = sizeof(unsigned long), | 385 | .maxlen = sizeof(unsigned long), |
388 | .mode = 0644, | 386 | .mode = 0644, |
389 | .proc_handler = &proc_doulongvec_minmax, | 387 | .proc_handler = proc_doulongvec_minmax, |
390 | .extra1 = (unsigned long *) &nlm_timeout_min, | 388 | .extra1 = (unsigned long *) &nlm_timeout_min, |
391 | .extra2 = (unsigned long *) &nlm_timeout_max, | 389 | .extra2 = (unsigned long *) &nlm_timeout_max, |
392 | }, | 390 | }, |
393 | { | 391 | { |
394 | .ctl_name = CTL_UNNUMBERED, | ||
395 | .procname = "nlm_udpport", | 392 | .procname = "nlm_udpport", |
396 | .data = &nlm_udpport, | 393 | .data = &nlm_udpport, |
397 | .maxlen = sizeof(int), | 394 | .maxlen = sizeof(int), |
398 | .mode = 0644, | 395 | .mode = 0644, |
399 | .proc_handler = &proc_dointvec_minmax, | 396 | .proc_handler = proc_dointvec_minmax, |
400 | .extra1 = (int *) &nlm_port_min, | 397 | .extra1 = (int *) &nlm_port_min, |
401 | .extra2 = (int *) &nlm_port_max, | 398 | .extra2 = (int *) &nlm_port_max, |
402 | }, | 399 | }, |
403 | { | 400 | { |
404 | .ctl_name = CTL_UNNUMBERED, | ||
405 | .procname = "nlm_tcpport", | 401 | .procname = "nlm_tcpport", |
406 | .data = &nlm_tcpport, | 402 | .data = &nlm_tcpport, |
407 | .maxlen = sizeof(int), | 403 | .maxlen = sizeof(int), |
408 | .mode = 0644, | 404 | .mode = 0644, |
409 | .proc_handler = &proc_dointvec_minmax, | 405 | .proc_handler = proc_dointvec_minmax, |
410 | .extra1 = (int *) &nlm_port_min, | 406 | .extra1 = (int *) &nlm_port_min, |
411 | .extra2 = (int *) &nlm_port_max, | 407 | .extra2 = (int *) &nlm_port_max, |
412 | }, | 408 | }, |
413 | { | 409 | { |
414 | .ctl_name = CTL_UNNUMBERED, | ||
415 | .procname = "nsm_use_hostnames", | 410 | .procname = "nsm_use_hostnames", |
416 | .data = &nsm_use_hostnames, | 411 | .data = &nsm_use_hostnames, |
417 | .maxlen = sizeof(int), | 412 | .maxlen = sizeof(int), |
418 | .mode = 0644, | 413 | .mode = 0644, |
419 | .proc_handler = &proc_dointvec, | 414 | .proc_handler = proc_dointvec, |
420 | }, | 415 | }, |
421 | { | 416 | { |
422 | .ctl_name = CTL_UNNUMBERED, | ||
423 | .procname = "nsm_local_state", | 417 | .procname = "nsm_local_state", |
424 | .data = &nsm_local_state, | 418 | .data = &nsm_local_state, |
425 | .maxlen = sizeof(int), | 419 | .maxlen = sizeof(int), |
426 | .mode = 0644, | 420 | .mode = 0644, |
427 | .proc_handler = &proc_dointvec, | 421 | .proc_handler = proc_dointvec, |
428 | }, | 422 | }, |
429 | { .ctl_name = 0 } | 423 | { } |
430 | }; | 424 | }; |
431 | 425 | ||
432 | static ctl_table nlm_sysctl_dir[] = { | 426 | static ctl_table nlm_sysctl_dir[] = { |
433 | { | 427 | { |
434 | .ctl_name = CTL_UNNUMBERED, | ||
435 | .procname = "nfs", | 428 | .procname = "nfs", |
436 | .mode = 0555, | 429 | .mode = 0555, |
437 | .child = nlm_sysctls, | 430 | .child = nlm_sysctls, |
438 | }, | 431 | }, |
439 | { .ctl_name = 0 } | 432 | { } |
440 | }; | 433 | }; |
441 | 434 | ||
442 | static ctl_table nlm_sysctl_root[] = { | 435 | static ctl_table nlm_sysctl_root[] = { |
443 | { | 436 | { |
444 | .ctl_name = CTL_FS, | ||
445 | .procname = "fs", | 437 | .procname = "fs", |
446 | .mode = 0555, | 438 | .mode = 0555, |
447 | .child = nlm_sysctl_dir, | 439 | .child = nlm_sysctl_dir, |
448 | }, | 440 | }, |
449 | { .ctl_name = 0 } | 441 | { } |
450 | }; | 442 | }; |
451 | 443 | ||
452 | #endif /* CONFIG_SYSCTL */ | 444 | #endif /* CONFIG_SYSCTL */ |
diff --git a/fs/namespace.c b/fs/namespace.c index bdc3cb4fd222..7d70d63ceb29 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1921,6 +1921,16 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, | |||
1921 | if (data_page) | 1921 | if (data_page) |
1922 | ((char *)data_page)[PAGE_SIZE - 1] = 0; | 1922 | ((char *)data_page)[PAGE_SIZE - 1] = 0; |
1923 | 1923 | ||
1924 | /* ... and get the mountpoint */ | ||
1925 | retval = kern_path(dir_name, LOOKUP_FOLLOW, &path); | ||
1926 | if (retval) | ||
1927 | return retval; | ||
1928 | |||
1929 | retval = security_sb_mount(dev_name, &path, | ||
1930 | type_page, flags, data_page); | ||
1931 | if (retval) | ||
1932 | goto dput_out; | ||
1933 | |||
1924 | /* Default to relatime unless overriden */ | 1934 | /* Default to relatime unless overriden */ |
1925 | if (!(flags & MS_NOATIME)) | 1935 | if (!(flags & MS_NOATIME)) |
1926 | mnt_flags |= MNT_RELATIME; | 1936 | mnt_flags |= MNT_RELATIME; |
@@ -1945,16 +1955,6 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, | |||
1945 | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | | 1955 | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | |
1946 | MS_STRICTATIME); | 1956 | MS_STRICTATIME); |
1947 | 1957 | ||
1948 | /* ... and get the mountpoint */ | ||
1949 | retval = kern_path(dir_name, LOOKUP_FOLLOW, &path); | ||
1950 | if (retval) | ||
1951 | return retval; | ||
1952 | |||
1953 | retval = security_sb_mount(dev_name, &path, | ||
1954 | type_page, flags, data_page); | ||
1955 | if (retval) | ||
1956 | goto dput_out; | ||
1957 | |||
1958 | if (flags & MS_REMOUNT) | 1958 | if (flags & MS_REMOUNT) |
1959 | retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags, | 1959 | retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags, |
1960 | data_page); | 1960 | data_page); |
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 0d58caf4a6e1..ec8f45f12e05 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c | |||
@@ -835,7 +835,7 @@ static int ncp_ioctl_need_write(unsigned int cmd) | |||
835 | case NCP_IOC_SETROOT: | 835 | case NCP_IOC_SETROOT: |
836 | return 0; | 836 | return 0; |
837 | default: | 837 | default: |
838 | /* unkown IOCTL command, assume write */ | 838 | /* unknown IOCTL command, assume write */ |
839 | return 1; | 839 | return 1; |
840 | } | 840 | } |
841 | } | 841 | } |
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index 70fad69eb959..fa588006588d 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c | |||
@@ -359,17 +359,13 @@ int nfs_fscache_release_page(struct page *page, gfp_t gfp) | |||
359 | 359 | ||
360 | BUG_ON(!cookie); | 360 | BUG_ON(!cookie); |
361 | 361 | ||
362 | if (fscache_check_page_write(cookie, page)) { | ||
363 | if (!(gfp & __GFP_WAIT)) | ||
364 | return 0; | ||
365 | fscache_wait_on_page_write(cookie, page); | ||
366 | } | ||
367 | |||
368 | if (PageFsCache(page)) { | 362 | if (PageFsCache(page)) { |
369 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", | 363 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", |
370 | cookie, page, nfsi); | 364 | cookie, page, nfsi); |
371 | 365 | ||
372 | fscache_uncache_page(cookie, page); | 366 | if (!fscache_maybe_release_page(cookie, page, gfp)) |
367 | return 0; | ||
368 | |||
373 | nfs_add_fscache_stats(page->mapping->host, | 369 | nfs_add_fscache_stats(page->mapping->host, |
374 | NFSIOS_FSCACHE_PAGES_UNCACHED, 1); | 370 | NFSIOS_FSCACHE_PAGES_UNCACHED, 1); |
375 | } | 371 | } |
diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c index b62481dabae9..70e1fbbaaeab 100644 --- a/fs/nfs/sysctl.c +++ b/fs/nfs/sysctl.c | |||
@@ -22,63 +22,55 @@ static struct ctl_table_header *nfs_callback_sysctl_table; | |||
22 | static ctl_table nfs_cb_sysctls[] = { | 22 | static ctl_table nfs_cb_sysctls[] = { |
23 | #ifdef CONFIG_NFS_V4 | 23 | #ifdef CONFIG_NFS_V4 |
24 | { | 24 | { |
25 | .ctl_name = CTL_UNNUMBERED, | ||
26 | .procname = "nfs_callback_tcpport", | 25 | .procname = "nfs_callback_tcpport", |
27 | .data = &nfs_callback_set_tcpport, | 26 | .data = &nfs_callback_set_tcpport, |
28 | .maxlen = sizeof(int), | 27 | .maxlen = sizeof(int), |
29 | .mode = 0644, | 28 | .mode = 0644, |
30 | .proc_handler = &proc_dointvec_minmax, | 29 | .proc_handler = proc_dointvec_minmax, |
31 | .extra1 = (int *)&nfs_set_port_min, | 30 | .extra1 = (int *)&nfs_set_port_min, |
32 | .extra2 = (int *)&nfs_set_port_max, | 31 | .extra2 = (int *)&nfs_set_port_max, |
33 | }, | 32 | }, |
34 | { | 33 | { |
35 | .ctl_name = CTL_UNNUMBERED, | ||
36 | .procname = "idmap_cache_timeout", | 34 | .procname = "idmap_cache_timeout", |
37 | .data = &nfs_idmap_cache_timeout, | 35 | .data = &nfs_idmap_cache_timeout, |
38 | .maxlen = sizeof(int), | 36 | .maxlen = sizeof(int), |
39 | .mode = 0644, | 37 | .mode = 0644, |
40 | .proc_handler = &proc_dointvec_jiffies, | 38 | .proc_handler = proc_dointvec_jiffies, |
41 | .strategy = &sysctl_jiffies, | ||
42 | }, | 39 | }, |
43 | #endif | 40 | #endif |
44 | { | 41 | { |
45 | .ctl_name = CTL_UNNUMBERED, | ||
46 | .procname = "nfs_mountpoint_timeout", | 42 | .procname = "nfs_mountpoint_timeout", |
47 | .data = &nfs_mountpoint_expiry_timeout, | 43 | .data = &nfs_mountpoint_expiry_timeout, |
48 | .maxlen = sizeof(nfs_mountpoint_expiry_timeout), | 44 | .maxlen = sizeof(nfs_mountpoint_expiry_timeout), |
49 | .mode = 0644, | 45 | .mode = 0644, |
50 | .proc_handler = &proc_dointvec_jiffies, | 46 | .proc_handler = proc_dointvec_jiffies, |
51 | .strategy = &sysctl_jiffies, | ||
52 | }, | 47 | }, |
53 | { | 48 | { |
54 | .ctl_name = CTL_UNNUMBERED, | ||
55 | .procname = "nfs_congestion_kb", | 49 | .procname = "nfs_congestion_kb", |
56 | .data = &nfs_congestion_kb, | 50 | .data = &nfs_congestion_kb, |
57 | .maxlen = sizeof(nfs_congestion_kb), | 51 | .maxlen = sizeof(nfs_congestion_kb), |
58 | .mode = 0644, | 52 | .mode = 0644, |
59 | .proc_handler = &proc_dointvec, | 53 | .proc_handler = proc_dointvec, |
60 | }, | 54 | }, |
61 | { .ctl_name = 0 } | 55 | { } |
62 | }; | 56 | }; |
63 | 57 | ||
64 | static ctl_table nfs_cb_sysctl_dir[] = { | 58 | static ctl_table nfs_cb_sysctl_dir[] = { |
65 | { | 59 | { |
66 | .ctl_name = CTL_UNNUMBERED, | ||
67 | .procname = "nfs", | 60 | .procname = "nfs", |
68 | .mode = 0555, | 61 | .mode = 0555, |
69 | .child = nfs_cb_sysctls, | 62 | .child = nfs_cb_sysctls, |
70 | }, | 63 | }, |
71 | { .ctl_name = 0 } | 64 | { } |
72 | }; | 65 | }; |
73 | 66 | ||
74 | static ctl_table nfs_cb_sysctl_root[] = { | 67 | static ctl_table nfs_cb_sysctl_root[] = { |
75 | { | 68 | { |
76 | .ctl_name = CTL_FS, | ||
77 | .procname = "fs", | 69 | .procname = "fs", |
78 | .mode = 0555, | 70 | .mode = 0555, |
79 | .child = nfs_cb_sysctl_dir, | 71 | .child = nfs_cb_sysctl_dir, |
80 | }, | 72 | }, |
81 | { .ctl_name = 0 } | 73 | { } |
82 | }; | 74 | }; |
83 | 75 | ||
84 | int nfs_register_sysctl(void) | 76 | int nfs_register_sysctl(void) |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 53eb26c16b50..c84b5cc1a943 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -178,7 +178,7 @@ static int wb_priority(struct writeback_control *wbc) | |||
178 | { | 178 | { |
179 | if (wbc->for_reclaim) | 179 | if (wbc->for_reclaim) |
180 | return FLUSH_HIGHPRI | FLUSH_STABLE; | 180 | return FLUSH_HIGHPRI | FLUSH_STABLE; |
181 | if (wbc->for_kupdate) | 181 | if (wbc->for_kupdate || wbc->for_background) |
182 | return FLUSH_LOWPRI; | 182 | return FLUSH_LOWPRI; |
183 | return 0; | 183 | return 0; |
184 | } | 184 | } |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index dcd2040d330c..5ef5f365a5c8 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -69,36 +69,30 @@ static int zero; | |||
69 | 69 | ||
70 | ctl_table inotify_table[] = { | 70 | ctl_table inotify_table[] = { |
71 | { | 71 | { |
72 | .ctl_name = INOTIFY_MAX_USER_INSTANCES, | ||
73 | .procname = "max_user_instances", | 72 | .procname = "max_user_instances", |
74 | .data = &inotify_max_user_instances, | 73 | .data = &inotify_max_user_instances, |
75 | .maxlen = sizeof(int), | 74 | .maxlen = sizeof(int), |
76 | .mode = 0644, | 75 | .mode = 0644, |
77 | .proc_handler = &proc_dointvec_minmax, | 76 | .proc_handler = proc_dointvec_minmax, |
78 | .strategy = &sysctl_intvec, | ||
79 | .extra1 = &zero, | 77 | .extra1 = &zero, |
80 | }, | 78 | }, |
81 | { | 79 | { |
82 | .ctl_name = INOTIFY_MAX_USER_WATCHES, | ||
83 | .procname = "max_user_watches", | 80 | .procname = "max_user_watches", |
84 | .data = &inotify_max_user_watches, | 81 | .data = &inotify_max_user_watches, |
85 | .maxlen = sizeof(int), | 82 | .maxlen = sizeof(int), |
86 | .mode = 0644, | 83 | .mode = 0644, |
87 | .proc_handler = &proc_dointvec_minmax, | 84 | .proc_handler = proc_dointvec_minmax, |
88 | .strategy = &sysctl_intvec, | ||
89 | .extra1 = &zero, | 85 | .extra1 = &zero, |
90 | }, | 86 | }, |
91 | { | 87 | { |
92 | .ctl_name = INOTIFY_MAX_QUEUED_EVENTS, | ||
93 | .procname = "max_queued_events", | 88 | .procname = "max_queued_events", |
94 | .data = &inotify_max_queued_events, | 89 | .data = &inotify_max_queued_events, |
95 | .maxlen = sizeof(int), | 90 | .maxlen = sizeof(int), |
96 | .mode = 0644, | 91 | .mode = 0644, |
97 | .proc_handler = &proc_dointvec_minmax, | 92 | .proc_handler = proc_dointvec_minmax, |
98 | .strategy = &sysctl_intvec, | ||
99 | .extra1 = &zero | 93 | .extra1 = &zero |
100 | }, | 94 | }, |
101 | { .ctl_name = 0 } | 95 | { } |
102 | }; | 96 | }; |
103 | #endif /* CONFIG_SYSCTL */ | 97 | #endif /* CONFIG_SYSCTL */ |
104 | 98 | ||
@@ -747,10 +741,6 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname, | |||
747 | 741 | ||
748 | /* create/update an inode mark */ | 742 | /* create/update an inode mark */ |
749 | ret = inotify_update_watch(group, inode, mask); | 743 | ret = inotify_update_watch(group, inode, mask); |
750 | if (unlikely(ret)) | ||
751 | goto path_put_and_out; | ||
752 | |||
753 | path_put_and_out: | ||
754 | path_put(&path); | 744 | path_put(&path); |
755 | fput_and_out: | 745 | fput_and_out: |
756 | fput_light(filp, fput_needed); | 746 | fput_light(filp, fput_needed); |
diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c index 9669541d0119..08f7530e9341 100644 --- a/fs/ntfs/compress.c +++ b/fs/ntfs/compress.c | |||
@@ -927,7 +927,7 @@ lock_retry_remap: | |||
927 | return 0; | 927 | return 0; |
928 | 928 | ||
929 | ntfs_debug("Failed. Returning error code %s.", err == -EOVERFLOW ? | 929 | ntfs_debug("Failed. Returning error code %s.", err == -EOVERFLOW ? |
930 | "EOVERFLOW" : (!err ? "EIO" : "unkown error")); | 930 | "EOVERFLOW" : (!err ? "EIO" : "unknown error")); |
931 | return err < 0 ? err : -EIO; | 931 | return err < 0 ? err : -EIO; |
932 | 932 | ||
933 | read_err: | 933 | read_err: |
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 663c0e341f8b..43179ddd336f 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
@@ -399,7 +399,7 @@ static inline void ntfs_fault_in_pages_readable_iovec(const struct iovec *iov, | |||
399 | * @cached_page: allocated but as yet unused page | 399 | * @cached_page: allocated but as yet unused page |
400 | * @lru_pvec: lru-buffering pagevec of caller | 400 | * @lru_pvec: lru-buffering pagevec of caller |
401 | * | 401 | * |
402 | * Obtain @nr_pages locked page cache pages from the mapping @maping and | 402 | * Obtain @nr_pages locked page cache pages from the mapping @mapping and |
403 | * starting at index @index. | 403 | * starting at index @index. |
404 | * | 404 | * |
405 | * If a page is newly created, increment its refcount and add it to the | 405 | * If a page is newly created, increment its refcount and add it to the |
@@ -1281,7 +1281,7 @@ rl_not_mapped_enoent: | |||
1281 | 1281 | ||
1282 | /* | 1282 | /* |
1283 | * Copy as much as we can into the pages and return the number of bytes which | 1283 | * Copy as much as we can into the pages and return the number of bytes which |
1284 | * were sucessfully copied. If a fault is encountered then clear the pages | 1284 | * were successfully copied. If a fault is encountered then clear the pages |
1285 | * out to (ofs + bytes) and return the number of bytes which were copied. | 1285 | * out to (ofs + bytes) and return the number of bytes which were copied. |
1286 | */ | 1286 | */ |
1287 | static inline size_t ntfs_copy_from_user(struct page **pages, | 1287 | static inline size_t ntfs_copy_from_user(struct page **pages, |
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c index 89b02985c054..4dadcdf3d451 100644 --- a/fs/ntfs/logfile.c +++ b/fs/ntfs/logfile.c | |||
@@ -338,7 +338,7 @@ err_out: | |||
338 | * copy of the complete multi sector transfer deprotected page. On failure, | 338 | * copy of the complete multi sector transfer deprotected page. On failure, |
339 | * *@wrp is undefined. | 339 | * *@wrp is undefined. |
340 | * | 340 | * |
341 | * Simillarly, if @lsn is not NULL, on succes *@lsn will be set to the current | 341 | * Simillarly, if @lsn is not NULL, on success *@lsn will be set to the current |
342 | * logfile lsn according to this restart page. On failure, *@lsn is undefined. | 342 | * logfile lsn according to this restart page. On failure, *@lsn is undefined. |
343 | * | 343 | * |
344 | * The following error codes are defined: | 344 | * The following error codes are defined: |
diff --git a/fs/ntfs/sysctl.c b/fs/ntfs/sysctl.c index 9ef85e628fe1..79a89184cb5e 100644 --- a/fs/ntfs/sysctl.c +++ b/fs/ntfs/sysctl.c | |||
@@ -36,12 +36,11 @@ | |||
36 | /* Definition of the ntfs sysctl. */ | 36 | /* Definition of the ntfs sysctl. */ |
37 | static ctl_table ntfs_sysctls[] = { | 37 | static ctl_table ntfs_sysctls[] = { |
38 | { | 38 | { |
39 | .ctl_name = CTL_UNNUMBERED, /* Binary and text IDs. */ | ||
40 | .procname = "ntfs-debug", | 39 | .procname = "ntfs-debug", |
41 | .data = &debug_msgs, /* Data pointer and size. */ | 40 | .data = &debug_msgs, /* Data pointer and size. */ |
42 | .maxlen = sizeof(debug_msgs), | 41 | .maxlen = sizeof(debug_msgs), |
43 | .mode = 0644, /* Mode, proc handler. */ | 42 | .mode = 0644, /* Mode, proc handler. */ |
44 | .proc_handler = &proc_dointvec | 43 | .proc_handler = proc_dointvec |
45 | }, | 44 | }, |
46 | {} | 45 | {} |
47 | }; | 46 | }; |
@@ -49,7 +48,6 @@ static ctl_table ntfs_sysctls[] = { | |||
49 | /* Define the parent directory /proc/sys/fs. */ | 48 | /* Define the parent directory /proc/sys/fs. */ |
50 | static ctl_table sysctls_root[] = { | 49 | static ctl_table sysctls_root[] = { |
51 | { | 50 | { |
52 | .ctl_name = CTL_FS, | ||
53 | .procname = "fs", | 51 | .procname = "fs", |
54 | .mode = 0555, | 52 | .mode = 0555, |
55 | .child = ntfs_sysctls | 53 | .child = ntfs_sysctls |
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 38a42f5d59ff..7c7198a5bc90 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
@@ -2398,7 +2398,7 @@ static int ocfs2_leftmost_rec_contains(struct ocfs2_extent_list *el, u32 cpos) | |||
2398 | * | 2398 | * |
2399 | * The array is assumed to be large enough to hold an entire path (tree depth). | 2399 | * The array is assumed to be large enough to hold an entire path (tree depth). |
2400 | * | 2400 | * |
2401 | * Upon succesful return from this function: | 2401 | * Upon successful return from this function: |
2402 | * | 2402 | * |
2403 | * - The 'right_path' array will contain a path to the leaf block | 2403 | * - The 'right_path' array will contain a path to the leaf block |
2404 | * whose range contains e_cpos. | 2404 | * whose range contains e_cpos. |
diff --git a/fs/ocfs2/blockcheck.c b/fs/ocfs2/blockcheck.c index a1163b8b417c..b7428c5d0d3b 100644 --- a/fs/ocfs2/blockcheck.c +++ b/fs/ocfs2/blockcheck.c | |||
@@ -47,7 +47,7 @@ | |||
47 | * Calculate the bit offset in the hamming code buffer based on the bit's | 47 | * Calculate the bit offset in the hamming code buffer based on the bit's |
48 | * offset in the data buffer. Since the hamming code reserves all | 48 | * offset in the data buffer. Since the hamming code reserves all |
49 | * power-of-two bits for parity, the data bit number and the code bit | 49 | * power-of-two bits for parity, the data bit number and the code bit |
50 | * number are offest by all the parity bits beforehand. | 50 | * number are offset by all the parity bits beforehand. |
51 | * | 51 | * |
52 | * Recall that bit numbers in hamming code are 1-based. This function | 52 | * Recall that bit numbers in hamming code are 1-based. This function |
53 | * takes the 0-based data bit from the caller. | 53 | * takes the 0-based data bit from the caller. |
diff --git a/fs/ocfs2/cluster/netdebug.c b/fs/ocfs2/cluster/netdebug.c index da794bc07a6c..a3f150e52b02 100644 --- a/fs/ocfs2/cluster/netdebug.c +++ b/fs/ocfs2/cluster/netdebug.c | |||
@@ -294,10 +294,10 @@ static int sc_seq_show(struct seq_file *seq, void *v) | |||
294 | if (sc->sc_sock) { | 294 | if (sc->sc_sock) { |
295 | inet = inet_sk(sc->sc_sock->sk); | 295 | inet = inet_sk(sc->sc_sock->sk); |
296 | /* the stack's structs aren't sparse endian clean */ | 296 | /* the stack's structs aren't sparse endian clean */ |
297 | saddr = (__force __be32)inet->saddr; | 297 | saddr = (__force __be32)inet->inet_saddr; |
298 | daddr = (__force __be32)inet->daddr; | 298 | daddr = (__force __be32)inet->inet_daddr; |
299 | sport = (__force __be16)inet->sport; | 299 | sport = (__force __be16)inet->inet_sport; |
300 | dport = (__force __be16)inet->dport; | 300 | dport = (__force __be16)inet->inet_dport; |
301 | } | 301 | } |
302 | 302 | ||
303 | /* XXX sigh, inet-> doesn't have sparse annotation so any | 303 | /* XXX sigh, inet-> doesn't have sparse annotation so any |
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 83bcaf266b35..03ccf9a7b1f4 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c | |||
@@ -2586,7 +2586,7 @@ fail: | |||
2586 | * is complete everywhere. if the target dies while this is | 2586 | * is complete everywhere. if the target dies while this is |
2587 | * going on, some nodes could potentially see the target as the | 2587 | * going on, some nodes could potentially see the target as the |
2588 | * master, so it is important that my recovery finds the migration | 2588 | * master, so it is important that my recovery finds the migration |
2589 | * mle and sets the master to UNKNONWN. */ | 2589 | * mle and sets the master to UNKNOWN. */ |
2590 | 2590 | ||
2591 | 2591 | ||
2592 | /* wait for new node to assert master */ | 2592 | /* wait for new node to assert master */ |
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 0d38d67194cb..c5e4a49e3a12 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c | |||
@@ -1855,7 +1855,7 @@ int ocfs2_file_lock(struct file *file, int ex, int trylock) | |||
1855 | * outstanding lock request, so a cancel convert is | 1855 | * outstanding lock request, so a cancel convert is |
1856 | * required. We intentionally overwrite 'ret' - if the | 1856 | * required. We intentionally overwrite 'ret' - if the |
1857 | * cancel fails and the lock was granted, it's easier | 1857 | * cancel fails and the lock was granted, it's easier |
1858 | * to just bubble sucess back up to the user. | 1858 | * to just bubble success back up to the user. |
1859 | */ | 1859 | */ |
1860 | ret = ocfs2_flock_handle_signal(lockres, level); | 1860 | ret = ocfs2_flock_handle_signal(lockres, level); |
1861 | } else if (!ret && (level > lockres->l_level)) { | 1861 | } else if (!ret && (level > lockres->l_level)) { |
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 54c16b66327e..bf34c491ae96 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c | |||
@@ -659,7 +659,7 @@ static int __ocfs2_journal_access(handle_t *handle, | |||
659 | 659 | ||
660 | default: | 660 | default: |
661 | status = -EINVAL; | 661 | status = -EINVAL; |
662 | mlog(ML_ERROR, "Uknown access type!\n"); | 662 | mlog(ML_ERROR, "Unknown access type!\n"); |
663 | } | 663 | } |
664 | if (!status && ocfs2_meta_ecc(osb) && triggers) | 664 | if (!status && ocfs2_meta_ecc(osb) && triggers) |
665 | jbd2_journal_set_triggers(bh, &triggers->ot_triggers); | 665 | jbd2_journal_set_triggers(bh, &triggers->ot_triggers); |
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 3a0df7a1b810..30967e3f5e43 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
@@ -2431,7 +2431,7 @@ out: | |||
2431 | * we gonna touch and whether we need to create new blocks. | 2431 | * we gonna touch and whether we need to create new blocks. |
2432 | * | 2432 | * |
2433 | * Normally the refcount blocks store these refcount should be | 2433 | * Normally the refcount blocks store these refcount should be |
2434 | * continguous also, so that we can get the number easily. | 2434 | * contiguous also, so that we can get the number easily. |
2435 | * As for meta_ac, we will at most add split 2 refcount record and | 2435 | * As for meta_ac, we will at most add split 2 refcount record and |
2436 | * 2 more refcount block, so just check it in a rough way. | 2436 | * 2 more refcount block, so just check it in a rough way. |
2437 | * | 2437 | * |
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c index 3f2f1c45b7b6..f3df0baa9a48 100644 --- a/fs/ocfs2/stackglue.c +++ b/fs/ocfs2/stackglue.c | |||
@@ -620,51 +620,46 @@ error: | |||
620 | 620 | ||
621 | static ctl_table ocfs2_nm_table[] = { | 621 | static ctl_table ocfs2_nm_table[] = { |
622 | { | 622 | { |
623 | .ctl_name = 1, | ||
624 | .procname = "hb_ctl_path", | 623 | .procname = "hb_ctl_path", |
625 | .data = ocfs2_hb_ctl_path, | 624 | .data = ocfs2_hb_ctl_path, |
626 | .maxlen = OCFS2_MAX_HB_CTL_PATH, | 625 | .maxlen = OCFS2_MAX_HB_CTL_PATH, |
627 | .mode = 0644, | 626 | .mode = 0644, |
628 | .proc_handler = &proc_dostring, | 627 | .proc_handler = proc_dostring, |
629 | .strategy = &sysctl_string, | ||
630 | }, | 628 | }, |
631 | { .ctl_name = 0 } | 629 | { } |
632 | }; | 630 | }; |
633 | 631 | ||
634 | static ctl_table ocfs2_mod_table[] = { | 632 | static ctl_table ocfs2_mod_table[] = { |
635 | { | 633 | { |
636 | .ctl_name = FS_OCFS2_NM, | ||
637 | .procname = "nm", | 634 | .procname = "nm", |
638 | .data = NULL, | 635 | .data = NULL, |
639 | .maxlen = 0, | 636 | .maxlen = 0, |
640 | .mode = 0555, | 637 | .mode = 0555, |
641 | .child = ocfs2_nm_table | 638 | .child = ocfs2_nm_table |
642 | }, | 639 | }, |
643 | { .ctl_name = 0} | 640 | { } |
644 | }; | 641 | }; |
645 | 642 | ||
646 | static ctl_table ocfs2_kern_table[] = { | 643 | static ctl_table ocfs2_kern_table[] = { |
647 | { | 644 | { |
648 | .ctl_name = FS_OCFS2, | ||
649 | .procname = "ocfs2", | 645 | .procname = "ocfs2", |
650 | .data = NULL, | 646 | .data = NULL, |
651 | .maxlen = 0, | 647 | .maxlen = 0, |
652 | .mode = 0555, | 648 | .mode = 0555, |
653 | .child = ocfs2_mod_table | 649 | .child = ocfs2_mod_table |
654 | }, | 650 | }, |
655 | { .ctl_name = 0} | 651 | { } |
656 | }; | 652 | }; |
657 | 653 | ||
658 | static ctl_table ocfs2_root_table[] = { | 654 | static ctl_table ocfs2_root_table[] = { |
659 | { | 655 | { |
660 | .ctl_name = CTL_FS, | ||
661 | .procname = "fs", | 656 | .procname = "fs", |
662 | .data = NULL, | 657 | .data = NULL, |
663 | .maxlen = 0, | 658 | .maxlen = 0, |
664 | .mode = 0555, | 659 | .mode = 0555, |
665 | .child = ocfs2_kern_table | 660 | .child = ocfs2_kern_table |
666 | }, | 661 | }, |
667 | { .ctl_name = 0 } | 662 | { } |
668 | }; | 663 | }; |
669 | 664 | ||
670 | static struct ctl_table_header *ocfs2_table_header = NULL; | 665 | static struct ctl_table_header *ocfs2_table_header = NULL; |
diff --git a/fs/omfs/bitmap.c b/fs/omfs/bitmap.c index e1c0ec0ae989..082234581d05 100644 --- a/fs/omfs/bitmap.c +++ b/fs/omfs/bitmap.c | |||
@@ -85,7 +85,7 @@ out: | |||
85 | } | 85 | } |
86 | 86 | ||
87 | /* | 87 | /* |
88 | * Tries to allocate exactly one block. Returns true if sucessful. | 88 | * Tries to allocate exactly one block. Returns true if successful. |
89 | */ | 89 | */ |
90 | int omfs_allocate_block(struct super_block *sb, u64 block) | 90 | int omfs_allocate_block(struct super_block *sb, u64 block) |
91 | { | 91 | { |
@@ -587,6 +587,9 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) | |||
587 | error = -EPERM; | 587 | error = -EPERM; |
588 | if (!capable(CAP_SYS_CHROOT)) | 588 | if (!capable(CAP_SYS_CHROOT)) |
589 | goto dput_and_out; | 589 | goto dput_and_out; |
590 | error = security_path_chroot(&path); | ||
591 | if (error) | ||
592 | goto dput_and_out; | ||
590 | 593 | ||
591 | set_fs_root(current->fs, &path); | 594 | set_fs_root(current->fs, &path); |
592 | error = 0; | 595 | error = 0; |
@@ -617,11 +620,15 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) | |||
617 | if (err) | 620 | if (err) |
618 | goto out_putf; | 621 | goto out_putf; |
619 | mutex_lock(&inode->i_mutex); | 622 | mutex_lock(&inode->i_mutex); |
623 | err = security_path_chmod(dentry, file->f_vfsmnt, mode); | ||
624 | if (err) | ||
625 | goto out_unlock; | ||
620 | if (mode == (mode_t) -1) | 626 | if (mode == (mode_t) -1) |
621 | mode = inode->i_mode; | 627 | mode = inode->i_mode; |
622 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | 628 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); |
623 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 629 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; |
624 | err = notify_change(dentry, &newattrs); | 630 | err = notify_change(dentry, &newattrs); |
631 | out_unlock: | ||
625 | mutex_unlock(&inode->i_mutex); | 632 | mutex_unlock(&inode->i_mutex); |
626 | mnt_drop_write(file->f_path.mnt); | 633 | mnt_drop_write(file->f_path.mnt); |
627 | out_putf: | 634 | out_putf: |
@@ -646,11 +653,15 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode) | |||
646 | if (error) | 653 | if (error) |
647 | goto dput_and_out; | 654 | goto dput_and_out; |
648 | mutex_lock(&inode->i_mutex); | 655 | mutex_lock(&inode->i_mutex); |
656 | error = security_path_chmod(path.dentry, path.mnt, mode); | ||
657 | if (error) | ||
658 | goto out_unlock; | ||
649 | if (mode == (mode_t) -1) | 659 | if (mode == (mode_t) -1) |
650 | mode = inode->i_mode; | 660 | mode = inode->i_mode; |
651 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | 661 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); |
652 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 662 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; |
653 | error = notify_change(path.dentry, &newattrs); | 663 | error = notify_change(path.dentry, &newattrs); |
664 | out_unlock: | ||
654 | mutex_unlock(&inode->i_mutex); | 665 | mutex_unlock(&inode->i_mutex); |
655 | mnt_drop_write(path.mnt); | 666 | mnt_drop_write(path.mnt); |
656 | dput_and_out: | 667 | dput_and_out: |
@@ -664,9 +675,9 @@ SYSCALL_DEFINE2(chmod, const char __user *, filename, mode_t, mode) | |||
664 | return sys_fchmodat(AT_FDCWD, filename, mode); | 675 | return sys_fchmodat(AT_FDCWD, filename, mode); |
665 | } | 676 | } |
666 | 677 | ||
667 | static int chown_common(struct dentry * dentry, uid_t user, gid_t group) | 678 | static int chown_common(struct path *path, uid_t user, gid_t group) |
668 | { | 679 | { |
669 | struct inode *inode = dentry->d_inode; | 680 | struct inode *inode = path->dentry->d_inode; |
670 | int error; | 681 | int error; |
671 | struct iattr newattrs; | 682 | struct iattr newattrs; |
672 | 683 | ||
@@ -683,7 +694,9 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group) | |||
683 | newattrs.ia_valid |= | 694 | newattrs.ia_valid |= |
684 | ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; | 695 | ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; |
685 | mutex_lock(&inode->i_mutex); | 696 | mutex_lock(&inode->i_mutex); |
686 | error = notify_change(dentry, &newattrs); | 697 | error = security_path_chown(path, user, group); |
698 | if (!error) | ||
699 | error = notify_change(path->dentry, &newattrs); | ||
687 | mutex_unlock(&inode->i_mutex); | 700 | mutex_unlock(&inode->i_mutex); |
688 | 701 | ||
689 | return error; | 702 | return error; |
@@ -700,7 +713,7 @@ SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group) | |||
700 | error = mnt_want_write(path.mnt); | 713 | error = mnt_want_write(path.mnt); |
701 | if (error) | 714 | if (error) |
702 | goto out_release; | 715 | goto out_release; |
703 | error = chown_common(path.dentry, user, group); | 716 | error = chown_common(&path, user, group); |
704 | mnt_drop_write(path.mnt); | 717 | mnt_drop_write(path.mnt); |
705 | out_release: | 718 | out_release: |
706 | path_put(&path); | 719 | path_put(&path); |
@@ -725,7 +738,7 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user, | |||
725 | error = mnt_want_write(path.mnt); | 738 | error = mnt_want_write(path.mnt); |
726 | if (error) | 739 | if (error) |
727 | goto out_release; | 740 | goto out_release; |
728 | error = chown_common(path.dentry, user, group); | 741 | error = chown_common(&path, user, group); |
729 | mnt_drop_write(path.mnt); | 742 | mnt_drop_write(path.mnt); |
730 | out_release: | 743 | out_release: |
731 | path_put(&path); | 744 | path_put(&path); |
@@ -744,7 +757,7 @@ SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group | |||
744 | error = mnt_want_write(path.mnt); | 757 | error = mnt_want_write(path.mnt); |
745 | if (error) | 758 | if (error) |
746 | goto out_release; | 759 | goto out_release; |
747 | error = chown_common(path.dentry, user, group); | 760 | error = chown_common(&path, user, group); |
748 | mnt_drop_write(path.mnt); | 761 | mnt_drop_write(path.mnt); |
749 | out_release: | 762 | out_release: |
750 | path_put(&path); | 763 | path_put(&path); |
@@ -767,7 +780,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) | |||
767 | goto out_fput; | 780 | goto out_fput; |
768 | dentry = file->f_path.dentry; | 781 | dentry = file->f_path.dentry; |
769 | audit_inode(NULL, dentry); | 782 | audit_inode(NULL, dentry); |
770 | error = chown_common(dentry, user, group); | 783 | error = chown_common(&file->f_path, user, group); |
771 | mnt_drop_write(file->f_path.mnt); | 784 | mnt_drop_write(file->f_path.mnt); |
772 | out_fput: | 785 | out_fput: |
773 | fput(file); | 786 | fput(file); |
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 7b685e10cbad..64bc8998ac9a 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -226,6 +226,13 @@ ssize_t part_alignment_offset_show(struct device *dev, | |||
226 | return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset); | 226 | return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset); |
227 | } | 227 | } |
228 | 228 | ||
229 | ssize_t part_discard_alignment_show(struct device *dev, | ||
230 | struct device_attribute *attr, char *buf) | ||
231 | { | ||
232 | struct hd_struct *p = dev_to_part(dev); | ||
233 | return sprintf(buf, "%u\n", p->discard_alignment); | ||
234 | } | ||
235 | |||
229 | ssize_t part_stat_show(struct device *dev, | 236 | ssize_t part_stat_show(struct device *dev, |
230 | struct device_attribute *attr, char *buf) | 237 | struct device_attribute *attr, char *buf) |
231 | { | 238 | { |
@@ -288,6 +295,8 @@ static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL); | |||
288 | static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); | 295 | static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); |
289 | static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); | 296 | static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); |
290 | static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL); | 297 | static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL); |
298 | static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show, | ||
299 | NULL); | ||
291 | static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); | 300 | static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); |
292 | static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); | 301 | static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); |
293 | #ifdef CONFIG_FAIL_MAKE_REQUEST | 302 | #ifdef CONFIG_FAIL_MAKE_REQUEST |
@@ -300,6 +309,7 @@ static struct attribute *part_attrs[] = { | |||
300 | &dev_attr_start.attr, | 309 | &dev_attr_start.attr, |
301 | &dev_attr_size.attr, | 310 | &dev_attr_size.attr, |
302 | &dev_attr_alignment_offset.attr, | 311 | &dev_attr_alignment_offset.attr, |
312 | &dev_attr_discard_alignment.attr, | ||
303 | &dev_attr_stat.attr, | 313 | &dev_attr_stat.attr, |
304 | &dev_attr_inflight.attr, | 314 | &dev_attr_inflight.attr, |
305 | #ifdef CONFIG_FAIL_MAKE_REQUEST | 315 | #ifdef CONFIG_FAIL_MAKE_REQUEST |
@@ -403,6 +413,8 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, | |||
403 | 413 | ||
404 | p->start_sect = start; | 414 | p->start_sect = start; |
405 | p->alignment_offset = queue_sector_alignment_offset(disk->queue, start); | 415 | p->alignment_offset = queue_sector_alignment_offset(disk->queue, start); |
416 | p->discard_alignment = queue_sector_discard_alignment(disk->queue, | ||
417 | start); | ||
406 | p->nr_sects = len; | 418 | p->nr_sects = len; |
407 | p->partno = partno; | 419 | p->partno = partno; |
408 | p->policy = get_disk_ro(disk); | 420 | p->policy = get_disk_ro(disk); |
diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c index 038a6022152f..49cfd5f54238 100644 --- a/fs/partitions/efi.c +++ b/fs/partitions/efi.c | |||
@@ -1,7 +1,9 @@ | |||
1 | /************************************************************ | 1 | /************************************************************ |
2 | * EFI GUID Partition Table handling | 2 | * EFI GUID Partition Table handling |
3 | * Per Intel EFI Specification v1.02 | 3 | * |
4 | * http://developer.intel.com/technology/efi/efi.htm | 4 | * http://www.uefi.org/specs/ |
5 | * http://www.intel.com/technology/efi/ | ||
6 | * | ||
5 | * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com> | 7 | * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com> |
6 | * Copyright 2000,2001,2002,2004 Dell Inc. | 8 | * Copyright 2000,2001,2002,2004 Dell Inc. |
7 | * | 9 | * |
@@ -92,6 +94,7 @@ | |||
92 | * | 94 | * |
93 | ************************************************************/ | 95 | ************************************************************/ |
94 | #include <linux/crc32.h> | 96 | #include <linux/crc32.h> |
97 | #include <linux/math64.h> | ||
95 | #include "check.h" | 98 | #include "check.h" |
96 | #include "efi.h" | 99 | #include "efi.h" |
97 | 100 | ||
@@ -141,7 +144,8 @@ last_lba(struct block_device *bdev) | |||
141 | { | 144 | { |
142 | if (!bdev || !bdev->bd_inode) | 145 | if (!bdev || !bdev->bd_inode) |
143 | return 0; | 146 | return 0; |
144 | return (bdev->bd_inode->i_size >> 9) - 1ULL; | 147 | return div_u64(bdev->bd_inode->i_size, |
148 | bdev_logical_block_size(bdev)) - 1ULL; | ||
145 | } | 149 | } |
146 | 150 | ||
147 | static inline int | 151 | static inline int |
@@ -188,6 +192,7 @@ static size_t | |||
188 | read_lba(struct block_device *bdev, u64 lba, u8 * buffer, size_t count) | 192 | read_lba(struct block_device *bdev, u64 lba, u8 * buffer, size_t count) |
189 | { | 193 | { |
190 | size_t totalreadcount = 0; | 194 | size_t totalreadcount = 0; |
195 | sector_t n = lba * (bdev_logical_block_size(bdev) / 512); | ||
191 | 196 | ||
192 | if (!bdev || !buffer || lba > last_lba(bdev)) | 197 | if (!bdev || !buffer || lba > last_lba(bdev)) |
193 | return 0; | 198 | return 0; |
@@ -195,7 +200,7 @@ read_lba(struct block_device *bdev, u64 lba, u8 * buffer, size_t count) | |||
195 | while (count) { | 200 | while (count) { |
196 | int copied = 512; | 201 | int copied = 512; |
197 | Sector sect; | 202 | Sector sect; |
198 | unsigned char *data = read_dev_sector(bdev, lba++, §); | 203 | unsigned char *data = read_dev_sector(bdev, n++, §); |
199 | if (!data) | 204 | if (!data) |
200 | break; | 205 | break; |
201 | if (copied > count) | 206 | if (copied > count) |
@@ -257,15 +262,16 @@ static gpt_header * | |||
257 | alloc_read_gpt_header(struct block_device *bdev, u64 lba) | 262 | alloc_read_gpt_header(struct block_device *bdev, u64 lba) |
258 | { | 263 | { |
259 | gpt_header *gpt; | 264 | gpt_header *gpt; |
265 | unsigned ssz = bdev_logical_block_size(bdev); | ||
266 | |||
260 | if (!bdev) | 267 | if (!bdev) |
261 | return NULL; | 268 | return NULL; |
262 | 269 | ||
263 | gpt = kzalloc(sizeof (gpt_header), GFP_KERNEL); | 270 | gpt = kzalloc(ssz, GFP_KERNEL); |
264 | if (!gpt) | 271 | if (!gpt) |
265 | return NULL; | 272 | return NULL; |
266 | 273 | ||
267 | if (read_lba(bdev, lba, (u8 *) gpt, | 274 | if (read_lba(bdev, lba, (u8 *) gpt, ssz) < ssz) { |
268 | sizeof (gpt_header)) < sizeof (gpt_header)) { | ||
269 | kfree(gpt); | 275 | kfree(gpt); |
270 | gpt=NULL; | 276 | gpt=NULL; |
271 | return NULL; | 277 | return NULL; |
@@ -601,6 +607,7 @@ efi_partition(struct parsed_partitions *state, struct block_device *bdev) | |||
601 | gpt_header *gpt = NULL; | 607 | gpt_header *gpt = NULL; |
602 | gpt_entry *ptes = NULL; | 608 | gpt_entry *ptes = NULL; |
603 | u32 i; | 609 | u32 i; |
610 | unsigned ssz = bdev_logical_block_size(bdev) / 512; | ||
604 | 611 | ||
605 | if (!find_valid_gpt(bdev, &gpt, &ptes) || !gpt || !ptes) { | 612 | if (!find_valid_gpt(bdev, &gpt, &ptes) || !gpt || !ptes) { |
606 | kfree(gpt); | 613 | kfree(gpt); |
@@ -611,13 +618,14 @@ efi_partition(struct parsed_partitions *state, struct block_device *bdev) | |||
611 | pr_debug("GUID Partition Table is valid! Yea!\n"); | 618 | pr_debug("GUID Partition Table is valid! Yea!\n"); |
612 | 619 | ||
613 | for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { | 620 | for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { |
621 | u64 start = le64_to_cpu(ptes[i].starting_lba); | ||
622 | u64 size = le64_to_cpu(ptes[i].ending_lba) - | ||
623 | le64_to_cpu(ptes[i].starting_lba) + 1ULL; | ||
624 | |||
614 | if (!is_pte_valid(&ptes[i], last_lba(bdev))) | 625 | if (!is_pte_valid(&ptes[i], last_lba(bdev))) |
615 | continue; | 626 | continue; |
616 | 627 | ||
617 | put_partition(state, i+1, le64_to_cpu(ptes[i].starting_lba), | 628 | put_partition(state, i+1, start * ssz, size * ssz); |
618 | (le64_to_cpu(ptes[i].ending_lba) - | ||
619 | le64_to_cpu(ptes[i].starting_lba) + | ||
620 | 1ULL)); | ||
621 | 629 | ||
622 | /* If this is a RAID volume, tell md */ | 630 | /* If this is a RAID volume, tell md */ |
623 | if (!efi_guidcmp(ptes[i].partition_type_guid, | 631 | if (!efi_guidcmp(ptes[i].partition_type_guid, |
diff --git a/fs/partitions/efi.h b/fs/partitions/efi.h index 2cc89d0475bf..6998b589abf9 100644 --- a/fs/partitions/efi.h +++ b/fs/partitions/efi.h | |||
@@ -37,7 +37,6 @@ | |||
37 | #define EFI_PMBR_OSTYPE_EFI 0xEF | 37 | #define EFI_PMBR_OSTYPE_EFI 0xEF |
38 | #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE | 38 | #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE |
39 | 39 | ||
40 | #define GPT_BLOCK_SIZE 512 | ||
41 | #define GPT_HEADER_SIGNATURE 0x5452415020494645ULL | 40 | #define GPT_HEADER_SIGNATURE 0x5452415020494645ULL |
42 | #define GPT_HEADER_REVISION_V1 0x00010000 | 41 | #define GPT_HEADER_REVISION_V1 0x00010000 |
43 | #define GPT_PRIMARY_PARTITION_TABLE_LBA 1 | 42 | #define GPT_PRIMARY_PARTITION_TABLE_LBA 1 |
@@ -79,7 +78,12 @@ typedef struct _gpt_header { | |||
79 | __le32 num_partition_entries; | 78 | __le32 num_partition_entries; |
80 | __le32 sizeof_partition_entry; | 79 | __le32 sizeof_partition_entry; |
81 | __le32 partition_entry_array_crc32; | 80 | __le32 partition_entry_array_crc32; |
82 | u8 reserved2[GPT_BLOCK_SIZE - 92]; | 81 | |
82 | /* The rest of the logical block is reserved by UEFI and must be zero. | ||
83 | * EFI standard handles this by: | ||
84 | * | ||
85 | * uint8_t reserved2[ BlockSize - 92 ]; | ||
86 | */ | ||
83 | } __attribute__ ((packed)) gpt_header; | 87 | } __attribute__ ((packed)) gpt_header; |
84 | 88 | ||
85 | typedef struct _gpt_entry_attributes { | 89 | typedef struct _gpt_entry_attributes { |
diff --git a/fs/proc/array.c b/fs/proc/array.c index 822c2d506518..4badde179b18 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -410,6 +410,16 @@ static void task_show_stack_usage(struct seq_file *m, struct task_struct *task) | |||
410 | } | 410 | } |
411 | #endif /* CONFIG_MMU */ | 411 | #endif /* CONFIG_MMU */ |
412 | 412 | ||
413 | static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) | ||
414 | { | ||
415 | seq_printf(m, "Cpus_allowed:\t"); | ||
416 | seq_cpumask(m, &task->cpus_allowed); | ||
417 | seq_printf(m, "\n"); | ||
418 | seq_printf(m, "Cpus_allowed_list:\t"); | ||
419 | seq_cpumask_list(m, &task->cpus_allowed); | ||
420 | seq_printf(m, "\n"); | ||
421 | } | ||
422 | |||
413 | int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, | 423 | int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, |
414 | struct pid *pid, struct task_struct *task) | 424 | struct pid *pid, struct task_struct *task) |
415 | { | 425 | { |
@@ -424,6 +434,7 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, | |||
424 | } | 434 | } |
425 | task_sig(m, task); | 435 | task_sig(m, task); |
426 | task_cap(m, task); | 436 | task_cap(m, task); |
437 | task_cpus_allowed(m, task); | ||
427 | cpuset_task_status_allowed(m, task); | 438 | cpuset_task_status_allowed(m, task); |
428 | #if defined(CONFIG_S390) | 439 | #if defined(CONFIG_S390) |
429 | task_show_regs(m, task); | 440 | task_show_regs(m, task); |
@@ -495,20 +506,17 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
495 | 506 | ||
496 | /* add up live thread stats at the group level */ | 507 | /* add up live thread stats at the group level */ |
497 | if (whole) { | 508 | if (whole) { |
498 | struct task_cputime cputime; | ||
499 | struct task_struct *t = task; | 509 | struct task_struct *t = task; |
500 | do { | 510 | do { |
501 | min_flt += t->min_flt; | 511 | min_flt += t->min_flt; |
502 | maj_flt += t->maj_flt; | 512 | maj_flt += t->maj_flt; |
503 | gtime = cputime_add(gtime, task_gtime(t)); | 513 | gtime = cputime_add(gtime, t->gtime); |
504 | t = next_thread(t); | 514 | t = next_thread(t); |
505 | } while (t != task); | 515 | } while (t != task); |
506 | 516 | ||
507 | min_flt += sig->min_flt; | 517 | min_flt += sig->min_flt; |
508 | maj_flt += sig->maj_flt; | 518 | maj_flt += sig->maj_flt; |
509 | thread_group_cputime(task, &cputime); | 519 | thread_group_times(task, &utime, &stime); |
510 | utime = cputime.utime; | ||
511 | stime = cputime.stime; | ||
512 | gtime = cputime_add(gtime, sig->gtime); | 520 | gtime = cputime_add(gtime, sig->gtime); |
513 | } | 521 | } |
514 | 522 | ||
@@ -524,9 +532,8 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
524 | if (!whole) { | 532 | if (!whole) { |
525 | min_flt = task->min_flt; | 533 | min_flt = task->min_flt; |
526 | maj_flt = task->maj_flt; | 534 | maj_flt = task->maj_flt; |
527 | utime = task_utime(task); | 535 | task_times(task, &utime, &stime); |
528 | stime = task_stime(task); | 536 | gtime = task->gtime; |
529 | gtime = task_gtime(task); | ||
530 | } | 537 | } |
531 | 538 | ||
532 | /* scale priority and nice values from timeslices to -20..20 */ | 539 | /* scale priority and nice values from timeslices to -20..20 */ |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index f667e8aeabdf..6ff9981f0a18 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -48,7 +48,7 @@ out: | |||
48 | static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name) | 48 | static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name) |
49 | { | 49 | { |
50 | int len; | 50 | int len; |
51 | for ( ; p->ctl_name || p->procname; p++) { | 51 | for ( ; p->procname; p++) { |
52 | 52 | ||
53 | if (!p->procname) | 53 | if (!p->procname) |
54 | continue; | 54 | continue; |
@@ -218,7 +218,7 @@ static int scan(struct ctl_table_header *head, ctl_table *table, | |||
218 | void *dirent, filldir_t filldir) | 218 | void *dirent, filldir_t filldir) |
219 | { | 219 | { |
220 | 220 | ||
221 | for (; table->ctl_name || table->procname; table++, (*pos)++) { | 221 | for (; table->procname; table++, (*pos)++) { |
222 | int res; | 222 | int res; |
223 | 223 | ||
224 | /* Can't do anything without a proc name */ | 224 | /* Can't do anything without a proc name */ |
diff --git a/fs/proc/stat.c b/fs/proc/stat.c index 7cc726c6d70a..b9b7aad2003d 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c | |||
@@ -27,7 +27,7 @@ static int show_stat(struct seq_file *p, void *v) | |||
27 | int i, j; | 27 | int i, j; |
28 | unsigned long jif; | 28 | unsigned long jif; |
29 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; | 29 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; |
30 | cputime64_t guest; | 30 | cputime64_t guest, guest_nice; |
31 | u64 sum = 0; | 31 | u64 sum = 0; |
32 | u64 sum_softirq = 0; | 32 | u64 sum_softirq = 0; |
33 | unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; | 33 | unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; |
@@ -36,7 +36,7 @@ static int show_stat(struct seq_file *p, void *v) | |||
36 | 36 | ||
37 | user = nice = system = idle = iowait = | 37 | user = nice = system = idle = iowait = |
38 | irq = softirq = steal = cputime64_zero; | 38 | irq = softirq = steal = cputime64_zero; |
39 | guest = cputime64_zero; | 39 | guest = guest_nice = cputime64_zero; |
40 | getboottime(&boottime); | 40 | getboottime(&boottime); |
41 | jif = boottime.tv_sec; | 41 | jif = boottime.tv_sec; |
42 | 42 | ||
@@ -51,6 +51,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
51 | softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); | 51 | softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); |
52 | steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); | 52 | steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); |
53 | guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); | 53 | guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); |
54 | guest_nice = cputime64_add(guest_nice, | ||
55 | kstat_cpu(i).cpustat.guest_nice); | ||
54 | for_each_irq_nr(j) { | 56 | for_each_irq_nr(j) { |
55 | sum += kstat_irqs_cpu(j, i); | 57 | sum += kstat_irqs_cpu(j, i); |
56 | } | 58 | } |
@@ -65,7 +67,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
65 | } | 67 | } |
66 | sum += arch_irq_stat(); | 68 | sum += arch_irq_stat(); |
67 | 69 | ||
68 | seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", | 70 | seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu " |
71 | "%llu\n", | ||
69 | (unsigned long long)cputime64_to_clock_t(user), | 72 | (unsigned long long)cputime64_to_clock_t(user), |
70 | (unsigned long long)cputime64_to_clock_t(nice), | 73 | (unsigned long long)cputime64_to_clock_t(nice), |
71 | (unsigned long long)cputime64_to_clock_t(system), | 74 | (unsigned long long)cputime64_to_clock_t(system), |
@@ -74,7 +77,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
74 | (unsigned long long)cputime64_to_clock_t(irq), | 77 | (unsigned long long)cputime64_to_clock_t(irq), |
75 | (unsigned long long)cputime64_to_clock_t(softirq), | 78 | (unsigned long long)cputime64_to_clock_t(softirq), |
76 | (unsigned long long)cputime64_to_clock_t(steal), | 79 | (unsigned long long)cputime64_to_clock_t(steal), |
77 | (unsigned long long)cputime64_to_clock_t(guest)); | 80 | (unsigned long long)cputime64_to_clock_t(guest), |
81 | (unsigned long long)cputime64_to_clock_t(guest_nice)); | ||
78 | for_each_online_cpu(i) { | 82 | for_each_online_cpu(i) { |
79 | 83 | ||
80 | /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ | 84 | /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ |
@@ -88,8 +92,10 @@ static int show_stat(struct seq_file *p, void *v) | |||
88 | softirq = kstat_cpu(i).cpustat.softirq; | 92 | softirq = kstat_cpu(i).cpustat.softirq; |
89 | steal = kstat_cpu(i).cpustat.steal; | 93 | steal = kstat_cpu(i).cpustat.steal; |
90 | guest = kstat_cpu(i).cpustat.guest; | 94 | guest = kstat_cpu(i).cpustat.guest; |
95 | guest_nice = kstat_cpu(i).cpustat.guest_nice; | ||
91 | seq_printf(p, | 96 | seq_printf(p, |
92 | "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", | 97 | "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu " |
98 | "%llu\n", | ||
93 | i, | 99 | i, |
94 | (unsigned long long)cputime64_to_clock_t(user), | 100 | (unsigned long long)cputime64_to_clock_t(user), |
95 | (unsigned long long)cputime64_to_clock_t(nice), | 101 | (unsigned long long)cputime64_to_clock_t(nice), |
@@ -99,7 +105,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
99 | (unsigned long long)cputime64_to_clock_t(irq), | 105 | (unsigned long long)cputime64_to_clock_t(irq), |
100 | (unsigned long long)cputime64_to_clock_t(softirq), | 106 | (unsigned long long)cputime64_to_clock_t(softirq), |
101 | (unsigned long long)cputime64_to_clock_t(steal), | 107 | (unsigned long long)cputime64_to_clock_t(steal), |
102 | (unsigned long long)cputime64_to_clock_t(guest)); | 108 | (unsigned long long)cputime64_to_clock_t(guest), |
109 | (unsigned long long)cputime64_to_clock_t(guest_nice)); | ||
103 | } | 110 | } |
104 | seq_printf(p, "intr %llu", (unsigned long long)sum); | 111 | seq_printf(p, "intr %llu", (unsigned long long)sum); |
105 | 112 | ||
diff --git a/fs/qnx4/bitmap.c b/fs/qnx4/bitmap.c index 0afba069d567..32f5d131a644 100644 --- a/fs/qnx4/bitmap.c +++ b/fs/qnx4/bitmap.c | |||
@@ -67,7 +67,7 @@ unsigned long qnx4_count_free_blocks(struct super_block *sb) | |||
67 | 67 | ||
68 | while (total < size) { | 68 | while (total < size) { |
69 | if ((bh = sb_bread(sb, start + offset)) == NULL) { | 69 | if ((bh = sb_bread(sb, start + offset)) == NULL) { |
70 | printk("qnx4: I/O error in counting free blocks\n"); | 70 | printk(KERN_ERR "qnx4: I/O error in counting free blocks\n"); |
71 | break; | 71 | break; |
72 | } | 72 | } |
73 | count_bits(bh->b_data, size - total, &total_free); | 73 | count_bits(bh->b_data, size - total, &total_free); |
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c index 86cc39cb1398..6f30c3d5bcbf 100644 --- a/fs/qnx4/dir.c +++ b/fs/qnx4/dir.c | |||
@@ -26,8 +26,8 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
26 | int ix, ino; | 26 | int ix, ino; |
27 | int size; | 27 | int size; |
28 | 28 | ||
29 | QNX4DEBUG(("qnx4_readdir:i_size = %ld\n", (long) inode->i_size)); | 29 | QNX4DEBUG((KERN_INFO "qnx4_readdir:i_size = %ld\n", (long) inode->i_size)); |
30 | QNX4DEBUG(("filp->f_pos = %ld\n", (long) filp->f_pos)); | 30 | QNX4DEBUG((KERN_INFO "filp->f_pos = %ld\n", (long) filp->f_pos)); |
31 | 31 | ||
32 | lock_kernel(); | 32 | lock_kernel(); |
33 | 33 | ||
@@ -50,7 +50,7 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
50 | size = QNX4_NAME_MAX; | 50 | size = QNX4_NAME_MAX; |
51 | 51 | ||
52 | if ( ( de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK) ) != 0 ) { | 52 | if ( ( de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK) ) != 0 ) { |
53 | QNX4DEBUG(("qnx4_readdir:%.*s\n", size, de->di_fname)); | 53 | QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, de->di_fname)); |
54 | if ( ( de->di_status & QNX4_FILE_LINK ) == 0 ) | 54 | if ( ( de->di_status & QNX4_FILE_LINK ) == 0 ) |
55 | ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1; | 55 | ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1; |
56 | else { | 56 | else { |
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index d2cd1798d8c4..449f5a66dd34 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c | |||
@@ -107,7 +107,7 @@ static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_h | |||
107 | { | 107 | { |
108 | unsigned long phys; | 108 | unsigned long phys; |
109 | 109 | ||
110 | QNX4DEBUG(("qnx4: qnx4_get_block inode=[%ld] iblock=[%ld]\n",inode->i_ino,iblock)); | 110 | QNX4DEBUG((KERN_INFO "qnx4: qnx4_get_block inode=[%ld] iblock=[%ld]\n",inode->i_ino,iblock)); |
111 | 111 | ||
112 | phys = qnx4_block_map( inode, iblock ); | 112 | phys = qnx4_block_map( inode, iblock ); |
113 | if ( phys ) { | 113 | if ( phys ) { |
@@ -142,12 +142,12 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock ) | |||
142 | // read next xtnt block. | 142 | // read next xtnt block. |
143 | bh = sb_bread(inode->i_sb, i_xblk - 1); | 143 | bh = sb_bread(inode->i_sb, i_xblk - 1); |
144 | if ( !bh ) { | 144 | if ( !bh ) { |
145 | QNX4DEBUG(("qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1)); | 145 | QNX4DEBUG((KERN_ERR "qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1)); |
146 | return -EIO; | 146 | return -EIO; |
147 | } | 147 | } |
148 | xblk = (struct qnx4_xblk*)bh->b_data; | 148 | xblk = (struct qnx4_xblk*)bh->b_data; |
149 | if ( memcmp( xblk->xblk_signature, "IamXblk", 7 ) ) { | 149 | if ( memcmp( xblk->xblk_signature, "IamXblk", 7 ) ) { |
150 | QNX4DEBUG(("qnx4: block at %ld is not a valid xtnt\n", qnx4_inode->i_xblk)); | 150 | QNX4DEBUG((KERN_ERR "qnx4: block at %ld is not a valid xtnt\n", qnx4_inode->i_xblk)); |
151 | return -EIO; | 151 | return -EIO; |
152 | } | 152 | } |
153 | } | 153 | } |
@@ -168,7 +168,7 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock ) | |||
168 | brelse( bh ); | 168 | brelse( bh ); |
169 | } | 169 | } |
170 | 170 | ||
171 | QNX4DEBUG(("qnx4: mapping block %ld of inode %ld = %ld\n",iblock,inode->i_ino,block)); | 171 | QNX4DEBUG((KERN_INFO "qnx4: mapping block %ld of inode %ld = %ld\n",iblock,inode->i_ino,block)); |
172 | return block; | 172 | return block; |
173 | } | 173 | } |
174 | 174 | ||
@@ -209,7 +209,7 @@ static const char *qnx4_checkroot(struct super_block *sb) | |||
209 | if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') { | 209 | if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') { |
210 | return "no qnx4 filesystem (no root dir)."; | 210 | return "no qnx4 filesystem (no root dir)."; |
211 | } else { | 211 | } else { |
212 | QNX4DEBUG(("QNX4 filesystem found on dev %s.\n", sb->s_id)); | 212 | QNX4DEBUG((KERN_NOTICE "QNX4 filesystem found on dev %s.\n", sb->s_id)); |
213 | rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1; | 213 | rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1; |
214 | rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size); | 214 | rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size); |
215 | for (j = 0; j < rl; j++) { | 215 | for (j = 0; j < rl; j++) { |
@@ -220,7 +220,7 @@ static const char *qnx4_checkroot(struct super_block *sb) | |||
220 | for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) { | 220 | for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) { |
221 | rootdir = (struct qnx4_inode_entry *) (bh->b_data + i * QNX4_DIR_ENTRY_SIZE); | 221 | rootdir = (struct qnx4_inode_entry *) (bh->b_data + i * QNX4_DIR_ENTRY_SIZE); |
222 | if (rootdir->di_fname != NULL) { | 222 | if (rootdir->di_fname != NULL) { |
223 | QNX4DEBUG(("Rootdir entry found : [%s]\n", rootdir->di_fname)); | 223 | QNX4DEBUG((KERN_INFO "rootdir entry found : [%s]\n", rootdir->di_fname)); |
224 | if (!strncmp(rootdir->di_fname, QNX4_BMNAME, sizeof QNX4_BMNAME)) { | 224 | if (!strncmp(rootdir->di_fname, QNX4_BMNAME, sizeof QNX4_BMNAME)) { |
225 | found = 1; | 225 | found = 1; |
226 | qnx4_sb(sb)->BitMap = kmalloc( sizeof( struct qnx4_inode_entry ), GFP_KERNEL ); | 226 | qnx4_sb(sb)->BitMap = kmalloc( sizeof( struct qnx4_inode_entry ), GFP_KERNEL ); |
@@ -265,12 +265,12 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) | |||
265 | if we don't belong here... */ | 265 | if we don't belong here... */ |
266 | bh = sb_bread(s, 1); | 266 | bh = sb_bread(s, 1); |
267 | if (!bh) { | 267 | if (!bh) { |
268 | printk("qnx4: unable to read the superblock\n"); | 268 | printk(KERN_ERR "qnx4: unable to read the superblock\n"); |
269 | goto outnobh; | 269 | goto outnobh; |
270 | } | 270 | } |
271 | if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) { | 271 | if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) { |
272 | if (!silent) | 272 | if (!silent) |
273 | printk("qnx4: wrong fsid in superblock.\n"); | 273 | printk(KERN_ERR "qnx4: wrong fsid in superblock.\n"); |
274 | goto out; | 274 | goto out; |
275 | } | 275 | } |
276 | s->s_op = &qnx4_sops; | 276 | s->s_op = &qnx4_sops; |
@@ -284,14 +284,14 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) | |||
284 | errmsg = qnx4_checkroot(s); | 284 | errmsg = qnx4_checkroot(s); |
285 | if (errmsg != NULL) { | 285 | if (errmsg != NULL) { |
286 | if (!silent) | 286 | if (!silent) |
287 | printk("qnx4: %s\n", errmsg); | 287 | printk(KERN_ERR "qnx4: %s\n", errmsg); |
288 | goto out; | 288 | goto out; |
289 | } | 289 | } |
290 | 290 | ||
291 | /* does root not have inode number QNX4_ROOT_INO ?? */ | 291 | /* does root not have inode number QNX4_ROOT_INO ?? */ |
292 | root = qnx4_iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK); | 292 | root = qnx4_iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK); |
293 | if (IS_ERR(root)) { | 293 | if (IS_ERR(root)) { |
294 | printk("qnx4: get inode failed\n"); | 294 | printk(KERN_ERR "qnx4: get inode failed\n"); |
295 | ret = PTR_ERR(root); | 295 | ret = PTR_ERR(root); |
296 | goto out; | 296 | goto out; |
297 | } | 297 | } |
@@ -374,7 +374,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino) | |||
374 | qnx4_inode = qnx4_raw_inode(inode); | 374 | qnx4_inode = qnx4_raw_inode(inode); |
375 | inode->i_mode = 0; | 375 | inode->i_mode = 0; |
376 | 376 | ||
377 | QNX4DEBUG(("Reading inode : [%d]\n", ino)); | 377 | QNX4DEBUG((KERN_INFO "reading inode : [%d]\n", ino)); |
378 | if (!ino) { | 378 | if (!ino) { |
379 | printk(KERN_ERR "qnx4: bad inode number on dev %s: %lu is " | 379 | printk(KERN_ERR "qnx4: bad inode number on dev %s: %lu is " |
380 | "out of range\n", | 380 | "out of range\n", |
@@ -385,7 +385,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino) | |||
385 | block = ino / QNX4_INODES_PER_BLOCK; | 385 | block = ino / QNX4_INODES_PER_BLOCK; |
386 | 386 | ||
387 | if (!(bh = sb_bread(sb, block))) { | 387 | if (!(bh = sb_bread(sb, block))) { |
388 | printk("qnx4: major problem: unable to read inode from dev " | 388 | printk(KERN_ERR "qnx4: major problem: unable to read inode from dev " |
389 | "%s\n", sb->s_id); | 389 | "%s\n", sb->s_id); |
390 | iget_failed(inode); | 390 | iget_failed(inode); |
391 | return ERR_PTR(-EIO); | 391 | return ERR_PTR(-EIO); |
@@ -499,7 +499,7 @@ static int __init init_qnx4_fs(void) | |||
499 | return err; | 499 | return err; |
500 | } | 500 | } |
501 | 501 | ||
502 | printk("QNX4 filesystem 0.2.3 registered.\n"); | 502 | printk(KERN_INFO "QNX4 filesystem 0.2.3 registered.\n"); |
503 | return 0; | 503 | return 0; |
504 | } | 504 | } |
505 | 505 | ||
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c index ae1e7edbacd6..58703ebba879 100644 --- a/fs/qnx4/namei.c +++ b/fs/qnx4/namei.c | |||
@@ -30,7 +30,7 @@ static int qnx4_match(int len, const char *name, | |||
30 | int namelen, thislen; | 30 | int namelen, thislen; |
31 | 31 | ||
32 | if (bh == NULL) { | 32 | if (bh == NULL) { |
33 | printk("qnx4: matching unassigned buffer !\n"); | 33 | printk(KERN_WARNING "qnx4: matching unassigned buffer !\n"); |
34 | return 0; | 34 | return 0; |
35 | } | 35 | } |
36 | de = (struct qnx4_inode_entry *) (bh->b_data + *offset); | 36 | de = (struct qnx4_inode_entry *) (bh->b_data + *offset); |
@@ -66,7 +66,7 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir, | |||
66 | 66 | ||
67 | *res_dir = NULL; | 67 | *res_dir = NULL; |
68 | if (!dir->i_sb) { | 68 | if (!dir->i_sb) { |
69 | printk("qnx4: no superblock on dir.\n"); | 69 | printk(KERN_WARNING "qnx4: no superblock on dir.\n"); |
70 | return NULL; | 70 | return NULL; |
71 | } | 71 | } |
72 | bh = NULL; | 72 | bh = NULL; |
@@ -124,7 +124,7 @@ struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nam | |||
124 | foundinode = qnx4_iget(dir->i_sb, ino); | 124 | foundinode = qnx4_iget(dir->i_sb, ino); |
125 | if (IS_ERR(foundinode)) { | 125 | if (IS_ERR(foundinode)) { |
126 | unlock_kernel(); | 126 | unlock_kernel(); |
127 | QNX4DEBUG(("qnx4: lookup->iget -> error %ld\n", | 127 | QNX4DEBUG((KERN_ERR "qnx4: lookup->iget -> error %ld\n", |
128 | PTR_ERR(foundinode))); | 128 | PTR_ERR(foundinode))); |
129 | return ERR_CAST(foundinode); | 129 | return ERR_CAST(foundinode); |
130 | } | 130 | } |
diff --git a/fs/quota/Kconfig b/fs/quota/Kconfig index 8047e01ef46b..353e78a9ebee 100644 --- a/fs/quota/Kconfig +++ b/fs/quota/Kconfig | |||
@@ -17,7 +17,7 @@ config QUOTA | |||
17 | 17 | ||
18 | config QUOTA_NETLINK_INTERFACE | 18 | config QUOTA_NETLINK_INTERFACE |
19 | bool "Report quota messages through netlink interface" | 19 | bool "Report quota messages through netlink interface" |
20 | depends on QUOTA && NET | 20 | depends on QUOTACTL && NET |
21 | help | 21 | help |
22 | If you say Y here, quota warnings (about exceeding softlimit, reaching | 22 | If you say Y here, quota warnings (about exceeding softlimit, reaching |
23 | hardlimit, etc.) will be reported through netlink interface. If unsure, | 23 | hardlimit, etc.) will be reported through netlink interface. If unsure, |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 39b49c42a7ed..eb5a755718f6 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
@@ -77,10 +77,6 @@ | |||
77 | #include <linux/capability.h> | 77 | #include <linux/capability.h> |
78 | #include <linux/quotaops.h> | 78 | #include <linux/quotaops.h> |
79 | #include <linux/writeback.h> /* for inode_lock, oddly enough.. */ | 79 | #include <linux/writeback.h> /* for inode_lock, oddly enough.. */ |
80 | #ifdef CONFIG_QUOTA_NETLINK_INTERFACE | ||
81 | #include <net/netlink.h> | ||
82 | #include <net/genetlink.h> | ||
83 | #endif | ||
84 | 80 | ||
85 | #include <asm/uaccess.h> | 81 | #include <asm/uaccess.h> |
86 | 82 | ||
@@ -1071,73 +1067,6 @@ static void print_warning(struct dquot *dquot, const int warntype) | |||
1071 | } | 1067 | } |
1072 | #endif | 1068 | #endif |
1073 | 1069 | ||
1074 | #ifdef CONFIG_QUOTA_NETLINK_INTERFACE | ||
1075 | |||
1076 | /* Netlink family structure for quota */ | ||
1077 | static struct genl_family quota_genl_family = { | ||
1078 | .id = GENL_ID_GENERATE, | ||
1079 | .hdrsize = 0, | ||
1080 | .name = "VFS_DQUOT", | ||
1081 | .version = 1, | ||
1082 | .maxattr = QUOTA_NL_A_MAX, | ||
1083 | }; | ||
1084 | |||
1085 | /* Send warning to userspace about user which exceeded quota */ | ||
1086 | static void send_warning(const struct dquot *dquot, const char warntype) | ||
1087 | { | ||
1088 | static atomic_t seq; | ||
1089 | struct sk_buff *skb; | ||
1090 | void *msg_head; | ||
1091 | int ret; | ||
1092 | int msg_size = 4 * nla_total_size(sizeof(u32)) + | ||
1093 | 2 * nla_total_size(sizeof(u64)); | ||
1094 | |||
1095 | /* We have to allocate using GFP_NOFS as we are called from a | ||
1096 | * filesystem performing write and thus further recursion into | ||
1097 | * the fs to free some data could cause deadlocks. */ | ||
1098 | skb = genlmsg_new(msg_size, GFP_NOFS); | ||
1099 | if (!skb) { | ||
1100 | printk(KERN_ERR | ||
1101 | "VFS: Not enough memory to send quota warning.\n"); | ||
1102 | return; | ||
1103 | } | ||
1104 | msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), | ||
1105 | "a_genl_family, 0, QUOTA_NL_C_WARNING); | ||
1106 | if (!msg_head) { | ||
1107 | printk(KERN_ERR | ||
1108 | "VFS: Cannot store netlink header in quota warning.\n"); | ||
1109 | goto err_out; | ||
1110 | } | ||
1111 | ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, dquot->dq_type); | ||
1112 | if (ret) | ||
1113 | goto attr_err_out; | ||
1114 | ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, dquot->dq_id); | ||
1115 | if (ret) | ||
1116 | goto attr_err_out; | ||
1117 | ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype); | ||
1118 | if (ret) | ||
1119 | goto attr_err_out; | ||
1120 | ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, | ||
1121 | MAJOR(dquot->dq_sb->s_dev)); | ||
1122 | if (ret) | ||
1123 | goto attr_err_out; | ||
1124 | ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, | ||
1125 | MINOR(dquot->dq_sb->s_dev)); | ||
1126 | if (ret) | ||
1127 | goto attr_err_out; | ||
1128 | ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid()); | ||
1129 | if (ret) | ||
1130 | goto attr_err_out; | ||
1131 | genlmsg_end(skb, msg_head); | ||
1132 | |||
1133 | genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); | ||
1134 | return; | ||
1135 | attr_err_out: | ||
1136 | printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); | ||
1137 | err_out: | ||
1138 | kfree_skb(skb); | ||
1139 | } | ||
1140 | #endif | ||
1141 | /* | 1070 | /* |
1142 | * Write warnings to the console and send warning messages over netlink. | 1071 | * Write warnings to the console and send warning messages over netlink. |
1143 | * | 1072 | * |
@@ -1145,18 +1074,20 @@ err_out: | |||
1145 | */ | 1074 | */ |
1146 | static void flush_warnings(struct dquot *const *dquots, char *warntype) | 1075 | static void flush_warnings(struct dquot *const *dquots, char *warntype) |
1147 | { | 1076 | { |
1077 | struct dquot *dq; | ||
1148 | int i; | 1078 | int i; |
1149 | 1079 | ||
1150 | for (i = 0; i < MAXQUOTAS; i++) | 1080 | for (i = 0; i < MAXQUOTAS; i++) { |
1151 | if (dquots[i] && warntype[i] != QUOTA_NL_NOWARN && | 1081 | dq = dquots[i]; |
1152 | !warning_issued(dquots[i], warntype[i])) { | 1082 | if (dq && warntype[i] != QUOTA_NL_NOWARN && |
1083 | !warning_issued(dq, warntype[i])) { | ||
1153 | #ifdef CONFIG_PRINT_QUOTA_WARNING | 1084 | #ifdef CONFIG_PRINT_QUOTA_WARNING |
1154 | print_warning(dquots[i], warntype[i]); | 1085 | print_warning(dq, warntype[i]); |
1155 | #endif | ||
1156 | #ifdef CONFIG_QUOTA_NETLINK_INTERFACE | ||
1157 | send_warning(dquots[i], warntype[i]); | ||
1158 | #endif | 1086 | #endif |
1087 | quota_send_warning(dq->dq_type, dq->dq_id, | ||
1088 | dq->dq_sb->s_dev, warntype[i]); | ||
1159 | } | 1089 | } |
1090 | } | ||
1160 | } | 1091 | } |
1161 | 1092 | ||
1162 | static int ignore_hardlimit(struct dquot *dquot) | 1093 | static int ignore_hardlimit(struct dquot *dquot) |
@@ -2473,100 +2404,89 @@ const struct quotactl_ops vfs_quotactl_ops = { | |||
2473 | 2404 | ||
2474 | static ctl_table fs_dqstats_table[] = { | 2405 | static ctl_table fs_dqstats_table[] = { |
2475 | { | 2406 | { |
2476 | .ctl_name = FS_DQ_LOOKUPS, | ||
2477 | .procname = "lookups", | 2407 | .procname = "lookups", |
2478 | .data = &dqstats.lookups, | 2408 | .data = &dqstats.lookups, |
2479 | .maxlen = sizeof(int), | 2409 | .maxlen = sizeof(int), |
2480 | .mode = 0444, | 2410 | .mode = 0444, |
2481 | .proc_handler = &proc_dointvec, | 2411 | .proc_handler = proc_dointvec, |
2482 | }, | 2412 | }, |
2483 | { | 2413 | { |
2484 | .ctl_name = FS_DQ_DROPS, | ||
2485 | .procname = "drops", | 2414 | .procname = "drops", |
2486 | .data = &dqstats.drops, | 2415 | .data = &dqstats.drops, |
2487 | .maxlen = sizeof(int), | 2416 | .maxlen = sizeof(int), |
2488 | .mode = 0444, | 2417 | .mode = 0444, |
2489 | .proc_handler = &proc_dointvec, | 2418 | .proc_handler = proc_dointvec, |
2490 | }, | 2419 | }, |
2491 | { | 2420 | { |
2492 | .ctl_name = FS_DQ_READS, | ||
2493 | .procname = "reads", | 2421 | .procname = "reads", |
2494 | .data = &dqstats.reads, | 2422 | .data = &dqstats.reads, |
2495 | .maxlen = sizeof(int), | 2423 | .maxlen = sizeof(int), |
2496 | .mode = 0444, | 2424 | .mode = 0444, |
2497 | .proc_handler = &proc_dointvec, | 2425 | .proc_handler = proc_dointvec, |
2498 | }, | 2426 | }, |
2499 | { | 2427 | { |
2500 | .ctl_name = FS_DQ_WRITES, | ||
2501 | .procname = "writes", | 2428 | .procname = "writes", |
2502 | .data = &dqstats.writes, | 2429 | .data = &dqstats.writes, |
2503 | .maxlen = sizeof(int), | 2430 | .maxlen = sizeof(int), |
2504 | .mode = 0444, | 2431 | .mode = 0444, |
2505 | .proc_handler = &proc_dointvec, | 2432 | .proc_handler = proc_dointvec, |
2506 | }, | 2433 | }, |
2507 | { | 2434 | { |
2508 | .ctl_name = FS_DQ_CACHE_HITS, | ||
2509 | .procname = "cache_hits", | 2435 | .procname = "cache_hits", |
2510 | .data = &dqstats.cache_hits, | 2436 | .data = &dqstats.cache_hits, |
2511 | .maxlen = sizeof(int), | 2437 | .maxlen = sizeof(int), |
2512 | .mode = 0444, | 2438 | .mode = 0444, |
2513 | .proc_handler = &proc_dointvec, | 2439 | .proc_handler = proc_dointvec, |
2514 | }, | 2440 | }, |
2515 | { | 2441 | { |
2516 | .ctl_name = FS_DQ_ALLOCATED, | ||
2517 | .procname = "allocated_dquots", | 2442 | .procname = "allocated_dquots", |
2518 | .data = &dqstats.allocated_dquots, | 2443 | .data = &dqstats.allocated_dquots, |
2519 | .maxlen = sizeof(int), | 2444 | .maxlen = sizeof(int), |
2520 | .mode = 0444, | 2445 | .mode = 0444, |
2521 | .proc_handler = &proc_dointvec, | 2446 | .proc_handler = proc_dointvec, |
2522 | }, | 2447 | }, |
2523 | { | 2448 | { |
2524 | .ctl_name = FS_DQ_FREE, | ||
2525 | .procname = "free_dquots", | 2449 | .procname = "free_dquots", |
2526 | .data = &dqstats.free_dquots, | 2450 | .data = &dqstats.free_dquots, |
2527 | .maxlen = sizeof(int), | 2451 | .maxlen = sizeof(int), |
2528 | .mode = 0444, | 2452 | .mode = 0444, |
2529 | .proc_handler = &proc_dointvec, | 2453 | .proc_handler = proc_dointvec, |
2530 | }, | 2454 | }, |
2531 | { | 2455 | { |
2532 | .ctl_name = FS_DQ_SYNCS, | ||
2533 | .procname = "syncs", | 2456 | .procname = "syncs", |
2534 | .data = &dqstats.syncs, | 2457 | .data = &dqstats.syncs, |
2535 | .maxlen = sizeof(int), | 2458 | .maxlen = sizeof(int), |
2536 | .mode = 0444, | 2459 | .mode = 0444, |
2537 | .proc_handler = &proc_dointvec, | 2460 | .proc_handler = proc_dointvec, |
2538 | }, | 2461 | }, |
2539 | #ifdef CONFIG_PRINT_QUOTA_WARNING | 2462 | #ifdef CONFIG_PRINT_QUOTA_WARNING |
2540 | { | 2463 | { |
2541 | .ctl_name = FS_DQ_WARNINGS, | ||
2542 | .procname = "warnings", | 2464 | .procname = "warnings", |
2543 | .data = &flag_print_warnings, | 2465 | .data = &flag_print_warnings, |
2544 | .maxlen = sizeof(int), | 2466 | .maxlen = sizeof(int), |
2545 | .mode = 0644, | 2467 | .mode = 0644, |
2546 | .proc_handler = &proc_dointvec, | 2468 | .proc_handler = proc_dointvec, |
2547 | }, | 2469 | }, |
2548 | #endif | 2470 | #endif |
2549 | { .ctl_name = 0 }, | 2471 | { }, |
2550 | }; | 2472 | }; |
2551 | 2473 | ||
2552 | static ctl_table fs_table[] = { | 2474 | static ctl_table fs_table[] = { |
2553 | { | 2475 | { |
2554 | .ctl_name = FS_DQSTATS, | ||
2555 | .procname = "quota", | 2476 | .procname = "quota", |
2556 | .mode = 0555, | 2477 | .mode = 0555, |
2557 | .child = fs_dqstats_table, | 2478 | .child = fs_dqstats_table, |
2558 | }, | 2479 | }, |
2559 | { .ctl_name = 0 }, | 2480 | { }, |
2560 | }; | 2481 | }; |
2561 | 2482 | ||
2562 | static ctl_table sys_table[] = { | 2483 | static ctl_table sys_table[] = { |
2563 | { | 2484 | { |
2564 | .ctl_name = CTL_FS, | ||
2565 | .procname = "fs", | 2485 | .procname = "fs", |
2566 | .mode = 0555, | 2486 | .mode = 0555, |
2567 | .child = fs_table, | 2487 | .child = fs_table, |
2568 | }, | 2488 | }, |
2569 | { .ctl_name = 0 }, | 2489 | { }, |
2570 | }; | 2490 | }; |
2571 | 2491 | ||
2572 | static int __init dquot_init(void) | 2492 | static int __init dquot_init(void) |
@@ -2607,12 +2527,6 @@ static int __init dquot_init(void) | |||
2607 | 2527 | ||
2608 | register_shrinker(&dqcache_shrinker); | 2528 | register_shrinker(&dqcache_shrinker); |
2609 | 2529 | ||
2610 | #ifdef CONFIG_QUOTA_NETLINK_INTERFACE | ||
2611 | if (genl_register_family("a_genl_family) != 0) | ||
2612 | printk(KERN_ERR | ||
2613 | "VFS: Failed to create quota netlink interface.\n"); | ||
2614 | #endif | ||
2615 | |||
2616 | return 0; | 2530 | return 0; |
2617 | } | 2531 | } |
2618 | module_init(dquot_init); | 2532 | module_init(dquot_init); |
diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 95c5b42384b2..ee91e2756950 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/capability.h> | 18 | #include <linux/capability.h> |
19 | #include <linux/quotaops.h> | 19 | #include <linux/quotaops.h> |
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <net/netlink.h> | ||
22 | #include <net/genetlink.h> | ||
21 | 23 | ||
22 | /* Check validity of generic quotactl commands */ | 24 | /* Check validity of generic quotactl commands */ |
23 | static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, | 25 | static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, |
@@ -525,3 +527,94 @@ asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special, | |||
525 | return ret; | 527 | return ret; |
526 | } | 528 | } |
527 | #endif | 529 | #endif |
530 | |||
531 | |||
532 | #ifdef CONFIG_QUOTA_NETLINK_INTERFACE | ||
533 | |||
534 | /* Netlink family structure for quota */ | ||
535 | static struct genl_family quota_genl_family = { | ||
536 | .id = GENL_ID_GENERATE, | ||
537 | .hdrsize = 0, | ||
538 | .name = "VFS_DQUOT", | ||
539 | .version = 1, | ||
540 | .maxattr = QUOTA_NL_A_MAX, | ||
541 | }; | ||
542 | |||
543 | /** | ||
544 | * quota_send_warning - Send warning to userspace about exceeded quota | ||
545 | * @type: The quota type: USRQQUOTA, GRPQUOTA,... | ||
546 | * @id: The user or group id of the quota that was exceeded | ||
547 | * @dev: The device on which the fs is mounted (sb->s_dev) | ||
548 | * @warntype: The type of the warning: QUOTA_NL_... | ||
549 | * | ||
550 | * This can be used by filesystems (including those which don't use | ||
551 | * dquot) to send a message to userspace relating to quota limits. | ||
552 | * | ||
553 | */ | ||
554 | |||
555 | void quota_send_warning(short type, unsigned int id, dev_t dev, | ||
556 | const char warntype) | ||
557 | { | ||
558 | static atomic_t seq; | ||
559 | struct sk_buff *skb; | ||
560 | void *msg_head; | ||
561 | int ret; | ||
562 | int msg_size = 4 * nla_total_size(sizeof(u32)) + | ||
563 | 2 * nla_total_size(sizeof(u64)); | ||
564 | |||
565 | /* We have to allocate using GFP_NOFS as we are called from a | ||
566 | * filesystem performing write and thus further recursion into | ||
567 | * the fs to free some data could cause deadlocks. */ | ||
568 | skb = genlmsg_new(msg_size, GFP_NOFS); | ||
569 | if (!skb) { | ||
570 | printk(KERN_ERR | ||
571 | "VFS: Not enough memory to send quota warning.\n"); | ||
572 | return; | ||
573 | } | ||
574 | msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), | ||
575 | "a_genl_family, 0, QUOTA_NL_C_WARNING); | ||
576 | if (!msg_head) { | ||
577 | printk(KERN_ERR | ||
578 | "VFS: Cannot store netlink header in quota warning.\n"); | ||
579 | goto err_out; | ||
580 | } | ||
581 | ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type); | ||
582 | if (ret) | ||
583 | goto attr_err_out; | ||
584 | ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id); | ||
585 | if (ret) | ||
586 | goto attr_err_out; | ||
587 | ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype); | ||
588 | if (ret) | ||
589 | goto attr_err_out; | ||
590 | ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, MAJOR(dev)); | ||
591 | if (ret) | ||
592 | goto attr_err_out; | ||
593 | ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev)); | ||
594 | if (ret) | ||
595 | goto attr_err_out; | ||
596 | ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid()); | ||
597 | if (ret) | ||
598 | goto attr_err_out; | ||
599 | genlmsg_end(skb, msg_head); | ||
600 | |||
601 | genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); | ||
602 | return; | ||
603 | attr_err_out: | ||
604 | printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); | ||
605 | err_out: | ||
606 | kfree_skb(skb); | ||
607 | } | ||
608 | EXPORT_SYMBOL(quota_send_warning); | ||
609 | |||
610 | static int __init quota_init(void) | ||
611 | { | ||
612 | if (genl_register_family("a_genl_family) != 0) | ||
613 | printk(KERN_ERR | ||
614 | "VFS: Failed to create quota netlink interface.\n"); | ||
615 | return 0; | ||
616 | }; | ||
617 | |||
618 | module_init(quota_init); | ||
619 | #endif | ||
620 | |||
diff --git a/fs/read_write.c b/fs/read_write.c index 3ac28987f22a..b7f4a1f94d48 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -826,8 +826,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
826 | if (!(out_file->f_mode & FMODE_WRITE)) | 826 | if (!(out_file->f_mode & FMODE_WRITE)) |
827 | goto fput_out; | 827 | goto fput_out; |
828 | retval = -EINVAL; | 828 | retval = -EINVAL; |
829 | if (!out_file->f_op || !out_file->f_op->sendpage) | ||
830 | goto fput_out; | ||
831 | in_inode = in_file->f_path.dentry->d_inode; | 829 | in_inode = in_file->f_path.dentry->d_inode; |
832 | out_inode = out_file->f_path.dentry->d_inode; | 830 | out_inode = out_file->f_path.dentry->d_inode; |
833 | retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count); | 831 | retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count); |
diff --git a/fs/reiserfs/Makefile b/fs/reiserfs/Makefile index 7c5ab6330dd6..6a9e30c041dd 100644 --- a/fs/reiserfs/Makefile +++ b/fs/reiserfs/Makefile | |||
@@ -7,7 +7,7 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs.o | |||
7 | reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \ | 7 | reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \ |
8 | super.o prints.o objectid.o lbalance.o ibalance.o stree.o \ | 8 | super.o prints.o objectid.o lbalance.o ibalance.o stree.o \ |
9 | hashes.o tail_conversion.o journal.o resize.o \ | 9 | hashes.o tail_conversion.o journal.o resize.o \ |
10 | item_ops.o ioctl.o procfs.o xattr.o | 10 | item_ops.o ioctl.o procfs.o xattr.o lock.o |
11 | 11 | ||
12 | ifeq ($(CONFIG_REISERFS_FS_XATTR),y) | 12 | ifeq ($(CONFIG_REISERFS_FS_XATTR),y) |
13 | reiserfs-objs += xattr_user.o xattr_trusted.o | 13 | reiserfs-objs += xattr_user.o xattr_trusted.o |
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index e716161ab325..685495707181 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c | |||
@@ -1249,14 +1249,18 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, | |||
1249 | else if (bitmap == 0) | 1249 | else if (bitmap == 0) |
1250 | block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1; | 1250 | block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1; |
1251 | 1251 | ||
1252 | reiserfs_write_unlock(sb); | ||
1252 | bh = sb_bread(sb, block); | 1253 | bh = sb_bread(sb, block); |
1254 | reiserfs_write_lock(sb); | ||
1253 | if (bh == NULL) | 1255 | if (bh == NULL) |
1254 | reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) " | 1256 | reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) " |
1255 | "reading failed", __func__, block); | 1257 | "reading failed", __func__, block); |
1256 | else { | 1258 | else { |
1257 | if (buffer_locked(bh)) { | 1259 | if (buffer_locked(bh)) { |
1258 | PROC_INFO_INC(sb, scan_bitmap.wait); | 1260 | PROC_INFO_INC(sb, scan_bitmap.wait); |
1261 | reiserfs_write_unlock(sb); | ||
1259 | __wait_on_buffer(bh); | 1262 | __wait_on_buffer(bh); |
1263 | reiserfs_write_lock(sb); | ||
1260 | } | 1264 | } |
1261 | BUG_ON(!buffer_uptodate(bh)); | 1265 | BUG_ON(!buffer_uptodate(bh)); |
1262 | BUG_ON(atomic_read(&bh->b_count) == 0); | 1266 | BUG_ON(atomic_read(&bh->b_count) == 0); |
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index 6d2668fdc384..c094f58c7448 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c | |||
@@ -20,7 +20,7 @@ const struct file_operations reiserfs_dir_operations = { | |||
20 | .read = generic_read_dir, | 20 | .read = generic_read_dir, |
21 | .readdir = reiserfs_readdir, | 21 | .readdir = reiserfs_readdir, |
22 | .fsync = reiserfs_dir_fsync, | 22 | .fsync = reiserfs_dir_fsync, |
23 | .ioctl = reiserfs_ioctl, | 23 | .unlocked_ioctl = reiserfs_ioctl, |
24 | #ifdef CONFIG_COMPAT | 24 | #ifdef CONFIG_COMPAT |
25 | .compat_ioctl = reiserfs_compat_ioctl, | 25 | .compat_ioctl = reiserfs_compat_ioctl, |
26 | #endif | 26 | #endif |
@@ -174,14 +174,22 @@ int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent, | |||
174 | // user space buffer is swapped out. At that time | 174 | // user space buffer is swapped out. At that time |
175 | // entry can move to somewhere else | 175 | // entry can move to somewhere else |
176 | memcpy(local_buf, d_name, d_reclen); | 176 | memcpy(local_buf, d_name, d_reclen); |
177 | |||
178 | /* | ||
179 | * Since filldir might sleep, we can release | ||
180 | * the write lock here for other waiters | ||
181 | */ | ||
182 | reiserfs_write_unlock(inode->i_sb); | ||
177 | if (filldir | 183 | if (filldir |
178 | (dirent, local_buf, d_reclen, d_off, d_ino, | 184 | (dirent, local_buf, d_reclen, d_off, d_ino, |
179 | DT_UNKNOWN) < 0) { | 185 | DT_UNKNOWN) < 0) { |
186 | reiserfs_write_lock(inode->i_sb); | ||
180 | if (local_buf != small_buf) { | 187 | if (local_buf != small_buf) { |
181 | kfree(local_buf); | 188 | kfree(local_buf); |
182 | } | 189 | } |
183 | goto end; | 190 | goto end; |
184 | } | 191 | } |
192 | reiserfs_write_lock(inode->i_sb); | ||
185 | if (local_buf != small_buf) { | 193 | if (local_buf != small_buf) { |
186 | kfree(local_buf); | 194 | kfree(local_buf); |
187 | } | 195 | } |
diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c index 128d3f7c8aa5..60c080440661 100644 --- a/fs/reiserfs/do_balan.c +++ b/fs/reiserfs/do_balan.c | |||
@@ -21,14 +21,6 @@ | |||
21 | #include <linux/buffer_head.h> | 21 | #include <linux/buffer_head.h> |
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | 23 | ||
24 | #ifdef CONFIG_REISERFS_CHECK | ||
25 | |||
26 | struct tree_balance *cur_tb = NULL; /* detects whether more than one | ||
27 | copy of tb exists as a means | ||
28 | of checking whether schedule | ||
29 | is interrupting do_balance */ | ||
30 | #endif | ||
31 | |||
32 | static inline void buffer_info_init_left(struct tree_balance *tb, | 24 | static inline void buffer_info_init_left(struct tree_balance *tb, |
33 | struct buffer_info *bi) | 25 | struct buffer_info *bi) |
34 | { | 26 | { |
@@ -1840,11 +1832,12 @@ static int check_before_balancing(struct tree_balance *tb) | |||
1840 | { | 1832 | { |
1841 | int retval = 0; | 1833 | int retval = 0; |
1842 | 1834 | ||
1843 | if (cur_tb) { | 1835 | if (REISERFS_SB(tb->tb_sb)->cur_tb) { |
1844 | reiserfs_panic(tb->tb_sb, "vs-12335", "suspect that schedule " | 1836 | reiserfs_panic(tb->tb_sb, "vs-12335", "suspect that schedule " |
1845 | "occurred based on cur_tb not being null at " | 1837 | "occurred based on cur_tb not being null at " |
1846 | "this point in code. do_balance cannot properly " | 1838 | "this point in code. do_balance cannot properly " |
1847 | "handle schedule occurring while it runs."); | 1839 | "handle concurrent tree accesses on a same " |
1840 | "mount point."); | ||
1848 | } | 1841 | } |
1849 | 1842 | ||
1850 | /* double check that buffers that we will modify are unlocked. (fix_nodes should already have | 1843 | /* double check that buffers that we will modify are unlocked. (fix_nodes should already have |
@@ -1986,7 +1979,7 @@ static inline void do_balance_starts(struct tree_balance *tb) | |||
1986 | "check");*/ | 1979 | "check");*/ |
1987 | RFALSE(check_before_balancing(tb), "PAP-12340: locked buffers in TB"); | 1980 | RFALSE(check_before_balancing(tb), "PAP-12340: locked buffers in TB"); |
1988 | #ifdef CONFIG_REISERFS_CHECK | 1981 | #ifdef CONFIG_REISERFS_CHECK |
1989 | cur_tb = tb; | 1982 | REISERFS_SB(tb->tb_sb)->cur_tb = tb; |
1990 | #endif | 1983 | #endif |
1991 | } | 1984 | } |
1992 | 1985 | ||
@@ -1996,7 +1989,7 @@ static inline void do_balance_completed(struct tree_balance *tb) | |||
1996 | #ifdef CONFIG_REISERFS_CHECK | 1989 | #ifdef CONFIG_REISERFS_CHECK |
1997 | check_leaf_level(tb); | 1990 | check_leaf_level(tb); |
1998 | check_internal_levels(tb); | 1991 | check_internal_levels(tb); |
1999 | cur_tb = NULL; | 1992 | REISERFS_SB(tb->tb_sb)->cur_tb = NULL; |
2000 | #endif | 1993 | #endif |
2001 | 1994 | ||
2002 | /* reiserfs_free_block is no longer schedule safe. So, we need to | 1995 | /* reiserfs_free_block is no longer schedule safe. So, we need to |
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 9f436668b7f8..da2dba082e2d 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c | |||
@@ -284,7 +284,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t | |||
284 | const struct file_operations reiserfs_file_operations = { | 284 | const struct file_operations reiserfs_file_operations = { |
285 | .read = do_sync_read, | 285 | .read = do_sync_read, |
286 | .write = reiserfs_file_write, | 286 | .write = reiserfs_file_write, |
287 | .ioctl = reiserfs_ioctl, | 287 | .unlocked_ioctl = reiserfs_ioctl, |
288 | #ifdef CONFIG_COMPAT | 288 | #ifdef CONFIG_COMPAT |
289 | .compat_ioctl = reiserfs_compat_ioctl, | 289 | .compat_ioctl = reiserfs_compat_ioctl, |
290 | #endif | 290 | #endif |
diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c index 5e5a4e6fbaf8..6591cb21edf6 100644 --- a/fs/reiserfs/fix_node.c +++ b/fs/reiserfs/fix_node.c | |||
@@ -563,9 +563,6 @@ static int get_num_ver(int mode, struct tree_balance *tb, int h, | |||
563 | return needed_nodes; | 563 | return needed_nodes; |
564 | } | 564 | } |
565 | 565 | ||
566 | #ifdef CONFIG_REISERFS_CHECK | ||
567 | extern struct tree_balance *cur_tb; | ||
568 | #endif | ||
569 | 566 | ||
570 | /* Set parameters for balancing. | 567 | /* Set parameters for balancing. |
571 | * Performs write of results of analysis of balancing into structure tb, | 568 | * Performs write of results of analysis of balancing into structure tb, |
@@ -834,7 +831,7 @@ static int get_empty_nodes(struct tree_balance *tb, int h) | |||
834 | RFALSE(buffer_dirty(new_bh) || | 831 | RFALSE(buffer_dirty(new_bh) || |
835 | buffer_journaled(new_bh) || | 832 | buffer_journaled(new_bh) || |
836 | buffer_journal_dirty(new_bh), | 833 | buffer_journal_dirty(new_bh), |
837 | "PAP-8140: journlaled or dirty buffer %b for the new block", | 834 | "PAP-8140: journaled or dirty buffer %b for the new block", |
838 | new_bh); | 835 | new_bh); |
839 | 836 | ||
840 | /* Put empty buffers into the array. */ | 837 | /* Put empty buffers into the array. */ |
@@ -1022,7 +1019,11 @@ static int get_far_parent(struct tree_balance *tb, | |||
1022 | /* Check whether the common parent is locked. */ | 1019 | /* Check whether the common parent is locked. */ |
1023 | 1020 | ||
1024 | if (buffer_locked(*pcom_father)) { | 1021 | if (buffer_locked(*pcom_father)) { |
1022 | |||
1023 | /* Release the write lock while the buffer is busy */ | ||
1024 | reiserfs_write_unlock(tb->tb_sb); | ||
1025 | __wait_on_buffer(*pcom_father); | 1025 | __wait_on_buffer(*pcom_father); |
1026 | reiserfs_write_lock(tb->tb_sb); | ||
1026 | if (FILESYSTEM_CHANGED_TB(tb)) { | 1027 | if (FILESYSTEM_CHANGED_TB(tb)) { |
1027 | brelse(*pcom_father); | 1028 | brelse(*pcom_father); |
1028 | return REPEAT_SEARCH; | 1029 | return REPEAT_SEARCH; |
@@ -1927,7 +1928,9 @@ static int get_direct_parent(struct tree_balance *tb, int h) | |||
1927 | return REPEAT_SEARCH; | 1928 | return REPEAT_SEARCH; |
1928 | 1929 | ||
1929 | if (buffer_locked(bh)) { | 1930 | if (buffer_locked(bh)) { |
1931 | reiserfs_write_unlock(tb->tb_sb); | ||
1930 | __wait_on_buffer(bh); | 1932 | __wait_on_buffer(bh); |
1933 | reiserfs_write_lock(tb->tb_sb); | ||
1931 | if (FILESYSTEM_CHANGED_TB(tb)) | 1934 | if (FILESYSTEM_CHANGED_TB(tb)) |
1932 | return REPEAT_SEARCH; | 1935 | return REPEAT_SEARCH; |
1933 | } | 1936 | } |
@@ -1965,7 +1968,9 @@ static int get_neighbors(struct tree_balance *tb, int h) | |||
1965 | tb->FL[h]) ? tb->lkey[h] : B_NR_ITEMS(tb-> | 1968 | tb->FL[h]) ? tb->lkey[h] : B_NR_ITEMS(tb-> |
1966 | FL[h]); | 1969 | FL[h]); |
1967 | son_number = B_N_CHILD_NUM(tb->FL[h], child_position); | 1970 | son_number = B_N_CHILD_NUM(tb->FL[h], child_position); |
1971 | reiserfs_write_unlock(sb); | ||
1968 | bh = sb_bread(sb, son_number); | 1972 | bh = sb_bread(sb, son_number); |
1973 | reiserfs_write_lock(sb); | ||
1969 | if (!bh) | 1974 | if (!bh) |
1970 | return IO_ERROR; | 1975 | return IO_ERROR; |
1971 | if (FILESYSTEM_CHANGED_TB(tb)) { | 1976 | if (FILESYSTEM_CHANGED_TB(tb)) { |
@@ -2003,7 +2008,9 @@ static int get_neighbors(struct tree_balance *tb, int h) | |||
2003 | child_position = | 2008 | child_position = |
2004 | (bh == tb->FR[h]) ? tb->rkey[h] + 1 : 0; | 2009 | (bh == tb->FR[h]) ? tb->rkey[h] + 1 : 0; |
2005 | son_number = B_N_CHILD_NUM(tb->FR[h], child_position); | 2010 | son_number = B_N_CHILD_NUM(tb->FR[h], child_position); |
2011 | reiserfs_write_unlock(sb); | ||
2006 | bh = sb_bread(sb, son_number); | 2012 | bh = sb_bread(sb, son_number); |
2013 | reiserfs_write_lock(sb); | ||
2007 | if (!bh) | 2014 | if (!bh) |
2008 | return IO_ERROR; | 2015 | return IO_ERROR; |
2009 | if (FILESYSTEM_CHANGED_TB(tb)) { | 2016 | if (FILESYSTEM_CHANGED_TB(tb)) { |
@@ -2278,7 +2285,9 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *tb) | |||
2278 | REPEAT_SEARCH : CARRY_ON; | 2285 | REPEAT_SEARCH : CARRY_ON; |
2279 | } | 2286 | } |
2280 | #endif | 2287 | #endif |
2288 | reiserfs_write_unlock(tb->tb_sb); | ||
2281 | __wait_on_buffer(locked); | 2289 | __wait_on_buffer(locked); |
2290 | reiserfs_write_lock(tb->tb_sb); | ||
2282 | if (FILESYSTEM_CHANGED_TB(tb)) | 2291 | if (FILESYSTEM_CHANGED_TB(tb)) |
2283 | return REPEAT_SEARCH; | 2292 | return REPEAT_SEARCH; |
2284 | } | 2293 | } |
@@ -2349,12 +2358,14 @@ int fix_nodes(int op_mode, struct tree_balance *tb, | |||
2349 | 2358 | ||
2350 | /* if it possible in indirect_to_direct conversion */ | 2359 | /* if it possible in indirect_to_direct conversion */ |
2351 | if (buffer_locked(tbS0)) { | 2360 | if (buffer_locked(tbS0)) { |
2361 | reiserfs_write_unlock(tb->tb_sb); | ||
2352 | __wait_on_buffer(tbS0); | 2362 | __wait_on_buffer(tbS0); |
2363 | reiserfs_write_lock(tb->tb_sb); | ||
2353 | if (FILESYSTEM_CHANGED_TB(tb)) | 2364 | if (FILESYSTEM_CHANGED_TB(tb)) |
2354 | return REPEAT_SEARCH; | 2365 | return REPEAT_SEARCH; |
2355 | } | 2366 | } |
2356 | #ifdef CONFIG_REISERFS_CHECK | 2367 | #ifdef CONFIG_REISERFS_CHECK |
2357 | if (cur_tb) { | 2368 | if (REISERFS_SB(tb->tb_sb)->cur_tb) { |
2358 | print_cur_tb("fix_nodes"); | 2369 | print_cur_tb("fix_nodes"); |
2359 | reiserfs_panic(tb->tb_sb, "PAP-8305", | 2370 | reiserfs_panic(tb->tb_sb, "PAP-8305", |
2360 | "there is pending do_balance"); | 2371 | "there is pending do_balance"); |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index a14d6cd9eeda..3a28e7751b3c 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -251,7 +251,6 @@ static int _get_block_create_0(struct inode *inode, sector_t block, | |||
251 | struct cpu_key key; | 251 | struct cpu_key key; |
252 | struct buffer_head *bh; | 252 | struct buffer_head *bh; |
253 | struct item_head *ih, tmp_ih; | 253 | struct item_head *ih, tmp_ih; |
254 | int fs_gen; | ||
255 | b_blocknr_t blocknr; | 254 | b_blocknr_t blocknr; |
256 | char *p = NULL; | 255 | char *p = NULL; |
257 | int chars; | 256 | int chars; |
@@ -265,7 +264,6 @@ static int _get_block_create_0(struct inode *inode, sector_t block, | |||
265 | (loff_t) block * inode->i_sb->s_blocksize + 1, TYPE_ANY, | 264 | (loff_t) block * inode->i_sb->s_blocksize + 1, TYPE_ANY, |
266 | 3); | 265 | 3); |
267 | 266 | ||
268 | research: | ||
269 | result = search_for_position_by_key(inode->i_sb, &key, &path); | 267 | result = search_for_position_by_key(inode->i_sb, &key, &path); |
270 | if (result != POSITION_FOUND) { | 268 | if (result != POSITION_FOUND) { |
271 | pathrelse(&path); | 269 | pathrelse(&path); |
@@ -340,7 +338,6 @@ static int _get_block_create_0(struct inode *inode, sector_t block, | |||
340 | } | 338 | } |
341 | // read file tail into part of page | 339 | // read file tail into part of page |
342 | offset = (cpu_key_k_offset(&key) - 1) & (PAGE_CACHE_SIZE - 1); | 340 | offset = (cpu_key_k_offset(&key) - 1) & (PAGE_CACHE_SIZE - 1); |
343 | fs_gen = get_generation(inode->i_sb); | ||
344 | copy_item_head(&tmp_ih, ih); | 341 | copy_item_head(&tmp_ih, ih); |
345 | 342 | ||
346 | /* we only want to kmap if we are reading the tail into the page. | 343 | /* we only want to kmap if we are reading the tail into the page. |
@@ -348,13 +345,9 @@ static int _get_block_create_0(struct inode *inode, sector_t block, | |||
348 | ** sure we need to. But, this means the item might move if | 345 | ** sure we need to. But, this means the item might move if |
349 | ** kmap schedules | 346 | ** kmap schedules |
350 | */ | 347 | */ |
351 | if (!p) { | 348 | if (!p) |
352 | p = (char *)kmap(bh_result->b_page); | 349 | p = (char *)kmap(bh_result->b_page); |
353 | if (fs_changed(fs_gen, inode->i_sb) | 350 | |
354 | && item_moved(&tmp_ih, &path)) { | ||
355 | goto research; | ||
356 | } | ||
357 | } | ||
358 | p += offset; | 351 | p += offset; |
359 | memset(p, 0, inode->i_sb->s_blocksize); | 352 | memset(p, 0, inode->i_sb->s_blocksize); |
360 | do { | 353 | do { |
@@ -489,10 +482,14 @@ static int reiserfs_get_blocks_direct_io(struct inode *inode, | |||
489 | disappeared */ | 482 | disappeared */ |
490 | if (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) { | 483 | if (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) { |
491 | int err; | 484 | int err; |
492 | lock_kernel(); | 485 | |
486 | reiserfs_write_lock(inode->i_sb); | ||
487 | |||
493 | err = reiserfs_commit_for_inode(inode); | 488 | err = reiserfs_commit_for_inode(inode); |
494 | REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; | 489 | REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; |
495 | unlock_kernel(); | 490 | |
491 | reiserfs_write_unlock(inode->i_sb); | ||
492 | |||
496 | if (err < 0) | 493 | if (err < 0) |
497 | ret = err; | 494 | ret = err; |
498 | } | 495 | } |
@@ -601,6 +598,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block, | |||
601 | __le32 *item; | 598 | __le32 *item; |
602 | int done; | 599 | int done; |
603 | int fs_gen; | 600 | int fs_gen; |
601 | int lock_depth; | ||
604 | struct reiserfs_transaction_handle *th = NULL; | 602 | struct reiserfs_transaction_handle *th = NULL; |
605 | /* space reserved in transaction batch: | 603 | /* space reserved in transaction batch: |
606 | . 3 balancings in direct->indirect conversion | 604 | . 3 balancings in direct->indirect conversion |
@@ -616,12 +614,11 @@ int reiserfs_get_block(struct inode *inode, sector_t block, | |||
616 | loff_t new_offset = | 614 | loff_t new_offset = |
617 | (((loff_t) block) << inode->i_sb->s_blocksize_bits) + 1; | 615 | (((loff_t) block) << inode->i_sb->s_blocksize_bits) + 1; |
618 | 616 | ||
619 | /* bad.... */ | 617 | lock_depth = reiserfs_write_lock_once(inode->i_sb); |
620 | reiserfs_write_lock(inode->i_sb); | ||
621 | version = get_inode_item_key_version(inode); | 618 | version = get_inode_item_key_version(inode); |
622 | 619 | ||
623 | if (!file_capable(inode, block)) { | 620 | if (!file_capable(inode, block)) { |
624 | reiserfs_write_unlock(inode->i_sb); | 621 | reiserfs_write_unlock_once(inode->i_sb, lock_depth); |
625 | return -EFBIG; | 622 | return -EFBIG; |
626 | } | 623 | } |
627 | 624 | ||
@@ -633,7 +630,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block, | |||
633 | /* find number of block-th logical block of the file */ | 630 | /* find number of block-th logical block of the file */ |
634 | ret = _get_block_create_0(inode, block, bh_result, | 631 | ret = _get_block_create_0(inode, block, bh_result, |
635 | create | GET_BLOCK_READ_DIRECT); | 632 | create | GET_BLOCK_READ_DIRECT); |
636 | reiserfs_write_unlock(inode->i_sb); | 633 | reiserfs_write_unlock_once(inode->i_sb, lock_depth); |
637 | return ret; | 634 | return ret; |
638 | } | 635 | } |
639 | /* | 636 | /* |
@@ -751,7 +748,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block, | |||
751 | if (!dangle && th) | 748 | if (!dangle && th) |
752 | retval = reiserfs_end_persistent_transaction(th); | 749 | retval = reiserfs_end_persistent_transaction(th); |
753 | 750 | ||
754 | reiserfs_write_unlock(inode->i_sb); | 751 | reiserfs_write_unlock_once(inode->i_sb, lock_depth); |
755 | 752 | ||
756 | /* the item was found, so new blocks were not added to the file | 753 | /* the item was found, so new blocks were not added to the file |
757 | ** there is no need to make sure the inode is updated with this | 754 | ** there is no need to make sure the inode is updated with this |
@@ -935,7 +932,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block, | |||
935 | if (blocks_needed == 1) { | 932 | if (blocks_needed == 1) { |
936 | un = &unf_single; | 933 | un = &unf_single; |
937 | } else { | 934 | } else { |
938 | un = kzalloc(min(blocks_needed, max_to_insert) * UNFM_P_SIZE, GFP_ATOMIC); // We need to avoid scheduling. | 935 | un = kzalloc(min(blocks_needed, max_to_insert) * UNFM_P_SIZE, GFP_NOFS); |
939 | if (!un) { | 936 | if (!un) { |
940 | un = &unf_single; | 937 | un = &unf_single; |
941 | blocks_needed = 1; | 938 | blocks_needed = 1; |
@@ -997,10 +994,16 @@ int reiserfs_get_block(struct inode *inode, sector_t block, | |||
997 | if (retval) | 994 | if (retval) |
998 | goto failure; | 995 | goto failure; |
999 | } | 996 | } |
1000 | /* inserting indirect pointers for a hole can take a | 997 | /* |
1001 | ** long time. reschedule if needed | 998 | * inserting indirect pointers for a hole can take a |
999 | * long time. reschedule if needed and also release the write | ||
1000 | * lock for others. | ||
1002 | */ | 1001 | */ |
1003 | cond_resched(); | 1002 | if (need_resched()) { |
1003 | reiserfs_write_unlock_once(inode->i_sb, lock_depth); | ||
1004 | schedule(); | ||
1005 | lock_depth = reiserfs_write_lock_once(inode->i_sb); | ||
1006 | } | ||
1004 | 1007 | ||
1005 | retval = search_for_position_by_key(inode->i_sb, &key, &path); | 1008 | retval = search_for_position_by_key(inode->i_sb, &key, &path); |
1006 | if (retval == IO_ERROR) { | 1009 | if (retval == IO_ERROR) { |
@@ -1035,7 +1038,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block, | |||
1035 | retval = err; | 1038 | retval = err; |
1036 | } | 1039 | } |
1037 | 1040 | ||
1038 | reiserfs_write_unlock(inode->i_sb); | 1041 | reiserfs_write_unlock_once(inode->i_sb, lock_depth); |
1039 | reiserfs_check_path(&path); | 1042 | reiserfs_check_path(&path); |
1040 | return retval; | 1043 | return retval; |
1041 | } | 1044 | } |
@@ -2072,8 +2075,9 @@ int reiserfs_truncate_file(struct inode *inode, int update_timestamps) | |||
2072 | int error; | 2075 | int error; |
2073 | struct buffer_head *bh = NULL; | 2076 | struct buffer_head *bh = NULL; |
2074 | int err2; | 2077 | int err2; |
2078 | int lock_depth; | ||
2075 | 2079 | ||
2076 | reiserfs_write_lock(inode->i_sb); | 2080 | lock_depth = reiserfs_write_lock_once(inode->i_sb); |
2077 | 2081 | ||
2078 | if (inode->i_size > 0) { | 2082 | if (inode->i_size > 0) { |
2079 | error = grab_tail_page(inode, &page, &bh); | 2083 | error = grab_tail_page(inode, &page, &bh); |
@@ -2142,14 +2146,17 @@ int reiserfs_truncate_file(struct inode *inode, int update_timestamps) | |||
2142 | page_cache_release(page); | 2146 | page_cache_release(page); |
2143 | } | 2147 | } |
2144 | 2148 | ||
2145 | reiserfs_write_unlock(inode->i_sb); | 2149 | reiserfs_write_unlock_once(inode->i_sb, lock_depth); |
2150 | |||
2146 | return 0; | 2151 | return 0; |
2147 | out: | 2152 | out: |
2148 | if (page) { | 2153 | if (page) { |
2149 | unlock_page(page); | 2154 | unlock_page(page); |
2150 | page_cache_release(page); | 2155 | page_cache_release(page); |
2151 | } | 2156 | } |
2152 | reiserfs_write_unlock(inode->i_sb); | 2157 | |
2158 | reiserfs_write_unlock_once(inode->i_sb, lock_depth); | ||
2159 | |||
2153 | return error; | 2160 | return error; |
2154 | } | 2161 | } |
2155 | 2162 | ||
@@ -2608,7 +2615,10 @@ int reiserfs_prepare_write(struct file *f, struct page *page, | |||
2608 | int ret; | 2615 | int ret; |
2609 | int old_ref = 0; | 2616 | int old_ref = 0; |
2610 | 2617 | ||
2618 | reiserfs_write_unlock(inode->i_sb); | ||
2611 | reiserfs_wait_on_write_block(inode->i_sb); | 2619 | reiserfs_wait_on_write_block(inode->i_sb); |
2620 | reiserfs_write_lock(inode->i_sb); | ||
2621 | |||
2612 | fix_tail_page_for_writing(page); | 2622 | fix_tail_page_for_writing(page); |
2613 | if (reiserfs_transaction_running(inode->i_sb)) { | 2623 | if (reiserfs_transaction_running(inode->i_sb)) { |
2614 | struct reiserfs_transaction_handle *th; | 2624 | struct reiserfs_transaction_handle *th; |
@@ -2664,6 +2674,8 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping, | |||
2664 | int update_sd = 0; | 2674 | int update_sd = 0; |
2665 | struct reiserfs_transaction_handle *th; | 2675 | struct reiserfs_transaction_handle *th; |
2666 | unsigned start; | 2676 | unsigned start; |
2677 | int lock_depth = 0; | ||
2678 | bool locked = false; | ||
2667 | 2679 | ||
2668 | if ((unsigned long)fsdata & AOP_FLAG_CONT_EXPAND) | 2680 | if ((unsigned long)fsdata & AOP_FLAG_CONT_EXPAND) |
2669 | pos ++; | 2681 | pos ++; |
@@ -2690,9 +2702,11 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping, | |||
2690 | ** to do the i_size updates here. | 2702 | ** to do the i_size updates here. |
2691 | */ | 2703 | */ |
2692 | pos += copied; | 2704 | pos += copied; |
2705 | |||
2693 | if (pos > inode->i_size) { | 2706 | if (pos > inode->i_size) { |
2694 | struct reiserfs_transaction_handle myth; | 2707 | struct reiserfs_transaction_handle myth; |
2695 | reiserfs_write_lock(inode->i_sb); | 2708 | lock_depth = reiserfs_write_lock_once(inode->i_sb); |
2709 | locked = true; | ||
2696 | /* If the file have grown beyond the border where it | 2710 | /* If the file have grown beyond the border where it |
2697 | can have a tail, unmark it as needing a tail | 2711 | can have a tail, unmark it as needing a tail |
2698 | packing */ | 2712 | packing */ |
@@ -2703,10 +2717,9 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping, | |||
2703 | REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; | 2717 | REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; |
2704 | 2718 | ||
2705 | ret = journal_begin(&myth, inode->i_sb, 1); | 2719 | ret = journal_begin(&myth, inode->i_sb, 1); |
2706 | if (ret) { | 2720 | if (ret) |
2707 | reiserfs_write_unlock(inode->i_sb); | ||
2708 | goto journal_error; | 2721 | goto journal_error; |
2709 | } | 2722 | |
2710 | reiserfs_update_inode_transaction(inode); | 2723 | reiserfs_update_inode_transaction(inode); |
2711 | inode->i_size = pos; | 2724 | inode->i_size = pos; |
2712 | /* | 2725 | /* |
@@ -2718,34 +2731,36 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping, | |||
2718 | reiserfs_update_sd(&myth, inode); | 2731 | reiserfs_update_sd(&myth, inode); |
2719 | update_sd = 1; | 2732 | update_sd = 1; |
2720 | ret = journal_end(&myth, inode->i_sb, 1); | 2733 | ret = journal_end(&myth, inode->i_sb, 1); |
2721 | reiserfs_write_unlock(inode->i_sb); | ||
2722 | if (ret) | 2734 | if (ret) |
2723 | goto journal_error; | 2735 | goto journal_error; |
2724 | } | 2736 | } |
2725 | if (th) { | 2737 | if (th) { |
2726 | reiserfs_write_lock(inode->i_sb); | 2738 | if (!locked) { |
2739 | lock_depth = reiserfs_write_lock_once(inode->i_sb); | ||
2740 | locked = true; | ||
2741 | } | ||
2727 | if (!update_sd) | 2742 | if (!update_sd) |
2728 | mark_inode_dirty(inode); | 2743 | mark_inode_dirty(inode); |
2729 | ret = reiserfs_end_persistent_transaction(th); | 2744 | ret = reiserfs_end_persistent_transaction(th); |
2730 | reiserfs_write_unlock(inode->i_sb); | ||
2731 | if (ret) | 2745 | if (ret) |
2732 | goto out; | 2746 | goto out; |
2733 | } | 2747 | } |
2734 | 2748 | ||
2735 | out: | 2749 | out: |
2750 | if (locked) | ||
2751 | reiserfs_write_unlock_once(inode->i_sb, lock_depth); | ||
2736 | unlock_page(page); | 2752 | unlock_page(page); |
2737 | page_cache_release(page); | 2753 | page_cache_release(page); |
2738 | return ret == 0 ? copied : ret; | 2754 | return ret == 0 ? copied : ret; |
2739 | 2755 | ||
2740 | journal_error: | 2756 | journal_error: |
2757 | reiserfs_write_unlock_once(inode->i_sb, lock_depth); | ||
2758 | locked = false; | ||
2741 | if (th) { | 2759 | if (th) { |
2742 | reiserfs_write_lock(inode->i_sb); | ||
2743 | if (!update_sd) | 2760 | if (!update_sd) |
2744 | reiserfs_update_sd(th, inode); | 2761 | reiserfs_update_sd(th, inode); |
2745 | ret = reiserfs_end_persistent_transaction(th); | 2762 | ret = reiserfs_end_persistent_transaction(th); |
2746 | reiserfs_write_unlock(inode->i_sb); | ||
2747 | } | 2763 | } |
2748 | |||
2749 | goto out; | 2764 | goto out; |
2750 | } | 2765 | } |
2751 | 2766 | ||
@@ -2758,7 +2773,10 @@ int reiserfs_commit_write(struct file *f, struct page *page, | |||
2758 | int update_sd = 0; | 2773 | int update_sd = 0; |
2759 | struct reiserfs_transaction_handle *th = NULL; | 2774 | struct reiserfs_transaction_handle *th = NULL; |
2760 | 2775 | ||
2776 | reiserfs_write_unlock(inode->i_sb); | ||
2761 | reiserfs_wait_on_write_block(inode->i_sb); | 2777 | reiserfs_wait_on_write_block(inode->i_sb); |
2778 | reiserfs_write_lock(inode->i_sb); | ||
2779 | |||
2762 | if (reiserfs_transaction_running(inode->i_sb)) { | 2780 | if (reiserfs_transaction_running(inode->i_sb)) { |
2763 | th = current->journal_info; | 2781 | th = current->journal_info; |
2764 | } | 2782 | } |
@@ -2770,7 +2788,6 @@ int reiserfs_commit_write(struct file *f, struct page *page, | |||
2770 | */ | 2788 | */ |
2771 | if (pos > inode->i_size) { | 2789 | if (pos > inode->i_size) { |
2772 | struct reiserfs_transaction_handle myth; | 2790 | struct reiserfs_transaction_handle myth; |
2773 | reiserfs_write_lock(inode->i_sb); | ||
2774 | /* If the file have grown beyond the border where it | 2791 | /* If the file have grown beyond the border where it |
2775 | can have a tail, unmark it as needing a tail | 2792 | can have a tail, unmark it as needing a tail |
2776 | packing */ | 2793 | packing */ |
@@ -2781,10 +2798,9 @@ int reiserfs_commit_write(struct file *f, struct page *page, | |||
2781 | REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; | 2798 | REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; |
2782 | 2799 | ||
2783 | ret = journal_begin(&myth, inode->i_sb, 1); | 2800 | ret = journal_begin(&myth, inode->i_sb, 1); |
2784 | if (ret) { | 2801 | if (ret) |
2785 | reiserfs_write_unlock(inode->i_sb); | ||
2786 | goto journal_error; | 2802 | goto journal_error; |
2787 | } | 2803 | |
2788 | reiserfs_update_inode_transaction(inode); | 2804 | reiserfs_update_inode_transaction(inode); |
2789 | inode->i_size = pos; | 2805 | inode->i_size = pos; |
2790 | /* | 2806 | /* |
@@ -2796,16 +2812,13 @@ int reiserfs_commit_write(struct file *f, struct page *page, | |||
2796 | reiserfs_update_sd(&myth, inode); | 2812 | reiserfs_update_sd(&myth, inode); |
2797 | update_sd = 1; | 2813 | update_sd = 1; |
2798 | ret = journal_end(&myth, inode->i_sb, 1); | 2814 | ret = journal_end(&myth, inode->i_sb, 1); |
2799 | reiserfs_write_unlock(inode->i_sb); | ||
2800 | if (ret) | 2815 | if (ret) |
2801 | goto journal_error; | 2816 | goto journal_error; |
2802 | } | 2817 | } |
2803 | if (th) { | 2818 | if (th) { |
2804 | reiserfs_write_lock(inode->i_sb); | ||
2805 | if (!update_sd) | 2819 | if (!update_sd) |
2806 | mark_inode_dirty(inode); | 2820 | mark_inode_dirty(inode); |
2807 | ret = reiserfs_end_persistent_transaction(th); | 2821 | ret = reiserfs_end_persistent_transaction(th); |
2808 | reiserfs_write_unlock(inode->i_sb); | ||
2809 | if (ret) | 2822 | if (ret) |
2810 | goto out; | 2823 | goto out; |
2811 | } | 2824 | } |
@@ -2815,11 +2828,9 @@ int reiserfs_commit_write(struct file *f, struct page *page, | |||
2815 | 2828 | ||
2816 | journal_error: | 2829 | journal_error: |
2817 | if (th) { | 2830 | if (th) { |
2818 | reiserfs_write_lock(inode->i_sb); | ||
2819 | if (!update_sd) | 2831 | if (!update_sd) |
2820 | reiserfs_update_sd(th, inode); | 2832 | reiserfs_update_sd(th, inode); |
2821 | ret = reiserfs_end_persistent_transaction(th); | 2833 | ret = reiserfs_end_persistent_transaction(th); |
2822 | reiserfs_write_unlock(inode->i_sb); | ||
2823 | } | 2834 | } |
2824 | 2835 | ||
2825 | return ret; | 2836 | return ret; |
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index 0ccc3fdda7bf..ace77451ceb1 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c | |||
@@ -13,44 +13,52 @@ | |||
13 | #include <linux/compat.h> | 13 | #include <linux/compat.h> |
14 | 14 | ||
15 | /* | 15 | /* |
16 | ** reiserfs_ioctl - handler for ioctl for inode | 16 | * reiserfs_ioctl - handler for ioctl for inode |
17 | ** supported commands: | 17 | * supported commands: |
18 | ** 1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect | 18 | * 1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect |
19 | ** and prevent packing file (argument arg has to be non-zero) | 19 | * and prevent packing file (argument arg has to be non-zero) |
20 | ** 2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION | 20 | * 2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION |
21 | ** 3) That's all for a while ... | 21 | * 3) That's all for a while ... |
22 | */ | 22 | */ |
23 | int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | 23 | long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
24 | unsigned long arg) | ||
25 | { | 24 | { |
25 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
26 | unsigned int flags; | 26 | unsigned int flags; |
27 | int err = 0; | 27 | int err = 0; |
28 | 28 | ||
29 | reiserfs_write_lock(inode->i_sb); | ||
30 | |||
29 | switch (cmd) { | 31 | switch (cmd) { |
30 | case REISERFS_IOC_UNPACK: | 32 | case REISERFS_IOC_UNPACK: |
31 | if (S_ISREG(inode->i_mode)) { | 33 | if (S_ISREG(inode->i_mode)) { |
32 | if (arg) | 34 | if (arg) |
33 | return reiserfs_unpack(inode, filp); | 35 | err = reiserfs_unpack(inode, filp); |
34 | else | ||
35 | return 0; | ||
36 | } else | 36 | } else |
37 | return -ENOTTY; | 37 | err = -ENOTTY; |
38 | /* following two cases are taken from fs/ext2/ioctl.c by Remy | 38 | break; |
39 | Card (card@masi.ibp.fr) */ | 39 | /* |
40 | * following two cases are taken from fs/ext2/ioctl.c by Remy | ||
41 | * Card (card@masi.ibp.fr) | ||
42 | */ | ||
40 | case REISERFS_IOC_GETFLAGS: | 43 | case REISERFS_IOC_GETFLAGS: |
41 | if (!reiserfs_attrs(inode->i_sb)) | 44 | if (!reiserfs_attrs(inode->i_sb)) { |
42 | return -ENOTTY; | 45 | err = -ENOTTY; |
46 | break; | ||
47 | } | ||
43 | 48 | ||
44 | flags = REISERFS_I(inode)->i_attrs; | 49 | flags = REISERFS_I(inode)->i_attrs; |
45 | i_attrs_to_sd_attrs(inode, (__u16 *) & flags); | 50 | i_attrs_to_sd_attrs(inode, (__u16 *) & flags); |
46 | return put_user(flags, (int __user *)arg); | 51 | err = put_user(flags, (int __user *)arg); |
52 | break; | ||
47 | case REISERFS_IOC_SETFLAGS:{ | 53 | case REISERFS_IOC_SETFLAGS:{ |
48 | if (!reiserfs_attrs(inode->i_sb)) | 54 | if (!reiserfs_attrs(inode->i_sb)) { |
49 | return -ENOTTY; | 55 | err = -ENOTTY; |
56 | break; | ||
57 | } | ||
50 | 58 | ||
51 | err = mnt_want_write(filp->f_path.mnt); | 59 | err = mnt_want_write(filp->f_path.mnt); |
52 | if (err) | 60 | if (err) |
53 | return err; | 61 | break; |
54 | 62 | ||
55 | if (!is_owner_or_cap(inode)) { | 63 | if (!is_owner_or_cap(inode)) { |
56 | err = -EPERM; | 64 | err = -EPERM; |
@@ -90,16 +98,18 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
90 | mark_inode_dirty(inode); | 98 | mark_inode_dirty(inode); |
91 | setflags_out: | 99 | setflags_out: |
92 | mnt_drop_write(filp->f_path.mnt); | 100 | mnt_drop_write(filp->f_path.mnt); |
93 | return err; | 101 | break; |
94 | } | 102 | } |
95 | case REISERFS_IOC_GETVERSION: | 103 | case REISERFS_IOC_GETVERSION: |
96 | return put_user(inode->i_generation, (int __user *)arg); | 104 | err = put_user(inode->i_generation, (int __user *)arg); |
105 | break; | ||
97 | case REISERFS_IOC_SETVERSION: | 106 | case REISERFS_IOC_SETVERSION: |
98 | if (!is_owner_or_cap(inode)) | 107 | if (!is_owner_or_cap(inode)) |
99 | return -EPERM; | 108 | err = -EPERM; |
109 | break; | ||
100 | err = mnt_want_write(filp->f_path.mnt); | 110 | err = mnt_want_write(filp->f_path.mnt); |
101 | if (err) | 111 | if (err) |
102 | return err; | 112 | break; |
103 | if (get_user(inode->i_generation, (int __user *)arg)) { | 113 | if (get_user(inode->i_generation, (int __user *)arg)) { |
104 | err = -EFAULT; | 114 | err = -EFAULT; |
105 | goto setversion_out; | 115 | goto setversion_out; |
@@ -108,19 +118,20 @@ setflags_out: | |||
108 | mark_inode_dirty(inode); | 118 | mark_inode_dirty(inode); |
109 | setversion_out: | 119 | setversion_out: |
110 | mnt_drop_write(filp->f_path.mnt); | 120 | mnt_drop_write(filp->f_path.mnt); |
111 | return err; | 121 | break; |
112 | default: | 122 | default: |
113 | return -ENOTTY; | 123 | err = -ENOTTY; |
114 | } | 124 | } |
125 | |||
126 | reiserfs_write_unlock(inode->i_sb); | ||
127 | |||
128 | return err; | ||
115 | } | 129 | } |
116 | 130 | ||
117 | #ifdef CONFIG_COMPAT | 131 | #ifdef CONFIG_COMPAT |
118 | long reiserfs_compat_ioctl(struct file *file, unsigned int cmd, | 132 | long reiserfs_compat_ioctl(struct file *file, unsigned int cmd, |
119 | unsigned long arg) | 133 | unsigned long arg) |
120 | { | 134 | { |
121 | struct inode *inode = file->f_path.dentry->d_inode; | ||
122 | int ret; | ||
123 | |||
124 | /* These are just misnamed, they actually get/put from/to user an int */ | 135 | /* These are just misnamed, they actually get/put from/to user an int */ |
125 | switch (cmd) { | 136 | switch (cmd) { |
126 | case REISERFS_IOC32_UNPACK: | 137 | case REISERFS_IOC32_UNPACK: |
@@ -141,10 +152,8 @@ long reiserfs_compat_ioctl(struct file *file, unsigned int cmd, | |||
141 | default: | 152 | default: |
142 | return -ENOIOCTLCMD; | 153 | return -ENOIOCTLCMD; |
143 | } | 154 | } |
144 | lock_kernel(); | 155 | |
145 | ret = reiserfs_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); | 156 | return reiserfs_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); |
146 | unlock_kernel(); | ||
147 | return ret; | ||
148 | } | 157 | } |
149 | #endif | 158 | #endif |
150 | 159 | ||
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 90622200b39c..2f8a7e7b8dab 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c | |||
@@ -429,21 +429,6 @@ static void clear_prepared_bits(struct buffer_head *bh) | |||
429 | clear_buffer_journal_restore_dirty(bh); | 429 | clear_buffer_journal_restore_dirty(bh); |
430 | } | 430 | } |
431 | 431 | ||
432 | /* utility function to force a BUG if it is called without the big | ||
433 | ** kernel lock held. caller is the string printed just before calling BUG() | ||
434 | */ | ||
435 | void reiserfs_check_lock_depth(struct super_block *sb, char *caller) | ||
436 | { | ||
437 | #ifdef CONFIG_SMP | ||
438 | if (current->lock_depth < 0) { | ||
439 | reiserfs_panic(sb, "journal-1", "%s called without kernel " | ||
440 | "lock held", caller); | ||
441 | } | ||
442 | #else | ||
443 | ; | ||
444 | #endif | ||
445 | } | ||
446 | |||
447 | /* return a cnode with same dev, block number and size in table, or null if not found */ | 432 | /* return a cnode with same dev, block number and size in table, or null if not found */ |
448 | static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct | 433 | static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct |
449 | super_block | 434 | super_block |
@@ -556,7 +541,8 @@ static inline void insert_journal_hash(struct reiserfs_journal_cnode **table, | |||
556 | static inline void lock_journal(struct super_block *sb) | 541 | static inline void lock_journal(struct super_block *sb) |
557 | { | 542 | { |
558 | PROC_INFO_INC(sb, journal.lock_journal); | 543 | PROC_INFO_INC(sb, journal.lock_journal); |
559 | mutex_lock(&SB_JOURNAL(sb)->j_mutex); | 544 | |
545 | reiserfs_mutex_lock_safe(&SB_JOURNAL(sb)->j_mutex, sb); | ||
560 | } | 546 | } |
561 | 547 | ||
562 | /* unlock the current transaction */ | 548 | /* unlock the current transaction */ |
@@ -708,7 +694,9 @@ static void check_barrier_completion(struct super_block *s, | |||
708 | disable_barrier(s); | 694 | disable_barrier(s); |
709 | set_buffer_uptodate(bh); | 695 | set_buffer_uptodate(bh); |
710 | set_buffer_dirty(bh); | 696 | set_buffer_dirty(bh); |
697 | reiserfs_write_unlock(s); | ||
711 | sync_dirty_buffer(bh); | 698 | sync_dirty_buffer(bh); |
699 | reiserfs_write_lock(s); | ||
712 | } | 700 | } |
713 | } | 701 | } |
714 | 702 | ||
@@ -996,8 +984,13 @@ static int reiserfs_async_progress_wait(struct super_block *s) | |||
996 | { | 984 | { |
997 | DEFINE_WAIT(wait); | 985 | DEFINE_WAIT(wait); |
998 | struct reiserfs_journal *j = SB_JOURNAL(s); | 986 | struct reiserfs_journal *j = SB_JOURNAL(s); |
999 | if (atomic_read(&j->j_async_throttle)) | 987 | |
988 | if (atomic_read(&j->j_async_throttle)) { | ||
989 | reiserfs_write_unlock(s); | ||
1000 | congestion_wait(BLK_RW_ASYNC, HZ / 10); | 990 | congestion_wait(BLK_RW_ASYNC, HZ / 10); |
991 | reiserfs_write_lock(s); | ||
992 | } | ||
993 | |||
1001 | return 0; | 994 | return 0; |
1002 | } | 995 | } |
1003 | 996 | ||
@@ -1043,7 +1036,8 @@ static int flush_commit_list(struct super_block *s, | |||
1043 | } | 1036 | } |
1044 | 1037 | ||
1045 | /* make sure nobody is trying to flush this one at the same time */ | 1038 | /* make sure nobody is trying to flush this one at the same time */ |
1046 | mutex_lock(&jl->j_commit_mutex); | 1039 | reiserfs_mutex_lock_safe(&jl->j_commit_mutex, s); |
1040 | |||
1047 | if (!journal_list_still_alive(s, trans_id)) { | 1041 | if (!journal_list_still_alive(s, trans_id)) { |
1048 | mutex_unlock(&jl->j_commit_mutex); | 1042 | mutex_unlock(&jl->j_commit_mutex); |
1049 | goto put_jl; | 1043 | goto put_jl; |
@@ -1061,12 +1055,17 @@ static int flush_commit_list(struct super_block *s, | |||
1061 | 1055 | ||
1062 | if (!list_empty(&jl->j_bh_list)) { | 1056 | if (!list_empty(&jl->j_bh_list)) { |
1063 | int ret; | 1057 | int ret; |
1064 | unlock_kernel(); | 1058 | |
1059 | /* | ||
1060 | * We might sleep in numerous places inside | ||
1061 | * write_ordered_buffers. Relax the write lock. | ||
1062 | */ | ||
1063 | reiserfs_write_unlock(s); | ||
1065 | ret = write_ordered_buffers(&journal->j_dirty_buffers_lock, | 1064 | ret = write_ordered_buffers(&journal->j_dirty_buffers_lock, |
1066 | journal, jl, &jl->j_bh_list); | 1065 | journal, jl, &jl->j_bh_list); |
1067 | if (ret < 0 && retval == 0) | 1066 | if (ret < 0 && retval == 0) |
1068 | retval = ret; | 1067 | retval = ret; |
1069 | lock_kernel(); | 1068 | reiserfs_write_lock(s); |
1070 | } | 1069 | } |
1071 | BUG_ON(!list_empty(&jl->j_bh_list)); | 1070 | BUG_ON(!list_empty(&jl->j_bh_list)); |
1072 | /* | 1071 | /* |
@@ -1085,8 +1084,11 @@ static int flush_commit_list(struct super_block *s, | |||
1085 | SB_ONDISK_JOURNAL_SIZE(s); | 1084 | SB_ONDISK_JOURNAL_SIZE(s); |
1086 | tbh = journal_find_get_block(s, bn); | 1085 | tbh = journal_find_get_block(s, bn); |
1087 | if (tbh) { | 1086 | if (tbh) { |
1088 | if (buffer_dirty(tbh)) | 1087 | if (buffer_dirty(tbh)) { |
1089 | ll_rw_block(WRITE, 1, &tbh) ; | 1088 | reiserfs_write_unlock(s); |
1089 | ll_rw_block(WRITE, 1, &tbh); | ||
1090 | reiserfs_write_lock(s); | ||
1091 | } | ||
1090 | put_bh(tbh) ; | 1092 | put_bh(tbh) ; |
1091 | } | 1093 | } |
1092 | } | 1094 | } |
@@ -1114,12 +1116,19 @@ static int flush_commit_list(struct super_block *s, | |||
1114 | bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + | 1116 | bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + |
1115 | (jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s); | 1117 | (jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s); |
1116 | tbh = journal_find_get_block(s, bn); | 1118 | tbh = journal_find_get_block(s, bn); |
1119 | |||
1120 | reiserfs_write_unlock(s); | ||
1117 | wait_on_buffer(tbh); | 1121 | wait_on_buffer(tbh); |
1122 | reiserfs_write_lock(s); | ||
1118 | // since we're using ll_rw_blk above, it might have skipped over | 1123 | // since we're using ll_rw_blk above, it might have skipped over |
1119 | // a locked buffer. Double check here | 1124 | // a locked buffer. Double check here |
1120 | // | 1125 | // |
1121 | if (buffer_dirty(tbh)) /* redundant, sync_dirty_buffer() checks */ | 1126 | /* redundant, sync_dirty_buffer() checks */ |
1127 | if (buffer_dirty(tbh)) { | ||
1128 | reiserfs_write_unlock(s); | ||
1122 | sync_dirty_buffer(tbh); | 1129 | sync_dirty_buffer(tbh); |
1130 | reiserfs_write_lock(s); | ||
1131 | } | ||
1123 | if (unlikely(!buffer_uptodate(tbh))) { | 1132 | if (unlikely(!buffer_uptodate(tbh))) { |
1124 | #ifdef CONFIG_REISERFS_CHECK | 1133 | #ifdef CONFIG_REISERFS_CHECK |
1125 | reiserfs_warning(s, "journal-601", | 1134 | reiserfs_warning(s, "journal-601", |
@@ -1143,10 +1152,15 @@ static int flush_commit_list(struct super_block *s, | |||
1143 | if (buffer_dirty(jl->j_commit_bh)) | 1152 | if (buffer_dirty(jl->j_commit_bh)) |
1144 | BUG(); | 1153 | BUG(); |
1145 | mark_buffer_dirty(jl->j_commit_bh) ; | 1154 | mark_buffer_dirty(jl->j_commit_bh) ; |
1155 | reiserfs_write_unlock(s); | ||
1146 | sync_dirty_buffer(jl->j_commit_bh) ; | 1156 | sync_dirty_buffer(jl->j_commit_bh) ; |
1157 | reiserfs_write_lock(s); | ||
1147 | } | 1158 | } |
1148 | } else | 1159 | } else { |
1160 | reiserfs_write_unlock(s); | ||
1149 | wait_on_buffer(jl->j_commit_bh); | 1161 | wait_on_buffer(jl->j_commit_bh); |
1162 | reiserfs_write_lock(s); | ||
1163 | } | ||
1150 | 1164 | ||
1151 | check_barrier_completion(s, jl->j_commit_bh); | 1165 | check_barrier_completion(s, jl->j_commit_bh); |
1152 | 1166 | ||
@@ -1286,7 +1300,9 @@ static int _update_journal_header_block(struct super_block *sb, | |||
1286 | 1300 | ||
1287 | if (trans_id >= journal->j_last_flush_trans_id) { | 1301 | if (trans_id >= journal->j_last_flush_trans_id) { |
1288 | if (buffer_locked((journal->j_header_bh))) { | 1302 | if (buffer_locked((journal->j_header_bh))) { |
1303 | reiserfs_write_unlock(sb); | ||
1289 | wait_on_buffer((journal->j_header_bh)); | 1304 | wait_on_buffer((journal->j_header_bh)); |
1305 | reiserfs_write_lock(sb); | ||
1290 | if (unlikely(!buffer_uptodate(journal->j_header_bh))) { | 1306 | if (unlikely(!buffer_uptodate(journal->j_header_bh))) { |
1291 | #ifdef CONFIG_REISERFS_CHECK | 1307 | #ifdef CONFIG_REISERFS_CHECK |
1292 | reiserfs_warning(sb, "journal-699", | 1308 | reiserfs_warning(sb, "journal-699", |
@@ -1312,12 +1328,16 @@ static int _update_journal_header_block(struct super_block *sb, | |||
1312 | disable_barrier(sb); | 1328 | disable_barrier(sb); |
1313 | goto sync; | 1329 | goto sync; |
1314 | } | 1330 | } |
1331 | reiserfs_write_unlock(sb); | ||
1315 | wait_on_buffer(journal->j_header_bh); | 1332 | wait_on_buffer(journal->j_header_bh); |
1333 | reiserfs_write_lock(sb); | ||
1316 | check_barrier_completion(sb, journal->j_header_bh); | 1334 | check_barrier_completion(sb, journal->j_header_bh); |
1317 | } else { | 1335 | } else { |
1318 | sync: | 1336 | sync: |
1319 | set_buffer_dirty(journal->j_header_bh); | 1337 | set_buffer_dirty(journal->j_header_bh); |
1338 | reiserfs_write_unlock(sb); | ||
1320 | sync_dirty_buffer(journal->j_header_bh); | 1339 | sync_dirty_buffer(journal->j_header_bh); |
1340 | reiserfs_write_lock(sb); | ||
1321 | } | 1341 | } |
1322 | if (!buffer_uptodate(journal->j_header_bh)) { | 1342 | if (!buffer_uptodate(journal->j_header_bh)) { |
1323 | reiserfs_warning(sb, "journal-837", | 1343 | reiserfs_warning(sb, "journal-837", |
@@ -1409,7 +1429,7 @@ static int flush_journal_list(struct super_block *s, | |||
1409 | 1429 | ||
1410 | /* if flushall == 0, the lock is already held */ | 1430 | /* if flushall == 0, the lock is already held */ |
1411 | if (flushall) { | 1431 | if (flushall) { |
1412 | mutex_lock(&journal->j_flush_mutex); | 1432 | reiserfs_mutex_lock_safe(&journal->j_flush_mutex, s); |
1413 | } else if (mutex_trylock(&journal->j_flush_mutex)) { | 1433 | } else if (mutex_trylock(&journal->j_flush_mutex)) { |
1414 | BUG(); | 1434 | BUG(); |
1415 | } | 1435 | } |
@@ -1553,7 +1573,11 @@ static int flush_journal_list(struct super_block *s, | |||
1553 | reiserfs_panic(s, "journal-1011", | 1573 | reiserfs_panic(s, "journal-1011", |
1554 | "cn->bh is NULL"); | 1574 | "cn->bh is NULL"); |
1555 | } | 1575 | } |
1576 | |||
1577 | reiserfs_write_unlock(s); | ||
1556 | wait_on_buffer(cn->bh); | 1578 | wait_on_buffer(cn->bh); |
1579 | reiserfs_write_lock(s); | ||
1580 | |||
1557 | if (!cn->bh) { | 1581 | if (!cn->bh) { |
1558 | reiserfs_panic(s, "journal-1012", | 1582 | reiserfs_panic(s, "journal-1012", |
1559 | "cn->bh is NULL"); | 1583 | "cn->bh is NULL"); |
@@ -1769,7 +1793,7 @@ static int kupdate_transactions(struct super_block *s, | |||
1769 | struct reiserfs_journal *journal = SB_JOURNAL(s); | 1793 | struct reiserfs_journal *journal = SB_JOURNAL(s); |
1770 | chunk.nr = 0; | 1794 | chunk.nr = 0; |
1771 | 1795 | ||
1772 | mutex_lock(&journal->j_flush_mutex); | 1796 | reiserfs_mutex_lock_safe(&journal->j_flush_mutex, s); |
1773 | if (!journal_list_still_alive(s, orig_trans_id)) { | 1797 | if (!journal_list_still_alive(s, orig_trans_id)) { |
1774 | goto done; | 1798 | goto done; |
1775 | } | 1799 | } |
@@ -1973,11 +1997,19 @@ static int do_journal_release(struct reiserfs_transaction_handle *th, | |||
1973 | reiserfs_mounted_fs_count--; | 1997 | reiserfs_mounted_fs_count--; |
1974 | /* wait for all commits to finish */ | 1998 | /* wait for all commits to finish */ |
1975 | cancel_delayed_work(&SB_JOURNAL(sb)->j_work); | 1999 | cancel_delayed_work(&SB_JOURNAL(sb)->j_work); |
2000 | |||
2001 | /* | ||
2002 | * We must release the write lock here because | ||
2003 | * the workqueue job (flush_async_commit) needs this lock | ||
2004 | */ | ||
2005 | reiserfs_write_unlock(sb); | ||
1976 | flush_workqueue(commit_wq); | 2006 | flush_workqueue(commit_wq); |
2007 | |||
1977 | if (!reiserfs_mounted_fs_count) { | 2008 | if (!reiserfs_mounted_fs_count) { |
1978 | destroy_workqueue(commit_wq); | 2009 | destroy_workqueue(commit_wq); |
1979 | commit_wq = NULL; | 2010 | commit_wq = NULL; |
1980 | } | 2011 | } |
2012 | reiserfs_write_lock(sb); | ||
1981 | 2013 | ||
1982 | free_journal_ram(sb); | 2014 | free_journal_ram(sb); |
1983 | 2015 | ||
@@ -2243,7 +2275,11 @@ static int journal_read_transaction(struct super_block *sb, | |||
2243 | /* read in the log blocks, memcpy to the corresponding real block */ | 2275 | /* read in the log blocks, memcpy to the corresponding real block */ |
2244 | ll_rw_block(READ, get_desc_trans_len(desc), log_blocks); | 2276 | ll_rw_block(READ, get_desc_trans_len(desc), log_blocks); |
2245 | for (i = 0; i < get_desc_trans_len(desc); i++) { | 2277 | for (i = 0; i < get_desc_trans_len(desc); i++) { |
2278 | |||
2279 | reiserfs_write_unlock(sb); | ||
2246 | wait_on_buffer(log_blocks[i]); | 2280 | wait_on_buffer(log_blocks[i]); |
2281 | reiserfs_write_lock(sb); | ||
2282 | |||
2247 | if (!buffer_uptodate(log_blocks[i])) { | 2283 | if (!buffer_uptodate(log_blocks[i])) { |
2248 | reiserfs_warning(sb, "journal-1212", | 2284 | reiserfs_warning(sb, "journal-1212", |
2249 | "REPLAY FAILURE fsck required! " | 2285 | "REPLAY FAILURE fsck required! " |
@@ -2765,11 +2801,27 @@ int journal_init(struct super_block *sb, const char *j_dev_name, | |||
2765 | goto free_and_return; | 2801 | goto free_and_return; |
2766 | } | 2802 | } |
2767 | 2803 | ||
2804 | /* | ||
2805 | * We need to unlock here to avoid creating the following | ||
2806 | * dependency: | ||
2807 | * reiserfs_lock -> sysfs_mutex | ||
2808 | * Because the reiserfs mmap path creates the following dependency: | ||
2809 | * mm->mmap -> reiserfs_lock, hence we have | ||
2810 | * mm->mmap -> reiserfs_lock ->sysfs_mutex | ||
2811 | * This would ends up in a circular dependency with sysfs readdir path | ||
2812 | * which does sysfs_mutex -> mm->mmap_sem | ||
2813 | * This is fine because the reiserfs lock is useless in mount path, | ||
2814 | * at least until we call journal_begin. We keep it for paranoid | ||
2815 | * reasons. | ||
2816 | */ | ||
2817 | reiserfs_write_unlock(sb); | ||
2768 | if (journal_init_dev(sb, journal, j_dev_name) != 0) { | 2818 | if (journal_init_dev(sb, journal, j_dev_name) != 0) { |
2819 | reiserfs_write_lock(sb); | ||
2769 | reiserfs_warning(sb, "sh-462", | 2820 | reiserfs_warning(sb, "sh-462", |
2770 | "unable to initialize jornal device"); | 2821 | "unable to initialize jornal device"); |
2771 | goto free_and_return; | 2822 | goto free_and_return; |
2772 | } | 2823 | } |
2824 | reiserfs_write_lock(sb); | ||
2773 | 2825 | ||
2774 | rs = SB_DISK_SUPER_BLOCK(sb); | 2826 | rs = SB_DISK_SUPER_BLOCK(sb); |
2775 | 2827 | ||
@@ -2881,8 +2933,11 @@ int journal_init(struct super_block *sb, const char *j_dev_name, | |||
2881 | } | 2933 | } |
2882 | 2934 | ||
2883 | reiserfs_mounted_fs_count++; | 2935 | reiserfs_mounted_fs_count++; |
2884 | if (reiserfs_mounted_fs_count <= 1) | 2936 | if (reiserfs_mounted_fs_count <= 1) { |
2937 | reiserfs_write_unlock(sb); | ||
2885 | commit_wq = create_workqueue("reiserfs"); | 2938 | commit_wq = create_workqueue("reiserfs"); |
2939 | reiserfs_write_lock(sb); | ||
2940 | } | ||
2886 | 2941 | ||
2887 | INIT_DELAYED_WORK(&journal->j_work, flush_async_commits); | 2942 | INIT_DELAYED_WORK(&journal->j_work, flush_async_commits); |
2888 | journal->j_work_sb = sb; | 2943 | journal->j_work_sb = sb; |
@@ -2964,8 +3019,11 @@ static void queue_log_writer(struct super_block *s) | |||
2964 | init_waitqueue_entry(&wait, current); | 3019 | init_waitqueue_entry(&wait, current); |
2965 | add_wait_queue(&journal->j_join_wait, &wait); | 3020 | add_wait_queue(&journal->j_join_wait, &wait); |
2966 | set_current_state(TASK_UNINTERRUPTIBLE); | 3021 | set_current_state(TASK_UNINTERRUPTIBLE); |
2967 | if (test_bit(J_WRITERS_QUEUED, &journal->j_state)) | 3022 | if (test_bit(J_WRITERS_QUEUED, &journal->j_state)) { |
3023 | reiserfs_write_unlock(s); | ||
2968 | schedule(); | 3024 | schedule(); |
3025 | reiserfs_write_lock(s); | ||
3026 | } | ||
2969 | __set_current_state(TASK_RUNNING); | 3027 | __set_current_state(TASK_RUNNING); |
2970 | remove_wait_queue(&journal->j_join_wait, &wait); | 3028 | remove_wait_queue(&journal->j_join_wait, &wait); |
2971 | } | 3029 | } |
@@ -2982,7 +3040,9 @@ static void let_transaction_grow(struct super_block *sb, unsigned int trans_id) | |||
2982 | struct reiserfs_journal *journal = SB_JOURNAL(sb); | 3040 | struct reiserfs_journal *journal = SB_JOURNAL(sb); |
2983 | unsigned long bcount = journal->j_bcount; | 3041 | unsigned long bcount = journal->j_bcount; |
2984 | while (1) { | 3042 | while (1) { |
3043 | reiserfs_write_unlock(sb); | ||
2985 | schedule_timeout_uninterruptible(1); | 3044 | schedule_timeout_uninterruptible(1); |
3045 | reiserfs_write_lock(sb); | ||
2986 | journal->j_current_jl->j_state |= LIST_COMMIT_PENDING; | 3046 | journal->j_current_jl->j_state |= LIST_COMMIT_PENDING; |
2987 | while ((atomic_read(&journal->j_wcount) > 0 || | 3047 | while ((atomic_read(&journal->j_wcount) > 0 || |
2988 | atomic_read(&journal->j_jlock)) && | 3048 | atomic_read(&journal->j_jlock)) && |
@@ -3033,7 +3093,9 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, | |||
3033 | 3093 | ||
3034 | if (test_bit(J_WRITERS_BLOCKED, &journal->j_state)) { | 3094 | if (test_bit(J_WRITERS_BLOCKED, &journal->j_state)) { |
3035 | unlock_journal(sb); | 3095 | unlock_journal(sb); |
3096 | reiserfs_write_unlock(sb); | ||
3036 | reiserfs_wait_on_write_block(sb); | 3097 | reiserfs_wait_on_write_block(sb); |
3098 | reiserfs_write_lock(sb); | ||
3037 | PROC_INFO_INC(sb, journal.journal_relock_writers); | 3099 | PROC_INFO_INC(sb, journal.journal_relock_writers); |
3038 | goto relock; | 3100 | goto relock; |
3039 | } | 3101 | } |
@@ -3506,14 +3568,14 @@ static void flush_async_commits(struct work_struct *work) | |||
3506 | struct reiserfs_journal_list *jl; | 3568 | struct reiserfs_journal_list *jl; |
3507 | struct list_head *entry; | 3569 | struct list_head *entry; |
3508 | 3570 | ||
3509 | lock_kernel(); | 3571 | reiserfs_write_lock(sb); |
3510 | if (!list_empty(&journal->j_journal_list)) { | 3572 | if (!list_empty(&journal->j_journal_list)) { |
3511 | /* last entry is the youngest, commit it and you get everything */ | 3573 | /* last entry is the youngest, commit it and you get everything */ |
3512 | entry = journal->j_journal_list.prev; | 3574 | entry = journal->j_journal_list.prev; |
3513 | jl = JOURNAL_LIST_ENTRY(entry); | 3575 | jl = JOURNAL_LIST_ENTRY(entry); |
3514 | flush_commit_list(sb, jl, 1); | 3576 | flush_commit_list(sb, jl, 1); |
3515 | } | 3577 | } |
3516 | unlock_kernel(); | 3578 | reiserfs_write_unlock(sb); |
3517 | } | 3579 | } |
3518 | 3580 | ||
3519 | /* | 3581 | /* |
@@ -4041,7 +4103,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, | |||
4041 | * the new transaction is fully setup, and we've already flushed the | 4103 | * the new transaction is fully setup, and we've already flushed the |
4042 | * ordered bh list | 4104 | * ordered bh list |
4043 | */ | 4105 | */ |
4044 | mutex_lock(&jl->j_commit_mutex); | 4106 | reiserfs_mutex_lock_safe(&jl->j_commit_mutex, sb); |
4045 | 4107 | ||
4046 | /* save the transaction id in case we need to commit it later */ | 4108 | /* save the transaction id in case we need to commit it later */ |
4047 | commit_trans_id = jl->j_trans_id; | 4109 | commit_trans_id = jl->j_trans_id; |
@@ -4156,7 +4218,9 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, | |||
4156 | next = cn->next; | 4218 | next = cn->next; |
4157 | free_cnode(sb, cn); | 4219 | free_cnode(sb, cn); |
4158 | cn = next; | 4220 | cn = next; |
4221 | reiserfs_write_unlock(sb); | ||
4159 | cond_resched(); | 4222 | cond_resched(); |
4223 | reiserfs_write_lock(sb); | ||
4160 | } | 4224 | } |
4161 | 4225 | ||
4162 | /* we are done with both the c_bh and d_bh, but | 4226 | /* we are done with both the c_bh and d_bh, but |
@@ -4203,10 +4267,10 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, | |||
4203 | * is lost. | 4267 | * is lost. |
4204 | */ | 4268 | */ |
4205 | if (!list_empty(&jl->j_tail_bh_list)) { | 4269 | if (!list_empty(&jl->j_tail_bh_list)) { |
4206 | unlock_kernel(); | 4270 | reiserfs_write_unlock(sb); |
4207 | write_ordered_buffers(&journal->j_dirty_buffers_lock, | 4271 | write_ordered_buffers(&journal->j_dirty_buffers_lock, |
4208 | journal, jl, &jl->j_tail_bh_list); | 4272 | journal, jl, &jl->j_tail_bh_list); |
4209 | lock_kernel(); | 4273 | reiserfs_write_lock(sb); |
4210 | } | 4274 | } |
4211 | BUG_ON(!list_empty(&jl->j_tail_bh_list)); | 4275 | BUG_ON(!list_empty(&jl->j_tail_bh_list)); |
4212 | mutex_unlock(&jl->j_commit_mutex); | 4276 | mutex_unlock(&jl->j_commit_mutex); |
diff --git a/fs/reiserfs/lock.c b/fs/reiserfs/lock.c new file mode 100644 index 000000000000..ee2cfc0fd8a7 --- /dev/null +++ b/fs/reiserfs/lock.c | |||
@@ -0,0 +1,88 @@ | |||
1 | #include <linux/reiserfs_fs.h> | ||
2 | #include <linux/mutex.h> | ||
3 | |||
4 | /* | ||
5 | * The previous reiserfs locking scheme was heavily based on | ||
6 | * the tricky properties of the Bkl: | ||
7 | * | ||
8 | * - it was acquired recursively by a same task | ||
9 | * - the performances relied on the release-while-schedule() property | ||
10 | * | ||
11 | * Now that we replace it by a mutex, we still want to keep the same | ||
12 | * recursive property to avoid big changes in the code structure. | ||
13 | * We use our own lock_owner here because the owner field on a mutex | ||
14 | * is only available in SMP or mutex debugging, also we only need this field | ||
15 | * for this mutex, no need for a system wide mutex facility. | ||
16 | * | ||
17 | * Also this lock is often released before a call that could block because | ||
18 | * reiserfs performances were partialy based on the release while schedule() | ||
19 | * property of the Bkl. | ||
20 | */ | ||
21 | void reiserfs_write_lock(struct super_block *s) | ||
22 | { | ||
23 | struct reiserfs_sb_info *sb_i = REISERFS_SB(s); | ||
24 | |||
25 | if (sb_i->lock_owner != current) { | ||
26 | mutex_lock(&sb_i->lock); | ||
27 | sb_i->lock_owner = current; | ||
28 | } | ||
29 | |||
30 | /* No need to protect it, only the current task touches it */ | ||
31 | sb_i->lock_depth++; | ||
32 | } | ||
33 | |||
34 | void reiserfs_write_unlock(struct super_block *s) | ||
35 | { | ||
36 | struct reiserfs_sb_info *sb_i = REISERFS_SB(s); | ||
37 | |||
38 | /* | ||
39 | * Are we unlocking without even holding the lock? | ||
40 | * Such a situation must raise a BUG() if we don't want | ||
41 | * to corrupt the data. | ||
42 | */ | ||
43 | BUG_ON(sb_i->lock_owner != current); | ||
44 | |||
45 | if (--sb_i->lock_depth == -1) { | ||
46 | sb_i->lock_owner = NULL; | ||
47 | mutex_unlock(&sb_i->lock); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * If we already own the lock, just exit and don't increase the depth. | ||
53 | * Useful when we don't want to lock more than once. | ||
54 | * | ||
55 | * We always return the lock_depth we had before calling | ||
56 | * this function. | ||
57 | */ | ||
58 | int reiserfs_write_lock_once(struct super_block *s) | ||
59 | { | ||
60 | struct reiserfs_sb_info *sb_i = REISERFS_SB(s); | ||
61 | |||
62 | if (sb_i->lock_owner != current) { | ||
63 | mutex_lock(&sb_i->lock); | ||
64 | sb_i->lock_owner = current; | ||
65 | return sb_i->lock_depth++; | ||
66 | } | ||
67 | |||
68 | return sb_i->lock_depth; | ||
69 | } | ||
70 | |||
71 | void reiserfs_write_unlock_once(struct super_block *s, int lock_depth) | ||
72 | { | ||
73 | if (lock_depth == -1) | ||
74 | reiserfs_write_unlock(s); | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * Utility function to force a BUG if it is called without the superblock | ||
79 | * write lock held. caller is the string printed just before calling BUG() | ||
80 | */ | ||
81 | void reiserfs_check_lock_depth(struct super_block *sb, char *caller) | ||
82 | { | ||
83 | struct reiserfs_sb_info *sb_i = REISERFS_SB(sb); | ||
84 | |||
85 | if (sb_i->lock_depth < 0) | ||
86 | reiserfs_panic(sb, "%s called without kernel lock held %d", | ||
87 | caller); | ||
88 | } | ||
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 271579128634..e296ff72a6cc 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c | |||
@@ -324,6 +324,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry, | |||
324 | struct nameidata *nd) | 324 | struct nameidata *nd) |
325 | { | 325 | { |
326 | int retval; | 326 | int retval; |
327 | int lock_depth; | ||
327 | struct inode *inode = NULL; | 328 | struct inode *inode = NULL; |
328 | struct reiserfs_dir_entry de; | 329 | struct reiserfs_dir_entry de; |
329 | INITIALIZE_PATH(path_to_entry); | 330 | INITIALIZE_PATH(path_to_entry); |
@@ -331,7 +332,13 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry, | |||
331 | if (REISERFS_MAX_NAME(dir->i_sb->s_blocksize) < dentry->d_name.len) | 332 | if (REISERFS_MAX_NAME(dir->i_sb->s_blocksize) < dentry->d_name.len) |
332 | return ERR_PTR(-ENAMETOOLONG); | 333 | return ERR_PTR(-ENAMETOOLONG); |
333 | 334 | ||
334 | reiserfs_write_lock(dir->i_sb); | 335 | /* |
336 | * Might be called with or without the write lock, must be careful | ||
337 | * to not recursively hold it in case we want to release the lock | ||
338 | * before rescheduling. | ||
339 | */ | ||
340 | lock_depth = reiserfs_write_lock_once(dir->i_sb); | ||
341 | |||
335 | de.de_gen_number_bit_string = NULL; | 342 | de.de_gen_number_bit_string = NULL; |
336 | retval = | 343 | retval = |
337 | reiserfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, | 344 | reiserfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, |
@@ -341,7 +348,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry, | |||
341 | inode = reiserfs_iget(dir->i_sb, | 348 | inode = reiserfs_iget(dir->i_sb, |
342 | (struct cpu_key *)&(de.de_dir_id)); | 349 | (struct cpu_key *)&(de.de_dir_id)); |
343 | if (!inode || IS_ERR(inode)) { | 350 | if (!inode || IS_ERR(inode)) { |
344 | reiserfs_write_unlock(dir->i_sb); | 351 | reiserfs_write_unlock_once(dir->i_sb, lock_depth); |
345 | return ERR_PTR(-EACCES); | 352 | return ERR_PTR(-EACCES); |
346 | } | 353 | } |
347 | 354 | ||
@@ -350,7 +357,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry, | |||
350 | if (IS_PRIVATE(dir)) | 357 | if (IS_PRIVATE(dir)) |
351 | inode->i_flags |= S_PRIVATE; | 358 | inode->i_flags |= S_PRIVATE; |
352 | } | 359 | } |
353 | reiserfs_write_unlock(dir->i_sb); | 360 | reiserfs_write_unlock_once(dir->i_sb, lock_depth); |
354 | if (retval == IO_ERROR) { | 361 | if (retval == IO_ERROR) { |
355 | return ERR_PTR(-EIO); | 362 | return ERR_PTR(-EIO); |
356 | } | 363 | } |
@@ -725,6 +732,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
725 | struct inode *inode; | 732 | struct inode *inode; |
726 | struct reiserfs_transaction_handle th; | 733 | struct reiserfs_transaction_handle th; |
727 | struct reiserfs_security_handle security; | 734 | struct reiserfs_security_handle security; |
735 | int lock_depth; | ||
728 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ | 736 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ |
729 | int jbegin_count = | 737 | int jbegin_count = |
730 | JOURNAL_PER_BALANCE_CNT * 3 + | 738 | JOURNAL_PER_BALANCE_CNT * 3 + |
@@ -748,7 +756,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
748 | return retval; | 756 | return retval; |
749 | } | 757 | } |
750 | jbegin_count += retval; | 758 | jbegin_count += retval; |
751 | reiserfs_write_lock(dir->i_sb); | 759 | lock_depth = reiserfs_write_lock_once(dir->i_sb); |
752 | 760 | ||
753 | retval = journal_begin(&th, dir->i_sb, jbegin_count); | 761 | retval = journal_begin(&th, dir->i_sb, jbegin_count); |
754 | if (retval) { | 762 | if (retval) { |
@@ -798,8 +806,8 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
798 | d_instantiate(dentry, inode); | 806 | d_instantiate(dentry, inode); |
799 | unlock_new_inode(inode); | 807 | unlock_new_inode(inode); |
800 | retval = journal_end(&th, dir->i_sb, jbegin_count); | 808 | retval = journal_end(&th, dir->i_sb, jbegin_count); |
801 | out_failed: | 809 | out_failed: |
802 | reiserfs_write_unlock(dir->i_sb); | 810 | reiserfs_write_unlock_once(dir->i_sb, lock_depth); |
803 | return retval; | 811 | return retval; |
804 | } | 812 | } |
805 | 813 | ||
diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c index 536eacaeb710..adbc6f538515 100644 --- a/fs/reiserfs/prints.c +++ b/fs/reiserfs/prints.c | |||
@@ -349,10 +349,6 @@ void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...) | |||
349 | 349 | ||
350 | . */ | 350 | . */ |
351 | 351 | ||
352 | #ifdef CONFIG_REISERFS_CHECK | ||
353 | extern struct tree_balance *cur_tb; | ||
354 | #endif | ||
355 | |||
356 | void __reiserfs_panic(struct super_block *sb, const char *id, | 352 | void __reiserfs_panic(struct super_block *sb, const char *id, |
357 | const char *function, const char *fmt, ...) | 353 | const char *function, const char *fmt, ...) |
358 | { | 354 | { |
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c index 18b315d3d104..b3a94d20f0fc 100644 --- a/fs/reiserfs/resize.c +++ b/fs/reiserfs/resize.c | |||
@@ -141,7 +141,9 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) | |||
141 | 141 | ||
142 | set_buffer_uptodate(bh); | 142 | set_buffer_uptodate(bh); |
143 | mark_buffer_dirty(bh); | 143 | mark_buffer_dirty(bh); |
144 | reiserfs_write_unlock(s); | ||
144 | sync_dirty_buffer(bh); | 145 | sync_dirty_buffer(bh); |
146 | reiserfs_write_lock(s); | ||
145 | // update bitmap_info stuff | 147 | // update bitmap_info stuff |
146 | bitmap[i].free_count = sb_blocksize(sb) * 8 - 1; | 148 | bitmap[i].free_count = sb_blocksize(sb) * 8 - 1; |
147 | brelse(bh); | 149 | brelse(bh); |
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index d036ee5b1c81..5fa7118f04e1 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c | |||
@@ -222,9 +222,6 @@ static inline int bin_search(const void *key, /* Key to search for. */ | |||
222 | return ITEM_NOT_FOUND; | 222 | return ITEM_NOT_FOUND; |
223 | } | 223 | } |
224 | 224 | ||
225 | #ifdef CONFIG_REISERFS_CHECK | ||
226 | extern struct tree_balance *cur_tb; | ||
227 | #endif | ||
228 | 225 | ||
229 | /* Minimal possible key. It is never in the tree. */ | 226 | /* Minimal possible key. It is never in the tree. */ |
230 | const struct reiserfs_key MIN_KEY = { 0, 0, {{0, 0},} }; | 227 | const struct reiserfs_key MIN_KEY = { 0, 0, {{0, 0},} }; |
@@ -519,25 +516,48 @@ static int is_tree_node(struct buffer_head *bh, int level) | |||
519 | 516 | ||
520 | #define SEARCH_BY_KEY_READA 16 | 517 | #define SEARCH_BY_KEY_READA 16 |
521 | 518 | ||
522 | /* The function is NOT SCHEDULE-SAFE! */ | 519 | /* |
523 | static void search_by_key_reada(struct super_block *s, | 520 | * The function is NOT SCHEDULE-SAFE! |
521 | * It might unlock the write lock if we needed to wait for a block | ||
522 | * to be read. Note that in this case it won't recover the lock to avoid | ||
523 | * high contention resulting from too much lock requests, especially | ||
524 | * the caller (search_by_key) will perform other schedule-unsafe | ||
525 | * operations just after calling this function. | ||
526 | * | ||
527 | * @return true if we have unlocked | ||
528 | */ | ||
529 | static bool search_by_key_reada(struct super_block *s, | ||
524 | struct buffer_head **bh, | 530 | struct buffer_head **bh, |
525 | b_blocknr_t *b, int num) | 531 | b_blocknr_t *b, int num) |
526 | { | 532 | { |
527 | int i, j; | 533 | int i, j; |
534 | bool unlocked = false; | ||
528 | 535 | ||
529 | for (i = 0; i < num; i++) { | 536 | for (i = 0; i < num; i++) { |
530 | bh[i] = sb_getblk(s, b[i]); | 537 | bh[i] = sb_getblk(s, b[i]); |
531 | } | 538 | } |
539 | /* | ||
540 | * We are going to read some blocks on which we | ||
541 | * have a reference. It's safe, though we might be | ||
542 | * reading blocks concurrently changed if we release | ||
543 | * the lock. But it's still fine because we check later | ||
544 | * if the tree changed | ||
545 | */ | ||
532 | for (j = 0; j < i; j++) { | 546 | for (j = 0; j < i; j++) { |
533 | /* | 547 | /* |
534 | * note, this needs attention if we are getting rid of the BKL | 548 | * note, this needs attention if we are getting rid of the BKL |
535 | * you have to make sure the prepared bit isn't set on this buffer | 549 | * you have to make sure the prepared bit isn't set on this buffer |
536 | */ | 550 | */ |
537 | if (!buffer_uptodate(bh[j])) | 551 | if (!buffer_uptodate(bh[j])) { |
552 | if (!unlocked) { | ||
553 | reiserfs_write_unlock(s); | ||
554 | unlocked = true; | ||
555 | } | ||
538 | ll_rw_block(READA, 1, bh + j); | 556 | ll_rw_block(READA, 1, bh + j); |
557 | } | ||
539 | brelse(bh[j]); | 558 | brelse(bh[j]); |
540 | } | 559 | } |
560 | return unlocked; | ||
541 | } | 561 | } |
542 | 562 | ||
543 | /************************************************************************** | 563 | /************************************************************************** |
@@ -625,11 +645,26 @@ int search_by_key(struct super_block *sb, const struct cpu_key *key, /* Key to s | |||
625 | have a pointer to it. */ | 645 | have a pointer to it. */ |
626 | if ((bh = last_element->pe_buffer = | 646 | if ((bh = last_element->pe_buffer = |
627 | sb_getblk(sb, block_number))) { | 647 | sb_getblk(sb, block_number))) { |
648 | bool unlocked = false; | ||
649 | |||
628 | if (!buffer_uptodate(bh) && reada_count > 1) | 650 | if (!buffer_uptodate(bh) && reada_count > 1) |
629 | search_by_key_reada(sb, reada_bh, | 651 | /* may unlock the write lock */ |
652 | unlocked = search_by_key_reada(sb, reada_bh, | ||
630 | reada_blocks, reada_count); | 653 | reada_blocks, reada_count); |
654 | /* | ||
655 | * If we haven't already unlocked the write lock, | ||
656 | * then we need to do that here before reading | ||
657 | * the current block | ||
658 | */ | ||
659 | if (!buffer_uptodate(bh) && !unlocked) { | ||
660 | reiserfs_write_unlock(sb); | ||
661 | unlocked = true; | ||
662 | } | ||
631 | ll_rw_block(READ, 1, &bh); | 663 | ll_rw_block(READ, 1, &bh); |
632 | wait_on_buffer(bh); | 664 | wait_on_buffer(bh); |
665 | |||
666 | if (unlocked) | ||
667 | reiserfs_write_lock(sb); | ||
633 | if (!buffer_uptodate(bh)) | 668 | if (!buffer_uptodate(bh)) |
634 | goto io_error; | 669 | goto io_error; |
635 | } else { | 670 | } else { |
@@ -673,7 +708,7 @@ int search_by_key(struct super_block *sb, const struct cpu_key *key, /* Key to s | |||
673 | !key_in_buffer(search_path, key, sb), | 708 | !key_in_buffer(search_path, key, sb), |
674 | "PAP-5130: key is not in the buffer"); | 709 | "PAP-5130: key is not in the buffer"); |
675 | #ifdef CONFIG_REISERFS_CHECK | 710 | #ifdef CONFIG_REISERFS_CHECK |
676 | if (cur_tb) { | 711 | if (REISERFS_SB(sb)->cur_tb) { |
677 | print_cur_tb("5140"); | 712 | print_cur_tb("5140"); |
678 | reiserfs_panic(sb, "PAP-5140", | 713 | reiserfs_panic(sb, "PAP-5140", |
679 | "schedule occurred in do_balance!"); | 714 | "schedule occurred in do_balance!"); |
@@ -1024,7 +1059,9 @@ static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, st | |||
1024 | reiserfs_free_block(th, inode, block, 1); | 1059 | reiserfs_free_block(th, inode, block, 1); |
1025 | } | 1060 | } |
1026 | 1061 | ||
1062 | reiserfs_write_unlock(sb); | ||
1027 | cond_resched(); | 1063 | cond_resched(); |
1064 | reiserfs_write_lock(sb); | ||
1028 | 1065 | ||
1029 | if (item_moved (&s_ih, path)) { | 1066 | if (item_moved (&s_ih, path)) { |
1030 | need_re_search = 1; | 1067 | need_re_search = 1; |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index f0ad05f38022..339b0baf2af6 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -465,7 +465,7 @@ static void reiserfs_put_super(struct super_block *s) | |||
465 | struct reiserfs_transaction_handle th; | 465 | struct reiserfs_transaction_handle th; |
466 | th.t_trans_id = 0; | 466 | th.t_trans_id = 0; |
467 | 467 | ||
468 | lock_kernel(); | 468 | reiserfs_write_lock(s); |
469 | 469 | ||
470 | if (s->s_dirt) | 470 | if (s->s_dirt) |
471 | reiserfs_write_super(s); | 471 | reiserfs_write_super(s); |
@@ -499,10 +499,10 @@ static void reiserfs_put_super(struct super_block *s) | |||
499 | 499 | ||
500 | reiserfs_proc_info_done(s); | 500 | reiserfs_proc_info_done(s); |
501 | 501 | ||
502 | reiserfs_write_unlock(s); | ||
503 | mutex_destroy(&REISERFS_SB(s)->lock); | ||
502 | kfree(s->s_fs_info); | 504 | kfree(s->s_fs_info); |
503 | s->s_fs_info = NULL; | 505 | s->s_fs_info = NULL; |
504 | |||
505 | unlock_kernel(); | ||
506 | } | 506 | } |
507 | 507 | ||
508 | static struct kmem_cache *reiserfs_inode_cachep; | 508 | static struct kmem_cache *reiserfs_inode_cachep; |
@@ -554,25 +554,28 @@ static void reiserfs_dirty_inode(struct inode *inode) | |||
554 | struct reiserfs_transaction_handle th; | 554 | struct reiserfs_transaction_handle th; |
555 | 555 | ||
556 | int err = 0; | 556 | int err = 0; |
557 | int lock_depth; | ||
558 | |||
557 | if (inode->i_sb->s_flags & MS_RDONLY) { | 559 | if (inode->i_sb->s_flags & MS_RDONLY) { |
558 | reiserfs_warning(inode->i_sb, "clm-6006", | 560 | reiserfs_warning(inode->i_sb, "clm-6006", |
559 | "writing inode %lu on readonly FS", | 561 | "writing inode %lu on readonly FS", |
560 | inode->i_ino); | 562 | inode->i_ino); |
561 | return; | 563 | return; |
562 | } | 564 | } |
563 | reiserfs_write_lock(inode->i_sb); | 565 | lock_depth = reiserfs_write_lock_once(inode->i_sb); |
564 | 566 | ||
565 | /* this is really only used for atime updates, so they don't have | 567 | /* this is really only used for atime updates, so they don't have |
566 | ** to be included in O_SYNC or fsync | 568 | ** to be included in O_SYNC or fsync |
567 | */ | 569 | */ |
568 | err = journal_begin(&th, inode->i_sb, 1); | 570 | err = journal_begin(&th, inode->i_sb, 1); |
569 | if (err) { | 571 | if (err) |
570 | reiserfs_write_unlock(inode->i_sb); | 572 | goto out; |
571 | return; | 573 | |
572 | } | ||
573 | reiserfs_update_sd(&th, inode); | 574 | reiserfs_update_sd(&th, inode); |
574 | journal_end(&th, inode->i_sb, 1); | 575 | journal_end(&th, inode->i_sb, 1); |
575 | reiserfs_write_unlock(inode->i_sb); | 576 | |
577 | out: | ||
578 | reiserfs_write_unlock_once(inode->i_sb, lock_depth); | ||
576 | } | 579 | } |
577 | 580 | ||
578 | #ifdef CONFIG_QUOTA | 581 | #ifdef CONFIG_QUOTA |
@@ -1168,11 +1171,14 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) | |||
1168 | unsigned int qfmt = 0; | 1171 | unsigned int qfmt = 0; |
1169 | #ifdef CONFIG_QUOTA | 1172 | #ifdef CONFIG_QUOTA |
1170 | int i; | 1173 | int i; |
1174 | #endif | ||
1175 | |||
1176 | reiserfs_write_lock(s); | ||
1171 | 1177 | ||
1178 | #ifdef CONFIG_QUOTA | ||
1172 | memcpy(qf_names, REISERFS_SB(s)->s_qf_names, sizeof(qf_names)); | 1179 | memcpy(qf_names, REISERFS_SB(s)->s_qf_names, sizeof(qf_names)); |
1173 | #endif | 1180 | #endif |
1174 | 1181 | ||
1175 | lock_kernel(); | ||
1176 | rs = SB_DISK_SUPER_BLOCK(s); | 1182 | rs = SB_DISK_SUPER_BLOCK(s); |
1177 | 1183 | ||
1178 | if (!reiserfs_parse_options | 1184 | if (!reiserfs_parse_options |
@@ -1295,12 +1301,12 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) | |||
1295 | 1301 | ||
1296 | out_ok: | 1302 | out_ok: |
1297 | replace_mount_options(s, new_opts); | 1303 | replace_mount_options(s, new_opts); |
1298 | unlock_kernel(); | 1304 | reiserfs_write_unlock(s); |
1299 | return 0; | 1305 | return 0; |
1300 | 1306 | ||
1301 | out_err: | 1307 | out_err: |
1302 | kfree(new_opts); | 1308 | kfree(new_opts); |
1303 | unlock_kernel(); | 1309 | reiserfs_write_unlock(s); |
1304 | return err; | 1310 | return err; |
1305 | } | 1311 | } |
1306 | 1312 | ||
@@ -1404,7 +1410,9 @@ static int read_super_block(struct super_block *s, int offset) | |||
1404 | static int reread_meta_blocks(struct super_block *s) | 1410 | static int reread_meta_blocks(struct super_block *s) |
1405 | { | 1411 | { |
1406 | ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s))); | 1412 | ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s))); |
1413 | reiserfs_write_unlock(s); | ||
1407 | wait_on_buffer(SB_BUFFER_WITH_SB(s)); | 1414 | wait_on_buffer(SB_BUFFER_WITH_SB(s)); |
1415 | reiserfs_write_lock(s); | ||
1408 | if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) { | 1416 | if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) { |
1409 | reiserfs_warning(s, "reiserfs-2504", "error reading the super"); | 1417 | reiserfs_warning(s, "reiserfs-2504", "error reading the super"); |
1410 | return 1; | 1418 | return 1; |
@@ -1613,7 +1621,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) | |||
1613 | sbi = kzalloc(sizeof(struct reiserfs_sb_info), GFP_KERNEL); | 1621 | sbi = kzalloc(sizeof(struct reiserfs_sb_info), GFP_KERNEL); |
1614 | if (!sbi) { | 1622 | if (!sbi) { |
1615 | errval = -ENOMEM; | 1623 | errval = -ENOMEM; |
1616 | goto error; | 1624 | goto error_alloc; |
1617 | } | 1625 | } |
1618 | s->s_fs_info = sbi; | 1626 | s->s_fs_info = sbi; |
1619 | /* Set default values for options: non-aggressive tails, RO on errors */ | 1627 | /* Set default values for options: non-aggressive tails, RO on errors */ |
@@ -1627,6 +1635,20 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) | |||
1627 | /* setup default block allocator options */ | 1635 | /* setup default block allocator options */ |
1628 | reiserfs_init_alloc_options(s); | 1636 | reiserfs_init_alloc_options(s); |
1629 | 1637 | ||
1638 | mutex_init(&REISERFS_SB(s)->lock); | ||
1639 | REISERFS_SB(s)->lock_depth = -1; | ||
1640 | |||
1641 | /* | ||
1642 | * This function is called with the bkl, which also was the old | ||
1643 | * locking used here. | ||
1644 | * do_journal_begin() will soon check if we hold the lock (ie: was the | ||
1645 | * bkl). This is likely because do_journal_begin() has several another | ||
1646 | * callers because at this time, it doesn't seem to be necessary to | ||
1647 | * protect against anything. | ||
1648 | * Anyway, let's be conservative and lock for now. | ||
1649 | */ | ||
1650 | reiserfs_write_lock(s); | ||
1651 | |||
1630 | jdev_name = NULL; | 1652 | jdev_name = NULL; |
1631 | if (reiserfs_parse_options | 1653 | if (reiserfs_parse_options |
1632 | (s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name, | 1654 | (s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name, |
@@ -1852,9 +1874,13 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) | |||
1852 | init_waitqueue_head(&(sbi->s_wait)); | 1874 | init_waitqueue_head(&(sbi->s_wait)); |
1853 | spin_lock_init(&sbi->bitmap_lock); | 1875 | spin_lock_init(&sbi->bitmap_lock); |
1854 | 1876 | ||
1877 | reiserfs_write_unlock(s); | ||
1878 | |||
1855 | return (0); | 1879 | return (0); |
1856 | 1880 | ||
1857 | error: | 1881 | error: |
1882 | reiserfs_write_unlock(s); | ||
1883 | error_alloc: | ||
1858 | if (jinit_done) { /* kill the commit thread, free journal ram */ | 1884 | if (jinit_done) { /* kill the commit thread, free journal ram */ |
1859 | journal_release_error(NULL, s); | 1885 | journal_release_error(NULL, s); |
1860 | } | 1886 | } |
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 6925b835a43b..58aa8e75f7f5 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c | |||
@@ -975,7 +975,7 @@ int reiserfs_lookup_privroot(struct super_block *s) | |||
975 | int err = 0; | 975 | int err = 0; |
976 | 976 | ||
977 | /* If we don't have the privroot located yet - go find it */ | 977 | /* If we don't have the privroot located yet - go find it */ |
978 | mutex_lock(&s->s_root->d_inode->i_mutex); | 978 | reiserfs_mutex_lock_safe(&s->s_root->d_inode->i_mutex, s); |
979 | dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, | 979 | dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, |
980 | strlen(PRIVROOT_NAME)); | 980 | strlen(PRIVROOT_NAME)); |
981 | if (!IS_ERR(dentry)) { | 981 | if (!IS_ERR(dentry)) { |
@@ -1004,14 +1004,14 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags) | |||
1004 | goto error; | 1004 | goto error; |
1005 | 1005 | ||
1006 | if (!privroot->d_inode && !(mount_flags & MS_RDONLY)) { | 1006 | if (!privroot->d_inode && !(mount_flags & MS_RDONLY)) { |
1007 | mutex_lock(&s->s_root->d_inode->i_mutex); | 1007 | reiserfs_mutex_lock_safe(&s->s_root->d_inode->i_mutex, s); |
1008 | err = create_privroot(REISERFS_SB(s)->priv_root); | 1008 | err = create_privroot(REISERFS_SB(s)->priv_root); |
1009 | mutex_unlock(&s->s_root->d_inode->i_mutex); | 1009 | mutex_unlock(&s->s_root->d_inode->i_mutex); |
1010 | } | 1010 | } |
1011 | 1011 | ||
1012 | if (privroot->d_inode) { | 1012 | if (privroot->d_inode) { |
1013 | s->s_xattr = reiserfs_xattr_handlers; | 1013 | s->s_xattr = reiserfs_xattr_handlers; |
1014 | mutex_lock(&privroot->d_inode->i_mutex); | 1014 | reiserfs_mutex_lock_safe(&privroot->d_inode->i_mutex, s); |
1015 | if (!REISERFS_SB(s)->xattr_root) { | 1015 | if (!REISERFS_SB(s)->xattr_root) { |
1016 | struct dentry *dentry; | 1016 | struct dentry *dentry; |
1017 | dentry = lookup_one_len(XAROOT_NAME, privroot, | 1017 | dentry = lookup_one_len(XAROOT_NAME, privroot, |
diff --git a/fs/splice.c b/fs/splice.c index 7394e9e17534..39208663aaf1 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -648,9 +648,11 @@ static int pipe_to_sendpage(struct pipe_inode_info *pipe, | |||
648 | ret = buf->ops->confirm(pipe, buf); | 648 | ret = buf->ops->confirm(pipe, buf); |
649 | if (!ret) { | 649 | if (!ret) { |
650 | more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len; | 650 | more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len; |
651 | 651 | if (file->f_op && file->f_op->sendpage) | |
652 | ret = file->f_op->sendpage(file, buf->page, buf->offset, | 652 | ret = file->f_op->sendpage(file, buf->page, buf->offset, |
653 | sd->len, &pos, more); | 653 | sd->len, &pos, more); |
654 | else | ||
655 | ret = -EINVAL; | ||
654 | } | 656 | } |
655 | 657 | ||
656 | return ret; | 658 | return ret; |
@@ -1068,8 +1070,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, | |||
1068 | if (unlikely(ret < 0)) | 1070 | if (unlikely(ret < 0)) |
1069 | return ret; | 1071 | return ret; |
1070 | 1072 | ||
1071 | splice_write = out->f_op->splice_write; | 1073 | if (out->f_op && out->f_op->splice_write) |
1072 | if (!splice_write) | 1074 | splice_write = out->f_op->splice_write; |
1075 | else | ||
1073 | splice_write = default_file_splice_write; | 1076 | splice_write = default_file_splice_write; |
1074 | 1077 | ||
1075 | return splice_write(pipe, out, ppos, len, flags); | 1078 | return splice_write(pipe, out, ppos, len, flags); |
@@ -1093,8 +1096,9 @@ static long do_splice_to(struct file *in, loff_t *ppos, | |||
1093 | if (unlikely(ret < 0)) | 1096 | if (unlikely(ret < 0)) |
1094 | return ret; | 1097 | return ret; |
1095 | 1098 | ||
1096 | splice_read = in->f_op->splice_read; | 1099 | if (in->f_op && in->f_op->splice_read) |
1097 | if (!splice_read) | 1100 | splice_read = in->f_op->splice_read; |
1101 | else | ||
1098 | splice_read = default_file_splice_read; | 1102 | splice_read = default_file_splice_read; |
1099 | 1103 | ||
1100 | return splice_read(in, ppos, pipe, len, flags); | 1104 | return splice_read(in, ppos, pipe, len, flags); |
@@ -1316,7 +1320,8 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
1316 | if (off_in) | 1320 | if (off_in) |
1317 | return -ESPIPE; | 1321 | return -ESPIPE; |
1318 | if (off_out) { | 1322 | if (off_out) { |
1319 | if (out->f_op->llseek == no_llseek) | 1323 | if (!out->f_op || !out->f_op->llseek || |
1324 | out->f_op->llseek == no_llseek) | ||
1320 | return -EINVAL; | 1325 | return -EINVAL; |
1321 | if (copy_from_user(&offset, off_out, sizeof(loff_t))) | 1326 | if (copy_from_user(&offset, off_out, sizeof(loff_t))) |
1322 | return -EFAULT; | 1327 | return -EFAULT; |
@@ -1336,7 +1341,8 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
1336 | if (off_out) | 1341 | if (off_out) |
1337 | return -ESPIPE; | 1342 | return -ESPIPE; |
1338 | if (off_in) { | 1343 | if (off_in) { |
1339 | if (in->f_op->llseek == no_llseek) | 1344 | if (!in->f_op || !in->f_op->llseek || |
1345 | in->f_op->llseek == no_llseek) | ||
1340 | return -EINVAL; | 1346 | return -EINVAL; |
1341 | if (copy_from_user(&offset, off_in, sizeof(loff_t))) | 1347 | if (copy_from_user(&offset, off_in, sizeof(loff_t))) |
1342 | return -EFAULT; | 1348 | return -EFAULT; |
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index dbc093afd946..8a771c59ac3e 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c | |||
@@ -2014,7 +2014,7 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr, | |||
2014 | inum = key_inum_flash(c, &dent->key); | 2014 | inum = key_inum_flash(c, &dent->key); |
2015 | fscki1 = read_add_inode(c, priv, inum); | 2015 | fscki1 = read_add_inode(c, priv, inum); |
2016 | if (IS_ERR(fscki1)) { | 2016 | if (IS_ERR(fscki1)) { |
2017 | err = PTR_ERR(fscki); | 2017 | err = PTR_ERR(fscki1); |
2018 | ubifs_err("error %d while processing entry node and " | 2018 | ubifs_err("error %d while processing entry node and " |
2019 | "trying to find parent inode node %lu", | 2019 | "trying to find parent inode node %lu", |
2020 | err, (unsigned long)inum); | 2020 | err, (unsigned long)inum); |
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 1009adc8d602..39849f887e72 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c | |||
@@ -1389,7 +1389,6 @@ static ssize_t ubifs_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
1389 | unsigned long nr_segs, loff_t pos) | 1389 | unsigned long nr_segs, loff_t pos) |
1390 | { | 1390 | { |
1391 | int err; | 1391 | int err; |
1392 | ssize_t ret; | ||
1393 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 1392 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
1394 | struct ubifs_info *c = inode->i_sb->s_fs_info; | 1393 | struct ubifs_info *c = inode->i_sb->s_fs_info; |
1395 | 1394 | ||
@@ -1397,17 +1396,7 @@ static ssize_t ubifs_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
1397 | if (err) | 1396 | if (err) |
1398 | return err; | 1397 | return err; |
1399 | 1398 | ||
1400 | ret = generic_file_aio_write(iocb, iov, nr_segs, pos); | 1399 | return generic_file_aio_write(iocb, iov, nr_segs, pos); |
1401 | if (ret < 0) | ||
1402 | return ret; | ||
1403 | |||
1404 | if (ret > 0 && (IS_SYNC(inode) || iocb->ki_filp->f_flags & O_SYNC)) { | ||
1405 | err = ubifs_sync_wbufs_by_inode(c, inode); | ||
1406 | if (err) | ||
1407 | return err; | ||
1408 | } | ||
1409 | |||
1410 | return ret; | ||
1411 | } | 1400 | } |
1412 | 1401 | ||
1413 | static int ubifs_set_page_dirty(struct page *page) | 1402 | static int ubifs_set_page_dirty(struct page *page) |
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index f94ddf7efba0..868a55ee080f 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c | |||
@@ -23,7 +23,7 @@ | |||
23 | /* | 23 | /* |
24 | * This file implements functions needed to recover from unclean un-mounts. | 24 | * This file implements functions needed to recover from unclean un-mounts. |
25 | * When UBIFS is mounted, it checks a flag on the master node to determine if | 25 | * When UBIFS is mounted, it checks a flag on the master node to determine if |
26 | * an un-mount was completed sucessfully. If not, the process of mounting | 26 | * an un-mount was completed successfully. If not, the process of mounting |
27 | * incorparates additional checking and fixing of on-flash data structures. | 27 | * incorparates additional checking and fixing of on-flash data structures. |
28 | * UBIFS always cleans away all remnants of an unclean un-mount, so that | 28 | * UBIFS always cleans away all remnants of an unclean un-mount, so that |
29 | * errors do not accumulate. However UBIFS defers recovery if it is mounted | 29 | * errors do not accumulate. However UBIFS defers recovery if it is mounted |
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 333e181ee987..943ad5624530 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
@@ -1842,22 +1842,32 @@ const struct super_operations ubifs_super_operations = { | |||
1842 | * @name: UBI volume name | 1842 | * @name: UBI volume name |
1843 | * @mode: UBI volume open mode | 1843 | * @mode: UBI volume open mode |
1844 | * | 1844 | * |
1845 | * There are several ways to specify UBI volumes when mounting UBIFS: | 1845 | * The primary method of mounting UBIFS is by specifying the UBI volume |
1846 | * o ubiX_Y - UBI device number X, volume Y; | 1846 | * character device node path. However, UBIFS may also be mounted withoug any |
1847 | * o ubiY - UBI device number 0, volume Y; | 1847 | * character device node using one of the following methods: |
1848 | * | ||
1849 | * o ubiX_Y - mount UBI device number X, volume Y; | ||
1850 | * o ubiY - mount UBI device number 0, volume Y; | ||
1848 | * o ubiX:NAME - mount UBI device X, volume with name NAME; | 1851 | * o ubiX:NAME - mount UBI device X, volume with name NAME; |
1849 | * o ubi:NAME - mount UBI device 0, volume with name NAME. | 1852 | * o ubi:NAME - mount UBI device 0, volume with name NAME. |
1850 | * | 1853 | * |
1851 | * Alternative '!' separator may be used instead of ':' (because some shells | 1854 | * Alternative '!' separator may be used instead of ':' (because some shells |
1852 | * like busybox may interpret ':' as an NFS host name separator). This function | 1855 | * like busybox may interpret ':' as an NFS host name separator). This function |
1853 | * returns ubi volume object in case of success and a negative error code in | 1856 | * returns UBI volume description object in case of success and a negative |
1854 | * case of failure. | 1857 | * error code in case of failure. |
1855 | */ | 1858 | */ |
1856 | static struct ubi_volume_desc *open_ubi(const char *name, int mode) | 1859 | static struct ubi_volume_desc *open_ubi(const char *name, int mode) |
1857 | { | 1860 | { |
1861 | struct ubi_volume_desc *ubi; | ||
1858 | int dev, vol; | 1862 | int dev, vol; |
1859 | char *endptr; | 1863 | char *endptr; |
1860 | 1864 | ||
1865 | /* First, try to open using the device node path method */ | ||
1866 | ubi = ubi_open_volume_path(name, mode); | ||
1867 | if (!IS_ERR(ubi)) | ||
1868 | return ubi; | ||
1869 | |||
1870 | /* Try the "nodev" method */ | ||
1861 | if (name[0] != 'u' || name[1] != 'b' || name[2] != 'i') | 1871 | if (name[0] != 'u' || name[1] != 'b' || name[2] != 'i') |
1862 | return ERR_PTR(-EINVAL); | 1872 | return ERR_PTR(-EINVAL); |
1863 | 1873 | ||
diff --git a/fs/xattr_acl.c b/fs/xattr_acl.c index c6ad7c7e3ee9..05ac0fe9c4d3 100644 --- a/fs/xattr_acl.c +++ b/fs/xattr_acl.c | |||
@@ -36,7 +36,7 @@ posix_acl_from_xattr(const void *value, size_t size) | |||
36 | if (count == 0) | 36 | if (count == 0) |
37 | return NULL; | 37 | return NULL; |
38 | 38 | ||
39 | acl = posix_acl_alloc(count, GFP_KERNEL); | 39 | acl = posix_acl_alloc(count, GFP_NOFS); |
40 | if (!acl) | 40 | if (!acl) |
41 | return ERR_PTR(-ENOMEM); | 41 | return ERR_PTR(-ENOMEM); |
42 | acl_e = acl->a_entries; | 42 | acl_e = acl->a_entries; |
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index c2e30eea74dc..70f989895d15 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -904,16 +904,9 @@ xfs_convert_page( | |||
904 | 904 | ||
905 | if (startio) { | 905 | if (startio) { |
906 | if (count) { | 906 | if (count) { |
907 | struct backing_dev_info *bdi; | ||
908 | |||
909 | bdi = inode->i_mapping->backing_dev_info; | ||
910 | wbc->nr_to_write--; | 907 | wbc->nr_to_write--; |
911 | if (bdi_write_congested(bdi)) { | 908 | if (wbc->nr_to_write <= 0) |
912 | wbc->encountered_congestion = 1; | ||
913 | done = 1; | ||
914 | } else if (wbc->nr_to_write <= 0) { | ||
915 | done = 1; | 909 | done = 1; |
916 | } | ||
917 | } | 910 | } |
918 | xfs_start_page_writeback(page, !page_dirty, count); | 911 | xfs_start_page_writeback(page, !page_dirty, count); |
919 | } | 912 | } |
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c index c5bc67c4e3bb..7bb5092d6ae4 100644 --- a/fs/xfs/linux-2.6/xfs_sysctl.c +++ b/fs/xfs/linux-2.6/xfs_sysctl.c | |||
@@ -55,170 +55,140 @@ xfs_stats_clear_proc_handler( | |||
55 | 55 | ||
56 | static ctl_table xfs_table[] = { | 56 | static ctl_table xfs_table[] = { |
57 | { | 57 | { |
58 | .ctl_name = XFS_SGID_INHERIT, | ||
59 | .procname = "irix_sgid_inherit", | 58 | .procname = "irix_sgid_inherit", |
60 | .data = &xfs_params.sgid_inherit.val, | 59 | .data = &xfs_params.sgid_inherit.val, |
61 | .maxlen = sizeof(int), | 60 | .maxlen = sizeof(int), |
62 | .mode = 0644, | 61 | .mode = 0644, |
63 | .proc_handler = &proc_dointvec_minmax, | 62 | .proc_handler = proc_dointvec_minmax, |
64 | .strategy = &sysctl_intvec, | ||
65 | .extra1 = &xfs_params.sgid_inherit.min, | 63 | .extra1 = &xfs_params.sgid_inherit.min, |
66 | .extra2 = &xfs_params.sgid_inherit.max | 64 | .extra2 = &xfs_params.sgid_inherit.max |
67 | }, | 65 | }, |
68 | { | 66 | { |
69 | .ctl_name = XFS_SYMLINK_MODE, | ||
70 | .procname = "irix_symlink_mode", | 67 | .procname = "irix_symlink_mode", |
71 | .data = &xfs_params.symlink_mode.val, | 68 | .data = &xfs_params.symlink_mode.val, |
72 | .maxlen = sizeof(int), | 69 | .maxlen = sizeof(int), |
73 | .mode = 0644, | 70 | .mode = 0644, |
74 | .proc_handler = &proc_dointvec_minmax, | 71 | .proc_handler = proc_dointvec_minmax, |
75 | .strategy = &sysctl_intvec, | ||
76 | .extra1 = &xfs_params.symlink_mode.min, | 72 | .extra1 = &xfs_params.symlink_mode.min, |
77 | .extra2 = &xfs_params.symlink_mode.max | 73 | .extra2 = &xfs_params.symlink_mode.max |
78 | }, | 74 | }, |
79 | { | 75 | { |
80 | .ctl_name = XFS_PANIC_MASK, | ||
81 | .procname = "panic_mask", | 76 | .procname = "panic_mask", |
82 | .data = &xfs_params.panic_mask.val, | 77 | .data = &xfs_params.panic_mask.val, |
83 | .maxlen = sizeof(int), | 78 | .maxlen = sizeof(int), |
84 | .mode = 0644, | 79 | .mode = 0644, |
85 | .proc_handler = &proc_dointvec_minmax, | 80 | .proc_handler = proc_dointvec_minmax, |
86 | .strategy = &sysctl_intvec, | ||
87 | .extra1 = &xfs_params.panic_mask.min, | 81 | .extra1 = &xfs_params.panic_mask.min, |
88 | .extra2 = &xfs_params.panic_mask.max | 82 | .extra2 = &xfs_params.panic_mask.max |
89 | }, | 83 | }, |
90 | 84 | ||
91 | { | 85 | { |
92 | .ctl_name = XFS_ERRLEVEL, | ||
93 | .procname = "error_level", | 86 | .procname = "error_level", |
94 | .data = &xfs_params.error_level.val, | 87 | .data = &xfs_params.error_level.val, |
95 | .maxlen = sizeof(int), | 88 | .maxlen = sizeof(int), |
96 | .mode = 0644, | 89 | .mode = 0644, |
97 | .proc_handler = &proc_dointvec_minmax, | 90 | .proc_handler = proc_dointvec_minmax, |
98 | .strategy = &sysctl_intvec, | ||
99 | .extra1 = &xfs_params.error_level.min, | 91 | .extra1 = &xfs_params.error_level.min, |
100 | .extra2 = &xfs_params.error_level.max | 92 | .extra2 = &xfs_params.error_level.max |
101 | }, | 93 | }, |
102 | { | 94 | { |
103 | .ctl_name = XFS_SYNCD_TIMER, | ||
104 | .procname = "xfssyncd_centisecs", | 95 | .procname = "xfssyncd_centisecs", |
105 | .data = &xfs_params.syncd_timer.val, | 96 | .data = &xfs_params.syncd_timer.val, |
106 | .maxlen = sizeof(int), | 97 | .maxlen = sizeof(int), |
107 | .mode = 0644, | 98 | .mode = 0644, |
108 | .proc_handler = &proc_dointvec_minmax, | 99 | .proc_handler = proc_dointvec_minmax, |
109 | .strategy = &sysctl_intvec, | ||
110 | .extra1 = &xfs_params.syncd_timer.min, | 100 | .extra1 = &xfs_params.syncd_timer.min, |
111 | .extra2 = &xfs_params.syncd_timer.max | 101 | .extra2 = &xfs_params.syncd_timer.max |
112 | }, | 102 | }, |
113 | { | 103 | { |
114 | .ctl_name = XFS_INHERIT_SYNC, | ||
115 | .procname = "inherit_sync", | 104 | .procname = "inherit_sync", |
116 | .data = &xfs_params.inherit_sync.val, | 105 | .data = &xfs_params.inherit_sync.val, |
117 | .maxlen = sizeof(int), | 106 | .maxlen = sizeof(int), |
118 | .mode = 0644, | 107 | .mode = 0644, |
119 | .proc_handler = &proc_dointvec_minmax, | 108 | .proc_handler = proc_dointvec_minmax, |
120 | .strategy = &sysctl_intvec, | ||
121 | .extra1 = &xfs_params.inherit_sync.min, | 109 | .extra1 = &xfs_params.inherit_sync.min, |
122 | .extra2 = &xfs_params.inherit_sync.max | 110 | .extra2 = &xfs_params.inherit_sync.max |
123 | }, | 111 | }, |
124 | { | 112 | { |
125 | .ctl_name = XFS_INHERIT_NODUMP, | ||
126 | .procname = "inherit_nodump", | 113 | .procname = "inherit_nodump", |
127 | .data = &xfs_params.inherit_nodump.val, | 114 | .data = &xfs_params.inherit_nodump.val, |
128 | .maxlen = sizeof(int), | 115 | .maxlen = sizeof(int), |
129 | .mode = 0644, | 116 | .mode = 0644, |
130 | .proc_handler = &proc_dointvec_minmax, | 117 | .proc_handler = proc_dointvec_minmax, |
131 | .strategy = &sysctl_intvec, | ||
132 | .extra1 = &xfs_params.inherit_nodump.min, | 118 | .extra1 = &xfs_params.inherit_nodump.min, |
133 | .extra2 = &xfs_params.inherit_nodump.max | 119 | .extra2 = &xfs_params.inherit_nodump.max |
134 | }, | 120 | }, |
135 | { | 121 | { |
136 | .ctl_name = XFS_INHERIT_NOATIME, | ||
137 | .procname = "inherit_noatime", | 122 | .procname = "inherit_noatime", |
138 | .data = &xfs_params.inherit_noatim.val, | 123 | .data = &xfs_params.inherit_noatim.val, |
139 | .maxlen = sizeof(int), | 124 | .maxlen = sizeof(int), |
140 | .mode = 0644, | 125 | .mode = 0644, |
141 | .proc_handler = &proc_dointvec_minmax, | 126 | .proc_handler = proc_dointvec_minmax, |
142 | .strategy = &sysctl_intvec, | ||
143 | .extra1 = &xfs_params.inherit_noatim.min, | 127 | .extra1 = &xfs_params.inherit_noatim.min, |
144 | .extra2 = &xfs_params.inherit_noatim.max | 128 | .extra2 = &xfs_params.inherit_noatim.max |
145 | }, | 129 | }, |
146 | { | 130 | { |
147 | .ctl_name = XFS_BUF_TIMER, | ||
148 | .procname = "xfsbufd_centisecs", | 131 | .procname = "xfsbufd_centisecs", |
149 | .data = &xfs_params.xfs_buf_timer.val, | 132 | .data = &xfs_params.xfs_buf_timer.val, |
150 | .maxlen = sizeof(int), | 133 | .maxlen = sizeof(int), |
151 | .mode = 0644, | 134 | .mode = 0644, |
152 | .proc_handler = &proc_dointvec_minmax, | 135 | .proc_handler = proc_dointvec_minmax, |
153 | .strategy = &sysctl_intvec, | ||
154 | .extra1 = &xfs_params.xfs_buf_timer.min, | 136 | .extra1 = &xfs_params.xfs_buf_timer.min, |
155 | .extra2 = &xfs_params.xfs_buf_timer.max | 137 | .extra2 = &xfs_params.xfs_buf_timer.max |
156 | }, | 138 | }, |
157 | { | 139 | { |
158 | .ctl_name = XFS_BUF_AGE, | ||
159 | .procname = "age_buffer_centisecs", | 140 | .procname = "age_buffer_centisecs", |
160 | .data = &xfs_params.xfs_buf_age.val, | 141 | .data = &xfs_params.xfs_buf_age.val, |
161 | .maxlen = sizeof(int), | 142 | .maxlen = sizeof(int), |
162 | .mode = 0644, | 143 | .mode = 0644, |
163 | .proc_handler = &proc_dointvec_minmax, | 144 | .proc_handler = proc_dointvec_minmax, |
164 | .strategy = &sysctl_intvec, | ||
165 | .extra1 = &xfs_params.xfs_buf_age.min, | 145 | .extra1 = &xfs_params.xfs_buf_age.min, |
166 | .extra2 = &xfs_params.xfs_buf_age.max | 146 | .extra2 = &xfs_params.xfs_buf_age.max |
167 | }, | 147 | }, |
168 | { | 148 | { |
169 | .ctl_name = XFS_INHERIT_NOSYM, | ||
170 | .procname = "inherit_nosymlinks", | 149 | .procname = "inherit_nosymlinks", |
171 | .data = &xfs_params.inherit_nosym.val, | 150 | .data = &xfs_params.inherit_nosym.val, |
172 | .maxlen = sizeof(int), | 151 | .maxlen = sizeof(int), |
173 | .mode = 0644, | 152 | .mode = 0644, |
174 | .proc_handler = &proc_dointvec_minmax, | 153 | .proc_handler = proc_dointvec_minmax, |
175 | .strategy = &sysctl_intvec, | ||
176 | .extra1 = &xfs_params.inherit_nosym.min, | 154 | .extra1 = &xfs_params.inherit_nosym.min, |
177 | .extra2 = &xfs_params.inherit_nosym.max | 155 | .extra2 = &xfs_params.inherit_nosym.max |
178 | }, | 156 | }, |
179 | { | 157 | { |
180 | .ctl_name = XFS_ROTORSTEP, | ||
181 | .procname = "rotorstep", | 158 | .procname = "rotorstep", |
182 | .data = &xfs_params.rotorstep.val, | 159 | .data = &xfs_params.rotorstep.val, |
183 | .maxlen = sizeof(int), | 160 | .maxlen = sizeof(int), |
184 | .mode = 0644, | 161 | .mode = 0644, |
185 | .proc_handler = &proc_dointvec_minmax, | 162 | .proc_handler = proc_dointvec_minmax, |
186 | .strategy = &sysctl_intvec, | ||
187 | .extra1 = &xfs_params.rotorstep.min, | 163 | .extra1 = &xfs_params.rotorstep.min, |
188 | .extra2 = &xfs_params.rotorstep.max | 164 | .extra2 = &xfs_params.rotorstep.max |
189 | }, | 165 | }, |
190 | { | 166 | { |
191 | .ctl_name = XFS_INHERIT_NODFRG, | ||
192 | .procname = "inherit_nodefrag", | 167 | .procname = "inherit_nodefrag", |
193 | .data = &xfs_params.inherit_nodfrg.val, | 168 | .data = &xfs_params.inherit_nodfrg.val, |
194 | .maxlen = sizeof(int), | 169 | .maxlen = sizeof(int), |
195 | .mode = 0644, | 170 | .mode = 0644, |
196 | .proc_handler = &proc_dointvec_minmax, | 171 | .proc_handler = proc_dointvec_minmax, |
197 | .strategy = &sysctl_intvec, | ||
198 | .extra1 = &xfs_params.inherit_nodfrg.min, | 172 | .extra1 = &xfs_params.inherit_nodfrg.min, |
199 | .extra2 = &xfs_params.inherit_nodfrg.max | 173 | .extra2 = &xfs_params.inherit_nodfrg.max |
200 | }, | 174 | }, |
201 | { | 175 | { |
202 | .ctl_name = XFS_FILESTREAM_TIMER, | ||
203 | .procname = "filestream_centisecs", | 176 | .procname = "filestream_centisecs", |
204 | .data = &xfs_params.fstrm_timer.val, | 177 | .data = &xfs_params.fstrm_timer.val, |
205 | .maxlen = sizeof(int), | 178 | .maxlen = sizeof(int), |
206 | .mode = 0644, | 179 | .mode = 0644, |
207 | .proc_handler = &proc_dointvec_minmax, | 180 | .proc_handler = proc_dointvec_minmax, |
208 | .strategy = &sysctl_intvec, | ||
209 | .extra1 = &xfs_params.fstrm_timer.min, | 181 | .extra1 = &xfs_params.fstrm_timer.min, |
210 | .extra2 = &xfs_params.fstrm_timer.max, | 182 | .extra2 = &xfs_params.fstrm_timer.max, |
211 | }, | 183 | }, |
212 | /* please keep this the last entry */ | 184 | /* please keep this the last entry */ |
213 | #ifdef CONFIG_PROC_FS | 185 | #ifdef CONFIG_PROC_FS |
214 | { | 186 | { |
215 | .ctl_name = XFS_STATS_CLEAR, | ||
216 | .procname = "stats_clear", | 187 | .procname = "stats_clear", |
217 | .data = &xfs_params.stats_clear.val, | 188 | .data = &xfs_params.stats_clear.val, |
218 | .maxlen = sizeof(int), | 189 | .maxlen = sizeof(int), |
219 | .mode = 0644, | 190 | .mode = 0644, |
220 | .proc_handler = &xfs_stats_clear_proc_handler, | 191 | .proc_handler = xfs_stats_clear_proc_handler, |
221 | .strategy = &sysctl_intvec, | ||
222 | .extra1 = &xfs_params.stats_clear.min, | 192 | .extra1 = &xfs_params.stats_clear.min, |
223 | .extra2 = &xfs_params.stats_clear.max | 193 | .extra2 = &xfs_params.stats_clear.max |
224 | }, | 194 | }, |
@@ -229,7 +199,6 @@ static ctl_table xfs_table[] = { | |||
229 | 199 | ||
230 | static ctl_table xfs_dir_table[] = { | 200 | static ctl_table xfs_dir_table[] = { |
231 | { | 201 | { |
232 | .ctl_name = FS_XFS, | ||
233 | .procname = "xfs", | 202 | .procname = "xfs", |
234 | .mode = 0555, | 203 | .mode = 0555, |
235 | .child = xfs_table | 204 | .child = xfs_table |
@@ -239,7 +208,6 @@ static ctl_table xfs_dir_table[] = { | |||
239 | 208 | ||
240 | static ctl_table xfs_root_table[] = { | 209 | static ctl_table xfs_root_table[] = { |
241 | { | 210 | { |
242 | .ctl_name = CTL_FS, | ||
243 | .procname = "fs", | 211 | .procname = "fs", |
244 | .mode = 0555, | 212 | .mode = 0555, |
245 | .child = xfs_dir_table | 213 | .child = xfs_dir_table |
diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h index 6533ead9b889..a2c16bcee90b 100644 --- a/fs/xfs/quota/xfs_dquot.h +++ b/fs/xfs/quota/xfs_dquot.h | |||
@@ -98,7 +98,7 @@ typedef struct xfs_dquot { | |||
98 | #define dq_flags q_lists.dqm_flags | 98 | #define dq_flags q_lists.dqm_flags |
99 | 99 | ||
100 | /* | 100 | /* |
101 | * Lock hierachy for q_qlock: | 101 | * Lock hierarchy for q_qlock: |
102 | * XFS_QLOCK_NORMAL is the implicit default, | 102 | * XFS_QLOCK_NORMAL is the implicit default, |
103 | * XFS_QLOCK_NESTED is the dquot with the higher id in xfs_dqlock2 | 103 | * XFS_QLOCK_NESTED is the dquot with the higher id in xfs_dqlock2 |
104 | */ | 104 | */ |