diff options
| author | David Woodhouse <David.Woodhouse@intel.com> | 2009-09-20 08:55:36 -0400 |
|---|---|---|
| committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-09-20 08:55:36 -0400 |
| commit | 6469f540ea37d53db089c8fea9c0c77a3d9353d4 (patch) | |
| tree | 1dc9dc077150d57f4424cae49e711b5dd6e903a1 /fs | |
| parent | 304e6d5fe294b80e6d3107f99ec241816390ebcc (diff) | |
| parent | 78f28b7c555359c67c2a0d23f7436e915329421e (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
drivers/mtd/mtdcore.c
Merged in order that I can apply the Nomadik nand/onenand support patches.
Diffstat (limited to 'fs')
221 files changed, 6531 insertions, 5310 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 0e7da7bb5d9..455aa207e67 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
| @@ -43,6 +43,7 @@ source "fs/xfs/Kconfig" | |||
| 43 | source "fs/gfs2/Kconfig" | 43 | source "fs/gfs2/Kconfig" |
| 44 | source "fs/ocfs2/Kconfig" | 44 | source "fs/ocfs2/Kconfig" |
| 45 | source "fs/btrfs/Kconfig" | 45 | source "fs/btrfs/Kconfig" |
| 46 | source "fs/nilfs2/Kconfig" | ||
| 46 | 47 | ||
| 47 | endif # BLOCK | 48 | endif # BLOCK |
| 48 | 49 | ||
| @@ -186,7 +187,6 @@ source "fs/romfs/Kconfig" | |||
| 186 | source "fs/sysv/Kconfig" | 187 | source "fs/sysv/Kconfig" |
| 187 | source "fs/ufs/Kconfig" | 188 | source "fs/ufs/Kconfig" |
| 188 | source "fs/exofs/Kconfig" | 189 | source "fs/exofs/Kconfig" |
| 189 | source "fs/nilfs2/Kconfig" | ||
| 190 | 190 | ||
| 191 | endif # MISC_FILESYSTEMS | 191 | endif # MISC_FILESYSTEMS |
| 192 | 192 | ||
diff --git a/fs/afs/write.c b/fs/afs/write.c index c2e7a7ff008..c63a3c8beb7 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c | |||
| @@ -712,7 +712,6 @@ int afs_writeback_all(struct afs_vnode *vnode) | |||
| 712 | .bdi = mapping->backing_dev_info, | 712 | .bdi = mapping->backing_dev_info, |
| 713 | .sync_mode = WB_SYNC_ALL, | 713 | .sync_mode = WB_SYNC_ALL, |
| 714 | .nr_to_write = LONG_MAX, | 714 | .nr_to_write = LONG_MAX, |
| 715 | .for_writepages = 1, | ||
| 716 | .range_cyclic = 1, | 715 | .range_cyclic = 1, |
| 717 | }; | 716 | }; |
| 718 | int ret; | 717 | int ret; |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index b7c1603cd4b..7c1e65d5487 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
| @@ -501,22 +501,22 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
| 501 | } | 501 | } |
| 502 | } | 502 | } |
| 503 | 503 | ||
| 504 | /* | 504 | if (last_bss > elf_bss) { |
| 505 | * Now fill out the bss section. First pad the last page up | 505 | /* |
| 506 | * to the page boundary, and then perform a mmap to make sure | 506 | * Now fill out the bss section. First pad the last page up |
| 507 | * that there are zero-mapped pages up to and including the | 507 | * to the page boundary, and then perform a mmap to make sure |
| 508 | * last bss page. | 508 | * that there are zero-mapped pages up to and including the |
| 509 | */ | 509 | * last bss page. |
| 510 | if (padzero(elf_bss)) { | 510 | */ |
| 511 | error = -EFAULT; | 511 | if (padzero(elf_bss)) { |
| 512 | goto out_close; | 512 | error = -EFAULT; |
| 513 | } | 513 | goto out_close; |
| 514 | } | ||
| 514 | 515 | ||
| 515 | /* What we have mapped so far */ | 516 | /* What we have mapped so far */ |
| 516 | elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); | 517 | elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); |
| 517 | 518 | ||
| 518 | /* Map the last of the bss segment */ | 519 | /* Map the last of the bss segment */ |
| 519 | if (last_bss > elf_bss) { | ||
| 520 | down_write(¤t->mm->mmap_sem); | 520 | down_write(¤t->mm->mmap_sem); |
| 521 | error = do_brk(elf_bss, last_bss - elf_bss); | 521 | error = do_brk(elf_bss, last_bss - elf_bss); |
| 522 | up_write(¤t->mm->mmap_sem); | 522 | up_write(¤t->mm->mmap_sem); |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 94dfda24c06..71e7e03ac34 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -420,7 +420,6 @@ static void bdev_destroy_inode(struct inode *inode) | |||
| 420 | { | 420 | { |
| 421 | struct bdev_inode *bdi = BDEV_I(inode); | 421 | struct bdev_inode *bdi = BDEV_I(inode); |
| 422 | 422 | ||
| 423 | bdi->bdev.bd_inode_backing_dev_info = NULL; | ||
| 424 | kmem_cache_free(bdev_cachep, bdi); | 423 | kmem_cache_free(bdev_cachep, bdi); |
| 425 | } | 424 | } |
| 426 | 425 | ||
| @@ -1405,6 +1404,33 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
| 1405 | } | 1404 | } |
| 1406 | 1405 | ||
| 1407 | /* | 1406 | /* |
| 1407 | * Write data to the block device. Only intended for the block device itself | ||
| 1408 | * and the raw driver which basically is a fake block device. | ||
| 1409 | * | ||
| 1410 | * Does not take i_mutex for the write and thus is not for general purpose | ||
| 1411 | * use. | ||
| 1412 | */ | ||
| 1413 | ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, | ||
| 1414 | unsigned long nr_segs, loff_t pos) | ||
| 1415 | { | ||
| 1416 | struct file *file = iocb->ki_filp; | ||
| 1417 | ssize_t ret; | ||
| 1418 | |||
| 1419 | BUG_ON(iocb->ki_pos != pos); | ||
| 1420 | |||
| 1421 | ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); | ||
| 1422 | if (ret > 0 || ret == -EIOCBQUEUED) { | ||
| 1423 | ssize_t err; | ||
| 1424 | |||
| 1425 | err = generic_write_sync(file, pos, ret); | ||
| 1426 | if (err < 0 && ret > 0) | ||
| 1427 | ret = err; | ||
| 1428 | } | ||
| 1429 | return ret; | ||
| 1430 | } | ||
| 1431 | EXPORT_SYMBOL_GPL(blkdev_aio_write); | ||
| 1432 | |||
| 1433 | /* | ||
| 1408 | * Try to release a page associated with block device when the system | 1434 | * Try to release a page associated with block device when the system |
| 1409 | * is under memory pressure. | 1435 | * is under memory pressure. |
| 1410 | */ | 1436 | */ |
| @@ -1436,7 +1462,7 @@ const struct file_operations def_blk_fops = { | |||
| 1436 | .read = do_sync_read, | 1462 | .read = do_sync_read, |
| 1437 | .write = do_sync_write, | 1463 | .write = do_sync_write, |
| 1438 | .aio_read = generic_file_aio_read, | 1464 | .aio_read = generic_file_aio_read, |
| 1439 | .aio_write = generic_file_aio_write_nolock, | 1465 | .aio_write = blkdev_aio_write, |
| 1440 | .mmap = generic_file_mmap, | 1466 | .mmap = generic_file_mmap, |
| 1441 | .fsync = block_fsync, | 1467 | .fsync = block_fsync, |
| 1442 | .unlocked_ioctl = block_ioctl, | 1468 | .unlocked_ioctl = block_ioctl, |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e83be2e4602..8b819279001 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -1352,6 +1352,7 @@ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) | |||
| 1352 | { | 1352 | { |
| 1353 | int err; | 1353 | int err; |
| 1354 | 1354 | ||
| 1355 | bdi->name = "btrfs"; | ||
| 1355 | bdi->capabilities = BDI_CAP_MAP_COPY; | 1356 | bdi->capabilities = BDI_CAP_MAP_COPY; |
| 1356 | err = bdi_init(bdi); | 1357 | err = bdi_init(bdi); |
| 1357 | if (err) | 1358 | if (err) |
| @@ -1599,6 +1600,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1599 | 1600 | ||
| 1600 | sb->s_blocksize = 4096; | 1601 | sb->s_blocksize = 4096; |
| 1601 | sb->s_blocksize_bits = blksize_bits(4096); | 1602 | sb->s_blocksize_bits = blksize_bits(4096); |
| 1603 | sb->s_bdi = &fs_info->bdi; | ||
| 1602 | 1604 | ||
| 1603 | /* | 1605 | /* |
| 1604 | * we set the i_size on the btree inode to the max possible int. | 1606 | * we set the i_size on the btree inode to the max possible int. |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 72a2b9c28e9..535f85ba104 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -1511,7 +1511,8 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans, | |||
| 1511 | static void btrfs_issue_discard(struct block_device *bdev, | 1511 | static void btrfs_issue_discard(struct block_device *bdev, |
| 1512 | u64 start, u64 len) | 1512 | u64 start, u64 len) |
| 1513 | { | 1513 | { |
| 1514 | blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL); | 1514 | blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL, |
| 1515 | DISCARD_FL_BARRIER); | ||
| 1515 | } | 1516 | } |
| 1516 | #endif | 1517 | #endif |
| 1517 | 1518 | ||
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index d6f0806c682..7b2f401e604 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
| @@ -740,7 +740,6 @@ int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start, | |||
| 740 | .nr_to_write = mapping->nrpages * 2, | 740 | .nr_to_write = mapping->nrpages * 2, |
| 741 | .range_start = start, | 741 | .range_start = start, |
| 742 | .range_end = end, | 742 | .range_end = end, |
| 743 | .for_writepages = 1, | ||
| 744 | }; | 743 | }; |
| 745 | return btrfs_writepages(mapping, &wbc); | 744 | return btrfs_writepages(mapping, &wbc); |
| 746 | } | 745 | } |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5dbefd11b4a..5cf405b0828 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
| @@ -260,7 +260,7 @@ loop_lock: | |||
| 260 | num_run++; | 260 | num_run++; |
| 261 | batch_run++; | 261 | batch_run++; |
| 262 | 262 | ||
| 263 | if (bio_sync(cur)) | 263 | if (bio_rw_flagged(cur, BIO_RW_SYNCIO)) |
| 264 | num_sync_run++; | 264 | num_sync_run++; |
| 265 | 265 | ||
| 266 | if (need_resched()) { | 266 | if (need_resched()) { |
| @@ -2903,7 +2903,7 @@ static noinline int schedule_bio(struct btrfs_root *root, | |||
| 2903 | bio->bi_rw |= rw; | 2903 | bio->bi_rw |= rw; |
| 2904 | 2904 | ||
| 2905 | spin_lock(&device->io_lock); | 2905 | spin_lock(&device->io_lock); |
| 2906 | if (bio_sync(bio)) | 2906 | if (bio_rw_flagged(bio, BIO_RW_SYNCIO)) |
| 2907 | pending_bios = &device->pending_sync_bios; | 2907 | pending_bios = &device->pending_sync_bios; |
| 2908 | else | 2908 | else |
| 2909 | pending_bios = &device->pending_bios; | 2909 | pending_bios = &device->pending_bios; |
diff --git a/fs/buffer.c b/fs/buffer.c index 28f320fac4d..90a98865b0c 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
| @@ -281,7 +281,7 @@ static void free_more_memory(void) | |||
| 281 | struct zone *zone; | 281 | struct zone *zone; |
| 282 | int nid; | 282 | int nid; |
| 283 | 283 | ||
| 284 | wakeup_pdflush(1024); | 284 | wakeup_flusher_threads(1024); |
| 285 | yield(); | 285 | yield(); |
| 286 | 286 | ||
| 287 | for_each_online_node(nid) { | 287 | for_each_online_node(nid) { |
diff --git a/fs/char_dev.c b/fs/char_dev.c index a173551e19d..3cbc57f932d 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | * - no readahead or I/O queue unplugging required | 31 | * - no readahead or I/O queue unplugging required |
| 32 | */ | 32 | */ |
| 33 | struct backing_dev_info directly_mappable_cdev_bdi = { | 33 | struct backing_dev_info directly_mappable_cdev_bdi = { |
| 34 | .name = "char", | ||
| 34 | .capabilities = ( | 35 | .capabilities = ( |
| 35 | #ifdef CONFIG_MMU | 36 | #ifdef CONFIG_MMU |
| 36 | /* permit private copies of the data to be taken */ | 37 | /* permit private copies of the data to be taken */ |
| @@ -237,8 +238,10 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, | |||
| 237 | } | 238 | } |
| 238 | 239 | ||
| 239 | /** | 240 | /** |
| 240 | * register_chrdev() - Register a major number for character devices. | 241 | * __register_chrdev() - create and register a cdev occupying a range of minors |
| 241 | * @major: major device number or 0 for dynamic allocation | 242 | * @major: major device number or 0 for dynamic allocation |
| 243 | * @baseminor: first of the requested range of minor numbers | ||
| 244 | * @count: the number of minor numbers required | ||
| 242 | * @name: name of this range of devices | 245 | * @name: name of this range of devices |
| 243 | * @fops: file operations associated with this devices | 246 | * @fops: file operations associated with this devices |
| 244 | * | 247 | * |
| @@ -254,19 +257,17 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, | |||
| 254 | * /dev. It only helps to keep track of the different owners of devices. If | 257 | * /dev. It only helps to keep track of the different owners of devices. If |
| 255 | * your module name has only one type of devices it's ok to use e.g. the name | 258 | * your module name has only one type of devices it's ok to use e.g. the name |
| 256 | * of the module here. | 259 | * of the module here. |
| 257 | * | ||
| 258 | * This function registers a range of 256 minor numbers. The first minor number | ||
| 259 | * is 0. | ||
| 260 | */ | 260 | */ |
| 261 | int register_chrdev(unsigned int major, const char *name, | 261 | int __register_chrdev(unsigned int major, unsigned int baseminor, |
| 262 | const struct file_operations *fops) | 262 | unsigned int count, const char *name, |
| 263 | const struct file_operations *fops) | ||
| 263 | { | 264 | { |
| 264 | struct char_device_struct *cd; | 265 | struct char_device_struct *cd; |
| 265 | struct cdev *cdev; | 266 | struct cdev *cdev; |
| 266 | char *s; | 267 | char *s; |
| 267 | int err = -ENOMEM; | 268 | int err = -ENOMEM; |
| 268 | 269 | ||
| 269 | cd = __register_chrdev_region(major, 0, 256, name); | 270 | cd = __register_chrdev_region(major, baseminor, count, name); |
| 270 | if (IS_ERR(cd)) | 271 | if (IS_ERR(cd)) |
| 271 | return PTR_ERR(cd); | 272 | return PTR_ERR(cd); |
| 272 | 273 | ||
| @@ -280,7 +281,7 @@ int register_chrdev(unsigned int major, const char *name, | |||
| 280 | for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/')) | 281 | for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/')) |
| 281 | *s = '!'; | 282 | *s = '!'; |
| 282 | 283 | ||
| 283 | err = cdev_add(cdev, MKDEV(cd->major, 0), 256); | 284 | err = cdev_add(cdev, MKDEV(cd->major, baseminor), count); |
| 284 | if (err) | 285 | if (err) |
| 285 | goto out; | 286 | goto out; |
| 286 | 287 | ||
| @@ -290,7 +291,7 @@ int register_chrdev(unsigned int major, const char *name, | |||
| 290 | out: | 291 | out: |
| 291 | kobject_put(&cdev->kobj); | 292 | kobject_put(&cdev->kobj); |
| 292 | out2: | 293 | out2: |
| 293 | kfree(__unregister_chrdev_region(cd->major, 0, 256)); | 294 | kfree(__unregister_chrdev_region(cd->major, baseminor, count)); |
| 294 | return err; | 295 | return err; |
| 295 | } | 296 | } |
| 296 | 297 | ||
| @@ -316,10 +317,23 @@ void unregister_chrdev_region(dev_t from, unsigned count) | |||
| 316 | } | 317 | } |
| 317 | } | 318 | } |
| 318 | 319 | ||
| 319 | void unregister_chrdev(unsigned int major, const char *name) | 320 | /** |
| 321 | * __unregister_chrdev - unregister and destroy a cdev | ||
| 322 | * @major: major device number | ||
| 323 | * @baseminor: first of the range of minor numbers | ||
| 324 | * @count: the number of minor numbers this cdev is occupying | ||
| 325 | * @name: name of this range of devices | ||
| 326 | * | ||
| 327 | * Unregister and destroy the cdev occupying the region described by | ||
| 328 | * @major, @baseminor and @count. This function undoes what | ||
| 329 | * __register_chrdev() did. | ||
| 330 | */ | ||
| 331 | void __unregister_chrdev(unsigned int major, unsigned int baseminor, | ||
| 332 | unsigned int count, const char *name) | ||
| 320 | { | 333 | { |
| 321 | struct char_device_struct *cd; | 334 | struct char_device_struct *cd; |
| 322 | cd = __unregister_chrdev_region(major, 0, 256); | 335 | |
| 336 | cd = __unregister_chrdev_region(major, baseminor, count); | ||
| 323 | if (cd && cd->cdev) | 337 | if (cd && cd->cdev) |
| 324 | cdev_del(cd->cdev); | 338 | cdev_del(cd->cdev); |
| 325 | kfree(cd); | 339 | kfree(cd); |
| @@ -568,6 +582,6 @@ EXPORT_SYMBOL(cdev_alloc); | |||
| 568 | EXPORT_SYMBOL(cdev_del); | 582 | EXPORT_SYMBOL(cdev_del); |
| 569 | EXPORT_SYMBOL(cdev_add); | 583 | EXPORT_SYMBOL(cdev_add); |
| 570 | EXPORT_SYMBOL(cdev_index); | 584 | EXPORT_SYMBOL(cdev_index); |
| 571 | EXPORT_SYMBOL(register_chrdev); | 585 | EXPORT_SYMBOL(__register_chrdev); |
| 572 | EXPORT_SYMBOL(unregister_chrdev); | 586 | EXPORT_SYMBOL(__unregister_chrdev); |
| 573 | EXPORT_SYMBOL(directly_mappable_cdev_bdi); | 587 | EXPORT_SYMBOL(directly_mappable_cdev_bdi); |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index e85b1e4389e..145540a316a 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
| @@ -3,7 +3,10 @@ Version 1.60 | |||
| 3 | Fix memory leak in reconnect. Fix oops in DFS mount error path. | 3 | Fix memory leak in reconnect. Fix oops in DFS mount error path. |
| 4 | Set s_maxbytes to smaller (the max that vfs can handle) so that | 4 | Set s_maxbytes to smaller (the max that vfs can handle) so that |
| 5 | sendfile will now work over cifs mounts again. Add noforcegid | 5 | sendfile will now work over cifs mounts again. Add noforcegid |
| 6 | and noforceuid mount parameters. | 6 | and noforceuid mount parameters. Fix small mem leak when using |
| 7 | ntlmv2. Fix 2nd mount to same server but with different port to | ||
| 8 | be allowed (rather than reusing the 1st port) - only when the | ||
| 9 | user explicitly overrides the port on the 2nd mount. | ||
| 7 | 10 | ||
| 8 | Version 1.59 | 11 | Version 1.59 |
| 9 | ------------ | 12 | ------------ |
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 051caecf7d6..8ec7736ce95 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
| @@ -125,7 +125,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
| 125 | if (server->addr.sockAddr.sin_family == AF_INET) | 125 | if (server->addr.sockAddr.sin_family == AF_INET) |
| 126 | sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr); | 126 | sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr); |
| 127 | else if (server->addr.sockAddr.sin_family == AF_INET6) | 127 | else if (server->addr.sockAddr.sin_family == AF_INET6) |
| 128 | sprintf(dp, "ip6=%pi6", &server->addr.sockAddr6.sin6_addr); | 128 | sprintf(dp, "ip6=%pI6", &server->addr.sockAddr6.sin6_addr); |
| 129 | else | 129 | else |
| 130 | goto out; | 130 | goto out; |
| 131 | 131 | ||
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 6941c22398a..7dfe0842a6f 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
| @@ -607,7 +607,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, | |||
| 607 | return get_cifs_acl_by_path(cifs_sb, path, pacllen); | 607 | return get_cifs_acl_by_path(cifs_sb, path, pacllen); |
| 608 | 608 | ||
| 609 | pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen); | 609 | pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen); |
| 610 | atomic_dec(&open_file->wrtPending); | 610 | cifsFileInfo_put(open_file); |
| 611 | return pntsd; | 611 | return pntsd; |
| 612 | } | 612 | } |
| 613 | 613 | ||
| @@ -665,7 +665,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
| 665 | return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); | 665 | return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); |
| 666 | 666 | ||
| 667 | rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen); | 667 | rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen); |
| 668 | atomic_dec(&open_file->wrtPending); | 668 | cifsFileInfo_put(open_file); |
| 669 | return rc; | 669 | return rc; |
| 670 | } | 670 | } |
| 671 | 671 | ||
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 7c9809523f4..7efe1745494 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
| @@ -373,6 +373,7 @@ calc_exit_2: | |||
| 373 | compare with the NTLM example */ | 373 | compare with the NTLM example */ |
| 374 | hmac_md5_final(ses->server->ntlmv2_hash, pctxt); | 374 | hmac_md5_final(ses->server->ntlmv2_hash, pctxt); |
| 375 | 375 | ||
| 376 | kfree(pctxt); | ||
| 376 | return rc; | 377 | return rc; |
| 377 | } | 378 | } |
| 378 | 379 | ||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 84b75253b05..3610e9958b4 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -361,13 +361,10 @@ cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) | |||
| 361 | static int | 361 | static int |
| 362 | cifs_show_options(struct seq_file *s, struct vfsmount *m) | 362 | cifs_show_options(struct seq_file *s, struct vfsmount *m) |
| 363 | { | 363 | { |
| 364 | struct cifs_sb_info *cifs_sb; | 364 | struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb); |
| 365 | struct cifsTconInfo *tcon; | 365 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
| 366 | |||
| 367 | cifs_sb = CIFS_SB(m->mnt_sb); | ||
| 368 | tcon = cifs_sb->tcon; | ||
| 369 | 366 | ||
| 370 | seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); | 367 | seq_printf(s, ",unc=%s", tcon->treeName); |
| 371 | if (tcon->ses->userName) | 368 | if (tcon->ses->userName) |
| 372 | seq_printf(s, ",username=%s", tcon->ses->userName); | 369 | seq_printf(s, ",username=%s", tcon->ses->userName); |
| 373 | if (tcon->ses->domainName) | 370 | if (tcon->ses->domainName) |
| @@ -989,19 +986,19 @@ static int cifs_oplock_thread(void *dummyarg) | |||
| 989 | if (try_to_freeze()) | 986 | if (try_to_freeze()) |
| 990 | continue; | 987 | continue; |
| 991 | 988 | ||
| 992 | spin_lock(&GlobalMid_Lock); | 989 | spin_lock(&cifs_oplock_lock); |
| 993 | if (list_empty(&GlobalOplock_Q)) { | 990 | if (list_empty(&cifs_oplock_list)) { |
| 994 | spin_unlock(&GlobalMid_Lock); | 991 | spin_unlock(&cifs_oplock_lock); |
| 995 | set_current_state(TASK_INTERRUPTIBLE); | 992 | set_current_state(TASK_INTERRUPTIBLE); |
| 996 | schedule_timeout(39*HZ); | 993 | schedule_timeout(39*HZ); |
| 997 | } else { | 994 | } else { |
| 998 | oplock_item = list_entry(GlobalOplock_Q.next, | 995 | oplock_item = list_entry(cifs_oplock_list.next, |
| 999 | struct oplock_q_entry, qhead); | 996 | struct oplock_q_entry, qhead); |
| 1000 | cFYI(1, ("found oplock item to write out")); | 997 | cFYI(1, ("found oplock item to write out")); |
| 1001 | pTcon = oplock_item->tcon; | 998 | pTcon = oplock_item->tcon; |
| 1002 | inode = oplock_item->pinode; | 999 | inode = oplock_item->pinode; |
| 1003 | netfid = oplock_item->netfid; | 1000 | netfid = oplock_item->netfid; |
| 1004 | spin_unlock(&GlobalMid_Lock); | 1001 | spin_unlock(&cifs_oplock_lock); |
| 1005 | DeleteOplockQEntry(oplock_item); | 1002 | DeleteOplockQEntry(oplock_item); |
| 1006 | /* can not grab inode sem here since it would | 1003 | /* can not grab inode sem here since it would |
| 1007 | deadlock when oplock received on delete | 1004 | deadlock when oplock received on delete |
| @@ -1058,7 +1055,7 @@ init_cifs(void) | |||
| 1058 | int rc = 0; | 1055 | int rc = 0; |
| 1059 | cifs_proc_init(); | 1056 | cifs_proc_init(); |
| 1060 | INIT_LIST_HEAD(&cifs_tcp_ses_list); | 1057 | INIT_LIST_HEAD(&cifs_tcp_ses_list); |
| 1061 | INIT_LIST_HEAD(&GlobalOplock_Q); | 1058 | INIT_LIST_HEAD(&cifs_oplock_list); |
| 1062 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 1059 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| 1063 | INIT_LIST_HEAD(&GlobalDnotifyReqList); | 1060 | INIT_LIST_HEAD(&GlobalDnotifyReqList); |
| 1064 | INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); | 1061 | INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); |
| @@ -1087,6 +1084,7 @@ init_cifs(void) | |||
| 1087 | rwlock_init(&GlobalSMBSeslock); | 1084 | rwlock_init(&GlobalSMBSeslock); |
| 1088 | rwlock_init(&cifs_tcp_ses_lock); | 1085 | rwlock_init(&cifs_tcp_ses_lock); |
| 1089 | spin_lock_init(&GlobalMid_Lock); | 1086 | spin_lock_init(&GlobalMid_Lock); |
| 1087 | spin_lock_init(&cifs_oplock_lock); | ||
| 1090 | 1088 | ||
| 1091 | if (cifs_max_pending < 2) { | 1089 | if (cifs_max_pending < 2) { |
| 1092 | cifs_max_pending = 2; | 1090 | cifs_max_pending = 2; |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 6c170948300..094325e3f71 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
| @@ -113,5 +113,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
| 113 | extern const struct export_operations cifs_export_ops; | 113 | extern const struct export_operations cifs_export_ops; |
| 114 | #endif /* EXPERIMENTAL */ | 114 | #endif /* EXPERIMENTAL */ |
| 115 | 115 | ||
| 116 | #define CIFS_VERSION "1.60" | 116 | #define CIFS_VERSION "1.61" |
| 117 | #endif /* _CIFSFS_H */ | 117 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 6084d6379c0..6cfc81a3270 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -351,11 +351,24 @@ struct cifsFileInfo { | |||
| 351 | bool closePend:1; /* file is marked to close */ | 351 | bool closePend:1; /* file is marked to close */ |
| 352 | bool invalidHandle:1; /* file closed via session abend */ | 352 | bool invalidHandle:1; /* file closed via session abend */ |
| 353 | bool messageMode:1; /* for pipes: message vs byte mode */ | 353 | bool messageMode:1; /* for pipes: message vs byte mode */ |
| 354 | atomic_t wrtPending; /* handle in use - defer close */ | 354 | atomic_t count; /* reference count */ |
| 355 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ | 355 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ |
| 356 | struct cifs_search_info srch_inf; | 356 | struct cifs_search_info srch_inf; |
| 357 | }; | 357 | }; |
| 358 | 358 | ||
| 359 | /* Take a reference on the file private data */ | ||
| 360 | static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file) | ||
| 361 | { | ||
| 362 | atomic_inc(&cifs_file->count); | ||
| 363 | } | ||
| 364 | |||
| 365 | /* Release a reference on the file private data */ | ||
| 366 | static inline void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | ||
| 367 | { | ||
| 368 | if (atomic_dec_and_test(&cifs_file->count)) | ||
| 369 | kfree(cifs_file); | ||
| 370 | } | ||
| 371 | |||
| 359 | /* | 372 | /* |
| 360 | * One of these for each file inode | 373 | * One of these for each file inode |
| 361 | */ | 374 | */ |
| @@ -656,7 +669,11 @@ GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; | |||
| 656 | */ | 669 | */ |
| 657 | GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; | 670 | GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; |
| 658 | 671 | ||
| 659 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; | 672 | /* Global list of oplocks */ |
| 673 | GLOBAL_EXTERN struct list_head cifs_oplock_list; | ||
| 674 | |||
| 675 | /* Protects the cifs_oplock_list */ | ||
| 676 | GLOBAL_EXTERN spinlock_t cifs_oplock_lock; | ||
| 660 | 677 | ||
| 661 | /* Outstanding dir notify requests */ | 678 | /* Outstanding dir notify requests */ |
| 662 | GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; | 679 | GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 1866bc2927d..301e307e127 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -100,110 +100,138 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon) | |||
| 100 | to this tcon */ | 100 | to this tcon */ |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | /* Allocate and return pointer to an SMB request buffer, and set basic | 103 | /* reconnect the socket, tcon, and smb session if needed */ |
| 104 | SMB information in the SMB header. If the return code is zero, this | ||
| 105 | function must have filled in request_buf pointer */ | ||
| 106 | static int | 104 | static int |
| 107 | small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | 105 | cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) |
| 108 | void **request_buf) | ||
| 109 | { | 106 | { |
| 110 | int rc = 0; | 107 | int rc = 0; |
| 108 | struct cifsSesInfo *ses; | ||
| 109 | struct TCP_Server_Info *server; | ||
| 110 | struct nls_table *nls_codepage; | ||
| 111 | 111 | ||
| 112 | /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so | 112 | /* |
| 113 | check for tcp and smb session status done differently | 113 | * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for |
| 114 | for those three - in the calling routine */ | 114 | * tcp and smb session status done differently for those three - in the |
| 115 | if (tcon) { | 115 | * calling routine |
| 116 | if (tcon->tidStatus == CifsExiting) { | 116 | */ |
| 117 | /* only tree disconnect, open, and write, | 117 | if (!tcon) |
| 118 | (and ulogoff which does not have tcon) | 118 | return 0; |
| 119 | are allowed as we start force umount */ | 119 | |
| 120 | if ((smb_command != SMB_COM_WRITE_ANDX) && | 120 | ses = tcon->ses; |
| 121 | (smb_command != SMB_COM_OPEN_ANDX) && | 121 | server = ses->server; |
| 122 | (smb_command != SMB_COM_TREE_DISCONNECT)) { | 122 | |
| 123 | cFYI(1, ("can not send cmd %d while umounting", | 123 | /* |
| 124 | smb_command)); | 124 | * only tree disconnect, open, and write, (and ulogoff which does not |
| 125 | return -ENODEV; | 125 | * have tcon) are allowed as we start force umount |
| 126 | } | 126 | */ |
| 127 | if (tcon->tidStatus == CifsExiting) { | ||
| 128 | if (smb_command != SMB_COM_WRITE_ANDX && | ||
| 129 | smb_command != SMB_COM_OPEN_ANDX && | ||
| 130 | smb_command != SMB_COM_TREE_DISCONNECT) { | ||
| 131 | cFYI(1, ("can not send cmd %d while umounting", | ||
| 132 | smb_command)); | ||
| 133 | return -ENODEV; | ||
| 127 | } | 134 | } |
| 128 | if ((tcon->ses) && (tcon->ses->status != CifsExiting) && | 135 | } |
| 129 | (tcon->ses->server)) { | ||
| 130 | struct nls_table *nls_codepage; | ||
| 131 | /* Give Demultiplex thread up to 10 seconds to | ||
| 132 | reconnect, should be greater than cifs socket | ||
| 133 | timeout which is 7 seconds */ | ||
| 134 | while (tcon->ses->server->tcpStatus == | ||
| 135 | CifsNeedReconnect) { | ||
| 136 | wait_event_interruptible_timeout(tcon->ses->server->response_q, | ||
| 137 | (tcon->ses->server->tcpStatus == | ||
| 138 | CifsGood), 10 * HZ); | ||
| 139 | if (tcon->ses->server->tcpStatus == | ||
| 140 | CifsNeedReconnect) { | ||
| 141 | /* on "soft" mounts we wait once */ | ||
| 142 | if (!tcon->retry || | ||
| 143 | (tcon->ses->status == CifsExiting)) { | ||
| 144 | cFYI(1, ("gave up waiting on " | ||
| 145 | "reconnect in smb_init")); | ||
| 146 | return -EHOSTDOWN; | ||
| 147 | } /* else "hard" mount - keep retrying | ||
| 148 | until process is killed or server | ||
| 149 | comes back on-line */ | ||
| 150 | } else /* TCP session is reestablished now */ | ||
| 151 | break; | ||
| 152 | } | ||
| 153 | 136 | ||
| 154 | nls_codepage = load_nls_default(); | 137 | if (ses->status == CifsExiting) |
| 155 | /* need to prevent multiple threads trying to | 138 | return -EIO; |
| 156 | simultaneously reconnect the same SMB session */ | ||
| 157 | down(&tcon->ses->sesSem); | ||
| 158 | if (tcon->ses->need_reconnect) | ||
| 159 | rc = cifs_setup_session(0, tcon->ses, | ||
| 160 | nls_codepage); | ||
| 161 | if (!rc && (tcon->need_reconnect)) { | ||
| 162 | mark_open_files_invalid(tcon); | ||
| 163 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, | ||
| 164 | tcon, nls_codepage); | ||
| 165 | up(&tcon->ses->sesSem); | ||
| 166 | /* BB FIXME add code to check if wsize needs | ||
| 167 | update due to negotiated smb buffer size | ||
| 168 | shrinking */ | ||
| 169 | if (rc == 0) { | ||
| 170 | atomic_inc(&tconInfoReconnectCount); | ||
| 171 | /* tell server Unix caps we support */ | ||
| 172 | if (tcon->ses->capabilities & CAP_UNIX) | ||
| 173 | reset_cifs_unix_caps( | ||
| 174 | 0 /* no xid */, | ||
| 175 | tcon, | ||
| 176 | NULL /* we do not know sb */, | ||
| 177 | NULL /* no vol info */); | ||
| 178 | } | ||
| 179 | 139 | ||
| 180 | cFYI(1, ("reconnect tcon rc = %d", rc)); | 140 | /* |
| 181 | /* Removed call to reopen open files here. | 141 | * Give demultiplex thread up to 10 seconds to reconnect, should be |
| 182 | It is safer (and faster) to reopen files | 142 | * greater than cifs socket timeout which is 7 seconds |
| 183 | one at a time as needed in read and write */ | 143 | */ |
| 184 | 144 | while (server->tcpStatus == CifsNeedReconnect) { | |
| 185 | /* Check if handle based operation so we | 145 | wait_event_interruptible_timeout(server->response_q, |
| 186 | know whether we can continue or not without | 146 | (server->tcpStatus == CifsGood), 10 * HZ); |
| 187 | returning to caller to reset file handle */ | ||
| 188 | switch (smb_command) { | ||
| 189 | case SMB_COM_READ_ANDX: | ||
| 190 | case SMB_COM_WRITE_ANDX: | ||
| 191 | case SMB_COM_CLOSE: | ||
| 192 | case SMB_COM_FIND_CLOSE2: | ||
| 193 | case SMB_COM_LOCKING_ANDX: { | ||
| 194 | unload_nls(nls_codepage); | ||
| 195 | return -EAGAIN; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | } else { | ||
| 199 | up(&tcon->ses->sesSem); | ||
| 200 | } | ||
| 201 | unload_nls(nls_codepage); | ||
| 202 | 147 | ||
| 203 | } else { | 148 | /* is TCP session is reestablished now ?*/ |
| 204 | return -EIO; | 149 | if (server->tcpStatus != CifsNeedReconnect) |
| 150 | break; | ||
| 151 | |||
| 152 | /* | ||
| 153 | * on "soft" mounts we wait once. Hard mounts keep | ||
| 154 | * retrying until process is killed or server comes | ||
| 155 | * back on-line | ||
| 156 | */ | ||
| 157 | if (!tcon->retry || ses->status == CifsExiting) { | ||
| 158 | cFYI(1, ("gave up waiting on reconnect in smb_init")); | ||
| 159 | return -EHOSTDOWN; | ||
| 205 | } | 160 | } |
| 206 | } | 161 | } |
| 162 | |||
| 163 | if (!ses->need_reconnect && !tcon->need_reconnect) | ||
| 164 | return 0; | ||
| 165 | |||
| 166 | nls_codepage = load_nls_default(); | ||
| 167 | |||
| 168 | /* | ||
| 169 | * need to prevent multiple threads trying to simultaneously | ||
| 170 | * reconnect the same SMB session | ||
| 171 | */ | ||
| 172 | down(&ses->sesSem); | ||
| 173 | if (ses->need_reconnect) | ||
| 174 | rc = cifs_setup_session(0, ses, nls_codepage); | ||
| 175 | |||
| 176 | /* do we need to reconnect tcon? */ | ||
| 177 | if (rc || !tcon->need_reconnect) { | ||
| 178 | up(&ses->sesSem); | ||
| 179 | goto out; | ||
| 180 | } | ||
| 181 | |||
| 182 | mark_open_files_invalid(tcon); | ||
| 183 | rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage); | ||
| 184 | up(&ses->sesSem); | ||
| 185 | cFYI(1, ("reconnect tcon rc = %d", rc)); | ||
| 186 | |||
| 187 | if (rc) | ||
| 188 | goto out; | ||
| 189 | |||
| 190 | /* | ||
| 191 | * FIXME: check if wsize needs updated due to negotiated smb buffer | ||
| 192 | * size shrinking | ||
| 193 | */ | ||
| 194 | atomic_inc(&tconInfoReconnectCount); | ||
| 195 | |||
| 196 | /* tell server Unix caps we support */ | ||
| 197 | if (ses->capabilities & CAP_UNIX) | ||
| 198 | reset_cifs_unix_caps(0, tcon, NULL, NULL); | ||
| 199 | |||
| 200 | /* | ||
| 201 | * Removed call to reopen open files here. It is safer (and faster) to | ||
| 202 | * reopen files one at a time as needed in read and write. | ||
| 203 | * | ||
| 204 | * FIXME: what about file locks? don't we need to reclaim them ASAP? | ||
| 205 | */ | ||
| 206 | |||
| 207 | out: | ||
| 208 | /* | ||
| 209 | * Check if handle based operation so we know whether we can continue | ||
| 210 | * or not without returning to caller to reset file handle | ||
| 211 | */ | ||
| 212 | switch (smb_command) { | ||
| 213 | case SMB_COM_READ_ANDX: | ||
| 214 | case SMB_COM_WRITE_ANDX: | ||
| 215 | case SMB_COM_CLOSE: | ||
| 216 | case SMB_COM_FIND_CLOSE2: | ||
| 217 | case SMB_COM_LOCKING_ANDX: | ||
| 218 | rc = -EAGAIN; | ||
| 219 | } | ||
| 220 | |||
| 221 | unload_nls(nls_codepage); | ||
| 222 | return rc; | ||
| 223 | } | ||
| 224 | |||
| 225 | /* Allocate and return pointer to an SMB request buffer, and set basic | ||
| 226 | SMB information in the SMB header. If the return code is zero, this | ||
| 227 | function must have filled in request_buf pointer */ | ||
| 228 | static int | ||
| 229 | small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | ||
| 230 | void **request_buf) | ||
| 231 | { | ||
| 232 | int rc = 0; | ||
| 233 | |||
| 234 | rc = cifs_reconnect_tcon(tcon, smb_command); | ||
| 207 | if (rc) | 235 | if (rc) |
| 208 | return rc; | 236 | return rc; |
| 209 | 237 | ||
| @@ -256,101 +284,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
| 256 | { | 284 | { |
| 257 | int rc = 0; | 285 | int rc = 0; |
| 258 | 286 | ||
| 259 | /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so | 287 | rc = cifs_reconnect_tcon(tcon, smb_command); |
| 260 | check for tcp and smb session status done differently | ||
| 261 | for those three - in the calling routine */ | ||
| 262 | if (tcon) { | ||
| 263 | if (tcon->tidStatus == CifsExiting) { | ||
| 264 | /* only tree disconnect, open, and write, | ||
| 265 | (and ulogoff which does not have tcon) | ||
| 266 | are allowed as we start force umount */ | ||
| 267 | if ((smb_command != SMB_COM_WRITE_ANDX) && | ||
| 268 | (smb_command != SMB_COM_OPEN_ANDX) && | ||
| 269 | (smb_command != SMB_COM_TREE_DISCONNECT)) { | ||
| 270 | cFYI(1, ("can not send cmd %d while umounting", | ||
| 271 | smb_command)); | ||
| 272 | return -ENODEV; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | if ((tcon->ses) && (tcon->ses->status != CifsExiting) && | ||
| 277 | (tcon->ses->server)) { | ||
| 278 | struct nls_table *nls_codepage; | ||
| 279 | /* Give Demultiplex thread up to 10 seconds to | ||
| 280 | reconnect, should be greater than cifs socket | ||
| 281 | timeout which is 7 seconds */ | ||
| 282 | while (tcon->ses->server->tcpStatus == | ||
| 283 | CifsNeedReconnect) { | ||
| 284 | wait_event_interruptible_timeout(tcon->ses->server->response_q, | ||
| 285 | (tcon->ses->server->tcpStatus == | ||
| 286 | CifsGood), 10 * HZ); | ||
| 287 | if (tcon->ses->server->tcpStatus == | ||
| 288 | CifsNeedReconnect) { | ||
| 289 | /* on "soft" mounts we wait once */ | ||
| 290 | if (!tcon->retry || | ||
| 291 | (tcon->ses->status == CifsExiting)) { | ||
| 292 | cFYI(1, ("gave up waiting on " | ||
| 293 | "reconnect in smb_init")); | ||
| 294 | return -EHOSTDOWN; | ||
| 295 | } /* else "hard" mount - keep retrying | ||
| 296 | until process is killed or server | ||
| 297 | comes on-line */ | ||
| 298 | } else /* TCP session is reestablished now */ | ||
| 299 | break; | ||
| 300 | } | ||
| 301 | nls_codepage = load_nls_default(); | ||
| 302 | /* need to prevent multiple threads trying to | ||
| 303 | simultaneously reconnect the same SMB session */ | ||
| 304 | down(&tcon->ses->sesSem); | ||
| 305 | if (tcon->ses->need_reconnect) | ||
| 306 | rc = cifs_setup_session(0, tcon->ses, | ||
| 307 | nls_codepage); | ||
| 308 | if (!rc && (tcon->need_reconnect)) { | ||
| 309 | mark_open_files_invalid(tcon); | ||
| 310 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, | ||
| 311 | tcon, nls_codepage); | ||
| 312 | up(&tcon->ses->sesSem); | ||
| 313 | /* BB FIXME add code to check if wsize needs | ||
| 314 | update due to negotiated smb buffer size | ||
| 315 | shrinking */ | ||
| 316 | if (rc == 0) { | ||
| 317 | atomic_inc(&tconInfoReconnectCount); | ||
| 318 | /* tell server Unix caps we support */ | ||
| 319 | if (tcon->ses->capabilities & CAP_UNIX) | ||
| 320 | reset_cifs_unix_caps( | ||
| 321 | 0 /* no xid */, | ||
| 322 | tcon, | ||
| 323 | NULL /* do not know sb */, | ||
| 324 | NULL /* no vol info */); | ||
| 325 | } | ||
| 326 | |||
| 327 | cFYI(1, ("reconnect tcon rc = %d", rc)); | ||
| 328 | /* Removed call to reopen open files here. | ||
| 329 | It is safer (and faster) to reopen files | ||
| 330 | one at a time as needed in read and write */ | ||
| 331 | |||
| 332 | /* Check if handle based operation so we | ||
| 333 | know whether we can continue or not without | ||
| 334 | returning to caller to reset file handle */ | ||
| 335 | switch (smb_command) { | ||
| 336 | case SMB_COM_READ_ANDX: | ||
| 337 | case SMB_COM_WRITE_ANDX: | ||
| 338 | case SMB_COM_CLOSE: | ||
| 339 | case SMB_COM_FIND_CLOSE2: | ||
| 340 | case SMB_COM_LOCKING_ANDX: { | ||
| 341 | unload_nls(nls_codepage); | ||
| 342 | return -EAGAIN; | ||
| 343 | } | ||
| 344 | } | ||
| 345 | } else { | ||
| 346 | up(&tcon->ses->sesSem); | ||
| 347 | } | ||
| 348 | unload_nls(nls_codepage); | ||
| 349 | |||
| 350 | } else { | ||
| 351 | return -EIO; | ||
| 352 | } | ||
| 353 | } | ||
| 354 | if (rc) | 288 | if (rc) |
| 355 | return rc; | 289 | return rc; |
| 356 | 290 | ||
| @@ -3961,6 +3895,10 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | |||
| 3961 | if (is_unicode) { | 3895 | if (is_unicode) { |
| 3962 | __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, | 3896 | __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, |
| 3963 | GFP_KERNEL); | 3897 | GFP_KERNEL); |
| 3898 | if (tmp == NULL) { | ||
| 3899 | rc = -ENOMEM; | ||
| 3900 | goto parse_DFS_referrals_exit; | ||
| 3901 | } | ||
| 3964 | cifsConvertToUCS((__le16 *) tmp, searchName, | 3902 | cifsConvertToUCS((__le16 *) tmp, searchName, |
| 3965 | PATH_MAX, nls_codepage, remap); | 3903 | PATH_MAX, nls_codepage, remap); |
| 3966 | node->path_consumed = cifs_ucs2_bytes(tmp, | 3904 | node->path_consumed = cifs_ucs2_bytes(tmp, |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 1f3345d7fa7..d49682433c2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -1377,7 +1377,7 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
| 1377 | } | 1377 | } |
| 1378 | 1378 | ||
| 1379 | static struct TCP_Server_Info * | 1379 | static struct TCP_Server_Info * |
| 1380 | cifs_find_tcp_session(struct sockaddr_storage *addr) | 1380 | cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port) |
| 1381 | { | 1381 | { |
| 1382 | struct list_head *tmp; | 1382 | struct list_head *tmp; |
| 1383 | struct TCP_Server_Info *server; | 1383 | struct TCP_Server_Info *server; |
| @@ -1397,16 +1397,37 @@ cifs_find_tcp_session(struct sockaddr_storage *addr) | |||
| 1397 | if (server->tcpStatus == CifsNew) | 1397 | if (server->tcpStatus == CifsNew) |
| 1398 | continue; | 1398 | continue; |
| 1399 | 1399 | ||
| 1400 | if (addr->ss_family == AF_INET && | 1400 | switch (addr->ss_family) { |
| 1401 | (addr4->sin_addr.s_addr != | 1401 | case AF_INET: |
| 1402 | server->addr.sockAddr.sin_addr.s_addr)) | 1402 | if (addr4->sin_addr.s_addr == |
| 1403 | continue; | 1403 | server->addr.sockAddr.sin_addr.s_addr) { |
| 1404 | else if (addr->ss_family == AF_INET6 && | 1404 | addr4->sin_port = htons(port); |
| 1405 | (!ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr, | 1405 | /* user overrode default port? */ |
| 1406 | &addr6->sin6_addr) || | 1406 | if (addr4->sin_port) { |
| 1407 | server->addr.sockAddr6.sin6_scope_id != | 1407 | if (addr4->sin_port != |
| 1408 | addr6->sin6_scope_id)) | 1408 | server->addr.sockAddr.sin_port) |
| 1409 | continue; | 1409 | continue; |
| 1410 | } | ||
| 1411 | break; | ||
| 1412 | } else | ||
| 1413 | continue; | ||
| 1414 | |||
| 1415 | case AF_INET6: | ||
| 1416 | if (ipv6_addr_equal(&addr6->sin6_addr, | ||
| 1417 | &server->addr.sockAddr6.sin6_addr) && | ||
| 1418 | (addr6->sin6_scope_id == | ||
| 1419 | server->addr.sockAddr6.sin6_scope_id)) { | ||
| 1420 | addr6->sin6_port = htons(port); | ||
| 1421 | /* user overrode default port? */ | ||
| 1422 | if (addr6->sin6_port) { | ||
| 1423 | if (addr6->sin6_port != | ||
| 1424 | server->addr.sockAddr6.sin6_port) | ||
| 1425 | continue; | ||
| 1426 | } | ||
| 1427 | break; | ||
| 1428 | } else | ||
| 1429 | continue; | ||
| 1430 | } | ||
| 1410 | 1431 | ||
| 1411 | ++server->srv_count; | 1432 | ++server->srv_count; |
| 1412 | write_unlock(&cifs_tcp_ses_lock); | 1433 | write_unlock(&cifs_tcp_ses_lock); |
| @@ -1475,7 +1496,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
| 1475 | } | 1496 | } |
| 1476 | 1497 | ||
| 1477 | /* see if we already have a matching tcp_ses */ | 1498 | /* see if we already have a matching tcp_ses */ |
| 1478 | tcp_ses = cifs_find_tcp_session(&addr); | 1499 | tcp_ses = cifs_find_tcp_session(&addr, volume_info->port); |
| 1479 | if (tcp_ses) | 1500 | if (tcp_ses) |
| 1480 | return tcp_ses; | 1501 | return tcp_ses; |
| 1481 | 1502 | ||
| @@ -2636,9 +2657,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2636 | return -EIO; | 2657 | return -EIO; |
| 2637 | 2658 | ||
| 2638 | smb_buffer = cifs_buf_get(); | 2659 | smb_buffer = cifs_buf_get(); |
| 2639 | if (smb_buffer == NULL) { | 2660 | if (smb_buffer == NULL) |
| 2640 | return -ENOMEM; | 2661 | return -ENOMEM; |
| 2641 | } | 2662 | |
| 2642 | smb_buffer_response = smb_buffer; | 2663 | smb_buffer_response = smb_buffer; |
| 2643 | 2664 | ||
| 2644 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, | 2665 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 4326ffd90fa..a6424cfc012 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -153,7 +153,7 @@ cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle, | |||
| 153 | mutex_init(&pCifsFile->fh_mutex); | 153 | mutex_init(&pCifsFile->fh_mutex); |
| 154 | mutex_init(&pCifsFile->lock_mutex); | 154 | mutex_init(&pCifsFile->lock_mutex); |
| 155 | INIT_LIST_HEAD(&pCifsFile->llist); | 155 | INIT_LIST_HEAD(&pCifsFile->llist); |
| 156 | atomic_set(&pCifsFile->wrtPending, 0); | 156 | atomic_set(&pCifsFile->count, 1); |
| 157 | 157 | ||
| 158 | /* set the following in open now | 158 | /* set the following in open now |
| 159 | pCifsFile->pfile = file; */ | 159 | pCifsFile->pfile = file; */ |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c34b7f8a217..fa7beac8b80 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -53,11 +53,9 @@ static inline struct cifsFileInfo *cifs_init_private( | |||
| 53 | private_data->pInode = inode; | 53 | private_data->pInode = inode; |
| 54 | private_data->invalidHandle = false; | 54 | private_data->invalidHandle = false; |
| 55 | private_data->closePend = false; | 55 | private_data->closePend = false; |
| 56 | /* we have to track num writers to the inode, since writepages | 56 | /* Initialize reference count to one. The private data is |
| 57 | does not tell us which handle the write is for so there can | 57 | freed on the release of the last reference */ |
| 58 | be a close (overlapping with write) of the filehandle that | 58 | atomic_set(&private_data->count, 1); |
| 59 | cifs_writepages chose to use */ | ||
| 60 | atomic_set(&private_data->wrtPending, 0); | ||
| 61 | 59 | ||
| 62 | return private_data; | 60 | return private_data; |
| 63 | } | 61 | } |
| @@ -643,7 +641,7 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 643 | if (!pTcon->need_reconnect) { | 641 | if (!pTcon->need_reconnect) { |
| 644 | write_unlock(&GlobalSMBSeslock); | 642 | write_unlock(&GlobalSMBSeslock); |
| 645 | timeout = 2; | 643 | timeout = 2; |
| 646 | while ((atomic_read(&pSMBFile->wrtPending) != 0) | 644 | while ((atomic_read(&pSMBFile->count) != 1) |
| 647 | && (timeout <= 2048)) { | 645 | && (timeout <= 2048)) { |
| 648 | /* Give write a better chance to get to | 646 | /* Give write a better chance to get to |
| 649 | server ahead of the close. We do not | 647 | server ahead of the close. We do not |
| @@ -657,8 +655,6 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 657 | msleep(timeout); | 655 | msleep(timeout); |
| 658 | timeout *= 4; | 656 | timeout *= 4; |
| 659 | } | 657 | } |
| 660 | if (atomic_read(&pSMBFile->wrtPending)) | ||
| 661 | cERROR(1, ("close with pending write")); | ||
| 662 | if (!pTcon->need_reconnect && | 658 | if (!pTcon->need_reconnect && |
| 663 | !pSMBFile->invalidHandle) | 659 | !pSMBFile->invalidHandle) |
| 664 | rc = CIFSSMBClose(xid, pTcon, | 660 | rc = CIFSSMBClose(xid, pTcon, |
| @@ -681,24 +677,7 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 681 | list_del(&pSMBFile->flist); | 677 | list_del(&pSMBFile->flist); |
| 682 | list_del(&pSMBFile->tlist); | 678 | list_del(&pSMBFile->tlist); |
| 683 | write_unlock(&GlobalSMBSeslock); | 679 | write_unlock(&GlobalSMBSeslock); |
| 684 | timeout = 10; | 680 | cifsFileInfo_put(file->private_data); |
| 685 | /* We waited above to give the SMBWrite a chance to issue | ||
| 686 | on the wire (so we do not get SMBWrite returning EBADF | ||
| 687 | if writepages is racing with close. Note that writepages | ||
| 688 | does not specify a file handle, so it is possible for a file | ||
| 689 | to be opened twice, and the application close the "wrong" | ||
| 690 | file handle - in these cases we delay long enough to allow | ||
| 691 | the SMBWrite to get on the wire before the SMB Close. | ||
| 692 | We allow total wait here over 45 seconds, more than | ||
| 693 | oplock break time, and more than enough to allow any write | ||
| 694 | to complete on the server, or to time out on the client */ | ||
| 695 | while ((atomic_read(&pSMBFile->wrtPending) != 0) | ||
| 696 | && (timeout <= 50000)) { | ||
| 697 | cERROR(1, ("writes pending, delay free of handle")); | ||
| 698 | msleep(timeout); | ||
| 699 | timeout *= 8; | ||
| 700 | } | ||
| 701 | kfree(file->private_data); | ||
| 702 | file->private_data = NULL; | 681 | file->private_data = NULL; |
| 703 | } else | 682 | } else |
| 704 | rc = -EBADF; | 683 | rc = -EBADF; |
| @@ -1236,7 +1215,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) | |||
| 1236 | if (!open_file->invalidHandle) { | 1215 | if (!open_file->invalidHandle) { |
| 1237 | /* found a good file */ | 1216 | /* found a good file */ |
| 1238 | /* lock it so it will not be closed on us */ | 1217 | /* lock it so it will not be closed on us */ |
| 1239 | atomic_inc(&open_file->wrtPending); | 1218 | cifsFileInfo_get(open_file); |
| 1240 | read_unlock(&GlobalSMBSeslock); | 1219 | read_unlock(&GlobalSMBSeslock); |
| 1241 | return open_file; | 1220 | return open_file; |
| 1242 | } /* else might as well continue, and look for | 1221 | } /* else might as well continue, and look for |
| @@ -1276,7 +1255,7 @@ refind_writable: | |||
| 1276 | if (open_file->pfile && | 1255 | if (open_file->pfile && |
| 1277 | ((open_file->pfile->f_flags & O_RDWR) || | 1256 | ((open_file->pfile->f_flags & O_RDWR) || |
| 1278 | (open_file->pfile->f_flags & O_WRONLY))) { | 1257 | (open_file->pfile->f_flags & O_WRONLY))) { |
| 1279 | atomic_inc(&open_file->wrtPending); | 1258 | cifsFileInfo_get(open_file); |
| 1280 | 1259 | ||
| 1281 | if (!open_file->invalidHandle) { | 1260 | if (!open_file->invalidHandle) { |
| 1282 | /* found a good writable file */ | 1261 | /* found a good writable file */ |
| @@ -1293,7 +1272,7 @@ refind_writable: | |||
| 1293 | else { /* start over in case this was deleted */ | 1272 | else { /* start over in case this was deleted */ |
| 1294 | /* since the list could be modified */ | 1273 | /* since the list could be modified */ |
| 1295 | read_lock(&GlobalSMBSeslock); | 1274 | read_lock(&GlobalSMBSeslock); |
| 1296 | atomic_dec(&open_file->wrtPending); | 1275 | cifsFileInfo_put(open_file); |
| 1297 | goto refind_writable; | 1276 | goto refind_writable; |
| 1298 | } | 1277 | } |
| 1299 | } | 1278 | } |
| @@ -1309,7 +1288,7 @@ refind_writable: | |||
| 1309 | read_lock(&GlobalSMBSeslock); | 1288 | read_lock(&GlobalSMBSeslock); |
| 1310 | /* can not use this handle, no write | 1289 | /* can not use this handle, no write |
| 1311 | pending on this one after all */ | 1290 | pending on this one after all */ |
| 1312 | atomic_dec(&open_file->wrtPending); | 1291 | cifsFileInfo_put(open_file); |
| 1313 | 1292 | ||
| 1314 | if (open_file->closePend) /* list could have changed */ | 1293 | if (open_file->closePend) /* list could have changed */ |
| 1315 | goto refind_writable; | 1294 | goto refind_writable; |
| @@ -1373,7 +1352,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
| 1373 | if (open_file) { | 1352 | if (open_file) { |
| 1374 | bytes_written = cifs_write(open_file->pfile, write_data, | 1353 | bytes_written = cifs_write(open_file->pfile, write_data, |
| 1375 | to-from, &offset); | 1354 | to-from, &offset); |
| 1376 | atomic_dec(&open_file->wrtPending); | 1355 | cifsFileInfo_put(open_file); |
| 1377 | /* Does mm or vfs already set times? */ | 1356 | /* Does mm or vfs already set times? */ |
| 1378 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); | 1357 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); |
| 1379 | if ((bytes_written > 0) && (offset)) | 1358 | if ((bytes_written > 0) && (offset)) |
| @@ -1562,7 +1541,7 @@ retry: | |||
| 1562 | bytes_to_write, offset, | 1541 | bytes_to_write, offset, |
| 1563 | &bytes_written, iov, n_iov, | 1542 | &bytes_written, iov, n_iov, |
| 1564 | long_op); | 1543 | long_op); |
| 1565 | atomic_dec(&open_file->wrtPending); | 1544 | cifsFileInfo_put(open_file); |
| 1566 | cifs_update_eof(cifsi, offset, bytes_written); | 1545 | cifs_update_eof(cifsi, offset, bytes_written); |
| 1567 | 1546 | ||
| 1568 | if (rc || bytes_written < bytes_to_write) { | 1547 | if (rc || bytes_written < bytes_to_write) { |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 82d83839655..1f09c761931 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -800,7 +800,7 @@ set_via_filehandle: | |||
| 800 | if (open_file == NULL) | 800 | if (open_file == NULL) |
| 801 | CIFSSMBClose(xid, pTcon, netfid); | 801 | CIFSSMBClose(xid, pTcon, netfid); |
| 802 | else | 802 | else |
| 803 | atomic_dec(&open_file->wrtPending); | 803 | cifsFileInfo_put(open_file); |
| 804 | out: | 804 | out: |
| 805 | return rc; | 805 | return rc; |
| 806 | } | 806 | } |
| @@ -1635,7 +1635,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
| 1635 | __u32 npid = open_file->pid; | 1635 | __u32 npid = open_file->pid; |
| 1636 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, | 1636 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, |
| 1637 | npid, false); | 1637 | npid, false); |
| 1638 | atomic_dec(&open_file->wrtPending); | 1638 | cifsFileInfo_put(open_file); |
| 1639 | cFYI(1, ("SetFSize for attrs rc = %d", rc)); | 1639 | cFYI(1, ("SetFSize for attrs rc = %d", rc)); |
| 1640 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | 1640 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { |
| 1641 | unsigned int bytes_written; | 1641 | unsigned int bytes_written; |
| @@ -1790,7 +1790,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
| 1790 | u16 nfid = open_file->netfid; | 1790 | u16 nfid = open_file->netfid; |
| 1791 | u32 npid = open_file->pid; | 1791 | u32 npid = open_file->pid; |
| 1792 | rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); | 1792 | rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); |
| 1793 | atomic_dec(&open_file->wrtPending); | 1793 | cifsFileInfo_put(open_file); |
| 1794 | } else { | 1794 | } else { |
| 1795 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, | 1795 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, |
| 1796 | cifs_sb->local_nls, | 1796 | cifs_sb->local_nls, |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0ad3e2d116a..1da4ab250ea 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
| @@ -119,20 +119,19 @@ AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon) | |||
| 119 | temp->pinode = pinode; | 119 | temp->pinode = pinode; |
| 120 | temp->tcon = tcon; | 120 | temp->tcon = tcon; |
| 121 | temp->netfid = fid; | 121 | temp->netfid = fid; |
| 122 | spin_lock(&GlobalMid_Lock); | 122 | spin_lock(&cifs_oplock_lock); |
| 123 | list_add_tail(&temp->qhead, &GlobalOplock_Q); | 123 | list_add_tail(&temp->qhead, &cifs_oplock_list); |
| 124 | spin_unlock(&GlobalMid_Lock); | 124 | spin_unlock(&cifs_oplock_lock); |
| 125 | } | 125 | } |
| 126 | return temp; | 126 | return temp; |
| 127 | |||
| 128 | } | 127 | } |
| 129 | 128 | ||
| 130 | void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry) | 129 | void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry) |
| 131 | { | 130 | { |
| 132 | spin_lock(&GlobalMid_Lock); | 131 | spin_lock(&cifs_oplock_lock); |
| 133 | /* should we check if list empty first? */ | 132 | /* should we check if list empty first? */ |
| 134 | list_del(&oplockEntry->qhead); | 133 | list_del(&oplockEntry->qhead); |
| 135 | spin_unlock(&GlobalMid_Lock); | 134 | spin_unlock(&cifs_oplock_lock); |
| 136 | kmem_cache_free(cifs_oplock_cachep, oplockEntry); | 135 | kmem_cache_free(cifs_oplock_cachep, oplockEntry); |
| 137 | } | 136 | } |
| 138 | 137 | ||
| @@ -144,14 +143,14 @@ void DeleteTconOplockQEntries(struct cifsTconInfo *tcon) | |||
| 144 | if (tcon == NULL) | 143 | if (tcon == NULL) |
| 145 | return; | 144 | return; |
| 146 | 145 | ||
| 147 | spin_lock(&GlobalMid_Lock); | 146 | spin_lock(&cifs_oplock_lock); |
| 148 | list_for_each_entry(temp, &GlobalOplock_Q, qhead) { | 147 | list_for_each_entry(temp, &cifs_oplock_list, qhead) { |
| 149 | if ((temp->tcon) && (temp->tcon == tcon)) { | 148 | if ((temp->tcon) && (temp->tcon == tcon)) { |
| 150 | list_del(&temp->qhead); | 149 | list_del(&temp->qhead); |
| 151 | kmem_cache_free(cifs_oplock_cachep, temp); | 150 | kmem_cache_free(cifs_oplock_cachep, temp); |
| 152 | } | 151 | } |
| 153 | } | 152 | } |
| 154 | spin_unlock(&GlobalMid_Lock); | 153 | spin_unlock(&cifs_oplock_lock); |
| 155 | } | 154 | } |
| 156 | 155 | ||
| 157 | static int | 156 | static int |
diff --git a/fs/compat.c b/fs/compat.c index 94502dab972..6d6f98fe64a 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -1485,20 +1485,15 @@ int compat_do_execve(char * filename, | |||
| 1485 | if (!bprm) | 1485 | if (!bprm) |
| 1486 | goto out_files; | 1486 | goto out_files; |
| 1487 | 1487 | ||
| 1488 | retval = -ERESTARTNOINTR; | 1488 | retval = prepare_bprm_creds(bprm); |
| 1489 | if (mutex_lock_interruptible(¤t->cred_guard_mutex)) | 1489 | if (retval) |
| 1490 | goto out_free; | 1490 | goto out_free; |
| 1491 | current->in_execve = 1; | ||
| 1492 | |||
| 1493 | retval = -ENOMEM; | ||
| 1494 | bprm->cred = prepare_exec_creds(); | ||
| 1495 | if (!bprm->cred) | ||
| 1496 | goto out_unlock; | ||
| 1497 | 1491 | ||
| 1498 | retval = check_unsafe_exec(bprm); | 1492 | retval = check_unsafe_exec(bprm); |
| 1499 | if (retval < 0) | 1493 | if (retval < 0) |
| 1500 | goto out_unlock; | 1494 | goto out_free; |
| 1501 | clear_in_exec = retval; | 1495 | clear_in_exec = retval; |
| 1496 | current->in_execve = 1; | ||
| 1502 | 1497 | ||
| 1503 | file = open_exec(filename); | 1498 | file = open_exec(filename); |
| 1504 | retval = PTR_ERR(file); | 1499 | retval = PTR_ERR(file); |
| @@ -1547,7 +1542,6 @@ int compat_do_execve(char * filename, | |||
| 1547 | /* execve succeeded */ | 1542 | /* execve succeeded */ |
| 1548 | current->fs->in_exec = 0; | 1543 | current->fs->in_exec = 0; |
| 1549 | current->in_execve = 0; | 1544 | current->in_execve = 0; |
| 1550 | mutex_unlock(¤t->cred_guard_mutex); | ||
| 1551 | acct_update_integrals(current); | 1545 | acct_update_integrals(current); |
| 1552 | free_bprm(bprm); | 1546 | free_bprm(bprm); |
| 1553 | if (displaced) | 1547 | if (displaced) |
| @@ -1567,10 +1561,7 @@ out_file: | |||
| 1567 | out_unmark: | 1561 | out_unmark: |
| 1568 | if (clear_in_exec) | 1562 | if (clear_in_exec) |
| 1569 | current->fs->in_exec = 0; | 1563 | current->fs->in_exec = 0; |
| 1570 | |||
| 1571 | out_unlock: | ||
| 1572 | current->in_execve = 0; | 1564 | current->in_execve = 0; |
| 1573 | mutex_unlock(¤t->cred_guard_mutex); | ||
| 1574 | 1565 | ||
| 1575 | out_free: | 1566 | out_free: |
| 1576 | free_bprm(bprm); | 1567 | free_bprm(bprm); |
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 4921e7426d9..a2f746066c5 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c | |||
| @@ -51,6 +51,7 @@ static const struct address_space_operations configfs_aops = { | |||
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | static struct backing_dev_info configfs_backing_dev_info = { | 53 | static struct backing_dev_info configfs_backing_dev_info = { |
| 54 | .name = "configfs", | ||
| 54 | .ra_pages = 0, /* No readahead */ | 55 | .ra_pages = 0, /* No readahead */ |
| 55 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, | 56 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, |
| 56 | }; | 57 | }; |
diff --git a/fs/dcache.c b/fs/dcache.c index 9e5cd3c3a6b..a100fa35a48 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <linux/swap.h> | 32 | #include <linux/swap.h> |
| 33 | #include <linux/bootmem.h> | 33 | #include <linux/bootmem.h> |
| 34 | #include <linux/fs_struct.h> | 34 | #include <linux/fs_struct.h> |
| 35 | #include <linux/hardirq.h> | ||
| 35 | #include "internal.h" | 36 | #include "internal.h" |
| 36 | 37 | ||
| 37 | int sysctl_vfs_cache_pressure __read_mostly = 100; | 38 | int sysctl_vfs_cache_pressure __read_mostly = 100; |
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 618a60f0388..240cef14fe5 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c | |||
| @@ -106,6 +106,7 @@ struct connection { | |||
| 106 | #define CF_CONNECT_PENDING 3 | 106 | #define CF_CONNECT_PENDING 3 |
| 107 | #define CF_INIT_PENDING 4 | 107 | #define CF_INIT_PENDING 4 |
| 108 | #define CF_IS_OTHERCON 5 | 108 | #define CF_IS_OTHERCON 5 |
| 109 | #define CF_CLOSE 6 | ||
| 109 | struct list_head writequeue; /* List of outgoing writequeue_entries */ | 110 | struct list_head writequeue; /* List of outgoing writequeue_entries */ |
| 110 | spinlock_t writequeue_lock; | 111 | spinlock_t writequeue_lock; |
| 111 | int (*rx_action) (struct connection *); /* What to do when active */ | 112 | int (*rx_action) (struct connection *); /* What to do when active */ |
| @@ -299,6 +300,8 @@ static void lowcomms_write_space(struct sock *sk) | |||
| 299 | 300 | ||
| 300 | static inline void lowcomms_connect_sock(struct connection *con) | 301 | static inline void lowcomms_connect_sock(struct connection *con) |
| 301 | { | 302 | { |
| 303 | if (test_bit(CF_CLOSE, &con->flags)) | ||
| 304 | return; | ||
| 302 | if (!test_and_set_bit(CF_CONNECT_PENDING, &con->flags)) | 305 | if (!test_and_set_bit(CF_CONNECT_PENDING, &con->flags)) |
| 303 | queue_work(send_workqueue, &con->swork); | 306 | queue_work(send_workqueue, &con->swork); |
| 304 | } | 307 | } |
| @@ -926,10 +929,8 @@ static void tcp_connect_to_sock(struct connection *con) | |||
| 926 | goto out_err; | 929 | goto out_err; |
| 927 | 930 | ||
| 928 | memset(&saddr, 0, sizeof(saddr)); | 931 | memset(&saddr, 0, sizeof(saddr)); |
| 929 | if (dlm_nodeid_to_addr(con->nodeid, &saddr)) { | 932 | if (dlm_nodeid_to_addr(con->nodeid, &saddr)) |
| 930 | sock_release(sock); | ||
| 931 | goto out_err; | 933 | goto out_err; |
| 932 | } | ||
| 933 | 934 | ||
| 934 | sock->sk->sk_user_data = con; | 935 | sock->sk->sk_user_data = con; |
| 935 | con->rx_action = receive_from_sock; | 936 | con->rx_action = receive_from_sock; |
| @@ -1284,7 +1285,6 @@ out: | |||
| 1284 | static void send_to_sock(struct connection *con) | 1285 | static void send_to_sock(struct connection *con) |
| 1285 | { | 1286 | { |
| 1286 | int ret = 0; | 1287 | int ret = 0; |
| 1287 | ssize_t(*sendpage) (struct socket *, struct page *, int, size_t, int); | ||
| 1288 | const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; | 1288 | const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; |
| 1289 | struct writequeue_entry *e; | 1289 | struct writequeue_entry *e; |
| 1290 | int len, offset; | 1290 | int len, offset; |
| @@ -1293,8 +1293,6 @@ static void send_to_sock(struct connection *con) | |||
| 1293 | if (con->sock == NULL) | 1293 | if (con->sock == NULL) |
| 1294 | goto out_connect; | 1294 | goto out_connect; |
| 1295 | 1295 | ||
| 1296 | sendpage = con->sock->ops->sendpage; | ||
| 1297 | |||
| 1298 | spin_lock(&con->writequeue_lock); | 1296 | spin_lock(&con->writequeue_lock); |
| 1299 | for (;;) { | 1297 | for (;;) { |
| 1300 | e = list_entry(con->writequeue.next, struct writequeue_entry, | 1298 | e = list_entry(con->writequeue.next, struct writequeue_entry, |
| @@ -1309,8 +1307,8 @@ static void send_to_sock(struct connection *con) | |||
| 1309 | 1307 | ||
| 1310 | ret = 0; | 1308 | ret = 0; |
| 1311 | if (len) { | 1309 | if (len) { |
| 1312 | ret = sendpage(con->sock, e->page, offset, len, | 1310 | ret = kernel_sendpage(con->sock, e->page, offset, len, |
| 1313 | msg_flags); | 1311 | msg_flags); |
| 1314 | if (ret == -EAGAIN || ret == 0) { | 1312 | if (ret == -EAGAIN || ret == 0) { |
| 1315 | cond_resched(); | 1313 | cond_resched(); |
| 1316 | goto out; | 1314 | goto out; |
| @@ -1370,6 +1368,13 @@ int dlm_lowcomms_close(int nodeid) | |||
| 1370 | log_print("closing connection to node %d", nodeid); | 1368 | log_print("closing connection to node %d", nodeid); |
| 1371 | con = nodeid2con(nodeid, 0); | 1369 | con = nodeid2con(nodeid, 0); |
| 1372 | if (con) { | 1370 | if (con) { |
| 1371 | clear_bit(CF_CONNECT_PENDING, &con->flags); | ||
| 1372 | clear_bit(CF_WRITE_PENDING, &con->flags); | ||
| 1373 | set_bit(CF_CLOSE, &con->flags); | ||
| 1374 | if (cancel_work_sync(&con->swork)) | ||
| 1375 | log_print("canceled swork for node %d", nodeid); | ||
| 1376 | if (cancel_work_sync(&con->rwork)) | ||
| 1377 | log_print("canceled rwork for node %d", nodeid); | ||
| 1373 | clean_one_writequeue(con); | 1378 | clean_one_writequeue(con); |
| 1374 | close_connection(con, true); | 1379 | close_connection(con, true); |
| 1375 | } | 1380 | } |
| @@ -1395,9 +1400,10 @@ static void process_send_sockets(struct work_struct *work) | |||
| 1395 | 1400 | ||
| 1396 | if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) { | 1401 | if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) { |
| 1397 | con->connect_action(con); | 1402 | con->connect_action(con); |
| 1403 | set_bit(CF_WRITE_PENDING, &con->flags); | ||
| 1398 | } | 1404 | } |
| 1399 | clear_bit(CF_WRITE_PENDING, &con->flags); | 1405 | if (test_and_clear_bit(CF_WRITE_PENDING, &con->flags)) |
| 1400 | send_to_sock(con); | 1406 | send_to_sock(con); |
| 1401 | } | 1407 | } |
| 1402 | 1408 | ||
| 1403 | 1409 | ||
diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c index ccc9d62c462..55ea369f43a 100644 --- a/fs/dlm/netlink.c +++ b/fs/dlm/netlink.c | |||
| @@ -63,7 +63,7 @@ static int send_data(struct sk_buff *skb) | |||
| 63 | return rv; | 63 | return rv; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | return genlmsg_unicast(skb, listener_nlpid); | 66 | return genlmsg_unicast(&init_net, skb, listener_nlpid); |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | static int user_cmd(struct sk_buff *skb, struct genl_info *info) | 69 | static int user_cmd(struct sk_buff *skb, struct genl_info *info) |
| @@ -1016,6 +1016,35 @@ out: | |||
| 1016 | EXPORT_SYMBOL(flush_old_exec); | 1016 | EXPORT_SYMBOL(flush_old_exec); |
| 1017 | 1017 | ||
| 1018 | /* | 1018 | /* |
| 1019 | * Prepare credentials and lock ->cred_guard_mutex. | ||
| 1020 | * install_exec_creds() commits the new creds and drops the lock. | ||
| 1021 | * Or, if exec fails before, free_bprm() should release ->cred and | ||
| 1022 | * and unlock. | ||
| 1023 | */ | ||
| 1024 | int prepare_bprm_creds(struct linux_binprm *bprm) | ||
| 1025 | { | ||
| 1026 | if (mutex_lock_interruptible(¤t->cred_guard_mutex)) | ||
| 1027 | return -ERESTARTNOINTR; | ||
| 1028 | |||
| 1029 | bprm->cred = prepare_exec_creds(); | ||
| 1030 | if (likely(bprm->cred)) | ||
| 1031 | return 0; | ||
| 1032 | |||
| 1033 | mutex_unlock(¤t->cred_guard_mutex); | ||
| 1034 | return -ENOMEM; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | void free_bprm(struct linux_binprm *bprm) | ||
| 1038 | { | ||
| 1039 | free_arg_pages(bprm); | ||
| 1040 | if (bprm->cred) { | ||
| 1041 | mutex_unlock(¤t->cred_guard_mutex); | ||
| 1042 | abort_creds(bprm->cred); | ||
| 1043 | } | ||
| 1044 | kfree(bprm); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | /* | ||
| 1019 | * install the new credentials for this executable | 1048 | * install the new credentials for this executable |
| 1020 | */ | 1049 | */ |
| 1021 | void install_exec_creds(struct linux_binprm *bprm) | 1050 | void install_exec_creds(struct linux_binprm *bprm) |
| @@ -1024,12 +1053,13 @@ void install_exec_creds(struct linux_binprm *bprm) | |||
| 1024 | 1053 | ||
| 1025 | commit_creds(bprm->cred); | 1054 | commit_creds(bprm->cred); |
| 1026 | bprm->cred = NULL; | 1055 | bprm->cred = NULL; |
| 1027 | 1056 | /* | |
| 1028 | /* cred_guard_mutex must be held at least to this point to prevent | 1057 | * cred_guard_mutex must be held at least to this point to prevent |
| 1029 | * ptrace_attach() from altering our determination of the task's | 1058 | * ptrace_attach() from altering our determination of the task's |
| 1030 | * credentials; any time after this it may be unlocked */ | 1059 | * credentials; any time after this it may be unlocked. |
| 1031 | 1060 | */ | |
| 1032 | security_bprm_committed_creds(bprm); | 1061 | security_bprm_committed_creds(bprm); |
| 1062 | mutex_unlock(¤t->cred_guard_mutex); | ||
| 1033 | } | 1063 | } |
| 1034 | EXPORT_SYMBOL(install_exec_creds); | 1064 | EXPORT_SYMBOL(install_exec_creds); |
| 1035 | 1065 | ||
| @@ -1246,14 +1276,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
| 1246 | 1276 | ||
| 1247 | EXPORT_SYMBOL(search_binary_handler); | 1277 | EXPORT_SYMBOL(search_binary_handler); |
| 1248 | 1278 | ||
| 1249 | void free_bprm(struct linux_binprm *bprm) | ||
| 1250 | { | ||
| 1251 | free_arg_pages(bprm); | ||
| 1252 | if (bprm->cred) | ||
| 1253 | abort_creds(bprm->cred); | ||
| 1254 | kfree(bprm); | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | /* | 1279 | /* |
| 1258 | * sys_execve() executes a new program. | 1280 | * sys_execve() executes a new program. |
| 1259 | */ | 1281 | */ |
| @@ -1277,20 +1299,15 @@ int do_execve(char * filename, | |||
| 1277 | if (!bprm) | 1299 | if (!bprm) |
| 1278 | goto out_files; | 1300 | goto out_files; |
| 1279 | 1301 | ||
| 1280 | retval = -ERESTARTNOINTR; | 1302 | retval = prepare_bprm_creds(bprm); |
| 1281 | if (mutex_lock_interruptible(¤t->cred_guard_mutex)) | 1303 | if (retval) |
| 1282 | goto out_free; | 1304 | goto out_free; |
| 1283 | current->in_execve = 1; | ||
| 1284 | |||
| 1285 | retval = -ENOMEM; | ||
| 1286 | bprm->cred = prepare_exec_creds(); | ||
| 1287 | if (!bprm->cred) | ||
| 1288 | goto out_unlock; | ||
| 1289 | 1305 | ||
| 1290 | retval = check_unsafe_exec(bprm); | 1306 | retval = check_unsafe_exec(bprm); |
| 1291 | if (retval < 0) | 1307 | if (retval < 0) |
| 1292 | goto out_unlock; | 1308 | goto out_free; |
| 1293 | clear_in_exec = retval; | 1309 | clear_in_exec = retval; |
| 1310 | current->in_execve = 1; | ||
| 1294 | 1311 | ||
| 1295 | file = open_exec(filename); | 1312 | file = open_exec(filename); |
| 1296 | retval = PTR_ERR(file); | 1313 | retval = PTR_ERR(file); |
| @@ -1340,7 +1357,6 @@ int do_execve(char * filename, | |||
| 1340 | /* execve succeeded */ | 1357 | /* execve succeeded */ |
| 1341 | current->fs->in_exec = 0; | 1358 | current->fs->in_exec = 0; |
| 1342 | current->in_execve = 0; | 1359 | current->in_execve = 0; |
| 1343 | mutex_unlock(¤t->cred_guard_mutex); | ||
| 1344 | acct_update_integrals(current); | 1360 | acct_update_integrals(current); |
| 1345 | free_bprm(bprm); | 1361 | free_bprm(bprm); |
| 1346 | if (displaced) | 1362 | if (displaced) |
| @@ -1360,10 +1376,7 @@ out_file: | |||
| 1360 | out_unmark: | 1376 | out_unmark: |
| 1361 | if (clear_in_exec) | 1377 | if (clear_in_exec) |
| 1362 | current->fs->in_exec = 0; | 1378 | current->fs->in_exec = 0; |
| 1363 | |||
| 1364 | out_unlock: | ||
| 1365 | current->in_execve = 0; | 1379 | current->in_execve = 0; |
| 1366 | mutex_unlock(¤t->cred_guard_mutex); | ||
| 1367 | 1380 | ||
| 1368 | out_free: | 1381 | out_free: |
| 1369 | free_bprm(bprm); | 1382 | free_bprm(bprm); |
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index d636e1297ca..a63d44256a7 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c | |||
| @@ -230,7 +230,7 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
| 230 | return error; | 230 | return error; |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | static int | 233 | int |
| 234 | ext2_check_acl(struct inode *inode, int mask) | 234 | ext2_check_acl(struct inode *inode, int mask) |
| 235 | { | 235 | { |
| 236 | struct posix_acl *acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); | 236 | struct posix_acl *acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); |
| @@ -246,12 +246,6 @@ ext2_check_acl(struct inode *inode, int mask) | |||
| 246 | return -EAGAIN; | 246 | return -EAGAIN; |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | int | ||
| 250 | ext2_permission(struct inode *inode, int mask) | ||
| 251 | { | ||
| 252 | return generic_permission(inode, mask, ext2_check_acl); | ||
| 253 | } | ||
| 254 | |||
| 255 | /* | 249 | /* |
| 256 | * Initialize the ACLs of a new inode. Called from ext2_new_inode. | 250 | * Initialize the ACLs of a new inode. Called from ext2_new_inode. |
| 257 | * | 251 | * |
diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h index ecefe478898..3ff6cbb9ac4 100644 --- a/fs/ext2/acl.h +++ b/fs/ext2/acl.h | |||
| @@ -54,13 +54,13 @@ static inline int ext2_acl_count(size_t size) | |||
| 54 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | 54 | #ifdef CONFIG_EXT2_FS_POSIX_ACL |
| 55 | 55 | ||
| 56 | /* acl.c */ | 56 | /* acl.c */ |
| 57 | extern int ext2_permission (struct inode *, int); | 57 | extern int ext2_check_acl (struct inode *, int); |
| 58 | extern int ext2_acl_chmod (struct inode *); | 58 | extern int ext2_acl_chmod (struct inode *); |
| 59 | extern int ext2_init_acl (struct inode *, struct inode *); | 59 | extern int ext2_init_acl (struct inode *, struct inode *); |
| 60 | 60 | ||
| 61 | #else | 61 | #else |
| 62 | #include <linux/sched.h> | 62 | #include <linux/sched.h> |
| 63 | #define ext2_permission NULL | 63 | #define ext2_check_acl NULL |
| 64 | #define ext2_get_acl NULL | 64 | #define ext2_get_acl NULL |
| 65 | #define ext2_set_acl NULL | 65 | #define ext2_set_acl NULL |
| 66 | 66 | ||
diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 2b9e47dc922..a2f3afd1a1c 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c | |||
| @@ -85,6 +85,6 @@ const struct inode_operations ext2_file_inode_operations = { | |||
| 85 | .removexattr = generic_removexattr, | 85 | .removexattr = generic_removexattr, |
| 86 | #endif | 86 | #endif |
| 87 | .setattr = ext2_setattr, | 87 | .setattr = ext2_setattr, |
| 88 | .permission = ext2_permission, | 88 | .check_acl = ext2_check_acl, |
| 89 | .fiemap = ext2_fiemap, | 89 | .fiemap = ext2_fiemap, |
| 90 | }; | 90 | }; |
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index e27130341d4..1c1638f873a 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
| @@ -482,7 +482,7 @@ static int ext2_alloc_branch(struct inode *inode, | |||
| 482 | unlock_buffer(bh); | 482 | unlock_buffer(bh); |
| 483 | mark_buffer_dirty_inode(bh, inode); | 483 | mark_buffer_dirty_inode(bh, inode); |
| 484 | /* We used to sync bh here if IS_SYNC(inode). | 484 | /* We used to sync bh here if IS_SYNC(inode). |
| 485 | * But we now rely upon generic_osync_inode() | 485 | * But we now rely upon generic_write_sync() |
| 486 | * and b_inode_buffers. But not for directories. | 486 | * and b_inode_buffers. But not for directories. |
| 487 | */ | 487 | */ |
| 488 | if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) | 488 | if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) |
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index e1dedb0f787..23701f289e9 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c | |||
| @@ -362,6 +362,10 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, | |||
| 362 | if (dir_de) { | 362 | if (dir_de) { |
| 363 | if (old_dir != new_dir) | 363 | if (old_dir != new_dir) |
| 364 | ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0); | 364 | ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0); |
| 365 | else { | ||
| 366 | kunmap(dir_page); | ||
| 367 | page_cache_release(dir_page); | ||
| 368 | } | ||
| 365 | inode_dec_link_count(old_dir); | 369 | inode_dec_link_count(old_dir); |
| 366 | } | 370 | } |
| 367 | return 0; | 371 | return 0; |
| @@ -396,7 +400,7 @@ const struct inode_operations ext2_dir_inode_operations = { | |||
| 396 | .removexattr = generic_removexattr, | 400 | .removexattr = generic_removexattr, |
| 397 | #endif | 401 | #endif |
| 398 | .setattr = ext2_setattr, | 402 | .setattr = ext2_setattr, |
| 399 | .permission = ext2_permission, | 403 | .check_acl = ext2_check_acl, |
| 400 | }; | 404 | }; |
| 401 | 405 | ||
| 402 | const struct inode_operations ext2_special_inode_operations = { | 406 | const struct inode_operations ext2_special_inode_operations = { |
| @@ -407,5 +411,5 @@ const struct inode_operations ext2_special_inode_operations = { | |||
| 407 | .removexattr = generic_removexattr, | 411 | .removexattr = generic_removexattr, |
| 408 | #endif | 412 | #endif |
| 409 | .setattr = ext2_setattr, | 413 | .setattr = ext2_setattr, |
| 410 | .permission = ext2_permission, | 414 | .check_acl = ext2_check_acl, |
| 411 | }; | 415 | }; |
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index e167bae37ef..c9b0df376b5 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c | |||
| @@ -238,7 +238,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, | |||
| 238 | return error; | 238 | return error; |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | static int | 241 | int |
| 242 | ext3_check_acl(struct inode *inode, int mask) | 242 | ext3_check_acl(struct inode *inode, int mask) |
| 243 | { | 243 | { |
| 244 | struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); | 244 | struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); |
| @@ -254,12 +254,6 @@ ext3_check_acl(struct inode *inode, int mask) | |||
| 254 | return -EAGAIN; | 254 | return -EAGAIN; |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | int | ||
| 258 | ext3_permission(struct inode *inode, int mask) | ||
| 259 | { | ||
| 260 | return generic_permission(inode, mask, ext3_check_acl); | ||
| 261 | } | ||
| 262 | |||
| 263 | /* | 257 | /* |
| 264 | * Initialize the ACLs of a new inode. Called from ext3_new_inode. | 258 | * Initialize the ACLs of a new inode. Called from ext3_new_inode. |
| 265 | * | 259 | * |
diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h index 07d15a3a596..597334626de 100644 --- a/fs/ext3/acl.h +++ b/fs/ext3/acl.h | |||
| @@ -54,13 +54,13 @@ static inline int ext3_acl_count(size_t size) | |||
| 54 | #ifdef CONFIG_EXT3_FS_POSIX_ACL | 54 | #ifdef CONFIG_EXT3_FS_POSIX_ACL |
| 55 | 55 | ||
| 56 | /* acl.c */ | 56 | /* acl.c */ |
| 57 | extern int ext3_permission (struct inode *, int); | 57 | extern int ext3_check_acl (struct inode *, int); |
| 58 | extern int ext3_acl_chmod (struct inode *); | 58 | extern int ext3_acl_chmod (struct inode *); |
| 59 | extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); | 59 | extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); |
| 60 | 60 | ||
| 61 | #else /* CONFIG_EXT3_FS_POSIX_ACL */ | 61 | #else /* CONFIG_EXT3_FS_POSIX_ACL */ |
| 62 | #include <linux/sched.h> | 62 | #include <linux/sched.h> |
| 63 | #define ext3_permission NULL | 63 | #define ext3_check_acl NULL |
| 64 | 64 | ||
| 65 | static inline int | 65 | static inline int |
| 66 | ext3_acl_chmod(struct inode *inode) | 66 | ext3_acl_chmod(struct inode *inode) |
diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 5b49704b231..388bbdfa0b4 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c | |||
| @@ -51,71 +51,12 @@ static int ext3_release_file (struct inode * inode, struct file * filp) | |||
| 51 | return 0; | 51 | return 0; |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | static ssize_t | ||
| 55 | ext3_file_write(struct kiocb *iocb, const struct iovec *iov, | ||
| 56 | unsigned long nr_segs, loff_t pos) | ||
| 57 | { | ||
| 58 | struct file *file = iocb->ki_filp; | ||
| 59 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 60 | ssize_t ret; | ||
| 61 | int err; | ||
| 62 | |||
| 63 | ret = generic_file_aio_write(iocb, iov, nr_segs, pos); | ||
| 64 | |||
| 65 | /* | ||
| 66 | * Skip flushing if there was an error, or if nothing was written. | ||
| 67 | */ | ||
| 68 | if (ret <= 0) | ||
| 69 | return ret; | ||
| 70 | |||
| 71 | /* | ||
| 72 | * If the inode is IS_SYNC, or is O_SYNC and we are doing data | ||
| 73 | * journalling then we need to make sure that we force the transaction | ||
| 74 | * to disk to keep all metadata uptodate synchronously. | ||
| 75 | */ | ||
| 76 | if (file->f_flags & O_SYNC) { | ||
| 77 | /* | ||
| 78 | * If we are non-data-journaled, then the dirty data has | ||
| 79 | * already been flushed to backing store by generic_osync_inode, | ||
| 80 | * and the inode has been flushed too if there have been any | ||
| 81 | * modifications other than mere timestamp updates. | ||
| 82 | * | ||
| 83 | * Open question --- do we care about flushing timestamps too | ||
| 84 | * if the inode is IS_SYNC? | ||
| 85 | */ | ||
| 86 | if (!ext3_should_journal_data(inode)) | ||
| 87 | return ret; | ||
| 88 | |||
| 89 | goto force_commit; | ||
| 90 | } | ||
| 91 | |||
| 92 | /* | ||
| 93 | * So we know that there has been no forced data flush. If the inode | ||
| 94 | * is marked IS_SYNC, we need to force one ourselves. | ||
| 95 | */ | ||
| 96 | if (!IS_SYNC(inode)) | ||
| 97 | return ret; | ||
| 98 | |||
| 99 | /* | ||
| 100 | * Open question #2 --- should we force data to disk here too? If we | ||
| 101 | * don't, the only impact is that data=writeback filesystems won't | ||
| 102 | * flush data to disk automatically on IS_SYNC, only metadata (but | ||
| 103 | * historically, that is what ext2 has done.) | ||
| 104 | */ | ||
| 105 | |||
| 106 | force_commit: | ||
| 107 | err = ext3_force_commit(inode->i_sb); | ||
| 108 | if (err) | ||
| 109 | return err; | ||
| 110 | return ret; | ||
| 111 | } | ||
| 112 | |||
| 113 | const struct file_operations ext3_file_operations = { | 54 | const struct file_operations ext3_file_operations = { |
| 114 | .llseek = generic_file_llseek, | 55 | .llseek = generic_file_llseek, |
| 115 | .read = do_sync_read, | 56 | .read = do_sync_read, |
| 116 | .write = do_sync_write, | 57 | .write = do_sync_write, |
| 117 | .aio_read = generic_file_aio_read, | 58 | .aio_read = generic_file_aio_read, |
| 118 | .aio_write = ext3_file_write, | 59 | .aio_write = generic_file_aio_write, |
| 119 | .unlocked_ioctl = ext3_ioctl, | 60 | .unlocked_ioctl = ext3_ioctl, |
| 120 | #ifdef CONFIG_COMPAT | 61 | #ifdef CONFIG_COMPAT |
| 121 | .compat_ioctl = ext3_compat_ioctl, | 62 | .compat_ioctl = ext3_compat_ioctl, |
| @@ -137,7 +78,7 @@ const struct inode_operations ext3_file_inode_operations = { | |||
| 137 | .listxattr = ext3_listxattr, | 78 | .listxattr = ext3_listxattr, |
| 138 | .removexattr = generic_removexattr, | 79 | .removexattr = generic_removexattr, |
| 139 | #endif | 80 | #endif |
| 140 | .permission = ext3_permission, | 81 | .check_acl = ext3_check_acl, |
| 141 | .fiemap = ext3_fiemap, | 82 | .fiemap = ext3_fiemap, |
| 142 | }; | 83 | }; |
| 143 | 84 | ||
diff --git a/fs/ext3/fsync.c b/fs/ext3/fsync.c index d33634119e1..451d166bbe9 100644 --- a/fs/ext3/fsync.c +++ b/fs/ext3/fsync.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include <linux/time.h> | 25 | #include <linux/time.h> |
| 26 | #include <linux/blkdev.h> | ||
| 26 | #include <linux/fs.h> | 27 | #include <linux/fs.h> |
| 27 | #include <linux/sched.h> | 28 | #include <linux/sched.h> |
| 28 | #include <linux/writeback.h> | 29 | #include <linux/writeback.h> |
| @@ -73,7 +74,7 @@ int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync) | |||
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | 76 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) |
| 76 | goto out; | 77 | goto flush; |
| 77 | 78 | ||
| 78 | /* | 79 | /* |
| 79 | * The VFS has written the file data. If the inode is unaltered | 80 | * The VFS has written the file data. If the inode is unaltered |
| @@ -85,7 +86,16 @@ int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync) | |||
| 85 | .nr_to_write = 0, /* sys_fsync did this */ | 86 | .nr_to_write = 0, /* sys_fsync did this */ |
| 86 | }; | 87 | }; |
| 87 | ret = sync_inode(inode, &wbc); | 88 | ret = sync_inode(inode, &wbc); |
| 89 | goto out; | ||
| 88 | } | 90 | } |
| 91 | flush: | ||
| 92 | /* | ||
| 93 | * In case we didn't commit a transaction, we have to flush | ||
| 94 | * disk caches manually so that data really is on persistent | ||
| 95 | * storage | ||
| 96 | */ | ||
| 97 | if (test_opt(inode->i_sb, BARRIER)) | ||
| 98 | blkdev_issue_flush(inode->i_sb->s_bdev, NULL); | ||
| 89 | out: | 99 | out: |
| 90 | return ret; | 100 | return ret; |
| 91 | } | 101 | } |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index b49908a167a..cd098a7b77f 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
| @@ -172,10 +172,21 @@ static int try_to_extend_transaction(handle_t *handle, struct inode *inode) | |||
| 172 | * so before we call here everything must be consistently dirtied against | 172 | * so before we call here everything must be consistently dirtied against |
| 173 | * this transaction. | 173 | * this transaction. |
| 174 | */ | 174 | */ |
| 175 | static int ext3_journal_test_restart(handle_t *handle, struct inode *inode) | 175 | static int truncate_restart_transaction(handle_t *handle, struct inode *inode) |
| 176 | { | 176 | { |
| 177 | int ret; | ||
| 178 | |||
| 177 | jbd_debug(2, "restarting handle %p\n", handle); | 179 | jbd_debug(2, "restarting handle %p\n", handle); |
| 178 | return ext3_journal_restart(handle, blocks_for_truncate(inode)); | 180 | /* |
| 181 | * Drop truncate_mutex to avoid deadlock with ext3_get_blocks_handle | ||
| 182 | * At this moment, get_block can be called only for blocks inside | ||
| 183 | * i_size since page cache has been already dropped and writes are | ||
| 184 | * blocked by i_mutex. So we can safely drop the truncate_mutex. | ||
| 185 | */ | ||
| 186 | mutex_unlock(&EXT3_I(inode)->truncate_mutex); | ||
| 187 | ret = ext3_journal_restart(handle, blocks_for_truncate(inode)); | ||
| 188 | mutex_lock(&EXT3_I(inode)->truncate_mutex); | ||
| 189 | return ret; | ||
| 179 | } | 190 | } |
| 180 | 191 | ||
| 181 | /* | 192 | /* |
| @@ -2072,7 +2083,7 @@ static void ext3_clear_blocks(handle_t *handle, struct inode *inode, | |||
| 2072 | ext3_journal_dirty_metadata(handle, bh); | 2083 | ext3_journal_dirty_metadata(handle, bh); |
| 2073 | } | 2084 | } |
| 2074 | ext3_mark_inode_dirty(handle, inode); | 2085 | ext3_mark_inode_dirty(handle, inode); |
| 2075 | ext3_journal_test_restart(handle, inode); | 2086 | truncate_restart_transaction(handle, inode); |
| 2076 | if (bh) { | 2087 | if (bh) { |
| 2077 | BUFFER_TRACE(bh, "retaking write access"); | 2088 | BUFFER_TRACE(bh, "retaking write access"); |
| 2078 | ext3_journal_get_write_access(handle, bh); | 2089 | ext3_journal_get_write_access(handle, bh); |
| @@ -2282,7 +2293,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, | |||
| 2282 | return; | 2293 | return; |
| 2283 | if (try_to_extend_transaction(handle, inode)) { | 2294 | if (try_to_extend_transaction(handle, inode)) { |
| 2284 | ext3_mark_inode_dirty(handle, inode); | 2295 | ext3_mark_inode_dirty(handle, inode); |
| 2285 | ext3_journal_test_restart(handle, inode); | 2296 | truncate_restart_transaction(handle, inode); |
| 2286 | } | 2297 | } |
| 2287 | 2298 | ||
| 2288 | ext3_free_blocks(handle, inode, nr, 1); | 2299 | ext3_free_blocks(handle, inode, nr, 1); |
| @@ -2892,6 +2903,10 @@ static int ext3_do_update_inode(handle_t *handle, | |||
| 2892 | struct buffer_head *bh = iloc->bh; | 2903 | struct buffer_head *bh = iloc->bh; |
| 2893 | int err = 0, rc, block; | 2904 | int err = 0, rc, block; |
| 2894 | 2905 | ||
| 2906 | again: | ||
| 2907 | /* we can't allow multiple procs in here at once, its a bit racey */ | ||
| 2908 | lock_buffer(bh); | ||
| 2909 | |||
| 2895 | /* For fields not not tracking in the in-memory inode, | 2910 | /* For fields not not tracking in the in-memory inode, |
| 2896 | * initialise them to zero for new inodes. */ | 2911 | * initialise them to zero for new inodes. */ |
| 2897 | if (ei->i_state & EXT3_STATE_NEW) | 2912 | if (ei->i_state & EXT3_STATE_NEW) |
| @@ -2951,16 +2966,20 @@ static int ext3_do_update_inode(handle_t *handle, | |||
| 2951 | /* If this is the first large file | 2966 | /* If this is the first large file |
| 2952 | * created, add a flag to the superblock. | 2967 | * created, add a flag to the superblock. |
| 2953 | */ | 2968 | */ |
| 2969 | unlock_buffer(bh); | ||
| 2954 | err = ext3_journal_get_write_access(handle, | 2970 | err = ext3_journal_get_write_access(handle, |
| 2955 | EXT3_SB(sb)->s_sbh); | 2971 | EXT3_SB(sb)->s_sbh); |
| 2956 | if (err) | 2972 | if (err) |
| 2957 | goto out_brelse; | 2973 | goto out_brelse; |
| 2974 | |||
| 2958 | ext3_update_dynamic_rev(sb); | 2975 | ext3_update_dynamic_rev(sb); |
| 2959 | EXT3_SET_RO_COMPAT_FEATURE(sb, | 2976 | EXT3_SET_RO_COMPAT_FEATURE(sb, |
| 2960 | EXT3_FEATURE_RO_COMPAT_LARGE_FILE); | 2977 | EXT3_FEATURE_RO_COMPAT_LARGE_FILE); |
| 2961 | handle->h_sync = 1; | 2978 | handle->h_sync = 1; |
| 2962 | err = ext3_journal_dirty_metadata(handle, | 2979 | err = ext3_journal_dirty_metadata(handle, |
| 2963 | EXT3_SB(sb)->s_sbh); | 2980 | EXT3_SB(sb)->s_sbh); |
| 2981 | /* get our lock and start over */ | ||
| 2982 | goto again; | ||
| 2964 | } | 2983 | } |
| 2965 | } | 2984 | } |
| 2966 | } | 2985 | } |
| @@ -2983,6 +3002,7 @@ static int ext3_do_update_inode(handle_t *handle, | |||
| 2983 | raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); | 3002 | raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); |
| 2984 | 3003 | ||
| 2985 | BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); | 3004 | BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); |
| 3005 | unlock_buffer(bh); | ||
| 2986 | rc = ext3_journal_dirty_metadata(handle, bh); | 3006 | rc = ext3_journal_dirty_metadata(handle, bh); |
| 2987 | if (!err) | 3007 | if (!err) |
| 2988 | err = rc; | 3008 | err = rc; |
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 6ff7b973023..aad6400c9b7 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c | |||
| @@ -2445,7 +2445,7 @@ const struct inode_operations ext3_dir_inode_operations = { | |||
| 2445 | .listxattr = ext3_listxattr, | 2445 | .listxattr = ext3_listxattr, |
| 2446 | .removexattr = generic_removexattr, | 2446 | .removexattr = generic_removexattr, |
| 2447 | #endif | 2447 | #endif |
| 2448 | .permission = ext3_permission, | 2448 | .check_acl = ext3_check_acl, |
| 2449 | }; | 2449 | }; |
| 2450 | 2450 | ||
| 2451 | const struct inode_operations ext3_special_inode_operations = { | 2451 | const struct inode_operations ext3_special_inode_operations = { |
| @@ -2456,5 +2456,5 @@ const struct inode_operations ext3_special_inode_operations = { | |||
| 2456 | .listxattr = ext3_listxattr, | 2456 | .listxattr = ext3_listxattr, |
| 2457 | .removexattr = generic_removexattr, | 2457 | .removexattr = generic_removexattr, |
| 2458 | #endif | 2458 | #endif |
| 2459 | .permission = ext3_permission, | 2459 | .check_acl = ext3_check_acl, |
| 2460 | }; | 2460 | }; |
diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig index 418b6f3b0ae..d5c0ea2e8f2 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig | |||
| @@ -37,7 +37,7 @@ config EXT4DEV_COMPAT | |||
| 37 | 37 | ||
| 38 | To enable backwards compatibility so that systems that are | 38 | To enable backwards compatibility so that systems that are |
| 39 | still expecting to mount ext4 filesystems using ext4dev, | 39 | still expecting to mount ext4 filesystems using ext4dev, |
| 40 | chose Y here. This feature will go away by 2.6.31, so | 40 | choose Y here. This feature will go away by 2.6.31, so |
| 41 | please arrange to get your userspace programs fixed! | 41 | please arrange to get your userspace programs fixed! |
| 42 | 42 | ||
| 43 | config EXT4_FS_XATTR | 43 | config EXT4_FS_XATTR |
| @@ -77,3 +77,12 @@ config EXT4_FS_SECURITY | |||
| 77 | 77 | ||
| 78 | If you are not using a security module that requires using | 78 | If you are not using a security module that requires using |
| 79 | extended attributes for file security labels, say N. | 79 | extended attributes for file security labels, say N. |
| 80 | |||
| 81 | config EXT4_DEBUG | ||
| 82 | bool "EXT4 debugging support" | ||
| 83 | depends on EXT4_FS | ||
| 84 | help | ||
| 85 | Enables run-time debugging support for the ext4 filesystem. | ||
| 86 | |||
| 87 | If you select Y here, then you will be able to turn on debugging | ||
| 88 | with a command such as "echo 1 > /sys/kernel/debug/ext4/mballoc-debug" | ||
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index f6d8967149c..0df88b2a69b 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c | |||
| @@ -236,7 +236,7 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, | |||
| 236 | return error; | 236 | return error; |
| 237 | } | 237 | } |
| 238 | 238 | ||
| 239 | static int | 239 | int |
| 240 | ext4_check_acl(struct inode *inode, int mask) | 240 | ext4_check_acl(struct inode *inode, int mask) |
| 241 | { | 241 | { |
| 242 | struct posix_acl *acl = ext4_get_acl(inode, ACL_TYPE_ACCESS); | 242 | struct posix_acl *acl = ext4_get_acl(inode, ACL_TYPE_ACCESS); |
| @@ -252,12 +252,6 @@ ext4_check_acl(struct inode *inode, int mask) | |||
| 252 | return -EAGAIN; | 252 | return -EAGAIN; |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | int | ||
| 256 | ext4_permission(struct inode *inode, int mask) | ||
| 257 | { | ||
| 258 | return generic_permission(inode, mask, ext4_check_acl); | ||
| 259 | } | ||
| 260 | |||
| 261 | /* | 255 | /* |
| 262 | * Initialize the ACLs of a new inode. Called from ext4_new_inode. | 256 | * Initialize the ACLs of a new inode. Called from ext4_new_inode. |
| 263 | * | 257 | * |
diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h index 949789d2bba..9d843d5deac 100644 --- a/fs/ext4/acl.h +++ b/fs/ext4/acl.h | |||
| @@ -54,13 +54,13 @@ static inline int ext4_acl_count(size_t size) | |||
| 54 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | 54 | #ifdef CONFIG_EXT4_FS_POSIX_ACL |
| 55 | 55 | ||
| 56 | /* acl.c */ | 56 | /* acl.c */ |
| 57 | extern int ext4_permission(struct inode *, int); | 57 | extern int ext4_check_acl(struct inode *, int); |
| 58 | extern int ext4_acl_chmod(struct inode *); | 58 | extern int ext4_acl_chmod(struct inode *); |
| 59 | extern int ext4_init_acl(handle_t *, struct inode *, struct inode *); | 59 | extern int ext4_init_acl(handle_t *, struct inode *, struct inode *); |
| 60 | 60 | ||
| 61 | #else /* CONFIG_EXT4_FS_POSIX_ACL */ | 61 | #else /* CONFIG_EXT4_FS_POSIX_ACL */ |
| 62 | #include <linux/sched.h> | 62 | #include <linux/sched.h> |
| 63 | #define ext4_permission NULL | 63 | #define ext4_check_acl NULL |
| 64 | 64 | ||
| 65 | static inline int | 65 | static inline int |
| 66 | ext4_acl_chmod(struct inode *inode) | 66 | ext4_acl_chmod(struct inode *inode) |
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index e2126d70dff..1d0418980f8 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
| @@ -478,7 +478,7 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb, | |||
| 478 | * new bitmap information | 478 | * new bitmap information |
| 479 | */ | 479 | */ |
| 480 | set_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &(grp->bb_state)); | 480 | set_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &(grp->bb_state)); |
| 481 | ext4_mb_update_group_info(grp, blocks_freed); | 481 | grp->bb_free += blocks_freed; |
| 482 | up_write(&grp->alloc_sem); | 482 | up_write(&grp->alloc_sem); |
| 483 | 483 | ||
| 484 | /* We dirtied the bitmap block */ | 484 | /* We dirtied the bitmap block */ |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 9714db393ef..e227eea23f0 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
| @@ -67,27 +67,29 @@ typedef unsigned int ext4_group_t; | |||
| 67 | 67 | ||
| 68 | 68 | ||
| 69 | /* prefer goal again. length */ | 69 | /* prefer goal again. length */ |
| 70 | #define EXT4_MB_HINT_MERGE 1 | 70 | #define EXT4_MB_HINT_MERGE 0x0001 |
| 71 | /* blocks already reserved */ | 71 | /* blocks already reserved */ |
| 72 | #define EXT4_MB_HINT_RESERVED 2 | 72 | #define EXT4_MB_HINT_RESERVED 0x0002 |
| 73 | /* metadata is being allocated */ | 73 | /* metadata is being allocated */ |
| 74 | #define EXT4_MB_HINT_METADATA 4 | 74 | #define EXT4_MB_HINT_METADATA 0x0004 |
| 75 | /* first blocks in the file */ | 75 | /* first blocks in the file */ |
| 76 | #define EXT4_MB_HINT_FIRST 8 | 76 | #define EXT4_MB_HINT_FIRST 0x0008 |
| 77 | /* search for the best chunk */ | 77 | /* search for the best chunk */ |
| 78 | #define EXT4_MB_HINT_BEST 16 | 78 | #define EXT4_MB_HINT_BEST 0x0010 |
| 79 | /* data is being allocated */ | 79 | /* data is being allocated */ |
| 80 | #define EXT4_MB_HINT_DATA 32 | 80 | #define EXT4_MB_HINT_DATA 0x0020 |
| 81 | /* don't preallocate (for tails) */ | 81 | /* don't preallocate (for tails) */ |
| 82 | #define EXT4_MB_HINT_NOPREALLOC 64 | 82 | #define EXT4_MB_HINT_NOPREALLOC 0x0040 |
| 83 | /* allocate for locality group */ | 83 | /* allocate for locality group */ |
| 84 | #define EXT4_MB_HINT_GROUP_ALLOC 128 | 84 | #define EXT4_MB_HINT_GROUP_ALLOC 0x0080 |
| 85 | /* allocate goal blocks or none */ | 85 | /* allocate goal blocks or none */ |
| 86 | #define EXT4_MB_HINT_GOAL_ONLY 256 | 86 | #define EXT4_MB_HINT_GOAL_ONLY 0x0100 |
| 87 | /* goal is meaningful */ | 87 | /* goal is meaningful */ |
| 88 | #define EXT4_MB_HINT_TRY_GOAL 512 | 88 | #define EXT4_MB_HINT_TRY_GOAL 0x0200 |
| 89 | /* blocks already pre-reserved by delayed allocation */ | 89 | /* blocks already pre-reserved by delayed allocation */ |
| 90 | #define EXT4_MB_DELALLOC_RESERVED 1024 | 90 | #define EXT4_MB_DELALLOC_RESERVED 0x0400 |
| 91 | /* We are doing stream allocation */ | ||
| 92 | #define EXT4_MB_STREAM_ALLOC 0x0800 | ||
| 91 | 93 | ||
| 92 | 94 | ||
| 93 | struct ext4_allocation_request { | 95 | struct ext4_allocation_request { |
| @@ -112,6 +114,21 @@ struct ext4_allocation_request { | |||
| 112 | }; | 114 | }; |
| 113 | 115 | ||
| 114 | /* | 116 | /* |
| 117 | * For delayed allocation tracking | ||
| 118 | */ | ||
| 119 | struct mpage_da_data { | ||
| 120 | struct inode *inode; | ||
| 121 | sector_t b_blocknr; /* start block number of extent */ | ||
| 122 | size_t b_size; /* size of extent */ | ||
| 123 | unsigned long b_state; /* state of the extent */ | ||
| 124 | unsigned long first_page, next_page; /* extent of pages */ | ||
| 125 | struct writeback_control *wbc; | ||
| 126 | int io_done; | ||
| 127 | int pages_written; | ||
| 128 | int retval; | ||
| 129 | }; | ||
| 130 | |||
| 131 | /* | ||
| 115 | * Special inodes numbers | 132 | * Special inodes numbers |
| 116 | */ | 133 | */ |
| 117 | #define EXT4_BAD_INO 1 /* Bad blocks inode */ | 134 | #define EXT4_BAD_INO 1 /* Bad blocks inode */ |
| @@ -251,7 +268,6 @@ struct flex_groups { | |||
| 251 | #define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ | 268 | #define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ |
| 252 | #define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ | 269 | #define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ |
| 253 | #define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ | 270 | #define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ |
| 254 | #define EXT4_EXT_MIGRATE 0x00100000 /* Inode is migrating */ | ||
| 255 | #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ | 271 | #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ |
| 256 | 272 | ||
| 257 | #define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */ | 273 | #define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */ |
| @@ -289,6 +305,7 @@ static inline __u32 ext4_mask_flags(umode_t mode, __u32 flags) | |||
| 289 | #define EXT4_STATE_XATTR 0x00000004 /* has in-inode xattrs */ | 305 | #define EXT4_STATE_XATTR 0x00000004 /* has in-inode xattrs */ |
| 290 | #define EXT4_STATE_NO_EXPAND 0x00000008 /* No space for expansion */ | 306 | #define EXT4_STATE_NO_EXPAND 0x00000008 /* No space for expansion */ |
| 291 | #define EXT4_STATE_DA_ALLOC_CLOSE 0x00000010 /* Alloc DA blks on close */ | 307 | #define EXT4_STATE_DA_ALLOC_CLOSE 0x00000010 /* Alloc DA blks on close */ |
| 308 | #define EXT4_STATE_EXT_MIGRATE 0x00000020 /* Inode is migrating */ | ||
| 292 | 309 | ||
| 293 | /* Used to pass group descriptor data when online resize is done */ | 310 | /* Used to pass group descriptor data when online resize is done */ |
| 294 | struct ext4_new_group_input { | 311 | struct ext4_new_group_input { |
| @@ -386,6 +403,9 @@ struct ext4_mount_options { | |||
| 386 | #endif | 403 | #endif |
| 387 | }; | 404 | }; |
| 388 | 405 | ||
| 406 | /* Max physical block we can addres w/o extents */ | ||
| 407 | #define EXT4_MAX_BLOCK_FILE_PHYS 0xFFFFFFFF | ||
| 408 | |||
| 389 | /* | 409 | /* |
| 390 | * Structure of an inode on the disk | 410 | * Structure of an inode on the disk |
| 391 | */ | 411 | */ |
| @@ -456,7 +476,6 @@ struct move_extent { | |||
| 456 | __u64 len; /* block length to be moved */ | 476 | __u64 len; /* block length to be moved */ |
| 457 | __u64 moved_len; /* moved block length */ | 477 | __u64 moved_len; /* moved block length */ |
| 458 | }; | 478 | }; |
| 459 | #define MAX_DEFRAG_SIZE ((1UL<<31) - 1) | ||
| 460 | 479 | ||
| 461 | #define EXT4_EPOCH_BITS 2 | 480 | #define EXT4_EPOCH_BITS 2 |
| 462 | #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) | 481 | #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) |
| @@ -694,7 +713,6 @@ struct ext4_inode_info { | |||
| 694 | #define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */ | 713 | #define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */ |
| 695 | #define EXT4_MOUNT_USRQUOTA 0x100000 /* "old" user quota */ | 714 | #define EXT4_MOUNT_USRQUOTA 0x100000 /* "old" user quota */ |
| 696 | #define EXT4_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */ | 715 | #define EXT4_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */ |
| 697 | #define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */ | ||
| 698 | #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */ | 716 | #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */ |
| 699 | #define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */ | 717 | #define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */ |
| 700 | #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ | 718 | #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ |
| @@ -841,6 +859,7 @@ struct ext4_sb_info { | |||
| 841 | unsigned long s_gdb_count; /* Number of group descriptor blocks */ | 859 | unsigned long s_gdb_count; /* Number of group descriptor blocks */ |
| 842 | unsigned long s_desc_per_block; /* Number of group descriptors per block */ | 860 | unsigned long s_desc_per_block; /* Number of group descriptors per block */ |
| 843 | ext4_group_t s_groups_count; /* Number of groups in the fs */ | 861 | ext4_group_t s_groups_count; /* Number of groups in the fs */ |
| 862 | ext4_group_t s_blockfile_groups;/* Groups acceptable for non-extent files */ | ||
| 844 | unsigned long s_overhead_last; /* Last calculated overhead */ | 863 | unsigned long s_overhead_last; /* Last calculated overhead */ |
| 845 | unsigned long s_blocks_last; /* Last seen block count */ | 864 | unsigned long s_blocks_last; /* Last seen block count */ |
| 846 | loff_t s_bitmap_maxbytes; /* max bytes for bitmap files */ | 865 | loff_t s_bitmap_maxbytes; /* max bytes for bitmap files */ |
| @@ -950,6 +969,7 @@ struct ext4_sb_info { | |||
| 950 | atomic_t s_mb_lost_chunks; | 969 | atomic_t s_mb_lost_chunks; |
| 951 | atomic_t s_mb_preallocated; | 970 | atomic_t s_mb_preallocated; |
| 952 | atomic_t s_mb_discarded; | 971 | atomic_t s_mb_discarded; |
| 972 | atomic_t s_lock_busy; | ||
| 953 | 973 | ||
| 954 | /* locality groups */ | 974 | /* locality groups */ |
| 955 | struct ext4_locality_group *s_locality_groups; | 975 | struct ext4_locality_group *s_locality_groups; |
| @@ -1340,8 +1360,6 @@ extern void ext4_mb_free_blocks(handle_t *, struct inode *, | |||
| 1340 | ext4_fsblk_t, unsigned long, int, unsigned long *); | 1360 | ext4_fsblk_t, unsigned long, int, unsigned long *); |
| 1341 | extern int ext4_mb_add_groupinfo(struct super_block *sb, | 1361 | extern int ext4_mb_add_groupinfo(struct super_block *sb, |
| 1342 | ext4_group_t i, struct ext4_group_desc *desc); | 1362 | ext4_group_t i, struct ext4_group_desc *desc); |
| 1343 | extern void ext4_mb_update_group_info(struct ext4_group_info *grp, | ||
| 1344 | ext4_grpblk_t add); | ||
| 1345 | extern int ext4_mb_get_buddy_cache_lock(struct super_block *, ext4_group_t); | 1363 | extern int ext4_mb_get_buddy_cache_lock(struct super_block *, ext4_group_t); |
| 1346 | extern void ext4_mb_put_buddy_cache_lock(struct super_block *, | 1364 | extern void ext4_mb_put_buddy_cache_lock(struct super_block *, |
| 1347 | ext4_group_t, int); | 1365 | ext4_group_t, int); |
| @@ -1367,6 +1385,7 @@ extern int ext4_change_inode_journal_flag(struct inode *, int); | |||
| 1367 | extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *); | 1385 | extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *); |
| 1368 | extern int ext4_can_truncate(struct inode *inode); | 1386 | extern int ext4_can_truncate(struct inode *inode); |
| 1369 | extern void ext4_truncate(struct inode *); | 1387 | extern void ext4_truncate(struct inode *); |
| 1388 | extern int ext4_truncate_restart_trans(handle_t *, struct inode *, int nblocks); | ||
| 1370 | extern void ext4_set_inode_flags(struct inode *); | 1389 | extern void ext4_set_inode_flags(struct inode *); |
| 1371 | extern void ext4_get_inode_flags(struct ext4_inode_info *); | 1390 | extern void ext4_get_inode_flags(struct ext4_inode_info *); |
| 1372 | extern int ext4_alloc_da_blocks(struct inode *inode); | 1391 | extern int ext4_alloc_da_blocks(struct inode *inode); |
| @@ -1575,15 +1594,18 @@ static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize) | |||
| 1575 | struct ext4_group_info { | 1594 | struct ext4_group_info { |
| 1576 | unsigned long bb_state; | 1595 | unsigned long bb_state; |
| 1577 | struct rb_root bb_free_root; | 1596 | struct rb_root bb_free_root; |
| 1578 | unsigned short bb_first_free; | 1597 | ext4_grpblk_t bb_first_free; /* first free block */ |
| 1579 | unsigned short bb_free; | 1598 | ext4_grpblk_t bb_free; /* total free blocks */ |
| 1580 | unsigned short bb_fragments; | 1599 | ext4_grpblk_t bb_fragments; /* nr of freespace fragments */ |
| 1581 | struct list_head bb_prealloc_list; | 1600 | struct list_head bb_prealloc_list; |
| 1582 | #ifdef DOUBLE_CHECK | 1601 | #ifdef DOUBLE_CHECK |
| 1583 | void *bb_bitmap; | 1602 | void *bb_bitmap; |
| 1584 | #endif | 1603 | #endif |
| 1585 | struct rw_semaphore alloc_sem; | 1604 | struct rw_semaphore alloc_sem; |
| 1586 | unsigned short bb_counters[]; | 1605 | ext4_grpblk_t bb_counters[]; /* Nr of free power-of-two-block |
| 1606 | * regions, index is order. | ||
| 1607 | * bb_counters[3] = 5 means | ||
| 1608 | * 5 free 8-block regions. */ | ||
| 1587 | }; | 1609 | }; |
| 1588 | 1610 | ||
| 1589 | #define EXT4_GROUP_INFO_NEED_INIT_BIT 0 | 1611 | #define EXT4_GROUP_INFO_NEED_INIT_BIT 0 |
| @@ -1591,15 +1613,42 @@ struct ext4_group_info { | |||
| 1591 | #define EXT4_MB_GRP_NEED_INIT(grp) \ | 1613 | #define EXT4_MB_GRP_NEED_INIT(grp) \ |
| 1592 | (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) | 1614 | (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) |
| 1593 | 1615 | ||
| 1616 | #define EXT4_MAX_CONTENTION 8 | ||
| 1617 | #define EXT4_CONTENTION_THRESHOLD 2 | ||
| 1618 | |||
| 1594 | static inline spinlock_t *ext4_group_lock_ptr(struct super_block *sb, | 1619 | static inline spinlock_t *ext4_group_lock_ptr(struct super_block *sb, |
| 1595 | ext4_group_t group) | 1620 | ext4_group_t group) |
| 1596 | { | 1621 | { |
| 1597 | return bgl_lock_ptr(EXT4_SB(sb)->s_blockgroup_lock, group); | 1622 | return bgl_lock_ptr(EXT4_SB(sb)->s_blockgroup_lock, group); |
| 1598 | } | 1623 | } |
| 1599 | 1624 | ||
| 1625 | /* | ||
| 1626 | * Returns true if the filesystem is busy enough that attempts to | ||
| 1627 | * access the block group locks has run into contention. | ||
| 1628 | */ | ||
| 1629 | static inline int ext4_fs_is_busy(struct ext4_sb_info *sbi) | ||
| 1630 | { | ||
| 1631 | return (atomic_read(&sbi->s_lock_busy) > EXT4_CONTENTION_THRESHOLD); | ||
| 1632 | } | ||
| 1633 | |||
| 1600 | static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group) | 1634 | static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group) |
| 1601 | { | 1635 | { |
| 1602 | spin_lock(ext4_group_lock_ptr(sb, group)); | 1636 | spinlock_t *lock = ext4_group_lock_ptr(sb, group); |
| 1637 | if (spin_trylock(lock)) | ||
| 1638 | /* | ||
| 1639 | * We're able to grab the lock right away, so drop the | ||
| 1640 | * lock contention counter. | ||
| 1641 | */ | ||
| 1642 | atomic_add_unless(&EXT4_SB(sb)->s_lock_busy, -1, 0); | ||
| 1643 | else { | ||
| 1644 | /* | ||
| 1645 | * The lock is busy, so bump the contention counter, | ||
| 1646 | * and then wait on the spin lock. | ||
| 1647 | */ | ||
| 1648 | atomic_add_unless(&EXT4_SB(sb)->s_lock_busy, 1, | ||
| 1649 | EXT4_MAX_CONTENTION); | ||
| 1650 | spin_lock(lock); | ||
| 1651 | } | ||
| 1603 | } | 1652 | } |
| 1604 | 1653 | ||
| 1605 | static inline void ext4_unlock_group(struct super_block *sb, | 1654 | static inline void ext4_unlock_group(struct super_block *sb, |
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index 20a84105a10..61652f1d15e 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h | |||
| @@ -43,8 +43,7 @@ | |||
| 43 | #define CHECK_BINSEARCH__ | 43 | #define CHECK_BINSEARCH__ |
| 44 | 44 | ||
| 45 | /* | 45 | /* |
| 46 | * If EXT_DEBUG is defined you can use the 'extdebug' mount option | 46 | * Turn on EXT_DEBUG to get lots of info about extents operations. |
| 47 | * to get lots of info about what's going on. | ||
| 48 | */ | 47 | */ |
| 49 | #define EXT_DEBUG__ | 48 | #define EXT_DEBUG__ |
| 50 | #ifdef EXT_DEBUG | 49 | #ifdef EXT_DEBUG |
| @@ -138,6 +137,7 @@ typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *, | |||
| 138 | #define EXT_BREAK 1 | 137 | #define EXT_BREAK 1 |
| 139 | #define EXT_REPEAT 2 | 138 | #define EXT_REPEAT 2 |
| 140 | 139 | ||
| 140 | /* Maximum logical block in a file; ext4_extent's ee_block is __le32 */ | ||
| 141 | #define EXT_MAX_BLOCK 0xffffffff | 141 | #define EXT_MAX_BLOCK 0xffffffff |
| 142 | 142 | ||
| 143 | /* | 143 | /* |
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index eb27fd0f2ee..6a9409920de 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c | |||
| @@ -44,7 +44,7 @@ int __ext4_journal_forget(const char *where, handle_t *handle, | |||
| 44 | handle, err); | 44 | handle, err); |
| 45 | } | 45 | } |
| 46 | else | 46 | else |
| 47 | brelse(bh); | 47 | bforget(bh); |
| 48 | return err; | 48 | return err; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| @@ -60,7 +60,7 @@ int __ext4_journal_revoke(const char *where, handle_t *handle, | |||
| 60 | handle, err); | 60 | handle, err); |
| 61 | } | 61 | } |
| 62 | else | 62 | else |
| 63 | brelse(bh); | 63 | bforget(bh); |
| 64 | return err; | 64 | return err; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| @@ -89,7 +89,10 @@ int __ext4_handle_dirty_metadata(const char *where, handle_t *handle, | |||
| 89 | ext4_journal_abort_handle(where, __func__, bh, | 89 | ext4_journal_abort_handle(where, __func__, bh, |
| 90 | handle, err); | 90 | handle, err); |
| 91 | } else { | 91 | } else { |
| 92 | mark_buffer_dirty(bh); | 92 | if (inode && bh) |
| 93 | mark_buffer_dirty_inode(bh, inode); | ||
| 94 | else | ||
| 95 | mark_buffer_dirty(bh); | ||
| 93 | if (inode && inode_needs_sync(inode)) { | 96 | if (inode && inode_needs_sync(inode)) { |
| 94 | sync_dirty_buffer(bh); | 97 | sync_dirty_buffer(bh); |
| 95 | if (buffer_req(bh) && !buffer_uptodate(bh)) { | 98 | if (buffer_req(bh) && !buffer_uptodate(bh)) { |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 73ebfb44ad7..7a383257792 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
| @@ -93,7 +93,9 @@ static void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb) | |||
| 93 | ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff); | 93 | ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | static int ext4_ext_journal_restart(handle_t *handle, int needed) | 96 | static int ext4_ext_truncate_extend_restart(handle_t *handle, |
| 97 | struct inode *inode, | ||
| 98 | int needed) | ||
| 97 | { | 99 | { |
| 98 | int err; | 100 | int err; |
| 99 | 101 | ||
| @@ -104,7 +106,14 @@ static int ext4_ext_journal_restart(handle_t *handle, int needed) | |||
| 104 | err = ext4_journal_extend(handle, needed); | 106 | err = ext4_journal_extend(handle, needed); |
| 105 | if (err <= 0) | 107 | if (err <= 0) |
| 106 | return err; | 108 | return err; |
| 107 | return ext4_journal_restart(handle, needed); | 109 | err = ext4_truncate_restart_trans(handle, inode, needed); |
| 110 | /* | ||
| 111 | * We have dropped i_data_sem so someone might have cached again | ||
| 112 | * an extent we are going to truncate. | ||
| 113 | */ | ||
| 114 | ext4_ext_invalidate_cache(inode); | ||
| 115 | |||
| 116 | return err; | ||
| 108 | } | 117 | } |
| 109 | 118 | ||
| 110 | /* | 119 | /* |
| @@ -220,57 +229,65 @@ ext4_ext_new_meta_block(handle_t *handle, struct inode *inode, | |||
| 220 | return newblock; | 229 | return newblock; |
| 221 | } | 230 | } |
| 222 | 231 | ||
| 223 | static int ext4_ext_space_block(struct inode *inode) | 232 | static inline int ext4_ext_space_block(struct inode *inode, int check) |
| 224 | { | 233 | { |
| 225 | int size; | 234 | int size; |
| 226 | 235 | ||
| 227 | size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) | 236 | size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) |
| 228 | / sizeof(struct ext4_extent); | 237 | / sizeof(struct ext4_extent); |
| 238 | if (!check) { | ||
| 229 | #ifdef AGGRESSIVE_TEST | 239 | #ifdef AGGRESSIVE_TEST |
| 230 | if (size > 6) | 240 | if (size > 6) |
| 231 | size = 6; | 241 | size = 6; |
| 232 | #endif | 242 | #endif |
| 243 | } | ||
| 233 | return size; | 244 | return size; |
| 234 | } | 245 | } |
| 235 | 246 | ||
| 236 | static int ext4_ext_space_block_idx(struct inode *inode) | 247 | static inline int ext4_ext_space_block_idx(struct inode *inode, int check) |
| 237 | { | 248 | { |
| 238 | int size; | 249 | int size; |
| 239 | 250 | ||
| 240 | size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) | 251 | size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) |
| 241 | / sizeof(struct ext4_extent_idx); | 252 | / sizeof(struct ext4_extent_idx); |
| 253 | if (!check) { | ||
| 242 | #ifdef AGGRESSIVE_TEST | 254 | #ifdef AGGRESSIVE_TEST |
| 243 | if (size > 5) | 255 | if (size > 5) |
| 244 | size = 5; | 256 | size = 5; |
| 245 | #endif | 257 | #endif |
| 258 | } | ||
| 246 | return size; | 259 | return size; |
| 247 | } | 260 | } |
| 248 | 261 | ||
| 249 | static int ext4_ext_space_root(struct inode *inode) | 262 | static inline int ext4_ext_space_root(struct inode *inode, int check) |
| 250 | { | 263 | { |
| 251 | int size; | 264 | int size; |
| 252 | 265 | ||
| 253 | size = sizeof(EXT4_I(inode)->i_data); | 266 | size = sizeof(EXT4_I(inode)->i_data); |
| 254 | size -= sizeof(struct ext4_extent_header); | 267 | size -= sizeof(struct ext4_extent_header); |
| 255 | size /= sizeof(struct ext4_extent); | 268 | size /= sizeof(struct ext4_extent); |
| 269 | if (!check) { | ||
| 256 | #ifdef AGGRESSIVE_TEST | 270 | #ifdef AGGRESSIVE_TEST |
| 257 | if (size > 3) | 271 | if (size > 3) |
| 258 | size = 3; | 272 | size = 3; |
| 259 | #endif | 273 | #endif |
| 274 | } | ||
| 260 | return size; | 275 | return size; |
| 261 | } | 276 | } |
| 262 | 277 | ||
| 263 | static int ext4_ext_space_root_idx(struct inode *inode) | 278 | static inline int ext4_ext_space_root_idx(struct inode *inode, int check) |
| 264 | { | 279 | { |
| 265 | int size; | 280 | int size; |
| 266 | 281 | ||
| 267 | size = sizeof(EXT4_I(inode)->i_data); | 282 | size = sizeof(EXT4_I(inode)->i_data); |
| 268 | size -= sizeof(struct ext4_extent_header); | 283 | size -= sizeof(struct ext4_extent_header); |
| 269 | size /= sizeof(struct ext4_extent_idx); | 284 | size /= sizeof(struct ext4_extent_idx); |
| 285 | if (!check) { | ||
| 270 | #ifdef AGGRESSIVE_TEST | 286 | #ifdef AGGRESSIVE_TEST |
| 271 | if (size > 4) | 287 | if (size > 4) |
| 272 | size = 4; | 288 | size = 4; |
| 273 | #endif | 289 | #endif |
| 290 | } | ||
| 274 | return size; | 291 | return size; |
| 275 | } | 292 | } |
| 276 | 293 | ||
| @@ -284,9 +301,9 @@ int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks) | |||
| 284 | int lcap, icap, rcap, leafs, idxs, num; | 301 | int lcap, icap, rcap, leafs, idxs, num; |
| 285 | int newextents = blocks; | 302 | int newextents = blocks; |
| 286 | 303 | ||
| 287 | rcap = ext4_ext_space_root_idx(inode); | 304 | rcap = ext4_ext_space_root_idx(inode, 0); |
| 288 | lcap = ext4_ext_space_block(inode); | 305 | lcap = ext4_ext_space_block(inode, 0); |
| 289 | icap = ext4_ext_space_block_idx(inode); | 306 | icap = ext4_ext_space_block_idx(inode, 0); |
| 290 | 307 | ||
| 291 | /* number of new leaf blocks needed */ | 308 | /* number of new leaf blocks needed */ |
| 292 | num = leafs = (newextents + lcap - 1) / lcap; | 309 | num = leafs = (newextents + lcap - 1) / lcap; |
| @@ -311,14 +328,14 @@ ext4_ext_max_entries(struct inode *inode, int depth) | |||
| 311 | 328 | ||
| 312 | if (depth == ext_depth(inode)) { | 329 | if (depth == ext_depth(inode)) { |
| 313 | if (depth == 0) | 330 | if (depth == 0) |
| 314 | max = ext4_ext_space_root(inode); | 331 | max = ext4_ext_space_root(inode, 1); |
| 315 | else | 332 | else |
| 316 | max = ext4_ext_space_root_idx(inode); | 333 | max = ext4_ext_space_root_idx(inode, 1); |
| 317 | } else { | 334 | } else { |
| 318 | if (depth == 0) | 335 | if (depth == 0) |
| 319 | max = ext4_ext_space_block(inode); | 336 | max = ext4_ext_space_block(inode, 1); |
| 320 | else | 337 | else |
| 321 | max = ext4_ext_space_block_idx(inode); | 338 | max = ext4_ext_space_block_idx(inode, 1); |
| 322 | } | 339 | } |
| 323 | 340 | ||
| 324 | return max; | 341 | return max; |
| @@ -437,8 +454,9 @@ static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) | |||
| 437 | ext_debug(" %d->%llu", le32_to_cpu(path->p_idx->ei_block), | 454 | ext_debug(" %d->%llu", le32_to_cpu(path->p_idx->ei_block), |
| 438 | idx_pblock(path->p_idx)); | 455 | idx_pblock(path->p_idx)); |
| 439 | } else if (path->p_ext) { | 456 | } else if (path->p_ext) { |
| 440 | ext_debug(" %d:%d:%llu ", | 457 | ext_debug(" %d:[%d]%d:%llu ", |
| 441 | le32_to_cpu(path->p_ext->ee_block), | 458 | le32_to_cpu(path->p_ext->ee_block), |
| 459 | ext4_ext_is_uninitialized(path->p_ext), | ||
| 442 | ext4_ext_get_actual_len(path->p_ext), | 460 | ext4_ext_get_actual_len(path->p_ext), |
| 443 | ext_pblock(path->p_ext)); | 461 | ext_pblock(path->p_ext)); |
| 444 | } else | 462 | } else |
| @@ -460,8 +478,11 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path) | |||
| 460 | eh = path[depth].p_hdr; | 478 | eh = path[depth].p_hdr; |
| 461 | ex = EXT_FIRST_EXTENT(eh); | 479 | ex = EXT_FIRST_EXTENT(eh); |
| 462 | 480 | ||
| 481 | ext_debug("Displaying leaf extents for inode %lu\n", inode->i_ino); | ||
| 482 | |||
| 463 | for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) { | 483 | for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) { |
| 464 | ext_debug("%d:%d:%llu ", le32_to_cpu(ex->ee_block), | 484 | ext_debug("%d:[%d]%d:%llu ", le32_to_cpu(ex->ee_block), |
| 485 | ext4_ext_is_uninitialized(ex), | ||
| 465 | ext4_ext_get_actual_len(ex), ext_pblock(ex)); | 486 | ext4_ext_get_actual_len(ex), ext_pblock(ex)); |
| 466 | } | 487 | } |
| 467 | ext_debug("\n"); | 488 | ext_debug("\n"); |
| @@ -580,9 +601,10 @@ ext4_ext_binsearch(struct inode *inode, | |||
| 580 | } | 601 | } |
| 581 | 602 | ||
| 582 | path->p_ext = l - 1; | 603 | path->p_ext = l - 1; |
| 583 | ext_debug(" -> %d:%llu:%d ", | 604 | ext_debug(" -> %d:%llu:[%d]%d ", |
| 584 | le32_to_cpu(path->p_ext->ee_block), | 605 | le32_to_cpu(path->p_ext->ee_block), |
| 585 | ext_pblock(path->p_ext), | 606 | ext_pblock(path->p_ext), |
| 607 | ext4_ext_is_uninitialized(path->p_ext), | ||
| 586 | ext4_ext_get_actual_len(path->p_ext)); | 608 | ext4_ext_get_actual_len(path->p_ext)); |
| 587 | 609 | ||
| 588 | #ifdef CHECK_BINSEARCH | 610 | #ifdef CHECK_BINSEARCH |
| @@ -612,7 +634,7 @@ int ext4_ext_tree_init(handle_t *handle, struct inode *inode) | |||
| 612 | eh->eh_depth = 0; | 634 | eh->eh_depth = 0; |
| 613 | eh->eh_entries = 0; | 635 | eh->eh_entries = 0; |
| 614 | eh->eh_magic = EXT4_EXT_MAGIC; | 636 | eh->eh_magic = EXT4_EXT_MAGIC; |
| 615 | eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode)); | 637 | eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0)); |
| 616 | ext4_mark_inode_dirty(handle, inode); | 638 | ext4_mark_inode_dirty(handle, inode); |
| 617 | ext4_ext_invalidate_cache(inode); | 639 | ext4_ext_invalidate_cache(inode); |
| 618 | return 0; | 640 | return 0; |
| @@ -837,7 +859,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, | |||
| 837 | 859 | ||
| 838 | neh = ext_block_hdr(bh); | 860 | neh = ext_block_hdr(bh); |
| 839 | neh->eh_entries = 0; | 861 | neh->eh_entries = 0; |
| 840 | neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode)); | 862 | neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0)); |
| 841 | neh->eh_magic = EXT4_EXT_MAGIC; | 863 | neh->eh_magic = EXT4_EXT_MAGIC; |
| 842 | neh->eh_depth = 0; | 864 | neh->eh_depth = 0; |
| 843 | ex = EXT_FIRST_EXTENT(neh); | 865 | ex = EXT_FIRST_EXTENT(neh); |
| @@ -850,9 +872,10 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, | |||
| 850 | path[depth].p_ext++; | 872 | path[depth].p_ext++; |
| 851 | while (path[depth].p_ext <= | 873 | while (path[depth].p_ext <= |
| 852 | EXT_MAX_EXTENT(path[depth].p_hdr)) { | 874 | EXT_MAX_EXTENT(path[depth].p_hdr)) { |
| 853 | ext_debug("move %d:%llu:%d in new leaf %llu\n", | 875 | ext_debug("move %d:%llu:[%d]%d in new leaf %llu\n", |
| 854 | le32_to_cpu(path[depth].p_ext->ee_block), | 876 | le32_to_cpu(path[depth].p_ext->ee_block), |
| 855 | ext_pblock(path[depth].p_ext), | 877 | ext_pblock(path[depth].p_ext), |
| 878 | ext4_ext_is_uninitialized(path[depth].p_ext), | ||
| 856 | ext4_ext_get_actual_len(path[depth].p_ext), | 879 | ext4_ext_get_actual_len(path[depth].p_ext), |
| 857 | newblock); | 880 | newblock); |
| 858 | /*memmove(ex++, path[depth].p_ext++, | 881 | /*memmove(ex++, path[depth].p_ext++, |
| @@ -912,7 +935,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, | |||
| 912 | neh = ext_block_hdr(bh); | 935 | neh = ext_block_hdr(bh); |
| 913 | neh->eh_entries = cpu_to_le16(1); | 936 | neh->eh_entries = cpu_to_le16(1); |
| 914 | neh->eh_magic = EXT4_EXT_MAGIC; | 937 | neh->eh_magic = EXT4_EXT_MAGIC; |
| 915 | neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode)); | 938 | neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0)); |
| 916 | neh->eh_depth = cpu_to_le16(depth - i); | 939 | neh->eh_depth = cpu_to_le16(depth - i); |
| 917 | fidx = EXT_FIRST_INDEX(neh); | 940 | fidx = EXT_FIRST_INDEX(neh); |
| 918 | fidx->ei_block = border; | 941 | fidx->ei_block = border; |
| @@ -1037,9 +1060,9 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, | |||
| 1037 | /* old root could have indexes or leaves | 1060 | /* old root could have indexes or leaves |
| 1038 | * so calculate e_max right way */ | 1061 | * so calculate e_max right way */ |
| 1039 | if (ext_depth(inode)) | 1062 | if (ext_depth(inode)) |
| 1040 | neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode)); | 1063 | neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0)); |
| 1041 | else | 1064 | else |
| 1042 | neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode)); | 1065 | neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0)); |
| 1043 | neh->eh_magic = EXT4_EXT_MAGIC; | 1066 | neh->eh_magic = EXT4_EXT_MAGIC; |
| 1044 | set_buffer_uptodate(bh); | 1067 | set_buffer_uptodate(bh); |
| 1045 | unlock_buffer(bh); | 1068 | unlock_buffer(bh); |
| @@ -1054,7 +1077,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, | |||
| 1054 | goto out; | 1077 | goto out; |
| 1055 | 1078 | ||
| 1056 | curp->p_hdr->eh_magic = EXT4_EXT_MAGIC; | 1079 | curp->p_hdr->eh_magic = EXT4_EXT_MAGIC; |
| 1057 | curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode)); | 1080 | curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode, 0)); |
| 1058 | curp->p_hdr->eh_entries = cpu_to_le16(1); | 1081 | curp->p_hdr->eh_entries = cpu_to_le16(1); |
| 1059 | curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr); | 1082 | curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr); |
| 1060 | 1083 | ||
| @@ -1580,9 +1603,11 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, | |||
| 1580 | 1603 | ||
| 1581 | /* try to insert block into found extent and return */ | 1604 | /* try to insert block into found extent and return */ |
| 1582 | if (ex && ext4_can_extents_be_merged(inode, ex, newext)) { | 1605 | if (ex && ext4_can_extents_be_merged(inode, ex, newext)) { |
| 1583 | ext_debug("append %d block to %d:%d (from %llu)\n", | 1606 | ext_debug("append [%d]%d block to %d:[%d]%d (from %llu)\n", |
| 1607 | ext4_ext_is_uninitialized(newext), | ||
| 1584 | ext4_ext_get_actual_len(newext), | 1608 | ext4_ext_get_actual_len(newext), |
| 1585 | le32_to_cpu(ex->ee_block), | 1609 | le32_to_cpu(ex->ee_block), |
| 1610 | ext4_ext_is_uninitialized(ex), | ||
| 1586 | ext4_ext_get_actual_len(ex), ext_pblock(ex)); | 1611 | ext4_ext_get_actual_len(ex), ext_pblock(ex)); |
| 1587 | err = ext4_ext_get_access(handle, inode, path + depth); | 1612 | err = ext4_ext_get_access(handle, inode, path + depth); |
| 1588 | if (err) | 1613 | if (err) |
| @@ -1651,9 +1676,10 @@ has_space: | |||
| 1651 | 1676 | ||
| 1652 | if (!nearex) { | 1677 | if (!nearex) { |
| 1653 | /* there is no extent in this leaf, create first one */ | 1678 | /* there is no extent in this leaf, create first one */ |
| 1654 | ext_debug("first extent in the leaf: %d:%llu:%d\n", | 1679 | ext_debug("first extent in the leaf: %d:%llu:[%d]%d\n", |
| 1655 | le32_to_cpu(newext->ee_block), | 1680 | le32_to_cpu(newext->ee_block), |
| 1656 | ext_pblock(newext), | 1681 | ext_pblock(newext), |
| 1682 | ext4_ext_is_uninitialized(newext), | ||
| 1657 | ext4_ext_get_actual_len(newext)); | 1683 | ext4_ext_get_actual_len(newext)); |
| 1658 | path[depth].p_ext = EXT_FIRST_EXTENT(eh); | 1684 | path[depth].p_ext = EXT_FIRST_EXTENT(eh); |
| 1659 | } else if (le32_to_cpu(newext->ee_block) | 1685 | } else if (le32_to_cpu(newext->ee_block) |
| @@ -1663,10 +1689,11 @@ has_space: | |||
| 1663 | len = EXT_MAX_EXTENT(eh) - nearex; | 1689 | len = EXT_MAX_EXTENT(eh) - nearex; |
| 1664 | len = (len - 1) * sizeof(struct ext4_extent); | 1690 | len = (len - 1) * sizeof(struct ext4_extent); |
| 1665 | len = len < 0 ? 0 : len; | 1691 | len = len < 0 ? 0 : len; |
| 1666 | ext_debug("insert %d:%llu:%d after: nearest 0x%p, " | 1692 | ext_debug("insert %d:%llu:[%d]%d after: nearest 0x%p, " |
| 1667 | "move %d from 0x%p to 0x%p\n", | 1693 | "move %d from 0x%p to 0x%p\n", |
| 1668 | le32_to_cpu(newext->ee_block), | 1694 | le32_to_cpu(newext->ee_block), |
| 1669 | ext_pblock(newext), | 1695 | ext_pblock(newext), |
| 1696 | ext4_ext_is_uninitialized(newext), | ||
| 1670 | ext4_ext_get_actual_len(newext), | 1697 | ext4_ext_get_actual_len(newext), |
| 1671 | nearex, len, nearex + 1, nearex + 2); | 1698 | nearex, len, nearex + 1, nearex + 2); |
| 1672 | memmove(nearex + 2, nearex + 1, len); | 1699 | memmove(nearex + 2, nearex + 1, len); |
| @@ -1676,10 +1703,11 @@ has_space: | |||
| 1676 | BUG_ON(newext->ee_block == nearex->ee_block); | 1703 | BUG_ON(newext->ee_block == nearex->ee_block); |
| 1677 | len = (EXT_MAX_EXTENT(eh) - nearex) * sizeof(struct ext4_extent); | 1704 | len = (EXT_MAX_EXTENT(eh) - nearex) * sizeof(struct ext4_extent); |
| 1678 | len = len < 0 ? 0 : len; | 1705 | len = len < 0 ? 0 : len; |
| 1679 | ext_debug("insert %d:%llu:%d before: nearest 0x%p, " | 1706 | ext_debug("insert %d:%llu:[%d]%d before: nearest 0x%p, " |
| 1680 | "move %d from 0x%p to 0x%p\n", | 1707 | "move %d from 0x%p to 0x%p\n", |
| 1681 | le32_to_cpu(newext->ee_block), | 1708 | le32_to_cpu(newext->ee_block), |
| 1682 | ext_pblock(newext), | 1709 | ext_pblock(newext), |
| 1710 | ext4_ext_is_uninitialized(newext), | ||
| 1683 | ext4_ext_get_actual_len(newext), | 1711 | ext4_ext_get_actual_len(newext), |
| 1684 | nearex, len, nearex + 1, nearex + 2); | 1712 | nearex, len, nearex + 1, nearex + 2); |
| 1685 | memmove(nearex + 1, nearex, len); | 1713 | memmove(nearex + 1, nearex, len); |
| @@ -2094,7 +2122,8 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, | |||
| 2094 | else | 2122 | else |
| 2095 | uninitialized = 0; | 2123 | uninitialized = 0; |
| 2096 | 2124 | ||
| 2097 | ext_debug("remove ext %lu:%u\n", ex_ee_block, ex_ee_len); | 2125 | ext_debug("remove ext %u:[%d]%d\n", ex_ee_block, |
| 2126 | uninitialized, ex_ee_len); | ||
| 2098 | path[depth].p_ext = ex; | 2127 | path[depth].p_ext = ex; |
| 2099 | 2128 | ||
| 2100 | a = ex_ee_block > start ? ex_ee_block : start; | 2129 | a = ex_ee_block > start ? ex_ee_block : start; |
| @@ -2138,7 +2167,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, | |||
| 2138 | } | 2167 | } |
| 2139 | credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); | 2168 | credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); |
| 2140 | 2169 | ||
| 2141 | err = ext4_ext_journal_restart(handle, credits); | 2170 | err = ext4_ext_truncate_extend_restart(handle, inode, credits); |
| 2142 | if (err) | 2171 | if (err) |
| 2143 | goto out; | 2172 | goto out; |
| 2144 | 2173 | ||
| @@ -2327,7 +2356,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start) | |||
| 2327 | if (err == 0) { | 2356 | if (err == 0) { |
| 2328 | ext_inode_hdr(inode)->eh_depth = 0; | 2357 | ext_inode_hdr(inode)->eh_depth = 0; |
| 2329 | ext_inode_hdr(inode)->eh_max = | 2358 | ext_inode_hdr(inode)->eh_max = |
| 2330 | cpu_to_le16(ext4_ext_space_root(inode)); | 2359 | cpu_to_le16(ext4_ext_space_root(inode, 0)); |
| 2331 | err = ext4_ext_dirty(handle, inode, path); | 2360 | err = ext4_ext_dirty(handle, inode, path); |
| 2332 | } | 2361 | } |
| 2333 | } | 2362 | } |
| @@ -2743,6 +2772,7 @@ insert: | |||
| 2743 | } else if (err) | 2772 | } else if (err) |
| 2744 | goto fix_extent_len; | 2773 | goto fix_extent_len; |
| 2745 | out: | 2774 | out: |
| 2775 | ext4_ext_show_leaf(inode, path); | ||
| 2746 | return err ? err : allocated; | 2776 | return err ? err : allocated; |
| 2747 | 2777 | ||
| 2748 | fix_extent_len: | 2778 | fix_extent_len: |
| @@ -2786,7 +2816,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
| 2786 | struct ext4_allocation_request ar; | 2816 | struct ext4_allocation_request ar; |
| 2787 | 2817 | ||
| 2788 | __clear_bit(BH_New, &bh_result->b_state); | 2818 | __clear_bit(BH_New, &bh_result->b_state); |
| 2789 | ext_debug("blocks %u/%u requested for inode %u\n", | 2819 | ext_debug("blocks %u/%u requested for inode %lu\n", |
| 2790 | iblock, max_blocks, inode->i_ino); | 2820 | iblock, max_blocks, inode->i_ino); |
| 2791 | 2821 | ||
| 2792 | /* check in cache */ | 2822 | /* check in cache */ |
| @@ -2849,7 +2879,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
| 2849 | newblock = iblock - ee_block + ee_start; | 2879 | newblock = iblock - ee_block + ee_start; |
| 2850 | /* number of remaining blocks in the extent */ | 2880 | /* number of remaining blocks in the extent */ |
| 2851 | allocated = ee_len - (iblock - ee_block); | 2881 | allocated = ee_len - (iblock - ee_block); |
| 2852 | ext_debug("%u fit into %lu:%d -> %llu\n", iblock, | 2882 | ext_debug("%u fit into %u:%d -> %llu\n", iblock, |
| 2853 | ee_block, ee_len, newblock); | 2883 | ee_block, ee_len, newblock); |
| 2854 | 2884 | ||
| 2855 | /* Do not put uninitialized extent in the cache */ | 2885 | /* Do not put uninitialized extent in the cache */ |
| @@ -2950,7 +2980,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
| 2950 | newblock = ext4_mb_new_blocks(handle, &ar, &err); | 2980 | newblock = ext4_mb_new_blocks(handle, &ar, &err); |
| 2951 | if (!newblock) | 2981 | if (!newblock) |
| 2952 | goto out2; | 2982 | goto out2; |
| 2953 | ext_debug("allocate new block: goal %llu, found %llu/%lu\n", | 2983 | ext_debug("allocate new block: goal %llu, found %llu/%u\n", |
| 2954 | ar.goal, newblock, allocated); | 2984 | ar.goal, newblock, allocated); |
| 2955 | 2985 | ||
| 2956 | /* try to insert new extent into found leaf and return */ | 2986 | /* try to insert new extent into found leaf and return */ |
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 3f1873fef1c..5ca3eca70a1 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
| @@ -58,10 +58,7 @@ static ssize_t | |||
| 58 | ext4_file_write(struct kiocb *iocb, const struct iovec *iov, | 58 | ext4_file_write(struct kiocb *iocb, const struct iovec *iov, |
| 59 | unsigned long nr_segs, loff_t pos) | 59 | unsigned long nr_segs, loff_t pos) |
| 60 | { | 60 | { |
| 61 | struct file *file = iocb->ki_filp; | 61 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; |
| 62 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 63 | ssize_t ret; | ||
| 64 | int err; | ||
| 65 | 62 | ||
| 66 | /* | 63 | /* |
| 67 | * If we have encountered a bitmap-format file, the size limit | 64 | * If we have encountered a bitmap-format file, the size limit |
| @@ -81,53 +78,7 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 81 | } | 78 | } |
| 82 | } | 79 | } |
| 83 | 80 | ||
| 84 | ret = generic_file_aio_write(iocb, iov, nr_segs, pos); | 81 | return generic_file_aio_write(iocb, iov, nr_segs, pos); |
| 85 | /* | ||
| 86 | * Skip flushing if there was an error, or if nothing was written. | ||
| 87 | */ | ||
| 88 | if (ret <= 0) | ||
| 89 | return ret; | ||
| 90 | |||
| 91 | /* | ||
| 92 | * If the inode is IS_SYNC, or is O_SYNC and we are doing data | ||
| 93 | * journalling then we need to make sure that we force the transaction | ||
| 94 | * to disk to keep all metadata uptodate synchronously. | ||
| 95 | */ | ||
| 96 | if (file->f_flags & O_SYNC) { | ||
| 97 | /* | ||
| 98 | * If we are non-data-journaled, then the dirty data has | ||
| 99 | * already been flushed to backing store by generic_osync_inode, | ||
| 100 | * and the inode has been flushed too if there have been any | ||
| 101 | * modifications other than mere timestamp updates. | ||
| 102 | * | ||
| 103 | * Open question --- do we care about flushing timestamps too | ||
| 104 | * if the inode is IS_SYNC? | ||
| 105 | */ | ||
| 106 | if (!ext4_should_journal_data(inode)) | ||
| 107 | return ret; | ||
| 108 | |||
| 109 | goto force_commit; | ||
| 110 | } | ||
| 111 | |||
| 112 | /* | ||
| 113 | * So we know that there has been no forced data flush. If the inode | ||
| 114 | * is marked IS_SYNC, we need to force one ourselves. | ||
| 115 | */ | ||
| 116 | if (!IS_SYNC(inode)) | ||
| 117 | return ret; | ||
| 118 | |||
| 119 | /* | ||
| 120 | * Open question #2 --- should we force data to disk here too? If we | ||
| 121 | * don't, the only impact is that data=writeback filesystems won't | ||
| 122 | * flush data to disk automatically on IS_SYNC, only metadata (but | ||
| 123 | * historically, that is what ext2 has done.) | ||
| 124 | */ | ||
| 125 | |||
| 126 | force_commit: | ||
| 127 | err = ext4_force_commit(inode->i_sb); | ||
| 128 | if (err) | ||
| 129 | return err; | ||
| 130 | return ret; | ||
| 131 | } | 82 | } |
| 132 | 83 | ||
| 133 | static struct vm_operations_struct ext4_file_vm_ops = { | 84 | static struct vm_operations_struct ext4_file_vm_ops = { |
| @@ -207,7 +158,7 @@ const struct inode_operations ext4_file_inode_operations = { | |||
| 207 | .listxattr = ext4_listxattr, | 158 | .listxattr = ext4_listxattr, |
| 208 | .removexattr = generic_removexattr, | 159 | .removexattr = generic_removexattr, |
| 209 | #endif | 160 | #endif |
| 210 | .permission = ext4_permission, | 161 | .check_acl = ext4_check_acl, |
| 211 | .fallocate = ext4_fallocate, | 162 | .fallocate = ext4_fallocate, |
| 212 | .fiemap = ext4_fiemap, | 163 | .fiemap = ext4_fiemap, |
| 213 | }; | 164 | }; |
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 83cf6415f59..07475740b51 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
| @@ -50,7 +50,7 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) | |||
| 50 | { | 50 | { |
| 51 | struct inode *inode = dentry->d_inode; | 51 | struct inode *inode = dentry->d_inode; |
| 52 | journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; | 52 | journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; |
| 53 | int ret = 0; | 53 | int err, ret = 0; |
| 54 | 54 | ||
| 55 | J_ASSERT(ext4_journal_current_handle() == NULL); | 55 | J_ASSERT(ext4_journal_current_handle() == NULL); |
| 56 | 56 | ||
| @@ -79,6 +79,9 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) | |||
| 79 | goto out; | 79 | goto out; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | if (!journal) | ||
| 83 | ret = sync_mapping_buffers(inode->i_mapping); | ||
| 84 | |||
| 82 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | 85 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) |
| 83 | goto out; | 86 | goto out; |
| 84 | 87 | ||
| @@ -91,10 +94,12 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) | |||
| 91 | .sync_mode = WB_SYNC_ALL, | 94 | .sync_mode = WB_SYNC_ALL, |
| 92 | .nr_to_write = 0, /* sys_fsync did this */ | 95 | .nr_to_write = 0, /* sys_fsync did this */ |
| 93 | }; | 96 | }; |
| 94 | ret = sync_inode(inode, &wbc); | 97 | err = sync_inode(inode, &wbc); |
| 95 | if (journal && (journal->j_flags & JBD2_BARRIER)) | 98 | if (ret == 0) |
| 96 | blkdev_issue_flush(inode->i_sb->s_bdev, NULL); | 99 | ret = err; |
| 97 | } | 100 | } |
| 98 | out: | 101 | out: |
| 102 | if (journal && (journal->j_flags & JBD2_BARRIER)) | ||
| 103 | blkdev_issue_flush(inode->i_sb->s_bdev, NULL); | ||
| 99 | return ret; | 104 | return ret; |
| 100 | } | 105 | } |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 29e6dc7299b..f3624ead4f6 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
| @@ -1189,7 +1189,7 @@ unsigned long ext4_count_free_inodes(struct super_block *sb) | |||
| 1189 | 1189 | ||
| 1190 | x = ext4_count_free(bitmap_bh, EXT4_INODES_PER_GROUP(sb) / 8); | 1190 | x = ext4_count_free(bitmap_bh, EXT4_INODES_PER_GROUP(sb) / 8); |
| 1191 | printk(KERN_DEBUG "group %lu: stored = %d, counted = %lu\n", | 1191 | printk(KERN_DEBUG "group %lu: stored = %d, counted = %lu\n", |
| 1192 | i, ext4_free_inodes_count(sb, gdp), x); | 1192 | (unsigned long) i, ext4_free_inodes_count(sb, gdp), x); |
| 1193 | bitmap_count += x; | 1193 | bitmap_count += x; |
| 1194 | } | 1194 | } |
| 1195 | brelse(bitmap_bh); | 1195 | brelse(bitmap_bh); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index f9c642b22ef..4abd683b963 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -192,11 +192,24 @@ static int try_to_extend_transaction(handle_t *handle, struct inode *inode) | |||
| 192 | * so before we call here everything must be consistently dirtied against | 192 | * so before we call here everything must be consistently dirtied against |
| 193 | * this transaction. | 193 | * this transaction. |
| 194 | */ | 194 | */ |
| 195 | static int ext4_journal_test_restart(handle_t *handle, struct inode *inode) | 195 | int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode, |
| 196 | int nblocks) | ||
| 196 | { | 197 | { |
| 198 | int ret; | ||
| 199 | |||
| 200 | /* | ||
| 201 | * Drop i_data_sem to avoid deadlock with ext4_get_blocks At this | ||
| 202 | * moment, get_block can be called only for blocks inside i_size since | ||
| 203 | * page cache has been already dropped and writes are blocked by | ||
| 204 | * i_mutex. So we can safely drop the i_data_sem here. | ||
| 205 | */ | ||
| 197 | BUG_ON(EXT4_JOURNAL(inode) == NULL); | 206 | BUG_ON(EXT4_JOURNAL(inode) == NULL); |
| 198 | jbd_debug(2, "restarting handle %p\n", handle); | 207 | jbd_debug(2, "restarting handle %p\n", handle); |
| 199 | return ext4_journal_restart(handle, blocks_for_truncate(inode)); | 208 | up_write(&EXT4_I(inode)->i_data_sem); |
| 209 | ret = ext4_journal_restart(handle, blocks_for_truncate(inode)); | ||
| 210 | down_write(&EXT4_I(inode)->i_data_sem); | ||
| 211 | |||
| 212 | return ret; | ||
| 200 | } | 213 | } |
| 201 | 214 | ||
| 202 | /* | 215 | /* |
| @@ -341,9 +354,7 @@ static int ext4_block_to_path(struct inode *inode, | |||
| 341 | int n = 0; | 354 | int n = 0; |
| 342 | int final = 0; | 355 | int final = 0; |
| 343 | 356 | ||
| 344 | if (i_block < 0) { | 357 | if (i_block < direct_blocks) { |
| 345 | ext4_warning(inode->i_sb, "ext4_block_to_path", "block < 0"); | ||
| 346 | } else if (i_block < direct_blocks) { | ||
| 347 | offsets[n++] = i_block; | 358 | offsets[n++] = i_block; |
| 348 | final = direct_blocks; | 359 | final = direct_blocks; |
| 349 | } else if ((i_block -= direct_blocks) < indirect_blocks) { | 360 | } else if ((i_block -= direct_blocks) < indirect_blocks) { |
| @@ -551,15 +562,21 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind) | |||
| 551 | * | 562 | * |
| 552 | * Normally this function find the preferred place for block allocation, | 563 | * Normally this function find the preferred place for block allocation, |
| 553 | * returns it. | 564 | * returns it. |
| 565 | * Because this is only used for non-extent files, we limit the block nr | ||
| 566 | * to 32 bits. | ||
| 554 | */ | 567 | */ |
| 555 | static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, | 568 | static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, |
| 556 | Indirect *partial) | 569 | Indirect *partial) |
| 557 | { | 570 | { |
| 571 | ext4_fsblk_t goal; | ||
| 572 | |||
| 558 | /* | 573 | /* |
| 559 | * XXX need to get goal block from mballoc's data structures | 574 | * XXX need to get goal block from mballoc's data structures |
| 560 | */ | 575 | */ |
| 561 | 576 | ||
| 562 | return ext4_find_near(inode, partial); | 577 | goal = ext4_find_near(inode, partial); |
| 578 | goal = goal & EXT4_MAX_BLOCK_FILE_PHYS; | ||
| 579 | return goal; | ||
| 563 | } | 580 | } |
| 564 | 581 | ||
| 565 | /** | 582 | /** |
| @@ -640,6 +657,8 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | |||
| 640 | if (*err) | 657 | if (*err) |
| 641 | goto failed_out; | 658 | goto failed_out; |
| 642 | 659 | ||
| 660 | BUG_ON(current_block + count > EXT4_MAX_BLOCK_FILE_PHYS); | ||
| 661 | |||
| 643 | target -= count; | 662 | target -= count; |
| 644 | /* allocate blocks for indirect blocks */ | 663 | /* allocate blocks for indirect blocks */ |
| 645 | while (index < indirect_blks && count) { | 664 | while (index < indirect_blks && count) { |
| @@ -674,6 +693,7 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | |||
| 674 | ar.flags = EXT4_MB_HINT_DATA; | 693 | ar.flags = EXT4_MB_HINT_DATA; |
| 675 | 694 | ||
| 676 | current_block = ext4_mb_new_blocks(handle, &ar, err); | 695 | current_block = ext4_mb_new_blocks(handle, &ar, err); |
| 696 | BUG_ON(current_block + ar.len > EXT4_MAX_BLOCK_FILE_PHYS); | ||
| 677 | 697 | ||
| 678 | if (*err && (target == blks)) { | 698 | if (*err && (target == blks)) { |
| 679 | /* | 699 | /* |
| @@ -762,8 +782,9 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | |||
| 762 | BUFFER_TRACE(bh, "call get_create_access"); | 782 | BUFFER_TRACE(bh, "call get_create_access"); |
| 763 | err = ext4_journal_get_create_access(handle, bh); | 783 | err = ext4_journal_get_create_access(handle, bh); |
| 764 | if (err) { | 784 | if (err) { |
| 785 | /* Don't brelse(bh) here; it's done in | ||
| 786 | * ext4_journal_forget() below */ | ||
| 765 | unlock_buffer(bh); | 787 | unlock_buffer(bh); |
| 766 | brelse(bh); | ||
| 767 | goto failed; | 788 | goto failed; |
| 768 | } | 789 | } |
| 769 | 790 | ||
| @@ -1109,16 +1130,15 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used) | |||
| 1109 | ext4_discard_preallocations(inode); | 1130 | ext4_discard_preallocations(inode); |
| 1110 | } | 1131 | } |
| 1111 | 1132 | ||
| 1112 | static int check_block_validity(struct inode *inode, sector_t logical, | 1133 | static int check_block_validity(struct inode *inode, const char *msg, |
| 1113 | sector_t phys, int len) | 1134 | sector_t logical, sector_t phys, int len) |
| 1114 | { | 1135 | { |
| 1115 | if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), phys, len)) { | 1136 | if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), phys, len)) { |
| 1116 | ext4_error(inode->i_sb, "check_block_validity", | 1137 | ext4_error(inode->i_sb, msg, |
| 1117 | "inode #%lu logical block %llu mapped to %llu " | 1138 | "inode #%lu logical block %llu mapped to %llu " |
| 1118 | "(size %d)", inode->i_ino, | 1139 | "(size %d)", inode->i_ino, |
| 1119 | (unsigned long long) logical, | 1140 | (unsigned long long) logical, |
| 1120 | (unsigned long long) phys, len); | 1141 | (unsigned long long) phys, len); |
| 1121 | WARN_ON(1); | ||
| 1122 | return -EIO; | 1142 | return -EIO; |
| 1123 | } | 1143 | } |
| 1124 | return 0; | 1144 | return 0; |
| @@ -1170,8 +1190,8 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block, | |||
| 1170 | up_read((&EXT4_I(inode)->i_data_sem)); | 1190 | up_read((&EXT4_I(inode)->i_data_sem)); |
| 1171 | 1191 | ||
| 1172 | if (retval > 0 && buffer_mapped(bh)) { | 1192 | if (retval > 0 && buffer_mapped(bh)) { |
| 1173 | int ret = check_block_validity(inode, block, | 1193 | int ret = check_block_validity(inode, "file system corruption", |
| 1174 | bh->b_blocknr, retval); | 1194 | block, bh->b_blocknr, retval); |
| 1175 | if (ret != 0) | 1195 | if (ret != 0) |
| 1176 | return ret; | 1196 | return ret; |
| 1177 | } | 1197 | } |
| @@ -1235,8 +1255,7 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block, | |||
| 1235 | * i_data's format changing. Force the migrate | 1255 | * i_data's format changing. Force the migrate |
| 1236 | * to fail by clearing migrate flags | 1256 | * to fail by clearing migrate flags |
| 1237 | */ | 1257 | */ |
| 1238 | EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags & | 1258 | EXT4_I(inode)->i_state &= ~EXT4_STATE_EXT_MIGRATE; |
| 1239 | ~EXT4_EXT_MIGRATE; | ||
| 1240 | } | 1259 | } |
| 1241 | } | 1260 | } |
| 1242 | 1261 | ||
| @@ -1252,8 +1271,9 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block, | |||
| 1252 | 1271 | ||
| 1253 | up_write((&EXT4_I(inode)->i_data_sem)); | 1272 | up_write((&EXT4_I(inode)->i_data_sem)); |
| 1254 | if (retval > 0 && buffer_mapped(bh)) { | 1273 | if (retval > 0 && buffer_mapped(bh)) { |
| 1255 | int ret = check_block_validity(inode, block, | 1274 | int ret = check_block_validity(inode, "file system " |
| 1256 | bh->b_blocknr, retval); | 1275 | "corruption after allocation", |
| 1276 | block, bh->b_blocknr, retval); | ||
| 1257 | if (ret != 0) | 1277 | if (ret != 0) |
| 1258 | return ret; | 1278 | return ret; |
| 1259 | } | 1279 | } |
| @@ -1863,18 +1883,6 @@ static void ext4_da_page_release_reservation(struct page *page, | |||
| 1863 | * Delayed allocation stuff | 1883 | * Delayed allocation stuff |
| 1864 | */ | 1884 | */ |
| 1865 | 1885 | ||
| 1866 | struct mpage_da_data { | ||
| 1867 | struct inode *inode; | ||
| 1868 | sector_t b_blocknr; /* start block number of extent */ | ||
| 1869 | size_t b_size; /* size of extent */ | ||
| 1870 | unsigned long b_state; /* state of the extent */ | ||
| 1871 | unsigned long first_page, next_page; /* extent of pages */ | ||
| 1872 | struct writeback_control *wbc; | ||
| 1873 | int io_done; | ||
| 1874 | int pages_written; | ||
| 1875 | int retval; | ||
| 1876 | }; | ||
| 1877 | |||
| 1878 | /* | 1886 | /* |
| 1879 | * mpage_da_submit_io - walks through extent of pages and try to write | 1887 | * mpage_da_submit_io - walks through extent of pages and try to write |
| 1880 | * them with writepage() call back | 1888 | * them with writepage() call back |
| @@ -2737,6 +2745,7 @@ static int ext4_da_writepages(struct address_space *mapping, | |||
| 2737 | long pages_skipped; | 2745 | long pages_skipped; |
| 2738 | int range_cyclic, cycled = 1, io_done = 0; | 2746 | int range_cyclic, cycled = 1, io_done = 0; |
| 2739 | int needed_blocks, ret = 0, nr_to_writebump = 0; | 2747 | int needed_blocks, ret = 0, nr_to_writebump = 0; |
| 2748 | loff_t range_start = wbc->range_start; | ||
| 2740 | struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb); | 2749 | struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb); |
| 2741 | 2750 | ||
| 2742 | trace_ext4_da_writepages(inode, wbc); | 2751 | trace_ext4_da_writepages(inode, wbc); |
| @@ -2850,6 +2859,7 @@ retry: | |||
| 2850 | mpd.io_done = 1; | 2859 | mpd.io_done = 1; |
| 2851 | ret = MPAGE_DA_EXTENT_TAIL; | 2860 | ret = MPAGE_DA_EXTENT_TAIL; |
| 2852 | } | 2861 | } |
| 2862 | trace_ext4_da_write_pages(inode, &mpd); | ||
| 2853 | wbc->nr_to_write -= mpd.pages_written; | 2863 | wbc->nr_to_write -= mpd.pages_written; |
| 2854 | 2864 | ||
| 2855 | ext4_journal_stop(handle); | 2865 | ext4_journal_stop(handle); |
| @@ -2905,6 +2915,7 @@ out_writepages: | |||
| 2905 | if (!no_nrwrite_index_update) | 2915 | if (!no_nrwrite_index_update) |
| 2906 | wbc->no_nrwrite_index_update = 0; | 2916 | wbc->no_nrwrite_index_update = 0; |
| 2907 | wbc->nr_to_write -= nr_to_writebump; | 2917 | wbc->nr_to_write -= nr_to_writebump; |
| 2918 | wbc->range_start = range_start; | ||
| 2908 | trace_ext4_da_writepages_result(inode, wbc, ret, pages_written); | 2919 | trace_ext4_da_writepages_result(inode, wbc, ret, pages_written); |
| 2909 | return ret; | 2920 | return ret; |
| 2910 | } | 2921 | } |
| @@ -3117,6 +3128,8 @@ out: | |||
| 3117 | */ | 3128 | */ |
| 3118 | int ext4_alloc_da_blocks(struct inode *inode) | 3129 | int ext4_alloc_da_blocks(struct inode *inode) |
| 3119 | { | 3130 | { |
| 3131 | trace_ext4_alloc_da_blocks(inode); | ||
| 3132 | |||
| 3120 | if (!EXT4_I(inode)->i_reserved_data_blocks && | 3133 | if (!EXT4_I(inode)->i_reserved_data_blocks && |
| 3121 | !EXT4_I(inode)->i_reserved_meta_blocks) | 3134 | !EXT4_I(inode)->i_reserved_meta_blocks) |
| 3122 | return 0; | 3135 | return 0; |
| @@ -3659,7 +3672,8 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode, | |||
| 3659 | ext4_handle_dirty_metadata(handle, inode, bh); | 3672 | ext4_handle_dirty_metadata(handle, inode, bh); |
| 3660 | } | 3673 | } |
| 3661 | ext4_mark_inode_dirty(handle, inode); | 3674 | ext4_mark_inode_dirty(handle, inode); |
| 3662 | ext4_journal_test_restart(handle, inode); | 3675 | ext4_truncate_restart_trans(handle, inode, |
| 3676 | blocks_for_truncate(inode)); | ||
| 3663 | if (bh) { | 3677 | if (bh) { |
| 3664 | BUFFER_TRACE(bh, "retaking write access"); | 3678 | BUFFER_TRACE(bh, "retaking write access"); |
| 3665 | ext4_journal_get_write_access(handle, bh); | 3679 | ext4_journal_get_write_access(handle, bh); |
| @@ -3870,7 +3884,8 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode, | |||
| 3870 | return; | 3884 | return; |
| 3871 | if (try_to_extend_transaction(handle, inode)) { | 3885 | if (try_to_extend_transaction(handle, inode)) { |
| 3872 | ext4_mark_inode_dirty(handle, inode); | 3886 | ext4_mark_inode_dirty(handle, inode); |
| 3873 | ext4_journal_test_restart(handle, inode); | 3887 | ext4_truncate_restart_trans(handle, inode, |
| 3888 | blocks_for_truncate(inode)); | ||
| 3874 | } | 3889 | } |
| 3875 | 3890 | ||
| 3876 | ext4_free_blocks(handle, inode, nr, 1, 1); | 3891 | ext4_free_blocks(handle, inode, nr, 1, 1); |
| @@ -3958,8 +3973,7 @@ void ext4_truncate(struct inode *inode) | |||
| 3958 | if (!ext4_can_truncate(inode)) | 3973 | if (!ext4_can_truncate(inode)) |
| 3959 | return; | 3974 | return; |
| 3960 | 3975 | ||
| 3961 | if (ei->i_disksize && inode->i_size == 0 && | 3976 | if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC)) |
| 3962 | !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC)) | ||
| 3963 | ei->i_state |= EXT4_STATE_DA_ALLOC_CLOSE; | 3977 | ei->i_state |= EXT4_STATE_DA_ALLOC_CLOSE; |
| 3964 | 3978 | ||
| 3965 | if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) { | 3979 | if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) { |
| @@ -4533,7 +4547,8 @@ static int ext4_inode_blocks_set(handle_t *handle, | |||
| 4533 | */ | 4547 | */ |
| 4534 | static int ext4_do_update_inode(handle_t *handle, | 4548 | static int ext4_do_update_inode(handle_t *handle, |
| 4535 | struct inode *inode, | 4549 | struct inode *inode, |
| 4536 | struct ext4_iloc *iloc) | 4550 | struct ext4_iloc *iloc, |
| 4551 | int do_sync) | ||
| 4537 | { | 4552 | { |
| 4538 | struct ext4_inode *raw_inode = ext4_raw_inode(iloc); | 4553 | struct ext4_inode *raw_inode = ext4_raw_inode(iloc); |
| 4539 | struct ext4_inode_info *ei = EXT4_I(inode); | 4554 | struct ext4_inode_info *ei = EXT4_I(inode); |
| @@ -4581,8 +4596,7 @@ static int ext4_do_update_inode(handle_t *handle, | |||
| 4581 | if (ext4_inode_blocks_set(handle, raw_inode, ei)) | 4596 | if (ext4_inode_blocks_set(handle, raw_inode, ei)) |
| 4582 | goto out_brelse; | 4597 | goto out_brelse; |
| 4583 | raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); | 4598 | raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); |
| 4584 | /* clear the migrate flag in the raw_inode */ | 4599 | raw_inode->i_flags = cpu_to_le32(ei->i_flags); |
| 4585 | raw_inode->i_flags = cpu_to_le32(ei->i_flags & ~EXT4_EXT_MIGRATE); | ||
| 4586 | if (EXT4_SB(inode->i_sb)->s_es->s_creator_os != | 4600 | if (EXT4_SB(inode->i_sb)->s_es->s_creator_os != |
| 4587 | cpu_to_le32(EXT4_OS_HURD)) | 4601 | cpu_to_le32(EXT4_OS_HURD)) |
| 4588 | raw_inode->i_file_acl_high = | 4602 | raw_inode->i_file_acl_high = |
| @@ -4635,10 +4649,22 @@ static int ext4_do_update_inode(handle_t *handle, | |||
| 4635 | raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); | 4649 | raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); |
| 4636 | } | 4650 | } |
| 4637 | 4651 | ||
| 4638 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | 4652 | /* |
| 4639 | rc = ext4_handle_dirty_metadata(handle, inode, bh); | 4653 | * If we're not using a journal and we were called from |
| 4640 | if (!err) | 4654 | * ext4_write_inode() to sync the inode (making do_sync true), |
| 4641 | err = rc; | 4655 | * we can just use sync_dirty_buffer() directly to do our dirty |
| 4656 | * work. Testing s_journal here is a bit redundant but it's | ||
| 4657 | * worth it to avoid potential future trouble. | ||
| 4658 | */ | ||
| 4659 | if (EXT4_SB(inode->i_sb)->s_journal == NULL && do_sync) { | ||
| 4660 | BUFFER_TRACE(bh, "call sync_dirty_buffer"); | ||
| 4661 | sync_dirty_buffer(bh); | ||
| 4662 | } else { | ||
| 4663 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | ||
| 4664 | rc = ext4_handle_dirty_metadata(handle, inode, bh); | ||
| 4665 | if (!err) | ||
| 4666 | err = rc; | ||
| 4667 | } | ||
| 4642 | ei->i_state &= ~EXT4_STATE_NEW; | 4668 | ei->i_state &= ~EXT4_STATE_NEW; |
| 4643 | 4669 | ||
| 4644 | out_brelse: | 4670 | out_brelse: |
| @@ -4684,19 +4710,32 @@ out_brelse: | |||
| 4684 | */ | 4710 | */ |
| 4685 | int ext4_write_inode(struct inode *inode, int wait) | 4711 | int ext4_write_inode(struct inode *inode, int wait) |
| 4686 | { | 4712 | { |
| 4713 | int err; | ||
| 4714 | |||
| 4687 | if (current->flags & PF_MEMALLOC) | 4715 | if (current->flags & PF_MEMALLOC) |
| 4688 | return 0; | 4716 | return 0; |
| 4689 | 4717 | ||
| 4690 | if (ext4_journal_current_handle()) { | 4718 | if (EXT4_SB(inode->i_sb)->s_journal) { |
| 4691 | jbd_debug(1, "called recursively, non-PF_MEMALLOC!\n"); | 4719 | if (ext4_journal_current_handle()) { |
| 4692 | dump_stack(); | 4720 | jbd_debug(1, "called recursively, non-PF_MEMALLOC!\n"); |
| 4693 | return -EIO; | 4721 | dump_stack(); |
| 4694 | } | 4722 | return -EIO; |
| 4723 | } | ||
| 4695 | 4724 | ||
| 4696 | if (!wait) | 4725 | if (!wait) |
| 4697 | return 0; | 4726 | return 0; |
| 4727 | |||
| 4728 | err = ext4_force_commit(inode->i_sb); | ||
| 4729 | } else { | ||
| 4730 | struct ext4_iloc iloc; | ||
| 4698 | 4731 | ||
| 4699 | return ext4_force_commit(inode->i_sb); | 4732 | err = ext4_get_inode_loc(inode, &iloc); |
| 4733 | if (err) | ||
| 4734 | return err; | ||
| 4735 | err = ext4_do_update_inode(EXT4_NOJOURNAL_HANDLE, | ||
| 4736 | inode, &iloc, wait); | ||
| 4737 | } | ||
| 4738 | return err; | ||
| 4700 | } | 4739 | } |
| 4701 | 4740 | ||
| 4702 | /* | 4741 | /* |
| @@ -4990,7 +5029,7 @@ int ext4_mark_iloc_dirty(handle_t *handle, | |||
| 4990 | get_bh(iloc->bh); | 5029 | get_bh(iloc->bh); |
| 4991 | 5030 | ||
| 4992 | /* ext4_do_update_inode() does jbd2_journal_dirty_metadata */ | 5031 | /* ext4_do_update_inode() does jbd2_journal_dirty_metadata */ |
| 4993 | err = ext4_do_update_inode(handle, inode, iloc); | 5032 | err = ext4_do_update_inode(handle, inode, iloc, 0); |
| 4994 | put_bh(iloc->bh); | 5033 | put_bh(iloc->bh); |
| 4995 | return err; | 5034 | return err; |
| 4996 | } | 5035 | } |
| @@ -5281,12 +5320,21 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
| 5281 | else | 5320 | else |
| 5282 | len = PAGE_CACHE_SIZE; | 5321 | len = PAGE_CACHE_SIZE; |
| 5283 | 5322 | ||
| 5323 | lock_page(page); | ||
| 5324 | /* | ||
| 5325 | * return if we have all the buffers mapped. This avoid | ||
| 5326 | * the need to call write_begin/write_end which does a | ||
| 5327 | * journal_start/journal_stop which can block and take | ||
| 5328 | * long time | ||
| 5329 | */ | ||
| 5284 | if (page_has_buffers(page)) { | 5330 | if (page_has_buffers(page)) { |
| 5285 | /* return if we have all the buffers mapped */ | ||
| 5286 | if (!walk_page_buffers(NULL, page_buffers(page), 0, len, NULL, | 5331 | if (!walk_page_buffers(NULL, page_buffers(page), 0, len, NULL, |
| 5287 | ext4_bh_unmapped)) | 5332 | ext4_bh_unmapped)) { |
| 5333 | unlock_page(page); | ||
| 5288 | goto out_unlock; | 5334 | goto out_unlock; |
| 5335 | } | ||
| 5289 | } | 5336 | } |
| 5337 | unlock_page(page); | ||
| 5290 | /* | 5338 | /* |
| 5291 | * OK, we need to fill the hole... Do write_begin write_end | 5339 | * OK, we need to fill the hole... Do write_begin write_end |
| 5292 | * to do block allocation/reservation.We are not holding | 5340 | * to do block allocation/reservation.We are not holding |
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 7050a9cd04a..c1cdf613e72 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
| @@ -243,10 +243,9 @@ setversion_out: | |||
| 243 | me.donor_start, me.len, &me.moved_len); | 243 | me.donor_start, me.len, &me.moved_len); |
| 244 | fput(donor_filp); | 244 | fput(donor_filp); |
| 245 | 245 | ||
| 246 | if (!err) | 246 | if (copy_to_user((struct move_extent *)arg, &me, sizeof(me))) |
| 247 | if (copy_to_user((struct move_extent *)arg, | 247 | return -EFAULT; |
| 248 | &me, sizeof(me))) | 248 | |
| 249 | return -EFAULT; | ||
| 250 | return err; | 249 | return err; |
| 251 | } | 250 | } |
| 252 | 251 | ||
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index cd258463e2a..e9c61896d60 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #include "mballoc.h" | 24 | #include "mballoc.h" |
| 25 | #include <linux/debugfs.h> | ||
| 25 | #include <trace/events/ext4.h> | 26 | #include <trace/events/ext4.h> |
| 26 | 27 | ||
| 27 | /* | 28 | /* |
| @@ -622,13 +623,13 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file, | |||
| 622 | 623 | ||
| 623 | /* FIXME!! need more doc */ | 624 | /* FIXME!! need more doc */ |
| 624 | static void ext4_mb_mark_free_simple(struct super_block *sb, | 625 | static void ext4_mb_mark_free_simple(struct super_block *sb, |
| 625 | void *buddy, unsigned first, int len, | 626 | void *buddy, ext4_grpblk_t first, ext4_grpblk_t len, |
| 626 | struct ext4_group_info *grp) | 627 | struct ext4_group_info *grp) |
| 627 | { | 628 | { |
| 628 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 629 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
| 629 | unsigned short min; | 630 | ext4_grpblk_t min; |
| 630 | unsigned short max; | 631 | ext4_grpblk_t max; |
| 631 | unsigned short chunk; | 632 | ext4_grpblk_t chunk; |
| 632 | unsigned short border; | 633 | unsigned short border; |
| 633 | 634 | ||
| 634 | BUG_ON(len > EXT4_BLOCKS_PER_GROUP(sb)); | 635 | BUG_ON(len > EXT4_BLOCKS_PER_GROUP(sb)); |
| @@ -662,10 +663,10 @@ void ext4_mb_generate_buddy(struct super_block *sb, | |||
| 662 | void *buddy, void *bitmap, ext4_group_t group) | 663 | void *buddy, void *bitmap, ext4_group_t group) |
| 663 | { | 664 | { |
| 664 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); | 665 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); |
| 665 | unsigned short max = EXT4_BLOCKS_PER_GROUP(sb); | 666 | ext4_grpblk_t max = EXT4_BLOCKS_PER_GROUP(sb); |
| 666 | unsigned short i = 0; | 667 | ext4_grpblk_t i = 0; |
| 667 | unsigned short first; | 668 | ext4_grpblk_t first; |
| 668 | unsigned short len; | 669 | ext4_grpblk_t len; |
| 669 | unsigned free = 0; | 670 | unsigned free = 0; |
| 670 | unsigned fragments = 0; | 671 | unsigned fragments = 0; |
| 671 | unsigned long long period = get_cycles(); | 672 | unsigned long long period = get_cycles(); |
| @@ -743,7 +744,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore) | |||
| 743 | char *data; | 744 | char *data; |
| 744 | char *bitmap; | 745 | char *bitmap; |
| 745 | 746 | ||
| 746 | mb_debug("init page %lu\n", page->index); | 747 | mb_debug(1, "init page %lu\n", page->index); |
| 747 | 748 | ||
| 748 | inode = page->mapping->host; | 749 | inode = page->mapping->host; |
| 749 | sb = inode->i_sb; | 750 | sb = inode->i_sb; |
| @@ -822,7 +823,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore) | |||
| 822 | set_bitmap_uptodate(bh[i]); | 823 | set_bitmap_uptodate(bh[i]); |
| 823 | bh[i]->b_end_io = end_buffer_read_sync; | 824 | bh[i]->b_end_io = end_buffer_read_sync; |
| 824 | submit_bh(READ, bh[i]); | 825 | submit_bh(READ, bh[i]); |
| 825 | mb_debug("read bitmap for group %u\n", first_group + i); | 826 | mb_debug(1, "read bitmap for group %u\n", first_group + i); |
| 826 | } | 827 | } |
| 827 | 828 | ||
| 828 | /* wait for I/O completion */ | 829 | /* wait for I/O completion */ |
| @@ -862,12 +863,13 @@ static int ext4_mb_init_cache(struct page *page, char *incore) | |||
| 862 | if ((first_block + i) & 1) { | 863 | if ((first_block + i) & 1) { |
| 863 | /* this is block of buddy */ | 864 | /* this is block of buddy */ |
| 864 | BUG_ON(incore == NULL); | 865 | BUG_ON(incore == NULL); |
| 865 | mb_debug("put buddy for group %u in page %lu/%x\n", | 866 | mb_debug(1, "put buddy for group %u in page %lu/%x\n", |
| 866 | group, page->index, i * blocksize); | 867 | group, page->index, i * blocksize); |
| 867 | grinfo = ext4_get_group_info(sb, group); | 868 | grinfo = ext4_get_group_info(sb, group); |
| 868 | grinfo->bb_fragments = 0; | 869 | grinfo->bb_fragments = 0; |
| 869 | memset(grinfo->bb_counters, 0, | 870 | memset(grinfo->bb_counters, 0, |
| 870 | sizeof(unsigned short)*(sb->s_blocksize_bits+2)); | 871 | sizeof(*grinfo->bb_counters) * |
| 872 | (sb->s_blocksize_bits+2)); | ||
| 871 | /* | 873 | /* |
| 872 | * incore got set to the group block bitmap below | 874 | * incore got set to the group block bitmap below |
| 873 | */ | 875 | */ |
| @@ -878,7 +880,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore) | |||
| 878 | } else { | 880 | } else { |
| 879 | /* this is block of bitmap */ | 881 | /* this is block of bitmap */ |
| 880 | BUG_ON(incore != NULL); | 882 | BUG_ON(incore != NULL); |
| 881 | mb_debug("put bitmap for group %u in page %lu/%x\n", | 883 | mb_debug(1, "put bitmap for group %u in page %lu/%x\n", |
| 882 | group, page->index, i * blocksize); | 884 | group, page->index, i * blocksize); |
| 883 | 885 | ||
| 884 | /* see comments in ext4_mb_put_pa() */ | 886 | /* see comments in ext4_mb_put_pa() */ |
| @@ -908,6 +910,100 @@ out: | |||
| 908 | return err; | 910 | return err; |
| 909 | } | 911 | } |
| 910 | 912 | ||
| 913 | static noinline_for_stack | ||
| 914 | int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) | ||
| 915 | { | ||
| 916 | |||
| 917 | int ret = 0; | ||
| 918 | void *bitmap; | ||
| 919 | int blocks_per_page; | ||
| 920 | int block, pnum, poff; | ||
| 921 | int num_grp_locked = 0; | ||
| 922 | struct ext4_group_info *this_grp; | ||
| 923 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
| 924 | struct inode *inode = sbi->s_buddy_cache; | ||
| 925 | struct page *page = NULL, *bitmap_page = NULL; | ||
| 926 | |||
| 927 | mb_debug(1, "init group %u\n", group); | ||
| 928 | blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; | ||
| 929 | this_grp = ext4_get_group_info(sb, group); | ||
| 930 | /* | ||
| 931 | * This ensures that we don't reinit the buddy cache | ||
| 932 | * page which map to the group from which we are already | ||
| 933 | * allocating. If we are looking at the buddy cache we would | ||
| 934 | * have taken a reference using ext4_mb_load_buddy and that | ||
| 935 | * would have taken the alloc_sem lock. | ||
| 936 | */ | ||
| 937 | num_grp_locked = ext4_mb_get_buddy_cache_lock(sb, group); | ||
| 938 | if (!EXT4_MB_GRP_NEED_INIT(this_grp)) { | ||
| 939 | /* | ||
| 940 | * somebody initialized the group | ||
| 941 | * return without doing anything | ||
| 942 | */ | ||
| 943 | ret = 0; | ||
| 944 | goto err; | ||
| 945 | } | ||
| 946 | /* | ||
| 947 | * the buddy cache inode stores the block bitmap | ||
| 948 | * and buddy information in consecutive blocks. | ||
| 949 | * So for each group we need two blocks. | ||
| 950 | */ | ||
| 951 | block = group * 2; | ||
| 952 | pnum = block / blocks_per_page; | ||
| 953 | poff = block % blocks_per_page; | ||
| 954 | page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); | ||
| 955 | if (page) { | ||
| 956 | BUG_ON(page->mapping != inode->i_mapping); | ||
| 957 | ret = ext4_mb_init_cache(page, NULL); | ||
| 958 | if (ret) { | ||
| 959 | unlock_page(page); | ||
| 960 | goto err; | ||
| 961 | } | ||
| 962 | unlock_page(page); | ||
| 963 | } | ||
| 964 | if (page == NULL || !PageUptodate(page)) { | ||
| 965 | ret = -EIO; | ||
| 966 | goto err; | ||
| 967 | } | ||
| 968 | mark_page_accessed(page); | ||
| 969 | bitmap_page = page; | ||
| 970 | bitmap = page_address(page) + (poff * sb->s_blocksize); | ||
| 971 | |||
| 972 | /* init buddy cache */ | ||
| 973 | block++; | ||
| 974 | pnum = block / blocks_per_page; | ||
| 975 | poff = block % blocks_per_page; | ||
| 976 | page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); | ||
| 977 | if (page == bitmap_page) { | ||
| 978 | /* | ||
| 979 | * If both the bitmap and buddy are in | ||
| 980 | * the same page we don't need to force | ||
| 981 | * init the buddy | ||
| 982 | */ | ||
| 983 | unlock_page(page); | ||
| 984 | } else if (page) { | ||
| 985 | BUG_ON(page->mapping != inode->i_mapping); | ||
| 986 | ret = ext4_mb_init_cache(page, bitmap); | ||
| 987 | if (ret) { | ||
| 988 | unlock_page(page); | ||
| 989 | goto err; | ||
| 990 | } | ||
| 991 | unlock_page(page); | ||
| 992 | } | ||
| 993 | if (page == NULL || !PageUptodate(page)) { | ||
| 994 | ret = -EIO; | ||
| 995 | goto err; | ||
| 996 | } | ||
| 997 | mark_page_accessed(page); | ||
| 998 | err: | ||
| 999 | ext4_mb_put_buddy_cache_lock(sb, group, num_grp_locked); | ||
| 1000 | if (bitmap_page) | ||
| 1001 | page_cache_release(bitmap_page); | ||
| 1002 | if (page) | ||
| 1003 | page_cache_release(page); | ||
| 1004 | return ret; | ||
| 1005 | } | ||
| 1006 | |||
| 911 | static noinline_for_stack int | 1007 | static noinline_for_stack int |
| 912 | ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, | 1008 | ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, |
| 913 | struct ext4_buddy *e4b) | 1009 | struct ext4_buddy *e4b) |
| @@ -922,7 +1018,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, | |||
| 922 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 1018 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
| 923 | struct inode *inode = sbi->s_buddy_cache; | 1019 | struct inode *inode = sbi->s_buddy_cache; |
| 924 | 1020 | ||
| 925 | mb_debug("load group %u\n", group); | 1021 | mb_debug(1, "load group %u\n", group); |
| 926 | 1022 | ||
| 927 | blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; | 1023 | blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; |
| 928 | grp = ext4_get_group_info(sb, group); | 1024 | grp = ext4_get_group_info(sb, group); |
| @@ -941,8 +1037,26 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, | |||
| 941 | * groups mapped by the page is blocked | 1037 | * groups mapped by the page is blocked |
| 942 | * till we are done with allocation | 1038 | * till we are done with allocation |
| 943 | */ | 1039 | */ |
| 1040 | repeat_load_buddy: | ||
| 944 | down_read(e4b->alloc_semp); | 1041 | down_read(e4b->alloc_semp); |
| 945 | 1042 | ||
| 1043 | if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) { | ||
| 1044 | /* we need to check for group need init flag | ||
| 1045 | * with alloc_semp held so that we can be sure | ||
| 1046 | * that new blocks didn't get added to the group | ||
| 1047 | * when we are loading the buddy cache | ||
| 1048 | */ | ||
| 1049 | up_read(e4b->alloc_semp); | ||
| 1050 | /* | ||
| 1051 | * we need full data about the group | ||
| 1052 | * to make a good selection | ||
| 1053 | */ | ||
| 1054 | ret = ext4_mb_init_group(sb, group); | ||
| 1055 | if (ret) | ||
| 1056 | return ret; | ||
| 1057 | goto repeat_load_buddy; | ||
| 1058 | } | ||
| 1059 | |||
| 946 | /* | 1060 | /* |
| 947 | * the buddy cache inode stores the block bitmap | 1061 | * the buddy cache inode stores the block bitmap |
| 948 | * and buddy information in consecutive blocks. | 1062 | * and buddy information in consecutive blocks. |
| @@ -1360,7 +1474,7 @@ static void ext4_mb_use_best_found(struct ext4_allocation_context *ac, | |||
| 1360 | ac->alloc_semp = e4b->alloc_semp; | 1474 | ac->alloc_semp = e4b->alloc_semp; |
| 1361 | e4b->alloc_semp = NULL; | 1475 | e4b->alloc_semp = NULL; |
| 1362 | /* store last allocated for subsequent stream allocation */ | 1476 | /* store last allocated for subsequent stream allocation */ |
| 1363 | if ((ac->ac_flags & EXT4_MB_HINT_DATA)) { | 1477 | if (ac->ac_flags & EXT4_MB_STREAM_ALLOC) { |
| 1364 | spin_lock(&sbi->s_md_lock); | 1478 | spin_lock(&sbi->s_md_lock); |
| 1365 | sbi->s_mb_last_group = ac->ac_f_ex.fe_group; | 1479 | sbi->s_mb_last_group = ac->ac_f_ex.fe_group; |
| 1366 | sbi->s_mb_last_start = ac->ac_f_ex.fe_start; | 1480 | sbi->s_mb_last_start = ac->ac_f_ex.fe_start; |
| @@ -1837,97 +1951,6 @@ void ext4_mb_put_buddy_cache_lock(struct super_block *sb, | |||
| 1837 | 1951 | ||
| 1838 | } | 1952 | } |
| 1839 | 1953 | ||
| 1840 | static noinline_for_stack | ||
| 1841 | int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) | ||
| 1842 | { | ||
| 1843 | |||
| 1844 | int ret; | ||
| 1845 | void *bitmap; | ||
| 1846 | int blocks_per_page; | ||
| 1847 | int block, pnum, poff; | ||
| 1848 | int num_grp_locked = 0; | ||
| 1849 | struct ext4_group_info *this_grp; | ||
| 1850 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
| 1851 | struct inode *inode = sbi->s_buddy_cache; | ||
| 1852 | struct page *page = NULL, *bitmap_page = NULL; | ||
| 1853 | |||
| 1854 | mb_debug("init group %lu\n", group); | ||
| 1855 | blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; | ||
| 1856 | this_grp = ext4_get_group_info(sb, group); | ||
| 1857 | /* | ||
| 1858 | * This ensures we don't add group | ||
| 1859 | * to this buddy cache via resize | ||
| 1860 | */ | ||
| 1861 | num_grp_locked = ext4_mb_get_buddy_cache_lock(sb, group); | ||
| 1862 | if (!EXT4_MB_GRP_NEED_INIT(this_grp)) { | ||
| 1863 | /* | ||
| 1864 | * somebody initialized the group | ||
| 1865 | * return without doing anything | ||
| 1866 | */ | ||
| 1867 | ret = 0; | ||
| 1868 | goto err; | ||
| 1869 | } | ||
| 1870 | /* | ||
| 1871 | * the buddy cache inode stores the block bitmap | ||
| 1872 | * and buddy information in consecutive blocks. | ||
| 1873 | * So for each group we need two blocks. | ||
| 1874 | */ | ||
| 1875 | block = group * 2; | ||
| 1876 | pnum = block / blocks_per_page; | ||
| 1877 | poff = block % blocks_per_page; | ||
| 1878 | page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); | ||
| 1879 | if (page) { | ||
| 1880 | BUG_ON(page->mapping != inode->i_mapping); | ||
| 1881 | ret = ext4_mb_init_cache(page, NULL); | ||
| 1882 | if (ret) { | ||
| 1883 | unlock_page(page); | ||
| 1884 | goto err; | ||
| 1885 | } | ||
| 1886 | unlock_page(page); | ||
| 1887 | } | ||
| 1888 | if (page == NULL || !PageUptodate(page)) { | ||
| 1889 | ret = -EIO; | ||
| 1890 | goto err; | ||
| 1891 | } | ||
| 1892 | mark_page_accessed(page); | ||
| 1893 | bitmap_page = page; | ||
| 1894 | bitmap = page_address(page) + (poff * sb->s_blocksize); | ||
| 1895 | |||
| 1896 | /* init buddy cache */ | ||
| 1897 | block++; | ||
| 1898 | pnum = block / blocks_per_page; | ||
| 1899 | poff = block % blocks_per_page; | ||
| 1900 | page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); | ||
| 1901 | if (page == bitmap_page) { | ||
| 1902 | /* | ||
| 1903 | * If both the bitmap and buddy are in | ||
| 1904 | * the same page we don't need to force | ||
| 1905 | * init the buddy | ||
| 1906 | */ | ||
| 1907 | unlock_page(page); | ||
| 1908 | } else if (page) { | ||
| 1909 | BUG_ON(page->mapping != inode->i_mapping); | ||
| 1910 | ret = ext4_mb_init_cache(page, bitmap); | ||
| 1911 | if (ret) { | ||
| 1912 | unlock_page(page); | ||
| 1913 | goto err; | ||
| 1914 | } | ||
| 1915 | unlock_page(page); | ||
| 1916 | } | ||
| 1917 | if (page == NULL || !PageUptodate(page)) { | ||
| 1918 | ret = -EIO; | ||
| 1919 | goto err; | ||
| 1920 | } | ||
| 1921 | mark_page_accessed(page); | ||
| 1922 | err: | ||
| 1923 | ext4_mb_put_buddy_cache_lock(sb, group, num_grp_locked); | ||
| 1924 | if (bitmap_page) | ||
| 1925 | page_cache_release(bitmap_page); | ||
| 1926 | if (page) | ||
| 1927 | page_cache_release(page); | ||
| 1928 | return ret; | ||
| 1929 | } | ||
| 1930 | |||
| 1931 | static noinline_for_stack int | 1954 | static noinline_for_stack int |
| 1932 | ext4_mb_regular_allocator(struct ext4_allocation_context *ac) | 1955 | ext4_mb_regular_allocator(struct ext4_allocation_context *ac) |
| 1933 | { | 1956 | { |
| @@ -1938,11 +1961,14 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac) | |||
| 1938 | struct ext4_sb_info *sbi; | 1961 | struct ext4_sb_info *sbi; |
| 1939 | struct super_block *sb; | 1962 | struct super_block *sb; |
| 1940 | struct ext4_buddy e4b; | 1963 | struct ext4_buddy e4b; |
| 1941 | loff_t size, isize; | ||
| 1942 | 1964 | ||
| 1943 | sb = ac->ac_sb; | 1965 | sb = ac->ac_sb; |
| 1944 | sbi = EXT4_SB(sb); | 1966 | sbi = EXT4_SB(sb); |
| 1945 | ngroups = ext4_get_groups_count(sb); | 1967 | ngroups = ext4_get_groups_count(sb); |
| 1968 | /* non-extent files are limited to low blocks/groups */ | ||
| 1969 | if (!(EXT4_I(ac->ac_inode)->i_flags & EXT4_EXTENTS_FL)) | ||
| 1970 | ngroups = sbi->s_blockfile_groups; | ||
| 1971 | |||
| 1946 | BUG_ON(ac->ac_status == AC_STATUS_FOUND); | 1972 | BUG_ON(ac->ac_status == AC_STATUS_FOUND); |
| 1947 | 1973 | ||
| 1948 | /* first, try the goal */ | 1974 | /* first, try the goal */ |
| @@ -1974,20 +2000,16 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac) | |||
| 1974 | } | 2000 | } |
| 1975 | 2001 | ||
| 1976 | bsbits = ac->ac_sb->s_blocksize_bits; | 2002 | bsbits = ac->ac_sb->s_blocksize_bits; |
| 1977 | /* if stream allocation is enabled, use global goal */ | ||
| 1978 | size = ac->ac_o_ex.fe_logical + ac->ac_o_ex.fe_len; | ||
| 1979 | isize = i_size_read(ac->ac_inode) >> bsbits; | ||
| 1980 | if (size < isize) | ||
| 1981 | size = isize; | ||
| 1982 | 2003 | ||
| 1983 | if (size < sbi->s_mb_stream_request && | 2004 | /* if stream allocation is enabled, use global goal */ |
| 1984 | (ac->ac_flags & EXT4_MB_HINT_DATA)) { | 2005 | if (ac->ac_flags & EXT4_MB_STREAM_ALLOC) { |
| 1985 | /* TBD: may be hot point */ | 2006 | /* TBD: may be hot point */ |
| 1986 | spin_lock(&sbi->s_md_lock); | 2007 | spin_lock(&sbi->s_md_lock); |
| 1987 | ac->ac_g_ex.fe_group = sbi->s_mb_last_group; | 2008 | ac->ac_g_ex.fe_group = sbi->s_mb_last_group; |
| 1988 | ac->ac_g_ex.fe_start = sbi->s_mb_last_start; | 2009 | ac->ac_g_ex.fe_start = sbi->s_mb_last_start; |
| 1989 | spin_unlock(&sbi->s_md_lock); | 2010 | spin_unlock(&sbi->s_md_lock); |
| 1990 | } | 2011 | } |
| 2012 | |||
| 1991 | /* Let's just scan groups to find more-less suitable blocks */ | 2013 | /* Let's just scan groups to find more-less suitable blocks */ |
| 1992 | cr = ac->ac_2order ? 0 : 1; | 2014 | cr = ac->ac_2order ? 0 : 1; |
| 1993 | /* | 2015 | /* |
| @@ -2015,27 +2037,6 @@ repeat: | |||
| 2015 | if (grp->bb_free == 0) | 2037 | if (grp->bb_free == 0) |
| 2016 | continue; | 2038 | continue; |
| 2017 | 2039 | ||
| 2018 | /* | ||
| 2019 | * if the group is already init we check whether it is | ||
| 2020 | * a good group and if not we don't load the buddy | ||
| 2021 | */ | ||
| 2022 | if (EXT4_MB_GRP_NEED_INIT(grp)) { | ||
| 2023 | /* | ||
| 2024 | * we need full data about the group | ||
| 2025 | * to make a good selection | ||
| 2026 | */ | ||
| 2027 | err = ext4_mb_init_group(sb, group); | ||
| 2028 | if (err) | ||
| 2029 | goto out; | ||
| 2030 | } | ||
| 2031 | |||
| 2032 | /* | ||
| 2033 | * If the particular group doesn't satisfy our | ||
| 2034 | * criteria we continue with the next group | ||
| 2035 | */ | ||
| 2036 | if (!ext4_mb_good_group(ac, group, cr)) | ||
| 2037 | continue; | ||
| 2038 | |||
| 2039 | err = ext4_mb_load_buddy(sb, group, &e4b); | 2040 | err = ext4_mb_load_buddy(sb, group, &e4b); |
| 2040 | if (err) | 2041 | if (err) |
| 2041 | goto out; | 2042 | goto out; |
| @@ -2156,7 +2157,7 @@ static int ext4_mb_seq_history_show(struct seq_file *seq, void *v) | |||
| 2156 | 2157 | ||
| 2157 | if (v == SEQ_START_TOKEN) { | 2158 | if (v == SEQ_START_TOKEN) { |
| 2158 | seq_printf(seq, "%-5s %-8s %-23s %-23s %-23s %-5s " | 2159 | seq_printf(seq, "%-5s %-8s %-23s %-23s %-23s %-5s " |
| 2159 | "%-5s %-2s %-5s %-5s %-5s %-6s\n", | 2160 | "%-5s %-2s %-6s %-5s %-5s %-6s\n", |
| 2160 | "pid", "inode", "original", "goal", "result", "found", | 2161 | "pid", "inode", "original", "goal", "result", "found", |
| 2161 | "grps", "cr", "flags", "merge", "tail", "broken"); | 2162 | "grps", "cr", "flags", "merge", "tail", "broken"); |
| 2162 | return 0; | 2163 | return 0; |
| @@ -2164,7 +2165,7 @@ static int ext4_mb_seq_history_show(struct seq_file *seq, void *v) | |||
| 2164 | 2165 | ||
| 2165 | if (hs->op == EXT4_MB_HISTORY_ALLOC) { | 2166 | if (hs->op == EXT4_MB_HISTORY_ALLOC) { |
| 2166 | fmt = "%-5u %-8u %-23s %-23s %-23s %-5u %-5u %-2u " | 2167 | fmt = "%-5u %-8u %-23s %-23s %-23s %-5u %-5u %-2u " |
| 2167 | "%-5u %-5s %-5u %-6u\n"; | 2168 | "0x%04x %-5s %-5u %-6u\n"; |
| 2168 | sprintf(buf2, "%u/%d/%u@%u", hs->result.fe_group, | 2169 | sprintf(buf2, "%u/%d/%u@%u", hs->result.fe_group, |
| 2169 | hs->result.fe_start, hs->result.fe_len, | 2170 | hs->result.fe_start, hs->result.fe_len, |
| 2170 | hs->result.fe_logical); | 2171 | hs->result.fe_logical); |
| @@ -2205,7 +2206,7 @@ static void ext4_mb_seq_history_stop(struct seq_file *seq, void *v) | |||
| 2205 | { | 2206 | { |
| 2206 | } | 2207 | } |
| 2207 | 2208 | ||
| 2208 | static struct seq_operations ext4_mb_seq_history_ops = { | 2209 | static const struct seq_operations ext4_mb_seq_history_ops = { |
| 2209 | .start = ext4_mb_seq_history_start, | 2210 | .start = ext4_mb_seq_history_start, |
| 2210 | .next = ext4_mb_seq_history_next, | 2211 | .next = ext4_mb_seq_history_next, |
| 2211 | .stop = ext4_mb_seq_history_stop, | 2212 | .stop = ext4_mb_seq_history_stop, |
| @@ -2287,7 +2288,7 @@ static ssize_t ext4_mb_seq_history_write(struct file *file, | |||
| 2287 | return count; | 2288 | return count; |
| 2288 | } | 2289 | } |
| 2289 | 2290 | ||
| 2290 | static struct file_operations ext4_mb_seq_history_fops = { | 2291 | static const struct file_operations ext4_mb_seq_history_fops = { |
| 2291 | .owner = THIS_MODULE, | 2292 | .owner = THIS_MODULE, |
| 2292 | .open = ext4_mb_seq_history_open, | 2293 | .open = ext4_mb_seq_history_open, |
| 2293 | .read = seq_read, | 2294 | .read = seq_read, |
| @@ -2328,7 +2329,7 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v) | |||
| 2328 | struct ext4_buddy e4b; | 2329 | struct ext4_buddy e4b; |
| 2329 | struct sg { | 2330 | struct sg { |
| 2330 | struct ext4_group_info info; | 2331 | struct ext4_group_info info; |
| 2331 | unsigned short counters[16]; | 2332 | ext4_grpblk_t counters[16]; |
| 2332 | } sg; | 2333 | } sg; |
| 2333 | 2334 | ||
| 2334 | group--; | 2335 | group--; |
| @@ -2366,7 +2367,7 @@ static void ext4_mb_seq_groups_stop(struct seq_file *seq, void *v) | |||
| 2366 | { | 2367 | { |
| 2367 | } | 2368 | } |
| 2368 | 2369 | ||
| 2369 | static struct seq_operations ext4_mb_seq_groups_ops = { | 2370 | static const struct seq_operations ext4_mb_seq_groups_ops = { |
| 2370 | .start = ext4_mb_seq_groups_start, | 2371 | .start = ext4_mb_seq_groups_start, |
| 2371 | .next = ext4_mb_seq_groups_next, | 2372 | .next = ext4_mb_seq_groups_next, |
| 2372 | .stop = ext4_mb_seq_groups_stop, | 2373 | .stop = ext4_mb_seq_groups_stop, |
| @@ -2387,7 +2388,7 @@ static int ext4_mb_seq_groups_open(struct inode *inode, struct file *file) | |||
| 2387 | 2388 | ||
| 2388 | } | 2389 | } |
| 2389 | 2390 | ||
| 2390 | static struct file_operations ext4_mb_seq_groups_fops = { | 2391 | static const struct file_operations ext4_mb_seq_groups_fops = { |
| 2391 | .owner = THIS_MODULE, | 2392 | .owner = THIS_MODULE, |
| 2392 | .open = ext4_mb_seq_groups_open, | 2393 | .open = ext4_mb_seq_groups_open, |
| 2393 | .read = seq_read, | 2394 | .read = seq_read, |
| @@ -2532,7 +2533,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group, | |||
| 2532 | 2533 | ||
| 2533 | INIT_LIST_HEAD(&meta_group_info[i]->bb_prealloc_list); | 2534 | INIT_LIST_HEAD(&meta_group_info[i]->bb_prealloc_list); |
| 2534 | init_rwsem(&meta_group_info[i]->alloc_sem); | 2535 | init_rwsem(&meta_group_info[i]->alloc_sem); |
| 2535 | meta_group_info[i]->bb_free_root.rb_node = NULL;; | 2536 | meta_group_info[i]->bb_free_root.rb_node = NULL; |
| 2536 | 2537 | ||
| 2537 | #ifdef DOUBLE_CHECK | 2538 | #ifdef DOUBLE_CHECK |
| 2538 | { | 2539 | { |
| @@ -2558,26 +2559,15 @@ exit_meta_group_info: | |||
| 2558 | return -ENOMEM; | 2559 | return -ENOMEM; |
| 2559 | } /* ext4_mb_add_groupinfo */ | 2560 | } /* ext4_mb_add_groupinfo */ |
| 2560 | 2561 | ||
| 2561 | /* | ||
| 2562 | * Update an existing group. | ||
| 2563 | * This function is used for online resize | ||
| 2564 | */ | ||
| 2565 | void ext4_mb_update_group_info(struct ext4_group_info *grp, ext4_grpblk_t add) | ||
| 2566 | { | ||
| 2567 | grp->bb_free += add; | ||
| 2568 | } | ||
| 2569 | |||
| 2570 | static int ext4_mb_init_backend(struct super_block *sb) | 2562 | static int ext4_mb_init_backend(struct super_block *sb) |
| 2571 | { | 2563 | { |
| 2572 | ext4_group_t ngroups = ext4_get_groups_count(sb); | 2564 | ext4_group_t ngroups = ext4_get_groups_count(sb); |
| 2573 | ext4_group_t i; | 2565 | ext4_group_t i; |
| 2574 | int metalen; | ||
| 2575 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 2566 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
| 2576 | struct ext4_super_block *es = sbi->s_es; | 2567 | struct ext4_super_block *es = sbi->s_es; |
| 2577 | int num_meta_group_infos; | 2568 | int num_meta_group_infos; |
| 2578 | int num_meta_group_infos_max; | 2569 | int num_meta_group_infos_max; |
| 2579 | int array_size; | 2570 | int array_size; |
| 2580 | struct ext4_group_info **meta_group_info; | ||
| 2581 | struct ext4_group_desc *desc; | 2571 | struct ext4_group_desc *desc; |
| 2582 | 2572 | ||
| 2583 | /* This is the number of blocks used by GDT */ | 2573 | /* This is the number of blocks used by GDT */ |
| @@ -2622,22 +2612,6 @@ static int ext4_mb_init_backend(struct super_block *sb) | |||
| 2622 | goto err_freesgi; | 2612 | goto err_freesgi; |
| 2623 | } | 2613 | } |
| 2624 | EXT4_I(sbi->s_buddy_cache)->i_disksize = 0; | 2614 | EXT4_I(sbi->s_buddy_cache)->i_disksize = 0; |
| 2625 | |||
| 2626 | metalen = sizeof(*meta_group_info) << EXT4_DESC_PER_BLOCK_BITS(sb); | ||
| 2627 | for (i = 0; i < num_meta_group_infos; i++) { | ||
| 2628 | if ((i + 1) == num_meta_group_infos) | ||
| 2629 | metalen = sizeof(*meta_group_info) * | ||
| 2630 | (ngroups - | ||
| 2631 | (i << EXT4_DESC_PER_BLOCK_BITS(sb))); | ||
| 2632 | meta_group_info = kmalloc(metalen, GFP_KERNEL); | ||
| 2633 | if (meta_group_info == NULL) { | ||
| 2634 | printk(KERN_ERR "EXT4-fs: can't allocate mem for a " | ||
| 2635 | "buddy group\n"); | ||
| 2636 | goto err_freemeta; | ||
| 2637 | } | ||
| 2638 | sbi->s_group_info[i] = meta_group_info; | ||
| 2639 | } | ||
| 2640 | |||
| 2641 | for (i = 0; i < ngroups; i++) { | 2615 | for (i = 0; i < ngroups; i++) { |
| 2642 | desc = ext4_get_group_desc(sb, i, NULL); | 2616 | desc = ext4_get_group_desc(sb, i, NULL); |
| 2643 | if (desc == NULL) { | 2617 | if (desc == NULL) { |
| @@ -2655,7 +2629,6 @@ err_freebuddy: | |||
| 2655 | while (i-- > 0) | 2629 | while (i-- > 0) |
| 2656 | kfree(ext4_get_group_info(sb, i)); | 2630 | kfree(ext4_get_group_info(sb, i)); |
| 2657 | i = num_meta_group_infos; | 2631 | i = num_meta_group_infos; |
| 2658 | err_freemeta: | ||
| 2659 | while (i-- > 0) | 2632 | while (i-- > 0) |
| 2660 | kfree(sbi->s_group_info[i]); | 2633 | kfree(sbi->s_group_info[i]); |
| 2661 | iput(sbi->s_buddy_cache); | 2634 | iput(sbi->s_buddy_cache); |
| @@ -2672,14 +2645,14 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery) | |||
| 2672 | unsigned max; | 2645 | unsigned max; |
| 2673 | int ret; | 2646 | int ret; |
| 2674 | 2647 | ||
| 2675 | i = (sb->s_blocksize_bits + 2) * sizeof(unsigned short); | 2648 | i = (sb->s_blocksize_bits + 2) * sizeof(*sbi->s_mb_offsets); |
| 2676 | 2649 | ||
| 2677 | sbi->s_mb_offsets = kmalloc(i, GFP_KERNEL); | 2650 | sbi->s_mb_offsets = kmalloc(i, GFP_KERNEL); |
| 2678 | if (sbi->s_mb_offsets == NULL) { | 2651 | if (sbi->s_mb_offsets == NULL) { |
| 2679 | return -ENOMEM; | 2652 | return -ENOMEM; |
| 2680 | } | 2653 | } |
| 2681 | 2654 | ||
| 2682 | i = (sb->s_blocksize_bits + 2) * sizeof(unsigned int); | 2655 | i = (sb->s_blocksize_bits + 2) * sizeof(*sbi->s_mb_maxs); |
| 2683 | sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL); | 2656 | sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL); |
| 2684 | if (sbi->s_mb_maxs == NULL) { | 2657 | if (sbi->s_mb_maxs == NULL) { |
| 2685 | kfree(sbi->s_mb_offsets); | 2658 | kfree(sbi->s_mb_offsets); |
| @@ -2758,7 +2731,7 @@ static void ext4_mb_cleanup_pa(struct ext4_group_info *grp) | |||
| 2758 | kmem_cache_free(ext4_pspace_cachep, pa); | 2731 | kmem_cache_free(ext4_pspace_cachep, pa); |
| 2759 | } | 2732 | } |
| 2760 | if (count) | 2733 | if (count) |
| 2761 | mb_debug("mballoc: %u PAs left\n", count); | 2734 | mb_debug(1, "mballoc: %u PAs left\n", count); |
| 2762 | 2735 | ||
| 2763 | } | 2736 | } |
| 2764 | 2737 | ||
| @@ -2839,7 +2812,7 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn) | |||
| 2839 | list_for_each_safe(l, ltmp, &txn->t_private_list) { | 2812 | list_for_each_safe(l, ltmp, &txn->t_private_list) { |
| 2840 | entry = list_entry(l, struct ext4_free_data, list); | 2813 | entry = list_entry(l, struct ext4_free_data, list); |
| 2841 | 2814 | ||
| 2842 | mb_debug("gonna free %u blocks in group %u (0x%p):", | 2815 | mb_debug(1, "gonna free %u blocks in group %u (0x%p):", |
| 2843 | entry->count, entry->group, entry); | 2816 | entry->count, entry->group, entry); |
| 2844 | 2817 | ||
| 2845 | err = ext4_mb_load_buddy(sb, entry->group, &e4b); | 2818 | err = ext4_mb_load_buddy(sb, entry->group, &e4b); |
| @@ -2874,9 +2847,43 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn) | |||
| 2874 | ext4_mb_release_desc(&e4b); | 2847 | ext4_mb_release_desc(&e4b); |
| 2875 | } | 2848 | } |
| 2876 | 2849 | ||
| 2877 | mb_debug("freed %u blocks in %u structures\n", count, count2); | 2850 | mb_debug(1, "freed %u blocks in %u structures\n", count, count2); |
| 2851 | } | ||
| 2852 | |||
| 2853 | #ifdef CONFIG_EXT4_DEBUG | ||
| 2854 | u8 mb_enable_debug __read_mostly; | ||
| 2855 | |||
| 2856 | static struct dentry *debugfs_dir; | ||
| 2857 | static struct dentry *debugfs_debug; | ||
| 2858 | |||
| 2859 | static void __init ext4_create_debugfs_entry(void) | ||
| 2860 | { | ||
| 2861 | debugfs_dir = debugfs_create_dir("ext4", NULL); | ||
| 2862 | if (debugfs_dir) | ||
| 2863 | debugfs_debug = debugfs_create_u8("mballoc-debug", | ||
| 2864 | S_IRUGO | S_IWUSR, | ||
| 2865 | debugfs_dir, | ||
| 2866 | &mb_enable_debug); | ||
| 2867 | } | ||
| 2868 | |||
| 2869 | static void ext4_remove_debugfs_entry(void) | ||
| 2870 | { | ||
| 2871 | debugfs_remove(debugfs_debug); | ||
| 2872 | debugfs_remove(debugfs_dir); | ||
| 2878 | } | 2873 | } |
| 2879 | 2874 | ||
| 2875 | #else | ||
| 2876 | |||
| 2877 | static void __init ext4_create_debugfs_entry(void) | ||
| 2878 | { | ||
| 2879 | } | ||
| 2880 | |||
| 2881 | static void ext4_remove_debugfs_entry(void) | ||
| 2882 | { | ||
| 2883 | } | ||
| 2884 | |||
| 2885 | #endif | ||
| 2886 | |||
| 2880 | int __init init_ext4_mballoc(void) | 2887 | int __init init_ext4_mballoc(void) |
| 2881 | { | 2888 | { |
| 2882 | ext4_pspace_cachep = | 2889 | ext4_pspace_cachep = |
| @@ -2904,6 +2911,7 @@ int __init init_ext4_mballoc(void) | |||
| 2904 | kmem_cache_destroy(ext4_ac_cachep); | 2911 | kmem_cache_destroy(ext4_ac_cachep); |
| 2905 | return -ENOMEM; | 2912 | return -ENOMEM; |
| 2906 | } | 2913 | } |
| 2914 | ext4_create_debugfs_entry(); | ||
| 2907 | return 0; | 2915 | return 0; |
| 2908 | } | 2916 | } |
| 2909 | 2917 | ||
| @@ -2917,6 +2925,7 @@ void exit_ext4_mballoc(void) | |||
| 2917 | kmem_cache_destroy(ext4_pspace_cachep); | 2925 | kmem_cache_destroy(ext4_pspace_cachep); |
| 2918 | kmem_cache_destroy(ext4_ac_cachep); | 2926 | kmem_cache_destroy(ext4_ac_cachep); |
| 2919 | kmem_cache_destroy(ext4_free_ext_cachep); | 2927 | kmem_cache_destroy(ext4_free_ext_cachep); |
| 2928 | ext4_remove_debugfs_entry(); | ||
| 2920 | } | 2929 | } |
| 2921 | 2930 | ||
| 2922 | 2931 | ||
| @@ -3061,7 +3070,7 @@ static void ext4_mb_normalize_group_request(struct ext4_allocation_context *ac) | |||
| 3061 | ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_stripe; | 3070 | ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_stripe; |
| 3062 | else | 3071 | else |
| 3063 | ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_mb_group_prealloc; | 3072 | ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_mb_group_prealloc; |
| 3064 | mb_debug("#%u: goal %u blocks for locality group\n", | 3073 | mb_debug(1, "#%u: goal %u blocks for locality group\n", |
| 3065 | current->pid, ac->ac_g_ex.fe_len); | 3074 | current->pid, ac->ac_g_ex.fe_len); |
| 3066 | } | 3075 | } |
| 3067 | 3076 | ||
| @@ -3180,23 +3189,18 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, | |||
| 3180 | BUG_ON(!(ac->ac_o_ex.fe_logical >= pa_end || | 3189 | BUG_ON(!(ac->ac_o_ex.fe_logical >= pa_end || |
| 3181 | ac->ac_o_ex.fe_logical < pa->pa_lstart)); | 3190 | ac->ac_o_ex.fe_logical < pa->pa_lstart)); |
| 3182 | 3191 | ||
| 3183 | /* skip PA normalized request doesn't overlap with */ | 3192 | /* skip PAs this normalized request doesn't overlap with */ |
| 3184 | if (pa->pa_lstart >= end) { | 3193 | if (pa->pa_lstart >= end || pa_end <= start) { |
| 3185 | spin_unlock(&pa->pa_lock); | ||
| 3186 | continue; | ||
| 3187 | } | ||
| 3188 | if (pa_end <= start) { | ||
| 3189 | spin_unlock(&pa->pa_lock); | 3194 | spin_unlock(&pa->pa_lock); |
| 3190 | continue; | 3195 | continue; |
| 3191 | } | 3196 | } |
| 3192 | BUG_ON(pa->pa_lstart <= start && pa_end >= end); | 3197 | BUG_ON(pa->pa_lstart <= start && pa_end >= end); |
| 3193 | 3198 | ||
| 3199 | /* adjust start or end to be adjacent to this pa */ | ||
| 3194 | if (pa_end <= ac->ac_o_ex.fe_logical) { | 3200 | if (pa_end <= ac->ac_o_ex.fe_logical) { |
| 3195 | BUG_ON(pa_end < start); | 3201 | BUG_ON(pa_end < start); |
| 3196 | start = pa_end; | 3202 | start = pa_end; |
| 3197 | } | 3203 | } else if (pa->pa_lstart > ac->ac_o_ex.fe_logical) { |
| 3198 | |||
| 3199 | if (pa->pa_lstart > ac->ac_o_ex.fe_logical) { | ||
| 3200 | BUG_ON(pa->pa_lstart > end); | 3204 | BUG_ON(pa->pa_lstart > end); |
| 3201 | end = pa->pa_lstart; | 3205 | end = pa->pa_lstart; |
| 3202 | } | 3206 | } |
| @@ -3251,7 +3255,7 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, | |||
| 3251 | ac->ac_flags |= EXT4_MB_HINT_TRY_GOAL; | 3255 | ac->ac_flags |= EXT4_MB_HINT_TRY_GOAL; |
| 3252 | } | 3256 | } |
| 3253 | 3257 | ||
| 3254 | mb_debug("goal: %u(was %u) blocks at %u\n", (unsigned) size, | 3258 | mb_debug(1, "goal: %u(was %u) blocks at %u\n", (unsigned) size, |
| 3255 | (unsigned) orig_size, (unsigned) start); | 3259 | (unsigned) orig_size, (unsigned) start); |
| 3256 | } | 3260 | } |
| 3257 | 3261 | ||
| @@ -3300,7 +3304,7 @@ static void ext4_mb_use_inode_pa(struct ext4_allocation_context *ac, | |||
| 3300 | BUG_ON(pa->pa_free < len); | 3304 | BUG_ON(pa->pa_free < len); |
| 3301 | pa->pa_free -= len; | 3305 | pa->pa_free -= len; |
| 3302 | 3306 | ||
| 3303 | mb_debug("use %llu/%u from inode pa %p\n", start, len, pa); | 3307 | mb_debug(1, "use %llu/%u from inode pa %p\n", start, len, pa); |
| 3304 | } | 3308 | } |
| 3305 | 3309 | ||
| 3306 | /* | 3310 | /* |
| @@ -3324,7 +3328,7 @@ static void ext4_mb_use_group_pa(struct ext4_allocation_context *ac, | |||
| 3324 | * in on-disk bitmap -- see ext4_mb_release_context() | 3328 | * in on-disk bitmap -- see ext4_mb_release_context() |
| 3325 | * Other CPUs are prevented from allocating from this pa by lg_mutex | 3329 | * Other CPUs are prevented from allocating from this pa by lg_mutex |
| 3326 | */ | 3330 | */ |
| 3327 | mb_debug("use %u/%u from group pa %p\n", pa->pa_lstart-len, len, pa); | 3331 | mb_debug(1, "use %u/%u from group pa %p\n", pa->pa_lstart-len, len, pa); |
| 3328 | } | 3332 | } |
| 3329 | 3333 | ||
| 3330 | /* | 3334 | /* |
| @@ -3382,6 +3386,11 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac) | |||
| 3382 | ac->ac_o_ex.fe_logical >= pa->pa_lstart + pa->pa_len) | 3386 | ac->ac_o_ex.fe_logical >= pa->pa_lstart + pa->pa_len) |
| 3383 | continue; | 3387 | continue; |
| 3384 | 3388 | ||
| 3389 | /* non-extent files can't have physical blocks past 2^32 */ | ||
| 3390 | if (!(EXT4_I(ac->ac_inode)->i_flags & EXT4_EXTENTS_FL) && | ||
| 3391 | pa->pa_pstart + pa->pa_len > EXT4_MAX_BLOCK_FILE_PHYS) | ||
| 3392 | continue; | ||
| 3393 | |||
| 3385 | /* found preallocated blocks, use them */ | 3394 | /* found preallocated blocks, use them */ |
| 3386 | spin_lock(&pa->pa_lock); | 3395 | spin_lock(&pa->pa_lock); |
| 3387 | if (pa->pa_deleted == 0 && pa->pa_free) { | 3396 | if (pa->pa_deleted == 0 && pa->pa_free) { |
| @@ -3503,7 +3512,7 @@ void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, | |||
| 3503 | preallocated += len; | 3512 | preallocated += len; |
| 3504 | count++; | 3513 | count++; |
| 3505 | } | 3514 | } |
| 3506 | mb_debug("prellocated %u for group %u\n", preallocated, group); | 3515 | mb_debug(1, "prellocated %u for group %u\n", preallocated, group); |
| 3507 | } | 3516 | } |
| 3508 | 3517 | ||
| 3509 | static void ext4_mb_pa_callback(struct rcu_head *head) | 3518 | static void ext4_mb_pa_callback(struct rcu_head *head) |
| @@ -3638,7 +3647,7 @@ ext4_mb_new_inode_pa(struct ext4_allocation_context *ac) | |||
| 3638 | pa->pa_deleted = 0; | 3647 | pa->pa_deleted = 0; |
| 3639 | pa->pa_type = MB_INODE_PA; | 3648 | pa->pa_type = MB_INODE_PA; |
| 3640 | 3649 | ||
| 3641 | mb_debug("new inode pa %p: %llu/%u for %u\n", pa, | 3650 | mb_debug(1, "new inode pa %p: %llu/%u for %u\n", pa, |
| 3642 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); | 3651 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); |
| 3643 | trace_ext4_mb_new_inode_pa(ac, pa); | 3652 | trace_ext4_mb_new_inode_pa(ac, pa); |
| 3644 | 3653 | ||
| @@ -3698,7 +3707,7 @@ ext4_mb_new_group_pa(struct ext4_allocation_context *ac) | |||
| 3698 | pa->pa_deleted = 0; | 3707 | pa->pa_deleted = 0; |
| 3699 | pa->pa_type = MB_GROUP_PA; | 3708 | pa->pa_type = MB_GROUP_PA; |
| 3700 | 3709 | ||
| 3701 | mb_debug("new group pa %p: %llu/%u for %u\n", pa, | 3710 | mb_debug(1, "new group pa %p: %llu/%u for %u\n", pa, |
| 3702 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); | 3711 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); |
| 3703 | trace_ext4_mb_new_group_pa(ac, pa); | 3712 | trace_ext4_mb_new_group_pa(ac, pa); |
| 3704 | 3713 | ||
| @@ -3777,7 +3786,7 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh, | |||
| 3777 | next = mb_find_next_bit(bitmap_bh->b_data, end, bit); | 3786 | next = mb_find_next_bit(bitmap_bh->b_data, end, bit); |
| 3778 | start = group * EXT4_BLOCKS_PER_GROUP(sb) + bit + | 3787 | start = group * EXT4_BLOCKS_PER_GROUP(sb) + bit + |
| 3779 | le32_to_cpu(sbi->s_es->s_first_data_block); | 3788 | le32_to_cpu(sbi->s_es->s_first_data_block); |
| 3780 | mb_debug(" free preallocated %u/%u in group %u\n", | 3789 | mb_debug(1, " free preallocated %u/%u in group %u\n", |
| 3781 | (unsigned) start, (unsigned) next - bit, | 3790 | (unsigned) start, (unsigned) next - bit, |
| 3782 | (unsigned) group); | 3791 | (unsigned) group); |
| 3783 | free += next - bit; | 3792 | free += next - bit; |
| @@ -3868,7 +3877,7 @@ ext4_mb_discard_group_preallocations(struct super_block *sb, | |||
| 3868 | int busy = 0; | 3877 | int busy = 0; |
| 3869 | int free = 0; | 3878 | int free = 0; |
| 3870 | 3879 | ||
| 3871 | mb_debug("discard preallocation for group %u\n", group); | 3880 | mb_debug(1, "discard preallocation for group %u\n", group); |
| 3872 | 3881 | ||
| 3873 | if (list_empty(&grp->bb_prealloc_list)) | 3882 | if (list_empty(&grp->bb_prealloc_list)) |
| 3874 | return 0; | 3883 | return 0; |
| @@ -3992,7 +4001,7 @@ void ext4_discard_preallocations(struct inode *inode) | |||
| 3992 | return; | 4001 | return; |
| 3993 | } | 4002 | } |
| 3994 | 4003 | ||
| 3995 | mb_debug("discard preallocation for inode %lu\n", inode->i_ino); | 4004 | mb_debug(1, "discard preallocation for inode %lu\n", inode->i_ino); |
| 3996 | trace_ext4_discard_preallocations(inode); | 4005 | trace_ext4_discard_preallocations(inode); |
| 3997 | 4006 | ||
| 3998 | INIT_LIST_HEAD(&list); | 4007 | INIT_LIST_HEAD(&list); |
| @@ -4097,7 +4106,7 @@ static void ext4_mb_return_to_preallocation(struct inode *inode, | |||
| 4097 | { | 4106 | { |
| 4098 | BUG_ON(!list_empty(&EXT4_I(inode)->i_prealloc_list)); | 4107 | BUG_ON(!list_empty(&EXT4_I(inode)->i_prealloc_list)); |
| 4099 | } | 4108 | } |
| 4100 | #ifdef MB_DEBUG | 4109 | #ifdef CONFIG_EXT4_DEBUG |
| 4101 | static void ext4_mb_show_ac(struct ext4_allocation_context *ac) | 4110 | static void ext4_mb_show_ac(struct ext4_allocation_context *ac) |
| 4102 | { | 4111 | { |
| 4103 | struct super_block *sb = ac->ac_sb; | 4112 | struct super_block *sb = ac->ac_sb; |
| @@ -4139,14 +4148,14 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac) | |||
| 4139 | ext4_get_group_no_and_offset(sb, pa->pa_pstart, | 4148 | ext4_get_group_no_and_offset(sb, pa->pa_pstart, |
| 4140 | NULL, &start); | 4149 | NULL, &start); |
| 4141 | spin_unlock(&pa->pa_lock); | 4150 | spin_unlock(&pa->pa_lock); |
| 4142 | printk(KERN_ERR "PA:%lu:%d:%u \n", i, | 4151 | printk(KERN_ERR "PA:%u:%d:%u \n", i, |
| 4143 | start, pa->pa_len); | 4152 | start, pa->pa_len); |
| 4144 | } | 4153 | } |
| 4145 | ext4_unlock_group(sb, i); | 4154 | ext4_unlock_group(sb, i); |
| 4146 | 4155 | ||
| 4147 | if (grp->bb_free == 0) | 4156 | if (grp->bb_free == 0) |
| 4148 | continue; | 4157 | continue; |
| 4149 | printk(KERN_ERR "%lu: %d/%d \n", | 4158 | printk(KERN_ERR "%u: %d/%d \n", |
| 4150 | i, grp->bb_free, grp->bb_fragments); | 4159 | i, grp->bb_free, grp->bb_fragments); |
| 4151 | } | 4160 | } |
| 4152 | printk(KERN_ERR "\n"); | 4161 | printk(KERN_ERR "\n"); |
| @@ -4174,16 +4183,26 @@ static void ext4_mb_group_or_file(struct ext4_allocation_context *ac) | |||
| 4174 | if (!(ac->ac_flags & EXT4_MB_HINT_DATA)) | 4183 | if (!(ac->ac_flags & EXT4_MB_HINT_DATA)) |
| 4175 | return; | 4184 | return; |
| 4176 | 4185 | ||
| 4186 | if (unlikely(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY)) | ||
| 4187 | return; | ||
| 4188 | |||
| 4177 | size = ac->ac_o_ex.fe_logical + ac->ac_o_ex.fe_len; | 4189 | size = ac->ac_o_ex.fe_logical + ac->ac_o_ex.fe_len; |
| 4178 | isize = i_size_read(ac->ac_inode) >> bsbits; | 4190 | isize = (i_size_read(ac->ac_inode) + ac->ac_sb->s_blocksize - 1) |
| 4191 | >> bsbits; | ||
| 4179 | size = max(size, isize); | 4192 | size = max(size, isize); |
| 4180 | 4193 | ||
| 4181 | /* don't use group allocation for large files */ | 4194 | if ((size == isize) && |
| 4182 | if (size >= sbi->s_mb_stream_request) | 4195 | !ext4_fs_is_busy(sbi) && |
| 4196 | (atomic_read(&ac->ac_inode->i_writecount) == 0)) { | ||
| 4197 | ac->ac_flags |= EXT4_MB_HINT_NOPREALLOC; | ||
| 4183 | return; | 4198 | return; |
| 4199 | } | ||
| 4184 | 4200 | ||
| 4185 | if (unlikely(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY)) | 4201 | /* don't use group allocation for large files */ |
| 4202 | if (size >= sbi->s_mb_stream_request) { | ||
| 4203 | ac->ac_flags |= EXT4_MB_STREAM_ALLOC; | ||
| 4186 | return; | 4204 | return; |
| 4205 | } | ||
| 4187 | 4206 | ||
| 4188 | BUG_ON(ac->ac_lg != NULL); | 4207 | BUG_ON(ac->ac_lg != NULL); |
| 4189 | /* | 4208 | /* |
| @@ -4246,7 +4265,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac, | |||
| 4246 | * locality group. this is a policy, actually */ | 4265 | * locality group. this is a policy, actually */ |
| 4247 | ext4_mb_group_or_file(ac); | 4266 | ext4_mb_group_or_file(ac); |
| 4248 | 4267 | ||
| 4249 | mb_debug("init ac: %u blocks @ %u, goal %u, flags %x, 2^%d, " | 4268 | mb_debug(1, "init ac: %u blocks @ %u, goal %u, flags %x, 2^%d, " |
| 4250 | "left: %u/%u, right %u/%u to %swritable\n", | 4269 | "left: %u/%u, right %u/%u to %swritable\n", |
| 4251 | (unsigned) ar->len, (unsigned) ar->logical, | 4270 | (unsigned) ar->len, (unsigned) ar->logical, |
| 4252 | (unsigned) ar->goal, ac->ac_flags, ac->ac_2order, | 4271 | (unsigned) ar->goal, ac->ac_flags, ac->ac_2order, |
| @@ -4268,7 +4287,7 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb, | |||
| 4268 | struct ext4_prealloc_space *pa, *tmp; | 4287 | struct ext4_prealloc_space *pa, *tmp; |
| 4269 | struct ext4_allocation_context *ac; | 4288 | struct ext4_allocation_context *ac; |
| 4270 | 4289 | ||
| 4271 | mb_debug("discard locality group preallocation\n"); | 4290 | mb_debug(1, "discard locality group preallocation\n"); |
| 4272 | 4291 | ||
| 4273 | INIT_LIST_HEAD(&discard_list); | 4292 | INIT_LIST_HEAD(&discard_list); |
| 4274 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 4293 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h index c96bb19f58f..188d3d709b2 100644 --- a/fs/ext4/mballoc.h +++ b/fs/ext4/mballoc.h | |||
| @@ -37,11 +37,19 @@ | |||
| 37 | 37 | ||
| 38 | /* | 38 | /* |
| 39 | */ | 39 | */ |
| 40 | #define MB_DEBUG__ | 40 | #ifdef CONFIG_EXT4_DEBUG |
| 41 | #ifdef MB_DEBUG | 41 | extern u8 mb_enable_debug; |
| 42 | #define mb_debug(fmt, a...) printk(fmt, ##a) | 42 | |
| 43 | #define mb_debug(n, fmt, a...) \ | ||
| 44 | do { \ | ||
| 45 | if ((n) <= mb_enable_debug) { \ | ||
| 46 | printk(KERN_DEBUG "(%s, %d): %s: ", \ | ||
| 47 | __FILE__, __LINE__, __func__); \ | ||
| 48 | printk(fmt, ## a); \ | ||
| 49 | } \ | ||
| 50 | } while (0) | ||
| 43 | #else | 51 | #else |
| 44 | #define mb_debug(fmt, a...) | 52 | #define mb_debug(n, fmt, a...) |
| 45 | #endif | 53 | #endif |
| 46 | 54 | ||
| 47 | /* | 55 | /* |
| @@ -128,8 +136,8 @@ struct ext4_prealloc_space { | |||
| 128 | unsigned pa_deleted; | 136 | unsigned pa_deleted; |
| 129 | ext4_fsblk_t pa_pstart; /* phys. block */ | 137 | ext4_fsblk_t pa_pstart; /* phys. block */ |
| 130 | ext4_lblk_t pa_lstart; /* log. block */ | 138 | ext4_lblk_t pa_lstart; /* log. block */ |
| 131 | unsigned short pa_len; /* len of preallocated chunk */ | 139 | ext4_grpblk_t pa_len; /* len of preallocated chunk */ |
| 132 | unsigned short pa_free; /* how many blocks are free */ | 140 | ext4_grpblk_t pa_free; /* how many blocks are free */ |
| 133 | unsigned short pa_type; /* pa type. inode or group */ | 141 | unsigned short pa_type; /* pa type. inode or group */ |
| 134 | spinlock_t *pa_obj_lock; | 142 | spinlock_t *pa_obj_lock; |
| 135 | struct inode *pa_inode; /* hack, for history only */ | 143 | struct inode *pa_inode; /* hack, for history only */ |
| @@ -144,7 +152,7 @@ struct ext4_free_extent { | |||
| 144 | ext4_lblk_t fe_logical; | 152 | ext4_lblk_t fe_logical; |
| 145 | ext4_grpblk_t fe_start; | 153 | ext4_grpblk_t fe_start; |
| 146 | ext4_group_t fe_group; | 154 | ext4_group_t fe_group; |
| 147 | int fe_len; | 155 | ext4_grpblk_t fe_len; |
| 148 | }; | 156 | }; |
| 149 | 157 | ||
| 150 | /* | 158 | /* |
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index 313a50b3974..bf519f239ae 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c | |||
| @@ -353,17 +353,16 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode, | |||
| 353 | 353 | ||
| 354 | down_write(&EXT4_I(inode)->i_data_sem); | 354 | down_write(&EXT4_I(inode)->i_data_sem); |
| 355 | /* | 355 | /* |
| 356 | * if EXT4_EXT_MIGRATE is cleared a block allocation | 356 | * if EXT4_STATE_EXT_MIGRATE is cleared a block allocation |
| 357 | * happened after we started the migrate. We need to | 357 | * happened after we started the migrate. We need to |
| 358 | * fail the migrate | 358 | * fail the migrate |
| 359 | */ | 359 | */ |
| 360 | if (!(EXT4_I(inode)->i_flags & EXT4_EXT_MIGRATE)) { | 360 | if (!(EXT4_I(inode)->i_state & EXT4_STATE_EXT_MIGRATE)) { |
| 361 | retval = -EAGAIN; | 361 | retval = -EAGAIN; |
| 362 | up_write(&EXT4_I(inode)->i_data_sem); | 362 | up_write(&EXT4_I(inode)->i_data_sem); |
| 363 | goto err_out; | 363 | goto err_out; |
| 364 | } else | 364 | } else |
| 365 | EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags & | 365 | EXT4_I(inode)->i_state &= ~EXT4_STATE_EXT_MIGRATE; |
| 366 | ~EXT4_EXT_MIGRATE; | ||
| 367 | /* | 366 | /* |
| 368 | * We have the extent map build with the tmp inode. | 367 | * We have the extent map build with the tmp inode. |
| 369 | * Now copy the i_data across | 368 | * Now copy the i_data across |
| @@ -517,14 +516,15 @@ int ext4_ext_migrate(struct inode *inode) | |||
| 517 | * when we add extents we extent the journal | 516 | * when we add extents we extent the journal |
| 518 | */ | 517 | */ |
| 519 | /* | 518 | /* |
| 520 | * Even though we take i_mutex we can still cause block allocation | 519 | * Even though we take i_mutex we can still cause block |
| 521 | * via mmap write to holes. If we have allocated new blocks we fail | 520 | * allocation via mmap write to holes. If we have allocated |
| 522 | * migrate. New block allocation will clear EXT4_EXT_MIGRATE flag. | 521 | * new blocks we fail migrate. New block allocation will |
| 523 | * The flag is updated with i_data_sem held to prevent racing with | 522 | * clear EXT4_STATE_EXT_MIGRATE flag. The flag is updated |
| 524 | * block allocation. | 523 | * with i_data_sem held to prevent racing with block |
| 524 | * allocation. | ||
| 525 | */ | 525 | */ |
| 526 | down_read((&EXT4_I(inode)->i_data_sem)); | 526 | down_read((&EXT4_I(inode)->i_data_sem)); |
| 527 | EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags | EXT4_EXT_MIGRATE; | 527 | EXT4_I(inode)->i_state |= EXT4_STATE_EXT_MIGRATE; |
| 528 | up_read((&EXT4_I(inode)->i_data_sem)); | 528 | up_read((&EXT4_I(inode)->i_data_sem)); |
| 529 | 529 | ||
| 530 | handle = ext4_journal_start(inode, 1); | 530 | handle = ext4_journal_start(inode, 1); |
| @@ -618,7 +618,7 @@ err_out: | |||
| 618 | tmp_inode->i_nlink = 0; | 618 | tmp_inode->i_nlink = 0; |
| 619 | 619 | ||
| 620 | ext4_journal_stop(handle); | 620 | ext4_journal_stop(handle); |
| 621 | 621 | unlock_new_inode(tmp_inode); | |
| 622 | iput(tmp_inode); | 622 | iput(tmp_inode); |
| 623 | 623 | ||
| 624 | return retval; | 624 | return retval; |
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index bbf2dd9404d..c07a2915e40 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c | |||
| @@ -19,14 +19,31 @@ | |||
| 19 | #include "ext4_extents.h" | 19 | #include "ext4_extents.h" |
| 20 | #include "ext4.h" | 20 | #include "ext4.h" |
| 21 | 21 | ||
| 22 | #define get_ext_path(path, inode, block, ret) \ | 22 | /** |
| 23 | do { \ | 23 | * get_ext_path - Find an extent path for designated logical block number. |
| 24 | path = ext4_ext_find_extent(inode, block, path); \ | 24 | * |
| 25 | if (IS_ERR(path)) { \ | 25 | * @inode: an inode which is searched |
| 26 | ret = PTR_ERR(path); \ | 26 | * @lblock: logical block number to find an extent path |
| 27 | path = NULL; \ | 27 | * @path: pointer to an extent path pointer (for output) |
| 28 | } \ | 28 | * |
| 29 | } while (0) | 29 | * ext4_ext_find_extent wrapper. Return 0 on success, or a negative error value |
| 30 | * on failure. | ||
| 31 | */ | ||
| 32 | static inline int | ||
| 33 | get_ext_path(struct inode *inode, ext4_lblk_t lblock, | ||
| 34 | struct ext4_ext_path **path) | ||
| 35 | { | ||
| 36 | int ret = 0; | ||
| 37 | |||
| 38 | *path = ext4_ext_find_extent(inode, lblock, *path); | ||
| 39 | if (IS_ERR(*path)) { | ||
| 40 | ret = PTR_ERR(*path); | ||
| 41 | *path = NULL; | ||
| 42 | } else if ((*path)[ext_depth(inode)].p_ext == NULL) | ||
| 43 | ret = -ENODATA; | ||
| 44 | |||
| 45 | return ret; | ||
| 46 | } | ||
| 30 | 47 | ||
| 31 | /** | 48 | /** |
| 32 | * copy_extent_status - Copy the extent's initialization status | 49 | * copy_extent_status - Copy the extent's initialization status |
| @@ -113,6 +130,31 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path, | |||
| 113 | } | 130 | } |
| 114 | 131 | ||
| 115 | /** | 132 | /** |
| 133 | * mext_check_null_inode - NULL check for two inodes | ||
| 134 | * | ||
| 135 | * If inode1 or inode2 is NULL, return -EIO. Otherwise, return 0. | ||
| 136 | */ | ||
| 137 | static int | ||
| 138 | mext_check_null_inode(struct inode *inode1, struct inode *inode2, | ||
| 139 | const char *function) | ||
| 140 | { | ||
| 141 | int ret = 0; | ||
| 142 | |||
| 143 | if (inode1 == NULL) { | ||
| 144 | ext4_error(inode2->i_sb, function, | ||
| 145 | "Both inodes should not be NULL: " | ||
| 146 | "inode1 NULL inode2 %lu", inode2->i_ino); | ||
| 147 | ret = -EIO; | ||
| 148 | } else if (inode2 == NULL) { | ||
| 149 | ext4_error(inode1->i_sb, function, | ||
| 150 | "Both inodes should not be NULL: " | ||
| 151 | "inode1 %lu inode2 NULL", inode1->i_ino); | ||
| 152 | ret = -EIO; | ||
| 153 | } | ||
| 154 | return ret; | ||
| 155 | } | ||
| 156 | |||
| 157 | /** | ||
| 116 | * mext_double_down_read - Acquire two inodes' read semaphore | 158 | * mext_double_down_read - Acquire two inodes' read semaphore |
| 117 | * | 159 | * |
| 118 | * @orig_inode: original inode structure | 160 | * @orig_inode: original inode structure |
| @@ -124,8 +166,6 @@ mext_double_down_read(struct inode *orig_inode, struct inode *donor_inode) | |||
| 124 | { | 166 | { |
| 125 | struct inode *first = orig_inode, *second = donor_inode; | 167 | struct inode *first = orig_inode, *second = donor_inode; |
| 126 | 168 | ||
| 127 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
| 128 | |||
| 129 | /* | 169 | /* |
| 130 | * Use the inode number to provide the stable locking order instead | 170 | * Use the inode number to provide the stable locking order instead |
| 131 | * of its address, because the C language doesn't guarantee you can | 171 | * of its address, because the C language doesn't guarantee you can |
| @@ -152,8 +192,6 @@ mext_double_down_write(struct inode *orig_inode, struct inode *donor_inode) | |||
| 152 | { | 192 | { |
| 153 | struct inode *first = orig_inode, *second = donor_inode; | 193 | struct inode *first = orig_inode, *second = donor_inode; |
| 154 | 194 | ||
| 155 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
| 156 | |||
| 157 | /* | 195 | /* |
| 158 | * Use the inode number to provide the stable locking order instead | 196 | * Use the inode number to provide the stable locking order instead |
| 159 | * of its address, because the C language doesn't guarantee you can | 197 | * of its address, because the C language doesn't guarantee you can |
| @@ -178,8 +216,6 @@ mext_double_down_write(struct inode *orig_inode, struct inode *donor_inode) | |||
| 178 | static void | 216 | static void |
| 179 | mext_double_up_read(struct inode *orig_inode, struct inode *donor_inode) | 217 | mext_double_up_read(struct inode *orig_inode, struct inode *donor_inode) |
| 180 | { | 218 | { |
| 181 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
| 182 | |||
| 183 | up_read(&EXT4_I(orig_inode)->i_data_sem); | 219 | up_read(&EXT4_I(orig_inode)->i_data_sem); |
| 184 | up_read(&EXT4_I(donor_inode)->i_data_sem); | 220 | up_read(&EXT4_I(donor_inode)->i_data_sem); |
| 185 | } | 221 | } |
| @@ -194,8 +230,6 @@ mext_double_up_read(struct inode *orig_inode, struct inode *donor_inode) | |||
| 194 | static void | 230 | static void |
| 195 | mext_double_up_write(struct inode *orig_inode, struct inode *donor_inode) | 231 | mext_double_up_write(struct inode *orig_inode, struct inode *donor_inode) |
| 196 | { | 232 | { |
| 197 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
| 198 | |||
| 199 | up_write(&EXT4_I(orig_inode)->i_data_sem); | 233 | up_write(&EXT4_I(orig_inode)->i_data_sem); |
| 200 | up_write(&EXT4_I(donor_inode)->i_data_sem); | 234 | up_write(&EXT4_I(donor_inode)->i_data_sem); |
| 201 | } | 235 | } |
| @@ -283,8 +317,8 @@ mext_insert_across_blocks(handle_t *handle, struct inode *orig_inode, | |||
| 283 | } | 317 | } |
| 284 | 318 | ||
| 285 | if (new_flag) { | 319 | if (new_flag) { |
| 286 | get_ext_path(orig_path, orig_inode, eblock, err); | 320 | err = get_ext_path(orig_inode, eblock, &orig_path); |
| 287 | if (orig_path == NULL) | 321 | if (err) |
| 288 | goto out; | 322 | goto out; |
| 289 | 323 | ||
| 290 | if (ext4_ext_insert_extent(handle, orig_inode, | 324 | if (ext4_ext_insert_extent(handle, orig_inode, |
| @@ -293,9 +327,9 @@ mext_insert_across_blocks(handle_t *handle, struct inode *orig_inode, | |||
| 293 | } | 327 | } |
| 294 | 328 | ||
| 295 | if (end_flag) { | 329 | if (end_flag) { |
| 296 | get_ext_path(orig_path, orig_inode, | 330 | err = get_ext_path(orig_inode, |
| 297 | le32_to_cpu(end_ext->ee_block) - 1, err); | 331 | le32_to_cpu(end_ext->ee_block) - 1, &orig_path); |
| 298 | if (orig_path == NULL) | 332 | if (err) |
| 299 | goto out; | 333 | goto out; |
| 300 | 334 | ||
| 301 | if (ext4_ext_insert_extent(handle, orig_inode, | 335 | if (ext4_ext_insert_extent(handle, orig_inode, |
| @@ -519,7 +553,15 @@ mext_leaf_block(handle_t *handle, struct inode *orig_inode, | |||
| 519 | * oext |-----------| | 553 | * oext |-----------| |
| 520 | * new_ext |-------| | 554 | * new_ext |-------| |
| 521 | */ | 555 | */ |
| 522 | BUG_ON(le32_to_cpu(oext->ee_block) + oext_alen - 1 < new_ext_end); | 556 | if (le32_to_cpu(oext->ee_block) + oext_alen - 1 < new_ext_end) { |
| 557 | ext4_error(orig_inode->i_sb, __func__, | ||
| 558 | "new_ext_end(%u) should be less than or equal to " | ||
| 559 | "oext->ee_block(%u) + oext_alen(%d) - 1", | ||
| 560 | new_ext_end, le32_to_cpu(oext->ee_block), | ||
| 561 | oext_alen); | ||
| 562 | ret = -EIO; | ||
| 563 | goto out; | ||
| 564 | } | ||
| 523 | 565 | ||
| 524 | /* | 566 | /* |
| 525 | * Case: new_ext is smaller than original extent | 567 | * Case: new_ext is smaller than original extent |
| @@ -543,6 +585,7 @@ mext_leaf_block(handle_t *handle, struct inode *orig_inode, | |||
| 543 | 585 | ||
| 544 | ret = mext_insert_extents(handle, orig_inode, orig_path, o_start, | 586 | ret = mext_insert_extents(handle, orig_inode, orig_path, o_start, |
| 545 | o_end, &start_ext, &new_ext, &end_ext); | 587 | o_end, &start_ext, &new_ext, &end_ext); |
| 588 | out: | ||
| 546 | return ret; | 589 | return ret; |
| 547 | } | 590 | } |
| 548 | 591 | ||
| @@ -554,8 +597,10 @@ mext_leaf_block(handle_t *handle, struct inode *orig_inode, | |||
| 554 | * @orig_off: block offset of original inode | 597 | * @orig_off: block offset of original inode |
| 555 | * @donor_off: block offset of donor inode | 598 | * @donor_off: block offset of donor inode |
| 556 | * @max_count: the maximun length of extents | 599 | * @max_count: the maximun length of extents |
| 600 | * | ||
| 601 | * Return 0 on success, or a negative error value on failure. | ||
| 557 | */ | 602 | */ |
| 558 | static void | 603 | static int |
| 559 | mext_calc_swap_extents(struct ext4_extent *tmp_dext, | 604 | mext_calc_swap_extents(struct ext4_extent *tmp_dext, |
| 560 | struct ext4_extent *tmp_oext, | 605 | struct ext4_extent *tmp_oext, |
| 561 | ext4_lblk_t orig_off, ext4_lblk_t donor_off, | 606 | ext4_lblk_t orig_off, ext4_lblk_t donor_off, |
| @@ -564,6 +609,19 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext, | |||
| 564 | ext4_lblk_t diff, orig_diff; | 609 | ext4_lblk_t diff, orig_diff; |
| 565 | struct ext4_extent dext_old, oext_old; | 610 | struct ext4_extent dext_old, oext_old; |
| 566 | 611 | ||
| 612 | BUG_ON(orig_off != donor_off); | ||
| 613 | |||
| 614 | /* original and donor extents have to cover the same block offset */ | ||
| 615 | if (orig_off < le32_to_cpu(tmp_oext->ee_block) || | ||
| 616 | le32_to_cpu(tmp_oext->ee_block) + | ||
| 617 | ext4_ext_get_actual_len(tmp_oext) - 1 < orig_off) | ||
| 618 | return -ENODATA; | ||
| 619 | |||
| 620 | if (orig_off < le32_to_cpu(tmp_dext->ee_block) || | ||
| 621 | le32_to_cpu(tmp_dext->ee_block) + | ||
| 622 | ext4_ext_get_actual_len(tmp_dext) - 1 < orig_off) | ||
| 623 | return -ENODATA; | ||
| 624 | |||
| 567 | dext_old = *tmp_dext; | 625 | dext_old = *tmp_dext; |
| 568 | oext_old = *tmp_oext; | 626 | oext_old = *tmp_oext; |
| 569 | 627 | ||
| @@ -591,6 +649,8 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext, | |||
| 591 | 649 | ||
| 592 | copy_extent_status(&oext_old, tmp_dext); | 650 | copy_extent_status(&oext_old, tmp_dext); |
| 593 | copy_extent_status(&dext_old, tmp_oext); | 651 | copy_extent_status(&dext_old, tmp_oext); |
| 652 | |||
| 653 | return 0; | ||
| 594 | } | 654 | } |
| 595 | 655 | ||
| 596 | /** | 656 | /** |
| @@ -631,13 +691,13 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
| 631 | mext_double_down_write(orig_inode, donor_inode); | 691 | mext_double_down_write(orig_inode, donor_inode); |
| 632 | 692 | ||
| 633 | /* Get the original extent for the block "orig_off" */ | 693 | /* Get the original extent for the block "orig_off" */ |
| 634 | get_ext_path(orig_path, orig_inode, orig_off, err); | 694 | err = get_ext_path(orig_inode, orig_off, &orig_path); |
| 635 | if (orig_path == NULL) | 695 | if (err) |
| 636 | goto out; | 696 | goto out; |
| 637 | 697 | ||
| 638 | /* Get the donor extent for the head */ | 698 | /* Get the donor extent for the head */ |
| 639 | get_ext_path(donor_path, donor_inode, donor_off, err); | 699 | err = get_ext_path(donor_inode, donor_off, &donor_path); |
| 640 | if (donor_path == NULL) | 700 | if (err) |
| 641 | goto out; | 701 | goto out; |
| 642 | depth = ext_depth(orig_inode); | 702 | depth = ext_depth(orig_inode); |
| 643 | oext = orig_path[depth].p_ext; | 703 | oext = orig_path[depth].p_ext; |
| @@ -647,13 +707,28 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
| 647 | dext = donor_path[depth].p_ext; | 707 | dext = donor_path[depth].p_ext; |
| 648 | tmp_dext = *dext; | 708 | tmp_dext = *dext; |
| 649 | 709 | ||
| 650 | mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, | 710 | err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, |
| 651 | donor_off, count); | 711 | donor_off, count); |
| 712 | if (err) | ||
| 713 | goto out; | ||
| 652 | 714 | ||
| 653 | /* Loop for the donor extents */ | 715 | /* Loop for the donor extents */ |
| 654 | while (1) { | 716 | while (1) { |
| 655 | /* The extent for donor must be found. */ | 717 | /* The extent for donor must be found. */ |
| 656 | BUG_ON(!dext || donor_off != le32_to_cpu(tmp_dext.ee_block)); | 718 | if (!dext) { |
| 719 | ext4_error(donor_inode->i_sb, __func__, | ||
| 720 | "The extent for donor must be found"); | ||
| 721 | err = -EIO; | ||
| 722 | goto out; | ||
| 723 | } else if (donor_off != le32_to_cpu(tmp_dext.ee_block)) { | ||
| 724 | ext4_error(donor_inode->i_sb, __func__, | ||
| 725 | "Donor offset(%u) and the first block of donor " | ||
| 726 | "extent(%u) should be equal", | ||
| 727 | donor_off, | ||
| 728 | le32_to_cpu(tmp_dext.ee_block)); | ||
| 729 | err = -EIO; | ||
| 730 | goto out; | ||
| 731 | } | ||
| 657 | 732 | ||
| 658 | /* Set donor extent to orig extent */ | 733 | /* Set donor extent to orig extent */ |
| 659 | err = mext_leaf_block(handle, orig_inode, | 734 | err = mext_leaf_block(handle, orig_inode, |
| @@ -678,8 +753,8 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
| 678 | 753 | ||
| 679 | if (orig_path) | 754 | if (orig_path) |
| 680 | ext4_ext_drop_refs(orig_path); | 755 | ext4_ext_drop_refs(orig_path); |
| 681 | get_ext_path(orig_path, orig_inode, orig_off, err); | 756 | err = get_ext_path(orig_inode, orig_off, &orig_path); |
| 682 | if (orig_path == NULL) | 757 | if (err) |
| 683 | goto out; | 758 | goto out; |
| 684 | depth = ext_depth(orig_inode); | 759 | depth = ext_depth(orig_inode); |
| 685 | oext = orig_path[depth].p_ext; | 760 | oext = orig_path[depth].p_ext; |
| @@ -692,9 +767,8 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
| 692 | 767 | ||
| 693 | if (donor_path) | 768 | if (donor_path) |
| 694 | ext4_ext_drop_refs(donor_path); | 769 | ext4_ext_drop_refs(donor_path); |
| 695 | get_ext_path(donor_path, donor_inode, | 770 | err = get_ext_path(donor_inode, donor_off, &donor_path); |
| 696 | donor_off, err); | 771 | if (err) |
| 697 | if (donor_path == NULL) | ||
| 698 | goto out; | 772 | goto out; |
| 699 | depth = ext_depth(donor_inode); | 773 | depth = ext_depth(donor_inode); |
| 700 | dext = donor_path[depth].p_ext; | 774 | dext = donor_path[depth].p_ext; |
| @@ -705,9 +779,10 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, | |||
| 705 | } | 779 | } |
| 706 | tmp_dext = *dext; | 780 | tmp_dext = *dext; |
| 707 | 781 | ||
| 708 | mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, | 782 | err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, |
| 709 | donor_off, | 783 | donor_off, count - replaced_count); |
| 710 | count - replaced_count); | 784 | if (err) |
| 785 | goto out; | ||
| 711 | } | 786 | } |
| 712 | 787 | ||
| 713 | out: | 788 | out: |
| @@ -740,7 +815,7 @@ out: | |||
| 740 | * on success, or a negative error value on failure. | 815 | * on success, or a negative error value on failure. |
| 741 | */ | 816 | */ |
| 742 | static int | 817 | static int |
| 743 | move_extent_par_page(struct file *o_filp, struct inode *donor_inode, | 818 | move_extent_per_page(struct file *o_filp, struct inode *donor_inode, |
| 744 | pgoff_t orig_page_offset, int data_offset_in_page, | 819 | pgoff_t orig_page_offset, int data_offset_in_page, |
| 745 | int block_len_in_page, int uninit) | 820 | int block_len_in_page, int uninit) |
| 746 | { | 821 | { |
| @@ -871,6 +946,7 @@ out: | |||
| 871 | if (PageLocked(page)) | 946 | if (PageLocked(page)) |
| 872 | unlock_page(page); | 947 | unlock_page(page); |
| 873 | page_cache_release(page); | 948 | page_cache_release(page); |
| 949 | ext4_journal_stop(handle); | ||
| 874 | } | 950 | } |
| 875 | out2: | 951 | out2: |
| 876 | ext4_journal_stop(handle); | 952 | ext4_journal_stop(handle); |
| @@ -897,6 +973,10 @@ mext_check_arguments(struct inode *orig_inode, | |||
| 897 | struct inode *donor_inode, __u64 orig_start, | 973 | struct inode *donor_inode, __u64 orig_start, |
| 898 | __u64 donor_start, __u64 *len, __u64 moved_len) | 974 | __u64 donor_start, __u64 *len, __u64 moved_len) |
| 899 | { | 975 | { |
| 976 | ext4_lblk_t orig_blocks, donor_blocks; | ||
| 977 | unsigned int blkbits = orig_inode->i_blkbits; | ||
| 978 | unsigned int blocksize = 1 << blkbits; | ||
| 979 | |||
| 900 | /* Regular file check */ | 980 | /* Regular file check */ |
| 901 | if (!S_ISREG(orig_inode->i_mode) || !S_ISREG(donor_inode->i_mode)) { | 981 | if (!S_ISREG(orig_inode->i_mode) || !S_ISREG(donor_inode->i_mode)) { |
| 902 | ext4_debug("ext4 move extent: The argument files should be " | 982 | ext4_debug("ext4 move extent: The argument files should be " |
| @@ -960,54 +1040,58 @@ mext_check_arguments(struct inode *orig_inode, | |||
| 960 | return -EINVAL; | 1040 | return -EINVAL; |
| 961 | } | 1041 | } |
| 962 | 1042 | ||
| 963 | if ((orig_start > MAX_DEFRAG_SIZE) || | 1043 | if ((orig_start > EXT_MAX_BLOCK) || |
| 964 | (donor_start > MAX_DEFRAG_SIZE) || | 1044 | (donor_start > EXT_MAX_BLOCK) || |
| 965 | (*len > MAX_DEFRAG_SIZE) || | 1045 | (*len > EXT_MAX_BLOCK) || |
| 966 | (orig_start + *len > MAX_DEFRAG_SIZE)) { | 1046 | (orig_start + *len > EXT_MAX_BLOCK)) { |
| 967 | ext4_debug("ext4 move extent: Can't handle over [%lu] blocks " | 1047 | ext4_debug("ext4 move extent: Can't handle over [%u] blocks " |
| 968 | "[ino:orig %lu, donor %lu]\n", MAX_DEFRAG_SIZE, | 1048 | "[ino:orig %lu, donor %lu]\n", EXT_MAX_BLOCK, |
| 969 | orig_inode->i_ino, donor_inode->i_ino); | 1049 | orig_inode->i_ino, donor_inode->i_ino); |
| 970 | return -EINVAL; | 1050 | return -EINVAL; |
| 971 | } | 1051 | } |
| 972 | 1052 | ||
| 973 | if (orig_inode->i_size > donor_inode->i_size) { | 1053 | if (orig_inode->i_size > donor_inode->i_size) { |
| 974 | if (orig_start >= donor_inode->i_size) { | 1054 | donor_blocks = (donor_inode->i_size + blocksize - 1) >> blkbits; |
| 1055 | /* TODO: eliminate this artificial restriction */ | ||
| 1056 | if (orig_start >= donor_blocks) { | ||
| 975 | ext4_debug("ext4 move extent: orig start offset " | 1057 | ext4_debug("ext4 move extent: orig start offset " |
| 976 | "[%llu] should be less than donor file size " | 1058 | "[%llu] should be less than donor file blocks " |
| 977 | "[%lld] [ino:orig %lu, donor_inode %lu]\n", | 1059 | "[%u] [ino:orig %lu, donor %lu]\n", |
| 978 | orig_start, donor_inode->i_size, | 1060 | orig_start, donor_blocks, |
| 979 | orig_inode->i_ino, donor_inode->i_ino); | 1061 | orig_inode->i_ino, donor_inode->i_ino); |
| 980 | return -EINVAL; | 1062 | return -EINVAL; |
| 981 | } | 1063 | } |
| 982 | 1064 | ||
| 983 | if (orig_start + *len > donor_inode->i_size) { | 1065 | /* TODO: eliminate this artificial restriction */ |
| 1066 | if (orig_start + *len > donor_blocks) { | ||
| 984 | ext4_debug("ext4 move extent: End offset [%llu] should " | 1067 | ext4_debug("ext4 move extent: End offset [%llu] should " |
| 985 | "be less than donor file size [%lld]." | 1068 | "be less than donor file blocks [%u]." |
| 986 | "So adjust length from %llu to %lld " | 1069 | "So adjust length from %llu to %llu " |
| 987 | "[ino:orig %lu, donor %lu]\n", | 1070 | "[ino:orig %lu, donor %lu]\n", |
| 988 | orig_start + *len, donor_inode->i_size, | 1071 | orig_start + *len, donor_blocks, |
| 989 | *len, donor_inode->i_size - orig_start, | 1072 | *len, donor_blocks - orig_start, |
| 990 | orig_inode->i_ino, donor_inode->i_ino); | 1073 | orig_inode->i_ino, donor_inode->i_ino); |
| 991 | *len = donor_inode->i_size - orig_start; | 1074 | *len = donor_blocks - orig_start; |
| 992 | } | 1075 | } |
| 993 | } else { | 1076 | } else { |
| 994 | if (orig_start >= orig_inode->i_size) { | 1077 | orig_blocks = (orig_inode->i_size + blocksize - 1) >> blkbits; |
| 1078 | if (orig_start >= orig_blocks) { | ||
| 995 | ext4_debug("ext4 move extent: start offset [%llu] " | 1079 | ext4_debug("ext4 move extent: start offset [%llu] " |
| 996 | "should be less than original file size " | 1080 | "should be less than original file blocks " |
| 997 | "[%lld] [inode:orig %lu, donor %lu]\n", | 1081 | "[%u] [ino:orig %lu, donor %lu]\n", |
| 998 | orig_start, orig_inode->i_size, | 1082 | orig_start, orig_blocks, |
| 999 | orig_inode->i_ino, donor_inode->i_ino); | 1083 | orig_inode->i_ino, donor_inode->i_ino); |
| 1000 | return -EINVAL; | 1084 | return -EINVAL; |
| 1001 | } | 1085 | } |
| 1002 | 1086 | ||
| 1003 | if (orig_start + *len > orig_inode->i_size) { | 1087 | if (orig_start + *len > orig_blocks) { |
| 1004 | ext4_debug("ext4 move extent: Adjust length " | 1088 | ext4_debug("ext4 move extent: Adjust length " |
| 1005 | "from %llu to %lld. Because it should be " | 1089 | "from %llu to %llu. Because it should be " |
| 1006 | "less than original file size " | 1090 | "less than original file blocks " |
| 1007 | "[ino:orig %lu, donor %lu]\n", | 1091 | "[ino:orig %lu, donor %lu]\n", |
| 1008 | *len, orig_inode->i_size - orig_start, | 1092 | *len, orig_blocks - orig_start, |
| 1009 | orig_inode->i_ino, donor_inode->i_ino); | 1093 | orig_inode->i_ino, donor_inode->i_ino); |
| 1010 | *len = orig_inode->i_size - orig_start; | 1094 | *len = orig_blocks - orig_start; |
| 1011 | } | 1095 | } |
| 1012 | } | 1096 | } |
| 1013 | 1097 | ||
| @@ -1027,18 +1111,23 @@ mext_check_arguments(struct inode *orig_inode, | |||
| 1027 | * @inode1: the inode structure | 1111 | * @inode1: the inode structure |
| 1028 | * @inode2: the inode structure | 1112 | * @inode2: the inode structure |
| 1029 | * | 1113 | * |
| 1030 | * Lock two inodes' i_mutex by i_ino order. This function is moved from | 1114 | * Lock two inodes' i_mutex by i_ino order. |
| 1031 | * fs/inode.c. | 1115 | * If inode1 or inode2 is NULL, return -EIO. Otherwise, return 0. |
| 1032 | */ | 1116 | */ |
| 1033 | static void | 1117 | static int |
| 1034 | mext_inode_double_lock(struct inode *inode1, struct inode *inode2) | 1118 | mext_inode_double_lock(struct inode *inode1, struct inode *inode2) |
| 1035 | { | 1119 | { |
| 1036 | if (inode1 == NULL || inode2 == NULL || inode1 == inode2) { | 1120 | int ret = 0; |
| 1037 | if (inode1) | 1121 | |
| 1038 | mutex_lock(&inode1->i_mutex); | 1122 | BUG_ON(inode1 == NULL && inode2 == NULL); |
| 1039 | else if (inode2) | 1123 | |
| 1040 | mutex_lock(&inode2->i_mutex); | 1124 | ret = mext_check_null_inode(inode1, inode2, __func__); |
| 1041 | return; | 1125 | if (ret < 0) |
| 1126 | goto out; | ||
| 1127 | |||
| 1128 | if (inode1 == inode2) { | ||
| 1129 | mutex_lock(&inode1->i_mutex); | ||
| 1130 | goto out; | ||
| 1042 | } | 1131 | } |
| 1043 | 1132 | ||
| 1044 | if (inode1->i_ino < inode2->i_ino) { | 1133 | if (inode1->i_ino < inode2->i_ino) { |
| @@ -1048,6 +1137,9 @@ mext_inode_double_lock(struct inode *inode1, struct inode *inode2) | |||
| 1048 | mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT); | 1137 | mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT); |
| 1049 | mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD); | 1138 | mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD); |
| 1050 | } | 1139 | } |
| 1140 | |||
| 1141 | out: | ||
| 1142 | return ret; | ||
| 1051 | } | 1143 | } |
| 1052 | 1144 | ||
| 1053 | /** | 1145 | /** |
| @@ -1056,17 +1148,28 @@ mext_inode_double_lock(struct inode *inode1, struct inode *inode2) | |||
| 1056 | * @inode1: the inode that is released first | 1148 | * @inode1: the inode that is released first |
| 1057 | * @inode2: the inode that is released second | 1149 | * @inode2: the inode that is released second |
| 1058 | * | 1150 | * |
| 1059 | * This function is moved from fs/inode.c. | 1151 | * If inode1 or inode2 is NULL, return -EIO. Otherwise, return 0. |
| 1060 | */ | 1152 | */ |
| 1061 | 1153 | ||
| 1062 | static void | 1154 | static int |
| 1063 | mext_inode_double_unlock(struct inode *inode1, struct inode *inode2) | 1155 | mext_inode_double_unlock(struct inode *inode1, struct inode *inode2) |
| 1064 | { | 1156 | { |
| 1157 | int ret = 0; | ||
| 1158 | |||
| 1159 | BUG_ON(inode1 == NULL && inode2 == NULL); | ||
| 1160 | |||
| 1161 | ret = mext_check_null_inode(inode1, inode2, __func__); | ||
| 1162 | if (ret < 0) | ||
| 1163 | goto out; | ||
| 1164 | |||
| 1065 | if (inode1) | 1165 | if (inode1) |
| 1066 | mutex_unlock(&inode1->i_mutex); | 1166 | mutex_unlock(&inode1->i_mutex); |
| 1067 | 1167 | ||
| 1068 | if (inode2 && inode2 != inode1) | 1168 | if (inode2 && inode2 != inode1) |
| 1069 | mutex_unlock(&inode2->i_mutex); | 1169 | mutex_unlock(&inode2->i_mutex); |
| 1170 | |||
| 1171 | out: | ||
| 1172 | return ret; | ||
| 1070 | } | 1173 | } |
| 1071 | 1174 | ||
| 1072 | /** | 1175 | /** |
| @@ -1123,70 +1226,76 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
| 1123 | ext4_lblk_t block_end, seq_start, add_blocks, file_end, seq_blocks = 0; | 1226 | ext4_lblk_t block_end, seq_start, add_blocks, file_end, seq_blocks = 0; |
| 1124 | ext4_lblk_t rest_blocks; | 1227 | ext4_lblk_t rest_blocks; |
| 1125 | pgoff_t orig_page_offset = 0, seq_end_page; | 1228 | pgoff_t orig_page_offset = 0, seq_end_page; |
| 1126 | int ret, depth, last_extent = 0; | 1229 | int ret1, ret2, depth, last_extent = 0; |
| 1127 | int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; | 1230 | int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; |
| 1128 | int data_offset_in_page; | 1231 | int data_offset_in_page; |
| 1129 | int block_len_in_page; | 1232 | int block_len_in_page; |
| 1130 | int uninit; | 1233 | int uninit; |
| 1131 | 1234 | ||
| 1132 | /* protect orig and donor against a truncate */ | 1235 | /* protect orig and donor against a truncate */ |
| 1133 | mext_inode_double_lock(orig_inode, donor_inode); | 1236 | ret1 = mext_inode_double_lock(orig_inode, donor_inode); |
| 1237 | if (ret1 < 0) | ||
| 1238 | return ret1; | ||
| 1134 | 1239 | ||
| 1135 | mext_double_down_read(orig_inode, donor_inode); | 1240 | mext_double_down_read(orig_inode, donor_inode); |
| 1136 | /* Check the filesystem environment whether move_extent can be done */ | 1241 | /* Check the filesystem environment whether move_extent can be done */ |
| 1137 | ret = mext_check_arguments(orig_inode, donor_inode, orig_start, | 1242 | ret1 = mext_check_arguments(orig_inode, donor_inode, orig_start, |
| 1138 | donor_start, &len, *moved_len); | 1243 | donor_start, &len, *moved_len); |
| 1139 | mext_double_up_read(orig_inode, donor_inode); | 1244 | mext_double_up_read(orig_inode, donor_inode); |
| 1140 | if (ret) | 1245 | if (ret1) |
| 1141 | goto out2; | 1246 | goto out; |
| 1142 | 1247 | ||
| 1143 | file_end = (i_size_read(orig_inode) - 1) >> orig_inode->i_blkbits; | 1248 | file_end = (i_size_read(orig_inode) - 1) >> orig_inode->i_blkbits; |
| 1144 | block_end = block_start + len - 1; | 1249 | block_end = block_start + len - 1; |
| 1145 | if (file_end < block_end) | 1250 | if (file_end < block_end) |
| 1146 | len -= block_end - file_end; | 1251 | len -= block_end - file_end; |
| 1147 | 1252 | ||
| 1148 | get_ext_path(orig_path, orig_inode, block_start, ret); | 1253 | ret1 = get_ext_path(orig_inode, block_start, &orig_path); |
| 1149 | if (orig_path == NULL) | 1254 | if (ret1) |
| 1150 | goto out2; | 1255 | goto out; |
| 1151 | 1256 | ||
| 1152 | /* Get path structure to check the hole */ | 1257 | /* Get path structure to check the hole */ |
| 1153 | get_ext_path(holecheck_path, orig_inode, block_start, ret); | 1258 | ret1 = get_ext_path(orig_inode, block_start, &holecheck_path); |
| 1154 | if (holecheck_path == NULL) | 1259 | if (ret1) |
| 1155 | goto out; | 1260 | goto out; |
| 1156 | 1261 | ||
| 1157 | depth = ext_depth(orig_inode); | 1262 | depth = ext_depth(orig_inode); |
| 1158 | ext_cur = holecheck_path[depth].p_ext; | 1263 | ext_cur = holecheck_path[depth].p_ext; |
| 1159 | if (ext_cur == NULL) { | ||
| 1160 | ret = -EINVAL; | ||
| 1161 | goto out; | ||
| 1162 | } | ||
| 1163 | 1264 | ||
| 1164 | /* | 1265 | /* |
| 1165 | * Get proper extent whose ee_block is beyond block_start | 1266 | * Get proper starting location of block replacement if block_start was |
| 1166 | * if block_start was within the hole. | 1267 | * within the hole. |
| 1167 | */ | 1268 | */ |
| 1168 | if (le32_to_cpu(ext_cur->ee_block) + | 1269 | if (le32_to_cpu(ext_cur->ee_block) + |
| 1169 | ext4_ext_get_actual_len(ext_cur) - 1 < block_start) { | 1270 | ext4_ext_get_actual_len(ext_cur) - 1 < block_start) { |
| 1271 | /* | ||
| 1272 | * The hole exists between extents or the tail of | ||
| 1273 | * original file. | ||
| 1274 | */ | ||
| 1170 | last_extent = mext_next_extent(orig_inode, | 1275 | last_extent = mext_next_extent(orig_inode, |
| 1171 | holecheck_path, &ext_cur); | 1276 | holecheck_path, &ext_cur); |
| 1172 | if (last_extent < 0) { | 1277 | if (last_extent < 0) { |
| 1173 | ret = last_extent; | 1278 | ret1 = last_extent; |
| 1174 | goto out; | 1279 | goto out; |
| 1175 | } | 1280 | } |
| 1176 | last_extent = mext_next_extent(orig_inode, orig_path, | 1281 | last_extent = mext_next_extent(orig_inode, orig_path, |
| 1177 | &ext_dummy); | 1282 | &ext_dummy); |
| 1178 | if (last_extent < 0) { | 1283 | if (last_extent < 0) { |
| 1179 | ret = last_extent; | 1284 | ret1 = last_extent; |
| 1180 | goto out; | 1285 | goto out; |
| 1181 | } | 1286 | } |
| 1182 | } | 1287 | seq_start = le32_to_cpu(ext_cur->ee_block); |
| 1183 | seq_start = block_start; | 1288 | } else if (le32_to_cpu(ext_cur->ee_block) > block_start) |
| 1289 | /* The hole exists at the beginning of original file. */ | ||
| 1290 | seq_start = le32_to_cpu(ext_cur->ee_block); | ||
| 1291 | else | ||
| 1292 | seq_start = block_start; | ||
| 1184 | 1293 | ||
| 1185 | /* No blocks within the specified range. */ | 1294 | /* No blocks within the specified range. */ |
| 1186 | if (le32_to_cpu(ext_cur->ee_block) > block_end) { | 1295 | if (le32_to_cpu(ext_cur->ee_block) > block_end) { |
| 1187 | ext4_debug("ext4 move extent: The specified range of file " | 1296 | ext4_debug("ext4 move extent: The specified range of file " |
| 1188 | "may be the hole\n"); | 1297 | "may be the hole\n"); |
| 1189 | ret = -EINVAL; | 1298 | ret1 = -EINVAL; |
| 1190 | goto out; | 1299 | goto out; |
| 1191 | } | 1300 | } |
| 1192 | 1301 | ||
| @@ -1206,7 +1315,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
| 1206 | last_extent = mext_next_extent(orig_inode, holecheck_path, | 1315 | last_extent = mext_next_extent(orig_inode, holecheck_path, |
| 1207 | &ext_cur); | 1316 | &ext_cur); |
| 1208 | if (last_extent < 0) { | 1317 | if (last_extent < 0) { |
| 1209 | ret = last_extent; | 1318 | ret1 = last_extent; |
| 1210 | break; | 1319 | break; |
| 1211 | } | 1320 | } |
| 1212 | add_blocks = ext4_ext_get_actual_len(ext_cur); | 1321 | add_blocks = ext4_ext_get_actual_len(ext_cur); |
| @@ -1258,16 +1367,23 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
| 1258 | while (orig_page_offset <= seq_end_page) { | 1367 | while (orig_page_offset <= seq_end_page) { |
| 1259 | 1368 | ||
| 1260 | /* Swap original branches with new branches */ | 1369 | /* Swap original branches with new branches */ |
| 1261 | ret = move_extent_par_page(o_filp, donor_inode, | 1370 | ret1 = move_extent_per_page(o_filp, donor_inode, |
| 1262 | orig_page_offset, | 1371 | orig_page_offset, |
| 1263 | data_offset_in_page, | 1372 | data_offset_in_page, |
| 1264 | block_len_in_page, uninit); | 1373 | block_len_in_page, uninit); |
| 1265 | if (ret < 0) | 1374 | if (ret1 < 0) |
| 1266 | goto out; | 1375 | goto out; |
| 1267 | orig_page_offset++; | 1376 | orig_page_offset++; |
| 1268 | /* Count how many blocks we have exchanged */ | 1377 | /* Count how many blocks we have exchanged */ |
| 1269 | *moved_len += block_len_in_page; | 1378 | *moved_len += block_len_in_page; |
| 1270 | BUG_ON(*moved_len > len); | 1379 | if (*moved_len > len) { |
| 1380 | ext4_error(orig_inode->i_sb, __func__, | ||
| 1381 | "We replaced blocks too much! " | ||
| 1382 | "sum of replaced: %llu requested: %llu", | ||
| 1383 | *moved_len, len); | ||
| 1384 | ret1 = -EIO; | ||
| 1385 | goto out; | ||
| 1386 | } | ||
| 1271 | 1387 | ||
| 1272 | data_offset_in_page = 0; | 1388 | data_offset_in_page = 0; |
| 1273 | rest_blocks -= block_len_in_page; | 1389 | rest_blocks -= block_len_in_page; |
| @@ -1280,17 +1396,16 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
| 1280 | /* Decrease buffer counter */ | 1396 | /* Decrease buffer counter */ |
| 1281 | if (holecheck_path) | 1397 | if (holecheck_path) |
| 1282 | ext4_ext_drop_refs(holecheck_path); | 1398 | ext4_ext_drop_refs(holecheck_path); |
| 1283 | get_ext_path(holecheck_path, orig_inode, | 1399 | ret1 = get_ext_path(orig_inode, seq_start, &holecheck_path); |
| 1284 | seq_start, ret); | 1400 | if (ret1) |
| 1285 | if (holecheck_path == NULL) | ||
| 1286 | break; | 1401 | break; |
| 1287 | depth = holecheck_path->p_depth; | 1402 | depth = holecheck_path->p_depth; |
| 1288 | 1403 | ||
| 1289 | /* Decrease buffer counter */ | 1404 | /* Decrease buffer counter */ |
| 1290 | if (orig_path) | 1405 | if (orig_path) |
| 1291 | ext4_ext_drop_refs(orig_path); | 1406 | ext4_ext_drop_refs(orig_path); |
| 1292 | get_ext_path(orig_path, orig_inode, seq_start, ret); | 1407 | ret1 = get_ext_path(orig_inode, seq_start, &orig_path); |
| 1293 | if (orig_path == NULL) | 1408 | if (ret1) |
| 1294 | break; | 1409 | break; |
| 1295 | 1410 | ||
| 1296 | ext_cur = holecheck_path[depth].p_ext; | 1411 | ext_cur = holecheck_path[depth].p_ext; |
| @@ -1307,14 +1422,13 @@ out: | |||
| 1307 | ext4_ext_drop_refs(holecheck_path); | 1422 | ext4_ext_drop_refs(holecheck_path); |
| 1308 | kfree(holecheck_path); | 1423 | kfree(holecheck_path); |
| 1309 | } | 1424 | } |
| 1310 | out2: | ||
| 1311 | mext_inode_double_unlock(orig_inode, donor_inode); | ||
| 1312 | 1425 | ||
| 1313 | if (ret) | 1426 | ret2 = mext_inode_double_unlock(orig_inode, donor_inode); |
| 1314 | return ret; | ||
| 1315 | 1427 | ||
| 1316 | /* All of the specified blocks must be exchanged in succeed */ | 1428 | if (ret1) |
| 1317 | BUG_ON(*moved_len != len); | 1429 | return ret1; |
| 1430 | else if (ret2) | ||
| 1431 | return ret2; | ||
| 1318 | 1432 | ||
| 1319 | return 0; | 1433 | return 0; |
| 1320 | } | 1434 | } |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index de04013d16f..42f81d285cd 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
| @@ -1518,8 +1518,12 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
| 1518 | return retval; | 1518 | return retval; |
| 1519 | 1519 | ||
| 1520 | if (blocks == 1 && !dx_fallback && | 1520 | if (blocks == 1 && !dx_fallback && |
| 1521 | EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) | 1521 | EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) { |
| 1522 | return make_indexed_dir(handle, dentry, inode, bh); | 1522 | retval = make_indexed_dir(handle, dentry, inode, bh); |
| 1523 | if (retval == -ENOSPC) | ||
| 1524 | brelse(bh); | ||
| 1525 | return retval; | ||
| 1526 | } | ||
| 1523 | brelse(bh); | 1527 | brelse(bh); |
| 1524 | } | 1528 | } |
| 1525 | bh = ext4_append(handle, dir, &block, &retval); | 1529 | bh = ext4_append(handle, dir, &block, &retval); |
| @@ -1528,7 +1532,10 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
| 1528 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 1532 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
| 1529 | de->inode = 0; | 1533 | de->inode = 0; |
| 1530 | de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize); | 1534 | de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize); |
| 1531 | return add_dirent_to_buf(handle, dentry, inode, de, bh); | 1535 | retval = add_dirent_to_buf(handle, dentry, inode, de, bh); |
| 1536 | if (retval == -ENOSPC) | ||
| 1537 | brelse(bh); | ||
| 1538 | return retval; | ||
| 1532 | } | 1539 | } |
| 1533 | 1540 | ||
| 1534 | /* | 1541 | /* |
| @@ -1590,9 +1597,9 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
| 1590 | goto cleanup; | 1597 | goto cleanup; |
| 1591 | node2 = (struct dx_node *)(bh2->b_data); | 1598 | node2 = (struct dx_node *)(bh2->b_data); |
| 1592 | entries2 = node2->entries; | 1599 | entries2 = node2->entries; |
| 1600 | memset(&node2->fake, 0, sizeof(struct fake_dirent)); | ||
| 1593 | node2->fake.rec_len = ext4_rec_len_to_disk(sb->s_blocksize, | 1601 | node2->fake.rec_len = ext4_rec_len_to_disk(sb->s_blocksize, |
| 1594 | sb->s_blocksize); | 1602 | sb->s_blocksize); |
| 1595 | node2->fake.inode = 0; | ||
| 1596 | BUFFER_TRACE(frame->bh, "get_write_access"); | 1603 | BUFFER_TRACE(frame->bh, "get_write_access"); |
| 1597 | err = ext4_journal_get_write_access(handle, frame->bh); | 1604 | err = ext4_journal_get_write_access(handle, frame->bh); |
| 1598 | if (err) | 1605 | if (err) |
| @@ -1657,7 +1664,8 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
| 1657 | if (!de) | 1664 | if (!de) |
| 1658 | goto cleanup; | 1665 | goto cleanup; |
| 1659 | err = add_dirent_to_buf(handle, dentry, inode, de, bh); | 1666 | err = add_dirent_to_buf(handle, dentry, inode, de, bh); |
| 1660 | bh = NULL; | 1667 | if (err != -ENOSPC) |
| 1668 | bh = NULL; | ||
| 1661 | goto cleanup; | 1669 | goto cleanup; |
| 1662 | 1670 | ||
| 1663 | journal_error: | 1671 | journal_error: |
| @@ -2310,7 +2318,7 @@ static int ext4_link(struct dentry *old_dentry, | |||
| 2310 | struct inode *inode = old_dentry->d_inode; | 2318 | struct inode *inode = old_dentry->d_inode; |
| 2311 | int err, retries = 0; | 2319 | int err, retries = 0; |
| 2312 | 2320 | ||
| 2313 | if (EXT4_DIR_LINK_MAX(inode)) | 2321 | if (inode->i_nlink >= EXT4_LINK_MAX) |
| 2314 | return -EMLINK; | 2322 | return -EMLINK; |
| 2315 | 2323 | ||
| 2316 | /* | 2324 | /* |
| @@ -2413,7 +2421,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2413 | goto end_rename; | 2421 | goto end_rename; |
| 2414 | retval = -EMLINK; | 2422 | retval = -EMLINK; |
| 2415 | if (!new_inode && new_dir != old_dir && | 2423 | if (!new_inode && new_dir != old_dir && |
| 2416 | new_dir->i_nlink >= EXT4_LINK_MAX) | 2424 | EXT4_DIR_LINK_MAX(new_dir)) |
| 2417 | goto end_rename; | 2425 | goto end_rename; |
| 2418 | } | 2426 | } |
| 2419 | if (!new_bh) { | 2427 | if (!new_bh) { |
| @@ -2536,7 +2544,7 @@ const struct inode_operations ext4_dir_inode_operations = { | |||
| 2536 | .listxattr = ext4_listxattr, | 2544 | .listxattr = ext4_listxattr, |
| 2537 | .removexattr = generic_removexattr, | 2545 | .removexattr = generic_removexattr, |
| 2538 | #endif | 2546 | #endif |
| 2539 | .permission = ext4_permission, | 2547 | .check_acl = ext4_check_acl, |
| 2540 | .fiemap = ext4_fiemap, | 2548 | .fiemap = ext4_fiemap, |
| 2541 | }; | 2549 | }; |
| 2542 | 2550 | ||
| @@ -2548,5 +2556,5 @@ const struct inode_operations ext4_special_inode_operations = { | |||
| 2548 | .listxattr = ext4_listxattr, | 2556 | .listxattr = ext4_listxattr, |
| 2549 | .removexattr = generic_removexattr, | 2557 | .removexattr = generic_removexattr, |
| 2550 | #endif | 2558 | #endif |
| 2551 | .permission = ext4_permission, | 2559 | .check_acl = ext4_check_acl, |
| 2552 | }; | 2560 | }; |
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 68b0351fc64..3cfc343c41b 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
| @@ -746,7 +746,6 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
| 746 | struct inode *inode = NULL; | 746 | struct inode *inode = NULL; |
| 747 | handle_t *handle; | 747 | handle_t *handle; |
| 748 | int gdb_off, gdb_num; | 748 | int gdb_off, gdb_num; |
| 749 | int num_grp_locked = 0; | ||
| 750 | int err, err2; | 749 | int err, err2; |
| 751 | 750 | ||
| 752 | gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb); | 751 | gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb); |
| @@ -856,7 +855,6 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
| 856 | * using the new disk blocks. | 855 | * using the new disk blocks. |
| 857 | */ | 856 | */ |
| 858 | 857 | ||
| 859 | num_grp_locked = ext4_mb_get_buddy_cache_lock(sb, input->group); | ||
| 860 | /* Update group descriptor block for new group */ | 858 | /* Update group descriptor block for new group */ |
| 861 | gdp = (struct ext4_group_desc *)((char *)primary->b_data + | 859 | gdp = (struct ext4_group_desc *)((char *)primary->b_data + |
| 862 | gdb_off * EXT4_DESC_SIZE(sb)); | 860 | gdb_off * EXT4_DESC_SIZE(sb)); |
| @@ -875,10 +873,8 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
| 875 | * descriptor | 873 | * descriptor |
| 876 | */ | 874 | */ |
| 877 | err = ext4_mb_add_groupinfo(sb, input->group, gdp); | 875 | err = ext4_mb_add_groupinfo(sb, input->group, gdp); |
| 878 | if (err) { | 876 | if (err) |
| 879 | ext4_mb_put_buddy_cache_lock(sb, input->group, num_grp_locked); | ||
| 880 | goto exit_journal; | 877 | goto exit_journal; |
| 881 | } | ||
| 882 | 878 | ||
| 883 | /* | 879 | /* |
| 884 | * Make the new blocks and inodes valid next. We do this before | 880 | * Make the new blocks and inodes valid next. We do this before |
| @@ -920,7 +916,6 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
| 920 | 916 | ||
| 921 | /* Update the global fs size fields */ | 917 | /* Update the global fs size fields */ |
| 922 | sbi->s_groups_count++; | 918 | sbi->s_groups_count++; |
| 923 | ext4_mb_put_buddy_cache_lock(sb, input->group, num_grp_locked); | ||
| 924 | 919 | ||
| 925 | ext4_handle_dirty_metadata(handle, NULL, primary); | 920 | ext4_handle_dirty_metadata(handle, NULL, primary); |
| 926 | 921 | ||
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 8f4f079e6b9..a6b1ab73472 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -45,6 +45,7 @@ | |||
| 45 | #include "ext4_jbd2.h" | 45 | #include "ext4_jbd2.h" |
| 46 | #include "xattr.h" | 46 | #include "xattr.h" |
| 47 | #include "acl.h" | 47 | #include "acl.h" |
| 48 | #include "mballoc.h" | ||
| 48 | 49 | ||
| 49 | #define CREATE_TRACE_POINTS | 50 | #define CREATE_TRACE_POINTS |
| 50 | #include <trace/events/ext4.h> | 51 | #include <trace/events/ext4.h> |
| @@ -344,7 +345,8 @@ static const char *ext4_decode_error(struct super_block *sb, int errno, | |||
| 344 | errstr = "Out of memory"; | 345 | errstr = "Out of memory"; |
| 345 | break; | 346 | break; |
| 346 | case -EROFS: | 347 | case -EROFS: |
| 347 | if (!sb || EXT4_SB(sb)->s_journal->j_flags & JBD2_ABORT) | 348 | if (!sb || (EXT4_SB(sb)->s_journal && |
| 349 | EXT4_SB(sb)->s_journal->j_flags & JBD2_ABORT)) | ||
| 348 | errstr = "Journal has aborted"; | 350 | errstr = "Journal has aborted"; |
| 349 | else | 351 | else |
| 350 | errstr = "Readonly filesystem"; | 352 | errstr = "Readonly filesystem"; |
| @@ -1279,11 +1281,9 @@ static int parse_options(char *options, struct super_block *sb, | |||
| 1279 | *journal_devnum = option; | 1281 | *journal_devnum = option; |
| 1280 | break; | 1282 | break; |
| 1281 | case Opt_journal_checksum: | 1283 | case Opt_journal_checksum: |
| 1282 | set_opt(sbi->s_mount_opt, JOURNAL_CHECKSUM); | 1284 | break; /* Kept for backwards compatibility */ |
| 1283 | break; | ||
| 1284 | case Opt_journal_async_commit: | 1285 | case Opt_journal_async_commit: |
| 1285 | set_opt(sbi->s_mount_opt, JOURNAL_ASYNC_COMMIT); | 1286 | set_opt(sbi->s_mount_opt, JOURNAL_ASYNC_COMMIT); |
| 1286 | set_opt(sbi->s_mount_opt, JOURNAL_CHECKSUM); | ||
| 1287 | break; | 1287 | break; |
| 1288 | case Opt_noload: | 1288 | case Opt_noload: |
| 1289 | set_opt(sbi->s_mount_opt, NOLOAD); | 1289 | set_opt(sbi->s_mount_opt, NOLOAD); |
| @@ -1695,12 +1695,12 @@ static int ext4_fill_flex_info(struct super_block *sb) | |||
| 1695 | gdp = ext4_get_group_desc(sb, i, NULL); | 1695 | gdp = ext4_get_group_desc(sb, i, NULL); |
| 1696 | 1696 | ||
| 1697 | flex_group = ext4_flex_group(sbi, i); | 1697 | flex_group = ext4_flex_group(sbi, i); |
| 1698 | atomic_set(&sbi->s_flex_groups[flex_group].free_inodes, | 1698 | atomic_add(ext4_free_inodes_count(sb, gdp), |
| 1699 | ext4_free_inodes_count(sb, gdp)); | 1699 | &sbi->s_flex_groups[flex_group].free_inodes); |
| 1700 | atomic_set(&sbi->s_flex_groups[flex_group].free_blocks, | 1700 | atomic_add(ext4_free_blks_count(sb, gdp), |
| 1701 | ext4_free_blks_count(sb, gdp)); | 1701 | &sbi->s_flex_groups[flex_group].free_blocks); |
| 1702 | atomic_set(&sbi->s_flex_groups[flex_group].used_dirs, | 1702 | atomic_add(ext4_used_dirs_count(sb, gdp), |
| 1703 | ext4_used_dirs_count(sb, gdp)); | 1703 | &sbi->s_flex_groups[flex_group].used_dirs); |
| 1704 | } | 1704 | } |
| 1705 | 1705 | ||
| 1706 | return 1; | 1706 | return 1; |
| @@ -2253,6 +2253,49 @@ static struct kobj_type ext4_ktype = { | |||
| 2253 | .release = ext4_sb_release, | 2253 | .release = ext4_sb_release, |
| 2254 | }; | 2254 | }; |
| 2255 | 2255 | ||
| 2256 | /* | ||
| 2257 | * Check whether this filesystem can be mounted based on | ||
| 2258 | * the features present and the RDONLY/RDWR mount requested. | ||
| 2259 | * Returns 1 if this filesystem can be mounted as requested, | ||
| 2260 | * 0 if it cannot be. | ||
| 2261 | */ | ||
| 2262 | static int ext4_feature_set_ok(struct super_block *sb, int readonly) | ||
| 2263 | { | ||
| 2264 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT4_FEATURE_INCOMPAT_SUPP)) { | ||
| 2265 | ext4_msg(sb, KERN_ERR, | ||
| 2266 | "Couldn't mount because of " | ||
| 2267 | "unsupported optional features (%x)", | ||
| 2268 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_incompat) & | ||
| 2269 | ~EXT4_FEATURE_INCOMPAT_SUPP)); | ||
| 2270 | return 0; | ||
| 2271 | } | ||
| 2272 | |||
| 2273 | if (readonly) | ||
| 2274 | return 1; | ||
| 2275 | |||
| 2276 | /* Check that feature set is OK for a read-write mount */ | ||
| 2277 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP)) { | ||
| 2278 | ext4_msg(sb, KERN_ERR, "couldn't mount RDWR because of " | ||
| 2279 | "unsupported optional features (%x)", | ||
| 2280 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_ro_compat) & | ||
| 2281 | ~EXT4_FEATURE_RO_COMPAT_SUPP)); | ||
| 2282 | return 0; | ||
| 2283 | } | ||
| 2284 | /* | ||
| 2285 | * Large file size enabled file system can only be mounted | ||
| 2286 | * read-write on 32-bit systems if kernel is built with CONFIG_LBDAF | ||
| 2287 | */ | ||
| 2288 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { | ||
| 2289 | if (sizeof(blkcnt_t) < sizeof(u64)) { | ||
| 2290 | ext4_msg(sb, KERN_ERR, "Filesystem with huge files " | ||
| 2291 | "cannot be mounted RDWR without " | ||
| 2292 | "CONFIG_LBDAF"); | ||
| 2293 | return 0; | ||
| 2294 | } | ||
| 2295 | } | ||
| 2296 | return 1; | ||
| 2297 | } | ||
| 2298 | |||
| 2256 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) | 2299 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) |
| 2257 | __releases(kernel_lock) | 2300 | __releases(kernel_lock) |
| 2258 | __acquires(kernel_lock) | 2301 | __acquires(kernel_lock) |
| @@ -2274,7 +2317,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
| 2274 | unsigned int db_count; | 2317 | unsigned int db_count; |
| 2275 | unsigned int i; | 2318 | unsigned int i; |
| 2276 | int needs_recovery, has_huge_files; | 2319 | int needs_recovery, has_huge_files; |
| 2277 | int features; | ||
| 2278 | __u64 blocks_count; | 2320 | __u64 blocks_count; |
| 2279 | int err; | 2321 | int err; |
| 2280 | unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; | 2322 | unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; |
| @@ -2401,39 +2443,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
| 2401 | * previously didn't change the revision level when setting the flags, | 2443 | * previously didn't change the revision level when setting the flags, |
| 2402 | * so there is a chance incompat flags are set on a rev 0 filesystem. | 2444 | * so there is a chance incompat flags are set on a rev 0 filesystem. |
| 2403 | */ | 2445 | */ |
| 2404 | features = EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT4_FEATURE_INCOMPAT_SUPP); | 2446 | if (!ext4_feature_set_ok(sb, (sb->s_flags & MS_RDONLY))) |
| 2405 | if (features) { | ||
| 2406 | ext4_msg(sb, KERN_ERR, | ||
| 2407 | "Couldn't mount because of " | ||
| 2408 | "unsupported optional features (%x)", | ||
| 2409 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_incompat) & | ||
| 2410 | ~EXT4_FEATURE_INCOMPAT_SUPP)); | ||
| 2411 | goto failed_mount; | ||
| 2412 | } | ||
| 2413 | features = EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP); | ||
| 2414 | if (!(sb->s_flags & MS_RDONLY) && features) { | ||
| 2415 | ext4_msg(sb, KERN_ERR, | ||
| 2416 | "Couldn't mount RDWR because of " | ||
| 2417 | "unsupported optional features (%x)", | ||
| 2418 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_ro_compat) & | ||
| 2419 | ~EXT4_FEATURE_RO_COMPAT_SUPP)); | ||
| 2420 | goto failed_mount; | 2447 | goto failed_mount; |
| 2421 | } | 2448 | |
| 2422 | has_huge_files = EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
| 2423 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE); | ||
| 2424 | if (has_huge_files) { | ||
| 2425 | /* | ||
| 2426 | * Large file size enabled file system can only be | ||
| 2427 | * mount if kernel is build with CONFIG_LBDAF | ||
| 2428 | */ | ||
| 2429 | if (sizeof(root->i_blocks) < sizeof(u64) && | ||
| 2430 | !(sb->s_flags & MS_RDONLY)) { | ||
| 2431 | ext4_msg(sb, KERN_ERR, "Filesystem with huge " | ||
| 2432 | "files cannot be mounted read-write " | ||
| 2433 | "without CONFIG_LBDAF"); | ||
| 2434 | goto failed_mount; | ||
| 2435 | } | ||
| 2436 | } | ||
| 2437 | blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); | 2449 | blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); |
| 2438 | 2450 | ||
| 2439 | if (blocksize < EXT4_MIN_BLOCK_SIZE || | 2451 | if (blocksize < EXT4_MIN_BLOCK_SIZE || |
| @@ -2469,6 +2481,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
| 2469 | } | 2481 | } |
| 2470 | } | 2482 | } |
| 2471 | 2483 | ||
| 2484 | has_huge_files = EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
| 2485 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE); | ||
| 2472 | sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits, | 2486 | sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits, |
| 2473 | has_huge_files); | 2487 | has_huge_files); |
| 2474 | sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files); | 2488 | sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files); |
| @@ -2549,12 +2563,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
| 2549 | goto failed_mount; | 2563 | goto failed_mount; |
| 2550 | } | 2564 | } |
| 2551 | 2565 | ||
| 2552 | if (ext4_blocks_count(es) > | 2566 | /* |
| 2553 | (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { | 2567 | * Test whether we have more sectors than will fit in sector_t, |
| 2568 | * and whether the max offset is addressable by the page cache. | ||
| 2569 | */ | ||
| 2570 | if ((ext4_blocks_count(es) > | ||
| 2571 | (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) || | ||
| 2572 | (ext4_blocks_count(es) > | ||
| 2573 | (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - sb->s_blocksize_bits))) { | ||
| 2554 | ext4_msg(sb, KERN_ERR, "filesystem" | 2574 | ext4_msg(sb, KERN_ERR, "filesystem" |
| 2555 | " too large to mount safely"); | 2575 | " too large to mount safely on this system"); |
| 2556 | if (sizeof(sector_t) < 8) | 2576 | if (sizeof(sector_t) < 8) |
| 2557 | ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled"); | 2577 | ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled"); |
| 2578 | ret = -EFBIG; | ||
| 2558 | goto failed_mount; | 2579 | goto failed_mount; |
| 2559 | } | 2580 | } |
| 2560 | 2581 | ||
| @@ -2595,6 +2616,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
| 2595 | goto failed_mount; | 2616 | goto failed_mount; |
| 2596 | } | 2617 | } |
| 2597 | sbi->s_groups_count = blocks_count; | 2618 | sbi->s_groups_count = blocks_count; |
| 2619 | sbi->s_blockfile_groups = min_t(ext4_group_t, sbi->s_groups_count, | ||
| 2620 | (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))); | ||
| 2598 | db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / | 2621 | db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / |
| 2599 | EXT4_DESC_PER_BLOCK(sb); | 2622 | EXT4_DESC_PER_BLOCK(sb); |
| 2600 | sbi->s_group_desc = kmalloc(db_count * sizeof(struct buffer_head *), | 2623 | sbi->s_group_desc = kmalloc(db_count * sizeof(struct buffer_head *), |
| @@ -2729,20 +2752,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
| 2729 | goto failed_mount4; | 2752 | goto failed_mount4; |
| 2730 | } | 2753 | } |
| 2731 | 2754 | ||
| 2732 | if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { | 2755 | jbd2_journal_set_features(sbi->s_journal, |
| 2733 | jbd2_journal_set_features(sbi->s_journal, | 2756 | JBD2_FEATURE_COMPAT_CHECKSUM, 0, 0); |
| 2734 | JBD2_FEATURE_COMPAT_CHECKSUM, 0, | 2757 | if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) |
| 2758 | jbd2_journal_set_features(sbi->s_journal, 0, 0, | ||
| 2735 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); | 2759 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); |
| 2736 | } else if (test_opt(sb, JOURNAL_CHECKSUM)) { | 2760 | else |
| 2737 | jbd2_journal_set_features(sbi->s_journal, | ||
| 2738 | JBD2_FEATURE_COMPAT_CHECKSUM, 0, 0); | ||
| 2739 | jbd2_journal_clear_features(sbi->s_journal, 0, 0, | 2761 | jbd2_journal_clear_features(sbi->s_journal, 0, 0, |
| 2740 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); | 2762 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); |
| 2741 | } else { | ||
| 2742 | jbd2_journal_clear_features(sbi->s_journal, | ||
| 2743 | JBD2_FEATURE_COMPAT_CHECKSUM, 0, | ||
| 2744 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); | ||
| 2745 | } | ||
| 2746 | 2763 | ||
| 2747 | /* We have now updated the journal if required, so we can | 2764 | /* We have now updated the journal if required, so we can |
| 2748 | * validate the data journaling mode. */ | 2765 | * validate the data journaling mode. */ |
| @@ -3208,7 +3225,18 @@ static int ext4_commit_super(struct super_block *sb, int sync) | |||
| 3208 | clear_buffer_write_io_error(sbh); | 3225 | clear_buffer_write_io_error(sbh); |
| 3209 | set_buffer_uptodate(sbh); | 3226 | set_buffer_uptodate(sbh); |
| 3210 | } | 3227 | } |
| 3211 | es->s_wtime = cpu_to_le32(get_seconds()); | 3228 | /* |
| 3229 | * If the file system is mounted read-only, don't update the | ||
| 3230 | * superblock write time. This avoids updating the superblock | ||
| 3231 | * write time when we are mounting the root file system | ||
| 3232 | * read/only but we need to replay the journal; at that point, | ||
| 3233 | * for people who are east of GMT and who make their clock | ||
| 3234 | * tick in localtime for Windows bug-for-bug compatibility, | ||
| 3235 | * the clock is set in the future, and this will cause e2fsck | ||
| 3236 | * to complain and force a full file system check. | ||
| 3237 | */ | ||
| 3238 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 3239 | es->s_wtime = cpu_to_le32(get_seconds()); | ||
| 3212 | es->s_kbytes_written = | 3240 | es->s_kbytes_written = |
| 3213 | cpu_to_le64(EXT4_SB(sb)->s_kbytes_written + | 3241 | cpu_to_le64(EXT4_SB(sb)->s_kbytes_written + |
| 3214 | ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) - | 3242 | ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) - |
| @@ -3477,18 +3505,11 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
| 3477 | if (sbi->s_journal) | 3505 | if (sbi->s_journal) |
| 3478 | ext4_mark_recovery_complete(sb, es); | 3506 | ext4_mark_recovery_complete(sb, es); |
| 3479 | } else { | 3507 | } else { |
| 3480 | int ret; | 3508 | /* Make sure we can mount this feature set readwrite */ |
| 3481 | if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb, | 3509 | if (!ext4_feature_set_ok(sb, 0)) { |
| 3482 | ~EXT4_FEATURE_RO_COMPAT_SUPP))) { | ||
| 3483 | ext4_msg(sb, KERN_WARNING, "couldn't " | ||
| 3484 | "remount RDWR because of unsupported " | ||
| 3485 | "optional features (%x)", | ||
| 3486 | (le32_to_cpu(sbi->s_es->s_feature_ro_compat) & | ||
| 3487 | ~EXT4_FEATURE_RO_COMPAT_SUPP)); | ||
| 3488 | err = -EROFS; | 3510 | err = -EROFS; |
| 3489 | goto restore_opts; | 3511 | goto restore_opts; |
| 3490 | } | 3512 | } |
| 3491 | |||
| 3492 | /* | 3513 | /* |
| 3493 | * Make sure the group descriptor checksums | 3514 | * Make sure the group descriptor checksums |
| 3494 | * are sane. If they aren't, refuse to remount r/w. | 3515 | * are sane. If they aren't, refuse to remount r/w. |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 62b31c24699..fed5b01d7a8 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
| @@ -810,12 +810,23 @@ inserted: | |||
| 810 | get_bh(new_bh); | 810 | get_bh(new_bh); |
| 811 | } else { | 811 | } else { |
| 812 | /* We need to allocate a new block */ | 812 | /* We need to allocate a new block */ |
| 813 | ext4_fsblk_t goal = ext4_group_first_block_no(sb, | 813 | ext4_fsblk_t goal, block; |
| 814 | |||
| 815 | goal = ext4_group_first_block_no(sb, | ||
| 814 | EXT4_I(inode)->i_block_group); | 816 | EXT4_I(inode)->i_block_group); |
| 815 | ext4_fsblk_t block = ext4_new_meta_blocks(handle, inode, | 817 | |
| 818 | /* non-extent files can't have physical blocks past 2^32 */ | ||
| 819 | if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) | ||
| 820 | goal = goal & EXT4_MAX_BLOCK_FILE_PHYS; | ||
| 821 | |||
| 822 | block = ext4_new_meta_blocks(handle, inode, | ||
| 816 | goal, NULL, &error); | 823 | goal, NULL, &error); |
| 817 | if (error) | 824 | if (error) |
| 818 | goto cleanup; | 825 | goto cleanup; |
| 826 | |||
| 827 | if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) | ||
| 828 | BUG_ON(block > EXT4_MAX_BLOCK_FILE_PHYS); | ||
| 829 | |||
| 819 | ea_idebug(inode, "creating block %d", block); | 830 | ea_idebug(inode, "creating block %d", block); |
| 820 | 831 | ||
| 821 | new_bh = sb_getblk(sb, block); | 832 | new_bh = sb_getblk(sb, block); |
diff --git a/fs/fat/file.c b/fs/fat/file.c index f042b965c95..e8c159de236 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
| @@ -176,8 +176,26 @@ static int fat_cont_expand(struct inode *inode, loff_t size) | |||
| 176 | 176 | ||
| 177 | inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; | 177 | inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; |
| 178 | mark_inode_dirty(inode); | 178 | mark_inode_dirty(inode); |
| 179 | if (IS_SYNC(inode)) | 179 | if (IS_SYNC(inode)) { |
| 180 | err = sync_page_range_nolock(inode, mapping, start, count); | 180 | int err2; |
| 181 | |||
| 182 | /* | ||
| 183 | * Opencode syncing since we don't have a file open to use | ||
| 184 | * standard fsync path. | ||
| 185 | */ | ||
| 186 | err = filemap_fdatawrite_range(mapping, start, | ||
| 187 | start + count - 1); | ||
| 188 | err2 = sync_mapping_buffers(mapping); | ||
| 189 | if (!err) | ||
| 190 | err = err2; | ||
| 191 | err2 = write_inode_now(inode, 1); | ||
| 192 | if (!err) | ||
| 193 | err = err2; | ||
| 194 | if (!err) { | ||
| 195 | err = filemap_fdatawait_range(mapping, start, | ||
| 196 | start + count - 1); | ||
| 197 | } | ||
| 198 | } | ||
| 181 | out: | 199 | out: |
| 182 | return err; | 200 | return err; |
| 183 | } | 201 | } |
diff --git a/fs/fat/misc.c b/fs/fat/misc.c index a6c20473dfd..4e35be873e0 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c | |||
| @@ -119,8 +119,8 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) | |||
| 119 | MSDOS_I(inode)->i_start = new_dclus; | 119 | MSDOS_I(inode)->i_start = new_dclus; |
| 120 | MSDOS_I(inode)->i_logstart = new_dclus; | 120 | MSDOS_I(inode)->i_logstart = new_dclus; |
| 121 | /* | 121 | /* |
| 122 | * Since generic_osync_inode() synchronize later if | 122 | * Since generic_write_sync() synchronizes regular files later, |
| 123 | * this is not directory, we don't here. | 123 | * we sync here only directories. |
| 124 | */ | 124 | */ |
| 125 | if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) { | 125 | if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) { |
| 126 | ret = fat_sync_inode(inode); | 126 | ret = fat_sync_inode(inode); |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index c54226be529..8e1e5e19d21 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
| @@ -19,171 +19,245 @@ | |||
| 19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
| 20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
| 21 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
| 22 | #include <linux/kthread.h> | ||
| 23 | #include <linux/freezer.h> | ||
| 22 | #include <linux/writeback.h> | 24 | #include <linux/writeback.h> |
| 23 | #include <linux/blkdev.h> | 25 | #include <linux/blkdev.h> |
| 24 | #include <linux/backing-dev.h> | 26 | #include <linux/backing-dev.h> |
| 25 | #include <linux/buffer_head.h> | 27 | #include <linux/buffer_head.h> |
| 26 | #include "internal.h" | 28 | #include "internal.h" |
| 27 | 29 | ||
| 30 | #define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info) | ||
| 28 | 31 | ||
| 29 | /** | 32 | /* |
| 30 | * writeback_acquire - attempt to get exclusive writeback access to a device | 33 | * We don't actually have pdflush, but this one is exported though /proc... |
| 31 | * @bdi: the device's backing_dev_info structure | 34 | */ |
| 32 | * | 35 | int nr_pdflush_threads; |
| 33 | * It is a waste of resources to have more than one pdflush thread blocked on | 36 | |
| 34 | * a single request queue. Exclusion at the request_queue level is obtained | 37 | /* |
| 35 | * via a flag in the request_queue's backing_dev_info.state. | 38 | * Passed into wb_writeback(), essentially a subset of writeback_control |
| 36 | * | 39 | */ |
| 37 | * Non-request_queue-backed address_spaces will share default_backing_dev_info, | 40 | struct wb_writeback_args { |
| 38 | * unless they implement their own. Which is somewhat inefficient, as this | 41 | long nr_pages; |
| 39 | * may prevent concurrent writeback against multiple devices. | 42 | struct super_block *sb; |
| 43 | enum writeback_sync_modes sync_mode; | ||
| 44 | int for_kupdate; | ||
| 45 | int range_cyclic; | ||
| 46 | }; | ||
| 47 | |||
| 48 | /* | ||
| 49 | * Work items for the bdi_writeback threads | ||
| 40 | */ | 50 | */ |
| 41 | static int writeback_acquire(struct backing_dev_info *bdi) | 51 | struct bdi_work { |
| 52 | struct list_head list; /* pending work list */ | ||
| 53 | struct rcu_head rcu_head; /* for RCU free/clear of work */ | ||
| 54 | |||
| 55 | unsigned long seen; /* threads that have seen this work */ | ||
| 56 | atomic_t pending; /* number of threads still to do work */ | ||
| 57 | |||
| 58 | struct wb_writeback_args args; /* writeback arguments */ | ||
| 59 | |||
| 60 | unsigned long state; /* flag bits, see WS_* */ | ||
| 61 | }; | ||
| 62 | |||
| 63 | enum { | ||
| 64 | WS_USED_B = 0, | ||
| 65 | WS_ONSTACK_B, | ||
| 66 | }; | ||
| 67 | |||
| 68 | #define WS_USED (1 << WS_USED_B) | ||
| 69 | #define WS_ONSTACK (1 << WS_ONSTACK_B) | ||
| 70 | |||
| 71 | static inline bool bdi_work_on_stack(struct bdi_work *work) | ||
| 72 | { | ||
| 73 | return test_bit(WS_ONSTACK_B, &work->state); | ||
| 74 | } | ||
| 75 | |||
| 76 | static inline void bdi_work_init(struct bdi_work *work, | ||
| 77 | struct wb_writeback_args *args) | ||
| 42 | { | 78 | { |
| 43 | return !test_and_set_bit(BDI_pdflush, &bdi->state); | 79 | INIT_RCU_HEAD(&work->rcu_head); |
| 80 | work->args = *args; | ||
| 81 | work->state = WS_USED; | ||
| 44 | } | 82 | } |
| 45 | 83 | ||
| 46 | /** | 84 | /** |
| 47 | * writeback_in_progress - determine whether there is writeback in progress | 85 | * writeback_in_progress - determine whether there is writeback in progress |
| 48 | * @bdi: the device's backing_dev_info structure. | 86 | * @bdi: the device's backing_dev_info structure. |
| 49 | * | 87 | * |
| 50 | * Determine whether there is writeback in progress against a backing device. | 88 | * Determine whether there is writeback waiting to be handled against a |
| 89 | * backing device. | ||
| 51 | */ | 90 | */ |
| 52 | int writeback_in_progress(struct backing_dev_info *bdi) | 91 | int writeback_in_progress(struct backing_dev_info *bdi) |
| 53 | { | 92 | { |
| 54 | return test_bit(BDI_pdflush, &bdi->state); | 93 | return !list_empty(&bdi->work_list); |
| 55 | } | 94 | } |
| 56 | 95 | ||
| 57 | /** | 96 | static void bdi_work_clear(struct bdi_work *work) |
| 58 | * writeback_release - relinquish exclusive writeback access against a device. | ||
| 59 | * @bdi: the device's backing_dev_info structure | ||
| 60 | */ | ||
| 61 | static void writeback_release(struct backing_dev_info *bdi) | ||
| 62 | { | 97 | { |
| 63 | BUG_ON(!writeback_in_progress(bdi)); | 98 | clear_bit(WS_USED_B, &work->state); |
| 64 | clear_bit(BDI_pdflush, &bdi->state); | 99 | smp_mb__after_clear_bit(); |
| 100 | /* | ||
| 101 | * work can have disappeared at this point. bit waitq functions | ||
| 102 | * should be able to tolerate this, provided bdi_sched_wait does | ||
| 103 | * not dereference it's pointer argument. | ||
| 104 | */ | ||
| 105 | wake_up_bit(&work->state, WS_USED_B); | ||
| 65 | } | 106 | } |
| 66 | 107 | ||
| 67 | static noinline void block_dump___mark_inode_dirty(struct inode *inode) | 108 | static void bdi_work_free(struct rcu_head *head) |
| 68 | { | 109 | { |
| 69 | if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) { | 110 | struct bdi_work *work = container_of(head, struct bdi_work, rcu_head); |
| 70 | struct dentry *dentry; | ||
| 71 | const char *name = "?"; | ||
| 72 | 111 | ||
| 73 | dentry = d_find_alias(inode); | 112 | if (!bdi_work_on_stack(work)) |
| 74 | if (dentry) { | 113 | kfree(work); |
| 75 | spin_lock(&dentry->d_lock); | 114 | else |
| 76 | name = (const char *) dentry->d_name.name; | 115 | bdi_work_clear(work); |
| 77 | } | ||
| 78 | printk(KERN_DEBUG | ||
| 79 | "%s(%d): dirtied inode %lu (%s) on %s\n", | ||
| 80 | current->comm, task_pid_nr(current), inode->i_ino, | ||
| 81 | name, inode->i_sb->s_id); | ||
| 82 | if (dentry) { | ||
| 83 | spin_unlock(&dentry->d_lock); | ||
| 84 | dput(dentry); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | } | 116 | } |
| 88 | 117 | ||
| 89 | /** | 118 | static void wb_work_complete(struct bdi_work *work) |
| 90 | * __mark_inode_dirty - internal function | ||
| 91 | * @inode: inode to mark | ||
| 92 | * @flags: what kind of dirty (i.e. I_DIRTY_SYNC) | ||
| 93 | * Mark an inode as dirty. Callers should use mark_inode_dirty or | ||
| 94 | * mark_inode_dirty_sync. | ||
| 95 | * | ||
| 96 | * Put the inode on the super block's dirty list. | ||
| 97 | * | ||
| 98 | * CAREFUL! We mark it dirty unconditionally, but move it onto the | ||
| 99 | * dirty list only if it is hashed or if it refers to a blockdev. | ||
| 100 | * If it was not hashed, it will never be added to the dirty list | ||
| 101 | * even if it is later hashed, as it will have been marked dirty already. | ||
| 102 | * | ||
| 103 | * In short, make sure you hash any inodes _before_ you start marking | ||
| 104 | * them dirty. | ||
| 105 | * | ||
| 106 | * This function *must* be atomic for the I_DIRTY_PAGES case - | ||
| 107 | * set_page_dirty() is called under spinlock in several places. | ||
| 108 | * | ||
| 109 | * Note that for blockdevs, inode->dirtied_when represents the dirtying time of | ||
| 110 | * the block-special inode (/dev/hda1) itself. And the ->dirtied_when field of | ||
| 111 | * the kernel-internal blockdev inode represents the dirtying time of the | ||
| 112 | * blockdev's pages. This is why for I_DIRTY_PAGES we always use | ||
| 113 | * page->mapping->host, so the page-dirtying time is recorded in the internal | ||
| 114 | * blockdev inode. | ||
| 115 | */ | ||
| 116 | void __mark_inode_dirty(struct inode *inode, int flags) | ||
| 117 | { | 119 | { |
| 118 | struct super_block *sb = inode->i_sb; | 120 | const enum writeback_sync_modes sync_mode = work->args.sync_mode; |
| 121 | int onstack = bdi_work_on_stack(work); | ||
| 119 | 122 | ||
| 120 | /* | 123 | /* |
| 121 | * Don't do this for I_DIRTY_PAGES - that doesn't actually | 124 | * For allocated work, we can clear the done/seen bit right here. |
| 122 | * dirty the inode itself | 125 | * For on-stack work, we need to postpone both the clear and free |
| 126 | * to after the RCU grace period, since the stack could be invalidated | ||
| 127 | * as soon as bdi_work_clear() has done the wakeup. | ||
| 123 | */ | 128 | */ |
| 124 | if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { | 129 | if (!onstack) |
| 125 | if (sb->s_op->dirty_inode) | 130 | bdi_work_clear(work); |
| 126 | sb->s_op->dirty_inode(inode); | 131 | if (sync_mode == WB_SYNC_NONE || onstack) |
| 127 | } | 132 | call_rcu(&work->rcu_head, bdi_work_free); |
| 133 | } | ||
| 128 | 134 | ||
| 135 | static void wb_clear_pending(struct bdi_writeback *wb, struct bdi_work *work) | ||
| 136 | { | ||
| 129 | /* | 137 | /* |
| 130 | * make sure that changes are seen by all cpus before we test i_state | 138 | * The caller has retrieved the work arguments from this work, |
| 131 | * -- mikulas | 139 | * drop our reference. If this is the last ref, delete and free it |
| 132 | */ | 140 | */ |
| 133 | smp_mb(); | 141 | if (atomic_dec_and_test(&work->pending)) { |
| 142 | struct backing_dev_info *bdi = wb->bdi; | ||
| 134 | 143 | ||
| 135 | /* avoid the locking if we can */ | 144 | spin_lock(&bdi->wb_lock); |
| 136 | if ((inode->i_state & flags) == flags) | 145 | list_del_rcu(&work->list); |
| 137 | return; | 146 | spin_unlock(&bdi->wb_lock); |
| 138 | 147 | ||
| 139 | if (unlikely(block_dump)) | 148 | wb_work_complete(work); |
| 140 | block_dump___mark_inode_dirty(inode); | 149 | } |
| 150 | } | ||
| 141 | 151 | ||
| 142 | spin_lock(&inode_lock); | 152 | static void bdi_queue_work(struct backing_dev_info *bdi, struct bdi_work *work) |
| 143 | if ((inode->i_state & flags) != flags) { | 153 | { |
| 144 | const int was_dirty = inode->i_state & I_DIRTY; | 154 | work->seen = bdi->wb_mask; |
| 155 | BUG_ON(!work->seen); | ||
| 156 | atomic_set(&work->pending, bdi->wb_cnt); | ||
| 157 | BUG_ON(!bdi->wb_cnt); | ||
| 145 | 158 | ||
| 146 | inode->i_state |= flags; | 159 | /* |
| 160 | * list_add_tail_rcu() contains the necessary barriers to | ||
| 161 | * make sure the above stores are seen before the item is | ||
| 162 | * noticed on the list | ||
| 163 | */ | ||
| 164 | spin_lock(&bdi->wb_lock); | ||
| 165 | list_add_tail_rcu(&work->list, &bdi->work_list); | ||
| 166 | spin_unlock(&bdi->wb_lock); | ||
| 147 | 167 | ||
| 148 | /* | 168 | /* |
| 149 | * If the inode is being synced, just update its dirty state. | 169 | * If the default thread isn't there, make sure we add it. When |
| 150 | * The unlocker will place the inode on the appropriate | 170 | * it gets created and wakes up, we'll run this work. |
| 151 | * superblock list, based upon its state. | 171 | */ |
| 152 | */ | 172 | if (unlikely(list_empty_careful(&bdi->wb_list))) |
| 153 | if (inode->i_state & I_SYNC) | 173 | wake_up_process(default_backing_dev_info.wb.task); |
| 154 | goto out; | 174 | else { |
| 175 | struct bdi_writeback *wb = &bdi->wb; | ||
| 155 | 176 | ||
| 156 | /* | 177 | if (wb->task) |
| 157 | * Only add valid (hashed) inodes to the superblock's | 178 | wake_up_process(wb->task); |
| 158 | * dirty list. Add blockdev inodes as well. | 179 | } |
| 159 | */ | 180 | } |
| 160 | if (!S_ISBLK(inode->i_mode)) { | ||
| 161 | if (hlist_unhashed(&inode->i_hash)) | ||
| 162 | goto out; | ||
| 163 | } | ||
| 164 | if (inode->i_state & (I_FREEING|I_CLEAR)) | ||
| 165 | goto out; | ||
| 166 | 181 | ||
| 167 | /* | 182 | /* |
| 168 | * If the inode was already on s_dirty/s_io/s_more_io, don't | 183 | * Used for on-stack allocated work items. The caller needs to wait until |
| 169 | * reposition it (that would break s_dirty time-ordering). | 184 | * the wb threads have acked the work before it's safe to continue. |
| 170 | */ | 185 | */ |
| 171 | if (!was_dirty) { | 186 | static void bdi_wait_on_work_clear(struct bdi_work *work) |
| 172 | inode->dirtied_when = jiffies; | 187 | { |
| 173 | list_move(&inode->i_list, &sb->s_dirty); | 188 | wait_on_bit(&work->state, WS_USED_B, bdi_sched_wait, |
| 174 | } | 189 | TASK_UNINTERRUPTIBLE); |
| 190 | } | ||
| 191 | |||
| 192 | static void bdi_alloc_queue_work(struct backing_dev_info *bdi, | ||
| 193 | struct wb_writeback_args *args) | ||
| 194 | { | ||
| 195 | struct bdi_work *work; | ||
| 196 | |||
| 197 | /* | ||
| 198 | * This is WB_SYNC_NONE writeback, so if allocation fails just | ||
| 199 | * wakeup the thread for old dirty data writeback | ||
| 200 | */ | ||
| 201 | work = kmalloc(sizeof(*work), GFP_ATOMIC); | ||
| 202 | if (work) { | ||
| 203 | bdi_work_init(work, args); | ||
| 204 | bdi_queue_work(bdi, work); | ||
| 205 | } else { | ||
| 206 | struct bdi_writeback *wb = &bdi->wb; | ||
| 207 | |||
| 208 | if (wb->task) | ||
| 209 | wake_up_process(wb->task); | ||
| 175 | } | 210 | } |
| 176 | out: | ||
| 177 | spin_unlock(&inode_lock); | ||
| 178 | } | 211 | } |
| 179 | 212 | ||
| 180 | EXPORT_SYMBOL(__mark_inode_dirty); | 213 | /** |
| 214 | * bdi_sync_writeback - start and wait for writeback | ||
| 215 | * @bdi: the backing device to write from | ||
| 216 | * @sb: write inodes from this super_block | ||
| 217 | * | ||
| 218 | * Description: | ||
| 219 | * This does WB_SYNC_ALL data integrity writeback and waits for the | ||
| 220 | * IO to complete. Callers must hold the sb s_umount semaphore for | ||
| 221 | * reading, to avoid having the super disappear before we are done. | ||
| 222 | */ | ||
| 223 | static void bdi_sync_writeback(struct backing_dev_info *bdi, | ||
| 224 | struct super_block *sb) | ||
| 225 | { | ||
| 226 | struct wb_writeback_args args = { | ||
| 227 | .sb = sb, | ||
| 228 | .sync_mode = WB_SYNC_ALL, | ||
| 229 | .nr_pages = LONG_MAX, | ||
| 230 | .range_cyclic = 0, | ||
| 231 | }; | ||
| 232 | struct bdi_work work; | ||
| 181 | 233 | ||
| 182 | static int write_inode(struct inode *inode, int sync) | 234 | bdi_work_init(&work, &args); |
| 235 | work.state |= WS_ONSTACK; | ||
| 236 | |||
| 237 | bdi_queue_work(bdi, &work); | ||
| 238 | bdi_wait_on_work_clear(&work); | ||
| 239 | } | ||
| 240 | |||
| 241 | /** | ||
| 242 | * bdi_start_writeback - start writeback | ||
| 243 | * @bdi: the backing device to write from | ||
| 244 | * @nr_pages: the number of pages to write | ||
| 245 | * | ||
| 246 | * Description: | ||
| 247 | * This does WB_SYNC_NONE opportunistic writeback. The IO is only | ||
| 248 | * started when this function returns, we make no guarentees on | ||
| 249 | * completion. Caller need not hold sb s_umount semaphore. | ||
| 250 | * | ||
| 251 | */ | ||
| 252 | void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages) | ||
| 183 | { | 253 | { |
| 184 | if (inode->i_sb->s_op->write_inode && !is_bad_inode(inode)) | 254 | struct wb_writeback_args args = { |
| 185 | return inode->i_sb->s_op->write_inode(inode, sync); | 255 | .sync_mode = WB_SYNC_NONE, |
| 186 | return 0; | 256 | .nr_pages = nr_pages, |
| 257 | .range_cyclic = 1, | ||
| 258 | }; | ||
| 259 | |||
| 260 | bdi_alloc_queue_work(bdi, &args); | ||
| 187 | } | 261 | } |
| 188 | 262 | ||
| 189 | /* | 263 | /* |
| @@ -191,31 +265,32 @@ static int write_inode(struct inode *inode, int sync) | |||
| 191 | * furthest end of its superblock's dirty-inode list. | 265 | * furthest end of its superblock's dirty-inode list. |
| 192 | * | 266 | * |
| 193 | * Before stamping the inode's ->dirtied_when, we check to see whether it is | 267 | * Before stamping the inode's ->dirtied_when, we check to see whether it is |
| 194 | * already the most-recently-dirtied inode on the s_dirty list. If that is | 268 | * already the most-recently-dirtied inode on the b_dirty list. If that is |
| 195 | * the case then the inode must have been redirtied while it was being written | 269 | * the case then the inode must have been redirtied while it was being written |
| 196 | * out and we don't reset its dirtied_when. | 270 | * out and we don't reset its dirtied_when. |
| 197 | */ | 271 | */ |
| 198 | static void redirty_tail(struct inode *inode) | 272 | static void redirty_tail(struct inode *inode) |
| 199 | { | 273 | { |
| 200 | struct super_block *sb = inode->i_sb; | 274 | struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; |
| 201 | 275 | ||
| 202 | if (!list_empty(&sb->s_dirty)) { | 276 | if (!list_empty(&wb->b_dirty)) { |
| 203 | struct inode *tail_inode; | 277 | struct inode *tail; |
| 204 | 278 | ||
| 205 | tail_inode = list_entry(sb->s_dirty.next, struct inode, i_list); | 279 | tail = list_entry(wb->b_dirty.next, struct inode, i_list); |
| 206 | if (time_before(inode->dirtied_when, | 280 | if (time_before(inode->dirtied_when, tail->dirtied_when)) |
| 207 | tail_inode->dirtied_when)) | ||
| 208 | inode->dirtied_when = jiffies; | 281 | inode->dirtied_when = jiffies; |
| 209 | } | 282 | } |
| 210 | list_move(&inode->i_list, &sb->s_dirty); | 283 | list_move(&inode->i_list, &wb->b_dirty); |
| 211 | } | 284 | } |
| 212 | 285 | ||
| 213 | /* | 286 | /* |
| 214 | * requeue inode for re-scanning after sb->s_io list is exhausted. | 287 | * requeue inode for re-scanning after bdi->b_io list is exhausted. |
| 215 | */ | 288 | */ |
| 216 | static void requeue_io(struct inode *inode) | 289 | static void requeue_io(struct inode *inode) |
| 217 | { | 290 | { |
| 218 | list_move(&inode->i_list, &inode->i_sb->s_more_io); | 291 | struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; |
| 292 | |||
| 293 | list_move(&inode->i_list, &wb->b_more_io); | ||
| 219 | } | 294 | } |
| 220 | 295 | ||
| 221 | static void inode_sync_complete(struct inode *inode) | 296 | static void inode_sync_complete(struct inode *inode) |
| @@ -262,20 +337,18 @@ static void move_expired_inodes(struct list_head *delaying_queue, | |||
| 262 | /* | 337 | /* |
| 263 | * Queue all expired dirty inodes for io, eldest first. | 338 | * Queue all expired dirty inodes for io, eldest first. |
| 264 | */ | 339 | */ |
| 265 | static void queue_io(struct super_block *sb, | 340 | static void queue_io(struct bdi_writeback *wb, unsigned long *older_than_this) |
| 266 | unsigned long *older_than_this) | ||
| 267 | { | 341 | { |
| 268 | list_splice_init(&sb->s_more_io, sb->s_io.prev); | 342 | list_splice_init(&wb->b_more_io, wb->b_io.prev); |
| 269 | move_expired_inodes(&sb->s_dirty, &sb->s_io, older_than_this); | 343 | move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this); |
| 270 | } | 344 | } |
| 271 | 345 | ||
| 272 | int sb_has_dirty_inodes(struct super_block *sb) | 346 | static int write_inode(struct inode *inode, int sync) |
| 273 | { | 347 | { |
| 274 | return !list_empty(&sb->s_dirty) || | 348 | if (inode->i_sb->s_op->write_inode && !is_bad_inode(inode)) |
| 275 | !list_empty(&sb->s_io) || | 349 | return inode->i_sb->s_op->write_inode(inode, sync); |
| 276 | !list_empty(&sb->s_more_io); | 350 | return 0; |
| 277 | } | 351 | } |
| 278 | EXPORT_SYMBOL(sb_has_dirty_inodes); | ||
| 279 | 352 | ||
| 280 | /* | 353 | /* |
| 281 | * Wait for writeback on an inode to complete. | 354 | * Wait for writeback on an inode to complete. |
| @@ -322,11 +395,11 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 322 | if (inode->i_state & I_SYNC) { | 395 | if (inode->i_state & I_SYNC) { |
| 323 | /* | 396 | /* |
| 324 | * If this inode is locked for writeback and we are not doing | 397 | * If this inode is locked for writeback and we are not doing |
| 325 | * writeback-for-data-integrity, move it to s_more_io so that | 398 | * writeback-for-data-integrity, move it to b_more_io so that |
| 326 | * writeback can proceed with the other inodes on s_io. | 399 | * writeback can proceed with the other inodes on s_io. |
| 327 | * | 400 | * |
| 328 | * We'll have another go at writing back this inode when we | 401 | * We'll have another go at writing back this inode when we |
| 329 | * completed a full scan of s_io. | 402 | * completed a full scan of b_io. |
| 330 | */ | 403 | */ |
| 331 | if (!wait) { | 404 | if (!wait) { |
| 332 | requeue_io(inode); | 405 | requeue_io(inode); |
| @@ -371,11 +444,11 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 371 | /* | 444 | /* |
| 372 | * We didn't write back all the pages. nfs_writepages() | 445 | * We didn't write back all the pages. nfs_writepages() |
| 373 | * sometimes bales out without doing anything. Redirty | 446 | * sometimes bales out without doing anything. Redirty |
| 374 | * the inode; Move it from s_io onto s_more_io/s_dirty. | 447 | * the inode; Move it from b_io onto b_more_io/b_dirty. |
| 375 | */ | 448 | */ |
| 376 | /* | 449 | /* |
| 377 | * akpm: if the caller was the kupdate function we put | 450 | * akpm: if the caller was the kupdate function we put |
| 378 | * this inode at the head of s_dirty so it gets first | 451 | * this inode at the head of b_dirty so it gets first |
| 379 | * consideration. Otherwise, move it to the tail, for | 452 | * consideration. Otherwise, move it to the tail, for |
| 380 | * the reasons described there. I'm not really sure | 453 | * the reasons described there. I'm not really sure |
| 381 | * how much sense this makes. Presumably I had a good | 454 | * how much sense this makes. Presumably I had a good |
| @@ -385,7 +458,7 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 385 | if (wbc->for_kupdate) { | 458 | if (wbc->for_kupdate) { |
| 386 | /* | 459 | /* |
| 387 | * For the kupdate function we move the inode | 460 | * For the kupdate function we move the inode |
| 388 | * to s_more_io so it will get more writeout as | 461 | * to b_more_io so it will get more writeout as |
| 389 | * soon as the queue becomes uncongested. | 462 | * soon as the queue becomes uncongested. |
| 390 | */ | 463 | */ |
| 391 | inode->i_state |= I_DIRTY_PAGES; | 464 | inode->i_state |= I_DIRTY_PAGES; |
| @@ -434,50 +507,84 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 434 | } | 507 | } |
| 435 | 508 | ||
| 436 | /* | 509 | /* |
| 437 | * Write out a superblock's list of dirty inodes. A wait will be performed | 510 | * For WB_SYNC_NONE writeback, the caller does not have the sb pinned |
| 438 | * upon no inodes, all inodes or the final one, depending upon sync_mode. | 511 | * before calling writeback. So make sure that we do pin it, so it doesn't |
| 439 | * | 512 | * go away while we are writing inodes from it. |
| 440 | * If older_than_this is non-NULL, then only write out inodes which | ||
| 441 | * had their first dirtying at a time earlier than *older_than_this. | ||
| 442 | * | ||
| 443 | * If we're a pdflush thread, then implement pdflush collision avoidance | ||
| 444 | * against the entire list. | ||
| 445 | * | 513 | * |
| 446 | * If `bdi' is non-zero then we're being asked to writeback a specific queue. | 514 | * Returns 0 if the super was successfully pinned (or pinning wasn't needed), |
| 447 | * This function assumes that the blockdev superblock's inodes are backed by | 515 | * 1 if we failed. |
| 448 | * a variety of queues, so all inodes are searched. For other superblocks, | ||
| 449 | * assume that all inodes are backed by the same queue. | ||
| 450 | * | ||
| 451 | * FIXME: this linear search could get expensive with many fileystems. But | ||
| 452 | * how to fix? We need to go from an address_space to all inodes which share | ||
| 453 | * a queue with that address_space. (Easy: have a global "dirty superblocks" | ||
| 454 | * list). | ||
| 455 | * | ||
| 456 | * The inodes to be written are parked on sb->s_io. They are moved back onto | ||
| 457 | * sb->s_dirty as they are selected for writing. This way, none can be missed | ||
| 458 | * on the writer throttling path, and we get decent balancing between many | ||
| 459 | * throttled threads: we don't want them all piling up on inode_sync_wait. | ||
| 460 | */ | 516 | */ |
| 461 | void generic_sync_sb_inodes(struct super_block *sb, | 517 | static int pin_sb_for_writeback(struct writeback_control *wbc, |
| 518 | struct inode *inode) | ||
| 519 | { | ||
| 520 | struct super_block *sb = inode->i_sb; | ||
| 521 | |||
| 522 | /* | ||
| 523 | * Caller must already hold the ref for this | ||
| 524 | */ | ||
| 525 | if (wbc->sync_mode == WB_SYNC_ALL) { | ||
| 526 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | ||
| 527 | return 0; | ||
| 528 | } | ||
| 529 | |||
| 530 | spin_lock(&sb_lock); | ||
| 531 | sb->s_count++; | ||
| 532 | if (down_read_trylock(&sb->s_umount)) { | ||
| 533 | if (sb->s_root) { | ||
| 534 | spin_unlock(&sb_lock); | ||
| 535 | return 0; | ||
| 536 | } | ||
| 537 | /* | ||
| 538 | * umounted, drop rwsem again and fall through to failure | ||
| 539 | */ | ||
| 540 | up_read(&sb->s_umount); | ||
| 541 | } | ||
| 542 | |||
| 543 | sb->s_count--; | ||
| 544 | spin_unlock(&sb_lock); | ||
| 545 | return 1; | ||
| 546 | } | ||
| 547 | |||
| 548 | static void unpin_sb_for_writeback(struct writeback_control *wbc, | ||
| 549 | struct inode *inode) | ||
| 550 | { | ||
| 551 | struct super_block *sb = inode->i_sb; | ||
| 552 | |||
| 553 | if (wbc->sync_mode == WB_SYNC_ALL) | ||
| 554 | return; | ||
| 555 | |||
| 556 | up_read(&sb->s_umount); | ||
| 557 | put_super(sb); | ||
| 558 | } | ||
| 559 | |||
| 560 | static void writeback_inodes_wb(struct bdi_writeback *wb, | ||
| 462 | struct writeback_control *wbc) | 561 | struct writeback_control *wbc) |
| 463 | { | 562 | { |
| 563 | struct super_block *sb = wbc->sb; | ||
| 564 | const int is_blkdev_sb = sb_is_blkdev_sb(sb); | ||
| 464 | const unsigned long start = jiffies; /* livelock avoidance */ | 565 | const unsigned long start = jiffies; /* livelock avoidance */ |
| 465 | int sync = wbc->sync_mode == WB_SYNC_ALL; | ||
| 466 | 566 | ||
| 467 | spin_lock(&inode_lock); | 567 | spin_lock(&inode_lock); |
| 468 | if (!wbc->for_kupdate || list_empty(&sb->s_io)) | ||
| 469 | queue_io(sb, wbc->older_than_this); | ||
| 470 | 568 | ||
| 471 | while (!list_empty(&sb->s_io)) { | 569 | if (!wbc->for_kupdate || list_empty(&wb->b_io)) |
| 472 | struct inode *inode = list_entry(sb->s_io.prev, | 570 | queue_io(wb, wbc->older_than_this); |
| 571 | |||
| 572 | while (!list_empty(&wb->b_io)) { | ||
| 573 | struct inode *inode = list_entry(wb->b_io.prev, | ||
| 473 | struct inode, i_list); | 574 | struct inode, i_list); |
| 474 | struct address_space *mapping = inode->i_mapping; | ||
| 475 | struct backing_dev_info *bdi = mapping->backing_dev_info; | ||
| 476 | long pages_skipped; | 575 | long pages_skipped; |
| 477 | 576 | ||
| 478 | if (!bdi_cap_writeback_dirty(bdi)) { | 577 | /* |
| 578 | * super block given and doesn't match, skip this inode | ||
| 579 | */ | ||
| 580 | if (sb && sb != inode->i_sb) { | ||
| 581 | redirty_tail(inode); | ||
| 582 | continue; | ||
| 583 | } | ||
| 584 | |||
| 585 | if (!bdi_cap_writeback_dirty(wb->bdi)) { | ||
| 479 | redirty_tail(inode); | 586 | redirty_tail(inode); |
| 480 | if (sb_is_blkdev_sb(sb)) { | 587 | if (is_blkdev_sb) { |
| 481 | /* | 588 | /* |
| 482 | * Dirty memory-backed blockdev: the ramdisk | 589 | * Dirty memory-backed blockdev: the ramdisk |
| 483 | * driver does this. Skip just this inode | 590 | * driver does this. Skip just this inode |
| @@ -497,21 +604,14 @@ void generic_sync_sb_inodes(struct super_block *sb, | |||
| 497 | continue; | 604 | continue; |
| 498 | } | 605 | } |
| 499 | 606 | ||
| 500 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | 607 | if (wbc->nonblocking && bdi_write_congested(wb->bdi)) { |
| 501 | wbc->encountered_congestion = 1; | 608 | wbc->encountered_congestion = 1; |
| 502 | if (!sb_is_blkdev_sb(sb)) | 609 | if (!is_blkdev_sb) |
| 503 | break; /* Skip a congested fs */ | 610 | break; /* Skip a congested fs */ |
| 504 | requeue_io(inode); | 611 | requeue_io(inode); |
| 505 | continue; /* Skip a congested blockdev */ | 612 | continue; /* Skip a congested blockdev */ |
| 506 | } | 613 | } |
| 507 | 614 | ||
| 508 | if (wbc->bdi && bdi != wbc->bdi) { | ||
| 509 | if (!sb_is_blkdev_sb(sb)) | ||
| 510 | break; /* fs has the wrong queue */ | ||
| 511 | requeue_io(inode); | ||
| 512 | continue; /* blockdev has wrong queue */ | ||
| 513 | } | ||
| 514 | |||
| 515 | /* | 615 | /* |
| 516 | * Was this inode dirtied after sync_sb_inodes was called? | 616 | * Was this inode dirtied after sync_sb_inodes was called? |
| 517 | * This keeps sync from extra jobs and livelock. | 617 | * This keeps sync from extra jobs and livelock. |
| @@ -519,16 +619,16 @@ void generic_sync_sb_inodes(struct super_block *sb, | |||
| 519 | if (inode_dirtied_after(inode, start)) | 619 | if (inode_dirtied_after(inode, start)) |
| 520 | break; | 620 | break; |
| 521 | 621 | ||
| 522 | /* Is another pdflush already flushing this queue? */ | 622 | if (pin_sb_for_writeback(wbc, inode)) { |
| 523 | if (current_is_pdflush() && !writeback_acquire(bdi)) | 623 | requeue_io(inode); |
| 524 | break; | 624 | continue; |
| 625 | } | ||
| 525 | 626 | ||
| 526 | BUG_ON(inode->i_state & (I_FREEING | I_CLEAR)); | 627 | BUG_ON(inode->i_state & (I_FREEING | I_CLEAR)); |
| 527 | __iget(inode); | 628 | __iget(inode); |
| 528 | pages_skipped = wbc->pages_skipped; | 629 | pages_skipped = wbc->pages_skipped; |
| 529 | writeback_single_inode(inode, wbc); | 630 | writeback_single_inode(inode, wbc); |
| 530 | if (current_is_pdflush()) | 631 | unpin_sb_for_writeback(wbc, inode); |
| 531 | writeback_release(bdi); | ||
| 532 | if (wbc->pages_skipped != pages_skipped) { | 632 | if (wbc->pages_skipped != pages_skipped) { |
| 533 | /* | 633 | /* |
| 534 | * writeback is not making progress due to locked | 634 | * writeback is not making progress due to locked |
| @@ -544,144 +644,520 @@ void generic_sync_sb_inodes(struct super_block *sb, | |||
| 544 | wbc->more_io = 1; | 644 | wbc->more_io = 1; |
| 545 | break; | 645 | break; |
| 546 | } | 646 | } |
| 547 | if (!list_empty(&sb->s_more_io)) | 647 | if (!list_empty(&wb->b_more_io)) |
| 548 | wbc->more_io = 1; | 648 | wbc->more_io = 1; |
| 549 | } | 649 | } |
| 550 | 650 | ||
| 551 | if (sync) { | 651 | spin_unlock(&inode_lock); |
| 552 | struct inode *inode, *old_inode = NULL; | 652 | /* Leave any unwritten inodes on b_io */ |
| 653 | } | ||
| 654 | |||
| 655 | void writeback_inodes_wbc(struct writeback_control *wbc) | ||
| 656 | { | ||
| 657 | struct backing_dev_info *bdi = wbc->bdi; | ||
| 553 | 658 | ||
| 659 | writeback_inodes_wb(&bdi->wb, wbc); | ||
| 660 | } | ||
| 661 | |||
| 662 | /* | ||
| 663 | * The maximum number of pages to writeout in a single bdi flush/kupdate | ||
| 664 | * operation. We do this so we don't hold I_SYNC against an inode for | ||
| 665 | * enormous amounts of time, which would block a userspace task which has | ||
| 666 | * been forced to throttle against that inode. Also, the code reevaluates | ||
| 667 | * the dirty each time it has written this many pages. | ||
| 668 | */ | ||
| 669 | #define MAX_WRITEBACK_PAGES 1024 | ||
| 670 | |||
| 671 | static inline bool over_bground_thresh(void) | ||
| 672 | { | ||
| 673 | unsigned long background_thresh, dirty_thresh; | ||
| 674 | |||
| 675 | get_dirty_limits(&background_thresh, &dirty_thresh, NULL, NULL); | ||
| 676 | |||
| 677 | return (global_page_state(NR_FILE_DIRTY) + | ||
| 678 | global_page_state(NR_UNSTABLE_NFS) >= background_thresh); | ||
| 679 | } | ||
| 680 | |||
| 681 | /* | ||
| 682 | * Explicit flushing or periodic writeback of "old" data. | ||
| 683 | * | ||
| 684 | * Define "old": the first time one of an inode's pages is dirtied, we mark the | ||
| 685 | * dirtying-time in the inode's address_space. So this periodic writeback code | ||
| 686 | * just walks the superblock inode list, writing back any inodes which are | ||
| 687 | * older than a specific point in time. | ||
| 688 | * | ||
| 689 | * Try to run once per dirty_writeback_interval. But if a writeback event | ||
| 690 | * takes longer than a dirty_writeback_interval interval, then leave a | ||
| 691 | * one-second gap. | ||
| 692 | * | ||
| 693 | * older_than_this takes precedence over nr_to_write. So we'll only write back | ||
| 694 | * all dirty pages if they are all attached to "old" mappings. | ||
| 695 | */ | ||
| 696 | static long wb_writeback(struct bdi_writeback *wb, | ||
| 697 | struct wb_writeback_args *args) | ||
| 698 | { | ||
| 699 | struct writeback_control wbc = { | ||
| 700 | .bdi = wb->bdi, | ||
| 701 | .sb = args->sb, | ||
| 702 | .sync_mode = args->sync_mode, | ||
| 703 | .older_than_this = NULL, | ||
| 704 | .for_kupdate = args->for_kupdate, | ||
| 705 | .range_cyclic = args->range_cyclic, | ||
| 706 | }; | ||
| 707 | unsigned long oldest_jif; | ||
| 708 | long wrote = 0; | ||
| 709 | |||
| 710 | if (wbc.for_kupdate) { | ||
| 711 | wbc.older_than_this = &oldest_jif; | ||
| 712 | oldest_jif = jiffies - | ||
| 713 | msecs_to_jiffies(dirty_expire_interval * 10); | ||
| 714 | } | ||
| 715 | if (!wbc.range_cyclic) { | ||
| 716 | wbc.range_start = 0; | ||
| 717 | wbc.range_end = LLONG_MAX; | ||
| 718 | } | ||
| 719 | |||
| 720 | for (;;) { | ||
| 554 | /* | 721 | /* |
| 555 | * Data integrity sync. Must wait for all pages under writeback, | 722 | * Don't flush anything for non-integrity writeback where |
| 556 | * because there may have been pages dirtied before our sync | 723 | * no nr_pages was given |
| 557 | * call, but which had writeout started before we write it out. | ||
| 558 | * In which case, the inode may not be on the dirty list, but | ||
| 559 | * we still have to wait for that writeout. | ||
| 560 | */ | 724 | */ |
| 561 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 725 | if (!args->for_kupdate && args->nr_pages <= 0 && |
| 562 | struct address_space *mapping; | 726 | args->sync_mode == WB_SYNC_NONE) |
| 727 | break; | ||
| 563 | 728 | ||
| 564 | if (inode->i_state & | 729 | /* |
| 565 | (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) | 730 | * If no specific pages were given and this is just a |
| 566 | continue; | 731 | * periodic background writeout and we are below the |
| 567 | mapping = inode->i_mapping; | 732 | * background dirty threshold, don't do anything |
| 568 | if (mapping->nrpages == 0) | 733 | */ |
| 734 | if (args->for_kupdate && args->nr_pages <= 0 && | ||
| 735 | !over_bground_thresh()) | ||
| 736 | break; | ||
| 737 | |||
| 738 | wbc.more_io = 0; | ||
| 739 | wbc.encountered_congestion = 0; | ||
| 740 | wbc.nr_to_write = MAX_WRITEBACK_PAGES; | ||
| 741 | wbc.pages_skipped = 0; | ||
| 742 | writeback_inodes_wb(wb, &wbc); | ||
| 743 | args->nr_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write; | ||
| 744 | wrote += MAX_WRITEBACK_PAGES - wbc.nr_to_write; | ||
| 745 | |||
| 746 | /* | ||
| 747 | * If we ran out of stuff to write, bail unless more_io got set | ||
| 748 | */ | ||
| 749 | if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) { | ||
| 750 | if (wbc.more_io && !wbc.for_kupdate) | ||
| 569 | continue; | 751 | continue; |
| 570 | __iget(inode); | 752 | break; |
| 571 | spin_unlock(&inode_lock); | 753 | } |
| 572 | /* | 754 | } |
| 573 | * We hold a reference to 'inode' so it couldn't have | 755 | |
| 574 | * been removed from s_inodes list while we dropped the | 756 | return wrote; |
| 575 | * inode_lock. We cannot iput the inode now as we can | 757 | } |
| 576 | * be holding the last reference and we cannot iput it | 758 | |
| 577 | * under inode_lock. So we keep the reference and iput | 759 | /* |
| 578 | * it later. | 760 | * Return the next bdi_work struct that hasn't been processed by this |
| 579 | */ | 761 | * wb thread yet. ->seen is initially set for each thread that exists |
| 580 | iput(old_inode); | 762 | * for this device, when a thread first notices a piece of work it |
| 581 | old_inode = inode; | 763 | * clears its bit. Depending on writeback type, the thread will notify |
| 764 | * completion on either receiving the work (WB_SYNC_NONE) or after | ||
| 765 | * it is done (WB_SYNC_ALL). | ||
| 766 | */ | ||
| 767 | static struct bdi_work *get_next_work_item(struct backing_dev_info *bdi, | ||
| 768 | struct bdi_writeback *wb) | ||
| 769 | { | ||
| 770 | struct bdi_work *work, *ret = NULL; | ||
| 771 | |||
| 772 | rcu_read_lock(); | ||
| 773 | |||
| 774 | list_for_each_entry_rcu(work, &bdi->work_list, list) { | ||
| 775 | if (!test_bit(wb->nr, &work->seen)) | ||
| 776 | continue; | ||
| 777 | clear_bit(wb->nr, &work->seen); | ||
| 778 | |||
| 779 | ret = work; | ||
| 780 | break; | ||
| 781 | } | ||
| 782 | |||
| 783 | rcu_read_unlock(); | ||
| 784 | return ret; | ||
| 785 | } | ||
| 786 | |||
| 787 | static long wb_check_old_data_flush(struct bdi_writeback *wb) | ||
| 788 | { | ||
| 789 | unsigned long expired; | ||
| 790 | long nr_pages; | ||
| 791 | |||
| 792 | expired = wb->last_old_flush + | ||
| 793 | msecs_to_jiffies(dirty_writeback_interval * 10); | ||
| 794 | if (time_before(jiffies, expired)) | ||
| 795 | return 0; | ||
| 796 | |||
| 797 | wb->last_old_flush = jiffies; | ||
| 798 | nr_pages = global_page_state(NR_FILE_DIRTY) + | ||
| 799 | global_page_state(NR_UNSTABLE_NFS) + | ||
| 800 | (inodes_stat.nr_inodes - inodes_stat.nr_unused); | ||
| 801 | |||
| 802 | if (nr_pages) { | ||
| 803 | struct wb_writeback_args args = { | ||
| 804 | .nr_pages = nr_pages, | ||
| 805 | .sync_mode = WB_SYNC_NONE, | ||
| 806 | .for_kupdate = 1, | ||
| 807 | .range_cyclic = 1, | ||
| 808 | }; | ||
| 809 | |||
| 810 | return wb_writeback(wb, &args); | ||
| 811 | } | ||
| 812 | |||
| 813 | return 0; | ||
| 814 | } | ||
| 815 | |||
| 816 | /* | ||
| 817 | * Retrieve work items and do the writeback they describe | ||
| 818 | */ | ||
| 819 | long wb_do_writeback(struct bdi_writeback *wb, int force_wait) | ||
| 820 | { | ||
| 821 | struct backing_dev_info *bdi = wb->bdi; | ||
| 822 | struct bdi_work *work; | ||
| 823 | long wrote = 0; | ||
| 582 | 824 | ||
| 583 | filemap_fdatawait(mapping); | 825 | while ((work = get_next_work_item(bdi, wb)) != NULL) { |
| 826 | struct wb_writeback_args args = work->args; | ||
| 584 | 827 | ||
| 585 | cond_resched(); | 828 | /* |
| 829 | * Override sync mode, in case we must wait for completion | ||
| 830 | */ | ||
| 831 | if (force_wait) | ||
| 832 | work->args.sync_mode = args.sync_mode = WB_SYNC_ALL; | ||
| 586 | 833 | ||
| 587 | spin_lock(&inode_lock); | 834 | /* |
| 835 | * If this isn't a data integrity operation, just notify | ||
| 836 | * that we have seen this work and we are now starting it. | ||
| 837 | */ | ||
| 838 | if (args.sync_mode == WB_SYNC_NONE) | ||
| 839 | wb_clear_pending(wb, work); | ||
| 840 | |||
| 841 | wrote += wb_writeback(wb, &args); | ||
| 842 | |||
| 843 | /* | ||
| 844 | * This is a data integrity writeback, so only do the | ||
| 845 | * notification when we have completed the work. | ||
| 846 | */ | ||
| 847 | if (args.sync_mode == WB_SYNC_ALL) | ||
| 848 | wb_clear_pending(wb, work); | ||
| 849 | } | ||
| 850 | |||
| 851 | /* | ||
| 852 | * Check for periodic writeback, kupdated() style | ||
| 853 | */ | ||
| 854 | wrote += wb_check_old_data_flush(wb); | ||
| 855 | |||
| 856 | return wrote; | ||
| 857 | } | ||
| 858 | |||
| 859 | /* | ||
| 860 | * Handle writeback of dirty data for the device backed by this bdi. Also | ||
| 861 | * wakes up periodically and does kupdated style flushing. | ||
| 862 | */ | ||
| 863 | int bdi_writeback_task(struct bdi_writeback *wb) | ||
| 864 | { | ||
| 865 | unsigned long last_active = jiffies; | ||
| 866 | unsigned long wait_jiffies = -1UL; | ||
| 867 | long pages_written; | ||
| 868 | |||
| 869 | while (!kthread_should_stop()) { | ||
| 870 | pages_written = wb_do_writeback(wb, 0); | ||
| 871 | |||
| 872 | if (pages_written) | ||
| 873 | last_active = jiffies; | ||
| 874 | else if (wait_jiffies != -1UL) { | ||
| 875 | unsigned long max_idle; | ||
| 876 | |||
| 877 | /* | ||
| 878 | * Longest period of inactivity that we tolerate. If we | ||
| 879 | * see dirty data again later, the task will get | ||
| 880 | * recreated automatically. | ||
| 881 | */ | ||
| 882 | max_idle = max(5UL * 60 * HZ, wait_jiffies); | ||
| 883 | if (time_after(jiffies, max_idle + last_active)) | ||
| 884 | break; | ||
| 588 | } | 885 | } |
| 589 | spin_unlock(&inode_lock); | ||
| 590 | iput(old_inode); | ||
| 591 | } else | ||
| 592 | spin_unlock(&inode_lock); | ||
| 593 | 886 | ||
| 594 | return; /* Leave any unwritten inodes on s_io */ | 887 | wait_jiffies = msecs_to_jiffies(dirty_writeback_interval * 10); |
| 888 | schedule_timeout_interruptible(wait_jiffies); | ||
| 889 | try_to_freeze(); | ||
| 890 | } | ||
| 891 | |||
| 892 | return 0; | ||
| 595 | } | 893 | } |
| 596 | EXPORT_SYMBOL_GPL(generic_sync_sb_inodes); | ||
| 597 | 894 | ||
| 598 | static void sync_sb_inodes(struct super_block *sb, | 895 | /* |
| 599 | struct writeback_control *wbc) | 896 | * Schedule writeback for all backing devices. This does WB_SYNC_NONE |
| 897 | * writeback, for integrity writeback see bdi_sync_writeback(). | ||
| 898 | */ | ||
| 899 | static void bdi_writeback_all(struct super_block *sb, long nr_pages) | ||
| 600 | { | 900 | { |
| 601 | generic_sync_sb_inodes(sb, wbc); | 901 | struct wb_writeback_args args = { |
| 902 | .sb = sb, | ||
| 903 | .nr_pages = nr_pages, | ||
| 904 | .sync_mode = WB_SYNC_NONE, | ||
| 905 | }; | ||
| 906 | struct backing_dev_info *bdi; | ||
| 907 | |||
| 908 | rcu_read_lock(); | ||
| 909 | |||
| 910 | list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) { | ||
| 911 | if (!bdi_has_dirty_io(bdi)) | ||
| 912 | continue; | ||
| 913 | |||
| 914 | bdi_alloc_queue_work(bdi, &args); | ||
| 915 | } | ||
| 916 | |||
| 917 | rcu_read_unlock(); | ||
| 602 | } | 918 | } |
| 603 | 919 | ||
| 604 | /* | 920 | /* |
| 605 | * Start writeback of dirty pagecache data against all unlocked inodes. | 921 | * Start writeback of `nr_pages' pages. If `nr_pages' is zero, write back |
| 922 | * the whole world. | ||
| 923 | */ | ||
| 924 | void wakeup_flusher_threads(long nr_pages) | ||
| 925 | { | ||
| 926 | if (nr_pages == 0) | ||
| 927 | nr_pages = global_page_state(NR_FILE_DIRTY) + | ||
| 928 | global_page_state(NR_UNSTABLE_NFS); | ||
| 929 | bdi_writeback_all(NULL, nr_pages); | ||
| 930 | } | ||
| 931 | |||
| 932 | static noinline void block_dump___mark_inode_dirty(struct inode *inode) | ||
| 933 | { | ||
| 934 | if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) { | ||
| 935 | struct dentry *dentry; | ||
| 936 | const char *name = "?"; | ||
| 937 | |||
| 938 | dentry = d_find_alias(inode); | ||
| 939 | if (dentry) { | ||
| 940 | spin_lock(&dentry->d_lock); | ||
| 941 | name = (const char *) dentry->d_name.name; | ||
| 942 | } | ||
| 943 | printk(KERN_DEBUG | ||
| 944 | "%s(%d): dirtied inode %lu (%s) on %s\n", | ||
| 945 | current->comm, task_pid_nr(current), inode->i_ino, | ||
| 946 | name, inode->i_sb->s_id); | ||
| 947 | if (dentry) { | ||
| 948 | spin_unlock(&dentry->d_lock); | ||
| 949 | dput(dentry); | ||
| 950 | } | ||
| 951 | } | ||
| 952 | } | ||
| 953 | |||
| 954 | /** | ||
| 955 | * __mark_inode_dirty - internal function | ||
| 956 | * @inode: inode to mark | ||
| 957 | * @flags: what kind of dirty (i.e. I_DIRTY_SYNC) | ||
| 958 | * Mark an inode as dirty. Callers should use mark_inode_dirty or | ||
| 959 | * mark_inode_dirty_sync. | ||
| 960 | * | ||
| 961 | * Put the inode on the super block's dirty list. | ||
| 606 | * | 962 | * |
| 607 | * Note: | 963 | * CAREFUL! We mark it dirty unconditionally, but move it onto the |
| 608 | * We don't need to grab a reference to superblock here. If it has non-empty | 964 | * dirty list only if it is hashed or if it refers to a blockdev. |
| 609 | * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed | 965 | * If it was not hashed, it will never be added to the dirty list |
| 610 | * past sync_inodes_sb() until the ->s_dirty/s_io/s_more_io lists are all | 966 | * even if it is later hashed, as it will have been marked dirty already. |
| 611 | * empty. Since __sync_single_inode() regains inode_lock before it finally moves | ||
| 612 | * inode from superblock lists we are OK. | ||
| 613 | * | 967 | * |
| 614 | * If `older_than_this' is non-zero then only flush inodes which have a | 968 | * In short, make sure you hash any inodes _before_ you start marking |
| 615 | * flushtime older than *older_than_this. | 969 | * them dirty. |
| 616 | * | 970 | * |
| 617 | * If `bdi' is non-zero then we will scan the first inode against each | 971 | * This function *must* be atomic for the I_DIRTY_PAGES case - |
| 618 | * superblock until we find the matching ones. One group will be the dirty | 972 | * set_page_dirty() is called under spinlock in several places. |
| 619 | * inodes against a filesystem. Then when we hit the dummy blockdev superblock, | 973 | * |
| 620 | * sync_sb_inodes will seekout the blockdev which matches `bdi'. Maybe not | 974 | * Note that for blockdevs, inode->dirtied_when represents the dirtying time of |
| 621 | * super-efficient but we're about to do a ton of I/O... | 975 | * the block-special inode (/dev/hda1) itself. And the ->dirtied_when field of |
| 976 | * the kernel-internal blockdev inode represents the dirtying time of the | ||
| 977 | * blockdev's pages. This is why for I_DIRTY_PAGES we always use | ||
| 978 | * page->mapping->host, so the page-dirtying time is recorded in the internal | ||
| 979 | * blockdev inode. | ||
| 622 | */ | 980 | */ |
| 623 | void | 981 | void __mark_inode_dirty(struct inode *inode, int flags) |
| 624 | writeback_inodes(struct writeback_control *wbc) | ||
| 625 | { | 982 | { |
| 626 | struct super_block *sb; | 983 | struct super_block *sb = inode->i_sb; |
| 627 | 984 | ||
| 628 | might_sleep(); | 985 | /* |
| 629 | spin_lock(&sb_lock); | 986 | * Don't do this for I_DIRTY_PAGES - that doesn't actually |
| 630 | restart: | 987 | * dirty the inode itself |
| 631 | list_for_each_entry_reverse(sb, &super_blocks, s_list) { | 988 | */ |
| 632 | if (sb_has_dirty_inodes(sb)) { | 989 | if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { |
| 633 | /* we're making our own get_super here */ | 990 | if (sb->s_op->dirty_inode) |
| 634 | sb->s_count++; | 991 | sb->s_op->dirty_inode(inode); |
| 635 | spin_unlock(&sb_lock); | 992 | } |
| 636 | /* | 993 | |
| 637 | * If we can't get the readlock, there's no sense in | 994 | /* |
| 638 | * waiting around, most of the time the FS is going to | 995 | * make sure that changes are seen by all cpus before we test i_state |
| 639 | * be unmounted by the time it is released. | 996 | * -- mikulas |
| 640 | */ | 997 | */ |
| 641 | if (down_read_trylock(&sb->s_umount)) { | 998 | smp_mb(); |
| 642 | if (sb->s_root) | 999 | |
| 643 | sync_sb_inodes(sb, wbc); | 1000 | /* avoid the locking if we can */ |
| 644 | up_read(&sb->s_umount); | 1001 | if ((inode->i_state & flags) == flags) |
| 1002 | return; | ||
| 1003 | |||
| 1004 | if (unlikely(block_dump)) | ||
| 1005 | block_dump___mark_inode_dirty(inode); | ||
| 1006 | |||
| 1007 | spin_lock(&inode_lock); | ||
| 1008 | if ((inode->i_state & flags) != flags) { | ||
| 1009 | const int was_dirty = inode->i_state & I_DIRTY; | ||
| 1010 | |||
| 1011 | inode->i_state |= flags; | ||
| 1012 | |||
| 1013 | /* | ||
| 1014 | * If the inode is being synced, just update its dirty state. | ||
| 1015 | * The unlocker will place the inode on the appropriate | ||
| 1016 | * superblock list, based upon its state. | ||
| 1017 | */ | ||
| 1018 | if (inode->i_state & I_SYNC) | ||
| 1019 | goto out; | ||
| 1020 | |||
| 1021 | /* | ||
| 1022 | * Only add valid (hashed) inodes to the superblock's | ||
| 1023 | * dirty list. Add blockdev inodes as well. | ||
| 1024 | */ | ||
| 1025 | if (!S_ISBLK(inode->i_mode)) { | ||
| 1026 | if (hlist_unhashed(&inode->i_hash)) | ||
| 1027 | goto out; | ||
| 1028 | } | ||
| 1029 | if (inode->i_state & (I_FREEING|I_CLEAR)) | ||
| 1030 | goto out; | ||
| 1031 | |||
| 1032 | /* | ||
| 1033 | * If the inode was already on b_dirty/b_io/b_more_io, don't | ||
| 1034 | * reposition it (that would break b_dirty time-ordering). | ||
| 1035 | */ | ||
| 1036 | if (!was_dirty) { | ||
| 1037 | struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; | ||
| 1038 | struct backing_dev_info *bdi = wb->bdi; | ||
| 1039 | |||
| 1040 | if (bdi_cap_writeback_dirty(bdi) && | ||
| 1041 | !test_bit(BDI_registered, &bdi->state)) { | ||
| 1042 | WARN_ON(1); | ||
| 1043 | printk(KERN_ERR "bdi-%s not registered\n", | ||
| 1044 | bdi->name); | ||
| 645 | } | 1045 | } |
| 646 | spin_lock(&sb_lock); | 1046 | |
| 647 | if (__put_super_and_need_restart(sb)) | 1047 | inode->dirtied_when = jiffies; |
| 648 | goto restart; | 1048 | list_move(&inode->i_list, &wb->b_dirty); |
| 649 | } | 1049 | } |
| 650 | if (wbc->nr_to_write <= 0) | ||
| 651 | break; | ||
| 652 | } | 1050 | } |
| 653 | spin_unlock(&sb_lock); | 1051 | out: |
| 1052 | spin_unlock(&inode_lock); | ||
| 654 | } | 1053 | } |
| 1054 | EXPORT_SYMBOL(__mark_inode_dirty); | ||
| 655 | 1055 | ||
| 656 | /* | 1056 | /* |
| 657 | * writeback and wait upon the filesystem's dirty inodes. The caller will | 1057 | * Write out a superblock's list of dirty inodes. A wait will be performed |
| 658 | * do this in two passes - one to write, and one to wait. | 1058 | * upon no inodes, all inodes or the final one, depending upon sync_mode. |
| 1059 | * | ||
| 1060 | * If older_than_this is non-NULL, then only write out inodes which | ||
| 1061 | * had their first dirtying at a time earlier than *older_than_this. | ||
| 1062 | * | ||
| 1063 | * If we're a pdlfush thread, then implement pdflush collision avoidance | ||
| 1064 | * against the entire list. | ||
| 659 | * | 1065 | * |
| 660 | * A finite limit is set on the number of pages which will be written. | 1066 | * If `bdi' is non-zero then we're being asked to writeback a specific queue. |
| 661 | * To prevent infinite livelock of sys_sync(). | 1067 | * This function assumes that the blockdev superblock's inodes are backed by |
| 1068 | * a variety of queues, so all inodes are searched. For other superblocks, | ||
| 1069 | * assume that all inodes are backed by the same queue. | ||
| 662 | * | 1070 | * |
| 663 | * We add in the number of potentially dirty inodes, because each inode write | 1071 | * The inodes to be written are parked on bdi->b_io. They are moved back onto |
| 664 | * can dirty pagecache in the underlying blockdev. | 1072 | * bdi->b_dirty as they are selected for writing. This way, none can be missed |
| 1073 | * on the writer throttling path, and we get decent balancing between many | ||
| 1074 | * throttled threads: we don't want them all piling up on inode_sync_wait. | ||
| 665 | */ | 1075 | */ |
| 666 | void sync_inodes_sb(struct super_block *sb, int wait) | 1076 | static void wait_sb_inodes(struct super_block *sb) |
| 667 | { | 1077 | { |
| 668 | struct writeback_control wbc = { | 1078 | struct inode *inode, *old_inode = NULL; |
| 669 | .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_NONE, | 1079 | |
| 670 | .range_start = 0, | 1080 | /* |
| 671 | .range_end = LLONG_MAX, | 1081 | * We need to be protected against the filesystem going from |
| 672 | }; | 1082 | * r/o to r/w or vice versa. |
| 1083 | */ | ||
| 1084 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | ||
| 1085 | |||
| 1086 | spin_lock(&inode_lock); | ||
| 1087 | |||
| 1088 | /* | ||
| 1089 | * Data integrity sync. Must wait for all pages under writeback, | ||
| 1090 | * because there may have been pages dirtied before our sync | ||
| 1091 | * call, but which had writeout started before we write it out. | ||
| 1092 | * In which case, the inode may not be on the dirty list, but | ||
| 1093 | * we still have to wait for that writeout. | ||
| 1094 | */ | ||
| 1095 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | ||
| 1096 | struct address_space *mapping; | ||
| 1097 | |||
| 1098 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) | ||
| 1099 | continue; | ||
| 1100 | mapping = inode->i_mapping; | ||
| 1101 | if (mapping->nrpages == 0) | ||
| 1102 | continue; | ||
| 1103 | __iget(inode); | ||
| 1104 | spin_unlock(&inode_lock); | ||
| 1105 | /* | ||
| 1106 | * We hold a reference to 'inode' so it couldn't have | ||
| 1107 | * been removed from s_inodes list while we dropped the | ||
| 1108 | * inode_lock. We cannot iput the inode now as we can | ||
| 1109 | * be holding the last reference and we cannot iput it | ||
| 1110 | * under inode_lock. So we keep the reference and iput | ||
| 1111 | * it later. | ||
| 1112 | */ | ||
| 1113 | iput(old_inode); | ||
| 1114 | old_inode = inode; | ||
| 1115 | |||
| 1116 | filemap_fdatawait(mapping); | ||
| 1117 | |||
| 1118 | cond_resched(); | ||
| 673 | 1119 | ||
| 674 | if (!wait) { | 1120 | spin_lock(&inode_lock); |
| 675 | unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY); | 1121 | } |
| 676 | unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS); | 1122 | spin_unlock(&inode_lock); |
| 1123 | iput(old_inode); | ||
| 1124 | } | ||
| 677 | 1125 | ||
| 678 | wbc.nr_to_write = nr_dirty + nr_unstable + | 1126 | /** |
| 1127 | * writeback_inodes_sb - writeback dirty inodes from given super_block | ||
| 1128 | * @sb: the superblock | ||
| 1129 | * | ||
| 1130 | * Start writeback on some inodes on this super_block. No guarantees are made | ||
| 1131 | * on how many (if any) will be written, and this function does not wait | ||
| 1132 | * for IO completion of submitted IO. The number of pages submitted is | ||
| 1133 | * returned. | ||
| 1134 | */ | ||
| 1135 | void writeback_inodes_sb(struct super_block *sb) | ||
| 1136 | { | ||
| 1137 | unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY); | ||
| 1138 | unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS); | ||
| 1139 | long nr_to_write; | ||
| 1140 | |||
| 1141 | nr_to_write = nr_dirty + nr_unstable + | ||
| 679 | (inodes_stat.nr_inodes - inodes_stat.nr_unused); | 1142 | (inodes_stat.nr_inodes - inodes_stat.nr_unused); |
| 680 | } else | ||
| 681 | wbc.nr_to_write = LONG_MAX; /* doesn't actually matter */ | ||
| 682 | 1143 | ||
| 683 | sync_sb_inodes(sb, &wbc); | 1144 | bdi_writeback_all(sb, nr_to_write); |
| 1145 | } | ||
| 1146 | EXPORT_SYMBOL(writeback_inodes_sb); | ||
| 1147 | |||
| 1148 | /** | ||
| 1149 | * sync_inodes_sb - sync sb inode pages | ||
| 1150 | * @sb: the superblock | ||
| 1151 | * | ||
| 1152 | * This function writes and waits on any dirty inode belonging to this | ||
| 1153 | * super_block. The number of pages synced is returned. | ||
| 1154 | */ | ||
| 1155 | void sync_inodes_sb(struct super_block *sb) | ||
| 1156 | { | ||
| 1157 | bdi_sync_writeback(sb->s_bdi, sb); | ||
| 1158 | wait_sb_inodes(sb); | ||
| 684 | } | 1159 | } |
| 1160 | EXPORT_SYMBOL(sync_inodes_sb); | ||
| 685 | 1161 | ||
| 686 | /** | 1162 | /** |
| 687 | * write_inode_now - write an inode to disk | 1163 | * write_inode_now - write an inode to disk |
| @@ -737,57 +1213,3 @@ int sync_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 737 | return ret; | 1213 | return ret; |
| 738 | } | 1214 | } |
| 739 | EXPORT_SYMBOL(sync_inode); | 1215 | EXPORT_SYMBOL(sync_inode); |
| 740 | |||
| 741 | /** | ||
| 742 | * generic_osync_inode - flush all dirty data for a given inode to disk | ||
| 743 | * @inode: inode to write | ||
| 744 | * @mapping: the address_space that should be flushed | ||
| 745 | * @what: what to write and wait upon | ||
| 746 | * | ||
| 747 | * This can be called by file_write functions for files which have the | ||
| 748 | * O_SYNC flag set, to flush dirty writes to disk. | ||
| 749 | * | ||
| 750 | * @what is a bitmask, specifying which part of the inode's data should be | ||
| 751 | * written and waited upon. | ||
| 752 | * | ||
| 753 | * OSYNC_DATA: i_mapping's dirty data | ||
| 754 | * OSYNC_METADATA: the buffers at i_mapping->private_list | ||
| 755 | * OSYNC_INODE: the inode itself | ||
| 756 | */ | ||
| 757 | |||
| 758 | int generic_osync_inode(struct inode *inode, struct address_space *mapping, int what) | ||
| 759 | { | ||
| 760 | int err = 0; | ||
| 761 | int need_write_inode_now = 0; | ||
| 762 | int err2; | ||
| 763 | |||
| 764 | if (what & OSYNC_DATA) | ||
| 765 | err = filemap_fdatawrite(mapping); | ||
| 766 | if (what & (OSYNC_METADATA|OSYNC_DATA)) { | ||
| 767 | err2 = sync_mapping_buffers(mapping); | ||
| 768 | if (!err) | ||
| 769 | err = err2; | ||
| 770 | } | ||
| 771 | if (what & OSYNC_DATA) { | ||
| 772 | err2 = filemap_fdatawait(mapping); | ||
| 773 | if (!err) | ||
| 774 | err = err2; | ||
| 775 | } | ||
| 776 | |||
| 777 | spin_lock(&inode_lock); | ||
| 778 | if ((inode->i_state & I_DIRTY) && | ||
| 779 | ((what & OSYNC_INODE) || (inode->i_state & I_DIRTY_DATASYNC))) | ||
| 780 | need_write_inode_now = 1; | ||
| 781 | spin_unlock(&inode_lock); | ||
| 782 | |||
| 783 | if (need_write_inode_now) { | ||
| 784 | err2 = write_inode_now(inode, 1); | ||
| 785 | if (!err) | ||
| 786 | err = err2; | ||
| 787 | } | ||
| 788 | else | ||
| 789 | inode_sync_wait(inode); | ||
| 790 | |||
| 791 | return err; | ||
| 792 | } | ||
| 793 | EXPORT_SYMBOL(generic_osync_inode); | ||
diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 99c99dfb037..3773fd63d2f 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c | |||
| @@ -61,6 +61,121 @@ static ssize_t fuse_conn_waiting_read(struct file *file, char __user *buf, | |||
| 61 | return simple_read_from_buffer(buf, len, ppos, tmp, size); | 61 | return simple_read_from_buffer(buf, len, ppos, tmp, size); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static ssize_t fuse_conn_limit_read(struct file *file, char __user *buf, | ||
| 65 | size_t len, loff_t *ppos, unsigned val) | ||
| 66 | { | ||
| 67 | char tmp[32]; | ||
| 68 | size_t size = sprintf(tmp, "%u\n", val); | ||
| 69 | |||
| 70 | return simple_read_from_buffer(buf, len, ppos, tmp, size); | ||
| 71 | } | ||
| 72 | |||
| 73 | static ssize_t fuse_conn_limit_write(struct file *file, const char __user *buf, | ||
| 74 | size_t count, loff_t *ppos, unsigned *val, | ||
| 75 | unsigned global_limit) | ||
| 76 | { | ||
| 77 | unsigned long t; | ||
| 78 | char tmp[32]; | ||
| 79 | unsigned limit = (1 << 16) - 1; | ||
| 80 | int err; | ||
| 81 | |||
| 82 | if (*ppos || count >= sizeof(tmp) - 1) | ||
| 83 | return -EINVAL; | ||
| 84 | |||
| 85 | if (copy_from_user(tmp, buf, count)) | ||
| 86 | return -EINVAL; | ||
| 87 | |||
| 88 | tmp[count] = '\0'; | ||
| 89 | |||
| 90 | err = strict_strtoul(tmp, 0, &t); | ||
| 91 | if (err) | ||
| 92 | return err; | ||
| 93 | |||
| 94 | if (!capable(CAP_SYS_ADMIN)) | ||
| 95 | limit = min(limit, global_limit); | ||
| 96 | |||
| 97 | if (t > limit) | ||
| 98 | return -EINVAL; | ||
| 99 | |||
| 100 | *val = t; | ||
| 101 | |||
| 102 | return count; | ||
| 103 | } | ||
| 104 | |||
| 105 | static ssize_t fuse_conn_max_background_read(struct file *file, | ||
| 106 | char __user *buf, size_t len, | ||
| 107 | loff_t *ppos) | ||
| 108 | { | ||
| 109 | struct fuse_conn *fc; | ||
| 110 | unsigned val; | ||
| 111 | |||
| 112 | fc = fuse_ctl_file_conn_get(file); | ||
| 113 | if (!fc) | ||
| 114 | return 0; | ||
| 115 | |||
| 116 | val = fc->max_background; | ||
| 117 | fuse_conn_put(fc); | ||
| 118 | |||
| 119 | return fuse_conn_limit_read(file, buf, len, ppos, val); | ||
| 120 | } | ||
| 121 | |||
| 122 | static ssize_t fuse_conn_max_background_write(struct file *file, | ||
| 123 | const char __user *buf, | ||
| 124 | size_t count, loff_t *ppos) | ||
| 125 | { | ||
| 126 | unsigned val; | ||
| 127 | ssize_t ret; | ||
| 128 | |||
| 129 | ret = fuse_conn_limit_write(file, buf, count, ppos, &val, | ||
| 130 | max_user_bgreq); | ||
| 131 | if (ret > 0) { | ||
| 132 | struct fuse_conn *fc = fuse_ctl_file_conn_get(file); | ||
| 133 | if (fc) { | ||
| 134 | fc->max_background = val; | ||
| 135 | fuse_conn_put(fc); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | return ret; | ||
| 140 | } | ||
| 141 | |||
| 142 | static ssize_t fuse_conn_congestion_threshold_read(struct file *file, | ||
| 143 | char __user *buf, size_t len, | ||
| 144 | loff_t *ppos) | ||
| 145 | { | ||
| 146 | struct fuse_conn *fc; | ||
| 147 | unsigned val; | ||
| 148 | |||
| 149 | fc = fuse_ctl_file_conn_get(file); | ||
| 150 | if (!fc) | ||
| 151 | return 0; | ||
| 152 | |||
| 153 | val = fc->congestion_threshold; | ||
| 154 | fuse_conn_put(fc); | ||
| 155 | |||
| 156 | return fuse_conn_limit_read(file, buf, len, ppos, val); | ||
| 157 | } | ||
| 158 | |||
| 159 | static ssize_t fuse_conn_congestion_threshold_write(struct file *file, | ||
| 160 | const char __user *buf, | ||
| 161 | size_t count, loff_t *ppos) | ||
| 162 | { | ||
| 163 | unsigned val; | ||
| 164 | ssize_t ret; | ||
| 165 | |||
| 166 | ret = fuse_conn_limit_write(file, buf, count, ppos, &val, | ||
| 167 | max_user_congthresh); | ||
| 168 | if (ret > 0) { | ||
| 169 | struct fuse_conn *fc = fuse_ctl_file_conn_get(file); | ||
| 170 | if (fc) { | ||
| 171 | fc->congestion_threshold = val; | ||
| 172 | fuse_conn_put(fc); | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | return ret; | ||
| 177 | } | ||
| 178 | |||
| 64 | static const struct file_operations fuse_ctl_abort_ops = { | 179 | static const struct file_operations fuse_ctl_abort_ops = { |
| 65 | .open = nonseekable_open, | 180 | .open = nonseekable_open, |
| 66 | .write = fuse_conn_abort_write, | 181 | .write = fuse_conn_abort_write, |
| @@ -71,6 +186,18 @@ static const struct file_operations fuse_ctl_waiting_ops = { | |||
| 71 | .read = fuse_conn_waiting_read, | 186 | .read = fuse_conn_waiting_read, |
| 72 | }; | 187 | }; |
| 73 | 188 | ||
| 189 | static const struct file_operations fuse_conn_max_background_ops = { | ||
| 190 | .open = nonseekable_open, | ||
| 191 | .read = fuse_conn_max_background_read, | ||
| 192 | .write = fuse_conn_max_background_write, | ||
| 193 | }; | ||
| 194 | |||
| 195 | static const struct file_operations fuse_conn_congestion_threshold_ops = { | ||
| 196 | .open = nonseekable_open, | ||
| 197 | .read = fuse_conn_congestion_threshold_read, | ||
| 198 | .write = fuse_conn_congestion_threshold_write, | ||
| 199 | }; | ||
| 200 | |||
| 74 | static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, | 201 | static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, |
| 75 | struct fuse_conn *fc, | 202 | struct fuse_conn *fc, |
| 76 | const char *name, | 203 | const char *name, |
| @@ -127,9 +254,14 @@ int fuse_ctl_add_conn(struct fuse_conn *fc) | |||
| 127 | goto err; | 254 | goto err; |
| 128 | 255 | ||
| 129 | if (!fuse_ctl_add_dentry(parent, fc, "waiting", S_IFREG | 0400, 1, | 256 | if (!fuse_ctl_add_dentry(parent, fc, "waiting", S_IFREG | 0400, 1, |
| 130 | NULL, &fuse_ctl_waiting_ops) || | 257 | NULL, &fuse_ctl_waiting_ops) || |
| 131 | !fuse_ctl_add_dentry(parent, fc, "abort", S_IFREG | 0200, 1, | 258 | !fuse_ctl_add_dentry(parent, fc, "abort", S_IFREG | 0200, 1, |
| 132 | NULL, &fuse_ctl_abort_ops)) | 259 | NULL, &fuse_ctl_abort_ops) || |
| 260 | !fuse_ctl_add_dentry(parent, fc, "max_background", S_IFREG | 0600, | ||
| 261 | 1, NULL, &fuse_conn_max_background_ops) || | ||
| 262 | !fuse_ctl_add_dentry(parent, fc, "congestion_threshold", | ||
| 263 | S_IFREG | 0600, 1, NULL, | ||
| 264 | &fuse_conn_congestion_threshold_ops)) | ||
| 133 | goto err; | 265 | goto err; |
| 134 | 266 | ||
| 135 | return 0; | 267 | return 0; |
| @@ -156,7 +288,7 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc) | |||
| 156 | d_drop(dentry); | 288 | d_drop(dentry); |
| 157 | dput(dentry); | 289 | dput(dentry); |
| 158 | } | 290 | } |
| 159 | fuse_control_sb->s_root->d_inode->i_nlink--; | 291 | drop_nlink(fuse_control_sb->s_root->d_inode); |
| 160 | } | 292 | } |
| 161 | 293 | ||
| 162 | static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent) | 294 | static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent) |
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 6484eb75acd..51d9e33d634 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
| @@ -250,7 +250,7 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req) | |||
| 250 | 250 | ||
| 251 | static void flush_bg_queue(struct fuse_conn *fc) | 251 | static void flush_bg_queue(struct fuse_conn *fc) |
| 252 | { | 252 | { |
| 253 | while (fc->active_background < FUSE_MAX_BACKGROUND && | 253 | while (fc->active_background < fc->max_background && |
| 254 | !list_empty(&fc->bg_queue)) { | 254 | !list_empty(&fc->bg_queue)) { |
| 255 | struct fuse_req *req; | 255 | struct fuse_req *req; |
| 256 | 256 | ||
| @@ -280,11 +280,11 @@ __releases(&fc->lock) | |||
| 280 | list_del(&req->intr_entry); | 280 | list_del(&req->intr_entry); |
| 281 | req->state = FUSE_REQ_FINISHED; | 281 | req->state = FUSE_REQ_FINISHED; |
| 282 | if (req->background) { | 282 | if (req->background) { |
| 283 | if (fc->num_background == FUSE_MAX_BACKGROUND) { | 283 | if (fc->num_background == fc->max_background) { |
| 284 | fc->blocked = 0; | 284 | fc->blocked = 0; |
| 285 | wake_up_all(&fc->blocked_waitq); | 285 | wake_up_all(&fc->blocked_waitq); |
| 286 | } | 286 | } |
| 287 | if (fc->num_background == FUSE_CONGESTION_THRESHOLD && | 287 | if (fc->num_background == fc->congestion_threshold && |
| 288 | fc->connected && fc->bdi_initialized) { | 288 | fc->connected && fc->bdi_initialized) { |
| 289 | clear_bdi_congested(&fc->bdi, BLK_RW_SYNC); | 289 | clear_bdi_congested(&fc->bdi, BLK_RW_SYNC); |
| 290 | clear_bdi_congested(&fc->bdi, BLK_RW_ASYNC); | 290 | clear_bdi_congested(&fc->bdi, BLK_RW_ASYNC); |
| @@ -410,9 +410,9 @@ static void fuse_request_send_nowait_locked(struct fuse_conn *fc, | |||
| 410 | { | 410 | { |
| 411 | req->background = 1; | 411 | req->background = 1; |
| 412 | fc->num_background++; | 412 | fc->num_background++; |
| 413 | if (fc->num_background == FUSE_MAX_BACKGROUND) | 413 | if (fc->num_background == fc->max_background) |
| 414 | fc->blocked = 1; | 414 | fc->blocked = 1; |
| 415 | if (fc->num_background == FUSE_CONGESTION_THRESHOLD && | 415 | if (fc->num_background == fc->congestion_threshold && |
| 416 | fc->bdi_initialized) { | 416 | fc->bdi_initialized) { |
| 417 | set_bdi_congested(&fc->bdi, BLK_RW_SYNC); | 417 | set_bdi_congested(&fc->bdi, BLK_RW_SYNC); |
| 418 | set_bdi_congested(&fc->bdi, BLK_RW_ASYNC); | 418 | set_bdi_congested(&fc->bdi, BLK_RW_ASYNC); |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 52b641fc0fa..fc9c79feb5f 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
| @@ -25,12 +25,6 @@ | |||
| 25 | /** Max number of pages that can be used in a single read request */ | 25 | /** Max number of pages that can be used in a single read request */ |
| 26 | #define FUSE_MAX_PAGES_PER_REQ 32 | 26 | #define FUSE_MAX_PAGES_PER_REQ 32 |
| 27 | 27 | ||
| 28 | /** Maximum number of outstanding background requests */ | ||
| 29 | #define FUSE_MAX_BACKGROUND 12 | ||
| 30 | |||
| 31 | /** Congestion starts at 75% of maximum */ | ||
| 32 | #define FUSE_CONGESTION_THRESHOLD (FUSE_MAX_BACKGROUND * 75 / 100) | ||
| 33 | |||
| 34 | /** Bias for fi->writectr, meaning new writepages must not be sent */ | 28 | /** Bias for fi->writectr, meaning new writepages must not be sent */ |
| 35 | #define FUSE_NOWRITE INT_MIN | 29 | #define FUSE_NOWRITE INT_MIN |
| 36 | 30 | ||
| @@ -38,7 +32,7 @@ | |||
| 38 | #define FUSE_NAME_MAX 1024 | 32 | #define FUSE_NAME_MAX 1024 |
| 39 | 33 | ||
| 40 | /** Number of dentries for each connection in the control filesystem */ | 34 | /** Number of dentries for each connection in the control filesystem */ |
| 41 | #define FUSE_CTL_NUM_DENTRIES 3 | 35 | #define FUSE_CTL_NUM_DENTRIES 5 |
| 42 | 36 | ||
| 43 | /** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem | 37 | /** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem |
| 44 | module will check permissions based on the file mode. Otherwise no | 38 | module will check permissions based on the file mode. Otherwise no |
| @@ -55,6 +49,10 @@ extern struct list_head fuse_conn_list; | |||
| 55 | /** Global mutex protecting fuse_conn_list and the control filesystem */ | 49 | /** Global mutex protecting fuse_conn_list and the control filesystem */ |
| 56 | extern struct mutex fuse_mutex; | 50 | extern struct mutex fuse_mutex; |
| 57 | 51 | ||
| 52 | /** Module parameters */ | ||
| 53 | extern unsigned max_user_bgreq; | ||
| 54 | extern unsigned max_user_congthresh; | ||
| 55 | |||
| 58 | /** FUSE inode */ | 56 | /** FUSE inode */ |
| 59 | struct fuse_inode { | 57 | struct fuse_inode { |
| 60 | /** Inode data */ | 58 | /** Inode data */ |
| @@ -349,6 +347,12 @@ struct fuse_conn { | |||
| 349 | /** rbtree of fuse_files waiting for poll events indexed by ph */ | 347 | /** rbtree of fuse_files waiting for poll events indexed by ph */ |
| 350 | struct rb_root polled_files; | 348 | struct rb_root polled_files; |
| 351 | 349 | ||
| 350 | /** Maximum number of outstanding background requests */ | ||
| 351 | unsigned max_background; | ||
| 352 | |||
| 353 | /** Number of background requests at which congestion starts */ | ||
| 354 | unsigned congestion_threshold; | ||
| 355 | |||
| 352 | /** Number of requests currently in the background */ | 356 | /** Number of requests currently in the background */ |
| 353 | unsigned num_background; | 357 | unsigned num_background; |
| 354 | 358 | ||
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index f91ccc4a189..6da947daabd 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/seq_file.h> | 14 | #include <linux/seq_file.h> |
| 15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/moduleparam.h> | ||
| 17 | #include <linux/parser.h> | 18 | #include <linux/parser.h> |
| 18 | #include <linux/statfs.h> | 19 | #include <linux/statfs.h> |
| 19 | #include <linux/random.h> | 20 | #include <linux/random.h> |
| @@ -28,10 +29,34 @@ static struct kmem_cache *fuse_inode_cachep; | |||
| 28 | struct list_head fuse_conn_list; | 29 | struct list_head fuse_conn_list; |
| 29 | DEFINE_MUTEX(fuse_mutex); | 30 | DEFINE_MUTEX(fuse_mutex); |
| 30 | 31 | ||
| 32 | static int set_global_limit(const char *val, struct kernel_param *kp); | ||
| 33 | |||
| 34 | unsigned max_user_bgreq; | ||
| 35 | module_param_call(max_user_bgreq, set_global_limit, param_get_uint, | ||
| 36 | &max_user_bgreq, 0644); | ||
| 37 | __MODULE_PARM_TYPE(max_user_bgreq, "uint"); | ||
| 38 | MODULE_PARM_DESC(max_user_bgreq, | ||
| 39 | "Global limit for the maximum number of backgrounded requests an " | ||
| 40 | "unprivileged user can set"); | ||
| 41 | |||
| 42 | unsigned max_user_congthresh; | ||
| 43 | module_param_call(max_user_congthresh, set_global_limit, param_get_uint, | ||
| 44 | &max_user_congthresh, 0644); | ||
| 45 | __MODULE_PARM_TYPE(max_user_congthresh, "uint"); | ||
| 46 | MODULE_PARM_DESC(max_user_congthresh, | ||
| 47 | "Global limit for the maximum congestion threshold an " | ||
| 48 | "unprivileged user can set"); | ||
| 49 | |||
| 31 | #define FUSE_SUPER_MAGIC 0x65735546 | 50 | #define FUSE_SUPER_MAGIC 0x65735546 |
| 32 | 51 | ||
| 33 | #define FUSE_DEFAULT_BLKSIZE 512 | 52 | #define FUSE_DEFAULT_BLKSIZE 512 |
| 34 | 53 | ||
| 54 | /** Maximum number of outstanding background requests */ | ||
| 55 | #define FUSE_DEFAULT_MAX_BACKGROUND 12 | ||
| 56 | |||
| 57 | /** Congestion starts at 75% of maximum */ | ||
| 58 | #define FUSE_DEFAULT_CONGESTION_THRESHOLD (FUSE_DEFAULT_MAX_BACKGROUND * 3 / 4) | ||
| 59 | |||
| 35 | struct fuse_mount_data { | 60 | struct fuse_mount_data { |
| 36 | int fd; | 61 | int fd; |
| 37 | unsigned rootmode; | 62 | unsigned rootmode; |
| @@ -517,6 +542,8 @@ void fuse_conn_init(struct fuse_conn *fc) | |||
| 517 | INIT_LIST_HEAD(&fc->bg_queue); | 542 | INIT_LIST_HEAD(&fc->bg_queue); |
| 518 | INIT_LIST_HEAD(&fc->entry); | 543 | INIT_LIST_HEAD(&fc->entry); |
| 519 | atomic_set(&fc->num_waiting, 0); | 544 | atomic_set(&fc->num_waiting, 0); |
| 545 | fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND; | ||
| 546 | fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD; | ||
| 520 | fc->khctr = 0; | 547 | fc->khctr = 0; |
| 521 | fc->polled_files = RB_ROOT; | 548 | fc->polled_files = RB_ROOT; |
| 522 | fc->reqctr = 0; | 549 | fc->reqctr = 0; |
| @@ -727,6 +754,54 @@ static const struct super_operations fuse_super_operations = { | |||
| 727 | .show_options = fuse_show_options, | 754 | .show_options = fuse_show_options, |
| 728 | }; | 755 | }; |
| 729 | 756 | ||
| 757 | static void sanitize_global_limit(unsigned *limit) | ||
| 758 | { | ||
| 759 | if (*limit == 0) | ||
| 760 | *limit = ((num_physpages << PAGE_SHIFT) >> 13) / | ||
| 761 | sizeof(struct fuse_req); | ||
| 762 | |||
| 763 | if (*limit >= 1 << 16) | ||
| 764 | *limit = (1 << 16) - 1; | ||
| 765 | } | ||
| 766 | |||
| 767 | static int set_global_limit(const char *val, struct kernel_param *kp) | ||
| 768 | { | ||
| 769 | int rv; | ||
| 770 | |||
| 771 | rv = param_set_uint(val, kp); | ||
| 772 | if (rv) | ||
| 773 | return rv; | ||
| 774 | |||
| 775 | sanitize_global_limit((unsigned *)kp->arg); | ||
| 776 | |||
| 777 | return 0; | ||
| 778 | } | ||
| 779 | |||
| 780 | static void process_init_limits(struct fuse_conn *fc, struct fuse_init_out *arg) | ||
| 781 | { | ||
| 782 | int cap_sys_admin = capable(CAP_SYS_ADMIN); | ||
| 783 | |||
| 784 | if (arg->minor < 13) | ||
| 785 | return; | ||
| 786 | |||
| 787 | sanitize_global_limit(&max_user_bgreq); | ||
| 788 | sanitize_global_limit(&max_user_congthresh); | ||
| 789 | |||
| 790 | if (arg->max_background) { | ||
| 791 | fc->max_background = arg->max_background; | ||
| 792 | |||
| 793 | if (!cap_sys_admin && fc->max_background > max_user_bgreq) | ||
| 794 | fc->max_background = max_user_bgreq; | ||
| 795 | } | ||
| 796 | if (arg->congestion_threshold) { | ||
| 797 | fc->congestion_threshold = arg->congestion_threshold; | ||
| 798 | |||
| 799 | if (!cap_sys_admin && | ||
| 800 | fc->congestion_threshold > max_user_congthresh) | ||
| 801 | fc->congestion_threshold = max_user_congthresh; | ||
| 802 | } | ||
| 803 | } | ||
| 804 | |||
| 730 | static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | 805 | static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) |
| 731 | { | 806 | { |
| 732 | struct fuse_init_out *arg = &req->misc.init_out; | 807 | struct fuse_init_out *arg = &req->misc.init_out; |
| @@ -736,6 +811,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
| 736 | else { | 811 | else { |
| 737 | unsigned long ra_pages; | 812 | unsigned long ra_pages; |
| 738 | 813 | ||
| 814 | process_init_limits(fc, arg); | ||
| 815 | |||
| 739 | if (arg->minor >= 6) { | 816 | if (arg->minor >= 6) { |
| 740 | ra_pages = arg->max_readahead / PAGE_CACHE_SIZE; | 817 | ra_pages = arg->max_readahead / PAGE_CACHE_SIZE; |
| 741 | if (arg->flags & FUSE_ASYNC_READ) | 818 | if (arg->flags & FUSE_ASYNC_READ) |
| @@ -801,6 +878,7 @@ static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb) | |||
| 801 | { | 878 | { |
| 802 | int err; | 879 | int err; |
| 803 | 880 | ||
| 881 | fc->bdi.name = "fuse"; | ||
| 804 | fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; | 882 | fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; |
| 805 | fc->bdi.unplug_io_fn = default_unplug_io_fn; | 883 | fc->bdi.unplug_io_fn = default_unplug_io_fn; |
| 806 | /* fuse does it's own writeback accounting */ | 884 | /* fuse does it's own writeback accounting */ |
| @@ -893,6 +971,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
| 893 | if (err) | 971 | if (err) |
| 894 | goto err_put_conn; | 972 | goto err_put_conn; |
| 895 | 973 | ||
| 974 | sb->s_bdi = &fc->bdi; | ||
| 975 | |||
| 896 | /* Handle umasking inside the fuse code */ | 976 | /* Handle umasking inside the fuse code */ |
| 897 | if (sb->s_flags & MS_POSIXACL) | 977 | if (sb->s_flags & MS_POSIXACL) |
| 898 | fc->dont_mask = 1; | 978 | fc->dont_mask = 1; |
| @@ -1147,6 +1227,9 @@ static int __init fuse_init(void) | |||
| 1147 | if (res) | 1227 | if (res) |
| 1148 | goto err_sysfs_cleanup; | 1228 | goto err_sysfs_cleanup; |
| 1149 | 1229 | ||
| 1230 | sanitize_global_limit(&max_user_bgreq); | ||
| 1231 | sanitize_global_limit(&max_user_congthresh); | ||
| 1232 | |||
| 1150 | return 0; | 1233 | return 0; |
| 1151 | 1234 | ||
| 1152 | err_sysfs_cleanup: | 1235 | err_sysfs_cleanup: |
diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 3da2f1f4f73..21f7e46da4c 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | EXTRA_CFLAGS := -I$(src) | 1 | EXTRA_CFLAGS := -I$(src) |
| 2 | obj-$(CONFIG_GFS2_FS) += gfs2.o | 2 | obj-$(CONFIG_GFS2_FS) += gfs2.o |
| 3 | gfs2-y := acl.o bmap.o dir.o eaops.o eattr.o glock.o \ | 3 | gfs2-y := acl.o bmap.o dir.o xattr.o glock.o \ |
| 4 | glops.o inode.o log.o lops.o main.o meta_io.o \ | 4 | glops.o inode.o log.o lops.o main.o meta_io.o \ |
| 5 | aops.o dentry.o export.o file.o \ | 5 | aops.o dentry.o export.o file.o \ |
| 6 | ops_fstype.o ops_inode.o quota.o \ | 6 | ops_fstype.o ops_inode.o quota.o \ |
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index fa881bdc3d8..3fc4e3ac7d8 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c | |||
| @@ -19,8 +19,7 @@ | |||
| 19 | #include "gfs2.h" | 19 | #include "gfs2.h" |
| 20 | #include "incore.h" | 20 | #include "incore.h" |
| 21 | #include "acl.h" | 21 | #include "acl.h" |
| 22 | #include "eaops.h" | 22 | #include "xattr.h" |
| 23 | #include "eattr.h" | ||
| 24 | #include "glock.h" | 23 | #include "glock.h" |
| 25 | #include "inode.h" | 24 | #include "inode.h" |
| 26 | #include "meta_io.h" | 25 | #include "meta_io.h" |
| @@ -31,8 +30,7 @@ | |||
| 31 | #define ACL_DEFAULT 0 | 30 | #define ACL_DEFAULT 0 |
| 32 | 31 | ||
| 33 | int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, | 32 | int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, |
| 34 | struct gfs2_ea_request *er, | 33 | struct gfs2_ea_request *er, int *remove, mode_t *mode) |
| 35 | int *remove, mode_t *mode) | ||
| 36 | { | 34 | { |
| 37 | struct posix_acl *acl; | 35 | struct posix_acl *acl; |
| 38 | int error; | 36 | int error; |
| @@ -83,30 +81,20 @@ int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access) | |||
| 83 | return 0; | 81 | return 0; |
| 84 | } | 82 | } |
| 85 | 83 | ||
| 86 | static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl, | 84 | static int acl_get(struct gfs2_inode *ip, const char *name, |
| 87 | struct gfs2_ea_location *el, char **data, unsigned int *len) | 85 | struct posix_acl **acl, struct gfs2_ea_location *el, |
| 86 | char **datap, unsigned int *lenp) | ||
| 88 | { | 87 | { |
| 89 | struct gfs2_ea_request er; | 88 | char *data; |
| 90 | struct gfs2_ea_location el_this; | 89 | unsigned int len; |
| 91 | int error; | 90 | int error; |
| 92 | 91 | ||
| 92 | el->el_bh = NULL; | ||
| 93 | |||
| 93 | if (!ip->i_eattr) | 94 | if (!ip->i_eattr) |
| 94 | return 0; | 95 | return 0; |
| 95 | 96 | ||
| 96 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 97 | error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, el); |
| 97 | if (access) { | ||
| 98 | er.er_name = GFS2_POSIX_ACL_ACCESS; | ||
| 99 | er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN; | ||
| 100 | } else { | ||
| 101 | er.er_name = GFS2_POSIX_ACL_DEFAULT; | ||
| 102 | er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN; | ||
| 103 | } | ||
| 104 | er.er_type = GFS2_EATYPE_SYS; | ||
| 105 | |||
| 106 | if (!el) | ||
| 107 | el = &el_this; | ||
| 108 | |||
| 109 | error = gfs2_ea_find(ip, &er, el); | ||
| 110 | if (error) | 98 | if (error) |
| 111 | return error; | 99 | return error; |
| 112 | if (!el->el_ea) | 100 | if (!el->el_ea) |
| @@ -114,32 +102,31 @@ static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl, | |||
| 114 | if (!GFS2_EA_DATA_LEN(el->el_ea)) | 102 | if (!GFS2_EA_DATA_LEN(el->el_ea)) |
| 115 | goto out; | 103 | goto out; |
| 116 | 104 | ||
| 117 | er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea); | 105 | len = GFS2_EA_DATA_LEN(el->el_ea); |
| 118 | er.er_data = kmalloc(er.er_data_len, GFP_NOFS); | 106 | data = kmalloc(len, GFP_NOFS); |
| 119 | error = -ENOMEM; | 107 | error = -ENOMEM; |
| 120 | if (!er.er_data) | 108 | if (!data) |
| 121 | goto out; | 109 | goto out; |
| 122 | 110 | ||
| 123 | error = gfs2_ea_get_copy(ip, el, er.er_data); | 111 | error = gfs2_ea_get_copy(ip, el, data, len); |
| 124 | if (error) | 112 | if (error < 0) |
| 125 | goto out_kfree; | 113 | goto out_kfree; |
| 114 | error = 0; | ||
| 126 | 115 | ||
| 127 | if (acl) { | 116 | if (acl) { |
| 128 | *acl = posix_acl_from_xattr(er.er_data, er.er_data_len); | 117 | *acl = posix_acl_from_xattr(data, len); |
| 129 | if (IS_ERR(*acl)) | 118 | if (IS_ERR(*acl)) |
| 130 | error = PTR_ERR(*acl); | 119 | error = PTR_ERR(*acl); |
| 131 | } | 120 | } |
| 132 | 121 | ||
| 133 | out_kfree: | 122 | out_kfree: |
| 134 | if (error || !data) | 123 | if (error || !datap) { |
| 135 | kfree(er.er_data); | 124 | kfree(data); |
| 136 | else { | 125 | } else { |
| 137 | *data = er.er_data; | 126 | *datap = data; |
| 138 | *len = er.er_data_len; | 127 | *lenp = len; |
| 139 | } | 128 | } |
| 140 | out: | 129 | out: |
| 141 | if (error || el == &el_this) | ||
| 142 | brelse(el->el_bh); | ||
| 143 | return error; | 130 | return error; |
| 144 | } | 131 | } |
| 145 | 132 | ||
| @@ -153,10 +140,12 @@ out: | |||
| 153 | 140 | ||
| 154 | int gfs2_check_acl(struct inode *inode, int mask) | 141 | int gfs2_check_acl(struct inode *inode, int mask) |
| 155 | { | 142 | { |
| 143 | struct gfs2_ea_location el; | ||
| 156 | struct posix_acl *acl = NULL; | 144 | struct posix_acl *acl = NULL; |
| 157 | int error; | 145 | int error; |
| 158 | 146 | ||
| 159 | error = acl_get(GFS2_I(inode), ACL_ACCESS, &acl, NULL, NULL, NULL); | 147 | error = acl_get(GFS2_I(inode), GFS2_POSIX_ACL_ACCESS, &acl, &el, NULL, NULL); |
| 148 | brelse(el.el_bh); | ||
| 160 | if (error) | 149 | if (error) |
| 161 | return error; | 150 | return error; |
| 162 | 151 | ||
| @@ -196,10 +185,12 @@ static int munge_mode(struct gfs2_inode *ip, mode_t mode) | |||
| 196 | 185 | ||
| 197 | int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | 186 | int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) |
| 198 | { | 187 | { |
| 188 | struct gfs2_ea_location el; | ||
| 199 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 189 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
| 200 | struct posix_acl *acl = NULL, *clone; | 190 | struct posix_acl *acl = NULL, *clone; |
| 201 | struct gfs2_ea_request er; | ||
| 202 | mode_t mode = ip->i_inode.i_mode; | 191 | mode_t mode = ip->i_inode.i_mode; |
| 192 | char *data = NULL; | ||
| 193 | unsigned int len; | ||
| 203 | int error; | 194 | int error; |
| 204 | 195 | ||
| 205 | if (!sdp->sd_args.ar_posix_acl) | 196 | if (!sdp->sd_args.ar_posix_acl) |
| @@ -207,11 +198,8 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
| 207 | if (S_ISLNK(ip->i_inode.i_mode)) | 198 | if (S_ISLNK(ip->i_inode.i_mode)) |
| 208 | return 0; | 199 | return 0; |
| 209 | 200 | ||
| 210 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 201 | error = acl_get(dip, GFS2_POSIX_ACL_DEFAULT, &acl, &el, &data, &len); |
| 211 | er.er_type = GFS2_EATYPE_SYS; | 202 | brelse(el.el_bh); |
| 212 | |||
| 213 | error = acl_get(dip, ACL_DEFAULT, &acl, NULL, | ||
| 214 | &er.er_data, &er.er_data_len); | ||
| 215 | if (error) | 203 | if (error) |
| 216 | return error; | 204 | return error; |
| 217 | if (!acl) { | 205 | if (!acl) { |
| @@ -229,9 +217,8 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
| 229 | acl = clone; | 217 | acl = clone; |
| 230 | 218 | ||
| 231 | if (S_ISDIR(ip->i_inode.i_mode)) { | 219 | if (S_ISDIR(ip->i_inode.i_mode)) { |
| 232 | er.er_name = GFS2_POSIX_ACL_DEFAULT; | 220 | error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS, |
| 233 | er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN; | 221 | GFS2_POSIX_ACL_DEFAULT, data, len, 0); |
| 234 | error = gfs2_system_eaops.eo_set(ip, &er); | ||
| 235 | if (error) | 222 | if (error) |
| 236 | goto out; | 223 | goto out; |
| 237 | } | 224 | } |
| @@ -239,21 +226,19 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
| 239 | error = posix_acl_create_masq(acl, &mode); | 226 | error = posix_acl_create_masq(acl, &mode); |
| 240 | if (error < 0) | 227 | if (error < 0) |
| 241 | goto out; | 228 | goto out; |
| 242 | if (error > 0) { | 229 | if (error == 0) |
| 243 | er.er_name = GFS2_POSIX_ACL_ACCESS; | 230 | goto munge; |
| 244 | er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN; | ||
| 245 | posix_acl_to_xattr(acl, er.er_data, er.er_data_len); | ||
| 246 | er.er_mode = mode; | ||
| 247 | er.er_flags = GFS2_ERF_MODE; | ||
| 248 | error = gfs2_system_eaops.eo_set(ip, &er); | ||
| 249 | if (error) | ||
| 250 | goto out; | ||
| 251 | } else | ||
| 252 | munge_mode(ip, mode); | ||
| 253 | 231 | ||
| 232 | posix_acl_to_xattr(acl, data, len); | ||
| 233 | error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS, | ||
| 234 | GFS2_POSIX_ACL_ACCESS, data, len, 0); | ||
| 235 | if (error) | ||
| 236 | goto out; | ||
| 237 | munge: | ||
| 238 | error = munge_mode(ip, mode); | ||
| 254 | out: | 239 | out: |
| 255 | posix_acl_release(acl); | 240 | posix_acl_release(acl); |
| 256 | kfree(er.er_data); | 241 | kfree(data); |
| 257 | return error; | 242 | return error; |
| 258 | } | 243 | } |
| 259 | 244 | ||
| @@ -265,9 +250,9 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) | |||
| 265 | unsigned int len; | 250 | unsigned int len; |
| 266 | int error; | 251 | int error; |
| 267 | 252 | ||
| 268 | error = acl_get(ip, ACL_ACCESS, &acl, &el, &data, &len); | 253 | error = acl_get(ip, GFS2_POSIX_ACL_ACCESS, &acl, &el, &data, &len); |
| 269 | if (error) | 254 | if (error) |
| 270 | return error; | 255 | goto out_brelse; |
| 271 | if (!acl) | 256 | if (!acl) |
| 272 | return gfs2_setattr_simple(ip, attr); | 257 | return gfs2_setattr_simple(ip, attr); |
| 273 | 258 | ||
| @@ -286,8 +271,9 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) | |||
| 286 | 271 | ||
| 287 | out: | 272 | out: |
| 288 | posix_acl_release(acl); | 273 | posix_acl_release(acl); |
| 289 | brelse(el.el_bh); | ||
| 290 | kfree(data); | 274 | kfree(data); |
| 275 | out_brelse: | ||
| 276 | brelse(el.el_bh); | ||
| 291 | return error; | 277 | return error; |
| 292 | } | 278 | } |
| 293 | 279 | ||
diff --git a/fs/gfs2/dentry.c b/fs/gfs2/dentry.c index 022c66cd560..91beddadd38 100644 --- a/fs/gfs2/dentry.c +++ b/fs/gfs2/dentry.c | |||
| @@ -107,8 +107,26 @@ static int gfs2_dhash(struct dentry *dentry, struct qstr *str) | |||
| 107 | return 0; | 107 | return 0; |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | static int gfs2_dentry_delete(struct dentry *dentry) | ||
| 111 | { | ||
| 112 | struct gfs2_inode *ginode; | ||
| 113 | |||
| 114 | if (!dentry->d_inode) | ||
| 115 | return 0; | ||
| 116 | |||
| 117 | ginode = GFS2_I(dentry->d_inode); | ||
| 118 | if (!ginode->i_iopen_gh.gh_gl) | ||
| 119 | return 0; | ||
| 120 | |||
| 121 | if (test_bit(GLF_DEMOTE, &ginode->i_iopen_gh.gh_gl->gl_flags)) | ||
| 122 | return 1; | ||
| 123 | |||
| 124 | return 0; | ||
| 125 | } | ||
| 126 | |||
| 110 | const struct dentry_operations gfs2_dops = { | 127 | const struct dentry_operations gfs2_dops = { |
| 111 | .d_revalidate = gfs2_drevalidate, | 128 | .d_revalidate = gfs2_drevalidate, |
| 112 | .d_hash = gfs2_dhash, | 129 | .d_hash = gfs2_dhash, |
| 130 | .d_delete = gfs2_dentry_delete, | ||
| 113 | }; | 131 | }; |
| 114 | 132 | ||
diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c deleted file mode 100644 index dee9b03e5b3..00000000000 --- a/fs/gfs2/eaops.c +++ /dev/null | |||
| @@ -1,157 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
| 3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||
| 4 | * | ||
| 5 | * This copyrighted material is made available to anyone wishing to use, | ||
| 6 | * modify, copy, or redistribute it subject to the terms and conditions | ||
| 7 | * of the GNU General Public License version 2. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/slab.h> | ||
| 11 | #include <linux/spinlock.h> | ||
| 12 | #include <linux/completion.h> | ||
| 13 | #include <linux/buffer_head.h> | ||
| 14 | #include <linux/capability.h> | ||
| 15 | #include <linux/xattr.h> | ||
| 16 | #include <linux/gfs2_ondisk.h> | ||
| 17 | #include <asm/uaccess.h> | ||
| 18 | |||
| 19 | #include "gfs2.h" | ||
| 20 | #include "incore.h" | ||
| 21 | #include "acl.h" | ||
| 22 | #include "eaops.h" | ||
| 23 | #include "eattr.h" | ||
| 24 | #include "util.h" | ||
| 25 | |||
| 26 | /** | ||
| 27 | * gfs2_ea_name2type - get the type of the ea, and truncate type from the name | ||
| 28 | * @namep: ea name, possibly with type appended | ||
| 29 | * | ||
| 30 | * Returns: GFS2_EATYPE_XXX | ||
| 31 | */ | ||
| 32 | |||
| 33 | unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name) | ||
| 34 | { | ||
| 35 | unsigned int type; | ||
| 36 | |||
| 37 | if (strncmp(name, "system.", 7) == 0) { | ||
| 38 | type = GFS2_EATYPE_SYS; | ||
| 39 | if (truncated_name) | ||
| 40 | *truncated_name = name + sizeof("system.") - 1; | ||
| 41 | } else if (strncmp(name, "user.", 5) == 0) { | ||
| 42 | type = GFS2_EATYPE_USR; | ||
| 43 | if (truncated_name) | ||
| 44 | *truncated_name = name + sizeof("user.") - 1; | ||
| 45 | } else if (strncmp(name, "security.", 9) == 0) { | ||
| 46 | type = GFS2_EATYPE_SECURITY; | ||
| 47 | if (truncated_name) | ||
| 48 | *truncated_name = name + sizeof("security.") - 1; | ||
| 49 | } else { | ||
| 50 | type = GFS2_EATYPE_UNUSED; | ||
| 51 | if (truncated_name) | ||
| 52 | *truncated_name = NULL; | ||
| 53 | } | ||
| 54 | |||
| 55 | return type; | ||
| 56 | } | ||
| 57 | |||
| 58 | static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
| 59 | { | ||
| 60 | if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) && | ||
| 61 | !GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) && | ||
| 62 | !capable(CAP_SYS_ADMIN)) | ||
| 63 | return -EPERM; | ||
| 64 | |||
| 65 | if (GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl == 0 && | ||
| 66 | (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) || | ||
| 67 | GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len))) | ||
| 68 | return -EOPNOTSUPP; | ||
| 69 | |||
| 70 | return gfs2_ea_get_i(ip, er); | ||
| 71 | } | ||
| 72 | |||
| 73 | static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
| 74 | { | ||
| 75 | int remove = 0; | ||
| 76 | int error; | ||
| 77 | |||
| 78 | if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) { | ||
| 79 | if (!(er->er_flags & GFS2_ERF_MODE)) { | ||
| 80 | er->er_mode = ip->i_inode.i_mode; | ||
| 81 | er->er_flags |= GFS2_ERF_MODE; | ||
| 82 | } | ||
| 83 | error = gfs2_acl_validate_set(ip, 1, er, | ||
| 84 | &remove, &er->er_mode); | ||
| 85 | if (error) | ||
| 86 | return error; | ||
| 87 | error = gfs2_ea_set_i(ip, er); | ||
| 88 | if (error) | ||
| 89 | return error; | ||
| 90 | if (remove) | ||
| 91 | gfs2_ea_remove_i(ip, er); | ||
| 92 | return 0; | ||
| 93 | |||
| 94 | } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) { | ||
| 95 | error = gfs2_acl_validate_set(ip, 0, er, | ||
| 96 | &remove, NULL); | ||
| 97 | if (error) | ||
| 98 | return error; | ||
| 99 | if (!remove) | ||
| 100 | error = gfs2_ea_set_i(ip, er); | ||
| 101 | else { | ||
| 102 | error = gfs2_ea_remove_i(ip, er); | ||
| 103 | if (error == -ENODATA) | ||
| 104 | error = 0; | ||
| 105 | } | ||
| 106 | return error; | ||
| 107 | } | ||
| 108 | |||
| 109 | return -EPERM; | ||
| 110 | } | ||
| 111 | |||
| 112 | static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
| 113 | { | ||
| 114 | if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) { | ||
| 115 | int error = gfs2_acl_validate_remove(ip, 1); | ||
| 116 | if (error) | ||
| 117 | return error; | ||
| 118 | |||
| 119 | } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) { | ||
| 120 | int error = gfs2_acl_validate_remove(ip, 0); | ||
| 121 | if (error) | ||
| 122 | return error; | ||
| 123 | |||
| 124 | } else | ||
| 125 | return -EPERM; | ||
| 126 | |||
| 127 | return gfs2_ea_remove_i(ip, er); | ||
| 128 | } | ||
| 129 | |||
| 130 | static const struct gfs2_eattr_operations gfs2_user_eaops = { | ||
| 131 | .eo_get = gfs2_ea_get_i, | ||
| 132 | .eo_set = gfs2_ea_set_i, | ||
| 133 | .eo_remove = gfs2_ea_remove_i, | ||
| 134 | .eo_name = "user", | ||
| 135 | }; | ||
| 136 | |||
| 137 | const struct gfs2_eattr_operations gfs2_system_eaops = { | ||
| 138 | .eo_get = system_eo_get, | ||
| 139 | .eo_set = system_eo_set, | ||
| 140 | .eo_remove = system_eo_remove, | ||
| 141 | .eo_name = "system", | ||
| 142 | }; | ||
| 143 | |||
| 144 | static const struct gfs2_eattr_operations gfs2_security_eaops = { | ||
| 145 | .eo_get = gfs2_ea_get_i, | ||
| 146 | .eo_set = gfs2_ea_set_i, | ||
| 147 | .eo_remove = gfs2_ea_remove_i, | ||
| 148 | .eo_name = "security", | ||
| 149 | }; | ||
| 150 | |||
| 151 | const struct gfs2_eattr_operations *gfs2_ea_ops[] = { | ||
| 152 | NULL, | ||
| 153 | &gfs2_user_eaops, | ||
| 154 | &gfs2_system_eaops, | ||
| 155 | &gfs2_security_eaops, | ||
| 156 | }; | ||
| 157 | |||
diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h deleted file mode 100644 index da2f7fbbb40..00000000000 --- a/fs/gfs2/eaops.h +++ /dev/null | |||
| @@ -1,30 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
| 3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||
| 4 | * | ||
| 5 | * This copyrighted material is made available to anyone wishing to use, | ||
| 6 | * modify, copy, or redistribute it subject to the terms and conditions | ||
| 7 | * of the GNU General Public License version 2. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef __EAOPS_DOT_H__ | ||
| 11 | #define __EAOPS_DOT_H__ | ||
| 12 | |||
| 13 | struct gfs2_ea_request; | ||
| 14 | struct gfs2_inode; | ||
| 15 | |||
| 16 | struct gfs2_eattr_operations { | ||
| 17 | int (*eo_get) (struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
| 18 | int (*eo_set) (struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
| 19 | int (*eo_remove) (struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
| 20 | char *eo_name; | ||
| 21 | }; | ||
| 22 | |||
| 23 | unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name); | ||
| 24 | |||
| 25 | extern const struct gfs2_eattr_operations gfs2_system_eaops; | ||
| 26 | |||
| 27 | extern const struct gfs2_eattr_operations *gfs2_ea_ops[]; | ||
| 28 | |||
| 29 | #endif /* __EAOPS_DOT_H__ */ | ||
| 30 | |||
diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index 9200ef22171..d15876e9aa2 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c | |||
| @@ -143,17 +143,14 @@ static struct dentry *gfs2_get_parent(struct dentry *child) | |||
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | static struct dentry *gfs2_get_dentry(struct super_block *sb, | 145 | static struct dentry *gfs2_get_dentry(struct super_block *sb, |
| 146 | struct gfs2_inum_host *inum) | 146 | struct gfs2_inum_host *inum) |
| 147 | { | 147 | { |
| 148 | struct gfs2_sbd *sdp = sb->s_fs_info; | 148 | struct gfs2_sbd *sdp = sb->s_fs_info; |
| 149 | struct gfs2_holder i_gh, ri_gh, rgd_gh; | 149 | struct gfs2_holder i_gh; |
| 150 | struct gfs2_rgrpd *rgd; | ||
| 151 | struct inode *inode; | 150 | struct inode *inode; |
| 152 | struct dentry *dentry; | 151 | struct dentry *dentry; |
| 153 | int error; | 152 | int error; |
| 154 | 153 | ||
| 155 | /* System files? */ | ||
| 156 | |||
| 157 | inode = gfs2_ilookup(sb, inum->no_addr); | 154 | inode = gfs2_ilookup(sb, inum->no_addr); |
| 158 | if (inode) { | 155 | if (inode) { |
| 159 | if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) { | 156 | if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) { |
| @@ -168,29 +165,11 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, | |||
| 168 | if (error) | 165 | if (error) |
| 169 | return ERR_PTR(error); | 166 | return ERR_PTR(error); |
| 170 | 167 | ||
| 171 | error = gfs2_rindex_hold(sdp, &ri_gh); | 168 | error = gfs2_check_blk_type(sdp, inum->no_addr, GFS2_BLKST_DINODE); |
| 172 | if (error) | 169 | if (error) |
| 173 | goto fail; | 170 | goto fail; |
| 174 | 171 | ||
| 175 | error = -EINVAL; | 172 | inode = gfs2_inode_lookup(sb, DT_UNKNOWN, inum->no_addr, 0, 0); |
| 176 | rgd = gfs2_blk2rgrpd(sdp, inum->no_addr); | ||
| 177 | if (!rgd) | ||
| 178 | goto fail_rindex; | ||
| 179 | |||
| 180 | error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh); | ||
| 181 | if (error) | ||
| 182 | goto fail_rindex; | ||
| 183 | |||
| 184 | error = -ESTALE; | ||
| 185 | if (gfs2_get_block_type(rgd, inum->no_addr) != GFS2_BLKST_DINODE) | ||
| 186 | goto fail_rgd; | ||
| 187 | |||
| 188 | gfs2_glock_dq_uninit(&rgd_gh); | ||
| 189 | gfs2_glock_dq_uninit(&ri_gh); | ||
| 190 | |||
| 191 | inode = gfs2_inode_lookup(sb, DT_UNKNOWN, | ||
| 192 | inum->no_addr, | ||
| 193 | 0, 0); | ||
| 194 | if (IS_ERR(inode)) { | 173 | if (IS_ERR(inode)) { |
| 195 | error = PTR_ERR(inode); | 174 | error = PTR_ERR(inode); |
| 196 | goto fail; | 175 | goto fail; |
| @@ -224,13 +203,6 @@ out_inode: | |||
| 224 | if (!IS_ERR(dentry)) | 203 | if (!IS_ERR(dentry)) |
| 225 | dentry->d_op = &gfs2_dops; | 204 | dentry->d_op = &gfs2_dops; |
| 226 | return dentry; | 205 | return dentry; |
| 227 | |||
| 228 | fail_rgd: | ||
| 229 | gfs2_glock_dq_uninit(&rgd_gh); | ||
| 230 | |||
| 231 | fail_rindex: | ||
| 232 | gfs2_glock_dq_uninit(&ri_gh); | ||
| 233 | |||
| 234 | fail: | 206 | fail: |
| 235 | gfs2_glock_dq_uninit(&i_gh); | 207 | gfs2_glock_dq_uninit(&i_gh); |
| 236 | return ERR_PTR(error); | 208 | return ERR_PTR(error); |
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 73318a3ce6f..166f38fbd24 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
| @@ -38,7 +38,6 @@ | |||
| 38 | #include "rgrp.h" | 38 | #include "rgrp.h" |
| 39 | #include "trans.h" | 39 | #include "trans.h" |
| 40 | #include "util.h" | 40 | #include "util.h" |
| 41 | #include "eaops.h" | ||
| 42 | 41 | ||
| 43 | /** | 42 | /** |
| 44 | * gfs2_llseek - seek to a location in a file | 43 | * gfs2_llseek - seek to a location in a file |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 61801ada36f..6edb423f90b 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
| @@ -406,6 +406,12 @@ struct gfs2_statfs_change_host { | |||
| 406 | #define GFS2_DATA_WRITEBACK 1 | 406 | #define GFS2_DATA_WRITEBACK 1 |
| 407 | #define GFS2_DATA_ORDERED 2 | 407 | #define GFS2_DATA_ORDERED 2 |
| 408 | 408 | ||
| 409 | #define GFS2_ERRORS_DEFAULT GFS2_ERRORS_WITHDRAW | ||
| 410 | #define GFS2_ERRORS_WITHDRAW 0 | ||
| 411 | #define GFS2_ERRORS_CONTINUE 1 /* place holder for future feature */ | ||
| 412 | #define GFS2_ERRORS_RO 2 /* place holder for future feature */ | ||
| 413 | #define GFS2_ERRORS_PANIC 3 | ||
| 414 | |||
| 409 | struct gfs2_args { | 415 | struct gfs2_args { |
| 410 | char ar_lockproto[GFS2_LOCKNAME_LEN]; /* Name of the Lock Protocol */ | 416 | char ar_lockproto[GFS2_LOCKNAME_LEN]; /* Name of the Lock Protocol */ |
| 411 | char ar_locktable[GFS2_LOCKNAME_LEN]; /* Name of the Lock Table */ | 417 | char ar_locktable[GFS2_LOCKNAME_LEN]; /* Name of the Lock Table */ |
| @@ -422,6 +428,7 @@ struct gfs2_args { | |||
| 422 | unsigned int ar_data:2; /* ordered/writeback */ | 428 | unsigned int ar_data:2; /* ordered/writeback */ |
| 423 | unsigned int ar_meta:1; /* mount metafs */ | 429 | unsigned int ar_meta:1; /* mount metafs */ |
| 424 | unsigned int ar_discard:1; /* discard requests */ | 430 | unsigned int ar_discard:1; /* discard requests */ |
| 431 | unsigned int ar_errors:2; /* errors=withdraw | panic */ | ||
| 425 | int ar_commit; /* Commit interval */ | 432 | int ar_commit; /* Commit interval */ |
| 426 | }; | 433 | }; |
| 427 | 434 | ||
| @@ -489,7 +496,6 @@ struct gfs2_sb_host { | |||
| 489 | */ | 496 | */ |
| 490 | 497 | ||
| 491 | struct lm_lockstruct { | 498 | struct lm_lockstruct { |
| 492 | u32 ls_id; | ||
| 493 | unsigned int ls_jid; | 499 | unsigned int ls_jid; |
| 494 | unsigned int ls_first; | 500 | unsigned int ls_first; |
| 495 | unsigned int ls_first_done; | 501 | unsigned int ls_first_done; |
| @@ -541,18 +547,12 @@ struct gfs2_sbd { | |||
| 541 | struct dentry *sd_root_dir; | 547 | struct dentry *sd_root_dir; |
| 542 | 548 | ||
| 543 | struct inode *sd_jindex; | 549 | struct inode *sd_jindex; |
| 544 | struct inode *sd_inum_inode; | ||
| 545 | struct inode *sd_statfs_inode; | 550 | struct inode *sd_statfs_inode; |
| 546 | struct inode *sd_ir_inode; | ||
| 547 | struct inode *sd_sc_inode; | 551 | struct inode *sd_sc_inode; |
| 548 | struct inode *sd_qc_inode; | 552 | struct inode *sd_qc_inode; |
| 549 | struct inode *sd_rindex; | 553 | struct inode *sd_rindex; |
| 550 | struct inode *sd_quota_inode; | 554 | struct inode *sd_quota_inode; |
| 551 | 555 | ||
| 552 | /* Inum stuff */ | ||
| 553 | |||
| 554 | struct mutex sd_inum_mutex; | ||
| 555 | |||
| 556 | /* StatFS stuff */ | 556 | /* StatFS stuff */ |
| 557 | 557 | ||
| 558 | spinlock_t sd_statfs_spin; | 558 | spinlock_t sd_statfs_spin; |
| @@ -580,7 +580,6 @@ struct gfs2_sbd { | |||
| 580 | struct gfs2_holder sd_journal_gh; | 580 | struct gfs2_holder sd_journal_gh; |
| 581 | struct gfs2_holder sd_jinode_gh; | 581 | struct gfs2_holder sd_jinode_gh; |
| 582 | 582 | ||
| 583 | struct gfs2_holder sd_ir_gh; | ||
| 584 | struct gfs2_holder sd_sc_gh; | 583 | struct gfs2_holder sd_sc_gh; |
| 585 | struct gfs2_holder sd_qc_gh; | 584 | struct gfs2_holder sd_qc_gh; |
| 586 | 585 | ||
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 2f94bd72369..fb15d3b1f40 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | #include "acl.h" | 24 | #include "acl.h" |
| 25 | #include "bmap.h" | 25 | #include "bmap.h" |
| 26 | #include "dir.h" | 26 | #include "dir.h" |
| 27 | #include "eattr.h" | 27 | #include "xattr.h" |
| 28 | #include "glock.h" | 28 | #include "glock.h" |
| 29 | #include "glops.h" | 29 | #include "glops.h" |
| 30 | #include "inode.h" | 30 | #include "inode.h" |
| @@ -519,139 +519,6 @@ out: | |||
| 519 | return inode ? inode : ERR_PTR(error); | 519 | return inode ? inode : ERR_PTR(error); |
| 520 | } | 520 | } |
| 521 | 521 | ||
| 522 | static void gfs2_inum_range_in(struct gfs2_inum_range_host *ir, const void *buf) | ||
| 523 | { | ||
| 524 | const struct gfs2_inum_range *str = buf; | ||
| 525 | |||
| 526 | ir->ir_start = be64_to_cpu(str->ir_start); | ||
| 527 | ir->ir_length = be64_to_cpu(str->ir_length); | ||
| 528 | } | ||
| 529 | |||
| 530 | static void gfs2_inum_range_out(const struct gfs2_inum_range_host *ir, void *buf) | ||
| 531 | { | ||
| 532 | struct gfs2_inum_range *str = buf; | ||
| 533 | |||
| 534 | str->ir_start = cpu_to_be64(ir->ir_start); | ||
| 535 | str->ir_length = cpu_to_be64(ir->ir_length); | ||
| 536 | } | ||
| 537 | |||
| 538 | static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino) | ||
| 539 | { | ||
| 540 | struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode); | ||
| 541 | struct buffer_head *bh; | ||
| 542 | struct gfs2_inum_range_host ir; | ||
| 543 | int error; | ||
| 544 | |||
| 545 | error = gfs2_trans_begin(sdp, RES_DINODE, 0); | ||
| 546 | if (error) | ||
| 547 | return error; | ||
| 548 | mutex_lock(&sdp->sd_inum_mutex); | ||
| 549 | |||
| 550 | error = gfs2_meta_inode_buffer(ip, &bh); | ||
| 551 | if (error) { | ||
| 552 | mutex_unlock(&sdp->sd_inum_mutex); | ||
| 553 | gfs2_trans_end(sdp); | ||
| 554 | return error; | ||
| 555 | } | ||
| 556 | |||
| 557 | gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode)); | ||
| 558 | |||
| 559 | if (ir.ir_length) { | ||
| 560 | *formal_ino = ir.ir_start++; | ||
| 561 | ir.ir_length--; | ||
| 562 | gfs2_trans_add_bh(ip->i_gl, bh, 1); | ||
| 563 | gfs2_inum_range_out(&ir, | ||
| 564 | bh->b_data + sizeof(struct gfs2_dinode)); | ||
| 565 | brelse(bh); | ||
| 566 | mutex_unlock(&sdp->sd_inum_mutex); | ||
| 567 | gfs2_trans_end(sdp); | ||
| 568 | return 0; | ||
| 569 | } | ||
| 570 | |||
| 571 | brelse(bh); | ||
| 572 | |||
| 573 | mutex_unlock(&sdp->sd_inum_mutex); | ||
| 574 | gfs2_trans_end(sdp); | ||
| 575 | |||
| 576 | return 1; | ||
| 577 | } | ||
| 578 | |||
| 579 | static int pick_formal_ino_2(struct gfs2_sbd *sdp, u64 *formal_ino) | ||
| 580 | { | ||
| 581 | struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode); | ||
| 582 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_inum_inode); | ||
| 583 | struct gfs2_holder gh; | ||
| 584 | struct buffer_head *bh; | ||
| 585 | struct gfs2_inum_range_host ir; | ||
| 586 | int error; | ||
| 587 | |||
| 588 | error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); | ||
| 589 | if (error) | ||
| 590 | return error; | ||
| 591 | |||
| 592 | error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0); | ||
| 593 | if (error) | ||
| 594 | goto out; | ||
| 595 | mutex_lock(&sdp->sd_inum_mutex); | ||
| 596 | |||
| 597 | error = gfs2_meta_inode_buffer(ip, &bh); | ||
| 598 | if (error) | ||
| 599 | goto out_end_trans; | ||
| 600 | |||
| 601 | gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode)); | ||
| 602 | |||
| 603 | if (!ir.ir_length) { | ||
| 604 | struct buffer_head *m_bh; | ||
| 605 | u64 x, y; | ||
| 606 | __be64 z; | ||
| 607 | |||
| 608 | error = gfs2_meta_inode_buffer(m_ip, &m_bh); | ||
| 609 | if (error) | ||
| 610 | goto out_brelse; | ||
| 611 | |||
| 612 | z = *(__be64 *)(m_bh->b_data + sizeof(struct gfs2_dinode)); | ||
| 613 | x = y = be64_to_cpu(z); | ||
| 614 | ir.ir_start = x; | ||
| 615 | ir.ir_length = GFS2_INUM_QUANTUM; | ||
| 616 | x += GFS2_INUM_QUANTUM; | ||
| 617 | if (x < y) | ||
| 618 | gfs2_consist_inode(m_ip); | ||
| 619 | z = cpu_to_be64(x); | ||
| 620 | gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); | ||
| 621 | *(__be64 *)(m_bh->b_data + sizeof(struct gfs2_dinode)) = z; | ||
| 622 | |||
| 623 | brelse(m_bh); | ||
| 624 | } | ||
| 625 | |||
| 626 | *formal_ino = ir.ir_start++; | ||
| 627 | ir.ir_length--; | ||
| 628 | |||
| 629 | gfs2_trans_add_bh(ip->i_gl, bh, 1); | ||
| 630 | gfs2_inum_range_out(&ir, bh->b_data + sizeof(struct gfs2_dinode)); | ||
| 631 | |||
| 632 | out_brelse: | ||
| 633 | brelse(bh); | ||
| 634 | out_end_trans: | ||
| 635 | mutex_unlock(&sdp->sd_inum_mutex); | ||
| 636 | gfs2_trans_end(sdp); | ||
| 637 | out: | ||
| 638 | gfs2_glock_dq_uninit(&gh); | ||
| 639 | return error; | ||
| 640 | } | ||
| 641 | |||
| 642 | static int pick_formal_ino(struct gfs2_sbd *sdp, u64 *inum) | ||
| 643 | { | ||
| 644 | int error; | ||
| 645 | |||
| 646 | error = pick_formal_ino_1(sdp, inum); | ||
| 647 | if (error <= 0) | ||
| 648 | return error; | ||
| 649 | |||
| 650 | error = pick_formal_ino_2(sdp, inum); | ||
| 651 | |||
| 652 | return error; | ||
| 653 | } | ||
| 654 | |||
| 655 | /** | 522 | /** |
| 656 | * create_ok - OK to create a new on-disk inode here? | 523 | * create_ok - OK to create a new on-disk inode here? |
| 657 | * @dip: Directory in which dinode is to be created | 524 | * @dip: Directory in which dinode is to be created |
| @@ -731,7 +598,7 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation) | |||
| 731 | if (error) | 598 | if (error) |
| 732 | goto out_ipreserv; | 599 | goto out_ipreserv; |
| 733 | 600 | ||
| 734 | *no_addr = gfs2_alloc_di(dip, generation); | 601 | error = gfs2_alloc_di(dip, no_addr, generation); |
| 735 | 602 | ||
| 736 | gfs2_trans_end(sdp); | 603 | gfs2_trans_end(sdp); |
| 737 | 604 | ||
| @@ -924,7 +791,6 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
| 924 | size_t len; | 791 | size_t len; |
| 925 | void *value; | 792 | void *value; |
| 926 | char *name; | 793 | char *name; |
| 927 | struct gfs2_ea_request er; | ||
| 928 | 794 | ||
| 929 | err = security_inode_init_security(&ip->i_inode, &dip->i_inode, | 795 | err = security_inode_init_security(&ip->i_inode, &dip->i_inode, |
| 930 | &name, &value, &len); | 796 | &name, &value, &len); |
| @@ -935,16 +801,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
| 935 | return err; | 801 | return err; |
| 936 | } | 802 | } |
| 937 | 803 | ||
| 938 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 804 | err = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SECURITY, name, value, len, 0); |
| 939 | |||
| 940 | er.er_type = GFS2_EATYPE_SECURITY; | ||
| 941 | er.er_name = name; | ||
| 942 | er.er_data = value; | ||
| 943 | er.er_name_len = strlen(name); | ||
| 944 | er.er_data_len = len; | ||
| 945 | |||
| 946 | err = gfs2_ea_set_i(ip, &er); | ||
| 947 | |||
| 948 | kfree(value); | 805 | kfree(value); |
| 949 | kfree(name); | 806 | kfree(name); |
| 950 | 807 | ||
| @@ -991,13 +848,10 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
| 991 | if (error) | 848 | if (error) |
| 992 | goto fail_gunlock; | 849 | goto fail_gunlock; |
| 993 | 850 | ||
| 994 | error = pick_formal_ino(sdp, &inum.no_formal_ino); | ||
| 995 | if (error) | ||
| 996 | goto fail_gunlock; | ||
| 997 | |||
| 998 | error = alloc_dinode(dip, &inum.no_addr, &generation); | 851 | error = alloc_dinode(dip, &inum.no_addr, &generation); |
| 999 | if (error) | 852 | if (error) |
| 1000 | goto fail_gunlock; | 853 | goto fail_gunlock; |
| 854 | inum.no_formal_ino = generation; | ||
| 1001 | 855 | ||
| 1002 | error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops, | 856 | error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops, |
| 1003 | LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); | 857 | LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); |
| @@ -1008,9 +862,8 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
| 1008 | if (error) | 862 | if (error) |
| 1009 | goto fail_gunlock2; | 863 | goto fail_gunlock2; |
| 1010 | 864 | ||
| 1011 | inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), | 865 | inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr, |
| 1012 | inum.no_addr, | 866 | inum.no_formal_ino, 0); |
| 1013 | inum.no_formal_ino, 0); | ||
| 1014 | if (IS_ERR(inode)) | 867 | if (IS_ERR(inode)) |
| 1015 | goto fail_gunlock2; | 868 | goto fail_gunlock2; |
| 1016 | 869 | ||
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 7bc3c45cd67..52fb6c04898 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
| @@ -84,7 +84,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) | |||
| 84 | 84 | ||
| 85 | gfs2_tune_init(&sdp->sd_tune); | 85 | gfs2_tune_init(&sdp->sd_tune); |
| 86 | 86 | ||
| 87 | mutex_init(&sdp->sd_inum_mutex); | ||
| 88 | spin_lock_init(&sdp->sd_statfs_spin); | 87 | spin_lock_init(&sdp->sd_statfs_spin); |
| 89 | 88 | ||
| 90 | spin_lock_init(&sdp->sd_rindex_spin); | 89 | spin_lock_init(&sdp->sd_rindex_spin); |
| @@ -833,21 +832,12 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) | |||
| 833 | if (error) | 832 | if (error) |
| 834 | goto fail; | 833 | goto fail; |
| 835 | 834 | ||
| 836 | /* Read in the master inode number inode */ | ||
| 837 | sdp->sd_inum_inode = gfs2_lookup_simple(master, "inum"); | ||
| 838 | if (IS_ERR(sdp->sd_inum_inode)) { | ||
| 839 | error = PTR_ERR(sdp->sd_inum_inode); | ||
| 840 | fs_err(sdp, "can't read in inum inode: %d\n", error); | ||
| 841 | goto fail_journal; | ||
| 842 | } | ||
| 843 | |||
| 844 | |||
| 845 | /* Read in the master statfs inode */ | 835 | /* Read in the master statfs inode */ |
| 846 | sdp->sd_statfs_inode = gfs2_lookup_simple(master, "statfs"); | 836 | sdp->sd_statfs_inode = gfs2_lookup_simple(master, "statfs"); |
| 847 | if (IS_ERR(sdp->sd_statfs_inode)) { | 837 | if (IS_ERR(sdp->sd_statfs_inode)) { |
| 848 | error = PTR_ERR(sdp->sd_statfs_inode); | 838 | error = PTR_ERR(sdp->sd_statfs_inode); |
| 849 | fs_err(sdp, "can't read in statfs inode: %d\n", error); | 839 | fs_err(sdp, "can't read in statfs inode: %d\n", error); |
| 850 | goto fail_inum; | 840 | goto fail_journal; |
| 851 | } | 841 | } |
| 852 | 842 | ||
| 853 | /* Read in the resource index inode */ | 843 | /* Read in the resource index inode */ |
| @@ -876,8 +866,6 @@ fail_rindex: | |||
| 876 | iput(sdp->sd_rindex); | 866 | iput(sdp->sd_rindex); |
| 877 | fail_statfs: | 867 | fail_statfs: |
| 878 | iput(sdp->sd_statfs_inode); | 868 | iput(sdp->sd_statfs_inode); |
| 879 | fail_inum: | ||
| 880 | iput(sdp->sd_inum_inode); | ||
| 881 | fail_journal: | 869 | fail_journal: |
| 882 | init_journal(sdp, UNDO); | 870 | init_journal(sdp, UNDO); |
| 883 | fail: | 871 | fail: |
| @@ -905,20 +893,12 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) | |||
| 905 | return error; | 893 | return error; |
| 906 | } | 894 | } |
| 907 | 895 | ||
| 908 | sprintf(buf, "inum_range%u", sdp->sd_jdesc->jd_jid); | ||
| 909 | sdp->sd_ir_inode = gfs2_lookup_simple(pn, buf); | ||
| 910 | if (IS_ERR(sdp->sd_ir_inode)) { | ||
| 911 | error = PTR_ERR(sdp->sd_ir_inode); | ||
| 912 | fs_err(sdp, "can't find local \"ir\" file: %d\n", error); | ||
| 913 | goto fail; | ||
| 914 | } | ||
| 915 | |||
| 916 | sprintf(buf, "statfs_change%u", sdp->sd_jdesc->jd_jid); | 896 | sprintf(buf, "statfs_change%u", sdp->sd_jdesc->jd_jid); |
| 917 | sdp->sd_sc_inode = gfs2_lookup_simple(pn, buf); | 897 | sdp->sd_sc_inode = gfs2_lookup_simple(pn, buf); |
| 918 | if (IS_ERR(sdp->sd_sc_inode)) { | 898 | if (IS_ERR(sdp->sd_sc_inode)) { |
| 919 | error = PTR_ERR(sdp->sd_sc_inode); | 899 | error = PTR_ERR(sdp->sd_sc_inode); |
| 920 | fs_err(sdp, "can't find local \"sc\" file: %d\n", error); | 900 | fs_err(sdp, "can't find local \"sc\" file: %d\n", error); |
| 921 | goto fail_ir_i; | 901 | goto fail; |
| 922 | } | 902 | } |
| 923 | 903 | ||
| 924 | sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid); | 904 | sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid); |
| @@ -932,27 +912,16 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) | |||
| 932 | iput(pn); | 912 | iput(pn); |
| 933 | pn = NULL; | 913 | pn = NULL; |
| 934 | 914 | ||
| 935 | ip = GFS2_I(sdp->sd_ir_inode); | ||
| 936 | error = gfs2_glock_nq_init(ip->i_gl, | ||
| 937 | LM_ST_EXCLUSIVE, 0, | ||
| 938 | &sdp->sd_ir_gh); | ||
| 939 | if (error) { | ||
| 940 | fs_err(sdp, "can't lock local \"ir\" file: %d\n", error); | ||
| 941 | goto fail_qc_i; | ||
| 942 | } | ||
| 943 | |||
| 944 | ip = GFS2_I(sdp->sd_sc_inode); | 915 | ip = GFS2_I(sdp->sd_sc_inode); |
| 945 | error = gfs2_glock_nq_init(ip->i_gl, | 916 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, |
| 946 | LM_ST_EXCLUSIVE, 0, | ||
| 947 | &sdp->sd_sc_gh); | 917 | &sdp->sd_sc_gh); |
| 948 | if (error) { | 918 | if (error) { |
| 949 | fs_err(sdp, "can't lock local \"sc\" file: %d\n", error); | 919 | fs_err(sdp, "can't lock local \"sc\" file: %d\n", error); |
| 950 | goto fail_ir_gh; | 920 | goto fail_qc_i; |
| 951 | } | 921 | } |
| 952 | 922 | ||
| 953 | ip = GFS2_I(sdp->sd_qc_inode); | 923 | ip = GFS2_I(sdp->sd_qc_inode); |
| 954 | error = gfs2_glock_nq_init(ip->i_gl, | 924 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, |
| 955 | LM_ST_EXCLUSIVE, 0, | ||
| 956 | &sdp->sd_qc_gh); | 925 | &sdp->sd_qc_gh); |
| 957 | if (error) { | 926 | if (error) { |
| 958 | fs_err(sdp, "can't lock local \"qc\" file: %d\n", error); | 927 | fs_err(sdp, "can't lock local \"qc\" file: %d\n", error); |
| @@ -965,14 +934,10 @@ fail_qc_gh: | |||
| 965 | gfs2_glock_dq_uninit(&sdp->sd_qc_gh); | 934 | gfs2_glock_dq_uninit(&sdp->sd_qc_gh); |
| 966 | fail_ut_gh: | 935 | fail_ut_gh: |
| 967 | gfs2_glock_dq_uninit(&sdp->sd_sc_gh); | 936 | gfs2_glock_dq_uninit(&sdp->sd_sc_gh); |
| 968 | fail_ir_gh: | ||
| 969 | gfs2_glock_dq_uninit(&sdp->sd_ir_gh); | ||
| 970 | fail_qc_i: | 937 | fail_qc_i: |
| 971 | iput(sdp->sd_qc_inode); | 938 | iput(sdp->sd_qc_inode); |
| 972 | fail_ut_i: | 939 | fail_ut_i: |
| 973 | iput(sdp->sd_sc_inode); | 940 | iput(sdp->sd_sc_inode); |
| 974 | fail_ir_i: | ||
| 975 | iput(sdp->sd_ir_inode); | ||
| 976 | fail: | 941 | fail: |
| 977 | if (pn) | 942 | if (pn) |
| 978 | iput(pn); | 943 | iput(pn); |
| @@ -1063,7 +1028,6 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) | |||
| 1063 | 1028 | ||
| 1064 | ls->ls_ops = lm; | 1029 | ls->ls_ops = lm; |
| 1065 | ls->ls_first = 1; | 1030 | ls->ls_first = 1; |
| 1066 | ls->ls_id = 0; | ||
| 1067 | 1031 | ||
| 1068 | for (options = args->ar_hostdata; (o = strsep(&options, ":")); ) { | 1032 | for (options = args->ar_hostdata; (o = strsep(&options, ":")); ) { |
| 1069 | substring_t tmp[MAX_OPT_ARGS]; | 1033 | substring_t tmp[MAX_OPT_ARGS]; |
| @@ -1081,10 +1045,7 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) | |||
| 1081 | ls->ls_jid = option; | 1045 | ls->ls_jid = option; |
| 1082 | break; | 1046 | break; |
| 1083 | case Opt_id: | 1047 | case Opt_id: |
| 1084 | ret = match_int(&tmp[0], &option); | 1048 | /* Obsolete, but left for backward compat purposes */ |
| 1085 | if (ret) | ||
| 1086 | goto hostdata_error; | ||
| 1087 | ls->ls_id = option; | ||
| 1088 | break; | 1049 | break; |
| 1089 | case Opt_first: | 1050 | case Opt_first: |
| 1090 | ret = match_int(&tmp[0], &option); | 1051 | ret = match_int(&tmp[0], &option); |
| @@ -1133,6 +1094,17 @@ void gfs2_lm_unmount(struct gfs2_sbd *sdp) | |||
| 1133 | lm->lm_unmount(sdp); | 1094 | lm->lm_unmount(sdp); |
| 1134 | } | 1095 | } |
| 1135 | 1096 | ||
| 1097 | void gfs2_online_uevent(struct gfs2_sbd *sdp) | ||
| 1098 | { | ||
| 1099 | struct super_block *sb = sdp->sd_vfs; | ||
| 1100 | char ro[20]; | ||
| 1101 | char spectator[20]; | ||
| 1102 | char *envp[] = { ro, spectator, NULL }; | ||
| 1103 | sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0); | ||
| 1104 | sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0); | ||
| 1105 | kobject_uevent_env(&sdp->sd_kobj, KOBJ_ONLINE, envp); | ||
| 1106 | } | ||
| 1107 | |||
| 1136 | /** | 1108 | /** |
| 1137 | * fill_super - Read in superblock | 1109 | * fill_super - Read in superblock |
| 1138 | * @sb: The VFS superblock | 1110 | * @sb: The VFS superblock |
| @@ -1157,6 +1129,7 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
| 1157 | sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT; | 1129 | sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT; |
| 1158 | sdp->sd_args.ar_data = GFS2_DATA_DEFAULT; | 1130 | sdp->sd_args.ar_data = GFS2_DATA_DEFAULT; |
| 1159 | sdp->sd_args.ar_commit = 60; | 1131 | sdp->sd_args.ar_commit = 60; |
| 1132 | sdp->sd_args.ar_errors = GFS2_ERRORS_DEFAULT; | ||
| 1160 | 1133 | ||
| 1161 | error = gfs2_mount_args(sdp, &sdp->sd_args, data); | 1134 | error = gfs2_mount_args(sdp, &sdp->sd_args, data); |
| 1162 | if (error) { | 1135 | if (error) { |
| @@ -1174,6 +1147,7 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
| 1174 | sb->s_magic = GFS2_MAGIC; | 1147 | sb->s_magic = GFS2_MAGIC; |
| 1175 | sb->s_op = &gfs2_super_ops; | 1148 | sb->s_op = &gfs2_super_ops; |
| 1176 | sb->s_export_op = &gfs2_export_ops; | 1149 | sb->s_export_op = &gfs2_export_ops; |
| 1150 | sb->s_xattr = gfs2_xattr_handlers; | ||
| 1177 | sb->s_time_gran = 1; | 1151 | sb->s_time_gran = 1; |
| 1178 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 1152 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
| 1179 | 1153 | ||
| @@ -1236,7 +1210,7 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
| 1236 | } | 1210 | } |
| 1237 | 1211 | ||
| 1238 | gfs2_glock_dq_uninit(&mount_gh); | 1212 | gfs2_glock_dq_uninit(&mount_gh); |
| 1239 | 1213 | gfs2_online_uevent(sdp); | |
| 1240 | return 0; | 1214 | return 0; |
| 1241 | 1215 | ||
| 1242 | fail_threads: | 1216 | fail_threads: |
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index f8bd20baf99..c3ac1805405 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
| @@ -26,8 +26,7 @@ | |||
| 26 | #include "acl.h" | 26 | #include "acl.h" |
| 27 | #include "bmap.h" | 27 | #include "bmap.h" |
| 28 | #include "dir.h" | 28 | #include "dir.h" |
| 29 | #include "eaops.h" | 29 | #include "xattr.h" |
| 30 | #include "eattr.h" | ||
| 31 | #include "glock.h" | 30 | #include "glock.h" |
| 32 | #include "inode.h" | 31 | #include "inode.h" |
| 33 | #include "meta_io.h" | 32 | #include "meta_io.h" |
| @@ -349,7 +348,7 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) | |||
| 349 | 348 | ||
| 350 | error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); | 349 | error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); |
| 351 | if (error) | 350 | if (error) |
| 352 | goto out_rgrp; | 351 | goto out_gunlock; |
| 353 | 352 | ||
| 354 | error = gfs2_dir_del(dip, &dentry->d_name); | 353 | error = gfs2_dir_del(dip, &dentry->d_name); |
| 355 | if (error) | 354 | if (error) |
| @@ -1302,60 +1301,53 @@ static int gfs2_setxattr(struct dentry *dentry, const char *name, | |||
| 1302 | const void *data, size_t size, int flags) | 1301 | const void *data, size_t size, int flags) |
| 1303 | { | 1302 | { |
| 1304 | struct inode *inode = dentry->d_inode; | 1303 | struct inode *inode = dentry->d_inode; |
| 1305 | struct gfs2_ea_request er; | 1304 | struct gfs2_inode *ip = GFS2_I(inode); |
| 1306 | 1305 | struct gfs2_holder gh; | |
| 1307 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 1306 | int ret; |
| 1308 | er.er_type = gfs2_ea_name2type(name, &er.er_name); | ||
| 1309 | if (er.er_type == GFS2_EATYPE_UNUSED) | ||
| 1310 | return -EOPNOTSUPP; | ||
| 1311 | er.er_data = (char *)data; | ||
| 1312 | er.er_name_len = strlen(er.er_name); | ||
| 1313 | er.er_data_len = size; | ||
| 1314 | er.er_flags = flags; | ||
| 1315 | |||
| 1316 | gfs2_assert_warn(GFS2_SB(inode), !(er.er_flags & GFS2_ERF_MODE)); | ||
| 1317 | 1307 | ||
| 1318 | return gfs2_ea_set(GFS2_I(inode), &er); | 1308 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); |
| 1309 | ret = gfs2_glock_nq(&gh); | ||
| 1310 | if (ret == 0) { | ||
| 1311 | ret = generic_setxattr(dentry, name, data, size, flags); | ||
| 1312 | gfs2_glock_dq(&gh); | ||
| 1313 | } | ||
| 1314 | gfs2_holder_uninit(&gh); | ||
| 1315 | return ret; | ||
| 1319 | } | 1316 | } |
| 1320 | 1317 | ||
| 1321 | static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, | 1318 | static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, |
| 1322 | void *data, size_t size) | 1319 | void *data, size_t size) |
| 1323 | { | 1320 | { |
| 1324 | struct gfs2_ea_request er; | 1321 | struct inode *inode = dentry->d_inode; |
| 1325 | 1322 | struct gfs2_inode *ip = GFS2_I(inode); | |
| 1326 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 1323 | struct gfs2_holder gh; |
| 1327 | er.er_type = gfs2_ea_name2type(name, &er.er_name); | 1324 | int ret; |
| 1328 | if (er.er_type == GFS2_EATYPE_UNUSED) | ||
| 1329 | return -EOPNOTSUPP; | ||
| 1330 | er.er_data = data; | ||
| 1331 | er.er_name_len = strlen(er.er_name); | ||
| 1332 | er.er_data_len = size; | ||
| 1333 | |||
| 1334 | return gfs2_ea_get(GFS2_I(dentry->d_inode), &er); | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) | ||
| 1338 | { | ||
| 1339 | struct gfs2_ea_request er; | ||
| 1340 | |||
| 1341 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | ||
| 1342 | er.er_data = (size) ? buffer : NULL; | ||
| 1343 | er.er_data_len = size; | ||
| 1344 | 1325 | ||
| 1345 | return gfs2_ea_list(GFS2_I(dentry->d_inode), &er); | 1326 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); |
| 1327 | ret = gfs2_glock_nq(&gh); | ||
| 1328 | if (ret == 0) { | ||
| 1329 | ret = generic_getxattr(dentry, name, data, size); | ||
| 1330 | gfs2_glock_dq(&gh); | ||
| 1331 | } | ||
| 1332 | gfs2_holder_uninit(&gh); | ||
| 1333 | return ret; | ||
| 1346 | } | 1334 | } |
| 1347 | 1335 | ||
| 1348 | static int gfs2_removexattr(struct dentry *dentry, const char *name) | 1336 | static int gfs2_removexattr(struct dentry *dentry, const char *name) |
| 1349 | { | 1337 | { |
| 1350 | struct gfs2_ea_request er; | 1338 | struct inode *inode = dentry->d_inode; |
| 1351 | 1339 | struct gfs2_inode *ip = GFS2_I(inode); | |
| 1352 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 1340 | struct gfs2_holder gh; |
| 1353 | er.er_type = gfs2_ea_name2type(name, &er.er_name); | 1341 | int ret; |
| 1354 | if (er.er_type == GFS2_EATYPE_UNUSED) | ||
| 1355 | return -EOPNOTSUPP; | ||
| 1356 | er.er_name_len = strlen(er.er_name); | ||
| 1357 | 1342 | ||
| 1358 | return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er); | 1343 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); |
| 1344 | ret = gfs2_glock_nq(&gh); | ||
| 1345 | if (ret == 0) { | ||
| 1346 | ret = generic_removexattr(dentry, name); | ||
| 1347 | gfs2_glock_dq(&gh); | ||
| 1348 | } | ||
| 1349 | gfs2_holder_uninit(&gh); | ||
| 1350 | return ret; | ||
| 1359 | } | 1351 | } |
| 1360 | 1352 | ||
| 1361 | static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 1353 | static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index fba795798d3..28c590b7c9d 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
| @@ -857,7 +857,8 @@ static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, | |||
| 857 | goto start_new_extent; | 857 | goto start_new_extent; |
| 858 | if ((start + nr_sects) != blk) { | 858 | if ((start + nr_sects) != blk) { |
| 859 | rv = blkdev_issue_discard(bdev, start, | 859 | rv = blkdev_issue_discard(bdev, start, |
| 860 | nr_sects, GFP_NOFS); | 860 | nr_sects, GFP_NOFS, |
| 861 | DISCARD_FL_BARRIER); | ||
| 861 | if (rv) | 862 | if (rv) |
| 862 | goto fail; | 863 | goto fail; |
| 863 | nr_sects = 0; | 864 | nr_sects = 0; |
| @@ -871,7 +872,8 @@ start_new_extent: | |||
| 871 | } | 872 | } |
| 872 | } | 873 | } |
| 873 | if (nr_sects) { | 874 | if (nr_sects) { |
| 874 | rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS); | 875 | rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS, |
| 876 | DISCARD_FL_BARRIER); | ||
| 875 | if (rv) | 877 | if (rv) |
| 876 | goto fail; | 878 | goto fail; |
| 877 | } | 879 | } |
| @@ -1256,7 +1258,7 @@ void gfs2_inplace_release(struct gfs2_inode *ip) | |||
| 1256 | * Returns: The block type (GFS2_BLKST_*) | 1258 | * Returns: The block type (GFS2_BLKST_*) |
| 1257 | */ | 1259 | */ |
| 1258 | 1260 | ||
| 1259 | unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) | 1261 | static unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) |
| 1260 | { | 1262 | { |
| 1261 | struct gfs2_bitmap *bi = NULL; | 1263 | struct gfs2_bitmap *bi = NULL; |
| 1262 | u32 length, rgrp_block, buf_block; | 1264 | u32 length, rgrp_block, buf_block; |
| @@ -1459,6 +1461,16 @@ int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl) | |||
| 1459 | return 0; | 1461 | return 0; |
| 1460 | } | 1462 | } |
| 1461 | 1463 | ||
| 1464 | static void gfs2_rgrp_error(struct gfs2_rgrpd *rgd) | ||
| 1465 | { | ||
| 1466 | struct gfs2_sbd *sdp = rgd->rd_sbd; | ||
| 1467 | fs_warn(sdp, "rgrp %llu has an error, marking it readonly until umount\n", | ||
| 1468 | (unsigned long long)rgd->rd_addr); | ||
| 1469 | fs_warn(sdp, "umount on all nodes and run fsck.gfs2 to fix the error\n"); | ||
| 1470 | gfs2_rgrp_dump(NULL, rgd->rd_gl); | ||
| 1471 | rgd->rd_flags |= GFS2_RDF_ERROR; | ||
| 1472 | } | ||
| 1473 | |||
| 1462 | /** | 1474 | /** |
| 1463 | * gfs2_alloc_block - Allocate one or more blocks | 1475 | * gfs2_alloc_block - Allocate one or more blocks |
| 1464 | * @ip: the inode to allocate the block for | 1476 | * @ip: the inode to allocate the block for |
| @@ -1520,22 +1532,20 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n) | |||
| 1520 | return 0; | 1532 | return 0; |
| 1521 | 1533 | ||
| 1522 | rgrp_error: | 1534 | rgrp_error: |
| 1523 | fs_warn(sdp, "rgrp %llu has an error, marking it readonly until umount\n", | 1535 | gfs2_rgrp_error(rgd); |
| 1524 | (unsigned long long)rgd->rd_addr); | ||
| 1525 | fs_warn(sdp, "umount on all nodes and run fsck.gfs2 to fix the error\n"); | ||
| 1526 | gfs2_rgrp_dump(NULL, rgd->rd_gl); | ||
| 1527 | rgd->rd_flags |= GFS2_RDF_ERROR; | ||
| 1528 | return -EIO; | 1536 | return -EIO; |
| 1529 | } | 1537 | } |
| 1530 | 1538 | ||
| 1531 | /** | 1539 | /** |
| 1532 | * gfs2_alloc_di - Allocate a dinode | 1540 | * gfs2_alloc_di - Allocate a dinode |
| 1533 | * @dip: the directory that the inode is going in | 1541 | * @dip: the directory that the inode is going in |
| 1542 | * @bn: the block number which is allocated | ||
| 1543 | * @generation: the generation number of the inode | ||
| 1534 | * | 1544 | * |
| 1535 | * Returns: the block allocated | 1545 | * Returns: 0 on success or error |
| 1536 | */ | 1546 | */ |
| 1537 | 1547 | ||
| 1538 | u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) | 1548 | int gfs2_alloc_di(struct gfs2_inode *dip, u64 *bn, u64 *generation) |
| 1539 | { | 1549 | { |
| 1540 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 1550 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
| 1541 | struct gfs2_alloc *al = dip->i_alloc; | 1551 | struct gfs2_alloc *al = dip->i_alloc; |
| @@ -1546,16 +1556,21 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) | |||
| 1546 | 1556 | ||
| 1547 | blk = rgblk_search(rgd, rgd->rd_last_alloc, | 1557 | blk = rgblk_search(rgd, rgd->rd_last_alloc, |
| 1548 | GFS2_BLKST_FREE, GFS2_BLKST_DINODE, &n); | 1558 | GFS2_BLKST_FREE, GFS2_BLKST_DINODE, &n); |
| 1549 | BUG_ON(blk == BFITNOENT); | ||
| 1550 | 1559 | ||
| 1551 | rgd->rd_last_alloc = blk; | 1560 | /* Since all blocks are reserved in advance, this shouldn't happen */ |
| 1561 | if (blk == BFITNOENT) | ||
| 1562 | goto rgrp_error; | ||
| 1552 | 1563 | ||
| 1564 | rgd->rd_last_alloc = blk; | ||
| 1553 | block = rgd->rd_data0 + blk; | 1565 | block = rgd->rd_data0 + blk; |
| 1566 | if (rgd->rd_free == 0) | ||
| 1567 | goto rgrp_error; | ||
| 1554 | 1568 | ||
| 1555 | gfs2_assert_withdraw(sdp, rgd->rd_free); | ||
| 1556 | rgd->rd_free--; | 1569 | rgd->rd_free--; |
| 1557 | rgd->rd_dinodes++; | 1570 | rgd->rd_dinodes++; |
| 1558 | *generation = rgd->rd_igeneration++; | 1571 | *generation = rgd->rd_igeneration++; |
| 1572 | if (*generation == 0) | ||
| 1573 | *generation = rgd->rd_igeneration++; | ||
| 1559 | gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); | 1574 | gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); |
| 1560 | gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); | 1575 | gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); |
| 1561 | 1576 | ||
| @@ -1568,7 +1583,12 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) | |||
| 1568 | rgd->rd_free_clone--; | 1583 | rgd->rd_free_clone--; |
| 1569 | spin_unlock(&sdp->sd_rindex_spin); | 1584 | spin_unlock(&sdp->sd_rindex_spin); |
| 1570 | trace_gfs2_block_alloc(dip, block, 1, GFS2_BLKST_DINODE); | 1585 | trace_gfs2_block_alloc(dip, block, 1, GFS2_BLKST_DINODE); |
| 1571 | return block; | 1586 | *bn = block; |
| 1587 | return 0; | ||
| 1588 | |||
| 1589 | rgrp_error: | ||
| 1590 | gfs2_rgrp_error(rgd); | ||
| 1591 | return -EIO; | ||
| 1572 | } | 1592 | } |
| 1573 | 1593 | ||
| 1574 | /** | 1594 | /** |
| @@ -1676,6 +1696,46 @@ void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip) | |||
| 1676 | } | 1696 | } |
| 1677 | 1697 | ||
| 1678 | /** | 1698 | /** |
| 1699 | * gfs2_check_blk_type - Check the type of a block | ||
| 1700 | * @sdp: The superblock | ||
| 1701 | * @no_addr: The block number to check | ||
| 1702 | * @type: The block type we are looking for | ||
| 1703 | * | ||
| 1704 | * Returns: 0 if the block type matches the expected type | ||
| 1705 | * -ESTALE if it doesn't match | ||
| 1706 | * or -ve errno if something went wrong while checking | ||
| 1707 | */ | ||
| 1708 | |||
| 1709 | int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type) | ||
| 1710 | { | ||
| 1711 | struct gfs2_rgrpd *rgd; | ||
| 1712 | struct gfs2_holder ri_gh, rgd_gh; | ||
| 1713 | int error; | ||
| 1714 | |||
| 1715 | error = gfs2_rindex_hold(sdp, &ri_gh); | ||
| 1716 | if (error) | ||
| 1717 | goto fail; | ||
| 1718 | |||
| 1719 | error = -EINVAL; | ||
| 1720 | rgd = gfs2_blk2rgrpd(sdp, no_addr); | ||
| 1721 | if (!rgd) | ||
| 1722 | goto fail_rindex; | ||
| 1723 | |||
| 1724 | error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh); | ||
| 1725 | if (error) | ||
| 1726 | goto fail_rindex; | ||
| 1727 | |||
| 1728 | if (gfs2_get_block_type(rgd, no_addr) != type) | ||
| 1729 | error = -ESTALE; | ||
| 1730 | |||
| 1731 | gfs2_glock_dq_uninit(&rgd_gh); | ||
| 1732 | fail_rindex: | ||
| 1733 | gfs2_glock_dq_uninit(&ri_gh); | ||
| 1734 | fail: | ||
| 1735 | return error; | ||
| 1736 | } | ||
| 1737 | |||
| 1738 | /** | ||
| 1679 | * gfs2_rlist_add - add a RG to a list of RGs | 1739 | * gfs2_rlist_add - add a RG to a list of RGs |
| 1680 | * @sdp: the filesystem | 1740 | * @sdp: the filesystem |
| 1681 | * @rlist: the list of resource groups | 1741 | * @rlist: the list of resource groups |
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 1e76ff0f3e0..b4106ddaaa9 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h | |||
| @@ -44,15 +44,15 @@ gfs2_inplace_reserve_i((ip), __FILE__, __LINE__) | |||
| 44 | 44 | ||
| 45 | extern void gfs2_inplace_release(struct gfs2_inode *ip); | 45 | extern void gfs2_inplace_release(struct gfs2_inode *ip); |
| 46 | 46 | ||
| 47 | extern unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block); | ||
| 48 | |||
| 49 | extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n); | 47 | extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n); |
| 50 | extern u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation); | 48 | extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation); |
| 51 | 49 | ||
| 52 | extern void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen); | 50 | extern void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen); |
| 53 | extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); | 51 | extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); |
| 54 | extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); | 52 | extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); |
| 55 | extern void gfs2_unlink_di(struct inode *inode); | 53 | extern void gfs2_unlink_di(struct inode *inode); |
| 54 | extern int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, | ||
| 55 | unsigned int type); | ||
| 56 | 56 | ||
| 57 | struct gfs2_rgrp_list { | 57 | struct gfs2_rgrp_list { |
| 58 | unsigned int rl_rgrps; | 58 | unsigned int rl_rgrps; |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index f522bb01797..0ec3ec672de 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
| @@ -38,7 +38,7 @@ | |||
| 38 | #include "trans.h" | 38 | #include "trans.h" |
| 39 | #include "util.h" | 39 | #include "util.h" |
| 40 | #include "sys.h" | 40 | #include "sys.h" |
| 41 | #include "eattr.h" | 41 | #include "xattr.h" |
| 42 | 42 | ||
| 43 | #define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x) | 43 | #define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x) |
| 44 | 44 | ||
| @@ -68,6 +68,8 @@ enum { | |||
| 68 | Opt_discard, | 68 | Opt_discard, |
| 69 | Opt_nodiscard, | 69 | Opt_nodiscard, |
| 70 | Opt_commit, | 70 | Opt_commit, |
| 71 | Opt_err_withdraw, | ||
| 72 | Opt_err_panic, | ||
| 71 | Opt_error, | 73 | Opt_error, |
| 72 | }; | 74 | }; |
| 73 | 75 | ||
| @@ -97,6 +99,8 @@ static const match_table_t tokens = { | |||
| 97 | {Opt_discard, "discard"}, | 99 | {Opt_discard, "discard"}, |
| 98 | {Opt_nodiscard, "nodiscard"}, | 100 | {Opt_nodiscard, "nodiscard"}, |
| 99 | {Opt_commit, "commit=%d"}, | 101 | {Opt_commit, "commit=%d"}, |
| 102 | {Opt_err_withdraw, "errors=withdraw"}, | ||
| 103 | {Opt_err_panic, "errors=panic"}, | ||
| 100 | {Opt_error, NULL} | 104 | {Opt_error, NULL} |
| 101 | }; | 105 | }; |
| 102 | 106 | ||
| @@ -152,6 +156,11 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) | |||
| 152 | args->ar_localcaching = 1; | 156 | args->ar_localcaching = 1; |
| 153 | break; | 157 | break; |
| 154 | case Opt_debug: | 158 | case Opt_debug: |
| 159 | if (args->ar_errors == GFS2_ERRORS_PANIC) { | ||
| 160 | fs_info(sdp, "-o debug and -o errors=panic " | ||
| 161 | "are mutually exclusive.\n"); | ||
| 162 | return -EINVAL; | ||
| 163 | } | ||
| 155 | args->ar_debug = 1; | 164 | args->ar_debug = 1; |
| 156 | break; | 165 | break; |
| 157 | case Opt_nodebug: | 166 | case Opt_nodebug: |
| @@ -205,6 +214,17 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) | |||
| 205 | return rv ? rv : -EINVAL; | 214 | return rv ? rv : -EINVAL; |
| 206 | } | 215 | } |
| 207 | break; | 216 | break; |
| 217 | case Opt_err_withdraw: | ||
| 218 | args->ar_errors = GFS2_ERRORS_WITHDRAW; | ||
| 219 | break; | ||
| 220 | case Opt_err_panic: | ||
| 221 | if (args->ar_debug) { | ||
| 222 | fs_info(sdp, "-o debug and -o errors=panic " | ||
| 223 | "are mutually exclusive.\n"); | ||
| 224 | return -EINVAL; | ||
| 225 | } | ||
| 226 | args->ar_errors = GFS2_ERRORS_PANIC; | ||
| 227 | break; | ||
| 208 | case Opt_error: | 228 | case Opt_error: |
| 209 | default: | 229 | default: |
| 210 | fs_info(sdp, "invalid mount option: %s\n", o); | 230 | fs_info(sdp, "invalid mount option: %s\n", o); |
| @@ -768,7 +788,6 @@ restart: | |||
| 768 | /* Release stuff */ | 788 | /* Release stuff */ |
| 769 | 789 | ||
| 770 | iput(sdp->sd_jindex); | 790 | iput(sdp->sd_jindex); |
| 771 | iput(sdp->sd_inum_inode); | ||
| 772 | iput(sdp->sd_statfs_inode); | 791 | iput(sdp->sd_statfs_inode); |
| 773 | iput(sdp->sd_rindex); | 792 | iput(sdp->sd_rindex); |
| 774 | iput(sdp->sd_quota_inode); | 793 | iput(sdp->sd_quota_inode); |
| @@ -779,10 +798,8 @@ restart: | |||
| 779 | if (!sdp->sd_args.ar_spectator) { | 798 | if (!sdp->sd_args.ar_spectator) { |
| 780 | gfs2_glock_dq_uninit(&sdp->sd_journal_gh); | 799 | gfs2_glock_dq_uninit(&sdp->sd_journal_gh); |
| 781 | gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); | 800 | gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); |
| 782 | gfs2_glock_dq_uninit(&sdp->sd_ir_gh); | ||
| 783 | gfs2_glock_dq_uninit(&sdp->sd_sc_gh); | 801 | gfs2_glock_dq_uninit(&sdp->sd_sc_gh); |
| 784 | gfs2_glock_dq_uninit(&sdp->sd_qc_gh); | 802 | gfs2_glock_dq_uninit(&sdp->sd_qc_gh); |
| 785 | iput(sdp->sd_ir_inode); | ||
| 786 | iput(sdp->sd_sc_inode); | 803 | iput(sdp->sd_sc_inode); |
| 787 | iput(sdp->sd_qc_inode); | 804 | iput(sdp->sd_qc_inode); |
| 788 | } | 805 | } |
| @@ -1084,6 +1101,7 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) | |||
| 1084 | gt->gt_log_flush_secs = args.ar_commit; | 1101 | gt->gt_log_flush_secs = args.ar_commit; |
| 1085 | spin_unlock(>->gt_spin); | 1102 | spin_unlock(>->gt_spin); |
| 1086 | 1103 | ||
| 1104 | gfs2_online_uevent(sdp); | ||
| 1087 | return 0; | 1105 | return 0; |
| 1088 | } | 1106 | } |
| 1089 | 1107 | ||
| @@ -1225,6 +1243,22 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
| 1225 | lfsecs = sdp->sd_tune.gt_log_flush_secs; | 1243 | lfsecs = sdp->sd_tune.gt_log_flush_secs; |
| 1226 | if (lfsecs != 60) | 1244 | if (lfsecs != 60) |
| 1227 | seq_printf(s, ",commit=%d", lfsecs); | 1245 | seq_printf(s, ",commit=%d", lfsecs); |
| 1246 | if (args->ar_errors != GFS2_ERRORS_DEFAULT) { | ||
| 1247 | const char *state; | ||
| 1248 | |||
| 1249 | switch (args->ar_errors) { | ||
| 1250 | case GFS2_ERRORS_WITHDRAW: | ||
| 1251 | state = "withdraw"; | ||
| 1252 | break; | ||
| 1253 | case GFS2_ERRORS_PANIC: | ||
| 1254 | state = "panic"; | ||
| 1255 | break; | ||
| 1256 | default: | ||
| 1257 | state = "unknown"; | ||
| 1258 | break; | ||
| 1259 | } | ||
| 1260 | seq_printf(s, ",errors=%s", state); | ||
| 1261 | } | ||
| 1228 | return 0; | 1262 | return 0; |
| 1229 | } | 1263 | } |
| 1230 | 1264 | ||
| @@ -1252,6 +1286,10 @@ static void gfs2_delete_inode(struct inode *inode) | |||
| 1252 | goto out; | 1286 | goto out; |
| 1253 | } | 1287 | } |
| 1254 | 1288 | ||
| 1289 | error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED); | ||
| 1290 | if (error) | ||
| 1291 | goto out_truncate; | ||
| 1292 | |||
| 1255 | gfs2_glock_dq_wait(&ip->i_iopen_gh); | 1293 | gfs2_glock_dq_wait(&ip->i_iopen_gh); |
| 1256 | gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh); | 1294 | gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh); |
| 1257 | error = gfs2_glock_nq(&ip->i_iopen_gh); | 1295 | error = gfs2_glock_nq(&ip->i_iopen_gh); |
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 22e0417ed99..235db368288 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h | |||
| @@ -25,7 +25,7 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) | |||
| 25 | return x; | 25 | return x; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | 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_sbd *sdp, struct gfs2_args *args, char *data); |
| 31 | 31 | ||
| @@ -36,7 +36,7 @@ extern int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename, | |||
| 36 | struct gfs2_inode **ipp); | 36 | struct gfs2_inode **ipp); |
| 37 | 37 | ||
| 38 | extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp); | 38 | extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp); |
| 39 | 39 | extern void gfs2_online_uevent(struct gfs2_sbd *sdp); | |
| 40 | extern int gfs2_statfs_init(struct gfs2_sbd *sdp); | 40 | extern int gfs2_statfs_init(struct gfs2_sbd *sdp); |
| 41 | extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, | 41 | extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, |
| 42 | s64 dinodes); | 42 | s64 dinodes); |
| @@ -54,6 +54,7 @@ extern struct file_system_type gfs2meta_fs_type; | |||
| 54 | extern const struct export_operations gfs2_export_ops; | 54 | extern const struct export_operations gfs2_export_ops; |
| 55 | extern const struct super_operations gfs2_super_ops; | 55 | extern const struct super_operations gfs2_super_ops; |
| 56 | extern const struct dentry_operations gfs2_dops; | 56 | extern const struct dentry_operations gfs2_dops; |
| 57 | extern struct xattr_handler *gfs2_xattr_handlers[]; | ||
| 57 | 58 | ||
| 58 | #endif /* __SUPER_DOT_H__ */ | 59 | #endif /* __SUPER_DOT_H__ */ |
| 59 | 60 | ||
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index a7cbfbd340c..446329728d5 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/kobject.h> | 16 | #include <linux/kobject.h> |
| 17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
| 18 | #include <linux/gfs2_ondisk.h> | 18 | #include <linux/gfs2_ondisk.h> |
| 19 | #include <linux/genhd.h> | ||
| 19 | 20 | ||
| 20 | #include "gfs2.h" | 21 | #include "gfs2.h" |
| 21 | #include "incore.h" | 22 | #include "incore.h" |
| @@ -319,12 +320,6 @@ static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len) | |||
| 319 | return ret; | 320 | return ret; |
| 320 | } | 321 | } |
| 321 | 322 | ||
| 322 | static ssize_t lkid_show(struct gfs2_sbd *sdp, char *buf) | ||
| 323 | { | ||
| 324 | struct lm_lockstruct *ls = &sdp->sd_lockstruct; | ||
| 325 | return sprintf(buf, "%u\n", ls->ls_id); | ||
| 326 | } | ||
| 327 | |||
| 328 | static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf) | 323 | static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf) |
| 329 | { | 324 | { |
| 330 | struct lm_lockstruct *ls = &sdp->sd_lockstruct; | 325 | struct lm_lockstruct *ls = &sdp->sd_lockstruct; |
| @@ -389,7 +384,6 @@ static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) | |||
| 389 | GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); | 384 | GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); |
| 390 | GDLM_ATTR(block, 0644, block_show, block_store); | 385 | GDLM_ATTR(block, 0644, block_show, block_store); |
| 391 | GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); | 386 | GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); |
| 392 | GDLM_ATTR(id, 0444, lkid_show, NULL); | ||
| 393 | GDLM_ATTR(jid, 0444, jid_show, NULL); | 387 | GDLM_ATTR(jid, 0444, jid_show, NULL); |
| 394 | GDLM_ATTR(first, 0444, lkfirst_show, NULL); | 388 | GDLM_ATTR(first, 0444, lkfirst_show, NULL); |
| 395 | GDLM_ATTR(first_done, 0444, first_done_show, NULL); | 389 | GDLM_ATTR(first_done, 0444, first_done_show, NULL); |
| @@ -401,7 +395,6 @@ static struct attribute *lock_module_attrs[] = { | |||
| 401 | &gdlm_attr_proto_name.attr, | 395 | &gdlm_attr_proto_name.attr, |
| 402 | &gdlm_attr_block.attr, | 396 | &gdlm_attr_block.attr, |
| 403 | &gdlm_attr_withdraw.attr, | 397 | &gdlm_attr_withdraw.attr, |
| 404 | &gdlm_attr_id.attr, | ||
| 405 | &gdlm_attr_jid.attr, | 398 | &gdlm_attr_jid.attr, |
| 406 | &gdlm_attr_first.attr, | 399 | &gdlm_attr_first.attr, |
| 407 | &gdlm_attr_first_done.attr, | 400 | &gdlm_attr_first_done.attr, |
| @@ -519,7 +512,14 @@ static struct attribute_group lock_module_group = { | |||
| 519 | 512 | ||
| 520 | int gfs2_sys_fs_add(struct gfs2_sbd *sdp) | 513 | int gfs2_sys_fs_add(struct gfs2_sbd *sdp) |
| 521 | { | 514 | { |
| 515 | struct super_block *sb = sdp->sd_vfs; | ||
| 522 | int error; | 516 | int error; |
| 517 | char ro[20]; | ||
| 518 | char spectator[20]; | ||
| 519 | char *envp[] = { ro, spectator, NULL }; | ||
| 520 | |||
| 521 | sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0); | ||
| 522 | sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0); | ||
| 523 | 523 | ||
| 524 | sdp->sd_kobj.kset = gfs2_kset; | 524 | sdp->sd_kobj.kset = gfs2_kset; |
| 525 | error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL, | 525 | error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL, |
| @@ -535,9 +535,17 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp) | |||
| 535 | if (error) | 535 | if (error) |
| 536 | goto fail_tune; | 536 | goto fail_tune; |
| 537 | 537 | ||
| 538 | kobject_uevent(&sdp->sd_kobj, KOBJ_ADD); | 538 | error = sysfs_create_link(&sdp->sd_kobj, |
| 539 | &disk_to_dev(sb->s_bdev->bd_disk)->kobj, | ||
| 540 | "device"); | ||
| 541 | if (error) | ||
| 542 | goto fail_lock_module; | ||
| 543 | |||
| 544 | kobject_uevent_env(&sdp->sd_kobj, KOBJ_ADD, envp); | ||
| 539 | return 0; | 545 | return 0; |
| 540 | 546 | ||
| 547 | fail_lock_module: | ||
| 548 | sysfs_remove_group(&sdp->sd_kobj, &lock_module_group); | ||
| 541 | fail_tune: | 549 | fail_tune: |
| 542 | sysfs_remove_group(&sdp->sd_kobj, &tune_group); | 550 | sysfs_remove_group(&sdp->sd_kobj, &tune_group); |
| 543 | fail_reg: | 551 | fail_reg: |
| @@ -549,12 +557,12 @@ fail: | |||
| 549 | 557 | ||
| 550 | void gfs2_sys_fs_del(struct gfs2_sbd *sdp) | 558 | void gfs2_sys_fs_del(struct gfs2_sbd *sdp) |
| 551 | { | 559 | { |
| 560 | sysfs_remove_link(&sdp->sd_kobj, "device"); | ||
| 552 | sysfs_remove_group(&sdp->sd_kobj, &tune_group); | 561 | sysfs_remove_group(&sdp->sd_kobj, &tune_group); |
| 553 | sysfs_remove_group(&sdp->sd_kobj, &lock_module_group); | 562 | sysfs_remove_group(&sdp->sd_kobj, &lock_module_group); |
| 554 | kobject_put(&sdp->sd_kobj); | 563 | kobject_put(&sdp->sd_kobj); |
| 555 | } | 564 | } |
| 556 | 565 | ||
| 557 | |||
| 558 | static int gfs2_uevent(struct kset *kset, struct kobject *kobj, | 566 | static int gfs2_uevent(struct kset *kset, struct kobject *kobj, |
| 559 | struct kobj_uevent_env *env) | 567 | struct kobj_uevent_env *env) |
| 560 | { | 568 | { |
| @@ -563,6 +571,8 @@ static int gfs2_uevent(struct kset *kset, struct kobject *kobj, | |||
| 563 | 571 | ||
| 564 | add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name); | 572 | add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name); |
| 565 | add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name); | 573 | add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name); |
| 574 | if (!sdp->sd_args.ar_spectator) | ||
| 575 | add_uevent_var(env, "JOURNALID=%u", sdp->sd_lockstruct.ls_jid); | ||
| 566 | if (gfs2_uuid_valid(uuid)) { | 576 | if (gfs2_uuid_valid(uuid)) { |
| 567 | add_uevent_var(env, "UUID=%02X%02X%02X%02X-%02X%02X-%02X%02X-" | 577 | add_uevent_var(env, "UUID=%02X%02X%02X%02X-%02X%02X-%02X%02X-" |
| 568 | "%02X%02X-%02X%02X%02X%02X%02X%02X", | 578 | "%02X%02X-%02X%02X%02X%02X%02X%02X", |
| @@ -578,7 +588,6 @@ static struct kset_uevent_ops gfs2_uevent_ops = { | |||
| 578 | .uevent = gfs2_uevent, | 588 | .uevent = gfs2_uevent, |
| 579 | }; | 589 | }; |
| 580 | 590 | ||
| 581 | |||
| 582 | int gfs2_sys_init(void) | 591 | int gfs2_sys_init(void) |
| 583 | { | 592 | { |
| 584 | gfs2_kset = kset_create_and_add("gfs2", &gfs2_uevent_ops, fs_kobj); | 593 | gfs2_kset = kset_create_and_add("gfs2", &gfs2_uevent_ops, fs_kobj); |
diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 9d12b1118ba..f6a7efa34eb 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c | |||
| @@ -38,24 +38,30 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) | |||
| 38 | const struct lm_lockops *lm = ls->ls_ops; | 38 | const struct lm_lockops *lm = ls->ls_ops; |
| 39 | va_list args; | 39 | va_list args; |
| 40 | 40 | ||
| 41 | if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) | 41 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW && |
| 42 | test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) | ||
| 42 | return 0; | 43 | return 0; |
| 43 | 44 | ||
| 44 | va_start(args, fmt); | 45 | va_start(args, fmt); |
| 45 | vprintk(fmt, args); | 46 | vprintk(fmt, args); |
| 46 | va_end(args); | 47 | va_end(args); |
| 47 | 48 | ||
| 48 | fs_err(sdp, "about to withdraw this file system\n"); | 49 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) { |
| 49 | BUG_ON(sdp->sd_args.ar_debug); | 50 | fs_err(sdp, "about to withdraw this file system\n"); |
| 51 | BUG_ON(sdp->sd_args.ar_debug); | ||
| 50 | 52 | ||
| 51 | kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE); | 53 | kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE); |
| 52 | 54 | ||
| 53 | if (lm->lm_unmount) { | 55 | if (lm->lm_unmount) { |
| 54 | fs_err(sdp, "telling LM to unmount\n"); | 56 | fs_err(sdp, "telling LM to unmount\n"); |
| 55 | lm->lm_unmount(sdp); | 57 | lm->lm_unmount(sdp); |
| 58 | } | ||
| 59 | fs_err(sdp, "withdrawn\n"); | ||
| 60 | dump_stack(); | ||
| 56 | } | 61 | } |
| 57 | fs_err(sdp, "withdrawn\n"); | 62 | |
| 58 | dump_stack(); | 63 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) |
| 64 | panic("GFS2: fsid=%s: panic requested.\n", sdp->sd_fsname); | ||
| 59 | 65 | ||
| 60 | return -1; | 66 | return -1; |
| 61 | } | 67 | } |
| @@ -93,17 +99,24 @@ int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion, | |||
| 93 | gfs2_tune_get(sdp, gt_complain_secs) * HZ)) | 99 | gfs2_tune_get(sdp, gt_complain_secs) * HZ)) |
| 94 | return -2; | 100 | return -2; |
| 95 | 101 | ||
| 96 | printk(KERN_WARNING | 102 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) |
| 97 | "GFS2: fsid=%s: warning: assertion \"%s\" failed\n" | 103 | printk(KERN_WARNING |
| 98 | "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", | 104 | "GFS2: fsid=%s: warning: assertion \"%s\" failed\n" |
| 99 | sdp->sd_fsname, assertion, | 105 | "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", |
| 100 | sdp->sd_fsname, function, file, line); | 106 | sdp->sd_fsname, assertion, |
| 107 | sdp->sd_fsname, function, file, line); | ||
| 101 | 108 | ||
| 102 | if (sdp->sd_args.ar_debug) | 109 | if (sdp->sd_args.ar_debug) |
| 103 | BUG(); | 110 | BUG(); |
| 104 | else | 111 | else |
| 105 | dump_stack(); | 112 | dump_stack(); |
| 106 | 113 | ||
| 114 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) | ||
| 115 | panic("GFS2: fsid=%s: warning: assertion \"%s\" failed\n" | ||
| 116 | "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", | ||
| 117 | sdp->sd_fsname, assertion, | ||
| 118 | sdp->sd_fsname, function, file, line); | ||
| 119 | |||
| 107 | sdp->sd_last_warning = jiffies; | 120 | sdp->sd_last_warning = jiffies; |
| 108 | 121 | ||
| 109 | return -1; | 122 | return -1; |
diff --git a/fs/gfs2/eattr.c b/fs/gfs2/xattr.c index 07ea9529add..8a0f8ef6ee2 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/xattr.c | |||
| @@ -18,8 +18,7 @@ | |||
| 18 | #include "gfs2.h" | 18 | #include "gfs2.h" |
| 19 | #include "incore.h" | 19 | #include "incore.h" |
| 20 | #include "acl.h" | 20 | #include "acl.h" |
| 21 | #include "eaops.h" | 21 | #include "xattr.h" |
| 22 | #include "eattr.h" | ||
| 23 | #include "glock.h" | 22 | #include "glock.h" |
| 24 | #include "inode.h" | 23 | #include "inode.h" |
| 25 | #include "meta_io.h" | 24 | #include "meta_io.h" |
| @@ -38,26 +37,32 @@ | |||
| 38 | * Returns: 1 if the EA should be stuffed | 37 | * Returns: 1 if the EA should be stuffed |
| 39 | */ | 38 | */ |
| 40 | 39 | ||
| 41 | static int ea_calc_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er, | 40 | static int ea_calc_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize, |
| 42 | unsigned int *size) | 41 | unsigned int *size) |
| 43 | { | 42 | { |
| 44 | *size = GFS2_EAREQ_SIZE_STUFFED(er); | 43 | unsigned int jbsize = sdp->sd_jbsize; |
| 45 | if (*size <= sdp->sd_jbsize) | 44 | |
| 45 | /* Stuffed */ | ||
| 46 | *size = ALIGN(sizeof(struct gfs2_ea_header) + nsize + dsize, 8); | ||
| 47 | |||
| 48 | if (*size <= jbsize) | ||
| 46 | return 1; | 49 | return 1; |
| 47 | 50 | ||
| 48 | *size = GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er); | 51 | /* Unstuffed */ |
| 52 | *size = ALIGN(sizeof(struct gfs2_ea_header) + nsize + | ||
| 53 | (sizeof(__be64) * DIV_ROUND_UP(dsize, jbsize)), 8); | ||
| 49 | 54 | ||
| 50 | return 0; | 55 | return 0; |
| 51 | } | 56 | } |
| 52 | 57 | ||
| 53 | static int ea_check_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er) | 58 | static int ea_check_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize) |
| 54 | { | 59 | { |
| 55 | unsigned int size; | 60 | unsigned int size; |
| 56 | 61 | ||
| 57 | if (er->er_data_len > GFS2_EA_MAX_DATA_LEN) | 62 | if (dsize > GFS2_EA_MAX_DATA_LEN) |
| 58 | return -ERANGE; | 63 | return -ERANGE; |
| 59 | 64 | ||
| 60 | ea_calc_size(sdp, er, &size); | 65 | ea_calc_size(sdp, nsize, dsize, &size); |
| 61 | 66 | ||
| 62 | /* This can only happen with 512 byte blocks */ | 67 | /* This can only happen with 512 byte blocks */ |
| 63 | if (size > sdp->sd_jbsize) | 68 | if (size > sdp->sd_jbsize) |
| @@ -151,7 +156,9 @@ out: | |||
| 151 | } | 156 | } |
| 152 | 157 | ||
| 153 | struct ea_find { | 158 | struct ea_find { |
| 154 | struct gfs2_ea_request *ef_er; | 159 | int type; |
| 160 | const char *name; | ||
| 161 | size_t namel; | ||
| 155 | struct gfs2_ea_location *ef_el; | 162 | struct gfs2_ea_location *ef_el; |
| 156 | }; | 163 | }; |
| 157 | 164 | ||
| @@ -160,14 +167,13 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
| 160 | void *private) | 167 | void *private) |
| 161 | { | 168 | { |
| 162 | struct ea_find *ef = private; | 169 | struct ea_find *ef = private; |
| 163 | struct gfs2_ea_request *er = ef->ef_er; | ||
| 164 | 170 | ||
| 165 | if (ea->ea_type == GFS2_EATYPE_UNUSED) | 171 | if (ea->ea_type == GFS2_EATYPE_UNUSED) |
| 166 | return 0; | 172 | return 0; |
| 167 | 173 | ||
| 168 | if (ea->ea_type == er->er_type) { | 174 | if (ea->ea_type == ef->type) { |
| 169 | if (ea->ea_name_len == er->er_name_len && | 175 | if (ea->ea_name_len == ef->namel && |
| 170 | !memcmp(GFS2_EA2NAME(ea), er->er_name, ea->ea_name_len)) { | 176 | !memcmp(GFS2_EA2NAME(ea), ef->name, ea->ea_name_len)) { |
| 171 | struct gfs2_ea_location *el = ef->ef_el; | 177 | struct gfs2_ea_location *el = ef->ef_el; |
| 172 | get_bh(bh); | 178 | get_bh(bh); |
| 173 | el->el_bh = bh; | 179 | el->el_bh = bh; |
| @@ -180,13 +186,15 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
| 180 | return 0; | 186 | return 0; |
| 181 | } | 187 | } |
| 182 | 188 | ||
| 183 | int gfs2_ea_find(struct gfs2_inode *ip, struct gfs2_ea_request *er, | 189 | int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, |
| 184 | struct gfs2_ea_location *el) | 190 | struct gfs2_ea_location *el) |
| 185 | { | 191 | { |
| 186 | struct ea_find ef; | 192 | struct ea_find ef; |
| 187 | int error; | 193 | int error; |
| 188 | 194 | ||
| 189 | ef.ef_er = er; | 195 | ef.type = type; |
| 196 | ef.name = name; | ||
| 197 | ef.namel = strlen(name); | ||
| 190 | ef.ef_el = el; | 198 | ef.ef_el = el; |
| 191 | 199 | ||
| 192 | memset(el, 0, sizeof(struct gfs2_ea_location)); | 200 | memset(el, 0, sizeof(struct gfs2_ea_location)); |
| @@ -344,6 +352,20 @@ struct ea_list { | |||
| 344 | unsigned int ei_size; | 352 | unsigned int ei_size; |
| 345 | }; | 353 | }; |
| 346 | 354 | ||
| 355 | static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea) | ||
| 356 | { | ||
| 357 | switch (ea->ea_type) { | ||
| 358 | case GFS2_EATYPE_USR: | ||
| 359 | return 5 + ea->ea_name_len + 1; | ||
| 360 | case GFS2_EATYPE_SYS: | ||
| 361 | return 7 + ea->ea_name_len + 1; | ||
| 362 | case GFS2_EATYPE_SECURITY: | ||
| 363 | return 9 + ea->ea_name_len + 1; | ||
| 364 | default: | ||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 347 | static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, | 369 | static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, |
| 348 | struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, | 370 | struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, |
| 349 | void *private) | 371 | void *private) |
| @@ -392,21 +414,25 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
| 392 | } | 414 | } |
| 393 | 415 | ||
| 394 | /** | 416 | /** |
| 395 | * gfs2_ea_list - | 417 | * gfs2_listxattr - List gfs2 extended attributes |
| 396 | * @ip: | 418 | * @dentry: The dentry whose inode we are interested in |
| 397 | * @er: | 419 | * @buffer: The buffer to write the results |
| 420 | * @size: The size of the buffer | ||
| 398 | * | 421 | * |
| 399 | * Returns: actual size of data on success, -errno on error | 422 | * Returns: actual size of data on success, -errno on error |
| 400 | */ | 423 | */ |
| 401 | 424 | ||
| 402 | int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 425 | ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) |
| 403 | { | 426 | { |
| 427 | struct gfs2_inode *ip = GFS2_I(dentry->d_inode); | ||
| 428 | struct gfs2_ea_request er; | ||
| 404 | struct gfs2_holder i_gh; | 429 | struct gfs2_holder i_gh; |
| 405 | int error; | 430 | int error; |
| 406 | 431 | ||
| 407 | if (!er->er_data || !er->er_data_len) { | 432 | memset(&er, 0, sizeof(struct gfs2_ea_request)); |
| 408 | er->er_data = NULL; | 433 | if (size) { |
| 409 | er->er_data_len = 0; | 434 | er.er_data = buffer; |
| 435 | er.er_data_len = size; | ||
| 410 | } | 436 | } |
| 411 | 437 | ||
| 412 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); | 438 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); |
| @@ -414,7 +440,7 @@ int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er) | |||
| 414 | return error; | 440 | return error; |
| 415 | 441 | ||
| 416 | if (ip->i_eattr) { | 442 | if (ip->i_eattr) { |
| 417 | struct ea_list ei = { .ei_er = er, .ei_size = 0 }; | 443 | struct ea_list ei = { .ei_er = &er, .ei_size = 0 }; |
| 418 | 444 | ||
| 419 | error = ea_foreach(ip, ea_list_i, &ei); | 445 | error = ea_foreach(ip, ea_list_i, &ei); |
| 420 | if (!error) | 446 | if (!error) |
| @@ -491,84 +517,61 @@ out: | |||
| 491 | } | 517 | } |
| 492 | 518 | ||
| 493 | int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, | 519 | int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, |
| 494 | char *data) | 520 | char *data, size_t size) |
| 495 | { | 521 | { |
| 522 | int ret; | ||
| 523 | size_t len = GFS2_EA_DATA_LEN(el->el_ea); | ||
| 524 | if (len > size) | ||
| 525 | return -ERANGE; | ||
| 526 | |||
| 496 | if (GFS2_EA_IS_STUFFED(el->el_ea)) { | 527 | if (GFS2_EA_IS_STUFFED(el->el_ea)) { |
| 497 | memcpy(data, GFS2_EA2DATA(el->el_ea), GFS2_EA_DATA_LEN(el->el_ea)); | 528 | memcpy(data, GFS2_EA2DATA(el->el_ea), len); |
| 498 | return 0; | 529 | return len; |
| 499 | } else | 530 | } |
| 500 | return ea_get_unstuffed(ip, el->el_ea, data); | 531 | ret = ea_get_unstuffed(ip, el->el_ea, data); |
| 532 | if (ret < 0) | ||
| 533 | return ret; | ||
| 534 | return len; | ||
| 501 | } | 535 | } |
| 502 | 536 | ||
| 503 | /** | 537 | /** |
| 504 | * gfs2_ea_get_i - | 538 | * gfs2_xattr_get - Get a GFS2 extended attribute |
| 505 | * @ip: The GFS2 inode | 539 | * @inode: The inode |
| 506 | * @er: The request structure | 540 | * @type: The type of extended attribute |
| 541 | * @name: The name of the extended attribute | ||
| 542 | * @buffer: The buffer to write the result into | ||
| 543 | * @size: The size of the buffer | ||
| 507 | * | 544 | * |
| 508 | * Returns: actual size of data on success, -errno on error | 545 | * Returns: actual size of data on success, -errno on error |
| 509 | */ | 546 | */ |
| 510 | 547 | ||
| 511 | int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 548 | int gfs2_xattr_get(struct inode *inode, int type, const char *name, |
| 549 | void *buffer, size_t size) | ||
| 512 | { | 550 | { |
| 551 | struct gfs2_inode *ip = GFS2_I(inode); | ||
| 513 | struct gfs2_ea_location el; | 552 | struct gfs2_ea_location el; |
| 514 | int error; | 553 | int error; |
| 515 | 554 | ||
| 516 | if (!ip->i_eattr) | 555 | if (!ip->i_eattr) |
| 517 | return -ENODATA; | 556 | return -ENODATA; |
| 557 | if (strlen(name) > GFS2_EA_MAX_NAME_LEN) | ||
| 558 | return -EINVAL; | ||
| 518 | 559 | ||
| 519 | error = gfs2_ea_find(ip, er, &el); | 560 | error = gfs2_ea_find(ip, type, name, &el); |
| 520 | if (error) | 561 | if (error) |
| 521 | return error; | 562 | return error; |
| 522 | if (!el.el_ea) | 563 | if (!el.el_ea) |
| 523 | return -ENODATA; | 564 | return -ENODATA; |
| 524 | 565 | if (size) | |
| 525 | if (er->er_data_len) { | 566 | error = gfs2_ea_get_copy(ip, &el, buffer, size); |
| 526 | if (GFS2_EA_DATA_LEN(el.el_ea) > er->er_data_len) | 567 | else |
| 527 | error = -ERANGE; | ||
| 528 | else | ||
| 529 | error = gfs2_ea_get_copy(ip, &el, er->er_data); | ||
| 530 | } | ||
| 531 | if (!error) | ||
| 532 | error = GFS2_EA_DATA_LEN(el.el_ea); | 568 | error = GFS2_EA_DATA_LEN(el.el_ea); |
| 533 | |||
| 534 | brelse(el.el_bh); | 569 | brelse(el.el_bh); |
| 535 | 570 | ||
| 536 | return error; | 571 | return error; |
| 537 | } | 572 | } |
| 538 | 573 | ||
| 539 | /** | 574 | /** |
| 540 | * gfs2_ea_get - | ||
| 541 | * @ip: The GFS2 inode | ||
| 542 | * @er: The request structure | ||
| 543 | * | ||
| 544 | * Returns: actual size of data on success, -errno on error | ||
| 545 | */ | ||
| 546 | |||
| 547 | int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
| 548 | { | ||
| 549 | struct gfs2_holder i_gh; | ||
| 550 | int error; | ||
| 551 | |||
| 552 | if (!er->er_name_len || | ||
| 553 | er->er_name_len > GFS2_EA_MAX_NAME_LEN) | ||
| 554 | return -EINVAL; | ||
| 555 | if (!er->er_data || !er->er_data_len) { | ||
| 556 | er->er_data = NULL; | ||
| 557 | er->er_data_len = 0; | ||
| 558 | } | ||
| 559 | |||
| 560 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); | ||
| 561 | if (error) | ||
| 562 | return error; | ||
| 563 | |||
| 564 | error = gfs2_ea_ops[er->er_type]->eo_get(ip, er); | ||
| 565 | |||
| 566 | gfs2_glock_dq_uninit(&i_gh); | ||
| 567 | |||
| 568 | return error; | ||
| 569 | } | ||
| 570 | |||
| 571 | /** | ||
| 572 | * ea_alloc_blk - allocates a new block for extended attributes. | 575 | * ea_alloc_blk - allocates a new block for extended attributes. |
| 573 | * @ip: A pointer to the inode that's getting extended attributes | 576 | * @ip: A pointer to the inode that's getting extended attributes |
| 574 | * @bhp: Pointer to pointer to a struct buffer_head | 577 | * @bhp: Pointer to pointer to a struct buffer_head |
| @@ -713,12 +716,6 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
| 713 | 716 | ||
| 714 | error = gfs2_meta_inode_buffer(ip, &dibh); | 717 | error = gfs2_meta_inode_buffer(ip, &dibh); |
| 715 | if (!error) { | 718 | if (!error) { |
| 716 | if (er->er_flags & GFS2_ERF_MODE) { | ||
| 717 | gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), | ||
| 718 | (ip->i_inode.i_mode & S_IFMT) == | ||
| 719 | (er->er_mode & S_IFMT)); | ||
| 720 | ip->i_inode.i_mode = er->er_mode; | ||
| 721 | } | ||
| 722 | ip->i_inode.i_ctime = CURRENT_TIME; | 719 | ip->i_inode.i_ctime = CURRENT_TIME; |
| 723 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 720 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
| 724 | gfs2_dinode_out(ip, dibh->b_data); | 721 | gfs2_dinode_out(ip, dibh->b_data); |
| @@ -762,15 +759,23 @@ static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
| 762 | * Returns: errno | 759 | * Returns: errno |
| 763 | */ | 760 | */ |
| 764 | 761 | ||
| 765 | static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 762 | static int ea_init(struct gfs2_inode *ip, int type, const char *name, |
| 763 | const void *data, size_t size) | ||
| 766 | { | 764 | { |
| 765 | struct gfs2_ea_request er; | ||
| 767 | unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize; | 766 | unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize; |
| 768 | unsigned int blks = 1; | 767 | unsigned int blks = 1; |
| 769 | 768 | ||
| 770 | if (GFS2_EAREQ_SIZE_STUFFED(er) > jbsize) | 769 | er.er_type = type; |
| 771 | blks += DIV_ROUND_UP(er->er_data_len, jbsize); | 770 | er.er_name = name; |
| 771 | er.er_name_len = strlen(name); | ||
| 772 | er.er_data = (void *)data; | ||
| 773 | er.er_data_len = size; | ||
| 774 | |||
| 775 | if (GFS2_EAREQ_SIZE_STUFFED(&er) > jbsize) | ||
| 776 | blks += DIV_ROUND_UP(er.er_data_len, jbsize); | ||
| 772 | 777 | ||
| 773 | return ea_alloc_skeleton(ip, er, blks, ea_init_i, NULL); | 778 | return ea_alloc_skeleton(ip, &er, blks, ea_init_i, NULL); |
| 774 | } | 779 | } |
| 775 | 780 | ||
| 776 | static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea) | 781 | static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea) |
| @@ -848,12 +853,6 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, | |||
| 848 | error = gfs2_meta_inode_buffer(ip, &dibh); | 853 | error = gfs2_meta_inode_buffer(ip, &dibh); |
| 849 | if (error) | 854 | if (error) |
| 850 | goto out; | 855 | goto out; |
| 851 | |||
| 852 | if (er->er_flags & GFS2_ERF_MODE) { | ||
| 853 | gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), | ||
| 854 | (ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT)); | ||
| 855 | ip->i_inode.i_mode = er->er_mode; | ||
| 856 | } | ||
| 857 | ip->i_inode.i_ctime = CURRENT_TIME; | 856 | ip->i_inode.i_ctime = CURRENT_TIME; |
| 858 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 857 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
| 859 | gfs2_dinode_out(ip, dibh->b_data); | 858 | gfs2_dinode_out(ip, dibh->b_data); |
| @@ -894,7 +893,8 @@ static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh, | |||
| 894 | int stuffed; | 893 | int stuffed; |
| 895 | int error; | 894 | int error; |
| 896 | 895 | ||
| 897 | stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er, &size); | 896 | stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er->er_name_len, |
| 897 | es->es_er->er_data_len, &size); | ||
| 898 | 898 | ||
| 899 | if (ea->ea_type == GFS2_EATYPE_UNUSED) { | 899 | if (ea->ea_type == GFS2_EATYPE_UNUSED) { |
| 900 | if (GFS2_EA_REC_LEN(ea) < size) | 900 | if (GFS2_EA_REC_LEN(ea) < size) |
| @@ -1005,15 +1005,22 @@ out: | |||
| 1005 | return error; | 1005 | return error; |
| 1006 | } | 1006 | } |
| 1007 | 1007 | ||
| 1008 | static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | 1008 | static int ea_set_i(struct gfs2_inode *ip, int type, const char *name, |
| 1009 | struct gfs2_ea_location *el) | 1009 | const void *value, size_t size, struct gfs2_ea_location *el) |
| 1010 | { | 1010 | { |
| 1011 | struct gfs2_ea_request er; | ||
| 1011 | struct ea_set es; | 1012 | struct ea_set es; |
| 1012 | unsigned int blks = 2; | 1013 | unsigned int blks = 2; |
| 1013 | int error; | 1014 | int error; |
| 1014 | 1015 | ||
| 1016 | er.er_type = type; | ||
| 1017 | er.er_name = name; | ||
| 1018 | er.er_data = (void *)value; | ||
| 1019 | er.er_name_len = strlen(name); | ||
| 1020 | er.er_data_len = size; | ||
| 1021 | |||
| 1015 | memset(&es, 0, sizeof(struct ea_set)); | 1022 | memset(&es, 0, sizeof(struct ea_set)); |
| 1016 | es.es_er = er; | 1023 | es.es_er = &er; |
| 1017 | es.es_el = el; | 1024 | es.es_el = el; |
| 1018 | 1025 | ||
| 1019 | error = ea_foreach(ip, ea_set_simple, &es); | 1026 | error = ea_foreach(ip, ea_set_simple, &es); |
| @@ -1024,10 +1031,10 @@ static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
| 1024 | 1031 | ||
| 1025 | if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT)) | 1032 | if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT)) |
| 1026 | blks++; | 1033 | blks++; |
| 1027 | if (GFS2_EAREQ_SIZE_STUFFED(er) > GFS2_SB(&ip->i_inode)->sd_jbsize) | 1034 | if (GFS2_EAREQ_SIZE_STUFFED(&er) > GFS2_SB(&ip->i_inode)->sd_jbsize) |
| 1028 | blks += DIV_ROUND_UP(er->er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize); | 1035 | blks += DIV_ROUND_UP(er.er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize); |
| 1029 | 1036 | ||
| 1030 | return ea_alloc_skeleton(ip, er, blks, ea_set_block, el); | 1037 | return ea_alloc_skeleton(ip, &er, blks, ea_set_block, el); |
| 1031 | } | 1038 | } |
| 1032 | 1039 | ||
| 1033 | static int ea_set_remove_unstuffed(struct gfs2_inode *ip, | 1040 | static int ea_set_remove_unstuffed(struct gfs2_inode *ip, |
| @@ -1039,75 +1046,7 @@ static int ea_set_remove_unstuffed(struct gfs2_inode *ip, | |||
| 1039 | GFS2_EA2NEXT(el->el_prev) == el->el_ea); | 1046 | GFS2_EA2NEXT(el->el_prev) == el->el_ea); |
| 1040 | } | 1047 | } |
| 1041 | 1048 | ||
| 1042 | return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0); | 1049 | return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev, 0); |
| 1043 | } | ||
| 1044 | |||
| 1045 | int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
| 1046 | { | ||
| 1047 | struct gfs2_ea_location el; | ||
| 1048 | int error; | ||
| 1049 | |||
| 1050 | if (!ip->i_eattr) { | ||
| 1051 | if (er->er_flags & XATTR_REPLACE) | ||
| 1052 | return -ENODATA; | ||
| 1053 | return ea_init(ip, er); | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | error = gfs2_ea_find(ip, er, &el); | ||
| 1057 | if (error) | ||
| 1058 | return error; | ||
| 1059 | |||
| 1060 | if (el.el_ea) { | ||
| 1061 | if (ip->i_diskflags & GFS2_DIF_APPENDONLY) { | ||
| 1062 | brelse(el.el_bh); | ||
| 1063 | return -EPERM; | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | error = -EEXIST; | ||
| 1067 | if (!(er->er_flags & XATTR_CREATE)) { | ||
| 1068 | int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea); | ||
| 1069 | error = ea_set_i(ip, er, &el); | ||
| 1070 | if (!error && unstuffed) | ||
| 1071 | ea_set_remove_unstuffed(ip, &el); | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | brelse(el.el_bh); | ||
| 1075 | } else { | ||
| 1076 | error = -ENODATA; | ||
| 1077 | if (!(er->er_flags & XATTR_REPLACE)) | ||
| 1078 | error = ea_set_i(ip, er, NULL); | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | return error; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
| 1085 | { | ||
| 1086 | struct gfs2_holder i_gh; | ||
| 1087 | int error; | ||
| 1088 | |||
| 1089 | if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN) | ||
| 1090 | return -EINVAL; | ||
| 1091 | if (!er->er_data || !er->er_data_len) { | ||
| 1092 | er->er_data = NULL; | ||
| 1093 | er->er_data_len = 0; | ||
| 1094 | } | ||
| 1095 | error = ea_check_size(GFS2_SB(&ip->i_inode), er); | ||
| 1096 | if (error) | ||
| 1097 | return error; | ||
| 1098 | |||
| 1099 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); | ||
| 1100 | if (error) | ||
| 1101 | return error; | ||
| 1102 | |||
| 1103 | if (IS_IMMUTABLE(&ip->i_inode)) | ||
| 1104 | error = -EPERM; | ||
| 1105 | else | ||
| 1106 | error = gfs2_ea_ops[er->er_type]->eo_set(ip, er); | ||
| 1107 | |||
| 1108 | gfs2_glock_dq_uninit(&i_gh); | ||
| 1109 | |||
| 1110 | return error; | ||
| 1111 | } | 1050 | } |
| 1112 | 1051 | ||
| 1113 | static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) | 1052 | static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) |
| @@ -1131,8 +1070,9 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) | |||
| 1131 | 1070 | ||
| 1132 | if (GFS2_EA_IS_LAST(ea)) | 1071 | if (GFS2_EA_IS_LAST(ea)) |
| 1133 | prev->ea_flags |= GFS2_EAFLAG_LAST; | 1072 | prev->ea_flags |= GFS2_EAFLAG_LAST; |
| 1134 | } else | 1073 | } else { |
| 1135 | ea->ea_type = GFS2_EATYPE_UNUSED; | 1074 | ea->ea_type = GFS2_EATYPE_UNUSED; |
| 1075 | } | ||
| 1136 | 1076 | ||
| 1137 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1077 | error = gfs2_meta_inode_buffer(ip, &dibh); |
| 1138 | if (!error) { | 1078 | if (!error) { |
| @@ -1147,15 +1087,29 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) | |||
| 1147 | return error; | 1087 | return error; |
| 1148 | } | 1088 | } |
| 1149 | 1089 | ||
| 1150 | int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 1090 | /** |
| 1091 | * gfs2_xattr_remove - Remove a GFS2 extended attribute | ||
| 1092 | * @inode: The inode | ||
| 1093 | * @type: The type of the extended attribute | ||
| 1094 | * @name: The name of the extended attribute | ||
| 1095 | * | ||
| 1096 | * This is not called directly by the VFS since we use the (common) | ||
| 1097 | * scheme of making a "set with NULL data" mean a remove request. Note | ||
| 1098 | * that this is different from a set with zero length data. | ||
| 1099 | * | ||
| 1100 | * Returns: 0, or errno on failure | ||
| 1101 | */ | ||
| 1102 | |||
| 1103 | static int gfs2_xattr_remove(struct inode *inode, int type, const char *name) | ||
| 1151 | { | 1104 | { |
| 1105 | struct gfs2_inode *ip = GFS2_I(inode); | ||
| 1152 | struct gfs2_ea_location el; | 1106 | struct gfs2_ea_location el; |
| 1153 | int error; | 1107 | int error; |
| 1154 | 1108 | ||
| 1155 | if (!ip->i_eattr) | 1109 | if (!ip->i_eattr) |
| 1156 | return -ENODATA; | 1110 | return -ENODATA; |
| 1157 | 1111 | ||
| 1158 | error = gfs2_ea_find(ip, er, &el); | 1112 | error = gfs2_ea_find(ip, type, name, &el); |
| 1159 | if (error) | 1113 | if (error) |
| 1160 | return error; | 1114 | return error; |
| 1161 | if (!el.el_ea) | 1115 | if (!el.el_ea) |
| @@ -1164,8 +1118,7 @@ int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | |||
| 1164 | if (GFS2_EA_IS_STUFFED(el.el_ea)) | 1118 | if (GFS2_EA_IS_STUFFED(el.el_ea)) |
| 1165 | error = ea_remove_stuffed(ip, &el); | 1119 | error = ea_remove_stuffed(ip, &el); |
| 1166 | else | 1120 | else |
| 1167 | error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, | 1121 | error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, 0); |
| 1168 | 0); | ||
| 1169 | 1122 | ||
| 1170 | brelse(el.el_bh); | 1123 | brelse(el.el_bh); |
| 1171 | 1124 | ||
| @@ -1173,31 +1126,70 @@ int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | |||
| 1173 | } | 1126 | } |
| 1174 | 1127 | ||
| 1175 | /** | 1128 | /** |
| 1176 | * gfs2_ea_remove - sets (or creates or replaces) an extended attribute | 1129 | * gfs2_xattr_set - Set (or remove) a GFS2 extended attribute |
| 1177 | * @ip: pointer to the inode of the target file | 1130 | * @inode: The inode |
| 1178 | * @er: request information | 1131 | * @type: The type of the extended attribute |
| 1132 | * @name: The name of the extended attribute | ||
| 1133 | * @value: The value of the extended attribute (NULL for remove) | ||
| 1134 | * @size: The size of the @value argument | ||
| 1135 | * @flags: Create or Replace | ||
| 1179 | * | 1136 | * |
| 1180 | * Returns: errno | 1137 | * See gfs2_xattr_remove() for details of the removal of xattrs. |
| 1138 | * | ||
| 1139 | * Returns: 0 or errno on failure | ||
| 1181 | */ | 1140 | */ |
| 1182 | 1141 | ||
| 1183 | int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 1142 | int gfs2_xattr_set(struct inode *inode, int type, const char *name, |
| 1143 | const void *value, size_t size, int flags) | ||
| 1184 | { | 1144 | { |
| 1185 | struct gfs2_holder i_gh; | 1145 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
| 1146 | struct gfs2_inode *ip = GFS2_I(inode); | ||
| 1147 | struct gfs2_ea_location el; | ||
| 1148 | unsigned int namel = strlen(name); | ||
| 1186 | int error; | 1149 | int error; |
| 1187 | 1150 | ||
| 1188 | if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN) | 1151 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
| 1189 | return -EINVAL; | 1152 | return -EPERM; |
| 1153 | if (namel > GFS2_EA_MAX_NAME_LEN) | ||
| 1154 | return -ERANGE; | ||
| 1190 | 1155 | ||
| 1191 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); | 1156 | if (value == NULL) |
| 1157 | return gfs2_xattr_remove(inode, type, name); | ||
| 1158 | |||
| 1159 | if (ea_check_size(sdp, namel, size)) | ||
| 1160 | return -ERANGE; | ||
| 1161 | |||
| 1162 | if (!ip->i_eattr) { | ||
| 1163 | if (flags & XATTR_REPLACE) | ||
| 1164 | return -ENODATA; | ||
| 1165 | return ea_init(ip, type, name, value, size); | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | error = gfs2_ea_find(ip, type, name, &el); | ||
| 1192 | if (error) | 1169 | if (error) |
| 1193 | return error; | 1170 | return error; |
| 1194 | 1171 | ||
| 1195 | if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) | 1172 | if (el.el_ea) { |
| 1196 | error = -EPERM; | 1173 | if (ip->i_diskflags & GFS2_DIF_APPENDONLY) { |
| 1197 | else | 1174 | brelse(el.el_bh); |
| 1198 | error = gfs2_ea_ops[er->er_type]->eo_remove(ip, er); | 1175 | return -EPERM; |
| 1176 | } | ||
| 1199 | 1177 | ||
| 1200 | gfs2_glock_dq_uninit(&i_gh); | 1178 | error = -EEXIST; |
| 1179 | if (!(flags & XATTR_CREATE)) { | ||
| 1180 | int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea); | ||
| 1181 | error = ea_set_i(ip, type, name, value, size, &el); | ||
| 1182 | if (!error && unstuffed) | ||
| 1183 | ea_set_remove_unstuffed(ip, &el); | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | brelse(el.el_bh); | ||
| 1187 | return error; | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | error = -ENODATA; | ||
| 1191 | if (!(flags & XATTR_REPLACE)) | ||
| 1192 | error = ea_set_i(ip, type, name, value, size, NULL); | ||
| 1201 | 1193 | ||
| 1202 | return error; | 1194 | return error; |
| 1203 | } | 1195 | } |
| @@ -1503,3 +1495,64 @@ out_alloc: | |||
| 1503 | return error; | 1495 | return error; |
| 1504 | } | 1496 | } |
| 1505 | 1497 | ||
| 1498 | static int gfs2_xattr_user_get(struct inode *inode, const char *name, | ||
| 1499 | void *buffer, size_t size) | ||
| 1500 | { | ||
| 1501 | return gfs2_xattr_get(inode, GFS2_EATYPE_USR, name, buffer, size); | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | static int gfs2_xattr_user_set(struct inode *inode, const char *name, | ||
| 1505 | const void *value, size_t size, int flags) | ||
| 1506 | { | ||
| 1507 | return gfs2_xattr_set(inode, GFS2_EATYPE_USR, name, value, size, flags); | ||
| 1508 | } | ||
| 1509 | |||
| 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, | ||
| 1523 | void *buffer, size_t size) | ||
| 1524 | { | ||
| 1525 | return gfs2_xattr_get(inode, GFS2_EATYPE_SECURITY, name, buffer, size); | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | static int gfs2_xattr_security_set(struct inode *inode, const char *name, | ||
| 1529 | const void *value, size_t size, int flags) | ||
| 1530 | { | ||
| 1531 | return gfs2_xattr_set(inode, GFS2_EATYPE_SECURITY, name, value, size, flags); | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | static struct xattr_handler gfs2_xattr_user_handler = { | ||
| 1535 | .prefix = XATTR_USER_PREFIX, | ||
| 1536 | .get = gfs2_xattr_user_get, | ||
| 1537 | .set = gfs2_xattr_user_set, | ||
| 1538 | }; | ||
| 1539 | |||
| 1540 | static struct xattr_handler gfs2_xattr_security_handler = { | ||
| 1541 | .prefix = XATTR_SECURITY_PREFIX, | ||
| 1542 | .get = gfs2_xattr_security_get, | ||
| 1543 | .set = gfs2_xattr_security_set, | ||
| 1544 | }; | ||
| 1545 | |||
| 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[] = { | ||
| 1553 | &gfs2_xattr_user_handler, | ||
| 1554 | &gfs2_xattr_security_handler, | ||
| 1555 | &gfs2_xattr_system_handler, | ||
| 1556 | NULL, | ||
| 1557 | }; | ||
| 1558 | |||
diff --git a/fs/gfs2/eattr.h b/fs/gfs2/xattr.h index c82dbe01d71..cbdfd774373 100644 --- a/fs/gfs2/eattr.h +++ b/fs/gfs2/xattr.h | |||
| @@ -19,7 +19,7 @@ struct iattr; | |||
| 19 | #define GFS2_EA_SIZE(ea) \ | 19 | #define GFS2_EA_SIZE(ea) \ |
| 20 | ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \ | 20 | ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \ |
| 21 | ((GFS2_EA_IS_STUFFED(ea)) ? GFS2_EA_DATA_LEN(ea) : \ | 21 | ((GFS2_EA_IS_STUFFED(ea)) ? GFS2_EA_DATA_LEN(ea) : \ |
| 22 | (sizeof(__be64) * (ea)->ea_num_ptrs)), 8) | 22 | (sizeof(__be64) * (ea)->ea_num_ptrs)), 8) |
| 23 | 23 | ||
| 24 | #define GFS2_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs) | 24 | #define GFS2_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs) |
| 25 | #define GFS2_EA_IS_LAST(ea) ((ea)->ea_flags & GFS2_EAFLAG_LAST) | 25 | #define GFS2_EA_IS_LAST(ea) ((ea)->ea_flags & GFS2_EAFLAG_LAST) |
| @@ -27,10 +27,6 @@ ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \ | |||
| 27 | #define GFS2_EAREQ_SIZE_STUFFED(er) \ | 27 | #define GFS2_EAREQ_SIZE_STUFFED(er) \ |
| 28 | ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8) | 28 | ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8) |
| 29 | 29 | ||
| 30 | #define GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er) \ | ||
| 31 | ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \ | ||
| 32 | sizeof(__be64) * DIV_ROUND_UP((er)->er_data_len, (sdp)->sd_jbsize), 8) | ||
| 33 | |||
| 34 | #define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1)) | 30 | #define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1)) |
| 35 | #define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len) | 31 | #define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len) |
| 36 | 32 | ||
| @@ -43,16 +39,12 @@ ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \ | |||
| 43 | #define GFS2_EA_BH2FIRST(bh) \ | 39 | #define GFS2_EA_BH2FIRST(bh) \ |
| 44 | ((struct gfs2_ea_header *)((bh)->b_data + sizeof(struct gfs2_meta_header))) | 40 | ((struct gfs2_ea_header *)((bh)->b_data + sizeof(struct gfs2_meta_header))) |
| 45 | 41 | ||
| 46 | #define GFS2_ERF_MODE 0x80000000 | ||
| 47 | |||
| 48 | struct gfs2_ea_request { | 42 | struct gfs2_ea_request { |
| 49 | const char *er_name; | 43 | const char *er_name; |
| 50 | char *er_data; | 44 | char *er_data; |
| 51 | unsigned int er_name_len; | 45 | unsigned int er_name_len; |
| 52 | unsigned int er_data_len; | 46 | unsigned int er_data_len; |
| 53 | unsigned int er_type; /* GFS2_EATYPE_... */ | 47 | unsigned int er_type; /* GFS2_EATYPE_... */ |
| 54 | int er_flags; | ||
| 55 | mode_t er_mode; | ||
| 56 | }; | 48 | }; |
| 57 | 49 | ||
| 58 | struct gfs2_ea_location { | 50 | struct gfs2_ea_location { |
| @@ -61,40 +53,20 @@ struct gfs2_ea_location { | |||
| 61 | struct gfs2_ea_header *el_prev; | 53 | struct gfs2_ea_header *el_prev; |
| 62 | }; | 54 | }; |
| 63 | 55 | ||
| 64 | int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 56 | extern int gfs2_xattr_get(struct inode *inode, int type, const char *name, |
| 65 | int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 57 | void *buffer, size_t size); |
| 66 | int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 58 | extern int gfs2_xattr_set(struct inode *inode, int type, const char *name, |
| 67 | 59 | const void *value, size_t size, int flags); | |
| 68 | int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 60 | extern ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size); |
| 69 | int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 61 | extern int gfs2_ea_dealloc(struct gfs2_inode *ip); |
| 70 | int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
| 71 | int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
| 72 | |||
| 73 | int gfs2_ea_dealloc(struct gfs2_inode *ip); | ||
| 74 | 62 | ||
| 75 | /* Exported to acl.c */ | 63 | /* Exported to acl.c */ |
| 76 | 64 | ||
| 77 | int gfs2_ea_find(struct gfs2_inode *ip, | 65 | extern int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, |
| 78 | struct gfs2_ea_request *er, | 66 | struct gfs2_ea_location *el); |
| 79 | struct gfs2_ea_location *el); | 67 | extern int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, |
| 80 | int gfs2_ea_get_copy(struct gfs2_inode *ip, | 68 | char *data, size_t size); |
| 81 | struct gfs2_ea_location *el, | 69 | extern int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, |
| 82 | char *data); | 70 | struct iattr *attr, char *data); |
| 83 | int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, | ||
| 84 | struct iattr *attr, char *data); | ||
| 85 | |||
| 86 | static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea) | ||
| 87 | { | ||
| 88 | switch (ea->ea_type) { | ||
| 89 | case GFS2_EATYPE_USR: | ||
| 90 | return 5 + ea->ea_name_len + 1; | ||
| 91 | case GFS2_EATYPE_SYS: | ||
| 92 | return 7 + ea->ea_name_len + 1; | ||
| 93 | case GFS2_EATYPE_SECURITY: | ||
| 94 | return 9 + ea->ea_name_len + 1; | ||
| 95 | default: | ||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | 71 | ||
| 100 | #endif /* __EATTR_DOT_H__ */ | 72 | #endif /* __EATTR_DOT_H__ */ |
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index cb88dac8cca..a93b885311d 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
| @@ -44,6 +44,7 @@ static const struct inode_operations hugetlbfs_dir_inode_operations; | |||
| 44 | static const struct inode_operations hugetlbfs_inode_operations; | 44 | static const struct inode_operations hugetlbfs_inode_operations; |
| 45 | 45 | ||
| 46 | static struct backing_dev_info hugetlbfs_backing_dev_info = { | 46 | static struct backing_dev_info hugetlbfs_backing_dev_info = { |
| 47 | .name = "hugetlbfs", | ||
| 47 | .ra_pages = 0, /* No readahead */ | 48 | .ra_pages = 0, /* No readahead */ |
| 48 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, | 49 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, |
| 49 | }; | 50 | }; |
diff --git a/fs/inode.c b/fs/inode.c index ae7b67e4866..b2ba83d2c4e 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
| @@ -182,9 +182,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode) | |||
| 182 | if (sb->s_bdev) { | 182 | if (sb->s_bdev) { |
| 183 | struct backing_dev_info *bdi; | 183 | struct backing_dev_info *bdi; |
| 184 | 184 | ||
| 185 | bdi = sb->s_bdev->bd_inode_backing_dev_info; | 185 | bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info; |
| 186 | if (!bdi) | ||
| 187 | bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info; | ||
| 188 | mapping->backing_dev_info = bdi; | 186 | mapping->backing_dev_info = bdi; |
| 189 | } | 187 | } |
| 190 | inode->i_private = NULL; | 188 | inode->i_private = NULL; |
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index 61f32f3868c..b0435dd0654 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c | |||
| @@ -456,7 +456,7 @@ int cleanup_journal_tail(journal_t *journal) | |||
| 456 | { | 456 | { |
| 457 | transaction_t * transaction; | 457 | transaction_t * transaction; |
| 458 | tid_t first_tid; | 458 | tid_t first_tid; |
| 459 | unsigned long blocknr, freed; | 459 | unsigned int blocknr, freed; |
| 460 | 460 | ||
| 461 | if (is_journal_aborted(journal)) | 461 | if (is_journal_aborted(journal)) |
| 462 | return 1; | 462 | return 1; |
| @@ -502,8 +502,8 @@ int cleanup_journal_tail(journal_t *journal) | |||
| 502 | freed = freed + journal->j_last - journal->j_first; | 502 | freed = freed + journal->j_last - journal->j_first; |
| 503 | 503 | ||
| 504 | jbd_debug(1, | 504 | jbd_debug(1, |
| 505 | "Cleaning journal tail from %d to %d (offset %lu), " | 505 | "Cleaning journal tail from %d to %d (offset %u), " |
| 506 | "freeing %lu\n", | 506 | "freeing %u\n", |
| 507 | journal->j_tail_sequence, first_tid, blocknr, freed); | 507 | journal->j_tail_sequence, first_tid, blocknr, freed); |
| 508 | 508 | ||
| 509 | journal->j_free += freed; | 509 | journal->j_free += freed; |
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 618e21c0b7a..4bd882548c4 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c | |||
| @@ -308,7 +308,7 @@ void journal_commit_transaction(journal_t *journal) | |||
| 308 | int bufs; | 308 | int bufs; |
| 309 | int flags; | 309 | int flags; |
| 310 | int err; | 310 | int err; |
| 311 | unsigned long blocknr; | 311 | unsigned int blocknr; |
| 312 | ktime_t start_time; | 312 | ktime_t start_time; |
| 313 | u64 commit_time; | 313 | u64 commit_time; |
| 314 | char *tagp = NULL; | 314 | char *tagp = NULL; |
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index f96f85092d1..bd3c073b485 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c | |||
| @@ -276,7 +276,7 @@ static void journal_kill_thread(journal_t *journal) | |||
| 276 | int journal_write_metadata_buffer(transaction_t *transaction, | 276 | int journal_write_metadata_buffer(transaction_t *transaction, |
| 277 | struct journal_head *jh_in, | 277 | struct journal_head *jh_in, |
| 278 | struct journal_head **jh_out, | 278 | struct journal_head **jh_out, |
| 279 | unsigned long blocknr) | 279 | unsigned int blocknr) |
| 280 | { | 280 | { |
| 281 | int need_copy_out = 0; | 281 | int need_copy_out = 0; |
| 282 | int done_copy_out = 0; | 282 | int done_copy_out = 0; |
| @@ -567,9 +567,9 @@ int log_wait_commit(journal_t *journal, tid_t tid) | |||
| 567 | * Log buffer allocation routines: | 567 | * Log buffer allocation routines: |
| 568 | */ | 568 | */ |
| 569 | 569 | ||
| 570 | int journal_next_log_block(journal_t *journal, unsigned long *retp) | 570 | int journal_next_log_block(journal_t *journal, unsigned int *retp) |
| 571 | { | 571 | { |
| 572 | unsigned long blocknr; | 572 | unsigned int blocknr; |
| 573 | 573 | ||
| 574 | spin_lock(&journal->j_state_lock); | 574 | spin_lock(&journal->j_state_lock); |
| 575 | J_ASSERT(journal->j_free > 1); | 575 | J_ASSERT(journal->j_free > 1); |
| @@ -590,11 +590,11 @@ int journal_next_log_block(journal_t *journal, unsigned long *retp) | |||
| 590 | * this is a no-op. If needed, we can use j_blk_offset - everything is | 590 | * this is a no-op. If needed, we can use j_blk_offset - everything is |
| 591 | * ready. | 591 | * ready. |
| 592 | */ | 592 | */ |
| 593 | int journal_bmap(journal_t *journal, unsigned long blocknr, | 593 | int journal_bmap(journal_t *journal, unsigned int blocknr, |
| 594 | unsigned long *retp) | 594 | unsigned int *retp) |
| 595 | { | 595 | { |
| 596 | int err = 0; | 596 | int err = 0; |
| 597 | unsigned long ret; | 597 | unsigned int ret; |
| 598 | 598 | ||
| 599 | if (journal->j_inode) { | 599 | if (journal->j_inode) { |
| 600 | ret = bmap(journal->j_inode, blocknr); | 600 | ret = bmap(journal->j_inode, blocknr); |
| @@ -604,7 +604,7 @@ int journal_bmap(journal_t *journal, unsigned long blocknr, | |||
| 604 | char b[BDEVNAME_SIZE]; | 604 | char b[BDEVNAME_SIZE]; |
| 605 | 605 | ||
| 606 | printk(KERN_ALERT "%s: journal block not found " | 606 | printk(KERN_ALERT "%s: journal block not found " |
| 607 | "at offset %lu on %s\n", | 607 | "at offset %u on %s\n", |
| 608 | __func__, | 608 | __func__, |
| 609 | blocknr, | 609 | blocknr, |
| 610 | bdevname(journal->j_dev, b)); | 610 | bdevname(journal->j_dev, b)); |
| @@ -630,7 +630,7 @@ int journal_bmap(journal_t *journal, unsigned long blocknr, | |||
| 630 | struct journal_head *journal_get_descriptor_buffer(journal_t *journal) | 630 | struct journal_head *journal_get_descriptor_buffer(journal_t *journal) |
| 631 | { | 631 | { |
| 632 | struct buffer_head *bh; | 632 | struct buffer_head *bh; |
| 633 | unsigned long blocknr; | 633 | unsigned int blocknr; |
| 634 | int err; | 634 | int err; |
| 635 | 635 | ||
| 636 | err = journal_next_log_block(journal, &blocknr); | 636 | err = journal_next_log_block(journal, &blocknr); |
| @@ -774,7 +774,7 @@ journal_t * journal_init_inode (struct inode *inode) | |||
| 774 | journal_t *journal = journal_init_common(); | 774 | journal_t *journal = journal_init_common(); |
| 775 | int err; | 775 | int err; |
| 776 | int n; | 776 | int n; |
| 777 | unsigned long blocknr; | 777 | unsigned int blocknr; |
| 778 | 778 | ||
| 779 | if (!journal) | 779 | if (!journal) |
| 780 | return NULL; | 780 | return NULL; |
| @@ -846,12 +846,12 @@ static void journal_fail_superblock (journal_t *journal) | |||
| 846 | static int journal_reset(journal_t *journal) | 846 | static int journal_reset(journal_t *journal) |
| 847 | { | 847 | { |
| 848 | journal_superblock_t *sb = journal->j_superblock; | 848 | journal_superblock_t *sb = journal->j_superblock; |
| 849 | unsigned long first, last; | 849 | unsigned int first, last; |
| 850 | 850 | ||
| 851 | first = be32_to_cpu(sb->s_first); | 851 | first = be32_to_cpu(sb->s_first); |
| 852 | last = be32_to_cpu(sb->s_maxlen); | 852 | last = be32_to_cpu(sb->s_maxlen); |
| 853 | if (first + JFS_MIN_JOURNAL_BLOCKS > last + 1) { | 853 | if (first + JFS_MIN_JOURNAL_BLOCKS > last + 1) { |
| 854 | printk(KERN_ERR "JBD: Journal too short (blocks %lu-%lu).\n", | 854 | printk(KERN_ERR "JBD: Journal too short (blocks %u-%u).\n", |
| 855 | first, last); | 855 | first, last); |
| 856 | journal_fail_superblock(journal); | 856 | journal_fail_superblock(journal); |
| 857 | return -EINVAL; | 857 | return -EINVAL; |
| @@ -885,7 +885,7 @@ static int journal_reset(journal_t *journal) | |||
| 885 | **/ | 885 | **/ |
| 886 | int journal_create(journal_t *journal) | 886 | int journal_create(journal_t *journal) |
| 887 | { | 887 | { |
| 888 | unsigned long blocknr; | 888 | unsigned int blocknr; |
| 889 | struct buffer_head *bh; | 889 | struct buffer_head *bh; |
| 890 | journal_superblock_t *sb; | 890 | journal_superblock_t *sb; |
| 891 | int i, err; | 891 | int i, err; |
| @@ -969,14 +969,14 @@ void journal_update_superblock(journal_t *journal, int wait) | |||
| 969 | if (sb->s_start == 0 && journal->j_tail_sequence == | 969 | if (sb->s_start == 0 && journal->j_tail_sequence == |
| 970 | journal->j_transaction_sequence) { | 970 | journal->j_transaction_sequence) { |
| 971 | jbd_debug(1,"JBD: Skipping superblock update on recovered sb " | 971 | jbd_debug(1,"JBD: Skipping superblock update on recovered sb " |
| 972 | "(start %ld, seq %d, errno %d)\n", | 972 | "(start %u, seq %d, errno %d)\n", |
| 973 | journal->j_tail, journal->j_tail_sequence, | 973 | journal->j_tail, journal->j_tail_sequence, |
| 974 | journal->j_errno); | 974 | journal->j_errno); |
| 975 | goto out; | 975 | goto out; |
| 976 | } | 976 | } |
| 977 | 977 | ||
| 978 | spin_lock(&journal->j_state_lock); | 978 | spin_lock(&journal->j_state_lock); |
| 979 | jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n", | 979 | jbd_debug(1,"JBD: updating superblock (start %u, seq %d, errno %d)\n", |
| 980 | journal->j_tail, journal->j_tail_sequence, journal->j_errno); | 980 | journal->j_tail, journal->j_tail_sequence, journal->j_errno); |
| 981 | 981 | ||
| 982 | sb->s_sequence = cpu_to_be32(journal->j_tail_sequence); | 982 | sb->s_sequence = cpu_to_be32(journal->j_tail_sequence); |
| @@ -1371,7 +1371,7 @@ int journal_flush(journal_t *journal) | |||
| 1371 | { | 1371 | { |
| 1372 | int err = 0; | 1372 | int err = 0; |
| 1373 | transaction_t *transaction = NULL; | 1373 | transaction_t *transaction = NULL; |
| 1374 | unsigned long old_tail; | 1374 | unsigned int old_tail; |
| 1375 | 1375 | ||
| 1376 | spin_lock(&journal->j_state_lock); | 1376 | spin_lock(&journal->j_state_lock); |
| 1377 | 1377 | ||
diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index db5e982c5dd..cb1a49ae605 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c | |||
| @@ -70,7 +70,7 @@ static int do_readahead(journal_t *journal, unsigned int start) | |||
| 70 | { | 70 | { |
| 71 | int err; | 71 | int err; |
| 72 | unsigned int max, nbufs, next; | 72 | unsigned int max, nbufs, next; |
| 73 | unsigned long blocknr; | 73 | unsigned int blocknr; |
| 74 | struct buffer_head *bh; | 74 | struct buffer_head *bh; |
| 75 | 75 | ||
| 76 | struct buffer_head * bufs[MAXBUF]; | 76 | struct buffer_head * bufs[MAXBUF]; |
| @@ -132,7 +132,7 @@ static int jread(struct buffer_head **bhp, journal_t *journal, | |||
| 132 | unsigned int offset) | 132 | unsigned int offset) |
| 133 | { | 133 | { |
| 134 | int err; | 134 | int err; |
| 135 | unsigned long blocknr; | 135 | unsigned int blocknr; |
| 136 | struct buffer_head *bh; | 136 | struct buffer_head *bh; |
| 137 | 137 | ||
| 138 | *bhp = NULL; | 138 | *bhp = NULL; |
| @@ -314,7 +314,7 @@ static int do_one_pass(journal_t *journal, | |||
| 314 | struct recovery_info *info, enum passtype pass) | 314 | struct recovery_info *info, enum passtype pass) |
| 315 | { | 315 | { |
| 316 | unsigned int first_commit_ID, next_commit_ID; | 316 | unsigned int first_commit_ID, next_commit_ID; |
| 317 | unsigned long next_log_block; | 317 | unsigned int next_log_block; |
| 318 | int err, success = 0; | 318 | int err, success = 0; |
| 319 | journal_superblock_t * sb; | 319 | journal_superblock_t * sb; |
| 320 | journal_header_t * tmp; | 320 | journal_header_t * tmp; |
| @@ -367,14 +367,14 @@ static int do_one_pass(journal_t *journal, | |||
| 367 | if (tid_geq(next_commit_ID, info->end_transaction)) | 367 | if (tid_geq(next_commit_ID, info->end_transaction)) |
| 368 | break; | 368 | break; |
| 369 | 369 | ||
| 370 | jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n", | 370 | jbd_debug(2, "Scanning for sequence ID %u at %u/%u\n", |
| 371 | next_commit_ID, next_log_block, journal->j_last); | 371 | next_commit_ID, next_log_block, journal->j_last); |
| 372 | 372 | ||
| 373 | /* Skip over each chunk of the transaction looking | 373 | /* Skip over each chunk of the transaction looking |
| 374 | * either the next descriptor block or the final commit | 374 | * either the next descriptor block or the final commit |
| 375 | * record. */ | 375 | * record. */ |
| 376 | 376 | ||
| 377 | jbd_debug(3, "JBD: checking block %ld\n", next_log_block); | 377 | jbd_debug(3, "JBD: checking block %u\n", next_log_block); |
| 378 | err = jread(&bh, journal, next_log_block); | 378 | err = jread(&bh, journal, next_log_block); |
| 379 | if (err) | 379 | if (err) |
| 380 | goto failed; | 380 | goto failed; |
| @@ -429,7 +429,7 @@ static int do_one_pass(journal_t *journal, | |||
| 429 | tagp = &bh->b_data[sizeof(journal_header_t)]; | 429 | tagp = &bh->b_data[sizeof(journal_header_t)]; |
| 430 | while ((tagp - bh->b_data +sizeof(journal_block_tag_t)) | 430 | while ((tagp - bh->b_data +sizeof(journal_block_tag_t)) |
| 431 | <= journal->j_blocksize) { | 431 | <= journal->j_blocksize) { |
| 432 | unsigned long io_block; | 432 | unsigned int io_block; |
| 433 | 433 | ||
| 434 | tag = (journal_block_tag_t *) tagp; | 434 | tag = (journal_block_tag_t *) tagp; |
| 435 | flags = be32_to_cpu(tag->t_flags); | 435 | flags = be32_to_cpu(tag->t_flags); |
| @@ -443,10 +443,10 @@ static int do_one_pass(journal_t *journal, | |||
| 443 | success = err; | 443 | success = err; |
| 444 | printk (KERN_ERR | 444 | printk (KERN_ERR |
| 445 | "JBD: IO error %d recovering " | 445 | "JBD: IO error %d recovering " |
| 446 | "block %ld in log\n", | 446 | "block %u in log\n", |
| 447 | err, io_block); | 447 | err, io_block); |
| 448 | } else { | 448 | } else { |
| 449 | unsigned long blocknr; | 449 | unsigned int blocknr; |
| 450 | 450 | ||
| 451 | J_ASSERT(obh != NULL); | 451 | J_ASSERT(obh != NULL); |
| 452 | blocknr = be32_to_cpu(tag->t_blocknr); | 452 | blocknr = be32_to_cpu(tag->t_blocknr); |
| @@ -581,7 +581,7 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, | |||
| 581 | max = be32_to_cpu(header->r_count); | 581 | max = be32_to_cpu(header->r_count); |
| 582 | 582 | ||
| 583 | while (offset < max) { | 583 | while (offset < max) { |
| 584 | unsigned long blocknr; | 584 | unsigned int blocknr; |
| 585 | int err; | 585 | int err; |
| 586 | 586 | ||
| 587 | blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset))); | 587 | blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset))); |
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index da6cd9bdaab..ad717328343 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c | |||
| @@ -101,7 +101,7 @@ struct jbd_revoke_record_s | |||
| 101 | { | 101 | { |
| 102 | struct list_head hash; | 102 | struct list_head hash; |
| 103 | tid_t sequence; /* Used for recovery only */ | 103 | tid_t sequence; /* Used for recovery only */ |
| 104 | unsigned long blocknr; | 104 | unsigned int blocknr; |
| 105 | }; | 105 | }; |
| 106 | 106 | ||
| 107 | 107 | ||
| @@ -126,7 +126,7 @@ static void flush_descriptor(journal_t *, struct journal_head *, int, int); | |||
| 126 | /* Utility functions to maintain the revoke table */ | 126 | /* Utility functions to maintain the revoke table */ |
| 127 | 127 | ||
| 128 | /* Borrowed from buffer.c: this is a tried and tested block hash function */ | 128 | /* Borrowed from buffer.c: this is a tried and tested block hash function */ |
| 129 | static inline int hash(journal_t *journal, unsigned long block) | 129 | static inline int hash(journal_t *journal, unsigned int block) |
| 130 | { | 130 | { |
| 131 | struct jbd_revoke_table_s *table = journal->j_revoke; | 131 | struct jbd_revoke_table_s *table = journal->j_revoke; |
| 132 | int hash_shift = table->hash_shift; | 132 | int hash_shift = table->hash_shift; |
| @@ -136,7 +136,7 @@ static inline int hash(journal_t *journal, unsigned long block) | |||
| 136 | (block << (hash_shift - 12))) & (table->hash_size - 1); | 136 | (block << (hash_shift - 12))) & (table->hash_size - 1); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | static int insert_revoke_hash(journal_t *journal, unsigned long blocknr, | 139 | static int insert_revoke_hash(journal_t *journal, unsigned int blocknr, |
| 140 | tid_t seq) | 140 | tid_t seq) |
| 141 | { | 141 | { |
| 142 | struct list_head *hash_list; | 142 | struct list_head *hash_list; |
| @@ -166,7 +166,7 @@ oom: | |||
| 166 | /* Find a revoke record in the journal's hash table. */ | 166 | /* Find a revoke record in the journal's hash table. */ |
| 167 | 167 | ||
| 168 | static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, | 168 | static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, |
| 169 | unsigned long blocknr) | 169 | unsigned int blocknr) |
| 170 | { | 170 | { |
| 171 | struct list_head *hash_list; | 171 | struct list_head *hash_list; |
| 172 | struct jbd_revoke_record_s *record; | 172 | struct jbd_revoke_record_s *record; |
| @@ -332,7 +332,7 @@ void journal_destroy_revoke(journal_t *journal) | |||
| 332 | * by one. | 332 | * by one. |
| 333 | */ | 333 | */ |
| 334 | 334 | ||
| 335 | int journal_revoke(handle_t *handle, unsigned long blocknr, | 335 | int journal_revoke(handle_t *handle, unsigned int blocknr, |
| 336 | struct buffer_head *bh_in) | 336 | struct buffer_head *bh_in) |
| 337 | { | 337 | { |
| 338 | struct buffer_head *bh = NULL; | 338 | struct buffer_head *bh = NULL; |
| @@ -401,7 +401,7 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, | |||
| 401 | } | 401 | } |
| 402 | } | 402 | } |
| 403 | 403 | ||
| 404 | jbd_debug(2, "insert revoke for block %lu, bh_in=%p\n", blocknr, bh_in); | 404 | jbd_debug(2, "insert revoke for block %u, bh_in=%p\n", blocknr, bh_in); |
| 405 | err = insert_revoke_hash(journal, blocknr, | 405 | err = insert_revoke_hash(journal, blocknr, |
| 406 | handle->h_transaction->t_tid); | 406 | handle->h_transaction->t_tid); |
| 407 | BUFFER_TRACE(bh_in, "exit"); | 407 | BUFFER_TRACE(bh_in, "exit"); |
| @@ -644,7 +644,7 @@ static void flush_descriptor(journal_t *journal, | |||
| 644 | */ | 644 | */ |
| 645 | 645 | ||
| 646 | int journal_set_revoke(journal_t *journal, | 646 | int journal_set_revoke(journal_t *journal, |
| 647 | unsigned long blocknr, | 647 | unsigned int blocknr, |
| 648 | tid_t sequence) | 648 | tid_t sequence) |
| 649 | { | 649 | { |
| 650 | struct jbd_revoke_record_s *record; | 650 | struct jbd_revoke_record_s *record; |
| @@ -668,7 +668,7 @@ int journal_set_revoke(journal_t *journal, | |||
| 668 | */ | 668 | */ |
| 669 | 669 | ||
| 670 | int journal_test_revoke(journal_t *journal, | 670 | int journal_test_revoke(journal_t *journal, |
| 671 | unsigned long blocknr, | 671 | unsigned int blocknr, |
| 672 | tid_t sequence) | 672 | tid_t sequence) |
| 673 | { | 673 | { |
| 674 | struct jbd_revoke_record_s *record; | 674 | struct jbd_revoke_record_s *record; |
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index c03ac11f74b..006f9ad838a 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c | |||
| @@ -56,7 +56,8 @@ get_transaction(journal_t *journal, transaction_t *transaction) | |||
| 56 | spin_lock_init(&transaction->t_handle_lock); | 56 | spin_lock_init(&transaction->t_handle_lock); |
| 57 | 57 | ||
| 58 | /* Set up the commit timer for the new transaction. */ | 58 | /* Set up the commit timer for the new transaction. */ |
| 59 | journal->j_commit_timer.expires = round_jiffies(transaction->t_expires); | 59 | journal->j_commit_timer.expires = |
| 60 | round_jiffies_up(transaction->t_expires); | ||
| 60 | add_timer(&journal->j_commit_timer); | 61 | add_timer(&journal->j_commit_timer); |
| 61 | 62 | ||
| 62 | J_ASSERT(journal->j_running_transaction == NULL); | 63 | J_ASSERT(journal->j_running_transaction == NULL); |
| @@ -228,6 +229,8 @@ repeat_locked: | |||
| 228 | __log_space_left(journal)); | 229 | __log_space_left(journal)); |
| 229 | spin_unlock(&transaction->t_handle_lock); | 230 | spin_unlock(&transaction->t_handle_lock); |
| 230 | spin_unlock(&journal->j_state_lock); | 231 | spin_unlock(&journal->j_state_lock); |
| 232 | |||
| 233 | lock_map_acquire(&handle->h_lockdep_map); | ||
| 231 | out: | 234 | out: |
| 232 | if (unlikely(new_transaction)) /* It's usually NULL */ | 235 | if (unlikely(new_transaction)) /* It's usually NULL */ |
| 233 | kfree(new_transaction); | 236 | kfree(new_transaction); |
| @@ -292,9 +295,6 @@ handle_t *journal_start(journal_t *journal, int nblocks) | |||
| 292 | handle = ERR_PTR(err); | 295 | handle = ERR_PTR(err); |
| 293 | goto out; | 296 | goto out; |
| 294 | } | 297 | } |
| 295 | |||
| 296 | lock_map_acquire(&handle->h_lockdep_map); | ||
| 297 | |||
| 298 | out: | 298 | out: |
| 299 | return handle; | 299 | return handle; |
| 300 | } | 300 | } |
| @@ -416,6 +416,7 @@ int journal_restart(handle_t *handle, int nblocks) | |||
| 416 | __log_start_commit(journal, transaction->t_tid); | 416 | __log_start_commit(journal, transaction->t_tid); |
| 417 | spin_unlock(&journal->j_state_lock); | 417 | spin_unlock(&journal->j_state_lock); |
| 418 | 418 | ||
| 419 | lock_map_release(&handle->h_lockdep_map); | ||
| 419 | handle->h_buffer_credits = nblocks; | 420 | handle->h_buffer_credits = nblocks; |
| 420 | ret = start_this_handle(journal, handle); | 421 | ret = start_this_handle(journal, handle); |
| 421 | return ret; | 422 | return ret; |
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 7b4088b2364..26d991ddc1e 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/writeback.h> | 25 | #include <linux/writeback.h> |
| 26 | #include <linux/backing-dev.h> | 26 | #include <linux/backing-dev.h> |
| 27 | #include <linux/bio.h> | 27 | #include <linux/bio.h> |
| 28 | #include <linux/blkdev.h> | ||
| 28 | #include <trace/events/jbd2.h> | 29 | #include <trace/events/jbd2.h> |
| 29 | 30 | ||
| 30 | /* | 31 | /* |
| @@ -133,8 +134,8 @@ static int journal_submit_commit_record(journal_t *journal, | |||
| 133 | bh->b_end_io = journal_end_buffer_io_sync; | 134 | bh->b_end_io = journal_end_buffer_io_sync; |
| 134 | 135 | ||
| 135 | if (journal->j_flags & JBD2_BARRIER && | 136 | if (journal->j_flags & JBD2_BARRIER && |
| 136 | !JBD2_HAS_INCOMPAT_FEATURE(journal, | 137 | !JBD2_HAS_INCOMPAT_FEATURE(journal, |
| 137 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) { | 138 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) { |
| 138 | set_buffer_ordered(bh); | 139 | set_buffer_ordered(bh); |
| 139 | barrier_done = 1; | 140 | barrier_done = 1; |
| 140 | } | 141 | } |
| @@ -220,7 +221,6 @@ static int journal_submit_inode_data_buffers(struct address_space *mapping) | |||
| 220 | .nr_to_write = mapping->nrpages * 2, | 221 | .nr_to_write = mapping->nrpages * 2, |
| 221 | .range_start = 0, | 222 | .range_start = 0, |
| 222 | .range_end = i_size_read(mapping->host), | 223 | .range_end = i_size_read(mapping->host), |
| 223 | .for_writepages = 1, | ||
| 224 | }; | 224 | }; |
| 225 | 225 | ||
| 226 | ret = generic_writepages(mapping, &wbc); | 226 | ret = generic_writepages(mapping, &wbc); |
| @@ -707,11 +707,13 @@ start_journal_io: | |||
| 707 | /* Done it all: now write the commit record asynchronously. */ | 707 | /* Done it all: now write the commit record asynchronously. */ |
| 708 | 708 | ||
| 709 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, | 709 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, |
| 710 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) { | 710 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) { |
| 711 | err = journal_submit_commit_record(journal, commit_transaction, | 711 | err = journal_submit_commit_record(journal, commit_transaction, |
| 712 | &cbh, crc32_sum); | 712 | &cbh, crc32_sum); |
| 713 | if (err) | 713 | if (err) |
| 714 | __jbd2_journal_abort_hard(journal); | 714 | __jbd2_journal_abort_hard(journal); |
| 715 | if (journal->j_flags & JBD2_BARRIER) | ||
| 716 | blkdev_issue_flush(journal->j_dev, NULL); | ||
| 715 | } | 717 | } |
| 716 | 718 | ||
| 717 | /* | 719 | /* |
| @@ -834,7 +836,7 @@ wait_for_iobuf: | |||
| 834 | jbd_debug(3, "JBD: commit phase 5\n"); | 836 | jbd_debug(3, "JBD: commit phase 5\n"); |
| 835 | 837 | ||
| 836 | if (!JBD2_HAS_INCOMPAT_FEATURE(journal, | 838 | if (!JBD2_HAS_INCOMPAT_FEATURE(journal, |
| 837 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) { | 839 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) { |
| 838 | err = journal_submit_commit_record(journal, commit_transaction, | 840 | err = journal_submit_commit_record(journal, commit_transaction, |
| 839 | &cbh, crc32_sum); | 841 | &cbh, crc32_sum); |
| 840 | if (err) | 842 | if (err) |
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index e378cb38397..a8a358bc0f2 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
| @@ -1187,6 +1187,12 @@ static int journal_reset(journal_t *journal) | |||
| 1187 | 1187 | ||
| 1188 | first = be32_to_cpu(sb->s_first); | 1188 | first = be32_to_cpu(sb->s_first); |
| 1189 | last = be32_to_cpu(sb->s_maxlen); | 1189 | last = be32_to_cpu(sb->s_maxlen); |
| 1190 | if (first + JBD2_MIN_JOURNAL_BLOCKS > last + 1) { | ||
| 1191 | printk(KERN_ERR "JBD: Journal too short (blocks %llu-%llu).\n", | ||
| 1192 | first, last); | ||
| 1193 | journal_fail_superblock(journal); | ||
| 1194 | return -EINVAL; | ||
| 1195 | } | ||
| 1190 | 1196 | ||
| 1191 | journal->j_first = first; | 1197 | journal->j_first = first; |
| 1192 | journal->j_last = last; | 1198 | journal->j_last = last; |
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 6213ac728f3..a0512700542 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
| @@ -57,7 +57,7 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction) | |||
| 57 | INIT_LIST_HEAD(&transaction->t_private_list); | 57 | INIT_LIST_HEAD(&transaction->t_private_list); |
| 58 | 58 | ||
| 59 | /* Set up the commit timer for the new transaction. */ | 59 | /* Set up the commit timer for the new transaction. */ |
| 60 | journal->j_commit_timer.expires = round_jiffies(transaction->t_expires); | 60 | journal->j_commit_timer.expires = round_jiffies_up(transaction->t_expires); |
| 61 | add_timer(&journal->j_commit_timer); | 61 | add_timer(&journal->j_commit_timer); |
| 62 | 62 | ||
| 63 | J_ASSERT(journal->j_running_transaction == NULL); | 63 | J_ASSERT(journal->j_running_transaction == NULL); |
| @@ -238,6 +238,8 @@ repeat_locked: | |||
| 238 | __jbd2_log_space_left(journal)); | 238 | __jbd2_log_space_left(journal)); |
| 239 | spin_unlock(&transaction->t_handle_lock); | 239 | spin_unlock(&transaction->t_handle_lock); |
| 240 | spin_unlock(&journal->j_state_lock); | 240 | spin_unlock(&journal->j_state_lock); |
| 241 | |||
| 242 | lock_map_acquire(&handle->h_lockdep_map); | ||
| 241 | out: | 243 | out: |
| 242 | if (unlikely(new_transaction)) /* It's usually NULL */ | 244 | if (unlikely(new_transaction)) /* It's usually NULL */ |
| 243 | kfree(new_transaction); | 245 | kfree(new_transaction); |
| @@ -303,8 +305,6 @@ handle_t *jbd2_journal_start(journal_t *journal, int nblocks) | |||
| 303 | handle = ERR_PTR(err); | 305 | handle = ERR_PTR(err); |
| 304 | goto out; | 306 | goto out; |
| 305 | } | 307 | } |
| 306 | |||
| 307 | lock_map_acquire(&handle->h_lockdep_map); | ||
| 308 | out: | 308 | out: |
| 309 | return handle; | 309 | return handle; |
| 310 | } | 310 | } |
| @@ -426,6 +426,7 @@ int jbd2_journal_restart(handle_t *handle, int nblocks) | |||
| 426 | __jbd2_log_start_commit(journal, transaction->t_tid); | 426 | __jbd2_log_start_commit(journal, transaction->t_tid); |
| 427 | spin_unlock(&journal->j_state_lock); | 427 | spin_unlock(&journal->j_state_lock); |
| 428 | 428 | ||
| 429 | lock_map_release(&handle->h_lockdep_map); | ||
| 429 | handle->h_buffer_credits = nblocks; | 430 | handle->h_buffer_credits = nblocks; |
| 430 | ret = start_this_handle(journal, handle); | 431 | ret = start_this_handle(journal, handle); |
| 431 | return ret; | 432 | return ret; |
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 8fcb6239218..7edb62e9741 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c | |||
| @@ -258,7 +258,7 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
| 258 | return rc; | 258 | return rc; |
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | static int jffs2_check_acl(struct inode *inode, int mask) | 261 | int jffs2_check_acl(struct inode *inode, int mask) |
| 262 | { | 262 | { |
| 263 | struct posix_acl *acl; | 263 | struct posix_acl *acl; |
| 264 | int rc; | 264 | int rc; |
| @@ -274,11 +274,6 @@ static int jffs2_check_acl(struct inode *inode, int mask) | |||
| 274 | return -EAGAIN; | 274 | return -EAGAIN; |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | int jffs2_permission(struct inode *inode, int mask) | ||
| 278 | { | ||
| 279 | return generic_permission(inode, mask, jffs2_check_acl); | ||
| 280 | } | ||
| 281 | |||
| 282 | int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) | 277 | int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) |
| 283 | { | 278 | { |
| 284 | struct posix_acl *acl, *clone; | 279 | struct posix_acl *acl, *clone; |
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index fc929f2a14f..f0ba63e3c36 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h | |||
| @@ -26,7 +26,7 @@ struct jffs2_acl_header { | |||
| 26 | 26 | ||
| 27 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL | 27 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL |
| 28 | 28 | ||
| 29 | extern int jffs2_permission(struct inode *, int); | 29 | extern int jffs2_check_acl(struct inode *, int); |
| 30 | extern int jffs2_acl_chmod(struct inode *); | 30 | extern int jffs2_acl_chmod(struct inode *); |
| 31 | extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); | 31 | extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); |
| 32 | extern int jffs2_init_acl_post(struct inode *); | 32 | extern int jffs2_init_acl_post(struct inode *); |
| @@ -36,7 +36,7 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler; | |||
| 36 | 36 | ||
| 37 | #else | 37 | #else |
| 38 | 38 | ||
| 39 | #define jffs2_permission (NULL) | 39 | #define jffs2_check_acl (NULL) |
| 40 | #define jffs2_acl_chmod(inode) (0) | 40 | #define jffs2_acl_chmod(inode) (0) |
| 41 | #define jffs2_init_acl_pre(dir_i,inode,mode) (0) | 41 | #define jffs2_init_acl_pre(dir_i,inode,mode) (0) |
| 42 | #define jffs2_init_acl_post(inode) (0) | 42 | #define jffs2_init_acl_post(inode) (0) |
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 6f60cc910f4..7aa4417e085 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
| @@ -55,7 +55,7 @@ const struct inode_operations jffs2_dir_inode_operations = | |||
| 55 | .rmdir = jffs2_rmdir, | 55 | .rmdir = jffs2_rmdir, |
| 56 | .mknod = jffs2_mknod, | 56 | .mknod = jffs2_mknod, |
| 57 | .rename = jffs2_rename, | 57 | .rename = jffs2_rename, |
| 58 | .permission = jffs2_permission, | 58 | .check_acl = jffs2_check_acl, |
| 59 | .setattr = jffs2_setattr, | 59 | .setattr = jffs2_setattr, |
| 60 | .setxattr = jffs2_setxattr, | 60 | .setxattr = jffs2_setxattr, |
| 61 | .getxattr = jffs2_getxattr, | 61 | .getxattr = jffs2_getxattr, |
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 23c94753986..b7b74e29914 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c | |||
| @@ -56,7 +56,7 @@ const struct file_operations jffs2_file_operations = | |||
| 56 | 56 | ||
| 57 | const struct inode_operations jffs2_file_inode_operations = | 57 | const struct inode_operations jffs2_file_inode_operations = |
| 58 | { | 58 | { |
| 59 | .permission = jffs2_permission, | 59 | .check_acl = jffs2_check_acl, |
| 60 | .setattr = jffs2_setattr, | 60 | .setattr = jffs2_setattr, |
| 61 | .setxattr = jffs2_setxattr, | 61 | .setxattr = jffs2_setxattr, |
| 62 | .getxattr = jffs2_getxattr, | 62 | .getxattr = jffs2_getxattr, |
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index b7339c3b6ad..4ec11e8bda8 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c | |||
| @@ -21,7 +21,7 @@ const struct inode_operations jffs2_symlink_inode_operations = | |||
| 21 | { | 21 | { |
| 22 | .readlink = generic_readlink, | 22 | .readlink = generic_readlink, |
| 23 | .follow_link = jffs2_follow_link, | 23 | .follow_link = jffs2_follow_link, |
| 24 | .permission = jffs2_permission, | 24 | .check_acl = jffs2_check_acl, |
| 25 | .setattr = jffs2_setattr, | 25 | .setattr = jffs2_setattr, |
| 26 | .setxattr = jffs2_setxattr, | 26 | .setxattr = jffs2_setxattr, |
| 27 | .getxattr = jffs2_getxattr, | 27 | .getxattr = jffs2_getxattr, |
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index a29c7c3e3fb..d66477c3430 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c | |||
| @@ -114,7 +114,7 @@ out: | |||
| 114 | return rc; | 114 | return rc; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | static int jfs_check_acl(struct inode *inode, int mask) | 117 | int jfs_check_acl(struct inode *inode, int mask) |
| 118 | { | 118 | { |
| 119 | struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); | 119 | struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); |
| 120 | 120 | ||
| @@ -129,11 +129,6 @@ static int jfs_check_acl(struct inode *inode, int mask) | |||
| 129 | return -EAGAIN; | 129 | return -EAGAIN; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | int jfs_permission(struct inode *inode, int mask) | ||
| 133 | { | ||
| 134 | return generic_permission(inode, mask, jfs_check_acl); | ||
| 135 | } | ||
| 136 | |||
| 137 | int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) | 132 | int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) |
| 138 | { | 133 | { |
| 139 | struct posix_acl *acl = NULL; | 134 | struct posix_acl *acl = NULL; |
diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 7f6063acaa3..2b70fa78e4a 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c | |||
| @@ -96,7 +96,7 @@ const struct inode_operations jfs_file_inode_operations = { | |||
| 96 | .removexattr = jfs_removexattr, | 96 | .removexattr = jfs_removexattr, |
| 97 | #ifdef CONFIG_JFS_POSIX_ACL | 97 | #ifdef CONFIG_JFS_POSIX_ACL |
| 98 | .setattr = jfs_setattr, | 98 | .setattr = jfs_setattr, |
| 99 | .permission = jfs_permission, | 99 | .check_acl = jfs_check_acl, |
| 100 | #endif | 100 | #endif |
| 101 | }; | 101 | }; |
| 102 | 102 | ||
diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h index 88475f10a38..b07bd417ef8 100644 --- a/fs/jfs/jfs_acl.h +++ b/fs/jfs/jfs_acl.h | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | #ifdef CONFIG_JFS_POSIX_ACL | 21 | #ifdef CONFIG_JFS_POSIX_ACL |
| 22 | 22 | ||
| 23 | int jfs_permission(struct inode *, int); | 23 | int jfs_check_acl(struct inode *, int); |
| 24 | int jfs_init_acl(tid_t, struct inode *, struct inode *); | 24 | int jfs_init_acl(tid_t, struct inode *, struct inode *); |
| 25 | int jfs_setattr(struct dentry *, struct iattr *); | 25 | int jfs_setattr(struct dentry *, struct iattr *); |
| 26 | 26 | ||
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 514ee2edb92..c79a4270f08 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c | |||
| @@ -1543,7 +1543,7 @@ const struct inode_operations jfs_dir_inode_operations = { | |||
| 1543 | .removexattr = jfs_removexattr, | 1543 | .removexattr = jfs_removexattr, |
| 1544 | #ifdef CONFIG_JFS_POSIX_ACL | 1544 | #ifdef CONFIG_JFS_POSIX_ACL |
| 1545 | .setattr = jfs_setattr, | 1545 | .setattr = jfs_setattr, |
| 1546 | .permission = jfs_permission, | 1546 | .check_acl = jfs_check_acl, |
| 1547 | #endif | 1547 | #endif |
| 1548 | }; | 1548 | }; |
| 1549 | 1549 | ||
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 99d737bd432..7cb076ac6b4 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
| @@ -87,18 +87,6 @@ static unsigned int nlm_hash_address(const struct sockaddr *sap) | |||
| 87 | return hash & (NLM_HOST_NRHASH - 1); | 87 | return hash & (NLM_HOST_NRHASH - 1); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | static void nlm_clear_port(struct sockaddr *sap) | ||
| 91 | { | ||
| 92 | switch (sap->sa_family) { | ||
| 93 | case AF_INET: | ||
| 94 | ((struct sockaddr_in *)sap)->sin_port = 0; | ||
| 95 | break; | ||
| 96 | case AF_INET6: | ||
| 97 | ((struct sockaddr_in6 *)sap)->sin6_port = 0; | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | /* | 90 | /* |
| 103 | * Common host lookup routine for server & client | 91 | * Common host lookup routine for server & client |
| 104 | */ | 92 | */ |
| @@ -177,7 +165,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni) | |||
| 177 | host->h_addrbuf = nsm->sm_addrbuf; | 165 | host->h_addrbuf = nsm->sm_addrbuf; |
| 178 | memcpy(nlm_addr(host), ni->sap, ni->salen); | 166 | memcpy(nlm_addr(host), ni->sap, ni->salen); |
| 179 | host->h_addrlen = ni->salen; | 167 | host->h_addrlen = ni->salen; |
| 180 | nlm_clear_port(nlm_addr(host)); | 168 | rpc_set_port(nlm_addr(host), 0); |
| 181 | memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len); | 169 | memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len); |
| 182 | host->h_version = ni->version; | 170 | host->h_version = ni->version; |
| 183 | host->h_proto = ni->protocol; | 171 | host->h_proto = ni->protocol; |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 7fce1b52584..30c933188dd 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
| @@ -61,43 +61,6 @@ static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) | |||
| 61 | return (struct sockaddr *)&nsm->sm_addr; | 61 | return (struct sockaddr *)&nsm->sm_addr; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static void nsm_display_ipv4_address(const struct sockaddr *sap, char *buf, | ||
| 65 | const size_t len) | ||
| 66 | { | ||
| 67 | const struct sockaddr_in *sin = (struct sockaddr_in *)sap; | ||
| 68 | snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr); | ||
| 69 | } | ||
| 70 | |||
| 71 | static void nsm_display_ipv6_address(const struct sockaddr *sap, char *buf, | ||
| 72 | const size_t len) | ||
| 73 | { | ||
| 74 | const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | ||
| 75 | |||
| 76 | if (ipv6_addr_v4mapped(&sin6->sin6_addr)) | ||
| 77 | snprintf(buf, len, "%pI4", &sin6->sin6_addr.s6_addr32[3]); | ||
| 78 | else if (sin6->sin6_scope_id != 0) | ||
| 79 | snprintf(buf, len, "%pI6%%%u", &sin6->sin6_addr, | ||
| 80 | sin6->sin6_scope_id); | ||
| 81 | else | ||
| 82 | snprintf(buf, len, "%pI6", &sin6->sin6_addr); | ||
| 83 | } | ||
| 84 | |||
| 85 | static void nsm_display_address(const struct sockaddr *sap, | ||
| 86 | char *buf, const size_t len) | ||
| 87 | { | ||
| 88 | switch (sap->sa_family) { | ||
| 89 | case AF_INET: | ||
| 90 | nsm_display_ipv4_address(sap, buf, len); | ||
| 91 | break; | ||
| 92 | case AF_INET6: | ||
| 93 | nsm_display_ipv6_address(sap, buf, len); | ||
| 94 | break; | ||
| 95 | default: | ||
| 96 | snprintf(buf, len, "unsupported address family"); | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | static struct rpc_clnt *nsm_create(void) | 64 | static struct rpc_clnt *nsm_create(void) |
| 102 | { | 65 | { |
| 103 | struct sockaddr_in sin = { | 66 | struct sockaddr_in sin = { |
| @@ -307,8 +270,11 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap, | |||
| 307 | memcpy(nsm_addr(new), sap, salen); | 270 | memcpy(nsm_addr(new), sap, salen); |
| 308 | new->sm_addrlen = salen; | 271 | new->sm_addrlen = salen; |
| 309 | nsm_init_private(new); | 272 | nsm_init_private(new); |
| 310 | nsm_display_address((const struct sockaddr *)&new->sm_addr, | 273 | |
| 311 | new->sm_addrbuf, sizeof(new->sm_addrbuf)); | 274 | if (rpc_ntop(nsm_addr(new), new->sm_addrbuf, |
| 275 | sizeof(new->sm_addrbuf)) == 0) | ||
| 276 | (void)snprintf(new->sm_addrbuf, sizeof(new->sm_addrbuf), | ||
| 277 | "unsupported address family"); | ||
| 312 | memcpy(new->sm_name, hostname, hostname_len); | 278 | memcpy(new->sm_name, hostname, hostname_len); |
| 313 | new->sm_name[hostname_len] = '\0'; | 279 | new->sm_name[hostname_len] = '\0'; |
| 314 | 280 | ||
diff --git a/fs/locks.c b/fs/locks.c index b6440f52178..19ee18a6829 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -768,7 +768,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) | |||
| 768 | * give it the opportunity to lock the file. | 768 | * give it the opportunity to lock the file. |
| 769 | */ | 769 | */ |
| 770 | if (found) | 770 | if (found) |
| 771 | cond_resched_bkl(); | 771 | cond_resched(); |
| 772 | 772 | ||
| 773 | find_conflict: | 773 | find_conflict: |
| 774 | for_each_lock(inode, before) { | 774 | for_each_lock(inode, before) { |
| @@ -1591,7 +1591,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) | |||
| 1591 | if (can_sleep) | 1591 | if (can_sleep) |
| 1592 | lock->fl_flags |= FL_SLEEP; | 1592 | lock->fl_flags |= FL_SLEEP; |
| 1593 | 1593 | ||
| 1594 | error = security_file_lock(filp, cmd); | 1594 | error = security_file_lock(filp, lock->fl_type); |
| 1595 | if (error) | 1595 | if (error) |
| 1596 | goto out_free; | 1596 | goto out_free; |
| 1597 | 1597 | ||
diff --git a/fs/namei.c b/fs/namei.c index f3c5b278895..d11f404667e 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -169,19 +169,10 @@ void putname(const char *name) | |||
| 169 | EXPORT_SYMBOL(putname); | 169 | EXPORT_SYMBOL(putname); |
| 170 | #endif | 170 | #endif |
| 171 | 171 | ||
| 172 | 172 | /* | |
| 173 | /** | 173 | * This does basic POSIX ACL permission checking |
| 174 | * generic_permission - check for access rights on a Posix-like filesystem | ||
| 175 | * @inode: inode to check access rights for | ||
| 176 | * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) | ||
| 177 | * @check_acl: optional callback to check for Posix ACLs | ||
| 178 | * | ||
| 179 | * Used to check for read/write/execute permissions on a file. | ||
| 180 | * We use "fsuid" for this, letting us set arbitrary permissions | ||
| 181 | * for filesystem access without changing the "normal" uids which | ||
| 182 | * are used for other things.. | ||
| 183 | */ | 174 | */ |
| 184 | int generic_permission(struct inode *inode, int mask, | 175 | static int acl_permission_check(struct inode *inode, int mask, |
| 185 | int (*check_acl)(struct inode *inode, int mask)) | 176 | int (*check_acl)(struct inode *inode, int mask)) |
| 186 | { | 177 | { |
| 187 | umode_t mode = inode->i_mode; | 178 | umode_t mode = inode->i_mode; |
| @@ -193,9 +184,7 @@ int generic_permission(struct inode *inode, int mask, | |||
| 193 | else { | 184 | else { |
| 194 | if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { | 185 | if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { |
| 195 | int error = check_acl(inode, mask); | 186 | int error = check_acl(inode, mask); |
| 196 | if (error == -EACCES) | 187 | if (error != -EAGAIN) |
| 197 | goto check_capabilities; | ||
| 198 | else if (error != -EAGAIN) | ||
| 199 | return error; | 188 | return error; |
| 200 | } | 189 | } |
| 201 | 190 | ||
| @@ -208,8 +197,32 @@ int generic_permission(struct inode *inode, int mask, | |||
| 208 | */ | 197 | */ |
| 209 | if ((mask & ~mode) == 0) | 198 | if ((mask & ~mode) == 0) |
| 210 | return 0; | 199 | return 0; |
| 200 | return -EACCES; | ||
| 201 | } | ||
| 202 | |||
| 203 | /** | ||
| 204 | * generic_permission - check for access rights on a Posix-like filesystem | ||
| 205 | * @inode: inode to check access rights for | ||
| 206 | * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) | ||
| 207 | * @check_acl: optional callback to check for Posix ACLs | ||
| 208 | * | ||
| 209 | * Used to check for read/write/execute permissions on a file. | ||
| 210 | * We use "fsuid" for this, letting us set arbitrary permissions | ||
| 211 | * for filesystem access without changing the "normal" uids which | ||
| 212 | * are used for other things.. | ||
| 213 | */ | ||
| 214 | int generic_permission(struct inode *inode, int mask, | ||
| 215 | int (*check_acl)(struct inode *inode, int mask)) | ||
| 216 | { | ||
| 217 | int ret; | ||
| 218 | |||
| 219 | /* | ||
| 220 | * Do the basic POSIX ACL permission checks. | ||
| 221 | */ | ||
| 222 | ret = acl_permission_check(inode, mask, check_acl); | ||
| 223 | if (ret != -EACCES) | ||
| 224 | return ret; | ||
| 211 | 225 | ||
| 212 | check_capabilities: | ||
| 213 | /* | 226 | /* |
| 214 | * Read/write DACs are always overridable. | 227 | * Read/write DACs are always overridable. |
| 215 | * Executable DACs are overridable if at least one exec bit is set. | 228 | * Executable DACs are overridable if at least one exec bit is set. |
| @@ -262,7 +275,7 @@ int inode_permission(struct inode *inode, int mask) | |||
| 262 | if (inode->i_op->permission) | 275 | if (inode->i_op->permission) |
| 263 | retval = inode->i_op->permission(inode, mask); | 276 | retval = inode->i_op->permission(inode, mask); |
| 264 | else | 277 | else |
| 265 | retval = generic_permission(inode, mask, NULL); | 278 | retval = generic_permission(inode, mask, inode->i_op->check_acl); |
| 266 | 279 | ||
| 267 | if (retval) | 280 | if (retval) |
| 268 | return retval; | 281 | return retval; |
| @@ -432,29 +445,22 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, | |||
| 432 | */ | 445 | */ |
| 433 | static int exec_permission_lite(struct inode *inode) | 446 | static int exec_permission_lite(struct inode *inode) |
| 434 | { | 447 | { |
| 435 | umode_t mode = inode->i_mode; | 448 | int ret; |
| 436 | 449 | ||
| 437 | if (inode->i_op->permission) | 450 | if (inode->i_op->permission) { |
| 438 | return -EAGAIN; | 451 | ret = inode->i_op->permission(inode, MAY_EXEC); |
| 439 | 452 | if (!ret) | |
| 440 | if (current_fsuid() == inode->i_uid) | 453 | goto ok; |
| 441 | mode >>= 6; | 454 | return ret; |
| 442 | else if (in_group_p(inode->i_gid)) | 455 | } |
| 443 | mode >>= 3; | 456 | ret = acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl); |
| 444 | 457 | if (!ret) | |
| 445 | if (mode & MAY_EXEC) | ||
| 446 | goto ok; | ||
| 447 | |||
| 448 | if ((inode->i_mode & S_IXUGO) && capable(CAP_DAC_OVERRIDE)) | ||
| 449 | goto ok; | ||
| 450 | |||
| 451 | if (S_ISDIR(inode->i_mode) && capable(CAP_DAC_OVERRIDE)) | ||
| 452 | goto ok; | 458 | goto ok; |
| 453 | 459 | ||
| 454 | if (S_ISDIR(inode->i_mode) && capable(CAP_DAC_READ_SEARCH)) | 460 | if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH)) |
| 455 | goto ok; | 461 | goto ok; |
| 456 | 462 | ||
| 457 | return -EACCES; | 463 | return ret; |
| 458 | ok: | 464 | ok: |
| 459 | return security_inode_permission(inode, MAY_EXEC); | 465 | return security_inode_permission(inode, MAY_EXEC); |
| 460 | } | 466 | } |
| @@ -853,12 +859,6 @@ static int __link_path_walk(const char *name, struct nameidata *nd) | |||
| 853 | 859 | ||
| 854 | nd->flags |= LOOKUP_CONTINUE; | 860 | nd->flags |= LOOKUP_CONTINUE; |
| 855 | err = exec_permission_lite(inode); | 861 | err = exec_permission_lite(inode); |
| 856 | if (err == -EAGAIN) | ||
| 857 | err = inode_permission(nd->path.dentry->d_inode, | ||
| 858 | MAY_EXEC); | ||
| 859 | if (!err) | ||
| 860 | err = ima_path_check(&nd->path, MAY_EXEC, | ||
| 861 | IMA_COUNT_UPDATE); | ||
| 862 | if (err) | 862 | if (err) |
| 863 | break; | 863 | break; |
| 864 | 864 | ||
| @@ -1533,37 +1533,42 @@ int may_open(struct path *path, int acc_mode, int flag) | |||
| 1533 | if (error) | 1533 | if (error) |
| 1534 | return error; | 1534 | return error; |
| 1535 | 1535 | ||
| 1536 | error = ima_path_check(path, | 1536 | error = ima_path_check(path, acc_mode ? |
| 1537 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC), | 1537 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) : |
| 1538 | ACC_MODE(flag) & (MAY_READ | MAY_WRITE), | ||
| 1538 | IMA_COUNT_UPDATE); | 1539 | IMA_COUNT_UPDATE); |
| 1540 | |||
| 1539 | if (error) | 1541 | if (error) |
| 1540 | return error; | 1542 | return error; |
| 1541 | /* | 1543 | /* |
| 1542 | * An append-only file must be opened in append mode for writing. | 1544 | * An append-only file must be opened in append mode for writing. |
| 1543 | */ | 1545 | */ |
| 1544 | if (IS_APPEND(inode)) { | 1546 | if (IS_APPEND(inode)) { |
| 1547 | error = -EPERM; | ||
| 1545 | if ((flag & FMODE_WRITE) && !(flag & O_APPEND)) | 1548 | if ((flag & FMODE_WRITE) && !(flag & O_APPEND)) |
| 1546 | return -EPERM; | 1549 | goto err_out; |
| 1547 | if (flag & O_TRUNC) | 1550 | if (flag & O_TRUNC) |
| 1548 | return -EPERM; | 1551 | goto err_out; |
| 1549 | } | 1552 | } |
| 1550 | 1553 | ||
| 1551 | /* O_NOATIME can only be set by the owner or superuser */ | 1554 | /* O_NOATIME can only be set by the owner or superuser */ |
| 1552 | if (flag & O_NOATIME) | 1555 | if (flag & O_NOATIME) |
| 1553 | if (!is_owner_or_cap(inode)) | 1556 | if (!is_owner_or_cap(inode)) { |
| 1554 | return -EPERM; | 1557 | error = -EPERM; |
| 1558 | goto err_out; | ||
| 1559 | } | ||
| 1555 | 1560 | ||
| 1556 | /* | 1561 | /* |
| 1557 | * Ensure there are no outstanding leases on the file. | 1562 | * Ensure there are no outstanding leases on the file. |
| 1558 | */ | 1563 | */ |
| 1559 | error = break_lease(inode, flag); | 1564 | error = break_lease(inode, flag); |
| 1560 | if (error) | 1565 | if (error) |
| 1561 | return error; | 1566 | goto err_out; |
| 1562 | 1567 | ||
| 1563 | if (flag & O_TRUNC) { | 1568 | if (flag & O_TRUNC) { |
| 1564 | error = get_write_access(inode); | 1569 | error = get_write_access(inode); |
| 1565 | if (error) | 1570 | if (error) |
| 1566 | return error; | 1571 | goto err_out; |
| 1567 | 1572 | ||
| 1568 | /* | 1573 | /* |
| 1569 | * Refuse to truncate files with mandatory locks held on them. | 1574 | * Refuse to truncate files with mandatory locks held on them. |
| @@ -1581,12 +1586,17 @@ int may_open(struct path *path, int acc_mode, int flag) | |||
| 1581 | } | 1586 | } |
| 1582 | put_write_access(inode); | 1587 | put_write_access(inode); |
| 1583 | if (error) | 1588 | if (error) |
| 1584 | return error; | 1589 | goto err_out; |
| 1585 | } else | 1590 | } else |
| 1586 | if (flag & FMODE_WRITE) | 1591 | if (flag & FMODE_WRITE) |
| 1587 | vfs_dq_init(inode); | 1592 | vfs_dq_init(inode); |
| 1588 | 1593 | ||
| 1589 | return 0; | 1594 | return 0; |
| 1595 | err_out: | ||
| 1596 | ima_counts_put(path, acc_mode ? | ||
| 1597 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) : | ||
| 1598 | ACC_MODE(flag) & (MAY_READ | MAY_WRITE)); | ||
| 1599 | return error; | ||
| 1590 | } | 1600 | } |
| 1591 | 1601 | ||
| 1592 | /* | 1602 | /* |
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 845159814de..da7fda639ea 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
| @@ -6,7 +6,8 @@ obj-$(CONFIG_NFS_FS) += nfs.o | |||
| 6 | 6 | ||
| 7 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ | 7 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ |
| 8 | direct.o pagelist.o proc.o read.o symlink.o unlink.o \ | 8 | direct.o pagelist.o proc.o read.o symlink.o unlink.o \ |
| 9 | write.o namespace.o mount_clnt.o | 9 | write.o namespace.o mount_clnt.o \ |
| 10 | dns_resolve.o cache_lib.o | ||
| 10 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o | 11 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o |
| 11 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o | 12 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o |
| 12 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o | 13 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o |
diff --git a/fs/nfs/cache_lib.c b/fs/nfs/cache_lib.c new file mode 100644 index 00000000000..b4ffd0146ea --- /dev/null +++ b/fs/nfs/cache_lib.c | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | /* | ||
| 2 | * linux/fs/nfs/cache_lib.c | ||
| 3 | * | ||
| 4 | * Helper routines for the NFS client caches | ||
| 5 | * | ||
| 6 | * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> | ||
| 7 | */ | ||
| 8 | #include <linux/kmod.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/moduleparam.h> | ||
| 11 | #include <linux/mount.h> | ||
| 12 | #include <linux/namei.h> | ||
| 13 | #include <linux/sunrpc/cache.h> | ||
| 14 | #include <linux/sunrpc/rpc_pipe_fs.h> | ||
| 15 | |||
| 16 | #include "cache_lib.h" | ||
| 17 | |||
| 18 | #define NFS_CACHE_UPCALL_PATHLEN 256 | ||
| 19 | #define NFS_CACHE_UPCALL_TIMEOUT 15 | ||
| 20 | |||
| 21 | static char nfs_cache_getent_prog[NFS_CACHE_UPCALL_PATHLEN] = | ||
| 22 | "/sbin/nfs_cache_getent"; | ||
| 23 | static unsigned long nfs_cache_getent_timeout = NFS_CACHE_UPCALL_TIMEOUT; | ||
| 24 | |||
| 25 | module_param_string(cache_getent, nfs_cache_getent_prog, | ||
| 26 | sizeof(nfs_cache_getent_prog), 0600); | ||
| 27 | MODULE_PARM_DESC(cache_getent, "Path to the client cache upcall program"); | ||
| 28 | module_param_named(cache_getent_timeout, nfs_cache_getent_timeout, ulong, 0600); | ||
| 29 | MODULE_PARM_DESC(cache_getent_timeout, "Timeout (in seconds) after which " | ||
| 30 | "the cache upcall is assumed to have failed"); | ||
| 31 | |||
| 32 | int nfs_cache_upcall(struct cache_detail *cd, char *entry_name) | ||
| 33 | { | ||
| 34 | static char *envp[] = { "HOME=/", | ||
| 35 | "TERM=linux", | ||
| 36 | "PATH=/sbin:/usr/sbin:/bin:/usr/bin", | ||
| 37 | NULL | ||
| 38 | }; | ||
| 39 | char *argv[] = { | ||
| 40 | nfs_cache_getent_prog, | ||
| 41 | cd->name, | ||
| 42 | entry_name, | ||
| 43 | NULL | ||
| 44 | }; | ||
| 45 | int ret = -EACCES; | ||
| 46 | |||
| 47 | if (nfs_cache_getent_prog[0] == '\0') | ||
| 48 | goto out; | ||
| 49 | ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); | ||
| 50 | /* | ||
| 51 | * Disable the upcall mechanism if we're getting an ENOENT or | ||
| 52 | * EACCES error. The admin can re-enable it on the fly by using | ||
| 53 | * sysfs to set the 'cache_getent' parameter once the problem | ||
| 54 | * has been fixed. | ||
| 55 | */ | ||
| 56 | if (ret == -ENOENT || ret == -EACCES) | ||
| 57 | nfs_cache_getent_prog[0] = '\0'; | ||
| 58 | out: | ||
| 59 | return ret > 0 ? 0 : ret; | ||
| 60 | } | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Deferred request handling | ||
| 64 | */ | ||
| 65 | void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq) | ||
| 66 | { | ||
| 67 | if (atomic_dec_and_test(&dreq->count)) | ||
| 68 | kfree(dreq); | ||
| 69 | } | ||
| 70 | |||
| 71 | static void nfs_dns_cache_revisit(struct cache_deferred_req *d, int toomany) | ||
| 72 | { | ||
| 73 | struct nfs_cache_defer_req *dreq; | ||
| 74 | |||
| 75 | dreq = container_of(d, struct nfs_cache_defer_req, deferred_req); | ||
| 76 | |||
| 77 | complete_all(&dreq->completion); | ||
| 78 | nfs_cache_defer_req_put(dreq); | ||
| 79 | } | ||
| 80 | |||
| 81 | static struct cache_deferred_req *nfs_dns_cache_defer(struct cache_req *req) | ||
| 82 | { | ||
| 83 | struct nfs_cache_defer_req *dreq; | ||
| 84 | |||
| 85 | dreq = container_of(req, struct nfs_cache_defer_req, req); | ||
| 86 | dreq->deferred_req.revisit = nfs_dns_cache_revisit; | ||
| 87 | atomic_inc(&dreq->count); | ||
| 88 | |||
| 89 | return &dreq->deferred_req; | ||
| 90 | } | ||
| 91 | |||
| 92 | struct nfs_cache_defer_req *nfs_cache_defer_req_alloc(void) | ||
| 93 | { | ||
| 94 | struct nfs_cache_defer_req *dreq; | ||
| 95 | |||
| 96 | dreq = kzalloc(sizeof(*dreq), GFP_KERNEL); | ||
| 97 | if (dreq) { | ||
| 98 | init_completion(&dreq->completion); | ||
| 99 | atomic_set(&dreq->count, 1); | ||
| 100 | dreq->req.defer = nfs_dns_cache_defer; | ||
| 101 | } | ||
| 102 | return dreq; | ||
| 103 | } | ||
| 104 | |||
| 105 | int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq) | ||
| 106 | { | ||
| 107 | if (wait_for_completion_timeout(&dreq->completion, | ||
| 108 | nfs_cache_getent_timeout * HZ) == 0) | ||
| 109 | return -ETIMEDOUT; | ||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | |||
| 113 | int nfs_cache_register(struct cache_detail *cd) | ||
| 114 | { | ||
| 115 | struct nameidata nd; | ||
| 116 | struct vfsmount *mnt; | ||
| 117 | int ret; | ||
| 118 | |||
| 119 | mnt = rpc_get_mount(); | ||
| 120 | if (IS_ERR(mnt)) | ||
| 121 | return PTR_ERR(mnt); | ||
| 122 | ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &nd); | ||
| 123 | if (ret) | ||
| 124 | goto err; | ||
| 125 | ret = sunrpc_cache_register_pipefs(nd.path.dentry, | ||
| 126 | cd->name, 0600, cd); | ||
| 127 | path_put(&nd.path); | ||
| 128 | if (!ret) | ||
| 129 | return ret; | ||
| 130 | err: | ||
| 131 | rpc_put_mount(); | ||
| 132 | return ret; | ||
| 133 | } | ||
| 134 | |||
| 135 | void nfs_cache_unregister(struct cache_detail *cd) | ||
| 136 | { | ||
| 137 | sunrpc_cache_unregister_pipefs(cd); | ||
| 138 | rpc_put_mount(); | ||
| 139 | } | ||
| 140 | |||
diff --git a/fs/nfs/cache_lib.h b/fs/nfs/cache_lib.h new file mode 100644 index 00000000000..76f856e284e --- /dev/null +++ b/fs/nfs/cache_lib.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | /* | ||
| 2 | * Helper routines for the NFS client caches | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/completion.h> | ||
| 8 | #include <linux/sunrpc/cache.h> | ||
| 9 | #include <asm/atomic.h> | ||
| 10 | |||
| 11 | /* | ||
| 12 | * Deferred request handling | ||
| 13 | */ | ||
| 14 | struct nfs_cache_defer_req { | ||
| 15 | struct cache_req req; | ||
| 16 | struct cache_deferred_req deferred_req; | ||
| 17 | struct completion completion; | ||
| 18 | atomic_t count; | ||
| 19 | }; | ||
| 20 | |||
| 21 | extern int nfs_cache_upcall(struct cache_detail *cd, char *entry_name); | ||
| 22 | extern struct nfs_cache_defer_req *nfs_cache_defer_req_alloc(void); | ||
| 23 | extern void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq); | ||
| 24 | extern int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq); | ||
| 25 | |||
| 26 | extern int nfs_cache_register(struct cache_detail *cd); | ||
| 27 | extern void nfs_cache_unregister(struct cache_detail *cd); | ||
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 7f604c7941f..293fa0528a6 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
| @@ -43,21 +43,29 @@ static struct svc_program nfs4_callback_program; | |||
| 43 | unsigned int nfs_callback_set_tcpport; | 43 | unsigned int nfs_callback_set_tcpport; |
| 44 | unsigned short nfs_callback_tcpport; | 44 | unsigned short nfs_callback_tcpport; |
| 45 | unsigned short nfs_callback_tcpport6; | 45 | unsigned short nfs_callback_tcpport6; |
| 46 | static const int nfs_set_port_min = 0; | 46 | #define NFS_CALLBACK_MAXPORTNR (65535U) |
| 47 | static const int nfs_set_port_max = 65535; | ||
| 48 | 47 | ||
| 49 | static int param_set_port(const char *val, struct kernel_param *kp) | 48 | static int param_set_portnr(const char *val, struct kernel_param *kp) |
| 50 | { | 49 | { |
| 51 | char *endp; | 50 | unsigned long num; |
| 52 | int num = simple_strtol(val, &endp, 0); | 51 | int ret; |
| 53 | if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max) | 52 | |
| 53 | if (!val) | ||
| 54 | return -EINVAL; | ||
| 55 | ret = strict_strtoul(val, 0, &num); | ||
| 56 | if (ret == -EINVAL || num > NFS_CALLBACK_MAXPORTNR) | ||
| 54 | return -EINVAL; | 57 | return -EINVAL; |
| 55 | *((int *)kp->arg) = num; | 58 | *((unsigned int *)kp->arg) = num; |
| 56 | return 0; | 59 | return 0; |
| 57 | } | 60 | } |
| 58 | 61 | ||
| 59 | module_param_call(callback_tcpport, param_set_port, param_get_int, | 62 | static int param_get_portnr(char *buffer, struct kernel_param *kp) |
| 60 | &nfs_callback_set_tcpport, 0644); | 63 | { |
| 64 | return param_get_uint(buffer, kp); | ||
| 65 | } | ||
| 66 | #define param_check_portnr(name, p) __param_check(name, p, unsigned int); | ||
| 67 | |||
| 68 | module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644); | ||
| 61 | 69 | ||
| 62 | /* | 70 | /* |
| 63 | * This is the NFSv4 callback kernel thread. | 71 | * This is the NFSv4 callback kernel thread. |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 8d25ccb2d51..e350bd6a233 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -809,6 +809,9 @@ static int nfs_init_server(struct nfs_server *server, | |||
| 809 | /* Initialise the client representation from the mount data */ | 809 | /* Initialise the client representation from the mount data */ |
| 810 | server->flags = data->flags; | 810 | server->flags = data->flags; |
| 811 | server->options = data->options; | 811 | server->options = data->options; |
| 812 | server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID| | ||
| 813 | NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP| | ||
| 814 | NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME; | ||
| 812 | 815 | ||
| 813 | if (data->rsize) | 816 | if (data->rsize) |
| 814 | server->rsize = nfs_block_size(data->rsize, NULL); | 817 | server->rsize = nfs_block_size(data->rsize, NULL); |
| @@ -879,6 +882,7 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo * | |||
| 879 | server->rsize = NFS_MAX_FILE_IO_SIZE; | 882 | server->rsize = NFS_MAX_FILE_IO_SIZE; |
| 880 | server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 883 | server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
| 881 | 884 | ||
| 885 | server->backing_dev_info.name = "nfs"; | ||
| 882 | server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD; | 886 | server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD; |
| 883 | 887 | ||
| 884 | if (server->wsize > max_rpc_payload) | 888 | if (server->wsize > max_rpc_payload) |
| @@ -1074,10 +1078,6 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1074 | (unsigned long long) server->fsid.major, | 1078 | (unsigned long long) server->fsid.major, |
| 1075 | (unsigned long long) server->fsid.minor); | 1079 | (unsigned long long) server->fsid.minor); |
| 1076 | 1080 | ||
| 1077 | BUG_ON(!server->nfs_client); | ||
| 1078 | BUG_ON(!server->nfs_client->rpc_ops); | ||
| 1079 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
| 1080 | |||
| 1081 | spin_lock(&nfs_client_lock); | 1081 | spin_lock(&nfs_client_lock); |
| 1082 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | 1082 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); |
| 1083 | list_add_tail(&server->master_link, &nfs_volume_list); | 1083 | list_add_tail(&server->master_link, &nfs_volume_list); |
| @@ -1274,7 +1274,7 @@ static int nfs4_init_server(struct nfs_server *server, | |||
| 1274 | 1274 | ||
| 1275 | /* Initialise the client representation from the mount data */ | 1275 | /* Initialise the client representation from the mount data */ |
| 1276 | server->flags = data->flags; | 1276 | server->flags = data->flags; |
| 1277 | server->caps |= NFS_CAP_ATOMIC_OPEN; | 1277 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; |
| 1278 | server->options = data->options; | 1278 | server->options = data->options; |
| 1279 | 1279 | ||
| 1280 | /* Get a client record */ | 1280 | /* Get a client record */ |
| @@ -1359,10 +1359,6 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1359 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) | 1359 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) |
| 1360 | server->namelen = NFS4_MAXNAMLEN; | 1360 | server->namelen = NFS4_MAXNAMLEN; |
| 1361 | 1361 | ||
| 1362 | BUG_ON(!server->nfs_client); | ||
| 1363 | BUG_ON(!server->nfs_client->rpc_ops); | ||
| 1364 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
| 1365 | |||
| 1366 | spin_lock(&nfs_client_lock); | 1362 | spin_lock(&nfs_client_lock); |
| 1367 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | 1363 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); |
| 1368 | list_add_tail(&server->master_link, &nfs_volume_list); | 1364 | list_add_tail(&server->master_link, &nfs_volume_list); |
| @@ -1400,7 +1396,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1400 | 1396 | ||
| 1401 | /* Initialise the client representation from the parent server */ | 1397 | /* Initialise the client representation from the parent server */ |
| 1402 | nfs_server_copy_userdata(server, parent_server); | 1398 | nfs_server_copy_userdata(server, parent_server); |
| 1403 | server->caps |= NFS_CAP_ATOMIC_OPEN; | 1399 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; |
| 1404 | 1400 | ||
| 1405 | /* Get a client representation. | 1401 | /* Get a client representation. |
| 1406 | * Note: NFSv4 always uses TCP, */ | 1402 | * Note: NFSv4 always uses TCP, */ |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index e4e089a8f29..6c3210099d5 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
| @@ -934,9 +934,6 @@ out: | |||
| 934 | * back into its cache. We let the server do generic write | 934 | * back into its cache. We let the server do generic write |
| 935 | * parameter checking and report problems. | 935 | * parameter checking and report problems. |
| 936 | * | 936 | * |
| 937 | * We also avoid an unnecessary invocation of generic_osync_inode(), | ||
| 938 | * as it is fairly meaningless to sync the metadata of an NFS file. | ||
| 939 | * | ||
| 940 | * We eliminate local atime updates, see direct read above. | 937 | * We eliminate local atime updates, see direct read above. |
| 941 | * | 938 | * |
| 942 | * We avoid unnecessary page cache invalidations for normal cached | 939 | * We avoid unnecessary page cache invalidations for normal cached |
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c new file mode 100644 index 00000000000..f4d54ba97cc --- /dev/null +++ b/fs/nfs/dns_resolve.c | |||
| @@ -0,0 +1,335 @@ | |||
| 1 | /* | ||
| 2 | * linux/fs/nfs/dns_resolve.c | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com> | ||
| 5 | * | ||
| 6 | * Resolves DNS hostnames into valid ip addresses | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/hash.h> | ||
| 10 | #include <linux/string.h> | ||
| 11 | #include <linux/kmod.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/socket.h> | ||
| 14 | #include <linux/seq_file.h> | ||
| 15 | #include <linux/inet.h> | ||
| 16 | #include <linux/sunrpc/clnt.h> | ||
| 17 | #include <linux/sunrpc/cache.h> | ||
| 18 | #include <linux/sunrpc/svcauth.h> | ||
| 19 | |||
| 20 | #include "dns_resolve.h" | ||
| 21 | #include "cache_lib.h" | ||
| 22 | |||
| 23 | #define NFS_DNS_HASHBITS 4 | ||
| 24 | #define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS) | ||
| 25 | |||
| 26 | static struct cache_head *nfs_dns_table[NFS_DNS_HASHTBL_SIZE]; | ||
| 27 | |||
| 28 | struct nfs_dns_ent { | ||
| 29 | struct cache_head h; | ||
| 30 | |||
| 31 | char *hostname; | ||
| 32 | size_t namelen; | ||
| 33 | |||
| 34 | struct sockaddr_storage addr; | ||
| 35 | size_t addrlen; | ||
| 36 | }; | ||
| 37 | |||
| 38 | |||
| 39 | static void nfs_dns_ent_init(struct cache_head *cnew, | ||
| 40 | struct cache_head *ckey) | ||
| 41 | { | ||
| 42 | struct nfs_dns_ent *new; | ||
| 43 | struct nfs_dns_ent *key; | ||
| 44 | |||
| 45 | new = container_of(cnew, struct nfs_dns_ent, h); | ||
| 46 | key = container_of(ckey, struct nfs_dns_ent, h); | ||
| 47 | |||
| 48 | kfree(new->hostname); | ||
| 49 | new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL); | ||
| 50 | if (new->hostname) { | ||
| 51 | new->namelen = key->namelen; | ||
| 52 | memcpy(&new->addr, &key->addr, key->addrlen); | ||
| 53 | new->addrlen = key->addrlen; | ||
| 54 | } else { | ||
| 55 | new->namelen = 0; | ||
| 56 | new->addrlen = 0; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | static void nfs_dns_ent_put(struct kref *ref) | ||
| 61 | { | ||
| 62 | struct nfs_dns_ent *item; | ||
| 63 | |||
| 64 | item = container_of(ref, struct nfs_dns_ent, h.ref); | ||
| 65 | kfree(item->hostname); | ||
| 66 | kfree(item); | ||
| 67 | } | ||
| 68 | |||
| 69 | static struct cache_head *nfs_dns_ent_alloc(void) | ||
| 70 | { | ||
| 71 | struct nfs_dns_ent *item = kmalloc(sizeof(*item), GFP_KERNEL); | ||
| 72 | |||
| 73 | if (item != NULL) { | ||
| 74 | item->hostname = NULL; | ||
| 75 | item->namelen = 0; | ||
| 76 | item->addrlen = 0; | ||
| 77 | return &item->h; | ||
| 78 | } | ||
| 79 | return NULL; | ||
| 80 | }; | ||
| 81 | |||
| 82 | static unsigned int nfs_dns_hash(const struct nfs_dns_ent *key) | ||
| 83 | { | ||
| 84 | return hash_str(key->hostname, NFS_DNS_HASHBITS); | ||
| 85 | } | ||
| 86 | |||
| 87 | static void nfs_dns_request(struct cache_detail *cd, | ||
| 88 | struct cache_head *ch, | ||
| 89 | char **bpp, int *blen) | ||
| 90 | { | ||
| 91 | struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); | ||
| 92 | |||
| 93 | qword_add(bpp, blen, key->hostname); | ||
| 94 | (*bpp)[-1] = '\n'; | ||
| 95 | } | ||
| 96 | |||
| 97 | static int nfs_dns_upcall(struct cache_detail *cd, | ||
| 98 | struct cache_head *ch) | ||
| 99 | { | ||
| 100 | struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); | ||
| 101 | int ret; | ||
| 102 | |||
| 103 | ret = nfs_cache_upcall(cd, key->hostname); | ||
| 104 | if (ret) | ||
| 105 | ret = sunrpc_cache_pipe_upcall(cd, ch, nfs_dns_request); | ||
| 106 | return ret; | ||
| 107 | } | ||
| 108 | |||
| 109 | static int nfs_dns_match(struct cache_head *ca, | ||
| 110 | struct cache_head *cb) | ||
| 111 | { | ||
| 112 | struct nfs_dns_ent *a; | ||
| 113 | struct nfs_dns_ent *b; | ||
| 114 | |||
| 115 | a = container_of(ca, struct nfs_dns_ent, h); | ||
| 116 | b = container_of(cb, struct nfs_dns_ent, h); | ||
| 117 | |||
| 118 | if (a->namelen == 0 || a->namelen != b->namelen) | ||
| 119 | return 0; | ||
| 120 | return memcmp(a->hostname, b->hostname, a->namelen) == 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd, | ||
| 124 | struct cache_head *h) | ||
| 125 | { | ||
| 126 | struct nfs_dns_ent *item; | ||
| 127 | long ttl; | ||
| 128 | |||
| 129 | if (h == NULL) { | ||
| 130 | seq_puts(m, "# ip address hostname ttl\n"); | ||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | item = container_of(h, struct nfs_dns_ent, h); | ||
| 134 | ttl = (long)item->h.expiry_time - (long)get_seconds(); | ||
| 135 | if (ttl < 0) | ||
| 136 | ttl = 0; | ||
| 137 | |||
| 138 | if (!test_bit(CACHE_NEGATIVE, &h->flags)) { | ||
| 139 | char buf[INET6_ADDRSTRLEN+IPV6_SCOPE_ID_LEN+1]; | ||
| 140 | |||
| 141 | rpc_ntop((struct sockaddr *)&item->addr, buf, sizeof(buf)); | ||
| 142 | seq_printf(m, "%15s ", buf); | ||
| 143 | } else | ||
| 144 | seq_puts(m, "<none> "); | ||
| 145 | seq_printf(m, "%15s %ld\n", item->hostname, ttl); | ||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd, | ||
| 150 | struct nfs_dns_ent *key) | ||
| 151 | { | ||
| 152 | struct cache_head *ch; | ||
| 153 | |||
| 154 | ch = sunrpc_cache_lookup(cd, | ||
| 155 | &key->h, | ||
| 156 | nfs_dns_hash(key)); | ||
| 157 | if (!ch) | ||
| 158 | return NULL; | ||
| 159 | return container_of(ch, struct nfs_dns_ent, h); | ||
| 160 | } | ||
| 161 | |||
| 162 | struct nfs_dns_ent *nfs_dns_update(struct cache_detail *cd, | ||
| 163 | struct nfs_dns_ent *new, | ||
| 164 | struct nfs_dns_ent *key) | ||
| 165 | { | ||
| 166 | struct cache_head *ch; | ||
| 167 | |||
| 168 | ch = sunrpc_cache_update(cd, | ||
| 169 | &new->h, &key->h, | ||
| 170 | nfs_dns_hash(key)); | ||
| 171 | if (!ch) | ||
| 172 | return NULL; | ||
| 173 | return container_of(ch, struct nfs_dns_ent, h); | ||
| 174 | } | ||
| 175 | |||
| 176 | static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) | ||
| 177 | { | ||
| 178 | char buf1[NFS_DNS_HOSTNAME_MAXLEN+1]; | ||
| 179 | struct nfs_dns_ent key, *item; | ||
| 180 | unsigned long ttl; | ||
| 181 | ssize_t len; | ||
| 182 | int ret = -EINVAL; | ||
| 183 | |||
| 184 | if (buf[buflen-1] != '\n') | ||
| 185 | goto out; | ||
| 186 | buf[buflen-1] = '\0'; | ||
| 187 | |||
| 188 | len = qword_get(&buf, buf1, sizeof(buf1)); | ||
| 189 | if (len <= 0) | ||
| 190 | goto out; | ||
| 191 | key.addrlen = rpc_pton(buf1, len, | ||
| 192 | (struct sockaddr *)&key.addr, | ||
| 193 | sizeof(key.addr)); | ||
| 194 | |||
| 195 | len = qword_get(&buf, buf1, sizeof(buf1)); | ||
| 196 | if (len <= 0) | ||
| 197 | goto out; | ||
| 198 | |||
| 199 | key.hostname = buf1; | ||
| 200 | key.namelen = len; | ||
| 201 | memset(&key.h, 0, sizeof(key.h)); | ||
| 202 | |||
| 203 | ttl = get_expiry(&buf); | ||
| 204 | if (ttl == 0) | ||
| 205 | goto out; | ||
| 206 | key.h.expiry_time = ttl + get_seconds(); | ||
| 207 | |||
| 208 | ret = -ENOMEM; | ||
| 209 | item = nfs_dns_lookup(cd, &key); | ||
| 210 | if (item == NULL) | ||
| 211 | goto out; | ||
| 212 | |||
| 213 | if (key.addrlen == 0) | ||
| 214 | set_bit(CACHE_NEGATIVE, &key.h.flags); | ||
| 215 | |||
| 216 | item = nfs_dns_update(cd, &key, item); | ||
| 217 | if (item == NULL) | ||
| 218 | goto out; | ||
| 219 | |||
| 220 | ret = 0; | ||
| 221 | cache_put(&item->h, cd); | ||
| 222 | out: | ||
| 223 | return ret; | ||
| 224 | } | ||
| 225 | |||
| 226 | static struct cache_detail nfs_dns_resolve = { | ||
| 227 | .owner = THIS_MODULE, | ||
| 228 | .hash_size = NFS_DNS_HASHTBL_SIZE, | ||
| 229 | .hash_table = nfs_dns_table, | ||
| 230 | .name = "dns_resolve", | ||
| 231 | .cache_put = nfs_dns_ent_put, | ||
| 232 | .cache_upcall = nfs_dns_upcall, | ||
| 233 | .cache_parse = nfs_dns_parse, | ||
| 234 | .cache_show = nfs_dns_show, | ||
| 235 | .match = nfs_dns_match, | ||
| 236 | .init = nfs_dns_ent_init, | ||
| 237 | .update = nfs_dns_ent_init, | ||
| 238 | .alloc = nfs_dns_ent_alloc, | ||
| 239 | }; | ||
| 240 | |||
| 241 | static int do_cache_lookup(struct cache_detail *cd, | ||
| 242 | struct nfs_dns_ent *key, | ||
| 243 | struct nfs_dns_ent **item, | ||
| 244 | struct nfs_cache_defer_req *dreq) | ||
| 245 | { | ||
| 246 | int ret = -ENOMEM; | ||
| 247 | |||
| 248 | *item = nfs_dns_lookup(cd, key); | ||
| 249 | if (*item) { | ||
| 250 | ret = cache_check(cd, &(*item)->h, &dreq->req); | ||
| 251 | if (ret) | ||
| 252 | *item = NULL; | ||
| 253 | } | ||
| 254 | return ret; | ||
| 255 | } | ||
| 256 | |||
| 257 | static int do_cache_lookup_nowait(struct cache_detail *cd, | ||
| 258 | struct nfs_dns_ent *key, | ||
| 259 | struct nfs_dns_ent **item) | ||
| 260 | { | ||
| 261 | int ret = -ENOMEM; | ||
| 262 | |||
| 263 | *item = nfs_dns_lookup(cd, key); | ||
| 264 | if (!*item) | ||
| 265 | goto out_err; | ||
| 266 | ret = -ETIMEDOUT; | ||
| 267 | if (!test_bit(CACHE_VALID, &(*item)->h.flags) | ||
| 268 | || (*item)->h.expiry_time < get_seconds() | ||
| 269 | || cd->flush_time > (*item)->h.last_refresh) | ||
| 270 | goto out_put; | ||
| 271 | ret = -ENOENT; | ||
| 272 | if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags)) | ||
| 273 | goto out_put; | ||
| 274 | return 0; | ||
| 275 | out_put: | ||
| 276 | cache_put(&(*item)->h, cd); | ||
| 277 | out_err: | ||
| 278 | *item = NULL; | ||
| 279 | return ret; | ||
| 280 | } | ||
| 281 | |||
| 282 | static int do_cache_lookup_wait(struct cache_detail *cd, | ||
| 283 | struct nfs_dns_ent *key, | ||
| 284 | struct nfs_dns_ent **item) | ||
| 285 | { | ||
| 286 | struct nfs_cache_defer_req *dreq; | ||
| 287 | int ret = -ENOMEM; | ||
| 288 | |||
| 289 | dreq = nfs_cache_defer_req_alloc(); | ||
| 290 | if (!dreq) | ||
| 291 | goto out; | ||
| 292 | ret = do_cache_lookup(cd, key, item, dreq); | ||
| 293 | if (ret == -EAGAIN) { | ||
| 294 | ret = nfs_cache_wait_for_upcall(dreq); | ||
| 295 | if (!ret) | ||
| 296 | ret = do_cache_lookup_nowait(cd, key, item); | ||
| 297 | } | ||
| 298 | nfs_cache_defer_req_put(dreq); | ||
| 299 | out: | ||
| 300 | return ret; | ||
| 301 | } | ||
| 302 | |||
| 303 | ssize_t nfs_dns_resolve_name(char *name, size_t namelen, | ||
| 304 | struct sockaddr *sa, size_t salen) | ||
| 305 | { | ||
| 306 | struct nfs_dns_ent key = { | ||
| 307 | .hostname = name, | ||
| 308 | .namelen = namelen, | ||
| 309 | }; | ||
| 310 | struct nfs_dns_ent *item = NULL; | ||
| 311 | ssize_t ret; | ||
| 312 | |||
| 313 | ret = do_cache_lookup_wait(&nfs_dns_resolve, &key, &item); | ||
| 314 | if (ret == 0) { | ||
| 315 | if (salen >= item->addrlen) { | ||
| 316 | memcpy(sa, &item->addr, item->addrlen); | ||
| 317 | ret = item->addrlen; | ||
| 318 | } else | ||
| 319 | ret = -EOVERFLOW; | ||
| 320 | cache_put(&item->h, &nfs_dns_resolve); | ||
| 321 | } else if (ret == -ENOENT) | ||
| 322 | ret = -ESRCH; | ||
| 323 | return ret; | ||
| 324 | } | ||
| 325 | |||
| 326 | int nfs_dns_resolver_init(void) | ||
| 327 | { | ||
| 328 | return nfs_cache_register(&nfs_dns_resolve); | ||
| 329 | } | ||
| 330 | |||
| 331 | void nfs_dns_resolver_destroy(void) | ||
| 332 | { | ||
| 333 | nfs_cache_unregister(&nfs_dns_resolve); | ||
| 334 | } | ||
| 335 | |||
diff --git a/fs/nfs/dns_resolve.h b/fs/nfs/dns_resolve.h new file mode 100644 index 00000000000..a3f0938babf --- /dev/null +++ b/fs/nfs/dns_resolve.h | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | /* | ||
| 2 | * Resolve DNS hostnames into valid ip addresses | ||
| 3 | */ | ||
| 4 | #ifndef __LINUX_FS_NFS_DNS_RESOLVE_H | ||
| 5 | #define __LINUX_FS_NFS_DNS_RESOLVE_H | ||
| 6 | |||
| 7 | #define NFS_DNS_HOSTNAME_MAXLEN (128) | ||
| 8 | |||
| 9 | extern int nfs_dns_resolver_init(void); | ||
| 10 | extern void nfs_dns_resolver_destroy(void); | ||
| 11 | extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen, | ||
| 12 | struct sockaddr *sa, size_t salen); | ||
| 13 | |||
| 14 | #endif | ||
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 05062329b67..5021b75d2d1 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -328,6 +328,42 @@ nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync) | |||
| 328 | } | 328 | } |
| 329 | 329 | ||
| 330 | /* | 330 | /* |
| 331 | * Decide whether a read/modify/write cycle may be more efficient | ||
| 332 | * then a modify/write/read cycle when writing to a page in the | ||
| 333 | * page cache. | ||
| 334 | * | ||
| 335 | * The modify/write/read cycle may occur if a page is read before | ||
| 336 | * being completely filled by the writer. In this situation, the | ||
| 337 | * page must be completely written to stable storage on the server | ||
| 338 | * before it can be refilled by reading in the page from the server. | ||
| 339 | * This can lead to expensive, small, FILE_SYNC mode writes being | ||
| 340 | * done. | ||
| 341 | * | ||
| 342 | * It may be more efficient to read the page first if the file is | ||
| 343 | * open for reading in addition to writing, the page is not marked | ||
| 344 | * as Uptodate, it is not dirty or waiting to be committed, | ||
| 345 | * indicating that it was previously allocated and then modified, | ||
| 346 | * that there were valid bytes of data in that range of the file, | ||
| 347 | * and that the new data won't completely replace the old data in | ||
| 348 | * that range of the file. | ||
| 349 | */ | ||
| 350 | static int nfs_want_read_modify_write(struct file *file, struct page *page, | ||
| 351 | loff_t pos, unsigned len) | ||
| 352 | { | ||
| 353 | unsigned int pglen = nfs_page_length(page); | ||
| 354 | unsigned int offset = pos & (PAGE_CACHE_SIZE - 1); | ||
| 355 | unsigned int end = offset + len; | ||
| 356 | |||
| 357 | if ((file->f_mode & FMODE_READ) && /* open for read? */ | ||
| 358 | !PageUptodate(page) && /* Uptodate? */ | ||
| 359 | !PagePrivate(page) && /* i/o request already? */ | ||
| 360 | pglen && /* valid bytes of file? */ | ||
| 361 | (end < pglen || offset)) /* replace all valid bytes? */ | ||
| 362 | return 1; | ||
| 363 | return 0; | ||
| 364 | } | ||
| 365 | |||
| 366 | /* | ||
| 331 | * This does the "real" work of the write. We must allocate and lock the | 367 | * This does the "real" work of the write. We must allocate and lock the |
| 332 | * page to be sent back to the generic routine, which then copies the | 368 | * page to be sent back to the generic routine, which then copies the |
| 333 | * data from user space. | 369 | * data from user space. |
| @@ -340,15 +376,16 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, | |||
| 340 | struct page **pagep, void **fsdata) | 376 | struct page **pagep, void **fsdata) |
| 341 | { | 377 | { |
| 342 | int ret; | 378 | int ret; |
| 343 | pgoff_t index; | 379 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
| 344 | struct page *page; | 380 | struct page *page; |
| 345 | index = pos >> PAGE_CACHE_SHIFT; | 381 | int once_thru = 0; |
| 346 | 382 | ||
| 347 | dfprintk(PAGECACHE, "NFS: write_begin(%s/%s(%ld), %u@%lld)\n", | 383 | dfprintk(PAGECACHE, "NFS: write_begin(%s/%s(%ld), %u@%lld)\n", |
| 348 | file->f_path.dentry->d_parent->d_name.name, | 384 | file->f_path.dentry->d_parent->d_name.name, |
| 349 | file->f_path.dentry->d_name.name, | 385 | file->f_path.dentry->d_name.name, |
| 350 | mapping->host->i_ino, len, (long long) pos); | 386 | mapping->host->i_ino, len, (long long) pos); |
| 351 | 387 | ||
| 388 | start: | ||
| 352 | /* | 389 | /* |
| 353 | * Prevent starvation issues if someone is doing a consistency | 390 | * Prevent starvation issues if someone is doing a consistency |
| 354 | * sync-to-disk | 391 | * sync-to-disk |
| @@ -367,6 +404,13 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, | |||
| 367 | if (ret) { | 404 | if (ret) { |
| 368 | unlock_page(page); | 405 | unlock_page(page); |
| 369 | page_cache_release(page); | 406 | page_cache_release(page); |
| 407 | } else if (!once_thru && | ||
| 408 | nfs_want_read_modify_write(file, page, pos, len)) { | ||
| 409 | once_thru = 1; | ||
| 410 | ret = nfs_readpage(file, page); | ||
| 411 | page_cache_release(page); | ||
| 412 | if (!ret) | ||
| 413 | goto start; | ||
| 370 | } | 414 | } |
| 371 | return ret; | 415 | return ret; |
| 372 | } | 416 | } |
| @@ -479,6 +523,7 @@ const struct address_space_operations nfs_file_aops = { | |||
| 479 | .invalidatepage = nfs_invalidate_page, | 523 | .invalidatepage = nfs_invalidate_page, |
| 480 | .releasepage = nfs_release_page, | 524 | .releasepage = nfs_release_page, |
| 481 | .direct_IO = nfs_direct_IO, | 525 | .direct_IO = nfs_direct_IO, |
| 526 | .migratepage = nfs_migrate_page, | ||
| 482 | .launder_page = nfs_launder_page, | 527 | .launder_page = nfs_launder_page, |
| 483 | }; | 528 | }; |
| 484 | 529 | ||
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 86147b0ab2c..21a84d45916 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
| @@ -101,7 +101,7 @@ static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); | |||
| 101 | 101 | ||
| 102 | static unsigned int fnvhash32(const void *, size_t); | 102 | static unsigned int fnvhash32(const void *, size_t); |
| 103 | 103 | ||
| 104 | static struct rpc_pipe_ops idmap_upcall_ops = { | 104 | static const struct rpc_pipe_ops idmap_upcall_ops = { |
| 105 | .upcall = idmap_pipe_upcall, | 105 | .upcall = idmap_pipe_upcall, |
| 106 | .downcall = idmap_pipe_downcall, | 106 | .downcall = idmap_pipe_downcall, |
| 107 | .destroy_msg = idmap_pipe_destroy_msg, | 107 | .destroy_msg = idmap_pipe_destroy_msg, |
| @@ -119,8 +119,8 @@ nfs_idmap_new(struct nfs_client *clp) | |||
| 119 | if (idmap == NULL) | 119 | if (idmap == NULL) |
| 120 | return -ENOMEM; | 120 | return -ENOMEM; |
| 121 | 121 | ||
| 122 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap", | 122 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry, |
| 123 | idmap, &idmap_upcall_ops, 0); | 123 | "idmap", idmap, &idmap_upcall_ops, 0); |
| 124 | if (IS_ERR(idmap->idmap_dentry)) { | 124 | if (IS_ERR(idmap->idmap_dentry)) { |
| 125 | error = PTR_ERR(idmap->idmap_dentry); | 125 | error = PTR_ERR(idmap->idmap_dentry); |
| 126 | kfree(idmap); | 126 | kfree(idmap); |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index bd7938eda6a..060022b4651 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #include "iostat.h" | 46 | #include "iostat.h" |
| 47 | #include "internal.h" | 47 | #include "internal.h" |
| 48 | #include "fscache.h" | 48 | #include "fscache.h" |
| 49 | #include "dns_resolve.h" | ||
| 49 | 50 | ||
| 50 | #define NFSDBG_FACILITY NFSDBG_VFS | 51 | #define NFSDBG_FACILITY NFSDBG_VFS |
| 51 | 52 | ||
| @@ -286,6 +287,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
| 286 | /* We can't support update_atime(), since the server will reset it */ | 287 | /* We can't support update_atime(), since the server will reset it */ |
| 287 | inode->i_flags |= S_NOATIME|S_NOCMTIME; | 288 | inode->i_flags |= S_NOATIME|S_NOCMTIME; |
| 288 | inode->i_mode = fattr->mode; | 289 | inode->i_mode = fattr->mode; |
| 290 | if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0 | ||
| 291 | && nfs_server_capable(inode, NFS_CAP_MODE)) | ||
| 292 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
| 293 | | NFS_INO_INVALID_ACCESS | ||
| 294 | | NFS_INO_INVALID_ACL; | ||
| 289 | /* Why so? Because we want revalidate for devices/FIFOs, and | 295 | /* Why so? Because we want revalidate for devices/FIFOs, and |
| 290 | * that's precisely what we have in nfs_file_inode_operations. | 296 | * that's precisely what we have in nfs_file_inode_operations. |
| 291 | */ | 297 | */ |
| @@ -330,20 +336,46 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
| 330 | nfsi->attr_gencount = fattr->gencount; | 336 | nfsi->attr_gencount = fattr->gencount; |
| 331 | if (fattr->valid & NFS_ATTR_FATTR_ATIME) | 337 | if (fattr->valid & NFS_ATTR_FATTR_ATIME) |
| 332 | inode->i_atime = fattr->atime; | 338 | inode->i_atime = fattr->atime; |
| 339 | else if (nfs_server_capable(inode, NFS_CAP_ATIME)) | ||
| 340 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | ||
| 333 | if (fattr->valid & NFS_ATTR_FATTR_MTIME) | 341 | if (fattr->valid & NFS_ATTR_FATTR_MTIME) |
| 334 | inode->i_mtime = fattr->mtime; | 342 | inode->i_mtime = fattr->mtime; |
| 343 | else if (nfs_server_capable(inode, NFS_CAP_MTIME)) | ||
| 344 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
| 345 | | NFS_INO_INVALID_DATA; | ||
| 335 | if (fattr->valid & NFS_ATTR_FATTR_CTIME) | 346 | if (fattr->valid & NFS_ATTR_FATTR_CTIME) |
| 336 | inode->i_ctime = fattr->ctime; | 347 | inode->i_ctime = fattr->ctime; |
| 348 | else if (nfs_server_capable(inode, NFS_CAP_CTIME)) | ||
| 349 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
| 350 | | NFS_INO_INVALID_ACCESS | ||
| 351 | | NFS_INO_INVALID_ACL; | ||
| 337 | if (fattr->valid & NFS_ATTR_FATTR_CHANGE) | 352 | if (fattr->valid & NFS_ATTR_FATTR_CHANGE) |
| 338 | nfsi->change_attr = fattr->change_attr; | 353 | nfsi->change_attr = fattr->change_attr; |
| 354 | else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR)) | ||
| 355 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
| 356 | | NFS_INO_INVALID_DATA; | ||
| 339 | if (fattr->valid & NFS_ATTR_FATTR_SIZE) | 357 | if (fattr->valid & NFS_ATTR_FATTR_SIZE) |
| 340 | inode->i_size = nfs_size_to_loff_t(fattr->size); | 358 | inode->i_size = nfs_size_to_loff_t(fattr->size); |
| 359 | else | ||
| 360 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
| 361 | | NFS_INO_INVALID_DATA | ||
| 362 | | NFS_INO_REVAL_PAGECACHE; | ||
| 341 | if (fattr->valid & NFS_ATTR_FATTR_NLINK) | 363 | if (fattr->valid & NFS_ATTR_FATTR_NLINK) |
| 342 | inode->i_nlink = fattr->nlink; | 364 | inode->i_nlink = fattr->nlink; |
| 365 | else if (nfs_server_capable(inode, NFS_CAP_NLINK)) | ||
| 366 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | ||
| 343 | if (fattr->valid & NFS_ATTR_FATTR_OWNER) | 367 | if (fattr->valid & NFS_ATTR_FATTR_OWNER) |
| 344 | inode->i_uid = fattr->uid; | 368 | inode->i_uid = fattr->uid; |
| 369 | else if (nfs_server_capable(inode, NFS_CAP_OWNER)) | ||
| 370 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
| 371 | | NFS_INO_INVALID_ACCESS | ||
| 372 | | NFS_INO_INVALID_ACL; | ||
| 345 | if (fattr->valid & NFS_ATTR_FATTR_GROUP) | 373 | if (fattr->valid & NFS_ATTR_FATTR_GROUP) |
| 346 | inode->i_gid = fattr->gid; | 374 | inode->i_gid = fattr->gid; |
| 375 | else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP)) | ||
| 376 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR | ||
| 377 | | NFS_INO_INVALID_ACCESS | ||
| 378 | | NFS_INO_INVALID_ACL; | ||
| 347 | if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) | 379 | if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) |
| 348 | inode->i_blocks = fattr->du.nfs2.blocks; | 380 | inode->i_blocks = fattr->du.nfs2.blocks; |
| 349 | if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { | 381 | if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { |
| @@ -1145,6 +1177,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1145 | loff_t cur_isize, new_isize; | 1177 | loff_t cur_isize, new_isize; |
| 1146 | unsigned long invalid = 0; | 1178 | unsigned long invalid = 0; |
| 1147 | unsigned long now = jiffies; | 1179 | unsigned long now = jiffies; |
| 1180 | unsigned long save_cache_validity; | ||
| 1148 | 1181 | ||
| 1149 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", | 1182 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", |
| 1150 | __func__, inode->i_sb->s_id, inode->i_ino, | 1183 | __func__, inode->i_sb->s_id, inode->i_ino, |
| @@ -1171,10 +1204,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1171 | */ | 1204 | */ |
| 1172 | nfsi->read_cache_jiffies = fattr->time_start; | 1205 | nfsi->read_cache_jiffies = fattr->time_start; |
| 1173 | 1206 | ||
| 1174 | if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) || (fattr->valid & (NFS_ATTR_FATTR_MTIME|NFS_ATTR_FATTR_CTIME))) | 1207 | save_cache_validity = nfsi->cache_validity; |
| 1175 | nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR | 1208 | nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR |
| 1176 | | NFS_INO_INVALID_ATIME | 1209 | | NFS_INO_INVALID_ATIME |
| 1177 | | NFS_INO_REVAL_PAGECACHE); | 1210 | | NFS_INO_REVAL_FORCED |
| 1211 | | NFS_INO_REVAL_PAGECACHE); | ||
| 1178 | 1212 | ||
| 1179 | /* Do atomic weak cache consistency updates */ | 1213 | /* Do atomic weak cache consistency updates */ |
| 1180 | nfs_wcc_update_inode(inode, fattr); | 1214 | nfs_wcc_update_inode(inode, fattr); |
| @@ -1189,7 +1223,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1189 | nfs_force_lookup_revalidate(inode); | 1223 | nfs_force_lookup_revalidate(inode); |
| 1190 | nfsi->change_attr = fattr->change_attr; | 1224 | nfsi->change_attr = fattr->change_attr; |
| 1191 | } | 1225 | } |
| 1192 | } | 1226 | } else if (server->caps & NFS_CAP_CHANGE_ATTR) |
| 1227 | invalid |= save_cache_validity; | ||
| 1193 | 1228 | ||
| 1194 | if (fattr->valid & NFS_ATTR_FATTR_MTIME) { | 1229 | if (fattr->valid & NFS_ATTR_FATTR_MTIME) { |
| 1195 | /* NFSv2/v3: Check if the mtime agrees */ | 1230 | /* NFSv2/v3: Check if the mtime agrees */ |
| @@ -1201,7 +1236,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1201 | nfs_force_lookup_revalidate(inode); | 1236 | nfs_force_lookup_revalidate(inode); |
| 1202 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); | 1237 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); |
| 1203 | } | 1238 | } |
| 1204 | } | 1239 | } else if (server->caps & NFS_CAP_MTIME) |
| 1240 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
| 1241 | | NFS_INO_INVALID_DATA | ||
| 1242 | | NFS_INO_REVAL_PAGECACHE | ||
| 1243 | | NFS_INO_REVAL_FORCED); | ||
| 1244 | |||
| 1205 | if (fattr->valid & NFS_ATTR_FATTR_CTIME) { | 1245 | if (fattr->valid & NFS_ATTR_FATTR_CTIME) { |
| 1206 | /* If ctime has changed we should definitely clear access+acl caches */ | 1246 | /* If ctime has changed we should definitely clear access+acl caches */ |
| 1207 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { | 1247 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { |
| @@ -1215,7 +1255,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1215 | } | 1255 | } |
| 1216 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | 1256 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); |
| 1217 | } | 1257 | } |
| 1218 | } | 1258 | } else if (server->caps & NFS_CAP_CTIME) |
| 1259 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
| 1260 | | NFS_INO_INVALID_ACCESS | ||
| 1261 | | NFS_INO_INVALID_ACL | ||
| 1262 | | NFS_INO_REVAL_FORCED); | ||
| 1219 | 1263 | ||
| 1220 | /* Check if our cached file size is stale */ | 1264 | /* Check if our cached file size is stale */ |
| 1221 | if (fattr->valid & NFS_ATTR_FATTR_SIZE) { | 1265 | if (fattr->valid & NFS_ATTR_FATTR_SIZE) { |
| @@ -1231,30 +1275,50 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1231 | dprintk("NFS: isize change on server for file %s/%ld\n", | 1275 | dprintk("NFS: isize change on server for file %s/%ld\n", |
| 1232 | inode->i_sb->s_id, inode->i_ino); | 1276 | inode->i_sb->s_id, inode->i_ino); |
| 1233 | } | 1277 | } |
| 1234 | } | 1278 | } else |
| 1279 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
| 1280 | | NFS_INO_REVAL_PAGECACHE | ||
| 1281 | | NFS_INO_REVAL_FORCED); | ||
| 1235 | 1282 | ||
| 1236 | 1283 | ||
| 1237 | if (fattr->valid & NFS_ATTR_FATTR_ATIME) | 1284 | if (fattr->valid & NFS_ATTR_FATTR_ATIME) |
| 1238 | memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); | 1285 | memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); |
| 1286 | else if (server->caps & NFS_CAP_ATIME) | ||
| 1287 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATIME | ||
| 1288 | | NFS_INO_REVAL_FORCED); | ||
| 1239 | 1289 | ||
| 1240 | if (fattr->valid & NFS_ATTR_FATTR_MODE) { | 1290 | if (fattr->valid & NFS_ATTR_FATTR_MODE) { |
| 1241 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { | 1291 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { |
| 1242 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1292 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
| 1243 | inode->i_mode = fattr->mode; | 1293 | inode->i_mode = fattr->mode; |
| 1244 | } | 1294 | } |
| 1245 | } | 1295 | } else if (server->caps & NFS_CAP_MODE) |
| 1296 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
| 1297 | | NFS_INO_INVALID_ACCESS | ||
| 1298 | | NFS_INO_INVALID_ACL | ||
| 1299 | | NFS_INO_REVAL_FORCED); | ||
| 1300 | |||
| 1246 | if (fattr->valid & NFS_ATTR_FATTR_OWNER) { | 1301 | if (fattr->valid & NFS_ATTR_FATTR_OWNER) { |
| 1247 | if (inode->i_uid != fattr->uid) { | 1302 | if (inode->i_uid != fattr->uid) { |
| 1248 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1303 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
| 1249 | inode->i_uid = fattr->uid; | 1304 | inode->i_uid = fattr->uid; |
| 1250 | } | 1305 | } |
| 1251 | } | 1306 | } else if (server->caps & NFS_CAP_OWNER) |
| 1307 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
| 1308 | | NFS_INO_INVALID_ACCESS | ||
| 1309 | | NFS_INO_INVALID_ACL | ||
| 1310 | | NFS_INO_REVAL_FORCED); | ||
| 1311 | |||
| 1252 | if (fattr->valid & NFS_ATTR_FATTR_GROUP) { | 1312 | if (fattr->valid & NFS_ATTR_FATTR_GROUP) { |
| 1253 | if (inode->i_gid != fattr->gid) { | 1313 | if (inode->i_gid != fattr->gid) { |
| 1254 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1314 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
| 1255 | inode->i_gid = fattr->gid; | 1315 | inode->i_gid = fattr->gid; |
| 1256 | } | 1316 | } |
| 1257 | } | 1317 | } else if (server->caps & NFS_CAP_OWNER_GROUP) |
| 1318 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
| 1319 | | NFS_INO_INVALID_ACCESS | ||
| 1320 | | NFS_INO_INVALID_ACL | ||
| 1321 | | NFS_INO_REVAL_FORCED); | ||
| 1258 | 1322 | ||
| 1259 | if (fattr->valid & NFS_ATTR_FATTR_NLINK) { | 1323 | if (fattr->valid & NFS_ATTR_FATTR_NLINK) { |
| 1260 | if (inode->i_nlink != fattr->nlink) { | 1324 | if (inode->i_nlink != fattr->nlink) { |
| @@ -1263,7 +1327,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1263 | invalid |= NFS_INO_INVALID_DATA; | 1327 | invalid |= NFS_INO_INVALID_DATA; |
| 1264 | inode->i_nlink = fattr->nlink; | 1328 | inode->i_nlink = fattr->nlink; |
| 1265 | } | 1329 | } |
| 1266 | } | 1330 | } else if (server->caps & NFS_CAP_NLINK) |
| 1331 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | ||
| 1332 | | NFS_INO_REVAL_FORCED); | ||
| 1267 | 1333 | ||
| 1268 | if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { | 1334 | if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { |
| 1269 | /* | 1335 | /* |
| @@ -1293,9 +1359,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1293 | || S_ISLNK(inode->i_mode))) | 1359 | || S_ISLNK(inode->i_mode))) |
| 1294 | invalid &= ~NFS_INO_INVALID_DATA; | 1360 | invalid &= ~NFS_INO_INVALID_DATA; |
| 1295 | if (!nfs_have_delegation(inode, FMODE_READ) || | 1361 | if (!nfs_have_delegation(inode, FMODE_READ) || |
| 1296 | (nfsi->cache_validity & NFS_INO_REVAL_FORCED)) | 1362 | (save_cache_validity & NFS_INO_REVAL_FORCED)) |
| 1297 | nfsi->cache_validity |= invalid; | 1363 | nfsi->cache_validity |= invalid; |
| 1298 | nfsi->cache_validity &= ~NFS_INO_REVAL_FORCED; | ||
| 1299 | 1364 | ||
| 1300 | return 0; | 1365 | return 0; |
| 1301 | out_changed: | 1366 | out_changed: |
| @@ -1442,6 +1507,10 @@ static int __init init_nfs_fs(void) | |||
| 1442 | { | 1507 | { |
| 1443 | int err; | 1508 | int err; |
| 1444 | 1509 | ||
| 1510 | err = nfs_dns_resolver_init(); | ||
| 1511 | if (err < 0) | ||
| 1512 | goto out8; | ||
| 1513 | |||
| 1445 | err = nfs_fscache_register(); | 1514 | err = nfs_fscache_register(); |
| 1446 | if (err < 0) | 1515 | if (err < 0) |
| 1447 | goto out7; | 1516 | goto out7; |
| @@ -1500,6 +1569,8 @@ out5: | |||
| 1500 | out6: | 1569 | out6: |
| 1501 | nfs_fscache_unregister(); | 1570 | nfs_fscache_unregister(); |
| 1502 | out7: | 1571 | out7: |
| 1572 | nfs_dns_resolver_destroy(); | ||
| 1573 | out8: | ||
| 1503 | return err; | 1574 | return err; |
| 1504 | } | 1575 | } |
| 1505 | 1576 | ||
| @@ -1511,6 +1582,7 @@ static void __exit exit_nfs_fs(void) | |||
| 1511 | nfs_destroy_inodecache(); | 1582 | nfs_destroy_inodecache(); |
| 1512 | nfs_destroy_nfspagecache(); | 1583 | nfs_destroy_nfspagecache(); |
| 1513 | nfs_fscache_unregister(); | 1584 | nfs_fscache_unregister(); |
| 1585 | nfs_dns_resolver_destroy(); | ||
| 1514 | #ifdef CONFIG_PROC_FS | 1586 | #ifdef CONFIG_PROC_FS |
| 1515 | rpc_proc_unregister("nfs"); | 1587 | rpc_proc_unregister("nfs"); |
| 1516 | #endif | 1588 | #endif |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 7dd90a6769d..e21b1bb9972 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -49,6 +49,11 @@ struct nfs_clone_mount { | |||
| 49 | #define NFS_MAX_SECFLAVORS (12) | 49 | #define NFS_MAX_SECFLAVORS (12) |
| 50 | 50 | ||
| 51 | /* | 51 | /* |
| 52 | * Value used if the user did not specify a port value. | ||
| 53 | */ | ||
| 54 | #define NFS_UNSPEC_PORT (-1) | ||
| 55 | |||
| 56 | /* | ||
| 52 | * In-kernel mount arguments | 57 | * In-kernel mount arguments |
| 53 | */ | 58 | */ |
| 54 | struct nfs_parsed_mount_data { | 59 | struct nfs_parsed_mount_data { |
| @@ -63,6 +68,7 @@ struct nfs_parsed_mount_data { | |||
| 63 | unsigned int auth_flavor_len; | 68 | unsigned int auth_flavor_len; |
| 64 | rpc_authflavor_t auth_flavors[1]; | 69 | rpc_authflavor_t auth_flavors[1]; |
| 65 | char *client_address; | 70 | char *client_address; |
| 71 | unsigned int version; | ||
| 66 | unsigned int minorversion; | 72 | unsigned int minorversion; |
| 67 | char *fscache_uniq; | 73 | char *fscache_uniq; |
| 68 | 74 | ||
| @@ -71,7 +77,7 @@ struct nfs_parsed_mount_data { | |||
| 71 | size_t addrlen; | 77 | size_t addrlen; |
| 72 | char *hostname; | 78 | char *hostname; |
| 73 | u32 version; | 79 | u32 version; |
| 74 | unsigned short port; | 80 | int port; |
| 75 | unsigned short protocol; | 81 | unsigned short protocol; |
| 76 | } mount_server; | 82 | } mount_server; |
| 77 | 83 | ||
| @@ -80,7 +86,7 @@ struct nfs_parsed_mount_data { | |||
| 80 | size_t addrlen; | 86 | size_t addrlen; |
| 81 | char *hostname; | 87 | char *hostname; |
| 82 | char *export_path; | 88 | char *export_path; |
| 83 | unsigned short port; | 89 | int port; |
| 84 | unsigned short protocol; | 90 | unsigned short protocol; |
| 85 | } nfs_server; | 91 | } nfs_server; |
| 86 | 92 | ||
| @@ -102,6 +108,7 @@ struct nfs_mount_request { | |||
| 102 | }; | 108 | }; |
| 103 | 109 | ||
| 104 | extern int nfs_mount(struct nfs_mount_request *info); | 110 | extern int nfs_mount(struct nfs_mount_request *info); |
| 111 | extern void nfs_umount(const struct nfs_mount_request *info); | ||
| 105 | 112 | ||
| 106 | /* client.c */ | 113 | /* client.c */ |
| 107 | extern struct rpc_program nfs_program; | 114 | extern struct rpc_program nfs_program; |
| @@ -213,7 +220,6 @@ void nfs_zap_acl_cache(struct inode *inode); | |||
| 213 | extern int nfs_wait_bit_killable(void *word); | 220 | extern int nfs_wait_bit_killable(void *word); |
| 214 | 221 | ||
| 215 | /* super.c */ | 222 | /* super.c */ |
| 216 | void nfs_parse_ip_address(char *, size_t, struct sockaddr *, size_t *); | ||
| 217 | extern struct file_system_type nfs_xdev_fs_type; | 223 | extern struct file_system_type nfs_xdev_fs_type; |
| 218 | #ifdef CONFIG_NFS_V4 | 224 | #ifdef CONFIG_NFS_V4 |
| 219 | extern struct file_system_type nfs4_xdev_fs_type; | 225 | extern struct file_system_type nfs4_xdev_fs_type; |
| @@ -248,6 +254,12 @@ extern void nfs_read_prepare(struct rpc_task *task, void *calldata); | |||
| 248 | 254 | ||
| 249 | /* write.c */ | 255 | /* write.c */ |
| 250 | extern void nfs_write_prepare(struct rpc_task *task, void *calldata); | 256 | extern void nfs_write_prepare(struct rpc_task *task, void *calldata); |
| 257 | #ifdef CONFIG_MIGRATION | ||
| 258 | extern int nfs_migrate_page(struct address_space *, | ||
| 259 | struct page *, struct page *); | ||
| 260 | #else | ||
| 261 | #define nfs_migrate_page NULL | ||
| 262 | #endif | ||
| 251 | 263 | ||
| 252 | /* nfs4proc.c */ | 264 | /* nfs4proc.c */ |
| 253 | extern int _nfs4_call_sync(struct nfs_server *server, | 265 | extern int _nfs4_call_sync(struct nfs_server *server, |
| @@ -368,24 +380,3 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len) | |||
| 368 | return ((unsigned long)len + (unsigned long)base + | 380 | return ((unsigned long)len + (unsigned long)base + |
| 369 | PAGE_SIZE - 1) >> PAGE_SHIFT; | 381 | PAGE_SIZE - 1) >> PAGE_SHIFT; |
| 370 | } | 382 | } |
| 371 | |||
| 372 | #define IPV6_SCOPE_DELIMITER '%' | ||
| 373 | |||
| 374 | /* | ||
| 375 | * Set the port number in an address. Be agnostic about the address | ||
| 376 | * family. | ||
| 377 | */ | ||
| 378 | static inline void nfs_set_port(struct sockaddr *sap, unsigned short port) | ||
| 379 | { | ||
| 380 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
| 381 | struct sockaddr_in6 *ap6 = (struct sockaddr_in6 *)sap; | ||
| 382 | |||
| 383 | switch (sap->sa_family) { | ||
| 384 | case AF_INET: | ||
| 385 | ap->sin_port = htons(port); | ||
| 386 | break; | ||
| 387 | case AF_INET6: | ||
| 388 | ap6->sin6_port = htons(port); | ||
| 389 | break; | ||
| 390 | } | ||
| 391 | } | ||
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 38ef9eaec40..0adefc40cc8 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
| @@ -209,6 +209,71 @@ out_mnt_err: | |||
| 209 | goto out; | 209 | goto out; |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | /** | ||
| 213 | * nfs_umount - Notify a server that we have unmounted this export | ||
| 214 | * @info: pointer to umount request arguments | ||
| 215 | * | ||
| 216 | * MOUNTPROC_UMNT is advisory, so we set a short timeout, and always | ||
| 217 | * use UDP. | ||
| 218 | */ | ||
| 219 | void nfs_umount(const struct nfs_mount_request *info) | ||
| 220 | { | ||
| 221 | static const struct rpc_timeout nfs_umnt_timeout = { | ||
| 222 | .to_initval = 1 * HZ, | ||
| 223 | .to_maxval = 3 * HZ, | ||
| 224 | .to_retries = 2, | ||
| 225 | }; | ||
| 226 | struct rpc_create_args args = { | ||
| 227 | .protocol = IPPROTO_UDP, | ||
| 228 | .address = info->sap, | ||
| 229 | .addrsize = info->salen, | ||
| 230 | .timeout = &nfs_umnt_timeout, | ||
| 231 | .servername = info->hostname, | ||
| 232 | .program = &mnt_program, | ||
| 233 | .version = info->version, | ||
| 234 | .authflavor = RPC_AUTH_UNIX, | ||
| 235 | .flags = RPC_CLNT_CREATE_NOPING, | ||
| 236 | }; | ||
| 237 | struct mountres result; | ||
| 238 | struct rpc_message msg = { | ||
| 239 | .rpc_argp = info->dirpath, | ||
| 240 | .rpc_resp = &result, | ||
| 241 | }; | ||
| 242 | struct rpc_clnt *clnt; | ||
| 243 | int status; | ||
| 244 | |||
| 245 | if (info->noresvport) | ||
| 246 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; | ||
| 247 | |||
| 248 | clnt = rpc_create(&args); | ||
| 249 | if (unlikely(IS_ERR(clnt))) | ||
| 250 | goto out_clnt_err; | ||
| 251 | |||
| 252 | dprintk("NFS: sending UMNT request for %s:%s\n", | ||
| 253 | (info->hostname ? info->hostname : "server"), info->dirpath); | ||
| 254 | |||
| 255 | if (info->version == NFS_MNT3_VERSION) | ||
| 256 | msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT]; | ||
| 257 | else | ||
| 258 | msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT]; | ||
| 259 | |||
| 260 | status = rpc_call_sync(clnt, &msg, 0); | ||
| 261 | rpc_shutdown_client(clnt); | ||
| 262 | |||
| 263 | if (unlikely(status < 0)) | ||
| 264 | goto out_call_err; | ||
| 265 | |||
| 266 | return; | ||
| 267 | |||
| 268 | out_clnt_err: | ||
| 269 | dprintk("NFS: failed to create UMNT RPC client, status=%ld\n", | ||
| 270 | PTR_ERR(clnt)); | ||
| 271 | return; | ||
| 272 | |||
| 273 | out_call_err: | ||
| 274 | dprintk("NFS: UMNT request failed, status=%d\n", status); | ||
| 275 | } | ||
| 276 | |||
| 212 | /* | 277 | /* |
| 213 | * XDR encode/decode functions for MOUNT | 278 | * XDR encode/decode functions for MOUNT |
| 214 | */ | 279 | */ |
| @@ -258,7 +323,7 @@ static int decode_status(struct xdr_stream *xdr, struct mountres *res) | |||
| 258 | return -EIO; | 323 | return -EIO; |
| 259 | status = ntohl(*p); | 324 | status = ntohl(*p); |
| 260 | 325 | ||
| 261 | for (i = 0; i <= ARRAY_SIZE(mnt_errtbl); i++) { | 326 | for (i = 0; i < ARRAY_SIZE(mnt_errtbl); i++) { |
| 262 | if (mnt_errtbl[i].status == status) { | 327 | if (mnt_errtbl[i].status == status) { |
| 263 | res->errno = mnt_errtbl[i].errno; | 328 | res->errno = mnt_errtbl[i].errno; |
| 264 | return 0; | 329 | return 0; |
| @@ -309,7 +374,7 @@ static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res) | |||
| 309 | return -EIO; | 374 | return -EIO; |
| 310 | status = ntohl(*p); | 375 | status = ntohl(*p); |
| 311 | 376 | ||
| 312 | for (i = 0; i <= ARRAY_SIZE(mnt3_errtbl); i++) { | 377 | for (i = 0; i < ARRAY_SIZE(mnt3_errtbl); i++) { |
| 313 | if (mnt3_errtbl[i].status == status) { | 378 | if (mnt3_errtbl[i].status == status) { |
| 314 | res->errno = mnt3_errtbl[i].errno; | 379 | res->errno = mnt3_errtbl[i].errno; |
| 315 | return 0; | 380 | return 0; |
| @@ -407,6 +472,13 @@ static struct rpc_procinfo mnt_procedures[] = { | |||
| 407 | .p_statidx = MOUNTPROC_MNT, | 472 | .p_statidx = MOUNTPROC_MNT, |
| 408 | .p_name = "MOUNT", | 473 | .p_name = "MOUNT", |
| 409 | }, | 474 | }, |
| 475 | [MOUNTPROC_UMNT] = { | ||
| 476 | .p_proc = MOUNTPROC_UMNT, | ||
| 477 | .p_encode = (kxdrproc_t)mnt_enc_dirpath, | ||
| 478 | .p_arglen = MNT_enc_dirpath_sz, | ||
| 479 | .p_statidx = MOUNTPROC_UMNT, | ||
| 480 | .p_name = "UMOUNT", | ||
| 481 | }, | ||
| 410 | }; | 482 | }; |
| 411 | 483 | ||
| 412 | static struct rpc_procinfo mnt3_procedures[] = { | 484 | static struct rpc_procinfo mnt3_procedures[] = { |
| @@ -419,6 +491,13 @@ static struct rpc_procinfo mnt3_procedures[] = { | |||
| 419 | .p_statidx = MOUNTPROC3_MNT, | 491 | .p_statidx = MOUNTPROC3_MNT, |
| 420 | .p_name = "MOUNT", | 492 | .p_name = "MOUNT", |
| 421 | }, | 493 | }, |
| 494 | [MOUNTPROC3_UMNT] = { | ||
| 495 | .p_proc = MOUNTPROC3_UMNT, | ||
| 496 | .p_encode = (kxdrproc_t)mnt_enc_dirpath, | ||
| 497 | .p_arglen = MNT_enc_dirpath_sz, | ||
| 498 | .p_statidx = MOUNTPROC3_UMNT, | ||
| 499 | .p_name = "UMOUNT", | ||
| 500 | }, | ||
| 422 | }; | 501 | }; |
| 423 | 502 | ||
| 424 | 503 | ||
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index d0cc5ce0edf..ee6a13f0544 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
| @@ -299,7 +299,6 @@ static void nfs3_free_createdata(struct nfs3_createdata *data) | |||
| 299 | 299 | ||
| 300 | /* | 300 | /* |
| 301 | * Create a regular file. | 301 | * Create a regular file. |
| 302 | * For now, we don't implement O_EXCL. | ||
| 303 | */ | 302 | */ |
| 304 | static int | 303 | static int |
| 305 | nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 304 | nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 2a2a0a7143a..2636c26d56f 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/inet.h> | 17 | #include <linux/inet.h> |
| 18 | #include "internal.h" | 18 | #include "internal.h" |
| 19 | #include "nfs4_fs.h" | 19 | #include "nfs4_fs.h" |
| 20 | #include "dns_resolve.h" | ||
| 20 | 21 | ||
| 21 | #define NFSDBG_FACILITY NFSDBG_VFS | 22 | #define NFSDBG_FACILITY NFSDBG_VFS |
| 22 | 23 | ||
| @@ -95,6 +96,20 @@ static int nfs4_validate_fspath(const struct vfsmount *mnt_parent, | |||
| 95 | return 0; | 96 | return 0; |
| 96 | } | 97 | } |
| 97 | 98 | ||
| 99 | static size_t nfs_parse_server_name(char *string, size_t len, | ||
| 100 | struct sockaddr *sa, size_t salen) | ||
| 101 | { | ||
| 102 | ssize_t ret; | ||
| 103 | |||
| 104 | ret = rpc_pton(string, len, sa, salen); | ||
| 105 | if (ret == 0) { | ||
| 106 | ret = nfs_dns_resolve_name(string, len, sa, salen); | ||
| 107 | if (ret < 0) | ||
| 108 | ret = 0; | ||
| 109 | } | ||
| 110 | return ret; | ||
| 111 | } | ||
| 112 | |||
| 98 | static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | 113 | static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, |
| 99 | char *page, char *page2, | 114 | char *page, char *page2, |
| 100 | const struct nfs4_fs_location *location) | 115 | const struct nfs4_fs_location *location) |
| @@ -121,11 +136,12 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
| 121 | 136 | ||
| 122 | if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) | 137 | if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) |
| 123 | continue; | 138 | continue; |
| 124 | nfs_parse_ip_address(buf->data, buf->len, | 139 | mountdata->addrlen = nfs_parse_server_name(buf->data, |
| 125 | mountdata->addr, &mountdata->addrlen); | 140 | buf->len, |
| 126 | if (mountdata->addr->sa_family == AF_UNSPEC) | 141 | mountdata->addr, mountdata->addrlen); |
| 142 | if (mountdata->addrlen == 0) | ||
| 127 | continue; | 143 | continue; |
| 128 | nfs_set_port(mountdata->addr, NFS_PORT); | 144 | rpc_set_port(mountdata->addr, NFS_PORT); |
| 129 | 145 | ||
| 130 | memcpy(page2, buf->data, buf->len); | 146 | memcpy(page2, buf->data, buf->len); |
| 131 | page2[buf->len] = '\0'; | 147 | page2[buf->len] = '\0'; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6917311f201..be6544aef41 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -61,6 +61,8 @@ | |||
| 61 | #define NFS4_POLL_RETRY_MIN (HZ/10) | 61 | #define NFS4_POLL_RETRY_MIN (HZ/10) |
| 62 | #define NFS4_POLL_RETRY_MAX (15*HZ) | 62 | #define NFS4_POLL_RETRY_MAX (15*HZ) |
| 63 | 63 | ||
| 64 | #define NFS4_MAX_LOOP_ON_RECOVER (10) | ||
| 65 | |||
| 64 | struct nfs4_opendata; | 66 | struct nfs4_opendata; |
| 65 | static int _nfs4_proc_open(struct nfs4_opendata *data); | 67 | static int _nfs4_proc_open(struct nfs4_opendata *data); |
| 66 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 68 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
| @@ -426,17 +428,19 @@ out: | |||
| 426 | static int nfs4_recover_session(struct nfs4_session *session) | 428 | static int nfs4_recover_session(struct nfs4_session *session) |
| 427 | { | 429 | { |
| 428 | struct nfs_client *clp = session->clp; | 430 | struct nfs_client *clp = session->clp; |
| 431 | unsigned int loop; | ||
| 429 | int ret; | 432 | int ret; |
| 430 | 433 | ||
| 431 | for (;;) { | 434 | for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) { |
| 432 | ret = nfs4_wait_clnt_recover(clp); | 435 | ret = nfs4_wait_clnt_recover(clp); |
| 433 | if (ret != 0) | 436 | if (ret != 0) |
| 434 | return ret; | 437 | break; |
| 435 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | 438 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) |
| 436 | break; | 439 | break; |
| 437 | nfs4_schedule_state_manager(clp); | 440 | nfs4_schedule_state_manager(clp); |
| 441 | ret = -EIO; | ||
| 438 | } | 442 | } |
| 439 | return 0; | 443 | return ret; |
| 440 | } | 444 | } |
| 441 | 445 | ||
| 442 | static int nfs41_setup_sequence(struct nfs4_session *session, | 446 | static int nfs41_setup_sequence(struct nfs4_session *session, |
| @@ -1444,18 +1448,20 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
| 1444 | static int nfs4_recover_expired_lease(struct nfs_server *server) | 1448 | static int nfs4_recover_expired_lease(struct nfs_server *server) |
| 1445 | { | 1449 | { |
| 1446 | struct nfs_client *clp = server->nfs_client; | 1450 | struct nfs_client *clp = server->nfs_client; |
| 1451 | unsigned int loop; | ||
| 1447 | int ret; | 1452 | int ret; |
| 1448 | 1453 | ||
| 1449 | for (;;) { | 1454 | for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) { |
| 1450 | ret = nfs4_wait_clnt_recover(clp); | 1455 | ret = nfs4_wait_clnt_recover(clp); |
| 1451 | if (ret != 0) | 1456 | if (ret != 0) |
| 1452 | return ret; | 1457 | break; |
| 1453 | if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) && | 1458 | if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) && |
| 1454 | !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state)) | 1459 | !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state)) |
| 1455 | break; | 1460 | break; |
| 1456 | nfs4_schedule_state_recovery(clp); | 1461 | nfs4_schedule_state_recovery(clp); |
| 1462 | ret = -EIO; | ||
| 1457 | } | 1463 | } |
| 1458 | return 0; | 1464 | return ret; |
| 1459 | } | 1465 | } |
| 1460 | 1466 | ||
| 1461 | /* | 1467 | /* |
| @@ -1997,12 +2003,34 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
| 1997 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 2003 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
| 1998 | if (status == 0) { | 2004 | if (status == 0) { |
| 1999 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); | 2005 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); |
| 2006 | server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS| | ||
| 2007 | NFS_CAP_SYMLINKS|NFS_CAP_FILEID| | ||
| 2008 | NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER| | ||
| 2009 | NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME| | ||
| 2010 | NFS_CAP_CTIME|NFS_CAP_MTIME); | ||
| 2000 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) | 2011 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) |
| 2001 | server->caps |= NFS_CAP_ACLS; | 2012 | server->caps |= NFS_CAP_ACLS; |
| 2002 | if (res.has_links != 0) | 2013 | if (res.has_links != 0) |
| 2003 | server->caps |= NFS_CAP_HARDLINKS; | 2014 | server->caps |= NFS_CAP_HARDLINKS; |
| 2004 | if (res.has_symlinks != 0) | 2015 | if (res.has_symlinks != 0) |
| 2005 | server->caps |= NFS_CAP_SYMLINKS; | 2016 | server->caps |= NFS_CAP_SYMLINKS; |
| 2017 | if (res.attr_bitmask[0] & FATTR4_WORD0_FILEID) | ||
| 2018 | server->caps |= NFS_CAP_FILEID; | ||
| 2019 | if (res.attr_bitmask[1] & FATTR4_WORD1_MODE) | ||
| 2020 | server->caps |= NFS_CAP_MODE; | ||
| 2021 | if (res.attr_bitmask[1] & FATTR4_WORD1_NUMLINKS) | ||
| 2022 | server->caps |= NFS_CAP_NLINK; | ||
| 2023 | if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER) | ||
| 2024 | server->caps |= NFS_CAP_OWNER; | ||
| 2025 | if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER_GROUP) | ||
| 2026 | server->caps |= NFS_CAP_OWNER_GROUP; | ||
| 2027 | if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_ACCESS) | ||
| 2028 | server->caps |= NFS_CAP_ATIME; | ||
| 2029 | if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_METADATA) | ||
| 2030 | server->caps |= NFS_CAP_CTIME; | ||
| 2031 | if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY) | ||
| 2032 | server->caps |= NFS_CAP_MTIME; | ||
| 2033 | |||
| 2006 | memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask)); | 2034 | memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask)); |
| 2007 | server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; | 2035 | server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; |
| 2008 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 2036 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 617273e7d47..cfc30d362f9 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -702,29 +702,12 @@ struct compound_hdr { | |||
| 702 | u32 minorversion; | 702 | u32 minorversion; |
| 703 | }; | 703 | }; |
| 704 | 704 | ||
| 705 | /* | 705 | static __be32 *reserve_space(struct xdr_stream *xdr, size_t nbytes) |
| 706 | * START OF "GENERIC" ENCODE ROUTINES. | 706 | { |
| 707 | * These may look a little ugly since they are imported from a "generic" | 707 | __be32 *p = xdr_reserve_space(xdr, nbytes); |
| 708 | * set of XDR encode/decode routines which are intended to be shared by | 708 | BUG_ON(!p); |
| 709 | * all of our NFSv4 implementations (OpenBSD, MacOS X...). | 709 | return p; |
| 710 | * | 710 | } |
| 711 | * If the pain of reading these is too great, it should be a straightforward | ||
| 712 | * task to translate them into Linux-specific versions which are more | ||
| 713 | * consistent with the style used in NFSv2/v3... | ||
| 714 | */ | ||
| 715 | #define WRITE32(n) *p++ = htonl(n) | ||
| 716 | #define WRITE64(n) do { \ | ||
| 717 | *p++ = htonl((uint32_t)((n) >> 32)); \ | ||
| 718 | *p++ = htonl((uint32_t)(n)); \ | ||
| 719 | } while (0) | ||
| 720 | #define WRITEMEM(ptr,nbytes) do { \ | ||
| 721 | p = xdr_encode_opaque_fixed(p, ptr, nbytes); \ | ||
| 722 | } while (0) | ||
| 723 | |||
| 724 | #define RESERVE_SPACE(nbytes) do { \ | ||
| 725 | p = xdr_reserve_space(xdr, nbytes); \ | ||
| 726 | BUG_ON(!p); \ | ||
| 727 | } while (0) | ||
| 728 | 711 | ||
| 729 | static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) | 712 | static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) |
| 730 | { | 713 | { |
| @@ -749,12 +732,11 @@ static void encode_compound_hdr(struct xdr_stream *xdr, | |||
| 749 | 732 | ||
| 750 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); | 733 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); |
| 751 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); | 734 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); |
| 752 | RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); | 735 | p = reserve_space(xdr, 4 + hdr->taglen + 8); |
| 753 | WRITE32(hdr->taglen); | 736 | p = xdr_encode_opaque(p, hdr->tag, hdr->taglen); |
| 754 | WRITEMEM(hdr->tag, hdr->taglen); | 737 | *p++ = cpu_to_be32(hdr->minorversion); |
| 755 | WRITE32(hdr->minorversion); | ||
| 756 | hdr->nops_p = p; | 738 | hdr->nops_p = p; |
| 757 | WRITE32(hdr->nops); | 739 | *p = cpu_to_be32(hdr->nops); |
| 758 | } | 740 | } |
| 759 | 741 | ||
| 760 | static void encode_nops(struct compound_hdr *hdr) | 742 | static void encode_nops(struct compound_hdr *hdr) |
| @@ -829,55 +811,53 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
| 829 | len += 16; | 811 | len += 16; |
| 830 | else if (iap->ia_valid & ATTR_MTIME) | 812 | else if (iap->ia_valid & ATTR_MTIME) |
| 831 | len += 4; | 813 | len += 4; |
| 832 | RESERVE_SPACE(len); | 814 | p = reserve_space(xdr, len); |
| 833 | 815 | ||
| 834 | /* | 816 | /* |
| 835 | * We write the bitmap length now, but leave the bitmap and the attribute | 817 | * We write the bitmap length now, but leave the bitmap and the attribute |
| 836 | * buffer length to be backfilled at the end of this routine. | 818 | * buffer length to be backfilled at the end of this routine. |
| 837 | */ | 819 | */ |
| 838 | WRITE32(2); | 820 | *p++ = cpu_to_be32(2); |
| 839 | q = p; | 821 | q = p; |
| 840 | p += 3; | 822 | p += 3; |
| 841 | 823 | ||
| 842 | if (iap->ia_valid & ATTR_SIZE) { | 824 | if (iap->ia_valid & ATTR_SIZE) { |
| 843 | bmval0 |= FATTR4_WORD0_SIZE; | 825 | bmval0 |= FATTR4_WORD0_SIZE; |
| 844 | WRITE64(iap->ia_size); | 826 | p = xdr_encode_hyper(p, iap->ia_size); |
| 845 | } | 827 | } |
| 846 | if (iap->ia_valid & ATTR_MODE) { | 828 | if (iap->ia_valid & ATTR_MODE) { |
| 847 | bmval1 |= FATTR4_WORD1_MODE; | 829 | bmval1 |= FATTR4_WORD1_MODE; |
| 848 | WRITE32(iap->ia_mode & S_IALLUGO); | 830 | *p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO); |
| 849 | } | 831 | } |
| 850 | if (iap->ia_valid & ATTR_UID) { | 832 | if (iap->ia_valid & ATTR_UID) { |
| 851 | bmval1 |= FATTR4_WORD1_OWNER; | 833 | bmval1 |= FATTR4_WORD1_OWNER; |
| 852 | WRITE32(owner_namelen); | 834 | p = xdr_encode_opaque(p, owner_name, owner_namelen); |
| 853 | WRITEMEM(owner_name, owner_namelen); | ||
| 854 | } | 835 | } |
| 855 | if (iap->ia_valid & ATTR_GID) { | 836 | if (iap->ia_valid & ATTR_GID) { |
| 856 | bmval1 |= FATTR4_WORD1_OWNER_GROUP; | 837 | bmval1 |= FATTR4_WORD1_OWNER_GROUP; |
| 857 | WRITE32(owner_grouplen); | 838 | p = xdr_encode_opaque(p, owner_group, owner_grouplen); |
| 858 | WRITEMEM(owner_group, owner_grouplen); | ||
| 859 | } | 839 | } |
| 860 | if (iap->ia_valid & ATTR_ATIME_SET) { | 840 | if (iap->ia_valid & ATTR_ATIME_SET) { |
| 861 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; | 841 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; |
| 862 | WRITE32(NFS4_SET_TO_CLIENT_TIME); | 842 | *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME); |
| 863 | WRITE32(0); | 843 | *p++ = cpu_to_be32(0); |
| 864 | WRITE32(iap->ia_mtime.tv_sec); | 844 | *p++ = cpu_to_be32(iap->ia_mtime.tv_sec); |
| 865 | WRITE32(iap->ia_mtime.tv_nsec); | 845 | *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec); |
| 866 | } | 846 | } |
| 867 | else if (iap->ia_valid & ATTR_ATIME) { | 847 | else if (iap->ia_valid & ATTR_ATIME) { |
| 868 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; | 848 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; |
| 869 | WRITE32(NFS4_SET_TO_SERVER_TIME); | 849 | *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME); |
| 870 | } | 850 | } |
| 871 | if (iap->ia_valid & ATTR_MTIME_SET) { | 851 | if (iap->ia_valid & ATTR_MTIME_SET) { |
| 872 | bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; | 852 | bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; |
| 873 | WRITE32(NFS4_SET_TO_CLIENT_TIME); | 853 | *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME); |
| 874 | WRITE32(0); | 854 | *p++ = cpu_to_be32(0); |
| 875 | WRITE32(iap->ia_mtime.tv_sec); | 855 | *p++ = cpu_to_be32(iap->ia_mtime.tv_sec); |
| 876 | WRITE32(iap->ia_mtime.tv_nsec); | 856 | *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec); |
| 877 | } | 857 | } |
| 878 | else if (iap->ia_valid & ATTR_MTIME) { | 858 | else if (iap->ia_valid & ATTR_MTIME) { |
| 879 | bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; | 859 | bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; |
| 880 | WRITE32(NFS4_SET_TO_SERVER_TIME); | 860 | *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME); |
| 881 | } | 861 | } |
| 882 | 862 | ||
| 883 | /* | 863 | /* |
| @@ -891,7 +871,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
| 891 | len = (char *)p - (char *)q - 12; | 871 | len = (char *)p - (char *)q - 12; |
| 892 | *q++ = htonl(bmval0); | 872 | *q++ = htonl(bmval0); |
| 893 | *q++ = htonl(bmval1); | 873 | *q++ = htonl(bmval1); |
| 894 | *q++ = htonl(len); | 874 | *q = htonl(len); |
| 895 | 875 | ||
| 896 | /* out: */ | 876 | /* out: */ |
| 897 | } | 877 | } |
| @@ -900,9 +880,9 @@ static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hd | |||
| 900 | { | 880 | { |
| 901 | __be32 *p; | 881 | __be32 *p; |
| 902 | 882 | ||
| 903 | RESERVE_SPACE(8); | 883 | p = reserve_space(xdr, 8); |
| 904 | WRITE32(OP_ACCESS); | 884 | *p++ = cpu_to_be32(OP_ACCESS); |
| 905 | WRITE32(access); | 885 | *p = cpu_to_be32(access); |
| 906 | hdr->nops++; | 886 | hdr->nops++; |
| 907 | hdr->replen += decode_access_maxsz; | 887 | hdr->replen += decode_access_maxsz; |
| 908 | } | 888 | } |
| @@ -911,10 +891,10 @@ static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg | |||
| 911 | { | 891 | { |
| 912 | __be32 *p; | 892 | __be32 *p; |
| 913 | 893 | ||
| 914 | RESERVE_SPACE(8+NFS4_STATEID_SIZE); | 894 | p = reserve_space(xdr, 8+NFS4_STATEID_SIZE); |
| 915 | WRITE32(OP_CLOSE); | 895 | *p++ = cpu_to_be32(OP_CLOSE); |
| 916 | WRITE32(arg->seqid->sequence->counter); | 896 | *p++ = cpu_to_be32(arg->seqid->sequence->counter); |
| 917 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 897 | xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); |
| 918 | hdr->nops++; | 898 | hdr->nops++; |
| 919 | hdr->replen += decode_close_maxsz; | 899 | hdr->replen += decode_close_maxsz; |
| 920 | } | 900 | } |
| @@ -923,10 +903,10 @@ static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *ar | |||
| 923 | { | 903 | { |
| 924 | __be32 *p; | 904 | __be32 *p; |
| 925 | 905 | ||
| 926 | RESERVE_SPACE(16); | 906 | p = reserve_space(xdr, 16); |
| 927 | WRITE32(OP_COMMIT); | 907 | *p++ = cpu_to_be32(OP_COMMIT); |
| 928 | WRITE64(args->offset); | 908 | p = xdr_encode_hyper(p, args->offset); |
| 929 | WRITE32(args->count); | 909 | *p = cpu_to_be32(args->count); |
| 930 | hdr->nops++; | 910 | hdr->nops++; |
| 931 | hdr->replen += decode_commit_maxsz; | 911 | hdr->replen += decode_commit_maxsz; |
| 932 | } | 912 | } |
| @@ -935,30 +915,28 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * | |||
| 935 | { | 915 | { |
| 936 | __be32 *p; | 916 | __be32 *p; |
| 937 | 917 | ||
| 938 | RESERVE_SPACE(8); | 918 | p = reserve_space(xdr, 8); |
| 939 | WRITE32(OP_CREATE); | 919 | *p++ = cpu_to_be32(OP_CREATE); |
| 940 | WRITE32(create->ftype); | 920 | *p = cpu_to_be32(create->ftype); |
| 941 | 921 | ||
| 942 | switch (create->ftype) { | 922 | switch (create->ftype) { |
| 943 | case NF4LNK: | 923 | case NF4LNK: |
| 944 | RESERVE_SPACE(4); | 924 | p = reserve_space(xdr, 4); |
| 945 | WRITE32(create->u.symlink.len); | 925 | *p = cpu_to_be32(create->u.symlink.len); |
| 946 | xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len); | 926 | xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len); |
| 947 | break; | 927 | break; |
| 948 | 928 | ||
| 949 | case NF4BLK: case NF4CHR: | 929 | case NF4BLK: case NF4CHR: |
| 950 | RESERVE_SPACE(8); | 930 | p = reserve_space(xdr, 8); |
| 951 | WRITE32(create->u.device.specdata1); | 931 | *p++ = cpu_to_be32(create->u.device.specdata1); |
| 952 | WRITE32(create->u.device.specdata2); | 932 | *p = cpu_to_be32(create->u.device.specdata2); |
| 953 | break; | 933 | break; |
| 954 | 934 | ||
| 955 | default: | 935 | default: |
| 956 | break; | 936 | break; |
| 957 | } | 937 | } |
| 958 | 938 | ||
| 959 | RESERVE_SPACE(4 + create->name->len); | 939 | encode_string(xdr, create->name->len, create->name->name); |
| 960 | WRITE32(create->name->len); | ||
| 961 | WRITEMEM(create->name->name, create->name->len); | ||
| 962 | hdr->nops++; | 940 | hdr->nops++; |
| 963 | hdr->replen += decode_create_maxsz; | 941 | hdr->replen += decode_create_maxsz; |
| 964 | 942 | ||
| @@ -969,10 +947,10 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c | |||
| 969 | { | 947 | { |
| 970 | __be32 *p; | 948 | __be32 *p; |
| 971 | 949 | ||
| 972 | RESERVE_SPACE(12); | 950 | p = reserve_space(xdr, 12); |
| 973 | WRITE32(OP_GETATTR); | 951 | *p++ = cpu_to_be32(OP_GETATTR); |
| 974 | WRITE32(1); | 952 | *p++ = cpu_to_be32(1); |
| 975 | WRITE32(bitmap); | 953 | *p = cpu_to_be32(bitmap); |
| 976 | hdr->nops++; | 954 | hdr->nops++; |
| 977 | hdr->replen += decode_getattr_maxsz; | 955 | hdr->replen += decode_getattr_maxsz; |
| 978 | } | 956 | } |
| @@ -981,11 +959,11 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm | |||
| 981 | { | 959 | { |
| 982 | __be32 *p; | 960 | __be32 *p; |
| 983 | 961 | ||
| 984 | RESERVE_SPACE(16); | 962 | p = reserve_space(xdr, 16); |
| 985 | WRITE32(OP_GETATTR); | 963 | *p++ = cpu_to_be32(OP_GETATTR); |
| 986 | WRITE32(2); | 964 | *p++ = cpu_to_be32(2); |
| 987 | WRITE32(bm0); | 965 | *p++ = cpu_to_be32(bm0); |
| 988 | WRITE32(bm1); | 966 | *p = cpu_to_be32(bm1); |
| 989 | hdr->nops++; | 967 | hdr->nops++; |
| 990 | hdr->replen += decode_getattr_maxsz; | 968 | hdr->replen += decode_getattr_maxsz; |
| 991 | } | 969 | } |
| @@ -1012,8 +990,8 @@ static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
| 1012 | { | 990 | { |
| 1013 | __be32 *p; | 991 | __be32 *p; |
| 1014 | 992 | ||
| 1015 | RESERVE_SPACE(4); | 993 | p = reserve_space(xdr, 4); |
| 1016 | WRITE32(OP_GETFH); | 994 | *p = cpu_to_be32(OP_GETFH); |
| 1017 | hdr->nops++; | 995 | hdr->nops++; |
| 1018 | hdr->replen += decode_getfh_maxsz; | 996 | hdr->replen += decode_getfh_maxsz; |
| 1019 | } | 997 | } |
| @@ -1022,10 +1000,9 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct | |||
| 1022 | { | 1000 | { |
| 1023 | __be32 *p; | 1001 | __be32 *p; |
| 1024 | 1002 | ||
| 1025 | RESERVE_SPACE(8 + name->len); | 1003 | p = reserve_space(xdr, 8 + name->len); |
| 1026 | WRITE32(OP_LINK); | 1004 | *p++ = cpu_to_be32(OP_LINK); |
| 1027 | WRITE32(name->len); | 1005 | xdr_encode_opaque(p, name->name, name->len); |
| 1028 | WRITEMEM(name->name, name->len); | ||
| 1029 | hdr->nops++; | 1006 | hdr->nops++; |
| 1030 | hdr->replen += decode_link_maxsz; | 1007 | hdr->replen += decode_link_maxsz; |
| 1031 | } | 1008 | } |
| @@ -1052,27 +1029,27 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args | |||
| 1052 | { | 1029 | { |
| 1053 | __be32 *p; | 1030 | __be32 *p; |
| 1054 | 1031 | ||
| 1055 | RESERVE_SPACE(32); | 1032 | p = reserve_space(xdr, 32); |
| 1056 | WRITE32(OP_LOCK); | 1033 | *p++ = cpu_to_be32(OP_LOCK); |
| 1057 | WRITE32(nfs4_lock_type(args->fl, args->block)); | 1034 | *p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block)); |
| 1058 | WRITE32(args->reclaim); | 1035 | *p++ = cpu_to_be32(args->reclaim); |
| 1059 | WRITE64(args->fl->fl_start); | 1036 | p = xdr_encode_hyper(p, args->fl->fl_start); |
| 1060 | WRITE64(nfs4_lock_length(args->fl)); | 1037 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); |
| 1061 | WRITE32(args->new_lock_owner); | 1038 | *p = cpu_to_be32(args->new_lock_owner); |
| 1062 | if (args->new_lock_owner){ | 1039 | if (args->new_lock_owner){ |
| 1063 | RESERVE_SPACE(4+NFS4_STATEID_SIZE+32); | 1040 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+32); |
| 1064 | WRITE32(args->open_seqid->sequence->counter); | 1041 | *p++ = cpu_to_be32(args->open_seqid->sequence->counter); |
| 1065 | WRITEMEM(args->open_stateid->data, NFS4_STATEID_SIZE); | 1042 | p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE); |
| 1066 | WRITE32(args->lock_seqid->sequence->counter); | 1043 | *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); |
| 1067 | WRITE64(args->lock_owner.clientid); | 1044 | p = xdr_encode_hyper(p, args->lock_owner.clientid); |
| 1068 | WRITE32(16); | 1045 | *p++ = cpu_to_be32(16); |
| 1069 | WRITEMEM("lock id:", 8); | 1046 | p = xdr_encode_opaque_fixed(p, "lock id:", 8); |
| 1070 | WRITE64(args->lock_owner.id); | 1047 | xdr_encode_hyper(p, args->lock_owner.id); |
| 1071 | } | 1048 | } |
| 1072 | else { | 1049 | else { |
| 1073 | RESERVE_SPACE(NFS4_STATEID_SIZE+4); | 1050 | p = reserve_space(xdr, NFS4_STATEID_SIZE+4); |
| 1074 | WRITEMEM(args->lock_stateid->data, NFS4_STATEID_SIZE); | 1051 | p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE); |
| 1075 | WRITE32(args->lock_seqid->sequence->counter); | 1052 | *p = cpu_to_be32(args->lock_seqid->sequence->counter); |
| 1076 | } | 1053 | } |
| 1077 | hdr->nops++; | 1054 | hdr->nops++; |
| 1078 | hdr->replen += decode_lock_maxsz; | 1055 | hdr->replen += decode_lock_maxsz; |
| @@ -1082,15 +1059,15 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar | |||
| 1082 | { | 1059 | { |
| 1083 | __be32 *p; | 1060 | __be32 *p; |
| 1084 | 1061 | ||
| 1085 | RESERVE_SPACE(52); | 1062 | p = reserve_space(xdr, 52); |
| 1086 | WRITE32(OP_LOCKT); | 1063 | *p++ = cpu_to_be32(OP_LOCKT); |
| 1087 | WRITE32(nfs4_lock_type(args->fl, 0)); | 1064 | *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); |
| 1088 | WRITE64(args->fl->fl_start); | 1065 | p = xdr_encode_hyper(p, args->fl->fl_start); |
| 1089 | WRITE64(nfs4_lock_length(args->fl)); | 1066 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); |
| 1090 | WRITE64(args->lock_owner.clientid); | 1067 | p = xdr_encode_hyper(p, args->lock_owner.clientid); |
| 1091 | WRITE32(16); | 1068 | *p++ = cpu_to_be32(16); |
| 1092 | WRITEMEM("lock id:", 8); | 1069 | p = xdr_encode_opaque_fixed(p, "lock id:", 8); |
| 1093 | WRITE64(args->lock_owner.id); | 1070 | xdr_encode_hyper(p, args->lock_owner.id); |
| 1094 | hdr->nops++; | 1071 | hdr->nops++; |
| 1095 | hdr->replen += decode_lockt_maxsz; | 1072 | hdr->replen += decode_lockt_maxsz; |
| 1096 | } | 1073 | } |
| @@ -1099,13 +1076,13 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar | |||
| 1099 | { | 1076 | { |
| 1100 | __be32 *p; | 1077 | __be32 *p; |
| 1101 | 1078 | ||
| 1102 | RESERVE_SPACE(12+NFS4_STATEID_SIZE+16); | 1079 | p = reserve_space(xdr, 12+NFS4_STATEID_SIZE+16); |
| 1103 | WRITE32(OP_LOCKU); | 1080 | *p++ = cpu_to_be32(OP_LOCKU); |
| 1104 | WRITE32(nfs4_lock_type(args->fl, 0)); | 1081 | *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); |
| 1105 | WRITE32(args->seqid->sequence->counter); | 1082 | *p++ = cpu_to_be32(args->seqid->sequence->counter); |
| 1106 | WRITEMEM(args->stateid->data, NFS4_STATEID_SIZE); | 1083 | p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE); |
| 1107 | WRITE64(args->fl->fl_start); | 1084 | p = xdr_encode_hyper(p, args->fl->fl_start); |
| 1108 | WRITE64(nfs4_lock_length(args->fl)); | 1085 | xdr_encode_hyper(p, nfs4_lock_length(args->fl)); |
| 1109 | hdr->nops++; | 1086 | hdr->nops++; |
| 1110 | hdr->replen += decode_locku_maxsz; | 1087 | hdr->replen += decode_locku_maxsz; |
| 1111 | } | 1088 | } |
| @@ -1115,10 +1092,9 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc | |||
| 1115 | int len = name->len; | 1092 | int len = name->len; |
| 1116 | __be32 *p; | 1093 | __be32 *p; |
| 1117 | 1094 | ||
| 1118 | RESERVE_SPACE(8 + len); | 1095 | p = reserve_space(xdr, 8 + len); |
| 1119 | WRITE32(OP_LOOKUP); | 1096 | *p++ = cpu_to_be32(OP_LOOKUP); |
| 1120 | WRITE32(len); | 1097 | xdr_encode_opaque(p, name->name, len); |
| 1121 | WRITEMEM(name->name, len); | ||
| 1122 | hdr->nops++; | 1098 | hdr->nops++; |
| 1123 | hdr->replen += decode_lookup_maxsz; | 1099 | hdr->replen += decode_lookup_maxsz; |
| 1124 | } | 1100 | } |
| @@ -1127,21 +1103,21 @@ static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) | |||
| 1127 | { | 1103 | { |
| 1128 | __be32 *p; | 1104 | __be32 *p; |
| 1129 | 1105 | ||
| 1130 | RESERVE_SPACE(8); | 1106 | p = reserve_space(xdr, 8); |
| 1131 | switch (fmode & (FMODE_READ|FMODE_WRITE)) { | 1107 | switch (fmode & (FMODE_READ|FMODE_WRITE)) { |
| 1132 | case FMODE_READ: | 1108 | case FMODE_READ: |
| 1133 | WRITE32(NFS4_SHARE_ACCESS_READ); | 1109 | *p++ = cpu_to_be32(NFS4_SHARE_ACCESS_READ); |
| 1134 | break; | 1110 | break; |
| 1135 | case FMODE_WRITE: | 1111 | case FMODE_WRITE: |
| 1136 | WRITE32(NFS4_SHARE_ACCESS_WRITE); | 1112 | *p++ = cpu_to_be32(NFS4_SHARE_ACCESS_WRITE); |
| 1137 | break; | 1113 | break; |
| 1138 | case FMODE_READ|FMODE_WRITE: | 1114 | case FMODE_READ|FMODE_WRITE: |
| 1139 | WRITE32(NFS4_SHARE_ACCESS_BOTH); | 1115 | *p++ = cpu_to_be32(NFS4_SHARE_ACCESS_BOTH); |
| 1140 | break; | 1116 | break; |
| 1141 | default: | 1117 | default: |
| 1142 | WRITE32(0); | 1118 | *p++ = cpu_to_be32(0); |
| 1143 | } | 1119 | } |
| 1144 | WRITE32(0); /* for linux, share_deny = 0 always */ | 1120 | *p = cpu_to_be32(0); /* for linux, share_deny = 0 always */ |
| 1145 | } | 1121 | } |
| 1146 | 1122 | ||
| 1147 | static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg) | 1123 | static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg) |
| @@ -1151,29 +1127,29 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena | |||
| 1151 | * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4, | 1127 | * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4, |
| 1152 | * owner 4 = 32 | 1128 | * owner 4 = 32 |
| 1153 | */ | 1129 | */ |
| 1154 | RESERVE_SPACE(8); | 1130 | p = reserve_space(xdr, 8); |
| 1155 | WRITE32(OP_OPEN); | 1131 | *p++ = cpu_to_be32(OP_OPEN); |
| 1156 | WRITE32(arg->seqid->sequence->counter); | 1132 | *p = cpu_to_be32(arg->seqid->sequence->counter); |
| 1157 | encode_share_access(xdr, arg->fmode); | 1133 | encode_share_access(xdr, arg->fmode); |
| 1158 | RESERVE_SPACE(28); | 1134 | p = reserve_space(xdr, 28); |
| 1159 | WRITE64(arg->clientid); | 1135 | p = xdr_encode_hyper(p, arg->clientid); |
| 1160 | WRITE32(16); | 1136 | *p++ = cpu_to_be32(16); |
| 1161 | WRITEMEM("open id:", 8); | 1137 | p = xdr_encode_opaque_fixed(p, "open id:", 8); |
| 1162 | WRITE64(arg->id); | 1138 | xdr_encode_hyper(p, arg->id); |
| 1163 | } | 1139 | } |
| 1164 | 1140 | ||
| 1165 | static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) | 1141 | static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) |
| 1166 | { | 1142 | { |
| 1167 | __be32 *p; | 1143 | __be32 *p; |
| 1168 | 1144 | ||
| 1169 | RESERVE_SPACE(4); | 1145 | p = reserve_space(xdr, 4); |
| 1170 | switch(arg->open_flags & O_EXCL) { | 1146 | switch(arg->open_flags & O_EXCL) { |
| 1171 | case 0: | 1147 | case 0: |
| 1172 | WRITE32(NFS4_CREATE_UNCHECKED); | 1148 | *p = cpu_to_be32(NFS4_CREATE_UNCHECKED); |
| 1173 | encode_attrs(xdr, arg->u.attrs, arg->server); | 1149 | encode_attrs(xdr, arg->u.attrs, arg->server); |
| 1174 | break; | 1150 | break; |
| 1175 | default: | 1151 | default: |
| 1176 | WRITE32(NFS4_CREATE_EXCLUSIVE); | 1152 | *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); |
| 1177 | encode_nfs4_verifier(xdr, &arg->u.verifier); | 1153 | encode_nfs4_verifier(xdr, &arg->u.verifier); |
| 1178 | } | 1154 | } |
| 1179 | } | 1155 | } |
| @@ -1182,14 +1158,14 @@ static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *a | |||
| 1182 | { | 1158 | { |
| 1183 | __be32 *p; | 1159 | __be32 *p; |
| 1184 | 1160 | ||
| 1185 | RESERVE_SPACE(4); | 1161 | p = reserve_space(xdr, 4); |
| 1186 | switch (arg->open_flags & O_CREAT) { | 1162 | switch (arg->open_flags & O_CREAT) { |
| 1187 | case 0: | 1163 | case 0: |
| 1188 | WRITE32(NFS4_OPEN_NOCREATE); | 1164 | *p = cpu_to_be32(NFS4_OPEN_NOCREATE); |
| 1189 | break; | 1165 | break; |
| 1190 | default: | 1166 | default: |
| 1191 | BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL); | 1167 | BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL); |
| 1192 | WRITE32(NFS4_OPEN_CREATE); | 1168 | *p = cpu_to_be32(NFS4_OPEN_CREATE); |
| 1193 | encode_createmode(xdr, arg); | 1169 | encode_createmode(xdr, arg); |
| 1194 | } | 1170 | } |
| 1195 | } | 1171 | } |
| @@ -1198,16 +1174,16 @@ static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delega | |||
| 1198 | { | 1174 | { |
| 1199 | __be32 *p; | 1175 | __be32 *p; |
| 1200 | 1176 | ||
| 1201 | RESERVE_SPACE(4); | 1177 | p = reserve_space(xdr, 4); |
| 1202 | switch (delegation_type) { | 1178 | switch (delegation_type) { |
| 1203 | case 0: | 1179 | case 0: |
| 1204 | WRITE32(NFS4_OPEN_DELEGATE_NONE); | 1180 | *p = cpu_to_be32(NFS4_OPEN_DELEGATE_NONE); |
| 1205 | break; | 1181 | break; |
| 1206 | case FMODE_READ: | 1182 | case FMODE_READ: |
| 1207 | WRITE32(NFS4_OPEN_DELEGATE_READ); | 1183 | *p = cpu_to_be32(NFS4_OPEN_DELEGATE_READ); |
| 1208 | break; | 1184 | break; |
| 1209 | case FMODE_WRITE|FMODE_READ: | 1185 | case FMODE_WRITE|FMODE_READ: |
| 1210 | WRITE32(NFS4_OPEN_DELEGATE_WRITE); | 1186 | *p = cpu_to_be32(NFS4_OPEN_DELEGATE_WRITE); |
| 1211 | break; | 1187 | break; |
| 1212 | default: | 1188 | default: |
| 1213 | BUG(); | 1189 | BUG(); |
| @@ -1218,8 +1194,8 @@ static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr * | |||
| 1218 | { | 1194 | { |
| 1219 | __be32 *p; | 1195 | __be32 *p; |
| 1220 | 1196 | ||
| 1221 | RESERVE_SPACE(4); | 1197 | p = reserve_space(xdr, 4); |
| 1222 | WRITE32(NFS4_OPEN_CLAIM_NULL); | 1198 | *p = cpu_to_be32(NFS4_OPEN_CLAIM_NULL); |
| 1223 | encode_string(xdr, name->len, name->name); | 1199 | encode_string(xdr, name->len, name->name); |
| 1224 | } | 1200 | } |
| 1225 | 1201 | ||
| @@ -1227,8 +1203,8 @@ static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type) | |||
| 1227 | { | 1203 | { |
| 1228 | __be32 *p; | 1204 | __be32 *p; |
| 1229 | 1205 | ||
| 1230 | RESERVE_SPACE(4); | 1206 | p = reserve_space(xdr, 4); |
| 1231 | WRITE32(NFS4_OPEN_CLAIM_PREVIOUS); | 1207 | *p = cpu_to_be32(NFS4_OPEN_CLAIM_PREVIOUS); |
| 1232 | encode_delegation_type(xdr, type); | 1208 | encode_delegation_type(xdr, type); |
| 1233 | } | 1209 | } |
| 1234 | 1210 | ||
| @@ -1236,9 +1212,9 @@ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struc | |||
| 1236 | { | 1212 | { |
| 1237 | __be32 *p; | 1213 | __be32 *p; |
| 1238 | 1214 | ||
| 1239 | RESERVE_SPACE(4+NFS4_STATEID_SIZE); | 1215 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); |
| 1240 | WRITE32(NFS4_OPEN_CLAIM_DELEGATE_CUR); | 1216 | *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR); |
| 1241 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); | 1217 | xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE); |
| 1242 | encode_string(xdr, name->len, name->name); | 1218 | encode_string(xdr, name->len, name->name); |
| 1243 | } | 1219 | } |
| 1244 | 1220 | ||
| @@ -1267,10 +1243,10 @@ static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_co | |||
| 1267 | { | 1243 | { |
| 1268 | __be32 *p; | 1244 | __be32 *p; |
| 1269 | 1245 | ||
| 1270 | RESERVE_SPACE(4+NFS4_STATEID_SIZE+4); | 1246 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4); |
| 1271 | WRITE32(OP_OPEN_CONFIRM); | 1247 | *p++ = cpu_to_be32(OP_OPEN_CONFIRM); |
| 1272 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 1248 | p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); |
| 1273 | WRITE32(arg->seqid->sequence->counter); | 1249 | *p = cpu_to_be32(arg->seqid->sequence->counter); |
| 1274 | hdr->nops++; | 1250 | hdr->nops++; |
| 1275 | hdr->replen += decode_open_confirm_maxsz; | 1251 | hdr->replen += decode_open_confirm_maxsz; |
| 1276 | } | 1252 | } |
| @@ -1279,10 +1255,10 @@ static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_close | |||
| 1279 | { | 1255 | { |
| 1280 | __be32 *p; | 1256 | __be32 *p; |
| 1281 | 1257 | ||
| 1282 | RESERVE_SPACE(4+NFS4_STATEID_SIZE+4); | 1258 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4); |
| 1283 | WRITE32(OP_OPEN_DOWNGRADE); | 1259 | *p++ = cpu_to_be32(OP_OPEN_DOWNGRADE); |
| 1284 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 1260 | p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); |
| 1285 | WRITE32(arg->seqid->sequence->counter); | 1261 | *p = cpu_to_be32(arg->seqid->sequence->counter); |
| 1286 | encode_share_access(xdr, arg->fmode); | 1262 | encode_share_access(xdr, arg->fmode); |
| 1287 | hdr->nops++; | 1263 | hdr->nops++; |
| 1288 | hdr->replen += decode_open_downgrade_maxsz; | 1264 | hdr->replen += decode_open_downgrade_maxsz; |
| @@ -1294,10 +1270,9 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hd | |||
| 1294 | int len = fh->size; | 1270 | int len = fh->size; |
| 1295 | __be32 *p; | 1271 | __be32 *p; |
| 1296 | 1272 | ||
| 1297 | RESERVE_SPACE(8 + len); | 1273 | p = reserve_space(xdr, 8 + len); |
| 1298 | WRITE32(OP_PUTFH); | 1274 | *p++ = cpu_to_be32(OP_PUTFH); |
| 1299 | WRITE32(len); | 1275 | xdr_encode_opaque(p, fh->data, len); |
| 1300 | WRITEMEM(fh->data, len); | ||
| 1301 | hdr->nops++; | 1276 | hdr->nops++; |
| 1302 | hdr->replen += decode_putfh_maxsz; | 1277 | hdr->replen += decode_putfh_maxsz; |
| 1303 | } | 1278 | } |
| @@ -1306,8 +1281,8 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
| 1306 | { | 1281 | { |
| 1307 | __be32 *p; | 1282 | __be32 *p; |
| 1308 | 1283 | ||
| 1309 | RESERVE_SPACE(4); | 1284 | p = reserve_space(xdr, 4); |
| 1310 | WRITE32(OP_PUTROOTFH); | 1285 | *p = cpu_to_be32(OP_PUTROOTFH); |
| 1311 | hdr->nops++; | 1286 | hdr->nops++; |
| 1312 | hdr->replen += decode_putrootfh_maxsz; | 1287 | hdr->replen += decode_putrootfh_maxsz; |
| 1313 | } | 1288 | } |
| @@ -1317,26 +1292,26 @@ static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context | |||
| 1317 | nfs4_stateid stateid; | 1292 | nfs4_stateid stateid; |
| 1318 | __be32 *p; | 1293 | __be32 *p; |
| 1319 | 1294 | ||
| 1320 | RESERVE_SPACE(NFS4_STATEID_SIZE); | 1295 | p = reserve_space(xdr, NFS4_STATEID_SIZE); |
| 1321 | if (ctx->state != NULL) { | 1296 | if (ctx->state != NULL) { |
| 1322 | nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner); | 1297 | nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner); |
| 1323 | WRITEMEM(stateid.data, NFS4_STATEID_SIZE); | 1298 | xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE); |
| 1324 | } else | 1299 | } else |
| 1325 | WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE); | 1300 | xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); |
| 1326 | } | 1301 | } |
| 1327 | 1302 | ||
| 1328 | static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr) | 1303 | static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr) |
| 1329 | { | 1304 | { |
| 1330 | __be32 *p; | 1305 | __be32 *p; |
| 1331 | 1306 | ||
| 1332 | RESERVE_SPACE(4); | 1307 | p = reserve_space(xdr, 4); |
| 1333 | WRITE32(OP_READ); | 1308 | *p = cpu_to_be32(OP_READ); |
| 1334 | 1309 | ||
| 1335 | encode_stateid(xdr, args->context); | 1310 | encode_stateid(xdr, args->context); |
| 1336 | 1311 | ||
| 1337 | RESERVE_SPACE(12); | 1312 | p = reserve_space(xdr, 12); |
| 1338 | WRITE64(args->offset); | 1313 | p = xdr_encode_hyper(p, args->offset); |
| 1339 | WRITE32(args->count); | 1314 | *p = cpu_to_be32(args->count); |
| 1340 | hdr->nops++; | 1315 | hdr->nops++; |
| 1341 | hdr->replen += decode_read_maxsz; | 1316 | hdr->replen += decode_read_maxsz; |
| 1342 | } | 1317 | } |
| @@ -1349,20 +1324,20 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
| 1349 | }; | 1324 | }; |
| 1350 | __be32 *p; | 1325 | __be32 *p; |
| 1351 | 1326 | ||
| 1352 | RESERVE_SPACE(12+NFS4_VERIFIER_SIZE+20); | 1327 | p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); |
| 1353 | WRITE32(OP_READDIR); | 1328 | *p++ = cpu_to_be32(OP_READDIR); |
| 1354 | WRITE64(readdir->cookie); | 1329 | p = xdr_encode_hyper(p, readdir->cookie); |
| 1355 | WRITEMEM(readdir->verifier.data, NFS4_VERIFIER_SIZE); | 1330 | p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE); |
| 1356 | WRITE32(readdir->count >> 1); /* We're not doing readdirplus */ | 1331 | *p++ = cpu_to_be32(readdir->count >> 1); /* We're not doing readdirplus */ |
| 1357 | WRITE32(readdir->count); | 1332 | *p++ = cpu_to_be32(readdir->count); |
| 1358 | WRITE32(2); | 1333 | *p++ = cpu_to_be32(2); |
| 1359 | /* Switch to mounted_on_fileid if the server supports it */ | 1334 | /* Switch to mounted_on_fileid if the server supports it */ |
| 1360 | if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) | 1335 | if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) |
| 1361 | attrs[0] &= ~FATTR4_WORD0_FILEID; | 1336 | attrs[0] &= ~FATTR4_WORD0_FILEID; |
| 1362 | else | 1337 | else |
| 1363 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; | 1338 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; |
| 1364 | WRITE32(attrs[0] & readdir->bitmask[0]); | 1339 | *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); |
| 1365 | WRITE32(attrs[1] & readdir->bitmask[1]); | 1340 | *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); |
| 1366 | hdr->nops++; | 1341 | hdr->nops++; |
| 1367 | hdr->replen += decode_readdir_maxsz; | 1342 | hdr->replen += decode_readdir_maxsz; |
| 1368 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", | 1343 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", |
| @@ -1378,8 +1353,8 @@ static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink * | |||
| 1378 | { | 1353 | { |
| 1379 | __be32 *p; | 1354 | __be32 *p; |
| 1380 | 1355 | ||
| 1381 | RESERVE_SPACE(4); | 1356 | p = reserve_space(xdr, 4); |
| 1382 | WRITE32(OP_READLINK); | 1357 | *p = cpu_to_be32(OP_READLINK); |
| 1383 | hdr->nops++; | 1358 | hdr->nops++; |
| 1384 | hdr->replen += decode_readlink_maxsz; | 1359 | hdr->replen += decode_readlink_maxsz; |
| 1385 | } | 1360 | } |
| @@ -1388,10 +1363,9 @@ static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struc | |||
| 1388 | { | 1363 | { |
| 1389 | __be32 *p; | 1364 | __be32 *p; |
| 1390 | 1365 | ||
| 1391 | RESERVE_SPACE(8 + name->len); | 1366 | p = reserve_space(xdr, 8 + name->len); |
| 1392 | WRITE32(OP_REMOVE); | 1367 | *p++ = cpu_to_be32(OP_REMOVE); |
| 1393 | WRITE32(name->len); | 1368 | xdr_encode_opaque(p, name->name, name->len); |
| 1394 | WRITEMEM(name->name, name->len); | ||
| 1395 | hdr->nops++; | 1369 | hdr->nops++; |
| 1396 | hdr->replen += decode_remove_maxsz; | 1370 | hdr->replen += decode_remove_maxsz; |
| 1397 | } | 1371 | } |
| @@ -1400,14 +1374,10 @@ static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, co | |||
| 1400 | { | 1374 | { |
| 1401 | __be32 *p; | 1375 | __be32 *p; |
| 1402 | 1376 | ||
| 1403 | RESERVE_SPACE(8 + oldname->len); | 1377 | p = reserve_space(xdr, 4); |
| 1404 | WRITE32(OP_RENAME); | 1378 | *p = cpu_to_be32(OP_RENAME); |
| 1405 | WRITE32(oldname->len); | 1379 | encode_string(xdr, oldname->len, oldname->name); |
| 1406 | WRITEMEM(oldname->name, oldname->len); | 1380 | encode_string(xdr, newname->len, newname->name); |
| 1407 | |||
| 1408 | RESERVE_SPACE(4 + newname->len); | ||
| 1409 | WRITE32(newname->len); | ||
| 1410 | WRITEMEM(newname->name, newname->len); | ||
| 1411 | hdr->nops++; | 1381 | hdr->nops++; |
| 1412 | hdr->replen += decode_rename_maxsz; | 1382 | hdr->replen += decode_rename_maxsz; |
| 1413 | } | 1383 | } |
| @@ -1416,9 +1386,9 @@ static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client | |||
| 1416 | { | 1386 | { |
| 1417 | __be32 *p; | 1387 | __be32 *p; |
| 1418 | 1388 | ||
| 1419 | RESERVE_SPACE(12); | 1389 | p = reserve_space(xdr, 12); |
| 1420 | WRITE32(OP_RENEW); | 1390 | *p++ = cpu_to_be32(OP_RENEW); |
| 1421 | WRITE64(client_stateid->cl_clientid); | 1391 | xdr_encode_hyper(p, client_stateid->cl_clientid); |
| 1422 | hdr->nops++; | 1392 | hdr->nops++; |
| 1423 | hdr->replen += decode_renew_maxsz; | 1393 | hdr->replen += decode_renew_maxsz; |
| 1424 | } | 1394 | } |
| @@ -1428,8 +1398,8 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
| 1428 | { | 1398 | { |
| 1429 | __be32 *p; | 1399 | __be32 *p; |
| 1430 | 1400 | ||
| 1431 | RESERVE_SPACE(4); | 1401 | p = reserve_space(xdr, 4); |
| 1432 | WRITE32(OP_RESTOREFH); | 1402 | *p = cpu_to_be32(OP_RESTOREFH); |
| 1433 | hdr->nops++; | 1403 | hdr->nops++; |
| 1434 | hdr->replen += decode_restorefh_maxsz; | 1404 | hdr->replen += decode_restorefh_maxsz; |
| 1435 | } | 1405 | } |
| @@ -1439,16 +1409,16 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun | |||
| 1439 | { | 1409 | { |
| 1440 | __be32 *p; | 1410 | __be32 *p; |
| 1441 | 1411 | ||
| 1442 | RESERVE_SPACE(4+NFS4_STATEID_SIZE); | 1412 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); |
| 1443 | WRITE32(OP_SETATTR); | 1413 | *p++ = cpu_to_be32(OP_SETATTR); |
| 1444 | WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE); | 1414 | xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); |
| 1445 | RESERVE_SPACE(2*4); | 1415 | p = reserve_space(xdr, 2*4); |
| 1446 | WRITE32(1); | 1416 | *p++ = cpu_to_be32(1); |
| 1447 | WRITE32(FATTR4_WORD0_ACL); | 1417 | *p = cpu_to_be32(FATTR4_WORD0_ACL); |
| 1448 | if (arg->acl_len % 4) | 1418 | if (arg->acl_len % 4) |
| 1449 | return -EINVAL; | 1419 | return -EINVAL; |
| 1450 | RESERVE_SPACE(4); | 1420 | p = reserve_space(xdr, 4); |
| 1451 | WRITE32(arg->acl_len); | 1421 | *p = cpu_to_be32(arg->acl_len); |
| 1452 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); | 1422 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); |
| 1453 | hdr->nops++; | 1423 | hdr->nops++; |
| 1454 | hdr->replen += decode_setacl_maxsz; | 1424 | hdr->replen += decode_setacl_maxsz; |
| @@ -1460,8 +1430,8 @@ encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
| 1460 | { | 1430 | { |
| 1461 | __be32 *p; | 1431 | __be32 *p; |
| 1462 | 1432 | ||
| 1463 | RESERVE_SPACE(4); | 1433 | p = reserve_space(xdr, 4); |
| 1464 | WRITE32(OP_SAVEFH); | 1434 | *p = cpu_to_be32(OP_SAVEFH); |
| 1465 | hdr->nops++; | 1435 | hdr->nops++; |
| 1466 | hdr->replen += decode_savefh_maxsz; | 1436 | hdr->replen += decode_savefh_maxsz; |
| 1467 | } | 1437 | } |
| @@ -1470,9 +1440,9 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs | |||
| 1470 | { | 1440 | { |
| 1471 | __be32 *p; | 1441 | __be32 *p; |
| 1472 | 1442 | ||
| 1473 | RESERVE_SPACE(4+NFS4_STATEID_SIZE); | 1443 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); |
| 1474 | WRITE32(OP_SETATTR); | 1444 | *p++ = cpu_to_be32(OP_SETATTR); |
| 1475 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); | 1445 | xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE); |
| 1476 | hdr->nops++; | 1446 | hdr->nops++; |
| 1477 | hdr->replen += decode_setattr_maxsz; | 1447 | hdr->replen += decode_setattr_maxsz; |
| 1478 | encode_attrs(xdr, arg->iap, server); | 1448 | encode_attrs(xdr, arg->iap, server); |
| @@ -1482,17 +1452,17 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie | |||
| 1482 | { | 1452 | { |
| 1483 | __be32 *p; | 1453 | __be32 *p; |
| 1484 | 1454 | ||
| 1485 | RESERVE_SPACE(4 + NFS4_VERIFIER_SIZE); | 1455 | p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE); |
| 1486 | WRITE32(OP_SETCLIENTID); | 1456 | *p++ = cpu_to_be32(OP_SETCLIENTID); |
| 1487 | WRITEMEM(setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE); | 1457 | xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE); |
| 1488 | 1458 | ||
| 1489 | encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name); | 1459 | encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name); |
| 1490 | RESERVE_SPACE(4); | 1460 | p = reserve_space(xdr, 4); |
| 1491 | WRITE32(setclientid->sc_prog); | 1461 | *p = cpu_to_be32(setclientid->sc_prog); |
| 1492 | encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid); | 1462 | encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid); |
| 1493 | encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr); | 1463 | encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr); |
| 1494 | RESERVE_SPACE(4); | 1464 | p = reserve_space(xdr, 4); |
| 1495 | WRITE32(setclientid->sc_cb_ident); | 1465 | *p = cpu_to_be32(setclientid->sc_cb_ident); |
| 1496 | hdr->nops++; | 1466 | hdr->nops++; |
| 1497 | hdr->replen += decode_setclientid_maxsz; | 1467 | hdr->replen += decode_setclientid_maxsz; |
| 1498 | } | 1468 | } |
| @@ -1501,10 +1471,10 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_ | |||
| 1501 | { | 1471 | { |
| 1502 | __be32 *p; | 1472 | __be32 *p; |
| 1503 | 1473 | ||
| 1504 | RESERVE_SPACE(12 + NFS4_VERIFIER_SIZE); | 1474 | p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE); |
| 1505 | WRITE32(OP_SETCLIENTID_CONFIRM); | 1475 | *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); |
| 1506 | WRITE64(client_state->cl_clientid); | 1476 | p = xdr_encode_hyper(p, client_state->cl_clientid); |
| 1507 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); | 1477 | xdr_encode_opaque_fixed(p, client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); |
| 1508 | hdr->nops++; | 1478 | hdr->nops++; |
| 1509 | hdr->replen += decode_setclientid_confirm_maxsz; | 1479 | hdr->replen += decode_setclientid_confirm_maxsz; |
| 1510 | } | 1480 | } |
| @@ -1513,15 +1483,15 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg | |||
| 1513 | { | 1483 | { |
| 1514 | __be32 *p; | 1484 | __be32 *p; |
| 1515 | 1485 | ||
| 1516 | RESERVE_SPACE(4); | 1486 | p = reserve_space(xdr, 4); |
| 1517 | WRITE32(OP_WRITE); | 1487 | *p = cpu_to_be32(OP_WRITE); |
| 1518 | 1488 | ||
| 1519 | encode_stateid(xdr, args->context); | 1489 | encode_stateid(xdr, args->context); |
| 1520 | 1490 | ||
| 1521 | RESERVE_SPACE(16); | 1491 | p = reserve_space(xdr, 16); |
| 1522 | WRITE64(args->offset); | 1492 | p = xdr_encode_hyper(p, args->offset); |
| 1523 | WRITE32(args->stable); | 1493 | *p++ = cpu_to_be32(args->stable); |
| 1524 | WRITE32(args->count); | 1494 | *p = cpu_to_be32(args->count); |
| 1525 | 1495 | ||
| 1526 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); | 1496 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); |
| 1527 | hdr->nops++; | 1497 | hdr->nops++; |
| @@ -1532,10 +1502,10 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state | |||
| 1532 | { | 1502 | { |
| 1533 | __be32 *p; | 1503 | __be32 *p; |
| 1534 | 1504 | ||
| 1535 | RESERVE_SPACE(4+NFS4_STATEID_SIZE); | 1505 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); |
| 1536 | 1506 | ||
| 1537 | WRITE32(OP_DELEGRETURN); | 1507 | *p++ = cpu_to_be32(OP_DELEGRETURN); |
| 1538 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); | 1508 | xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE); |
| 1539 | hdr->nops++; | 1509 | hdr->nops++; |
| 1540 | hdr->replen += decode_delegreturn_maxsz; | 1510 | hdr->replen += decode_delegreturn_maxsz; |
| 1541 | } | 1511 | } |
| @@ -1548,16 +1518,16 @@ static void encode_exchange_id(struct xdr_stream *xdr, | |||
| 1548 | { | 1518 | { |
| 1549 | __be32 *p; | 1519 | __be32 *p; |
| 1550 | 1520 | ||
| 1551 | RESERVE_SPACE(4 + sizeof(args->verifier->data)); | 1521 | p = reserve_space(xdr, 4 + sizeof(args->verifier->data)); |
| 1552 | WRITE32(OP_EXCHANGE_ID); | 1522 | *p++ = cpu_to_be32(OP_EXCHANGE_ID); |
| 1553 | WRITEMEM(args->verifier->data, sizeof(args->verifier->data)); | 1523 | xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data)); |
| 1554 | 1524 | ||
| 1555 | encode_string(xdr, args->id_len, args->id); | 1525 | encode_string(xdr, args->id_len, args->id); |
| 1556 | 1526 | ||
| 1557 | RESERVE_SPACE(12); | 1527 | p = reserve_space(xdr, 12); |
| 1558 | WRITE32(args->flags); | 1528 | *p++ = cpu_to_be32(args->flags); |
| 1559 | WRITE32(0); /* zero length state_protect4_a */ | 1529 | *p++ = cpu_to_be32(0); /* zero length state_protect4_a */ |
| 1560 | WRITE32(0); /* zero length implementation id array */ | 1530 | *p = cpu_to_be32(0); /* zero length implementation id array */ |
| 1561 | hdr->nops++; | 1531 | hdr->nops++; |
| 1562 | hdr->replen += decode_exchange_id_maxsz; | 1532 | hdr->replen += decode_exchange_id_maxsz; |
| 1563 | } | 1533 | } |
| @@ -1571,55 +1541,43 @@ static void encode_create_session(struct xdr_stream *xdr, | |||
| 1571 | uint32_t len; | 1541 | uint32_t len; |
| 1572 | struct nfs_client *clp = args->client; | 1542 | struct nfs_client *clp = args->client; |
| 1573 | 1543 | ||
| 1574 | RESERVE_SPACE(4); | 1544 | len = scnprintf(machine_name, sizeof(machine_name), "%s", |
| 1575 | WRITE32(OP_CREATE_SESSION); | 1545 | clp->cl_ipaddr); |
| 1576 | |||
| 1577 | RESERVE_SPACE(8); | ||
| 1578 | WRITE64(clp->cl_ex_clid); | ||
| 1579 | 1546 | ||
| 1580 | RESERVE_SPACE(8); | 1547 | p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12); |
| 1581 | WRITE32(clp->cl_seqid); /*Sequence id */ | 1548 | *p++ = cpu_to_be32(OP_CREATE_SESSION); |
| 1582 | WRITE32(args->flags); /*flags */ | 1549 | p = xdr_encode_hyper(p, clp->cl_ex_clid); |
| 1550 | *p++ = cpu_to_be32(clp->cl_seqid); /*Sequence id */ | ||
| 1551 | *p++ = cpu_to_be32(args->flags); /*flags */ | ||
| 1583 | 1552 | ||
| 1584 | RESERVE_SPACE(2*28); /* 2 channel_attrs */ | ||
| 1585 | /* Fore Channel */ | 1553 | /* Fore Channel */ |
| 1586 | WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ | 1554 | *p++ = cpu_to_be32(args->fc_attrs.headerpadsz); /* header padding size */ |
| 1587 | WRITE32(args->fc_attrs.max_rqst_sz); /* max req size */ | 1555 | *p++ = cpu_to_be32(args->fc_attrs.max_rqst_sz); /* max req size */ |
| 1588 | WRITE32(args->fc_attrs.max_resp_sz); /* max resp size */ | 1556 | *p++ = cpu_to_be32(args->fc_attrs.max_resp_sz); /* max resp size */ |
| 1589 | WRITE32(args->fc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | 1557 | *p++ = cpu_to_be32(args->fc_attrs.max_resp_sz_cached); /* Max resp sz cached */ |
| 1590 | WRITE32(args->fc_attrs.max_ops); /* max operations */ | 1558 | *p++ = cpu_to_be32(args->fc_attrs.max_ops); /* max operations */ |
| 1591 | WRITE32(args->fc_attrs.max_reqs); /* max requests */ | 1559 | *p++ = cpu_to_be32(args->fc_attrs.max_reqs); /* max requests */ |
| 1592 | WRITE32(0); /* rdmachannel_attrs */ | 1560 | *p++ = cpu_to_be32(0); /* rdmachannel_attrs */ |
| 1593 | 1561 | ||
| 1594 | /* Back Channel */ | 1562 | /* Back Channel */ |
| 1595 | WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ | 1563 | *p++ = cpu_to_be32(args->fc_attrs.headerpadsz); /* header padding size */ |
| 1596 | WRITE32(args->bc_attrs.max_rqst_sz); /* max req size */ | 1564 | *p++ = cpu_to_be32(args->bc_attrs.max_rqst_sz); /* max req size */ |
| 1597 | WRITE32(args->bc_attrs.max_resp_sz); /* max resp size */ | 1565 | *p++ = cpu_to_be32(args->bc_attrs.max_resp_sz); /* max resp size */ |
| 1598 | WRITE32(args->bc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | 1566 | *p++ = cpu_to_be32(args->bc_attrs.max_resp_sz_cached); /* Max resp sz cached */ |
| 1599 | WRITE32(args->bc_attrs.max_ops); /* max operations */ | 1567 | *p++ = cpu_to_be32(args->bc_attrs.max_ops); /* max operations */ |
| 1600 | WRITE32(args->bc_attrs.max_reqs); /* max requests */ | 1568 | *p++ = cpu_to_be32(args->bc_attrs.max_reqs); /* max requests */ |
| 1601 | WRITE32(0); /* rdmachannel_attrs */ | 1569 | *p++ = cpu_to_be32(0); /* rdmachannel_attrs */ |
| 1602 | 1570 | ||
| 1603 | RESERVE_SPACE(4); | 1571 | *p++ = cpu_to_be32(args->cb_program); /* cb_program */ |
| 1604 | WRITE32(args->cb_program); /* cb_program */ | 1572 | *p++ = cpu_to_be32(1); |
| 1605 | 1573 | *p++ = cpu_to_be32(RPC_AUTH_UNIX); /* auth_sys */ | |
| 1606 | RESERVE_SPACE(4); /* # of security flavors */ | ||
| 1607 | WRITE32(1); | ||
| 1608 | |||
| 1609 | RESERVE_SPACE(4); | ||
| 1610 | WRITE32(RPC_AUTH_UNIX); /* auth_sys */ | ||
| 1611 | 1574 | ||
| 1612 | /* authsys_parms rfc1831 */ | 1575 | /* authsys_parms rfc1831 */ |
| 1613 | RESERVE_SPACE(4); | 1576 | *p++ = cpu_to_be32((u32)clp->cl_boot_time.tv_nsec); /* stamp */ |
| 1614 | WRITE32((u32)clp->cl_boot_time.tv_nsec); /* stamp */ | 1577 | p = xdr_encode_opaque(p, machine_name, len); |
| 1615 | len = scnprintf(machine_name, sizeof(machine_name), "%s", | 1578 | *p++ = cpu_to_be32(0); /* UID */ |
| 1616 | clp->cl_ipaddr); | 1579 | *p++ = cpu_to_be32(0); /* GID */ |
| 1617 | RESERVE_SPACE(16 + len); | 1580 | *p = cpu_to_be32(0); /* No more gids */ |
| 1618 | WRITE32(len); | ||
| 1619 | WRITEMEM(machine_name, len); | ||
| 1620 | WRITE32(0); /* UID */ | ||
| 1621 | WRITE32(0); /* GID */ | ||
| 1622 | WRITE32(0); /* No more gids */ | ||
| 1623 | hdr->nops++; | 1581 | hdr->nops++; |
| 1624 | hdr->replen += decode_create_session_maxsz; | 1582 | hdr->replen += decode_create_session_maxsz; |
| 1625 | } | 1583 | } |
| @@ -1629,9 +1587,9 @@ static void encode_destroy_session(struct xdr_stream *xdr, | |||
| 1629 | struct compound_hdr *hdr) | 1587 | struct compound_hdr *hdr) |
| 1630 | { | 1588 | { |
| 1631 | __be32 *p; | 1589 | __be32 *p; |
| 1632 | RESERVE_SPACE(4 + NFS4_MAX_SESSIONID_LEN); | 1590 | p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN); |
| 1633 | WRITE32(OP_DESTROY_SESSION); | 1591 | *p++ = cpu_to_be32(OP_DESTROY_SESSION); |
| 1634 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | 1592 | xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); |
| 1635 | hdr->nops++; | 1593 | hdr->nops++; |
| 1636 | hdr->replen += decode_destroy_session_maxsz; | 1594 | hdr->replen += decode_destroy_session_maxsz; |
| 1637 | } | 1595 | } |
| @@ -1655,8 +1613,8 @@ static void encode_sequence(struct xdr_stream *xdr, | |||
| 1655 | WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); | 1613 | WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); |
| 1656 | slot = tp->slots + args->sa_slotid; | 1614 | slot = tp->slots + args->sa_slotid; |
| 1657 | 1615 | ||
| 1658 | RESERVE_SPACE(4); | 1616 | p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN + 16); |
| 1659 | WRITE32(OP_SEQUENCE); | 1617 | *p++ = cpu_to_be32(OP_SEQUENCE); |
| 1660 | 1618 | ||
| 1661 | /* | 1619 | /* |
| 1662 | * Sessionid + seqid + slotid + max slotid + cache_this | 1620 | * Sessionid + seqid + slotid + max slotid + cache_this |
| @@ -1670,12 +1628,11 @@ static void encode_sequence(struct xdr_stream *xdr, | |||
| 1670 | ((u32 *)session->sess_id.data)[3], | 1628 | ((u32 *)session->sess_id.data)[3], |
| 1671 | slot->seq_nr, args->sa_slotid, | 1629 | slot->seq_nr, args->sa_slotid, |
| 1672 | tp->highest_used_slotid, args->sa_cache_this); | 1630 | tp->highest_used_slotid, args->sa_cache_this); |
| 1673 | RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 16); | 1631 | p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); |
| 1674 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | 1632 | *p++ = cpu_to_be32(slot->seq_nr); |
| 1675 | WRITE32(slot->seq_nr); | 1633 | *p++ = cpu_to_be32(args->sa_slotid); |
| 1676 | WRITE32(args->sa_slotid); | 1634 | *p++ = cpu_to_be32(tp->highest_used_slotid); |
| 1677 | WRITE32(tp->highest_used_slotid); | 1635 | *p = cpu_to_be32(args->sa_cache_this); |
| 1678 | WRITE32(args->sa_cache_this); | ||
| 1679 | hdr->nops++; | 1636 | hdr->nops++; |
| 1680 | hdr->replen += decode_sequence_maxsz; | 1637 | hdr->replen += decode_sequence_maxsz; |
| 1681 | #endif /* CONFIG_NFS_V4_1 */ | 1638 | #endif /* CONFIG_NFS_V4_1 */ |
| @@ -2466,68 +2423,53 @@ static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, | |||
| 2466 | } | 2423 | } |
| 2467 | #endif /* CONFIG_NFS_V4_1 */ | 2424 | #endif /* CONFIG_NFS_V4_1 */ |
| 2468 | 2425 | ||
| 2469 | /* | 2426 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) |
| 2470 | * START OF "GENERIC" DECODE ROUTINES. | 2427 | { |
| 2471 | * These may look a little ugly since they are imported from a "generic" | 2428 | dprintk("nfs: %s: prematurely hit end of receive buffer. " |
| 2472 | * set of XDR encode/decode routines which are intended to be shared by | 2429 | "Remaining buffer length is %tu words.\n", |
| 2473 | * all of our NFSv4 implementations (OpenBSD, MacOS X...). | 2430 | func, xdr->end - xdr->p); |
| 2474 | * | 2431 | } |
| 2475 | * If the pain of reading these is too great, it should be a straightforward | ||
| 2476 | * task to translate them into Linux-specific versions which are more | ||
| 2477 | * consistent with the style used in NFSv2/v3... | ||
| 2478 | */ | ||
| 2479 | #define READ32(x) (x) = ntohl(*p++) | ||
| 2480 | #define READ64(x) do { \ | ||
| 2481 | (x) = (u64)ntohl(*p++) << 32; \ | ||
| 2482 | (x) |= ntohl(*p++); \ | ||
| 2483 | } while (0) | ||
| 2484 | #define READTIME(x) do { \ | ||
| 2485 | p++; \ | ||
| 2486 | (x.tv_sec) = ntohl(*p++); \ | ||
| 2487 | (x.tv_nsec) = ntohl(*p++); \ | ||
| 2488 | } while (0) | ||
| 2489 | #define COPYMEM(x,nbytes) do { \ | ||
| 2490 | memcpy((x), p, nbytes); \ | ||
| 2491 | p += XDR_QUADLEN(nbytes); \ | ||
| 2492 | } while (0) | ||
| 2493 | |||
| 2494 | #define READ_BUF(nbytes) do { \ | ||
| 2495 | p = xdr_inline_decode(xdr, nbytes); \ | ||
| 2496 | if (unlikely(!p)) { \ | ||
| 2497 | dprintk("nfs: %s: prematurely hit end of receive" \ | ||
| 2498 | " buffer\n", __func__); \ | ||
| 2499 | dprintk("nfs: %s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \ | ||
| 2500 | __func__, xdr->p, nbytes, xdr->end); \ | ||
| 2501 | return -EIO; \ | ||
| 2502 | } \ | ||
| 2503 | } while (0) | ||
| 2504 | 2432 | ||
| 2505 | static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string) | 2433 | static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string) |
| 2506 | { | 2434 | { |
| 2507 | __be32 *p; | 2435 | __be32 *p; |
| 2508 | 2436 | ||
| 2509 | READ_BUF(4); | 2437 | p = xdr_inline_decode(xdr, 4); |
| 2510 | READ32(*len); | 2438 | if (unlikely(!p)) |
| 2511 | READ_BUF(*len); | 2439 | goto out_overflow; |
| 2440 | *len = be32_to_cpup(p); | ||
| 2441 | p = xdr_inline_decode(xdr, *len); | ||
| 2442 | if (unlikely(!p)) | ||
| 2443 | goto out_overflow; | ||
| 2512 | *string = (char *)p; | 2444 | *string = (char *)p; |
| 2513 | return 0; | 2445 | return 0; |
| 2446 | out_overflow: | ||
| 2447 | print_overflow_msg(__func__, xdr); | ||
| 2448 | return -EIO; | ||
| 2514 | } | 2449 | } |
| 2515 | 2450 | ||
| 2516 | static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) | 2451 | static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) |
| 2517 | { | 2452 | { |
| 2518 | __be32 *p; | 2453 | __be32 *p; |
| 2519 | 2454 | ||
| 2520 | READ_BUF(8); | 2455 | p = xdr_inline_decode(xdr, 8); |
| 2521 | READ32(hdr->status); | 2456 | if (unlikely(!p)) |
| 2522 | READ32(hdr->taglen); | 2457 | goto out_overflow; |
| 2458 | hdr->status = be32_to_cpup(p++); | ||
| 2459 | hdr->taglen = be32_to_cpup(p); | ||
| 2523 | 2460 | ||
| 2524 | READ_BUF(hdr->taglen + 4); | 2461 | p = xdr_inline_decode(xdr, hdr->taglen + 4); |
| 2462 | if (unlikely(!p)) | ||
| 2463 | goto out_overflow; | ||
| 2525 | hdr->tag = (char *)p; | 2464 | hdr->tag = (char *)p; |
| 2526 | p += XDR_QUADLEN(hdr->taglen); | 2465 | p += XDR_QUADLEN(hdr->taglen); |
| 2527 | READ32(hdr->nops); | 2466 | hdr->nops = be32_to_cpup(p); |
| 2528 | if (unlikely(hdr->nops < 1)) | 2467 | if (unlikely(hdr->nops < 1)) |
| 2529 | return nfs4_stat_to_errno(hdr->status); | 2468 | return nfs4_stat_to_errno(hdr->status); |
| 2530 | return 0; | 2469 | return 0; |
| 2470 | out_overflow: | ||
| 2471 | print_overflow_msg(__func__, xdr); | ||
| 2472 | return -EIO; | ||
| 2531 | } | 2473 | } |
| 2532 | 2474 | ||
| 2533 | static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | 2475 | static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) |
| @@ -2536,18 +2478,23 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | |||
| 2536 | uint32_t opnum; | 2478 | uint32_t opnum; |
| 2537 | int32_t nfserr; | 2479 | int32_t nfserr; |
| 2538 | 2480 | ||
| 2539 | READ_BUF(8); | 2481 | p = xdr_inline_decode(xdr, 8); |
| 2540 | READ32(opnum); | 2482 | if (unlikely(!p)) |
| 2483 | goto out_overflow; | ||
| 2484 | opnum = be32_to_cpup(p++); | ||
| 2541 | if (opnum != expected) { | 2485 | if (opnum != expected) { |
| 2542 | dprintk("nfs: Server returned operation" | 2486 | dprintk("nfs: Server returned operation" |
| 2543 | " %d but we issued a request for %d\n", | 2487 | " %d but we issued a request for %d\n", |
| 2544 | opnum, expected); | 2488 | opnum, expected); |
| 2545 | return -EIO; | 2489 | return -EIO; |
| 2546 | } | 2490 | } |
| 2547 | READ32(nfserr); | 2491 | nfserr = be32_to_cpup(p); |
| 2548 | if (nfserr != NFS_OK) | 2492 | if (nfserr != NFS_OK) |
| 2549 | return nfs4_stat_to_errno(nfserr); | 2493 | return nfs4_stat_to_errno(nfserr); |
| 2550 | return 0; | 2494 | return 0; |
| 2495 | out_overflow: | ||
| 2496 | print_overflow_msg(__func__, xdr); | ||
| 2497 | return -EIO; | ||
| 2551 | } | 2498 | } |
| 2552 | 2499 | ||
| 2553 | /* Dummy routine */ | 2500 | /* Dummy routine */ |
| @@ -2557,8 +2504,11 @@ static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp) | |||
| 2557 | unsigned int strlen; | 2504 | unsigned int strlen; |
| 2558 | char *str; | 2505 | char *str; |
| 2559 | 2506 | ||
| 2560 | READ_BUF(12); | 2507 | p = xdr_inline_decode(xdr, 12); |
| 2561 | return decode_opaque_inline(xdr, &strlen, &str); | 2508 | if (likely(p)) |
| 2509 | return decode_opaque_inline(xdr, &strlen, &str); | ||
| 2510 | print_overflow_msg(__func__, xdr); | ||
| 2511 | return -EIO; | ||
| 2562 | } | 2512 | } |
| 2563 | 2513 | ||
| 2564 | static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) | 2514 | static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) |
| @@ -2566,27 +2516,39 @@ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) | |||
| 2566 | uint32_t bmlen; | 2516 | uint32_t bmlen; |
| 2567 | __be32 *p; | 2517 | __be32 *p; |
| 2568 | 2518 | ||
| 2569 | READ_BUF(4); | 2519 | p = xdr_inline_decode(xdr, 4); |
| 2570 | READ32(bmlen); | 2520 | if (unlikely(!p)) |
| 2521 | goto out_overflow; | ||
| 2522 | bmlen = be32_to_cpup(p); | ||
| 2571 | 2523 | ||
| 2572 | bitmap[0] = bitmap[1] = 0; | 2524 | bitmap[0] = bitmap[1] = 0; |
| 2573 | READ_BUF((bmlen << 2)); | 2525 | p = xdr_inline_decode(xdr, (bmlen << 2)); |
| 2526 | if (unlikely(!p)) | ||
| 2527 | goto out_overflow; | ||
| 2574 | if (bmlen > 0) { | 2528 | if (bmlen > 0) { |
| 2575 | READ32(bitmap[0]); | 2529 | bitmap[0] = be32_to_cpup(p++); |
| 2576 | if (bmlen > 1) | 2530 | if (bmlen > 1) |
| 2577 | READ32(bitmap[1]); | 2531 | bitmap[1] = be32_to_cpup(p); |
| 2578 | } | 2532 | } |
| 2579 | return 0; | 2533 | return 0; |
| 2534 | out_overflow: | ||
| 2535 | print_overflow_msg(__func__, xdr); | ||
| 2536 | return -EIO; | ||
| 2580 | } | 2537 | } |
| 2581 | 2538 | ||
| 2582 | static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep) | 2539 | static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep) |
| 2583 | { | 2540 | { |
| 2584 | __be32 *p; | 2541 | __be32 *p; |
| 2585 | 2542 | ||
| 2586 | READ_BUF(4); | 2543 | p = xdr_inline_decode(xdr, 4); |
| 2587 | READ32(*attrlen); | 2544 | if (unlikely(!p)) |
| 2545 | goto out_overflow; | ||
| 2546 | *attrlen = be32_to_cpup(p); | ||
| 2588 | *savep = xdr->p; | 2547 | *savep = xdr->p; |
| 2589 | return 0; | 2548 | return 0; |
| 2549 | out_overflow: | ||
| 2550 | print_overflow_msg(__func__, xdr); | ||
| 2551 | return -EIO; | ||
| 2590 | } | 2552 | } |
| 2591 | 2553 | ||
| 2592 | static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask) | 2554 | static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask) |
| @@ -2609,8 +2571,10 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t * | |||
| 2609 | if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U))) | 2571 | if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U))) |
| 2610 | return -EIO; | 2572 | return -EIO; |
| 2611 | if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) { | 2573 | if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) { |
| 2612 | READ_BUF(4); | 2574 | p = xdr_inline_decode(xdr, 4); |
| 2613 | READ32(*type); | 2575 | if (unlikely(!p)) |
| 2576 | goto out_overflow; | ||
| 2577 | *type = be32_to_cpup(p); | ||
| 2614 | if (*type < NF4REG || *type > NF4NAMEDATTR) { | 2578 | if (*type < NF4REG || *type > NF4NAMEDATTR) { |
| 2615 | dprintk("%s: bad type %d\n", __func__, *type); | 2579 | dprintk("%s: bad type %d\n", __func__, *type); |
| 2616 | return -EIO; | 2580 | return -EIO; |
| @@ -2620,6 +2584,9 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t * | |||
| 2620 | } | 2584 | } |
| 2621 | dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]); | 2585 | dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]); |
| 2622 | return ret; | 2586 | return ret; |
| 2587 | out_overflow: | ||
| 2588 | print_overflow_msg(__func__, xdr); | ||
| 2589 | return -EIO; | ||
| 2623 | } | 2590 | } |
| 2624 | 2591 | ||
| 2625 | static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change) | 2592 | static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change) |
| @@ -2631,14 +2598,19 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t | |||
| 2631 | if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U))) | 2598 | if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U))) |
| 2632 | return -EIO; | 2599 | return -EIO; |
| 2633 | if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) { | 2600 | if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) { |
| 2634 | READ_BUF(8); | 2601 | p = xdr_inline_decode(xdr, 8); |
| 2635 | READ64(*change); | 2602 | if (unlikely(!p)) |
| 2603 | goto out_overflow; | ||
| 2604 | xdr_decode_hyper(p, change); | ||
| 2636 | bitmap[0] &= ~FATTR4_WORD0_CHANGE; | 2605 | bitmap[0] &= ~FATTR4_WORD0_CHANGE; |
| 2637 | ret = NFS_ATTR_FATTR_CHANGE; | 2606 | ret = NFS_ATTR_FATTR_CHANGE; |
| 2638 | } | 2607 | } |
| 2639 | dprintk("%s: change attribute=%Lu\n", __func__, | 2608 | dprintk("%s: change attribute=%Lu\n", __func__, |
| 2640 | (unsigned long long)*change); | 2609 | (unsigned long long)*change); |
| 2641 | return ret; | 2610 | return ret; |
| 2611 | out_overflow: | ||
| 2612 | print_overflow_msg(__func__, xdr); | ||
| 2613 | return -EIO; | ||
| 2642 | } | 2614 | } |
| 2643 | 2615 | ||
| 2644 | static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size) | 2616 | static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size) |
| @@ -2650,13 +2622,18 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t * | |||
| 2650 | if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U))) | 2622 | if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U))) |
| 2651 | return -EIO; | 2623 | return -EIO; |
| 2652 | if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) { | 2624 | if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) { |
| 2653 | READ_BUF(8); | 2625 | p = xdr_inline_decode(xdr, 8); |
| 2654 | READ64(*size); | 2626 | if (unlikely(!p)) |
| 2627 | goto out_overflow; | ||
| 2628 | xdr_decode_hyper(p, size); | ||
| 2655 | bitmap[0] &= ~FATTR4_WORD0_SIZE; | 2629 | bitmap[0] &= ~FATTR4_WORD0_SIZE; |
| 2656 | ret = NFS_ATTR_FATTR_SIZE; | 2630 | ret = NFS_ATTR_FATTR_SIZE; |
| 2657 | } | 2631 | } |
| 2658 | dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size); | 2632 | dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size); |
| 2659 | return ret; | 2633 | return ret; |
| 2634 | out_overflow: | ||
| 2635 | print_overflow_msg(__func__, xdr); | ||
| 2636 | return -EIO; | ||
| 2660 | } | 2637 | } |
| 2661 | 2638 | ||
| 2662 | static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) | 2639 | static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) |
| @@ -2667,12 +2644,17 @@ static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, ui | |||
| 2667 | if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U))) | 2644 | if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U))) |
| 2668 | return -EIO; | 2645 | return -EIO; |
| 2669 | if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) { | 2646 | if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) { |
| 2670 | READ_BUF(4); | 2647 | p = xdr_inline_decode(xdr, 4); |
| 2671 | READ32(*res); | 2648 | if (unlikely(!p)) |
| 2649 | goto out_overflow; | ||
| 2650 | *res = be32_to_cpup(p); | ||
| 2672 | bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT; | 2651 | bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT; |
| 2673 | } | 2652 | } |
| 2674 | dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true"); | 2653 | dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true"); |
| 2675 | return 0; | 2654 | return 0; |
| 2655 | out_overflow: | ||
| 2656 | print_overflow_msg(__func__, xdr); | ||
| 2657 | return -EIO; | ||
| 2676 | } | 2658 | } |
| 2677 | 2659 | ||
| 2678 | static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) | 2660 | static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) |
| @@ -2683,12 +2665,17 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, | |||
| 2683 | if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U))) | 2665 | if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U))) |
| 2684 | return -EIO; | 2666 | return -EIO; |
| 2685 | if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) { | 2667 | if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) { |
| 2686 | READ_BUF(4); | 2668 | p = xdr_inline_decode(xdr, 4); |
| 2687 | READ32(*res); | 2669 | if (unlikely(!p)) |
| 2670 | goto out_overflow; | ||
| 2671 | *res = be32_to_cpup(p); | ||
| 2688 | bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT; | 2672 | bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT; |
| 2689 | } | 2673 | } |
| 2690 | dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true"); | 2674 | dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true"); |
| 2691 | return 0; | 2675 | return 0; |
| 2676 | out_overflow: | ||
| 2677 | print_overflow_msg(__func__, xdr); | ||
| 2678 | return -EIO; | ||
| 2692 | } | 2679 | } |
| 2693 | 2680 | ||
| 2694 | static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid) | 2681 | static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid) |
| @@ -2701,9 +2688,11 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs | |||
| 2701 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U))) | 2688 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U))) |
| 2702 | return -EIO; | 2689 | return -EIO; |
| 2703 | if (likely(bitmap[0] & FATTR4_WORD0_FSID)) { | 2690 | if (likely(bitmap[0] & FATTR4_WORD0_FSID)) { |
| 2704 | READ_BUF(16); | 2691 | p = xdr_inline_decode(xdr, 16); |
| 2705 | READ64(fsid->major); | 2692 | if (unlikely(!p)) |
| 2706 | READ64(fsid->minor); | 2693 | goto out_overflow; |
| 2694 | p = xdr_decode_hyper(p, &fsid->major); | ||
| 2695 | xdr_decode_hyper(p, &fsid->minor); | ||
| 2707 | bitmap[0] &= ~FATTR4_WORD0_FSID; | 2696 | bitmap[0] &= ~FATTR4_WORD0_FSID; |
| 2708 | ret = NFS_ATTR_FATTR_FSID; | 2697 | ret = NFS_ATTR_FATTR_FSID; |
| 2709 | } | 2698 | } |
| @@ -2711,6 +2700,9 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs | |||
| 2711 | (unsigned long long)fsid->major, | 2700 | (unsigned long long)fsid->major, |
| 2712 | (unsigned long long)fsid->minor); | 2701 | (unsigned long long)fsid->minor); |
| 2713 | return ret; | 2702 | return ret; |
| 2703 | out_overflow: | ||
| 2704 | print_overflow_msg(__func__, xdr); | ||
| 2705 | return -EIO; | ||
| 2714 | } | 2706 | } |
| 2715 | 2707 | ||
| 2716 | static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) | 2708 | static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) |
| @@ -2721,12 +2713,17 @@ static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint | |||
| 2721 | if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U))) | 2713 | if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U))) |
| 2722 | return -EIO; | 2714 | return -EIO; |
| 2723 | if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) { | 2715 | if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) { |
| 2724 | READ_BUF(4); | 2716 | p = xdr_inline_decode(xdr, 4); |
| 2725 | READ32(*res); | 2717 | if (unlikely(!p)) |
| 2718 | goto out_overflow; | ||
| 2719 | *res = be32_to_cpup(p); | ||
| 2726 | bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME; | 2720 | bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME; |
| 2727 | } | 2721 | } |
| 2728 | dprintk("%s: file size=%u\n", __func__, (unsigned int)*res); | 2722 | dprintk("%s: file size=%u\n", __func__, (unsigned int)*res); |
| 2729 | return 0; | 2723 | return 0; |
| 2724 | out_overflow: | ||
| 2725 | print_overflow_msg(__func__, xdr); | ||
| 2726 | return -EIO; | ||
| 2730 | } | 2727 | } |
| 2731 | 2728 | ||
| 2732 | static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) | 2729 | static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) |
| @@ -2737,12 +2734,17 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint | |||
| 2737 | if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U))) | 2734 | if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U))) |
| 2738 | return -EIO; | 2735 | return -EIO; |
| 2739 | if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) { | 2736 | if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) { |
| 2740 | READ_BUF(4); | 2737 | p = xdr_inline_decode(xdr, 4); |
| 2741 | READ32(*res); | 2738 | if (unlikely(!p)) |
| 2739 | goto out_overflow; | ||
| 2740 | *res = be32_to_cpup(p); | ||
| 2742 | bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT; | 2741 | bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT; |
| 2743 | } | 2742 | } |
| 2744 | dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res); | 2743 | dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res); |
| 2745 | return 0; | 2744 | return 0; |
| 2745 | out_overflow: | ||
| 2746 | print_overflow_msg(__func__, xdr); | ||
| 2747 | return -EIO; | ||
| 2746 | } | 2748 | } |
| 2747 | 2749 | ||
| 2748 | static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid) | 2750 | static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid) |
| @@ -2754,13 +2756,18 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t | |||
| 2754 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U))) | 2756 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U))) |
| 2755 | return -EIO; | 2757 | return -EIO; |
| 2756 | if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) { | 2758 | if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) { |
| 2757 | READ_BUF(8); | 2759 | p = xdr_inline_decode(xdr, 8); |
| 2758 | READ64(*fileid); | 2760 | if (unlikely(!p)) |
| 2761 | goto out_overflow; | ||
| 2762 | xdr_decode_hyper(p, fileid); | ||
| 2759 | bitmap[0] &= ~FATTR4_WORD0_FILEID; | 2763 | bitmap[0] &= ~FATTR4_WORD0_FILEID; |
| 2760 | ret = NFS_ATTR_FATTR_FILEID; | 2764 | ret = NFS_ATTR_FATTR_FILEID; |
| 2761 | } | 2765 | } |
| 2762 | dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); | 2766 | dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); |
| 2763 | return ret; | 2767 | return ret; |
| 2768 | out_overflow: | ||
| 2769 | print_overflow_msg(__func__, xdr); | ||
| 2770 | return -EIO; | ||
| 2764 | } | 2771 | } |
| 2765 | 2772 | ||
| 2766 | static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid) | 2773 | static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid) |
| @@ -2772,13 +2779,18 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma | |||
| 2772 | if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U))) | 2779 | if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U))) |
| 2773 | return -EIO; | 2780 | return -EIO; |
| 2774 | if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) { | 2781 | if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) { |
| 2775 | READ_BUF(8); | 2782 | p = xdr_inline_decode(xdr, 8); |
| 2776 | READ64(*fileid); | 2783 | if (unlikely(!p)) |
| 2784 | goto out_overflow; | ||
| 2785 | xdr_decode_hyper(p, fileid); | ||
| 2777 | bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; | 2786 | bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; |
| 2778 | ret = NFS_ATTR_FATTR_FILEID; | 2787 | ret = NFS_ATTR_FATTR_FILEID; |
| 2779 | } | 2788 | } |
| 2780 | dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); | 2789 | dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); |
| 2781 | return ret; | 2790 | return ret; |
| 2791 | out_overflow: | ||
| 2792 | print_overflow_msg(__func__, xdr); | ||
| 2793 | return -EIO; | ||
| 2782 | } | 2794 | } |
| 2783 | 2795 | ||
| 2784 | static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) | 2796 | static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) |
| @@ -2790,12 +2802,17 @@ static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin | |||
| 2790 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U))) | 2802 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U))) |
| 2791 | return -EIO; | 2803 | return -EIO; |
| 2792 | if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) { | 2804 | if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) { |
| 2793 | READ_BUF(8); | 2805 | p = xdr_inline_decode(xdr, 8); |
| 2794 | READ64(*res); | 2806 | if (unlikely(!p)) |
| 2807 | goto out_overflow; | ||
| 2808 | xdr_decode_hyper(p, res); | ||
| 2795 | bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL; | 2809 | bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL; |
| 2796 | } | 2810 | } |
| 2797 | dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res); | 2811 | dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res); |
| 2798 | return status; | 2812 | return status; |
| 2813 | out_overflow: | ||
| 2814 | print_overflow_msg(__func__, xdr); | ||
| 2815 | return -EIO; | ||
| 2799 | } | 2816 | } |
| 2800 | 2817 | ||
| 2801 | static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) | 2818 | static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) |
| @@ -2807,12 +2824,17 @@ static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint | |||
| 2807 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U))) | 2824 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U))) |
| 2808 | return -EIO; | 2825 | return -EIO; |
| 2809 | if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) { | 2826 | if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) { |
| 2810 | READ_BUF(8); | 2827 | p = xdr_inline_decode(xdr, 8); |
| 2811 | READ64(*res); | 2828 | if (unlikely(!p)) |
| 2829 | goto out_overflow; | ||
| 2830 | xdr_decode_hyper(p, res); | ||
| 2812 | bitmap[0] &= ~FATTR4_WORD0_FILES_FREE; | 2831 | bitmap[0] &= ~FATTR4_WORD0_FILES_FREE; |
| 2813 | } | 2832 | } |
| 2814 | dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res); | 2833 | dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res); |
| 2815 | return status; | 2834 | return status; |
| 2835 | out_overflow: | ||
| 2836 | print_overflow_msg(__func__, xdr); | ||
| 2837 | return -EIO; | ||
| 2816 | } | 2838 | } |
| 2817 | 2839 | ||
| 2818 | static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) | 2840 | static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) |
| @@ -2824,12 +2846,17 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin | |||
| 2824 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U))) | 2846 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U))) |
| 2825 | return -EIO; | 2847 | return -EIO; |
| 2826 | if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) { | 2848 | if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) { |
| 2827 | READ_BUF(8); | 2849 | p = xdr_inline_decode(xdr, 8); |
| 2828 | READ64(*res); | 2850 | if (unlikely(!p)) |
| 2851 | goto out_overflow; | ||
| 2852 | xdr_decode_hyper(p, res); | ||
| 2829 | bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL; | 2853 | bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL; |
| 2830 | } | 2854 | } |
| 2831 | dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res); | 2855 | dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res); |
| 2832 | return status; | 2856 | return status; |
| 2857 | out_overflow: | ||
| 2858 | print_overflow_msg(__func__, xdr); | ||
| 2859 | return -EIO; | ||
| 2833 | } | 2860 | } |
| 2834 | 2861 | ||
| 2835 | static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) | 2862 | static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) |
| @@ -2838,8 +2865,10 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) | |||
| 2838 | __be32 *p; | 2865 | __be32 *p; |
| 2839 | int status = 0; | 2866 | int status = 0; |
| 2840 | 2867 | ||
| 2841 | READ_BUF(4); | 2868 | p = xdr_inline_decode(xdr, 4); |
| 2842 | READ32(n); | 2869 | if (unlikely(!p)) |
| 2870 | goto out_overflow; | ||
| 2871 | n = be32_to_cpup(p); | ||
| 2843 | if (n == 0) | 2872 | if (n == 0) |
| 2844 | goto root_path; | 2873 | goto root_path; |
| 2845 | dprintk("path "); | 2874 | dprintk("path "); |
| @@ -2873,6 +2902,9 @@ out_eio: | |||
| 2873 | dprintk(" status %d", status); | 2902 | dprintk(" status %d", status); |
| 2874 | status = -EIO; | 2903 | status = -EIO; |
| 2875 | goto out; | 2904 | goto out; |
| 2905 | out_overflow: | ||
| 2906 | print_overflow_msg(__func__, xdr); | ||
| 2907 | return -EIO; | ||
| 2876 | } | 2908 | } |
| 2877 | 2909 | ||
| 2878 | static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res) | 2910 | static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res) |
| @@ -2890,8 +2922,10 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st | |||
| 2890 | status = decode_pathname(xdr, &res->fs_path); | 2922 | status = decode_pathname(xdr, &res->fs_path); |
| 2891 | if (unlikely(status != 0)) | 2923 | if (unlikely(status != 0)) |
| 2892 | goto out; | 2924 | goto out; |
| 2893 | READ_BUF(4); | 2925 | p = xdr_inline_decode(xdr, 4); |
| 2894 | READ32(n); | 2926 | if (unlikely(!p)) |
| 2927 | goto out_overflow; | ||
| 2928 | n = be32_to_cpup(p); | ||
| 2895 | if (n <= 0) | 2929 | if (n <= 0) |
| 2896 | goto out_eio; | 2930 | goto out_eio; |
| 2897 | res->nlocations = 0; | 2931 | res->nlocations = 0; |
| @@ -2899,8 +2933,10 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st | |||
| 2899 | u32 m; | 2933 | u32 m; |
| 2900 | struct nfs4_fs_location *loc = &res->locations[res->nlocations]; | 2934 | struct nfs4_fs_location *loc = &res->locations[res->nlocations]; |
| 2901 | 2935 | ||
| 2902 | READ_BUF(4); | 2936 | p = xdr_inline_decode(xdr, 4); |
| 2903 | READ32(m); | 2937 | if (unlikely(!p)) |
| 2938 | goto out_overflow; | ||
| 2939 | m = be32_to_cpup(p); | ||
| 2904 | 2940 | ||
| 2905 | loc->nservers = 0; | 2941 | loc->nservers = 0; |
| 2906 | dprintk("%s: servers ", __func__); | 2942 | dprintk("%s: servers ", __func__); |
| @@ -2939,6 +2975,8 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st | |||
| 2939 | out: | 2975 | out: |
| 2940 | dprintk("%s: fs_locations done, error = %d\n", __func__, status); | 2976 | dprintk("%s: fs_locations done, error = %d\n", __func__, status); |
| 2941 | return status; | 2977 | return status; |
| 2978 | out_overflow: | ||
| 2979 | print_overflow_msg(__func__, xdr); | ||
| 2942 | out_eio: | 2980 | out_eio: |
| 2943 | status = -EIO; | 2981 | status = -EIO; |
| 2944 | goto out; | 2982 | goto out; |
| @@ -2953,12 +2991,17 @@ static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uin | |||
| 2953 | if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U))) | 2991 | if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U))) |
| 2954 | return -EIO; | 2992 | return -EIO; |
| 2955 | if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) { | 2993 | if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) { |
| 2956 | READ_BUF(8); | 2994 | p = xdr_inline_decode(xdr, 8); |
| 2957 | READ64(*res); | 2995 | if (unlikely(!p)) |
| 2996 | goto out_overflow; | ||
| 2997 | xdr_decode_hyper(p, res); | ||
| 2958 | bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE; | 2998 | bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE; |
| 2959 | } | 2999 | } |
| 2960 | dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res); | 3000 | dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res); |
| 2961 | return status; | 3001 | return status; |
| 3002 | out_overflow: | ||
| 3003 | print_overflow_msg(__func__, xdr); | ||
| 3004 | return -EIO; | ||
| 2962 | } | 3005 | } |
| 2963 | 3006 | ||
| 2964 | static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink) | 3007 | static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink) |
| @@ -2970,12 +3013,17 @@ static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ | |||
| 2970 | if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U))) | 3013 | if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U))) |
| 2971 | return -EIO; | 3014 | return -EIO; |
| 2972 | if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) { | 3015 | if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) { |
| 2973 | READ_BUF(4); | 3016 | p = xdr_inline_decode(xdr, 4); |
| 2974 | READ32(*maxlink); | 3017 | if (unlikely(!p)) |
| 3018 | goto out_overflow; | ||
| 3019 | *maxlink = be32_to_cpup(p); | ||
| 2975 | bitmap[0] &= ~FATTR4_WORD0_MAXLINK; | 3020 | bitmap[0] &= ~FATTR4_WORD0_MAXLINK; |
| 2976 | } | 3021 | } |
| 2977 | dprintk("%s: maxlink=%u\n", __func__, *maxlink); | 3022 | dprintk("%s: maxlink=%u\n", __func__, *maxlink); |
| 2978 | return status; | 3023 | return status; |
| 3024 | out_overflow: | ||
| 3025 | print_overflow_msg(__func__, xdr); | ||
| 3026 | return -EIO; | ||
| 2979 | } | 3027 | } |
| 2980 | 3028 | ||
| 2981 | static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname) | 3029 | static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname) |
| @@ -2987,12 +3035,17 @@ static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ | |||
| 2987 | if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U))) | 3035 | if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U))) |
| 2988 | return -EIO; | 3036 | return -EIO; |
| 2989 | if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) { | 3037 | if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) { |
| 2990 | READ_BUF(4); | 3038 | p = xdr_inline_decode(xdr, 4); |
| 2991 | READ32(*maxname); | 3039 | if (unlikely(!p)) |
| 3040 | goto out_overflow; | ||
| 3041 | *maxname = be32_to_cpup(p); | ||
| 2992 | bitmap[0] &= ~FATTR4_WORD0_MAXNAME; | 3042 | bitmap[0] &= ~FATTR4_WORD0_MAXNAME; |
| 2993 | } | 3043 | } |
| 2994 | dprintk("%s: maxname=%u\n", __func__, *maxname); | 3044 | dprintk("%s: maxname=%u\n", __func__, *maxname); |
| 2995 | return status; | 3045 | return status; |
| 3046 | out_overflow: | ||
| 3047 | print_overflow_msg(__func__, xdr); | ||
| 3048 | return -EIO; | ||
| 2996 | } | 3049 | } |
| 2997 | 3050 | ||
| 2998 | static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) | 3051 | static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) |
| @@ -3005,8 +3058,10 @@ static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ | |||
| 3005 | return -EIO; | 3058 | return -EIO; |
| 3006 | if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) { | 3059 | if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) { |
| 3007 | uint64_t maxread; | 3060 | uint64_t maxread; |
| 3008 | READ_BUF(8); | 3061 | p = xdr_inline_decode(xdr, 8); |
| 3009 | READ64(maxread); | 3062 | if (unlikely(!p)) |
| 3063 | goto out_overflow; | ||
| 3064 | xdr_decode_hyper(p, &maxread); | ||
| 3010 | if (maxread > 0x7FFFFFFF) | 3065 | if (maxread > 0x7FFFFFFF) |
| 3011 | maxread = 0x7FFFFFFF; | 3066 | maxread = 0x7FFFFFFF; |
| 3012 | *res = (uint32_t)maxread; | 3067 | *res = (uint32_t)maxread; |
| @@ -3014,6 +3069,9 @@ static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ | |||
| 3014 | } | 3069 | } |
| 3015 | dprintk("%s: maxread=%lu\n", __func__, (unsigned long)*res); | 3070 | dprintk("%s: maxread=%lu\n", __func__, (unsigned long)*res); |
| 3016 | return status; | 3071 | return status; |
| 3072 | out_overflow: | ||
| 3073 | print_overflow_msg(__func__, xdr); | ||
| 3074 | return -EIO; | ||
| 3017 | } | 3075 | } |
| 3018 | 3076 | ||
| 3019 | static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) | 3077 | static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) |
| @@ -3026,8 +3084,10 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32 | |||
| 3026 | return -EIO; | 3084 | return -EIO; |
| 3027 | if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) { | 3085 | if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) { |
| 3028 | uint64_t maxwrite; | 3086 | uint64_t maxwrite; |
| 3029 | READ_BUF(8); | 3087 | p = xdr_inline_decode(xdr, 8); |
| 3030 | READ64(maxwrite); | 3088 | if (unlikely(!p)) |
| 3089 | goto out_overflow; | ||
| 3090 | xdr_decode_hyper(p, &maxwrite); | ||
| 3031 | if (maxwrite > 0x7FFFFFFF) | 3091 | if (maxwrite > 0x7FFFFFFF) |
| 3032 | maxwrite = 0x7FFFFFFF; | 3092 | maxwrite = 0x7FFFFFFF; |
| 3033 | *res = (uint32_t)maxwrite; | 3093 | *res = (uint32_t)maxwrite; |
| @@ -3035,6 +3095,9 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32 | |||
| 3035 | } | 3095 | } |
| 3036 | dprintk("%s: maxwrite=%lu\n", __func__, (unsigned long)*res); | 3096 | dprintk("%s: maxwrite=%lu\n", __func__, (unsigned long)*res); |
| 3037 | return status; | 3097 | return status; |
| 3098 | out_overflow: | ||
| 3099 | print_overflow_msg(__func__, xdr); | ||
| 3100 | return -EIO; | ||
| 3038 | } | 3101 | } |
| 3039 | 3102 | ||
| 3040 | static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode) | 3103 | static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode) |
| @@ -3047,14 +3110,19 @@ static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *m | |||
| 3047 | if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U))) | 3110 | if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U))) |
| 3048 | return -EIO; | 3111 | return -EIO; |
| 3049 | if (likely(bitmap[1] & FATTR4_WORD1_MODE)) { | 3112 | if (likely(bitmap[1] & FATTR4_WORD1_MODE)) { |
| 3050 | READ_BUF(4); | 3113 | p = xdr_inline_decode(xdr, 4); |
| 3051 | READ32(tmp); | 3114 | if (unlikely(!p)) |
| 3115 | goto out_overflow; | ||
| 3116 | tmp = be32_to_cpup(p); | ||
| 3052 | *mode = tmp & ~S_IFMT; | 3117 | *mode = tmp & ~S_IFMT; |
| 3053 | bitmap[1] &= ~FATTR4_WORD1_MODE; | 3118 | bitmap[1] &= ~FATTR4_WORD1_MODE; |
| 3054 | ret = NFS_ATTR_FATTR_MODE; | 3119 | ret = NFS_ATTR_FATTR_MODE; |
| 3055 | } | 3120 | } |
| 3056 | dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode); | 3121 | dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode); |
| 3057 | return ret; | 3122 | return ret; |
| 3123 | out_overflow: | ||
| 3124 | print_overflow_msg(__func__, xdr); | ||
| 3125 | return -EIO; | ||
| 3058 | } | 3126 | } |
| 3059 | 3127 | ||
| 3060 | static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink) | 3128 | static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink) |
| @@ -3066,16 +3134,22 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t | |||
| 3066 | if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U))) | 3134 | if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U))) |
| 3067 | return -EIO; | 3135 | return -EIO; |
| 3068 | if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) { | 3136 | if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) { |
| 3069 | READ_BUF(4); | 3137 | p = xdr_inline_decode(xdr, 4); |
| 3070 | READ32(*nlink); | 3138 | if (unlikely(!p)) |
| 3139 | goto out_overflow; | ||
| 3140 | *nlink = be32_to_cpup(p); | ||
| 3071 | bitmap[1] &= ~FATTR4_WORD1_NUMLINKS; | 3141 | bitmap[1] &= ~FATTR4_WORD1_NUMLINKS; |
| 3072 | ret = NFS_ATTR_FATTR_NLINK; | 3142 | ret = NFS_ATTR_FATTR_NLINK; |
| 3073 | } | 3143 | } |
| 3074 | dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink); | 3144 | dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink); |
| 3075 | return ret; | 3145 | return ret; |
| 3146 | out_overflow: | ||
| 3147 | print_overflow_msg(__func__, xdr); | ||
| 3148 | return -EIO; | ||
| 3076 | } | 3149 | } |
| 3077 | 3150 | ||
| 3078 | static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *uid) | 3151 | static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, |
| 3152 | struct nfs_client *clp, uint32_t *uid, int may_sleep) | ||
| 3079 | { | 3153 | { |
| 3080 | uint32_t len; | 3154 | uint32_t len; |
| 3081 | __be32 *p; | 3155 | __be32 *p; |
| @@ -3085,10 +3159,16 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf | |||
| 3085 | if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U))) | 3159 | if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U))) |
| 3086 | return -EIO; | 3160 | return -EIO; |
| 3087 | if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) { | 3161 | if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) { |
| 3088 | READ_BUF(4); | 3162 | p = xdr_inline_decode(xdr, 4); |
| 3089 | READ32(len); | 3163 | if (unlikely(!p)) |
| 3090 | READ_BUF(len); | 3164 | goto out_overflow; |
| 3091 | if (len < XDR_MAX_NETOBJ) { | 3165 | len = be32_to_cpup(p); |
| 3166 | p = xdr_inline_decode(xdr, len); | ||
| 3167 | if (unlikely(!p)) | ||
| 3168 | goto out_overflow; | ||
| 3169 | if (!may_sleep) { | ||
| 3170 | /* do nothing */ | ||
| 3171 | } else if (len < XDR_MAX_NETOBJ) { | ||
| 3092 | if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0) | 3172 | if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0) |
| 3093 | ret = NFS_ATTR_FATTR_OWNER; | 3173 | ret = NFS_ATTR_FATTR_OWNER; |
| 3094 | else | 3174 | else |
| @@ -3101,9 +3181,13 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf | |||
| 3101 | } | 3181 | } |
| 3102 | dprintk("%s: uid=%d\n", __func__, (int)*uid); | 3182 | dprintk("%s: uid=%d\n", __func__, (int)*uid); |
| 3103 | return ret; | 3183 | return ret; |
| 3184 | out_overflow: | ||
| 3185 | print_overflow_msg(__func__, xdr); | ||
| 3186 | return -EIO; | ||
| 3104 | } | 3187 | } |
| 3105 | 3188 | ||
| 3106 | static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *gid) | 3189 | static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, |
| 3190 | struct nfs_client *clp, uint32_t *gid, int may_sleep) | ||
| 3107 | { | 3191 | { |
| 3108 | uint32_t len; | 3192 | uint32_t len; |
| 3109 | __be32 *p; | 3193 | __be32 *p; |
| @@ -3113,10 +3197,16 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf | |||
| 3113 | if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U))) | 3197 | if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U))) |
| 3114 | return -EIO; | 3198 | return -EIO; |
| 3115 | if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) { | 3199 | if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) { |
| 3116 | READ_BUF(4); | 3200 | p = xdr_inline_decode(xdr, 4); |
| 3117 | READ32(len); | 3201 | if (unlikely(!p)) |
| 3118 | READ_BUF(len); | 3202 | goto out_overflow; |
| 3119 | if (len < XDR_MAX_NETOBJ) { | 3203 | len = be32_to_cpup(p); |
| 3204 | p = xdr_inline_decode(xdr, len); | ||
| 3205 | if (unlikely(!p)) | ||
| 3206 | goto out_overflow; | ||
| 3207 | if (!may_sleep) { | ||
| 3208 | /* do nothing */ | ||
| 3209 | } else if (len < XDR_MAX_NETOBJ) { | ||
| 3120 | if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0) | 3210 | if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0) |
| 3121 | ret = NFS_ATTR_FATTR_GROUP; | 3211 | ret = NFS_ATTR_FATTR_GROUP; |
| 3122 | else | 3212 | else |
| @@ -3129,6 +3219,9 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf | |||
| 3129 | } | 3219 | } |
| 3130 | dprintk("%s: gid=%d\n", __func__, (int)*gid); | 3220 | dprintk("%s: gid=%d\n", __func__, (int)*gid); |
| 3131 | return ret; | 3221 | return ret; |
| 3222 | out_overflow: | ||
| 3223 | print_overflow_msg(__func__, xdr); | ||
| 3224 | return -EIO; | ||
| 3132 | } | 3225 | } |
| 3133 | 3226 | ||
| 3134 | static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev) | 3227 | static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev) |
| @@ -3143,9 +3236,11 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde | |||
| 3143 | if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) { | 3236 | if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) { |
| 3144 | dev_t tmp; | 3237 | dev_t tmp; |
| 3145 | 3238 | ||
| 3146 | READ_BUF(8); | 3239 | p = xdr_inline_decode(xdr, 8); |
| 3147 | READ32(major); | 3240 | if (unlikely(!p)) |
| 3148 | READ32(minor); | 3241 | goto out_overflow; |
| 3242 | major = be32_to_cpup(p++); | ||
| 3243 | minor = be32_to_cpup(p); | ||
| 3149 | tmp = MKDEV(major, minor); | 3244 | tmp = MKDEV(major, minor); |
| 3150 | if (MAJOR(tmp) == major && MINOR(tmp) == minor) | 3245 | if (MAJOR(tmp) == major && MINOR(tmp) == minor) |
| 3151 | *rdev = tmp; | 3246 | *rdev = tmp; |
| @@ -3154,6 +3249,9 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde | |||
| 3154 | } | 3249 | } |
| 3155 | dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor); | 3250 | dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor); |
| 3156 | return ret; | 3251 | return ret; |
| 3252 | out_overflow: | ||
| 3253 | print_overflow_msg(__func__, xdr); | ||
| 3254 | return -EIO; | ||
| 3157 | } | 3255 | } |
| 3158 | 3256 | ||
| 3159 | static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) | 3257 | static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) |
| @@ -3165,12 +3263,17 @@ static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin | |||
| 3165 | if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U))) | 3263 | if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U))) |
| 3166 | return -EIO; | 3264 | return -EIO; |
| 3167 | if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) { | 3265 | if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) { |
| 3168 | READ_BUF(8); | 3266 | p = xdr_inline_decode(xdr, 8); |
| 3169 | READ64(*res); | 3267 | if (unlikely(!p)) |
| 3268 | goto out_overflow; | ||
| 3269 | xdr_decode_hyper(p, res); | ||
| 3170 | bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL; | 3270 | bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL; |
| 3171 | } | 3271 | } |
| 3172 | dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res); | 3272 | dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res); |
| 3173 | return status; | 3273 | return status; |
| 3274 | out_overflow: | ||
| 3275 | print_overflow_msg(__func__, xdr); | ||
| 3276 | return -EIO; | ||
| 3174 | } | 3277 | } |
| 3175 | 3278 | ||
| 3176 | static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) | 3279 | static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) |
| @@ -3182,12 +3285,17 @@ static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint | |||
| 3182 | if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U))) | 3285 | if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U))) |
| 3183 | return -EIO; | 3286 | return -EIO; |
| 3184 | if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) { | 3287 | if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) { |
| 3185 | READ_BUF(8); | 3288 | p = xdr_inline_decode(xdr, 8); |
| 3186 | READ64(*res); | 3289 | if (unlikely(!p)) |
| 3290 | goto out_overflow; | ||
| 3291 | xdr_decode_hyper(p, res); | ||
| 3187 | bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE; | 3292 | bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE; |
| 3188 | } | 3293 | } |
| 3189 | dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res); | 3294 | dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res); |
| 3190 | return status; | 3295 | return status; |
| 3296 | out_overflow: | ||
| 3297 | print_overflow_msg(__func__, xdr); | ||
| 3298 | return -EIO; | ||
| 3191 | } | 3299 | } |
| 3192 | 3300 | ||
| 3193 | static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) | 3301 | static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) |
| @@ -3199,12 +3307,17 @@ static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uin | |||
| 3199 | if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U))) | 3307 | if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U))) |
| 3200 | return -EIO; | 3308 | return -EIO; |
| 3201 | if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) { | 3309 | if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) { |
| 3202 | READ_BUF(8); | 3310 | p = xdr_inline_decode(xdr, 8); |
| 3203 | READ64(*res); | 3311 | if (unlikely(!p)) |
| 3312 | goto out_overflow; | ||
| 3313 | xdr_decode_hyper(p, res); | ||
| 3204 | bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL; | 3314 | bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL; |
| 3205 | } | 3315 | } |
| 3206 | dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res); | 3316 | dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res); |
| 3207 | return status; | 3317 | return status; |
| 3318 | out_overflow: | ||
| 3319 | print_overflow_msg(__func__, xdr); | ||
| 3320 | return -EIO; | ||
| 3208 | } | 3321 | } |
| 3209 | 3322 | ||
| 3210 | static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used) | 3323 | static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used) |
| @@ -3216,14 +3329,19 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint | |||
| 3216 | if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U))) | 3329 | if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U))) |
| 3217 | return -EIO; | 3330 | return -EIO; |
| 3218 | if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) { | 3331 | if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) { |
| 3219 | READ_BUF(8); | 3332 | p = xdr_inline_decode(xdr, 8); |
| 3220 | READ64(*used); | 3333 | if (unlikely(!p)) |
| 3334 | goto out_overflow; | ||
| 3335 | xdr_decode_hyper(p, used); | ||
| 3221 | bitmap[1] &= ~FATTR4_WORD1_SPACE_USED; | 3336 | bitmap[1] &= ~FATTR4_WORD1_SPACE_USED; |
| 3222 | ret = NFS_ATTR_FATTR_SPACE_USED; | 3337 | ret = NFS_ATTR_FATTR_SPACE_USED; |
| 3223 | } | 3338 | } |
| 3224 | dprintk("%s: space used=%Lu\n", __func__, | 3339 | dprintk("%s: space used=%Lu\n", __func__, |
| 3225 | (unsigned long long)*used); | 3340 | (unsigned long long)*used); |
| 3226 | return ret; | 3341 | return ret; |
| 3342 | out_overflow: | ||
| 3343 | print_overflow_msg(__func__, xdr); | ||
| 3344 | return -EIO; | ||
| 3227 | } | 3345 | } |
| 3228 | 3346 | ||
| 3229 | static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time) | 3347 | static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time) |
| @@ -3232,12 +3350,17 @@ static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time) | |||
| 3232 | uint64_t sec; | 3350 | uint64_t sec; |
| 3233 | uint32_t nsec; | 3351 | uint32_t nsec; |
| 3234 | 3352 | ||
| 3235 | READ_BUF(12); | 3353 | p = xdr_inline_decode(xdr, 12); |
| 3236 | READ64(sec); | 3354 | if (unlikely(!p)) |
| 3237 | READ32(nsec); | 3355 | goto out_overflow; |
| 3356 | p = xdr_decode_hyper(p, &sec); | ||
| 3357 | nsec = be32_to_cpup(p); | ||
| 3238 | time->tv_sec = (time_t)sec; | 3358 | time->tv_sec = (time_t)sec; |
| 3239 | time->tv_nsec = (long)nsec; | 3359 | time->tv_nsec = (long)nsec; |
| 3240 | return 0; | 3360 | return 0; |
| 3361 | out_overflow: | ||
| 3362 | print_overflow_msg(__func__, xdr); | ||
| 3363 | return -EIO; | ||
| 3241 | } | 3364 | } |
| 3242 | 3365 | ||
| 3243 | static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) | 3366 | static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) |
| @@ -3315,11 +3438,16 @@ static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *c | |||
| 3315 | { | 3438 | { |
| 3316 | __be32 *p; | 3439 | __be32 *p; |
| 3317 | 3440 | ||
| 3318 | READ_BUF(20); | 3441 | p = xdr_inline_decode(xdr, 20); |
| 3319 | READ32(cinfo->atomic); | 3442 | if (unlikely(!p)) |
| 3320 | READ64(cinfo->before); | 3443 | goto out_overflow; |
| 3321 | READ64(cinfo->after); | 3444 | cinfo->atomic = be32_to_cpup(p++); |
| 3445 | p = xdr_decode_hyper(p, &cinfo->before); | ||
| 3446 | xdr_decode_hyper(p, &cinfo->after); | ||
| 3322 | return 0; | 3447 | return 0; |
| 3448 | out_overflow: | ||
| 3449 | print_overflow_msg(__func__, xdr); | ||
| 3450 | return -EIO; | ||
| 3323 | } | 3451 | } |
| 3324 | 3452 | ||
| 3325 | static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) | 3453 | static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) |
| @@ -3331,40 +3459,62 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) | |||
| 3331 | status = decode_op_hdr(xdr, OP_ACCESS); | 3459 | status = decode_op_hdr(xdr, OP_ACCESS); |
| 3332 | if (status) | 3460 | if (status) |
| 3333 | return status; | 3461 | return status; |
| 3334 | READ_BUF(8); | 3462 | p = xdr_inline_decode(xdr, 8); |
| 3335 | READ32(supp); | 3463 | if (unlikely(!p)) |
| 3336 | READ32(acc); | 3464 | goto out_overflow; |
| 3465 | supp = be32_to_cpup(p++); | ||
| 3466 | acc = be32_to_cpup(p); | ||
| 3337 | access->supported = supp; | 3467 | access->supported = supp; |
| 3338 | access->access = acc; | 3468 | access->access = acc; |
| 3339 | return 0; | 3469 | return 0; |
| 3470 | out_overflow: | ||
| 3471 | print_overflow_msg(__func__, xdr); | ||
| 3472 | return -EIO; | ||
| 3340 | } | 3473 | } |
| 3341 | 3474 | ||
| 3342 | static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) | 3475 | static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len) |
| 3343 | { | 3476 | { |
| 3344 | __be32 *p; | 3477 | __be32 *p; |
| 3478 | |||
| 3479 | p = xdr_inline_decode(xdr, len); | ||
| 3480 | if (likely(p)) { | ||
| 3481 | memcpy(buf, p, len); | ||
| 3482 | return 0; | ||
| 3483 | } | ||
| 3484 | print_overflow_msg(__func__, xdr); | ||
| 3485 | return -EIO; | ||
| 3486 | } | ||
| 3487 | |||
| 3488 | static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) | ||
| 3489 | { | ||
| 3490 | return decode_opaque_fixed(xdr, stateid->data, NFS4_STATEID_SIZE); | ||
| 3491 | } | ||
| 3492 | |||
| 3493 | static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) | ||
| 3494 | { | ||
| 3345 | int status; | 3495 | int status; |
| 3346 | 3496 | ||
| 3347 | status = decode_op_hdr(xdr, OP_CLOSE); | 3497 | status = decode_op_hdr(xdr, OP_CLOSE); |
| 3348 | if (status != -EIO) | 3498 | if (status != -EIO) |
| 3349 | nfs_increment_open_seqid(status, res->seqid); | 3499 | nfs_increment_open_seqid(status, res->seqid); |
| 3350 | if (status) | 3500 | if (!status) |
| 3351 | return status; | 3501 | status = decode_stateid(xdr, &res->stateid); |
| 3352 | READ_BUF(NFS4_STATEID_SIZE); | 3502 | return status; |
| 3353 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | 3503 | } |
| 3354 | return 0; | 3504 | |
| 3505 | static int decode_verifier(struct xdr_stream *xdr, void *verifier) | ||
| 3506 | { | ||
| 3507 | return decode_opaque_fixed(xdr, verifier, 8); | ||
| 3355 | } | 3508 | } |
| 3356 | 3509 | ||
| 3357 | static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) | 3510 | static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) |
| 3358 | { | 3511 | { |
| 3359 | __be32 *p; | ||
| 3360 | int status; | 3512 | int status; |
| 3361 | 3513 | ||
| 3362 | status = decode_op_hdr(xdr, OP_COMMIT); | 3514 | status = decode_op_hdr(xdr, OP_COMMIT); |
| 3363 | if (status) | 3515 | if (!status) |
| 3364 | return status; | 3516 | status = decode_verifier(xdr, res->verf->verifier); |
| 3365 | READ_BUF(8); | 3517 | return status; |
| 3366 | COPYMEM(res->verf->verifier, 8); | ||
| 3367 | return 0; | ||
| 3368 | } | 3518 | } |
| 3369 | 3519 | ||
| 3370 | static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) | 3520 | static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) |
| @@ -3378,10 +3528,16 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) | |||
| 3378 | return status; | 3528 | return status; |
| 3379 | if ((status = decode_change_info(xdr, cinfo))) | 3529 | if ((status = decode_change_info(xdr, cinfo))) |
| 3380 | return status; | 3530 | return status; |
| 3381 | READ_BUF(4); | 3531 | p = xdr_inline_decode(xdr, 4); |
| 3382 | READ32(bmlen); | 3532 | if (unlikely(!p)) |
| 3383 | READ_BUF(bmlen << 2); | 3533 | goto out_overflow; |
| 3384 | return 0; | 3534 | bmlen = be32_to_cpup(p); |
| 3535 | p = xdr_inline_decode(xdr, bmlen << 2); | ||
| 3536 | if (likely(p)) | ||
| 3537 | return 0; | ||
| 3538 | out_overflow: | ||
| 3539 | print_overflow_msg(__func__, xdr); | ||
| 3540 | return -EIO; | ||
| 3385 | } | 3541 | } |
| 3386 | 3542 | ||
| 3387 | static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res) | 3543 | static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res) |
| @@ -3466,7 +3622,8 @@ xdr_error: | |||
| 3466 | return status; | 3622 | return status; |
| 3467 | } | 3623 | } |
| 3468 | 3624 | ||
| 3469 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server) | 3625 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, |
| 3626 | const struct nfs_server *server, int may_sleep) | ||
| 3470 | { | 3627 | { |
| 3471 | __be32 *savep; | 3628 | __be32 *savep; |
| 3472 | uint32_t attrlen, | 3629 | uint32_t attrlen, |
| @@ -3538,12 +3695,14 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons | |||
| 3538 | goto xdr_error; | 3695 | goto xdr_error; |
| 3539 | fattr->valid |= status; | 3696 | fattr->valid |= status; |
| 3540 | 3697 | ||
| 3541 | status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid); | 3698 | status = decode_attr_owner(xdr, bitmap, server->nfs_client, |
| 3699 | &fattr->uid, may_sleep); | ||
| 3542 | if (status < 0) | 3700 | if (status < 0) |
| 3543 | goto xdr_error; | 3701 | goto xdr_error; |
| 3544 | fattr->valid |= status; | 3702 | fattr->valid |= status; |
| 3545 | 3703 | ||
| 3546 | status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid); | 3704 | status = decode_attr_group(xdr, bitmap, server->nfs_client, |
| 3705 | &fattr->gid, may_sleep); | ||
| 3547 | if (status < 0) | 3706 | if (status < 0) |
| 3548 | goto xdr_error; | 3707 | goto xdr_error; |
| 3549 | fattr->valid |= status; | 3708 | fattr->valid |= status; |
| @@ -3633,14 +3792,21 @@ static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh) | |||
| 3633 | if (status) | 3792 | if (status) |
| 3634 | return status; | 3793 | return status; |
| 3635 | 3794 | ||
| 3636 | READ_BUF(4); | 3795 | p = xdr_inline_decode(xdr, 4); |
| 3637 | READ32(len); | 3796 | if (unlikely(!p)) |
| 3797 | goto out_overflow; | ||
| 3798 | len = be32_to_cpup(p); | ||
| 3638 | if (len > NFS4_FHSIZE) | 3799 | if (len > NFS4_FHSIZE) |
| 3639 | return -EIO; | 3800 | return -EIO; |
| 3640 | fh->size = len; | 3801 | fh->size = len; |
| 3641 | READ_BUF(len); | 3802 | p = xdr_inline_decode(xdr, len); |
| 3642 | COPYMEM(fh->data, len); | 3803 | if (unlikely(!p)) |
| 3804 | goto out_overflow; | ||
| 3805 | memcpy(fh->data, p, len); | ||
| 3643 | return 0; | 3806 | return 0; |
| 3807 | out_overflow: | ||
| 3808 | print_overflow_msg(__func__, xdr); | ||
| 3809 | return -EIO; | ||
| 3644 | } | 3810 | } |
| 3645 | 3811 | ||
| 3646 | static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) | 3812 | static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) |
| @@ -3662,10 +3828,12 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) | |||
| 3662 | __be32 *p; | 3828 | __be32 *p; |
| 3663 | uint32_t namelen, type; | 3829 | uint32_t namelen, type; |
| 3664 | 3830 | ||
| 3665 | READ_BUF(32); | 3831 | p = xdr_inline_decode(xdr, 32); |
| 3666 | READ64(offset); | 3832 | if (unlikely(!p)) |
| 3667 | READ64(length); | 3833 | goto out_overflow; |
| 3668 | READ32(type); | 3834 | p = xdr_decode_hyper(p, &offset); |
| 3835 | p = xdr_decode_hyper(p, &length); | ||
| 3836 | type = be32_to_cpup(p++); | ||
| 3669 | if (fl != NULL) { | 3837 | if (fl != NULL) { |
| 3670 | fl->fl_start = (loff_t)offset; | 3838 | fl->fl_start = (loff_t)offset; |
| 3671 | fl->fl_end = fl->fl_start + (loff_t)length - 1; | 3839 | fl->fl_end = fl->fl_start + (loff_t)length - 1; |
| @@ -3676,23 +3844,27 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) | |||
| 3676 | fl->fl_type = F_RDLCK; | 3844 | fl->fl_type = F_RDLCK; |
| 3677 | fl->fl_pid = 0; | 3845 | fl->fl_pid = 0; |
| 3678 | } | 3846 | } |
| 3679 | READ64(clientid); | 3847 | p = xdr_decode_hyper(p, &clientid); |
| 3680 | READ32(namelen); | 3848 | namelen = be32_to_cpup(p); |
| 3681 | READ_BUF(namelen); | 3849 | p = xdr_inline_decode(xdr, namelen); |
| 3682 | return -NFS4ERR_DENIED; | 3850 | if (likely(p)) |
| 3851 | return -NFS4ERR_DENIED; | ||
| 3852 | out_overflow: | ||
| 3853 | print_overflow_msg(__func__, xdr); | ||
| 3854 | return -EIO; | ||
| 3683 | } | 3855 | } |
| 3684 | 3856 | ||
| 3685 | static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res) | 3857 | static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res) |
| 3686 | { | 3858 | { |
| 3687 | __be32 *p; | ||
| 3688 | int status; | 3859 | int status; |
| 3689 | 3860 | ||
| 3690 | status = decode_op_hdr(xdr, OP_LOCK); | 3861 | status = decode_op_hdr(xdr, OP_LOCK); |
| 3691 | if (status == -EIO) | 3862 | if (status == -EIO) |
| 3692 | goto out; | 3863 | goto out; |
| 3693 | if (status == 0) { | 3864 | if (status == 0) { |
| 3694 | READ_BUF(NFS4_STATEID_SIZE); | 3865 | status = decode_stateid(xdr, &res->stateid); |
| 3695 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | 3866 | if (unlikely(status)) |
| 3867 | goto out; | ||
| 3696 | } else if (status == -NFS4ERR_DENIED) | 3868 | } else if (status == -NFS4ERR_DENIED) |
| 3697 | status = decode_lock_denied(xdr, NULL); | 3869 | status = decode_lock_denied(xdr, NULL); |
| 3698 | if (res->open_seqid != NULL) | 3870 | if (res->open_seqid != NULL) |
| @@ -3713,16 +3885,13 @@ static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res) | |||
| 3713 | 3885 | ||
| 3714 | static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res) | 3886 | static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res) |
| 3715 | { | 3887 | { |
| 3716 | __be32 *p; | ||
| 3717 | int status; | 3888 | int status; |
| 3718 | 3889 | ||
| 3719 | status = decode_op_hdr(xdr, OP_LOCKU); | 3890 | status = decode_op_hdr(xdr, OP_LOCKU); |
| 3720 | if (status != -EIO) | 3891 | if (status != -EIO) |
| 3721 | nfs_increment_lock_seqid(status, res->seqid); | 3892 | nfs_increment_lock_seqid(status, res->seqid); |
| 3722 | if (status == 0) { | 3893 | if (status == 0) |
| 3723 | READ_BUF(NFS4_STATEID_SIZE); | 3894 | status = decode_stateid(xdr, &res->stateid); |
| 3724 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | ||
| 3725 | } | ||
| 3726 | return status; | 3895 | return status; |
| 3727 | } | 3896 | } |
| 3728 | 3897 | ||
| @@ -3737,34 +3906,46 @@ static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize) | |||
| 3737 | __be32 *p; | 3906 | __be32 *p; |
| 3738 | uint32_t limit_type, nblocks, blocksize; | 3907 | uint32_t limit_type, nblocks, blocksize; |
| 3739 | 3908 | ||
| 3740 | READ_BUF(12); | 3909 | p = xdr_inline_decode(xdr, 12); |
| 3741 | READ32(limit_type); | 3910 | if (unlikely(!p)) |
| 3911 | goto out_overflow; | ||
| 3912 | limit_type = be32_to_cpup(p++); | ||
| 3742 | switch (limit_type) { | 3913 | switch (limit_type) { |
| 3743 | case 1: | 3914 | case 1: |
| 3744 | READ64(*maxsize); | 3915 | xdr_decode_hyper(p, maxsize); |
| 3745 | break; | 3916 | break; |
| 3746 | case 2: | 3917 | case 2: |
| 3747 | READ32(nblocks); | 3918 | nblocks = be32_to_cpup(p++); |
| 3748 | READ32(blocksize); | 3919 | blocksize = be32_to_cpup(p); |
| 3749 | *maxsize = (uint64_t)nblocks * (uint64_t)blocksize; | 3920 | *maxsize = (uint64_t)nblocks * (uint64_t)blocksize; |
| 3750 | } | 3921 | } |
| 3751 | return 0; | 3922 | return 0; |
| 3923 | out_overflow: | ||
| 3924 | print_overflow_msg(__func__, xdr); | ||
| 3925 | return -EIO; | ||
| 3752 | } | 3926 | } |
| 3753 | 3927 | ||
| 3754 | static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) | 3928 | static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) |
| 3755 | { | 3929 | { |
| 3756 | __be32 *p; | 3930 | __be32 *p; |
| 3757 | uint32_t delegation_type; | 3931 | uint32_t delegation_type; |
| 3932 | int status; | ||
| 3758 | 3933 | ||
| 3759 | READ_BUF(4); | 3934 | p = xdr_inline_decode(xdr, 4); |
| 3760 | READ32(delegation_type); | 3935 | if (unlikely(!p)) |
| 3936 | goto out_overflow; | ||
| 3937 | delegation_type = be32_to_cpup(p); | ||
| 3761 | if (delegation_type == NFS4_OPEN_DELEGATE_NONE) { | 3938 | if (delegation_type == NFS4_OPEN_DELEGATE_NONE) { |
| 3762 | res->delegation_type = 0; | 3939 | res->delegation_type = 0; |
| 3763 | return 0; | 3940 | return 0; |
| 3764 | } | 3941 | } |
| 3765 | READ_BUF(NFS4_STATEID_SIZE+4); | 3942 | status = decode_stateid(xdr, &res->delegation); |
| 3766 | COPYMEM(res->delegation.data, NFS4_STATEID_SIZE); | 3943 | if (unlikely(status)) |
| 3767 | READ32(res->do_recall); | 3944 | return status; |
| 3945 | p = xdr_inline_decode(xdr, 4); | ||
| 3946 | if (unlikely(!p)) | ||
| 3947 | goto out_overflow; | ||
| 3948 | res->do_recall = be32_to_cpup(p); | ||
| 3768 | 3949 | ||
| 3769 | switch (delegation_type) { | 3950 | switch (delegation_type) { |
| 3770 | case NFS4_OPEN_DELEGATE_READ: | 3951 | case NFS4_OPEN_DELEGATE_READ: |
| @@ -3776,6 +3957,9 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) | |||
| 3776 | return -EIO; | 3957 | return -EIO; |
| 3777 | } | 3958 | } |
| 3778 | return decode_ace(xdr, NULL, res->server->nfs_client); | 3959 | return decode_ace(xdr, NULL, res->server->nfs_client); |
| 3960 | out_overflow: | ||
| 3961 | print_overflow_msg(__func__, xdr); | ||
| 3962 | return -EIO; | ||
| 3779 | } | 3963 | } |
| 3780 | 3964 | ||
| 3781 | static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) | 3965 | static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) |
| @@ -3787,23 +3971,27 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) | |||
| 3787 | status = decode_op_hdr(xdr, OP_OPEN); | 3971 | status = decode_op_hdr(xdr, OP_OPEN); |
| 3788 | if (status != -EIO) | 3972 | if (status != -EIO) |
| 3789 | nfs_increment_open_seqid(status, res->seqid); | 3973 | nfs_increment_open_seqid(status, res->seqid); |
| 3790 | if (status) | 3974 | if (!status) |
| 3975 | status = decode_stateid(xdr, &res->stateid); | ||
| 3976 | if (unlikely(status)) | ||
| 3791 | return status; | 3977 | return status; |
| 3792 | READ_BUF(NFS4_STATEID_SIZE); | ||
| 3793 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | ||
| 3794 | 3978 | ||
| 3795 | decode_change_info(xdr, &res->cinfo); | 3979 | decode_change_info(xdr, &res->cinfo); |
| 3796 | 3980 | ||
| 3797 | READ_BUF(8); | 3981 | p = xdr_inline_decode(xdr, 8); |
| 3798 | READ32(res->rflags); | 3982 | if (unlikely(!p)) |
| 3799 | READ32(bmlen); | 3983 | goto out_overflow; |
| 3984 | res->rflags = be32_to_cpup(p++); | ||
| 3985 | bmlen = be32_to_cpup(p); | ||
| 3800 | if (bmlen > 10) | 3986 | if (bmlen > 10) |
| 3801 | goto xdr_error; | 3987 | goto xdr_error; |
| 3802 | 3988 | ||
| 3803 | READ_BUF(bmlen << 2); | 3989 | p = xdr_inline_decode(xdr, bmlen << 2); |
| 3990 | if (unlikely(!p)) | ||
| 3991 | goto out_overflow; | ||
| 3804 | savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE); | 3992 | savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE); |
| 3805 | for (i = 0; i < savewords; ++i) | 3993 | for (i = 0; i < savewords; ++i) |
| 3806 | READ32(res->attrset[i]); | 3994 | res->attrset[i] = be32_to_cpup(p++); |
| 3807 | for (; i < NFS4_BITMAP_SIZE; i++) | 3995 | for (; i < NFS4_BITMAP_SIZE; i++) |
| 3808 | res->attrset[i] = 0; | 3996 | res->attrset[i] = 0; |
| 3809 | 3997 | ||
| @@ -3811,36 +3999,33 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) | |||
| 3811 | xdr_error: | 3999 | xdr_error: |
| 3812 | dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen); | 4000 | dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen); |
| 3813 | return -EIO; | 4001 | return -EIO; |
| 4002 | out_overflow: | ||
| 4003 | print_overflow_msg(__func__, xdr); | ||
| 4004 | return -EIO; | ||
| 3814 | } | 4005 | } |
| 3815 | 4006 | ||
| 3816 | static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res) | 4007 | static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res) |
| 3817 | { | 4008 | { |
| 3818 | __be32 *p; | ||
| 3819 | int status; | 4009 | int status; |
| 3820 | 4010 | ||
| 3821 | status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); | 4011 | status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); |
| 3822 | if (status != -EIO) | 4012 | if (status != -EIO) |
| 3823 | nfs_increment_open_seqid(status, res->seqid); | 4013 | nfs_increment_open_seqid(status, res->seqid); |
| 3824 | if (status) | 4014 | if (!status) |
| 3825 | return status; | 4015 | status = decode_stateid(xdr, &res->stateid); |
| 3826 | READ_BUF(NFS4_STATEID_SIZE); | 4016 | return status; |
| 3827 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | ||
| 3828 | return 0; | ||
| 3829 | } | 4017 | } |
| 3830 | 4018 | ||
| 3831 | static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res) | 4019 | static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res) |
| 3832 | { | 4020 | { |
| 3833 | __be32 *p; | ||
| 3834 | int status; | 4021 | int status; |
| 3835 | 4022 | ||
| 3836 | status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE); | 4023 | status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE); |
| 3837 | if (status != -EIO) | 4024 | if (status != -EIO) |
| 3838 | nfs_increment_open_seqid(status, res->seqid); | 4025 | nfs_increment_open_seqid(status, res->seqid); |
| 3839 | if (status) | 4026 | if (!status) |
| 3840 | return status; | 4027 | status = decode_stateid(xdr, &res->stateid); |
| 3841 | READ_BUF(NFS4_STATEID_SIZE); | 4028 | return status; |
| 3842 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | ||
| 3843 | return 0; | ||
| 3844 | } | 4029 | } |
| 3845 | 4030 | ||
| 3846 | static int decode_putfh(struct xdr_stream *xdr) | 4031 | static int decode_putfh(struct xdr_stream *xdr) |
| @@ -3863,9 +4048,11 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_ | |||
| 3863 | status = decode_op_hdr(xdr, OP_READ); | 4048 | status = decode_op_hdr(xdr, OP_READ); |
| 3864 | if (status) | 4049 | if (status) |
| 3865 | return status; | 4050 | return status; |
| 3866 | READ_BUF(8); | 4051 | p = xdr_inline_decode(xdr, 8); |
| 3867 | READ32(eof); | 4052 | if (unlikely(!p)) |
| 3868 | READ32(count); | 4053 | goto out_overflow; |
| 4054 | eof = be32_to_cpup(p++); | ||
| 4055 | count = be32_to_cpup(p); | ||
| 3869 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 4056 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
| 3870 | recvd = req->rq_rcv_buf.len - hdrlen; | 4057 | recvd = req->rq_rcv_buf.len - hdrlen; |
| 3871 | if (count > recvd) { | 4058 | if (count > recvd) { |
| @@ -3878,6 +4065,9 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_ | |||
| 3878 | res->eof = eof; | 4065 | res->eof = eof; |
| 3879 | res->count = count; | 4066 | res->count = count; |
| 3880 | return 0; | 4067 | return 0; |
| 4068 | out_overflow: | ||
| 4069 | print_overflow_msg(__func__, xdr); | ||
| 4070 | return -EIO; | ||
| 3881 | } | 4071 | } |
| 3882 | 4072 | ||
| 3883 | static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) | 4073 | static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) |
| @@ -3892,17 +4082,17 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
| 3892 | int status; | 4082 | int status; |
| 3893 | 4083 | ||
| 3894 | status = decode_op_hdr(xdr, OP_READDIR); | 4084 | status = decode_op_hdr(xdr, OP_READDIR); |
| 3895 | if (status) | 4085 | if (!status) |
| 4086 | status = decode_verifier(xdr, readdir->verifier.data); | ||
| 4087 | if (unlikely(status)) | ||
| 3896 | return status; | 4088 | return status; |
| 3897 | READ_BUF(8); | ||
| 3898 | COPYMEM(readdir->verifier.data, 8); | ||
| 3899 | dprintk("%s: verifier = %08x:%08x\n", | 4089 | dprintk("%s: verifier = %08x:%08x\n", |
| 3900 | __func__, | 4090 | __func__, |
| 3901 | ((u32 *)readdir->verifier.data)[0], | 4091 | ((u32 *)readdir->verifier.data)[0], |
| 3902 | ((u32 *)readdir->verifier.data)[1]); | 4092 | ((u32 *)readdir->verifier.data)[1]); |
| 3903 | 4093 | ||
| 3904 | 4094 | ||
| 3905 | hdrlen = (char *) p - (char *) iov->iov_base; | 4095 | hdrlen = (char *) xdr->p - (char *) iov->iov_base; |
| 3906 | recvd = rcvbuf->len - hdrlen; | 4096 | recvd = rcvbuf->len - hdrlen; |
| 3907 | if (pglen > recvd) | 4097 | if (pglen > recvd) |
| 3908 | pglen = recvd; | 4098 | pglen = recvd; |
| @@ -3990,8 +4180,10 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | |||
| 3990 | return status; | 4180 | return status; |
| 3991 | 4181 | ||
| 3992 | /* Convert length of symlink */ | 4182 | /* Convert length of symlink */ |
| 3993 | READ_BUF(4); | 4183 | p = xdr_inline_decode(xdr, 4); |
| 3994 | READ32(len); | 4184 | if (unlikely(!p)) |
| 4185 | goto out_overflow; | ||
| 4186 | len = be32_to_cpup(p); | ||
| 3995 | if (len >= rcvbuf->page_len || len <= 0) { | 4187 | if (len >= rcvbuf->page_len || len <= 0) { |
| 3996 | dprintk("nfs: server returned giant symlink!\n"); | 4188 | dprintk("nfs: server returned giant symlink!\n"); |
| 3997 | return -ENAMETOOLONG; | 4189 | return -ENAMETOOLONG; |
| @@ -4015,6 +4207,9 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | |||
| 4015 | kaddr[len+rcvbuf->page_base] = '\0'; | 4207 | kaddr[len+rcvbuf->page_base] = '\0'; |
| 4016 | kunmap_atomic(kaddr, KM_USER0); | 4208 | kunmap_atomic(kaddr, KM_USER0); |
| 4017 | return 0; | 4209 | return 0; |
| 4210 | out_overflow: | ||
| 4211 | print_overflow_msg(__func__, xdr); | ||
| 4212 | return -EIO; | ||
| 4018 | } | 4213 | } |
| 4019 | 4214 | ||
| 4020 | static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) | 4215 | static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) |
| @@ -4112,10 +4307,16 @@ static int decode_setattr(struct xdr_stream *xdr) | |||
| 4112 | status = decode_op_hdr(xdr, OP_SETATTR); | 4307 | status = decode_op_hdr(xdr, OP_SETATTR); |
| 4113 | if (status) | 4308 | if (status) |
| 4114 | return status; | 4309 | return status; |
| 4115 | READ_BUF(4); | 4310 | p = xdr_inline_decode(xdr, 4); |
| 4116 | READ32(bmlen); | 4311 | if (unlikely(!p)) |
| 4117 | READ_BUF(bmlen << 2); | 4312 | goto out_overflow; |
| 4118 | return 0; | 4313 | bmlen = be32_to_cpup(p); |
| 4314 | p = xdr_inline_decode(xdr, bmlen << 2); | ||
| 4315 | if (likely(p)) | ||
| 4316 | return 0; | ||
| 4317 | out_overflow: | ||
| 4318 | print_overflow_msg(__func__, xdr); | ||
| 4319 | return -EIO; | ||
| 4119 | } | 4320 | } |
| 4120 | 4321 | ||
| 4121 | static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) | 4322 | static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) |
| @@ -4124,35 +4325,50 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) | |||
| 4124 | uint32_t opnum; | 4325 | uint32_t opnum; |
| 4125 | int32_t nfserr; | 4326 | int32_t nfserr; |
| 4126 | 4327 | ||
| 4127 | READ_BUF(8); | 4328 | p = xdr_inline_decode(xdr, 8); |
| 4128 | READ32(opnum); | 4329 | if (unlikely(!p)) |
| 4330 | goto out_overflow; | ||
| 4331 | opnum = be32_to_cpup(p++); | ||
| 4129 | if (opnum != OP_SETCLIENTID) { | 4332 | if (opnum != OP_SETCLIENTID) { |
| 4130 | dprintk("nfs: decode_setclientid: Server returned operation" | 4333 | dprintk("nfs: decode_setclientid: Server returned operation" |
| 4131 | " %d\n", opnum); | 4334 | " %d\n", opnum); |
| 4132 | return -EIO; | 4335 | return -EIO; |
| 4133 | } | 4336 | } |
| 4134 | READ32(nfserr); | 4337 | nfserr = be32_to_cpup(p); |
| 4135 | if (nfserr == NFS_OK) { | 4338 | if (nfserr == NFS_OK) { |
| 4136 | READ_BUF(8 + NFS4_VERIFIER_SIZE); | 4339 | p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE); |
| 4137 | READ64(clp->cl_clientid); | 4340 | if (unlikely(!p)) |
| 4138 | COPYMEM(clp->cl_confirm.data, NFS4_VERIFIER_SIZE); | 4341 | goto out_overflow; |
| 4342 | p = xdr_decode_hyper(p, &clp->cl_clientid); | ||
| 4343 | memcpy(clp->cl_confirm.data, p, NFS4_VERIFIER_SIZE); | ||
| 4139 | } else if (nfserr == NFSERR_CLID_INUSE) { | 4344 | } else if (nfserr == NFSERR_CLID_INUSE) { |
| 4140 | uint32_t len; | 4345 | uint32_t len; |
| 4141 | 4346 | ||
| 4142 | /* skip netid string */ | 4347 | /* skip netid string */ |
| 4143 | READ_BUF(4); | 4348 | p = xdr_inline_decode(xdr, 4); |
| 4144 | READ32(len); | 4349 | if (unlikely(!p)) |
| 4145 | READ_BUF(len); | 4350 | goto out_overflow; |
| 4351 | len = be32_to_cpup(p); | ||
| 4352 | p = xdr_inline_decode(xdr, len); | ||
| 4353 | if (unlikely(!p)) | ||
| 4354 | goto out_overflow; | ||
| 4146 | 4355 | ||
| 4147 | /* skip uaddr string */ | 4356 | /* skip uaddr string */ |
| 4148 | READ_BUF(4); | 4357 | p = xdr_inline_decode(xdr, 4); |
| 4149 | READ32(len); | 4358 | if (unlikely(!p)) |
| 4150 | READ_BUF(len); | 4359 | goto out_overflow; |
| 4360 | len = be32_to_cpup(p); | ||
| 4361 | p = xdr_inline_decode(xdr, len); | ||
| 4362 | if (unlikely(!p)) | ||
| 4363 | goto out_overflow; | ||
| 4151 | return -NFSERR_CLID_INUSE; | 4364 | return -NFSERR_CLID_INUSE; |
| 4152 | } else | 4365 | } else |
| 4153 | return nfs4_stat_to_errno(nfserr); | 4366 | return nfs4_stat_to_errno(nfserr); |
| 4154 | 4367 | ||
| 4155 | return 0; | 4368 | return 0; |
| 4369 | out_overflow: | ||
| 4370 | print_overflow_msg(__func__, xdr); | ||
| 4371 | return -EIO; | ||
| 4156 | } | 4372 | } |
| 4157 | 4373 | ||
| 4158 | static int decode_setclientid_confirm(struct xdr_stream *xdr) | 4374 | static int decode_setclientid_confirm(struct xdr_stream *xdr) |
| @@ -4169,11 +4385,16 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) | |||
| 4169 | if (status) | 4385 | if (status) |
| 4170 | return status; | 4386 | return status; |
| 4171 | 4387 | ||
| 4172 | READ_BUF(16); | 4388 | p = xdr_inline_decode(xdr, 16); |
| 4173 | READ32(res->count); | 4389 | if (unlikely(!p)) |
| 4174 | READ32(res->verf->committed); | 4390 | goto out_overflow; |
| 4175 | COPYMEM(res->verf->verifier, 8); | 4391 | res->count = be32_to_cpup(p++); |
| 4392 | res->verf->committed = be32_to_cpup(p++); | ||
| 4393 | memcpy(res->verf->verifier, p, 8); | ||
| 4176 | return 0; | 4394 | return 0; |
| 4395 | out_overflow: | ||
| 4396 | print_overflow_msg(__func__, xdr); | ||
| 4397 | return -EIO; | ||
| 4177 | } | 4398 | } |
| 4178 | 4399 | ||
| 4179 | static int decode_delegreturn(struct xdr_stream *xdr) | 4400 | static int decode_delegreturn(struct xdr_stream *xdr) |
| @@ -4187,6 +4408,7 @@ static int decode_exchange_id(struct xdr_stream *xdr, | |||
| 4187 | { | 4408 | { |
| 4188 | __be32 *p; | 4409 | __be32 *p; |
| 4189 | uint32_t dummy; | 4410 | uint32_t dummy; |
| 4411 | char *dummy_str; | ||
| 4190 | int status; | 4412 | int status; |
| 4191 | struct nfs_client *clp = res->client; | 4413 | struct nfs_client *clp = res->client; |
| 4192 | 4414 | ||
| @@ -4194,36 +4416,45 @@ static int decode_exchange_id(struct xdr_stream *xdr, | |||
| 4194 | if (status) | 4416 | if (status) |
| 4195 | return status; | 4417 | return status; |
| 4196 | 4418 | ||
| 4197 | READ_BUF(8); | 4419 | p = xdr_inline_decode(xdr, 8); |
| 4198 | READ64(clp->cl_ex_clid); | 4420 | if (unlikely(!p)) |
| 4199 | READ_BUF(12); | 4421 | goto out_overflow; |
| 4200 | READ32(clp->cl_seqid); | 4422 | xdr_decode_hyper(p, &clp->cl_ex_clid); |
| 4201 | READ32(clp->cl_exchange_flags); | 4423 | p = xdr_inline_decode(xdr, 12); |
| 4424 | if (unlikely(!p)) | ||
| 4425 | goto out_overflow; | ||
| 4426 | clp->cl_seqid = be32_to_cpup(p++); | ||
| 4427 | clp->cl_exchange_flags = be32_to_cpup(p++); | ||
| 4202 | 4428 | ||
| 4203 | /* We ask for SP4_NONE */ | 4429 | /* We ask for SP4_NONE */ |
| 4204 | READ32(dummy); | 4430 | dummy = be32_to_cpup(p); |
| 4205 | if (dummy != SP4_NONE) | 4431 | if (dummy != SP4_NONE) |
| 4206 | return -EIO; | 4432 | return -EIO; |
| 4207 | 4433 | ||
| 4208 | /* Throw away minor_id */ | 4434 | /* Throw away minor_id */ |
| 4209 | READ_BUF(8); | 4435 | p = xdr_inline_decode(xdr, 8); |
| 4436 | if (unlikely(!p)) | ||
| 4437 | goto out_overflow; | ||
| 4210 | 4438 | ||
| 4211 | /* Throw away Major id */ | 4439 | /* Throw away Major id */ |
| 4212 | READ_BUF(4); | 4440 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); |
| 4213 | READ32(dummy); | 4441 | if (unlikely(status)) |
| 4214 | READ_BUF(dummy); | 4442 | return status; |
| 4215 | 4443 | ||
| 4216 | /* Throw away server_scope */ | 4444 | /* Throw away server_scope */ |
| 4217 | READ_BUF(4); | 4445 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); |
| 4218 | READ32(dummy); | 4446 | if (unlikely(status)) |
| 4219 | READ_BUF(dummy); | 4447 | return status; |
| 4220 | 4448 | ||
| 4221 | /* Throw away Implementation id array */ | 4449 | /* Throw away Implementation id array */ |
| 4222 | READ_BUF(4); | 4450 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); |
| 4223 | READ32(dummy); | 4451 | if (unlikely(status)) |
| 4224 | READ_BUF(dummy); | 4452 | return status; |
| 4225 | 4453 | ||
| 4226 | return 0; | 4454 | return 0; |
| 4455 | out_overflow: | ||
| 4456 | print_overflow_msg(__func__, xdr); | ||
| 4457 | return -EIO; | ||
| 4227 | } | 4458 | } |
| 4228 | 4459 | ||
| 4229 | static int decode_chan_attrs(struct xdr_stream *xdr, | 4460 | static int decode_chan_attrs(struct xdr_stream *xdr, |
| @@ -4232,22 +4463,35 @@ static int decode_chan_attrs(struct xdr_stream *xdr, | |||
| 4232 | __be32 *p; | 4463 | __be32 *p; |
| 4233 | u32 nr_attrs; | 4464 | u32 nr_attrs; |
| 4234 | 4465 | ||
| 4235 | READ_BUF(28); | 4466 | p = xdr_inline_decode(xdr, 28); |
| 4236 | READ32(attrs->headerpadsz); | 4467 | if (unlikely(!p)) |
| 4237 | READ32(attrs->max_rqst_sz); | 4468 | goto out_overflow; |
| 4238 | READ32(attrs->max_resp_sz); | 4469 | attrs->headerpadsz = be32_to_cpup(p++); |
| 4239 | READ32(attrs->max_resp_sz_cached); | 4470 | attrs->max_rqst_sz = be32_to_cpup(p++); |
| 4240 | READ32(attrs->max_ops); | 4471 | attrs->max_resp_sz = be32_to_cpup(p++); |
| 4241 | READ32(attrs->max_reqs); | 4472 | attrs->max_resp_sz_cached = be32_to_cpup(p++); |
| 4242 | READ32(nr_attrs); | 4473 | attrs->max_ops = be32_to_cpup(p++); |
| 4474 | attrs->max_reqs = be32_to_cpup(p++); | ||
| 4475 | nr_attrs = be32_to_cpup(p); | ||
| 4243 | if (unlikely(nr_attrs > 1)) { | 4476 | if (unlikely(nr_attrs > 1)) { |
| 4244 | printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n", | 4477 | printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n", |
| 4245 | __func__, nr_attrs); | 4478 | __func__, nr_attrs); |
| 4246 | return -EINVAL; | 4479 | return -EINVAL; |
| 4247 | } | 4480 | } |
| 4248 | if (nr_attrs == 1) | 4481 | if (nr_attrs == 1) { |
| 4249 | READ_BUF(4); /* skip rdma_attrs */ | 4482 | p = xdr_inline_decode(xdr, 4); /* skip rdma_attrs */ |
| 4483 | if (unlikely(!p)) | ||
| 4484 | goto out_overflow; | ||
| 4485 | } | ||
| 4250 | return 0; | 4486 | return 0; |
| 4487 | out_overflow: | ||
| 4488 | print_overflow_msg(__func__, xdr); | ||
| 4489 | return -EIO; | ||
| 4490 | } | ||
| 4491 | |||
| 4492 | static int decode_sessionid(struct xdr_stream *xdr, struct nfs4_sessionid *sid) | ||
| 4493 | { | ||
| 4494 | return decode_opaque_fixed(xdr, sid->data, NFS4_MAX_SESSIONID_LEN); | ||
| 4251 | } | 4495 | } |
| 4252 | 4496 | ||
| 4253 | static int decode_create_session(struct xdr_stream *xdr, | 4497 | static int decode_create_session(struct xdr_stream *xdr, |
| @@ -4259,24 +4503,26 @@ static int decode_create_session(struct xdr_stream *xdr, | |||
| 4259 | struct nfs4_session *session = clp->cl_session; | 4503 | struct nfs4_session *session = clp->cl_session; |
| 4260 | 4504 | ||
| 4261 | status = decode_op_hdr(xdr, OP_CREATE_SESSION); | 4505 | status = decode_op_hdr(xdr, OP_CREATE_SESSION); |
| 4262 | 4506 | if (!status) | |
| 4263 | if (status) | 4507 | status = decode_sessionid(xdr, &session->sess_id); |
| 4508 | if (unlikely(status)) | ||
| 4264 | return status; | 4509 | return status; |
| 4265 | 4510 | ||
| 4266 | /* sessionid */ | ||
| 4267 | READ_BUF(NFS4_MAX_SESSIONID_LEN); | ||
| 4268 | COPYMEM(&session->sess_id, NFS4_MAX_SESSIONID_LEN); | ||
| 4269 | |||
| 4270 | /* seqid, flags */ | 4511 | /* seqid, flags */ |
| 4271 | READ_BUF(8); | 4512 | p = xdr_inline_decode(xdr, 8); |
| 4272 | READ32(clp->cl_seqid); | 4513 | if (unlikely(!p)) |
| 4273 | READ32(session->flags); | 4514 | goto out_overflow; |
| 4515 | clp->cl_seqid = be32_to_cpup(p++); | ||
| 4516 | session->flags = be32_to_cpup(p); | ||
| 4274 | 4517 | ||
| 4275 | /* Channel attributes */ | 4518 | /* Channel attributes */ |
| 4276 | status = decode_chan_attrs(xdr, &session->fc_attrs); | 4519 | status = decode_chan_attrs(xdr, &session->fc_attrs); |
| 4277 | if (!status) | 4520 | if (!status) |
| 4278 | status = decode_chan_attrs(xdr, &session->bc_attrs); | 4521 | status = decode_chan_attrs(xdr, &session->bc_attrs); |
| 4279 | return status; | 4522 | return status; |
| 4523 | out_overflow: | ||
| 4524 | print_overflow_msg(__func__, xdr); | ||
| 4525 | return -EIO; | ||
| 4280 | } | 4526 | } |
| 4281 | 4527 | ||
| 4282 | static int decode_destroy_session(struct xdr_stream *xdr, void *dummy) | 4528 | static int decode_destroy_session(struct xdr_stream *xdr, void *dummy) |
| @@ -4300,7 +4546,9 @@ static int decode_sequence(struct xdr_stream *xdr, | |||
| 4300 | return 0; | 4546 | return 0; |
| 4301 | 4547 | ||
| 4302 | status = decode_op_hdr(xdr, OP_SEQUENCE); | 4548 | status = decode_op_hdr(xdr, OP_SEQUENCE); |
| 4303 | if (status) | 4549 | if (!status) |
| 4550 | status = decode_sessionid(xdr, &id); | ||
| 4551 | if (unlikely(status)) | ||
| 4304 | goto out_err; | 4552 | goto out_err; |
| 4305 | 4553 | ||
| 4306 | /* | 4554 | /* |
| @@ -4309,36 +4557,43 @@ static int decode_sequence(struct xdr_stream *xdr, | |||
| 4309 | */ | 4557 | */ |
| 4310 | status = -ESERVERFAULT; | 4558 | status = -ESERVERFAULT; |
| 4311 | 4559 | ||
| 4312 | slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; | ||
| 4313 | READ_BUF(NFS4_MAX_SESSIONID_LEN + 20); | ||
| 4314 | COPYMEM(id.data, NFS4_MAX_SESSIONID_LEN); | ||
| 4315 | if (memcmp(id.data, res->sr_session->sess_id.data, | 4560 | if (memcmp(id.data, res->sr_session->sess_id.data, |
| 4316 | NFS4_MAX_SESSIONID_LEN)) { | 4561 | NFS4_MAX_SESSIONID_LEN)) { |
| 4317 | dprintk("%s Invalid session id\n", __func__); | 4562 | dprintk("%s Invalid session id\n", __func__); |
| 4318 | goto out_err; | 4563 | goto out_err; |
| 4319 | } | 4564 | } |
| 4565 | |||
| 4566 | p = xdr_inline_decode(xdr, 20); | ||
| 4567 | if (unlikely(!p)) | ||
| 4568 | goto out_overflow; | ||
| 4569 | |||
| 4320 | /* seqid */ | 4570 | /* seqid */ |
| 4321 | READ32(dummy); | 4571 | slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; |
| 4572 | dummy = be32_to_cpup(p++); | ||
| 4322 | if (dummy != slot->seq_nr) { | 4573 | if (dummy != slot->seq_nr) { |
| 4323 | dprintk("%s Invalid sequence number\n", __func__); | 4574 | dprintk("%s Invalid sequence number\n", __func__); |
| 4324 | goto out_err; | 4575 | goto out_err; |
| 4325 | } | 4576 | } |
| 4326 | /* slot id */ | 4577 | /* slot id */ |
| 4327 | READ32(dummy); | 4578 | dummy = be32_to_cpup(p++); |
| 4328 | if (dummy != res->sr_slotid) { | 4579 | if (dummy != res->sr_slotid) { |
| 4329 | dprintk("%s Invalid slot id\n", __func__); | 4580 | dprintk("%s Invalid slot id\n", __func__); |
| 4330 | goto out_err; | 4581 | goto out_err; |
| 4331 | } | 4582 | } |
| 4332 | /* highest slot id - currently not processed */ | 4583 | /* highest slot id - currently not processed */ |
| 4333 | READ32(dummy); | 4584 | dummy = be32_to_cpup(p++); |
| 4334 | /* target highest slot id - currently not processed */ | 4585 | /* target highest slot id - currently not processed */ |
| 4335 | READ32(dummy); | 4586 | dummy = be32_to_cpup(p++); |
| 4336 | /* result flags - currently not processed */ | 4587 | /* result flags - currently not processed */ |
| 4337 | READ32(dummy); | 4588 | dummy = be32_to_cpup(p); |
| 4338 | status = 0; | 4589 | status = 0; |
| 4339 | out_err: | 4590 | out_err: |
| 4340 | res->sr_status = status; | 4591 | res->sr_status = status; |
| 4341 | return status; | 4592 | return status; |
| 4593 | out_overflow: | ||
| 4594 | print_overflow_msg(__func__, xdr); | ||
| 4595 | status = -EIO; | ||
| 4596 | goto out_err; | ||
| 4342 | #else /* CONFIG_NFS_V4_1 */ | 4597 | #else /* CONFIG_NFS_V4_1 */ |
| 4343 | return 0; | 4598 | return 0; |
| 4344 | #endif /* CONFIG_NFS_V4_1 */ | 4599 | #endif /* CONFIG_NFS_V4_1 */ |
| @@ -4370,7 +4625,8 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct | |||
| 4370 | status = decode_open_downgrade(&xdr, res); | 4625 | status = decode_open_downgrade(&xdr, res); |
| 4371 | if (status != 0) | 4626 | if (status != 0) |
| 4372 | goto out; | 4627 | goto out; |
| 4373 | decode_getfattr(&xdr, res->fattr, res->server); | 4628 | decode_getfattr(&xdr, res->fattr, res->server, |
| 4629 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4374 | out: | 4630 | out: |
| 4375 | return status; | 4631 | return status; |
| 4376 | } | 4632 | } |
| @@ -4397,7 +4653,8 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac | |||
| 4397 | status = decode_access(&xdr, res); | 4653 | status = decode_access(&xdr, res); |
| 4398 | if (status != 0) | 4654 | if (status != 0) |
| 4399 | goto out; | 4655 | goto out; |
| 4400 | decode_getfattr(&xdr, res->fattr, res->server); | 4656 | decode_getfattr(&xdr, res->fattr, res->server, |
| 4657 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4401 | out: | 4658 | out: |
| 4402 | return status; | 4659 | return status; |
| 4403 | } | 4660 | } |
| @@ -4424,7 +4681,8 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo | |||
| 4424 | goto out; | 4681 | goto out; |
| 4425 | if ((status = decode_getfh(&xdr, res->fh)) != 0) | 4682 | if ((status = decode_getfh(&xdr, res->fh)) != 0) |
| 4426 | goto out; | 4683 | goto out; |
| 4427 | status = decode_getfattr(&xdr, res->fattr, res->server); | 4684 | status = decode_getfattr(&xdr, res->fattr, res->server |
| 4685 | ,!RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4428 | out: | 4686 | out: |
| 4429 | return status; | 4687 | return status; |
| 4430 | } | 4688 | } |
| @@ -4448,7 +4706,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
| 4448 | if ((status = decode_putrootfh(&xdr)) != 0) | 4706 | if ((status = decode_putrootfh(&xdr)) != 0) |
| 4449 | goto out; | 4707 | goto out; |
| 4450 | if ((status = decode_getfh(&xdr, res->fh)) == 0) | 4708 | if ((status = decode_getfh(&xdr, res->fh)) == 0) |
| 4451 | status = decode_getfattr(&xdr, res->fattr, res->server); | 4709 | status = decode_getfattr(&xdr, res->fattr, res->server, |
| 4710 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4452 | out: | 4711 | out: |
| 4453 | return status; | 4712 | return status; |
| 4454 | } | 4713 | } |
| @@ -4473,7 +4732,8 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem | |||
| 4473 | goto out; | 4732 | goto out; |
| 4474 | if ((status = decode_remove(&xdr, &res->cinfo)) != 0) | 4733 | if ((status = decode_remove(&xdr, &res->cinfo)) != 0) |
| 4475 | goto out; | 4734 | goto out; |
| 4476 | decode_getfattr(&xdr, &res->dir_attr, res->server); | 4735 | decode_getfattr(&xdr, &res->dir_attr, res->server, |
| 4736 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4477 | out: | 4737 | out: |
| 4478 | return status; | 4738 | return status; |
| 4479 | } | 4739 | } |
| @@ -4503,11 +4763,13 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re | |||
| 4503 | if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0) | 4763 | if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0) |
| 4504 | goto out; | 4764 | goto out; |
| 4505 | /* Current FH is target directory */ | 4765 | /* Current FH is target directory */ |
| 4506 | if (decode_getfattr(&xdr, res->new_fattr, res->server) != 0) | 4766 | if (decode_getfattr(&xdr, res->new_fattr, res->server, |
| 4767 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
| 4507 | goto out; | 4768 | goto out; |
| 4508 | if ((status = decode_restorefh(&xdr)) != 0) | 4769 | if ((status = decode_restorefh(&xdr)) != 0) |
| 4509 | goto out; | 4770 | goto out; |
| 4510 | decode_getfattr(&xdr, res->old_fattr, res->server); | 4771 | decode_getfattr(&xdr, res->old_fattr, res->server, |
| 4772 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4511 | out: | 4773 | out: |
| 4512 | return status; | 4774 | return status; |
| 4513 | } | 4775 | } |
| @@ -4540,11 +4802,13 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link | |||
| 4540 | * Note order: OP_LINK leaves the directory as the current | 4802 | * Note order: OP_LINK leaves the directory as the current |
| 4541 | * filehandle. | 4803 | * filehandle. |
| 4542 | */ | 4804 | */ |
| 4543 | if (decode_getfattr(&xdr, res->dir_attr, res->server) != 0) | 4805 | if (decode_getfattr(&xdr, res->dir_attr, res->server, |
| 4806 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
| 4544 | goto out; | 4807 | goto out; |
| 4545 | if ((status = decode_restorefh(&xdr)) != 0) | 4808 | if ((status = decode_restorefh(&xdr)) != 0) |
| 4546 | goto out; | 4809 | goto out; |
| 4547 | decode_getfattr(&xdr, res->fattr, res->server); | 4810 | decode_getfattr(&xdr, res->fattr, res->server, |
| 4811 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4548 | out: | 4812 | out: |
| 4549 | return status; | 4813 | return status; |
| 4550 | } | 4814 | } |
| @@ -4573,11 +4837,13 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr | |||
| 4573 | goto out; | 4837 | goto out; |
| 4574 | if ((status = decode_getfh(&xdr, res->fh)) != 0) | 4838 | if ((status = decode_getfh(&xdr, res->fh)) != 0) |
| 4575 | goto out; | 4839 | goto out; |
| 4576 | if (decode_getfattr(&xdr, res->fattr, res->server) != 0) | 4840 | if (decode_getfattr(&xdr, res->fattr, res->server, |
| 4841 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
| 4577 | goto out; | 4842 | goto out; |
| 4578 | if ((status = decode_restorefh(&xdr)) != 0) | 4843 | if ((status = decode_restorefh(&xdr)) != 0) |
| 4579 | goto out; | 4844 | goto out; |
| 4580 | decode_getfattr(&xdr, res->dir_fattr, res->server); | 4845 | decode_getfattr(&xdr, res->dir_fattr, res->server, |
| 4846 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4581 | out: | 4847 | out: |
| 4582 | return status; | 4848 | return status; |
| 4583 | } | 4849 | } |
| @@ -4609,7 +4875,8 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g | |||
| 4609 | status = decode_putfh(&xdr); | 4875 | status = decode_putfh(&xdr); |
| 4610 | if (status) | 4876 | if (status) |
| 4611 | goto out; | 4877 | goto out; |
| 4612 | status = decode_getfattr(&xdr, res->fattr, res->server); | 4878 | status = decode_getfattr(&xdr, res->fattr, res->server, |
| 4879 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4613 | out: | 4880 | out: |
| 4614 | return status; | 4881 | return status; |
| 4615 | } | 4882 | } |
| @@ -4716,7 +4983,8 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos | |||
| 4716 | * an ESTALE error. Shouldn't be a problem, | 4983 | * an ESTALE error. Shouldn't be a problem, |
| 4717 | * though, since fattr->valid will remain unset. | 4984 | * though, since fattr->valid will remain unset. |
| 4718 | */ | 4985 | */ |
| 4719 | decode_getfattr(&xdr, res->fattr, res->server); | 4986 | decode_getfattr(&xdr, res->fattr, res->server, |
| 4987 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4720 | out: | 4988 | out: |
| 4721 | return status; | 4989 | return status; |
| 4722 | } | 4990 | } |
| @@ -4748,11 +5016,13 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr | |||
| 4748 | goto out; | 5016 | goto out; |
| 4749 | if (decode_getfh(&xdr, &res->fh) != 0) | 5017 | if (decode_getfh(&xdr, &res->fh) != 0) |
| 4750 | goto out; | 5018 | goto out; |
| 4751 | if (decode_getfattr(&xdr, res->f_attr, res->server) != 0) | 5019 | if (decode_getfattr(&xdr, res->f_attr, res->server, |
| 5020 | !RPC_IS_ASYNC(rqstp->rq_task)) != 0) | ||
| 4752 | goto out; | 5021 | goto out; |
| 4753 | if (decode_restorefh(&xdr) != 0) | 5022 | if (decode_restorefh(&xdr) != 0) |
| 4754 | goto out; | 5023 | goto out; |
| 4755 | decode_getfattr(&xdr, res->dir_attr, res->server); | 5024 | decode_getfattr(&xdr, res->dir_attr, res->server, |
| 5025 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4756 | out: | 5026 | out: |
| 4757 | return status; | 5027 | return status; |
| 4758 | } | 5028 | } |
| @@ -4800,7 +5070,8 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
| 4800 | status = decode_open(&xdr, res); | 5070 | status = decode_open(&xdr, res); |
| 4801 | if (status) | 5071 | if (status) |
| 4802 | goto out; | 5072 | goto out; |
| 4803 | decode_getfattr(&xdr, res->f_attr, res->server); | 5073 | decode_getfattr(&xdr, res->f_attr, res->server, |
| 5074 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4804 | out: | 5075 | out: |
| 4805 | return status; | 5076 | return status; |
| 4806 | } | 5077 | } |
| @@ -4827,7 +5098,8 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se | |||
| 4827 | status = decode_setattr(&xdr); | 5098 | status = decode_setattr(&xdr); |
| 4828 | if (status) | 5099 | if (status) |
| 4829 | goto out; | 5100 | goto out; |
| 4830 | decode_getfattr(&xdr, res->fattr, res->server); | 5101 | decode_getfattr(&xdr, res->fattr, res->server, |
| 5102 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 4831 | out: | 5103 | out: |
| 4832 | return status; | 5104 | return status; |
| 4833 | } | 5105 | } |
| @@ -5001,7 +5273,8 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writ | |||
| 5001 | status = decode_write(&xdr, res); | 5273 | status = decode_write(&xdr, res); |
| 5002 | if (status) | 5274 | if (status) |
| 5003 | goto out; | 5275 | goto out; |
| 5004 | decode_getfattr(&xdr, res->fattr, res->server); | 5276 | decode_getfattr(&xdr, res->fattr, res->server, |
| 5277 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 5005 | if (!status) | 5278 | if (!status) |
| 5006 | status = res->count; | 5279 | status = res->count; |
| 5007 | out: | 5280 | out: |
| @@ -5030,7 +5303,8 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_wri | |||
| 5030 | status = decode_commit(&xdr, res); | 5303 | status = decode_commit(&xdr, res); |
| 5031 | if (status) | 5304 | if (status) |
| 5032 | goto out; | 5305 | goto out; |
| 5033 | decode_getfattr(&xdr, res->fattr, res->server); | 5306 | decode_getfattr(&xdr, res->fattr, res->server, |
| 5307 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 5034 | out: | 5308 | out: |
| 5035 | return status; | 5309 | return status; |
| 5036 | } | 5310 | } |
| @@ -5194,7 +5468,8 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
| 5194 | if (status != 0) | 5468 | if (status != 0) |
| 5195 | goto out; | 5469 | goto out; |
| 5196 | status = decode_delegreturn(&xdr); | 5470 | status = decode_delegreturn(&xdr); |
| 5197 | decode_getfattr(&xdr, res->fattr, res->server); | 5471 | decode_getfattr(&xdr, res->fattr, res->server, |
| 5472 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
| 5198 | out: | 5473 | out: |
| 5199 | return status; | 5474 | return status; |
| 5200 | } | 5475 | } |
| @@ -5222,7 +5497,8 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, | |||
| 5222 | goto out; | 5497 | goto out; |
| 5223 | xdr_enter_page(&xdr, PAGE_SIZE); | 5498 | xdr_enter_page(&xdr, PAGE_SIZE); |
| 5224 | status = decode_getfattr(&xdr, &res->fs_locations->fattr, | 5499 | status = decode_getfattr(&xdr, &res->fs_locations->fattr, |
| 5225 | res->fs_locations->server); | 5500 | res->fs_locations->server, |
| 5501 | !RPC_IS_ASYNC(req->rq_task)); | ||
| 5226 | out: | 5502 | out: |
| 5227 | return status; | 5503 | return status; |
| 5228 | } | 5504 | } |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 0b4cbdc60ab..de935692d40 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -73,7 +73,7 @@ enum { | |||
| 73 | Opt_cto, Opt_nocto, | 73 | Opt_cto, Opt_nocto, |
| 74 | Opt_ac, Opt_noac, | 74 | Opt_ac, Opt_noac, |
| 75 | Opt_lock, Opt_nolock, | 75 | Opt_lock, Opt_nolock, |
| 76 | Opt_v2, Opt_v3, | 76 | Opt_v2, Opt_v3, Opt_v4, |
| 77 | Opt_udp, Opt_tcp, Opt_rdma, | 77 | Opt_udp, Opt_tcp, Opt_rdma, |
| 78 | Opt_acl, Opt_noacl, | 78 | Opt_acl, Opt_noacl, |
| 79 | Opt_rdirplus, Opt_nordirplus, | 79 | Opt_rdirplus, Opt_nordirplus, |
| @@ -127,6 +127,7 @@ static const match_table_t nfs_mount_option_tokens = { | |||
| 127 | { Opt_nolock, "nolock" }, | 127 | { Opt_nolock, "nolock" }, |
| 128 | { Opt_v2, "v2" }, | 128 | { Opt_v2, "v2" }, |
| 129 | { Opt_v3, "v3" }, | 129 | { Opt_v3, "v3" }, |
| 130 | { Opt_v4, "v4" }, | ||
| 130 | { Opt_udp, "udp" }, | 131 | { Opt_udp, "udp" }, |
| 131 | { Opt_tcp, "tcp" }, | 132 | { Opt_tcp, "tcp" }, |
| 132 | { Opt_rdma, "rdma" }, | 133 | { Opt_rdma, "rdma" }, |
| @@ -158,7 +159,7 @@ static const match_table_t nfs_mount_option_tokens = { | |||
| 158 | { Opt_mountvers, "mountvers=%s" }, | 159 | { Opt_mountvers, "mountvers=%s" }, |
| 159 | { Opt_nfsvers, "nfsvers=%s" }, | 160 | { Opt_nfsvers, "nfsvers=%s" }, |
| 160 | { Opt_nfsvers, "vers=%s" }, | 161 | { Opt_nfsvers, "vers=%s" }, |
| 161 | { Opt_minorversion, "minorversion=%u" }, | 162 | { Opt_minorversion, "minorversion=%s" }, |
| 162 | 163 | ||
| 163 | { Opt_sec, "sec=%s" }, | 164 | { Opt_sec, "sec=%s" }, |
| 164 | { Opt_proto, "proto=%s" }, | 165 | { Opt_proto, "proto=%s" }, |
| @@ -272,6 +273,10 @@ static const struct super_operations nfs_sops = { | |||
| 272 | }; | 273 | }; |
| 273 | 274 | ||
| 274 | #ifdef CONFIG_NFS_V4 | 275 | #ifdef CONFIG_NFS_V4 |
| 276 | static int nfs4_validate_text_mount_data(void *options, | ||
| 277 | struct nfs_parsed_mount_data *args, const char *dev_name); | ||
| 278 | static int nfs4_try_mount(int flags, const char *dev_name, | ||
| 279 | struct nfs_parsed_mount_data *data, struct vfsmount *mnt); | ||
| 275 | static int nfs4_get_sb(struct file_system_type *fs_type, | 280 | static int nfs4_get_sb(struct file_system_type *fs_type, |
| 276 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 281 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
| 277 | static int nfs4_remote_get_sb(struct file_system_type *fs_type, | 282 | static int nfs4_remote_get_sb(struct file_system_type *fs_type, |
| @@ -742,127 +747,23 @@ static int nfs_verify_server_address(struct sockaddr *addr) | |||
| 742 | } | 747 | } |
| 743 | } | 748 | } |
| 744 | 749 | ||
| 750 | dfprintk(MOUNT, "NFS: Invalid IP address specified\n"); | ||
| 745 | return 0; | 751 | return 0; |
| 746 | } | 752 | } |
| 747 | 753 | ||
| 748 | static void nfs_parse_ipv4_address(char *string, size_t str_len, | ||
| 749 | struct sockaddr *sap, size_t *addr_len) | ||
| 750 | { | ||
| 751 | struct sockaddr_in *sin = (struct sockaddr_in *)sap; | ||
| 752 | u8 *addr = (u8 *)&sin->sin_addr.s_addr; | ||
| 753 | |||
| 754 | if (str_len <= INET_ADDRSTRLEN) { | ||
| 755 | dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n", | ||
| 756 | (int)str_len, string); | ||
| 757 | |||
| 758 | sin->sin_family = AF_INET; | ||
| 759 | *addr_len = sizeof(*sin); | ||
| 760 | if (in4_pton(string, str_len, addr, '\0', NULL)) | ||
| 761 | return; | ||
| 762 | } | ||
| 763 | |||
| 764 | sap->sa_family = AF_UNSPEC; | ||
| 765 | *addr_len = 0; | ||
| 766 | } | ||
| 767 | |||
| 768 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 769 | static int nfs_parse_ipv6_scope_id(const char *string, const size_t str_len, | ||
| 770 | const char *delim, | ||
| 771 | struct sockaddr_in6 *sin6) | ||
| 772 | { | ||
| 773 | char *p; | ||
| 774 | size_t len; | ||
| 775 | |||
| 776 | if ((string + str_len) == delim) | ||
| 777 | return 1; | ||
| 778 | |||
| 779 | if (*delim != IPV6_SCOPE_DELIMITER) | ||
| 780 | return 0; | ||
| 781 | |||
| 782 | if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) | ||
| 783 | return 0; | ||
| 784 | |||
| 785 | len = (string + str_len) - delim - 1; | ||
| 786 | p = kstrndup(delim + 1, len, GFP_KERNEL); | ||
| 787 | if (p) { | ||
| 788 | unsigned long scope_id = 0; | ||
| 789 | struct net_device *dev; | ||
| 790 | |||
| 791 | dev = dev_get_by_name(&init_net, p); | ||
| 792 | if (dev != NULL) { | ||
| 793 | scope_id = dev->ifindex; | ||
| 794 | dev_put(dev); | ||
| 795 | } else { | ||
| 796 | if (strict_strtoul(p, 10, &scope_id) == 0) { | ||
| 797 | kfree(p); | ||
| 798 | return 0; | ||
| 799 | } | ||
| 800 | } | ||
| 801 | |||
| 802 | kfree(p); | ||
| 803 | |||
| 804 | sin6->sin6_scope_id = scope_id; | ||
| 805 | dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id); | ||
| 806 | return 1; | ||
| 807 | } | ||
| 808 | |||
| 809 | return 0; | ||
| 810 | } | ||
| 811 | |||
| 812 | static void nfs_parse_ipv6_address(char *string, size_t str_len, | ||
| 813 | struct sockaddr *sap, size_t *addr_len) | ||
| 814 | { | ||
| 815 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | ||
| 816 | u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; | ||
| 817 | const char *delim; | ||
| 818 | |||
| 819 | if (str_len <= INET6_ADDRSTRLEN) { | ||
| 820 | dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n", | ||
| 821 | (int)str_len, string); | ||
| 822 | |||
| 823 | sin6->sin6_family = AF_INET6; | ||
| 824 | *addr_len = sizeof(*sin6); | ||
| 825 | if (in6_pton(string, str_len, addr, | ||
| 826 | IPV6_SCOPE_DELIMITER, &delim) != 0) { | ||
| 827 | if (nfs_parse_ipv6_scope_id(string, str_len, | ||
| 828 | delim, sin6) != 0) | ||
| 829 | return; | ||
| 830 | } | ||
| 831 | } | ||
| 832 | |||
| 833 | sap->sa_family = AF_UNSPEC; | ||
| 834 | *addr_len = 0; | ||
| 835 | } | ||
| 836 | #else | ||
| 837 | static void nfs_parse_ipv6_address(char *string, size_t str_len, | ||
| 838 | struct sockaddr *sap, size_t *addr_len) | ||
| 839 | { | ||
| 840 | sap->sa_family = AF_UNSPEC; | ||
| 841 | *addr_len = 0; | ||
| 842 | } | ||
| 843 | #endif | ||
| 844 | |||
| 845 | /* | 754 | /* |
| 846 | * Construct a sockaddr based on the contents of a string that contains | 755 | * Select between a default port value and a user-specified port value. |
| 847 | * an IP address in presentation format. | 756 | * If a zero value is set, then autobind will be used. |
| 848 | * | ||
| 849 | * If there is a problem constructing the new sockaddr, set the address | ||
| 850 | * family to AF_UNSPEC. | ||
| 851 | */ | 757 | */ |
| 852 | void nfs_parse_ip_address(char *string, size_t str_len, | 758 | static void nfs_set_default_port(struct sockaddr *sap, const int parsed_port, |
| 853 | struct sockaddr *sap, size_t *addr_len) | 759 | const unsigned short default_port) |
| 854 | { | 760 | { |
| 855 | unsigned int i, colons; | 761 | unsigned short port = default_port; |
| 856 | 762 | ||
| 857 | colons = 0; | 763 | if (parsed_port != NFS_UNSPEC_PORT) |
| 858 | for (i = 0; i < str_len; i++) | 764 | port = parsed_port; |
| 859 | if (string[i] == ':') | ||
| 860 | colons++; | ||
| 861 | 765 | ||
| 862 | if (colons >= 2) | 766 | rpc_set_port(sap, port); |
| 863 | nfs_parse_ipv6_address(string, str_len, sap, addr_len); | ||
| 864 | else | ||
| 865 | nfs_parse_ipv4_address(string, str_len, sap, addr_len); | ||
| 866 | } | 767 | } |
| 867 | 768 | ||
| 868 | /* | 769 | /* |
| @@ -904,8 +805,6 @@ static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt) | |||
| 904 | 805 | ||
| 905 | /* | 806 | /* |
| 906 | * Parse the value of the 'sec=' option. | 807 | * Parse the value of the 'sec=' option. |
| 907 | * | ||
| 908 | * The flavor_len setting is for v4 mounts. | ||
| 909 | */ | 808 | */ |
| 910 | static int nfs_parse_security_flavors(char *value, | 809 | static int nfs_parse_security_flavors(char *value, |
| 911 | struct nfs_parsed_mount_data *mnt) | 810 | struct nfs_parsed_mount_data *mnt) |
| @@ -916,53 +815,43 @@ static int nfs_parse_security_flavors(char *value, | |||
| 916 | 815 | ||
| 917 | switch (match_token(value, nfs_secflavor_tokens, args)) { | 816 | switch (match_token(value, nfs_secflavor_tokens, args)) { |
| 918 | case Opt_sec_none: | 817 | case Opt_sec_none: |
| 919 | mnt->auth_flavor_len = 0; | ||
| 920 | mnt->auth_flavors[0] = RPC_AUTH_NULL; | 818 | mnt->auth_flavors[0] = RPC_AUTH_NULL; |
| 921 | break; | 819 | break; |
| 922 | case Opt_sec_sys: | 820 | case Opt_sec_sys: |
| 923 | mnt->auth_flavor_len = 0; | ||
| 924 | mnt->auth_flavors[0] = RPC_AUTH_UNIX; | 821 | mnt->auth_flavors[0] = RPC_AUTH_UNIX; |
| 925 | break; | 822 | break; |
| 926 | case Opt_sec_krb5: | 823 | case Opt_sec_krb5: |
| 927 | mnt->auth_flavor_len = 1; | ||
| 928 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; | 824 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; |
| 929 | break; | 825 | break; |
| 930 | case Opt_sec_krb5i: | 826 | case Opt_sec_krb5i: |
| 931 | mnt->auth_flavor_len = 1; | ||
| 932 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; | 827 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; |
| 933 | break; | 828 | break; |
| 934 | case Opt_sec_krb5p: | 829 | case Opt_sec_krb5p: |
| 935 | mnt->auth_flavor_len = 1; | ||
| 936 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; | 830 | mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; |
| 937 | break; | 831 | break; |
| 938 | case Opt_sec_lkey: | 832 | case Opt_sec_lkey: |
| 939 | mnt->auth_flavor_len = 1; | ||
| 940 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; | 833 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; |
| 941 | break; | 834 | break; |
| 942 | case Opt_sec_lkeyi: | 835 | case Opt_sec_lkeyi: |
| 943 | mnt->auth_flavor_len = 1; | ||
| 944 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; | 836 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; |
| 945 | break; | 837 | break; |
| 946 | case Opt_sec_lkeyp: | 838 | case Opt_sec_lkeyp: |
| 947 | mnt->auth_flavor_len = 1; | ||
| 948 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; | 839 | mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; |
| 949 | break; | 840 | break; |
| 950 | case Opt_sec_spkm: | 841 | case Opt_sec_spkm: |
| 951 | mnt->auth_flavor_len = 1; | ||
| 952 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; | 842 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; |
| 953 | break; | 843 | break; |
| 954 | case Opt_sec_spkmi: | 844 | case Opt_sec_spkmi: |
| 955 | mnt->auth_flavor_len = 1; | ||
| 956 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; | 845 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; |
| 957 | break; | 846 | break; |
| 958 | case Opt_sec_spkmp: | 847 | case Opt_sec_spkmp: |
| 959 | mnt->auth_flavor_len = 1; | ||
| 960 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; | 848 | mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; |
| 961 | break; | 849 | break; |
| 962 | default: | 850 | default: |
| 963 | return 0; | 851 | return 0; |
| 964 | } | 852 | } |
| 965 | 853 | ||
| 854 | mnt->auth_flavor_len = 1; | ||
| 966 | return 1; | 855 | return 1; |
| 967 | } | 856 | } |
| 968 | 857 | ||
| @@ -1001,7 +890,6 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1001 | while ((p = strsep(&raw, ",")) != NULL) { | 890 | while ((p = strsep(&raw, ",")) != NULL) { |
| 1002 | substring_t args[MAX_OPT_ARGS]; | 891 | substring_t args[MAX_OPT_ARGS]; |
| 1003 | unsigned long option; | 892 | unsigned long option; |
| 1004 | int int_option; | ||
| 1005 | int token; | 893 | int token; |
| 1006 | 894 | ||
| 1007 | if (!*p) | 895 | if (!*p) |
| @@ -1047,10 +935,18 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1047 | break; | 935 | break; |
| 1048 | case Opt_v2: | 936 | case Opt_v2: |
| 1049 | mnt->flags &= ~NFS_MOUNT_VER3; | 937 | mnt->flags &= ~NFS_MOUNT_VER3; |
| 938 | mnt->version = 2; | ||
| 1050 | break; | 939 | break; |
| 1051 | case Opt_v3: | 940 | case Opt_v3: |
| 1052 | mnt->flags |= NFS_MOUNT_VER3; | 941 | mnt->flags |= NFS_MOUNT_VER3; |
| 942 | mnt->version = 3; | ||
| 1053 | break; | 943 | break; |
| 944 | #ifdef CONFIG_NFS_V4 | ||
| 945 | case Opt_v4: | ||
| 946 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
| 947 | mnt->version = 4; | ||
| 948 | break; | ||
| 949 | #endif | ||
| 1054 | case Opt_udp: | 950 | case Opt_udp: |
| 1055 | mnt->flags &= ~NFS_MOUNT_TCP; | 951 | mnt->flags &= ~NFS_MOUNT_TCP; |
| 1056 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 952 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
| @@ -1264,20 +1160,33 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1264 | switch (option) { | 1160 | switch (option) { |
| 1265 | case NFS2_VERSION: | 1161 | case NFS2_VERSION: |
| 1266 | mnt->flags &= ~NFS_MOUNT_VER3; | 1162 | mnt->flags &= ~NFS_MOUNT_VER3; |
| 1163 | mnt->version = 2; | ||
| 1267 | break; | 1164 | break; |
| 1268 | case NFS3_VERSION: | 1165 | case NFS3_VERSION: |
| 1269 | mnt->flags |= NFS_MOUNT_VER3; | 1166 | mnt->flags |= NFS_MOUNT_VER3; |
| 1167 | mnt->version = 3; | ||
| 1270 | break; | 1168 | break; |
| 1169 | #ifdef CONFIG_NFS_V4 | ||
| 1170 | case NFS4_VERSION: | ||
| 1171 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
| 1172 | mnt->version = 4; | ||
| 1173 | break; | ||
| 1174 | #endif | ||
| 1271 | default: | 1175 | default: |
| 1272 | goto out_invalid_value; | 1176 | goto out_invalid_value; |
| 1273 | } | 1177 | } |
| 1274 | break; | 1178 | break; |
| 1275 | case Opt_minorversion: | 1179 | case Opt_minorversion: |
| 1276 | if (match_int(args, &int_option)) | 1180 | string = match_strdup(args); |
| 1277 | return 0; | 1181 | if (string == NULL) |
| 1278 | if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION) | 1182 | goto out_nomem; |
| 1279 | return 0; | 1183 | rc = strict_strtoul(string, 10, &option); |
| 1280 | mnt->minorversion = int_option; | 1184 | kfree(string); |
| 1185 | if (rc != 0) | ||
| 1186 | goto out_invalid_value; | ||
| 1187 | if (option > NFS4_MAX_MINOR_VERSION) | ||
| 1188 | goto out_invalid_value; | ||
| 1189 | mnt->minorversion = option; | ||
| 1281 | break; | 1190 | break; |
| 1282 | 1191 | ||
| 1283 | /* | 1192 | /* |
| @@ -1352,11 +1261,14 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1352 | string = match_strdup(args); | 1261 | string = match_strdup(args); |
| 1353 | if (string == NULL) | 1262 | if (string == NULL) |
| 1354 | goto out_nomem; | 1263 | goto out_nomem; |
| 1355 | nfs_parse_ip_address(string, strlen(string), | 1264 | mnt->nfs_server.addrlen = |
| 1356 | (struct sockaddr *) | 1265 | rpc_pton(string, strlen(string), |
| 1357 | &mnt->nfs_server.address, | 1266 | (struct sockaddr *) |
| 1358 | &mnt->nfs_server.addrlen); | 1267 | &mnt->nfs_server.address, |
| 1268 | sizeof(mnt->nfs_server.address)); | ||
| 1359 | kfree(string); | 1269 | kfree(string); |
| 1270 | if (mnt->nfs_server.addrlen == 0) | ||
| 1271 | goto out_invalid_address; | ||
| 1360 | break; | 1272 | break; |
| 1361 | case Opt_clientaddr: | 1273 | case Opt_clientaddr: |
| 1362 | string = match_strdup(args); | 1274 | string = match_strdup(args); |
| @@ -1376,11 +1288,14 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1376 | string = match_strdup(args); | 1288 | string = match_strdup(args); |
| 1377 | if (string == NULL) | 1289 | if (string == NULL) |
| 1378 | goto out_nomem; | 1290 | goto out_nomem; |
| 1379 | nfs_parse_ip_address(string, strlen(string), | 1291 | mnt->mount_server.addrlen = |
| 1380 | (struct sockaddr *) | 1292 | rpc_pton(string, strlen(string), |
| 1381 | &mnt->mount_server.address, | 1293 | (struct sockaddr *) |
| 1382 | &mnt->mount_server.addrlen); | 1294 | &mnt->mount_server.address, |
| 1295 | sizeof(mnt->mount_server.address)); | ||
| 1383 | kfree(string); | 1296 | kfree(string); |
| 1297 | if (mnt->mount_server.addrlen == 0) | ||
| 1298 | goto out_invalid_address; | ||
| 1384 | break; | 1299 | break; |
| 1385 | case Opt_lookupcache: | 1300 | case Opt_lookupcache: |
| 1386 | string = match_strdup(args); | 1301 | string = match_strdup(args); |
| @@ -1432,8 +1347,11 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1432 | 1347 | ||
| 1433 | return 1; | 1348 | return 1; |
| 1434 | 1349 | ||
| 1350 | out_invalid_address: | ||
| 1351 | printk(KERN_INFO "NFS: bad IP address specified: %s\n", p); | ||
| 1352 | return 0; | ||
| 1435 | out_invalid_value: | 1353 | out_invalid_value: |
| 1436 | printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p); | 1354 | printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p); |
| 1437 | return 0; | 1355 | return 0; |
| 1438 | out_nomem: | 1356 | out_nomem: |
| 1439 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); | 1357 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); |
| @@ -1445,13 +1363,60 @@ out_security_failure: | |||
| 1445 | } | 1363 | } |
| 1446 | 1364 | ||
| 1447 | /* | 1365 | /* |
| 1366 | * Match the requested auth flavors with the list returned by | ||
| 1367 | * the server. Returns zero and sets the mount's authentication | ||
| 1368 | * flavor on success; returns -EACCES if server does not support | ||
| 1369 | * the requested flavor. | ||
| 1370 | */ | ||
| 1371 | static int nfs_walk_authlist(struct nfs_parsed_mount_data *args, | ||
| 1372 | struct nfs_mount_request *request) | ||
| 1373 | { | ||
| 1374 | unsigned int i, j, server_authlist_len = *(request->auth_flav_len); | ||
| 1375 | |||
| 1376 | /* | ||
| 1377 | * Certain releases of Linux's mountd return an empty | ||
| 1378 | * flavor list. To prevent behavioral regression with | ||
| 1379 | * these servers (ie. rejecting mounts that used to | ||
| 1380 | * succeed), revert to pre-2.6.32 behavior (no checking) | ||
| 1381 | * if the returned flavor list is empty. | ||
| 1382 | */ | ||
| 1383 | if (server_authlist_len == 0) | ||
| 1384 | return 0; | ||
| 1385 | |||
| 1386 | /* | ||
| 1387 | * We avoid sophisticated negotiating here, as there are | ||
| 1388 | * plenty of cases where we can get it wrong, providing | ||
| 1389 | * either too little or too much security. | ||
| 1390 | * | ||
| 1391 | * RFC 2623, section 2.7 suggests we SHOULD prefer the | ||
| 1392 | * flavor listed first. However, some servers list | ||
| 1393 | * AUTH_NULL first. Our caller plants AUTH_SYS, the | ||
| 1394 | * preferred default, in args->auth_flavors[0] if user | ||
| 1395 | * didn't specify sec= mount option. | ||
| 1396 | */ | ||
| 1397 | for (i = 0; i < args->auth_flavor_len; i++) | ||
| 1398 | for (j = 0; j < server_authlist_len; j++) | ||
| 1399 | if (args->auth_flavors[i] == request->auth_flavs[j]) { | ||
| 1400 | dfprintk(MOUNT, "NFS: using auth flavor %d\n", | ||
| 1401 | request->auth_flavs[j]); | ||
| 1402 | args->auth_flavors[0] = request->auth_flavs[j]; | ||
| 1403 | return 0; | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | dfprintk(MOUNT, "NFS: server does not support requested auth flavor\n"); | ||
| 1407 | nfs_umount(request); | ||
| 1408 | return -EACCES; | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | /* | ||
| 1448 | * Use the remote server's MOUNT service to request the NFS file handle | 1412 | * Use the remote server's MOUNT service to request the NFS file handle |
| 1449 | * corresponding to the provided path. | 1413 | * corresponding to the provided path. |
| 1450 | */ | 1414 | */ |
| 1451 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1415 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
| 1452 | struct nfs_fh *root_fh) | 1416 | struct nfs_fh *root_fh) |
| 1453 | { | 1417 | { |
| 1454 | unsigned int auth_flavor_len = 0; | 1418 | rpc_authflavor_t server_authlist[NFS_MAX_SECFLAVORS]; |
| 1419 | unsigned int server_authlist_len = ARRAY_SIZE(server_authlist); | ||
| 1455 | struct nfs_mount_request request = { | 1420 | struct nfs_mount_request request = { |
| 1456 | .sap = (struct sockaddr *) | 1421 | .sap = (struct sockaddr *) |
| 1457 | &args->mount_server.address, | 1422 | &args->mount_server.address, |
| @@ -1459,7 +1424,8 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
| 1459 | .protocol = args->mount_server.protocol, | 1424 | .protocol = args->mount_server.protocol, |
| 1460 | .fh = root_fh, | 1425 | .fh = root_fh, |
| 1461 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | 1426 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, |
| 1462 | .auth_flav_len = &auth_flavor_len, | 1427 | .auth_flav_len = &server_authlist_len, |
| 1428 | .auth_flavs = server_authlist, | ||
| 1463 | }; | 1429 | }; |
| 1464 | int status; | 1430 | int status; |
| 1465 | 1431 | ||
| @@ -1485,23 +1451,25 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
| 1485 | args->mount_server.addrlen = args->nfs_server.addrlen; | 1451 | args->mount_server.addrlen = args->nfs_server.addrlen; |
| 1486 | } | 1452 | } |
| 1487 | request.salen = args->mount_server.addrlen; | 1453 | request.salen = args->mount_server.addrlen; |
| 1488 | 1454 | nfs_set_default_port(request.sap, args->mount_server.port, 0); | |
| 1489 | /* | ||
| 1490 | * autobind will be used if mount_server.port == 0 | ||
| 1491 | */ | ||
| 1492 | nfs_set_port(request.sap, args->mount_server.port); | ||
| 1493 | 1455 | ||
| 1494 | /* | 1456 | /* |
| 1495 | * Now ask the mount server to map our export path | 1457 | * Now ask the mount server to map our export path |
| 1496 | * to a file handle. | 1458 | * to a file handle. |
| 1497 | */ | 1459 | */ |
| 1498 | status = nfs_mount(&request); | 1460 | status = nfs_mount(&request); |
| 1499 | if (status == 0) | 1461 | if (status != 0) { |
| 1500 | return 0; | 1462 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", |
| 1463 | request.hostname, status); | ||
| 1464 | return status; | ||
| 1465 | } | ||
| 1501 | 1466 | ||
| 1502 | dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", | 1467 | /* |
| 1503 | request.hostname, status); | 1468 | * MNTv1 (NFSv2) does not support auth flavor negotiation. |
| 1504 | return status; | 1469 | */ |
| 1470 | if (args->mount_server.version != NFS_MNT3_VERSION) | ||
| 1471 | return 0; | ||
| 1472 | return nfs_walk_authlist(args, &request); | ||
| 1505 | } | 1473 | } |
| 1506 | 1474 | ||
| 1507 | static int nfs_parse_simple_hostname(const char *dev_name, | 1475 | static int nfs_parse_simple_hostname(const char *dev_name, |
| @@ -1661,6 +1629,7 @@ static int nfs_validate_mount_data(void *options, | |||
| 1661 | const char *dev_name) | 1629 | const char *dev_name) |
| 1662 | { | 1630 | { |
| 1663 | struct nfs_mount_data *data = (struct nfs_mount_data *)options; | 1631 | struct nfs_mount_data *data = (struct nfs_mount_data *)options; |
| 1632 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; | ||
| 1664 | 1633 | ||
| 1665 | if (data == NULL) | 1634 | if (data == NULL) |
| 1666 | goto out_no_data; | 1635 | goto out_no_data; |
| @@ -1672,10 +1641,12 @@ static int nfs_validate_mount_data(void *options, | |||
| 1672 | args->acregmax = NFS_DEF_ACREGMAX; | 1641 | args->acregmax = NFS_DEF_ACREGMAX; |
| 1673 | args->acdirmin = NFS_DEF_ACDIRMIN; | 1642 | args->acdirmin = NFS_DEF_ACDIRMIN; |
| 1674 | args->acdirmax = NFS_DEF_ACDIRMAX; | 1643 | args->acdirmax = NFS_DEF_ACDIRMAX; |
| 1675 | args->mount_server.port = 0; /* autobind unless user sets port */ | 1644 | args->mount_server.port = NFS_UNSPEC_PORT; |
| 1676 | args->nfs_server.port = 0; /* autobind unless user sets port */ | 1645 | args->nfs_server.port = NFS_UNSPEC_PORT; |
| 1677 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1646 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
| 1678 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1647 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
| 1648 | args->auth_flavor_len = 1; | ||
| 1649 | args->minorversion = 0; | ||
| 1679 | 1650 | ||
| 1680 | switch (data->version) { | 1651 | switch (data->version) { |
| 1681 | case 1: | 1652 | case 1: |
| @@ -1697,8 +1668,11 @@ static int nfs_validate_mount_data(void *options, | |||
| 1697 | if (data->root.size > NFS3_FHSIZE || data->root.size == 0) | 1668 | if (data->root.size > NFS3_FHSIZE || data->root.size == 0) |
| 1698 | goto out_invalid_fh; | 1669 | goto out_invalid_fh; |
| 1699 | mntfh->size = data->root.size; | 1670 | mntfh->size = data->root.size; |
| 1700 | } else | 1671 | args->version = 3; |
| 1672 | } else { | ||
| 1701 | mntfh->size = NFS2_FHSIZE; | 1673 | mntfh->size = NFS2_FHSIZE; |
| 1674 | args->version = 2; | ||
| 1675 | } | ||
| 1702 | 1676 | ||
| 1703 | 1677 | ||
| 1704 | memcpy(mntfh->data, data->root.data, mntfh->size); | 1678 | memcpy(mntfh->data, data->root.data, mntfh->size); |
| @@ -1720,11 +1694,9 @@ static int nfs_validate_mount_data(void *options, | |||
| 1720 | args->acdirmin = data->acdirmin; | 1694 | args->acdirmin = data->acdirmin; |
| 1721 | args->acdirmax = data->acdirmax; | 1695 | args->acdirmax = data->acdirmax; |
| 1722 | 1696 | ||
| 1723 | memcpy(&args->nfs_server.address, &data->addr, | 1697 | memcpy(sap, &data->addr, sizeof(data->addr)); |
| 1724 | sizeof(data->addr)); | ||
| 1725 | args->nfs_server.addrlen = sizeof(data->addr); | 1698 | args->nfs_server.addrlen = sizeof(data->addr); |
| 1726 | if (!nfs_verify_server_address((struct sockaddr *) | 1699 | if (!nfs_verify_server_address(sap)) |
| 1727 | &args->nfs_server.address)) | ||
| 1728 | goto out_no_address; | 1700 | goto out_no_address; |
| 1729 | 1701 | ||
| 1730 | if (!(data->flags & NFS_MOUNT_TCP)) | 1702 | if (!(data->flags & NFS_MOUNT_TCP)) |
| @@ -1772,12 +1744,18 @@ static int nfs_validate_mount_data(void *options, | |||
| 1772 | if (nfs_parse_mount_options((char *)options, args) == 0) | 1744 | if (nfs_parse_mount_options((char *)options, args) == 0) |
| 1773 | return -EINVAL; | 1745 | return -EINVAL; |
| 1774 | 1746 | ||
| 1775 | if (!nfs_verify_server_address((struct sockaddr *) | 1747 | if (!nfs_verify_server_address(sap)) |
| 1776 | &args->nfs_server.address)) | ||
| 1777 | goto out_no_address; | 1748 | goto out_no_address; |
| 1778 | 1749 | ||
| 1779 | nfs_set_port((struct sockaddr *)&args->nfs_server.address, | 1750 | if (args->version == 4) |
| 1780 | args->nfs_server.port); | 1751 | #ifdef CONFIG_NFS_V4 |
| 1752 | return nfs4_validate_text_mount_data(options, | ||
| 1753 | args, dev_name); | ||
| 1754 | #else | ||
| 1755 | goto out_v4_not_compiled; | ||
| 1756 | #endif | ||
| 1757 | |||
| 1758 | nfs_set_default_port(sap, args->nfs_server.port, 0); | ||
| 1781 | 1759 | ||
| 1782 | nfs_set_mount_transport_protocol(args); | 1760 | nfs_set_mount_transport_protocol(args); |
| 1783 | 1761 | ||
| @@ -1825,6 +1803,12 @@ out_v3_not_compiled: | |||
| 1825 | return -EPROTONOSUPPORT; | 1803 | return -EPROTONOSUPPORT; |
| 1826 | #endif /* !CONFIG_NFS_V3 */ | 1804 | #endif /* !CONFIG_NFS_V3 */ |
| 1827 | 1805 | ||
| 1806 | #ifndef CONFIG_NFS_V4 | ||
| 1807 | out_v4_not_compiled: | ||
| 1808 | dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n"); | ||
| 1809 | return -EPROTONOSUPPORT; | ||
| 1810 | #endif /* !CONFIG_NFS_V4 */ | ||
| 1811 | |||
| 1828 | out_nomem: | 1812 | out_nomem: |
| 1829 | dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); | 1813 | dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); |
| 1830 | return -ENOMEM; | 1814 | return -ENOMEM; |
| @@ -1934,6 +1918,8 @@ static inline void nfs_initialise_sb(struct super_block *sb) | |||
| 1934 | if (server->flags & NFS_MOUNT_NOAC) | 1918 | if (server->flags & NFS_MOUNT_NOAC) |
| 1935 | sb->s_flags |= MS_SYNCHRONOUS; | 1919 | sb->s_flags |= MS_SYNCHRONOUS; |
| 1936 | 1920 | ||
| 1921 | sb->s_bdi = &server->backing_dev_info; | ||
| 1922 | |||
| 1937 | nfs_super_set_maxbytes(sb, server->maxfilesize); | 1923 | nfs_super_set_maxbytes(sb, server->maxfilesize); |
| 1938 | } | 1924 | } |
| 1939 | 1925 | ||
| @@ -2120,6 +2106,14 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
| 2120 | if (error < 0) | 2106 | if (error < 0) |
| 2121 | goto out; | 2107 | goto out; |
| 2122 | 2108 | ||
| 2109 | #ifdef CONFIG_NFS_V4 | ||
| 2110 | if (data->version == 4) { | ||
| 2111 | error = nfs4_try_mount(flags, dev_name, data, mnt); | ||
| 2112 | kfree(data->client_address); | ||
| 2113 | goto out; | ||
| 2114 | } | ||
| 2115 | #endif /* CONFIG_NFS_V4 */ | ||
| 2116 | |||
| 2123 | /* Get a volume representation */ | 2117 | /* Get a volume representation */ |
| 2124 | server = nfs_create_server(data, mntfh); | 2118 | server = nfs_create_server(data, mntfh); |
| 2125 | if (IS_ERR(server)) { | 2119 | if (IS_ERR(server)) { |
| @@ -2317,6 +2311,43 @@ static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) | |||
| 2317 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3); | 2311 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3); |
| 2318 | } | 2312 | } |
| 2319 | 2313 | ||
| 2314 | static int nfs4_validate_text_mount_data(void *options, | ||
| 2315 | struct nfs_parsed_mount_data *args, | ||
| 2316 | const char *dev_name) | ||
| 2317 | { | ||
| 2318 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; | ||
| 2319 | |||
| 2320 | nfs_set_default_port(sap, args->nfs_server.port, NFS_PORT); | ||
| 2321 | |||
| 2322 | nfs_validate_transport_protocol(args); | ||
| 2323 | |||
| 2324 | nfs4_validate_mount_flags(args); | ||
| 2325 | |||
| 2326 | if (args->version != 4) { | ||
| 2327 | dfprintk(MOUNT, | ||
| 2328 | "NFS4: Illegal mount version\n"); | ||
| 2329 | return -EINVAL; | ||
| 2330 | } | ||
| 2331 | |||
| 2332 | if (args->auth_flavor_len > 1) { | ||
| 2333 | dfprintk(MOUNT, | ||
| 2334 | "NFS4: Too many RPC auth flavours specified\n"); | ||
| 2335 | return -EINVAL; | ||
| 2336 | } | ||
| 2337 | |||
| 2338 | if (args->client_address == NULL) { | ||
| 2339 | dfprintk(MOUNT, | ||
| 2340 | "NFS4: mount program didn't pass callback address\n"); | ||
| 2341 | return -EINVAL; | ||
| 2342 | } | ||
| 2343 | |||
| 2344 | return nfs_parse_devname(dev_name, | ||
| 2345 | &args->nfs_server.hostname, | ||
| 2346 | NFS4_MAXNAMLEN, | ||
| 2347 | &args->nfs_server.export_path, | ||
| 2348 | NFS4_MAXPATHLEN); | ||
| 2349 | } | ||
| 2350 | |||
| 2320 | /* | 2351 | /* |
| 2321 | * Validate NFSv4 mount options | 2352 | * Validate NFSv4 mount options |
| 2322 | */ | 2353 | */ |
| @@ -2324,7 +2355,7 @@ static int nfs4_validate_mount_data(void *options, | |||
| 2324 | struct nfs_parsed_mount_data *args, | 2355 | struct nfs_parsed_mount_data *args, |
| 2325 | const char *dev_name) | 2356 | const char *dev_name) |
| 2326 | { | 2357 | { |
| 2327 | struct sockaddr_in *ap; | 2358 | struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; |
| 2328 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; | 2359 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; |
| 2329 | char *c; | 2360 | char *c; |
| 2330 | 2361 | ||
| @@ -2337,23 +2368,22 @@ static int nfs4_validate_mount_data(void *options, | |||
| 2337 | args->acregmax = NFS_DEF_ACREGMAX; | 2368 | args->acregmax = NFS_DEF_ACREGMAX; |
| 2338 | args->acdirmin = NFS_DEF_ACDIRMIN; | 2369 | args->acdirmin = NFS_DEF_ACDIRMIN; |
| 2339 | args->acdirmax = NFS_DEF_ACDIRMAX; | 2370 | args->acdirmax = NFS_DEF_ACDIRMAX; |
| 2340 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | 2371 | args->nfs_server.port = NFS_UNSPEC_PORT; |
| 2341 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 2372 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
| 2342 | args->auth_flavor_len = 0; | 2373 | args->auth_flavor_len = 1; |
| 2374 | args->version = 4; | ||
| 2343 | args->minorversion = 0; | 2375 | args->minorversion = 0; |
| 2344 | 2376 | ||
| 2345 | switch (data->version) { | 2377 | switch (data->version) { |
| 2346 | case 1: | 2378 | case 1: |
| 2347 | ap = (struct sockaddr_in *)&args->nfs_server.address; | ||
| 2348 | if (data->host_addrlen > sizeof(args->nfs_server.address)) | 2379 | if (data->host_addrlen > sizeof(args->nfs_server.address)) |
| 2349 | goto out_no_address; | 2380 | goto out_no_address; |
| 2350 | if (data->host_addrlen == 0) | 2381 | if (data->host_addrlen == 0) |
| 2351 | goto out_no_address; | 2382 | goto out_no_address; |
| 2352 | args->nfs_server.addrlen = data->host_addrlen; | 2383 | args->nfs_server.addrlen = data->host_addrlen; |
| 2353 | if (copy_from_user(ap, data->host_addr, data->host_addrlen)) | 2384 | if (copy_from_user(sap, data->host_addr, data->host_addrlen)) |
| 2354 | return -EFAULT; | 2385 | return -EFAULT; |
| 2355 | if (!nfs_verify_server_address((struct sockaddr *) | 2386 | if (!nfs_verify_server_address(sap)) |
| 2356 | &args->nfs_server.address)) | ||
| 2357 | goto out_no_address; | 2387 | goto out_no_address; |
| 2358 | 2388 | ||
| 2359 | if (data->auth_flavourlen) { | 2389 | if (data->auth_flavourlen) { |
| @@ -2399,39 +2429,14 @@ static int nfs4_validate_mount_data(void *options, | |||
| 2399 | nfs_validate_transport_protocol(args); | 2429 | nfs_validate_transport_protocol(args); |
| 2400 | 2430 | ||
| 2401 | break; | 2431 | break; |
| 2402 | default: { | 2432 | default: |
| 2403 | int status; | ||
| 2404 | |||
| 2405 | if (nfs_parse_mount_options((char *)options, args) == 0) | 2433 | if (nfs_parse_mount_options((char *)options, args) == 0) |
| 2406 | return -EINVAL; | 2434 | return -EINVAL; |
| 2407 | 2435 | ||
| 2408 | if (!nfs_verify_server_address((struct sockaddr *) | 2436 | if (!nfs_verify_server_address(sap)) |
| 2409 | &args->nfs_server.address)) | ||
| 2410 | return -EINVAL; | 2437 | return -EINVAL; |
| 2411 | 2438 | ||
| 2412 | nfs_set_port((struct sockaddr *)&args->nfs_server.address, | 2439 | return nfs4_validate_text_mount_data(options, args, dev_name); |
| 2413 | args->nfs_server.port); | ||
| 2414 | |||
| 2415 | nfs_validate_transport_protocol(args); | ||
| 2416 | |||
| 2417 | nfs4_validate_mount_flags(args); | ||
| 2418 | |||
| 2419 | if (args->auth_flavor_len > 1) | ||
| 2420 | goto out_inval_auth; | ||
| 2421 | |||
| 2422 | if (args->client_address == NULL) | ||
| 2423 | goto out_no_client_address; | ||
| 2424 | |||
| 2425 | status = nfs_parse_devname(dev_name, | ||
| 2426 | &args->nfs_server.hostname, | ||
| 2427 | NFS4_MAXNAMLEN, | ||
| 2428 | &args->nfs_server.export_path, | ||
| 2429 | NFS4_MAXPATHLEN); | ||
| 2430 | if (status < 0) | ||
| 2431 | return status; | ||
| 2432 | |||
| 2433 | break; | ||
| 2434 | } | ||
| 2435 | } | 2440 | } |
| 2436 | 2441 | ||
| 2437 | return 0; | 2442 | return 0; |
| @@ -2448,10 +2453,6 @@ out_inval_auth: | |||
| 2448 | out_no_address: | 2453 | out_no_address: |
| 2449 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); | 2454 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); |
| 2450 | return -EINVAL; | 2455 | return -EINVAL; |
| 2451 | |||
| 2452 | out_no_client_address: | ||
| 2453 | dfprintk(MOUNT, "NFS4: mount program didn't pass callback address\n"); | ||
| 2454 | return -EINVAL; | ||
| 2455 | } | 2456 | } |
| 2456 | 2457 | ||
| 2457 | /* | 2458 | /* |
| @@ -2618,6 +2619,34 @@ out_err: | |||
| 2618 | return ret; | 2619 | return ret; |
| 2619 | } | 2620 | } |
| 2620 | 2621 | ||
| 2622 | static int nfs4_try_mount(int flags, const char *dev_name, | ||
| 2623 | struct nfs_parsed_mount_data *data, | ||
| 2624 | struct vfsmount *mnt) | ||
| 2625 | { | ||
| 2626 | char *export_path; | ||
| 2627 | struct vfsmount *root_mnt; | ||
| 2628 | int error; | ||
| 2629 | |||
| 2630 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | ||
| 2631 | |||
| 2632 | export_path = data->nfs_server.export_path; | ||
| 2633 | data->nfs_server.export_path = "/"; | ||
| 2634 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, | ||
| 2635 | data->nfs_server.hostname); | ||
| 2636 | data->nfs_server.export_path = export_path; | ||
| 2637 | |||
| 2638 | error = PTR_ERR(root_mnt); | ||
| 2639 | if (IS_ERR(root_mnt)) | ||
| 2640 | goto out; | ||
| 2641 | |||
| 2642 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
| 2643 | |||
| 2644 | out: | ||
| 2645 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n", error, | ||
| 2646 | error != 0 ? " [error]" : ""); | ||
| 2647 | return error; | ||
| 2648 | } | ||
| 2649 | |||
| 2621 | /* | 2650 | /* |
| 2622 | * Get the superblock for an NFS4 mountpoint | 2651 | * Get the superblock for an NFS4 mountpoint |
| 2623 | */ | 2652 | */ |
| @@ -2625,8 +2654,6 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
| 2625 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 2654 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) |
| 2626 | { | 2655 | { |
| 2627 | struct nfs_parsed_mount_data *data; | 2656 | struct nfs_parsed_mount_data *data; |
| 2628 | char *export_path; | ||
| 2629 | struct vfsmount *root_mnt; | ||
| 2630 | int error = -ENOMEM; | 2657 | int error = -ENOMEM; |
| 2631 | 2658 | ||
| 2632 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 2659 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
| @@ -2638,17 +2665,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
| 2638 | if (error < 0) | 2665 | if (error < 0) |
| 2639 | goto out; | 2666 | goto out; |
| 2640 | 2667 | ||
| 2641 | export_path = data->nfs_server.export_path; | 2668 | error = nfs4_try_mount(flags, dev_name, data, mnt); |
| 2642 | data->nfs_server.export_path = "/"; | ||
| 2643 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, | ||
| 2644 | data->nfs_server.hostname); | ||
| 2645 | data->nfs_server.export_path = export_path; | ||
| 2646 | |||
| 2647 | error = PTR_ERR(root_mnt); | ||
| 2648 | if (IS_ERR(root_mnt)) | ||
| 2649 | goto out; | ||
| 2650 | |||
| 2651 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
| 2652 | 2669 | ||
| 2653 | out: | 2670 | out: |
| 2654 | kfree(data->client_address); | 2671 | kfree(data->client_address); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index a34fae21fe1..53eb26c16b5 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/file.h> | 13 | #include <linux/file.h> |
| 14 | #include <linux/writeback.h> | 14 | #include <linux/writeback.h> |
| 15 | #include <linux/swap.h> | 15 | #include <linux/swap.h> |
| 16 | #include <linux/migrate.h> | ||
| 16 | 17 | ||
| 17 | #include <linux/sunrpc/clnt.h> | 18 | #include <linux/sunrpc/clnt.h> |
| 18 | #include <linux/nfs_fs.h> | 19 | #include <linux/nfs_fs.h> |
| @@ -26,6 +27,7 @@ | |||
| 26 | #include "internal.h" | 27 | #include "internal.h" |
| 27 | #include "iostat.h" | 28 | #include "iostat.h" |
| 28 | #include "nfs4_fs.h" | 29 | #include "nfs4_fs.h" |
| 30 | #include "fscache.h" | ||
| 29 | 31 | ||
| 30 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 32 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
| 31 | 33 | ||
| @@ -218,24 +220,17 @@ static void nfs_end_page_writeback(struct page *page) | |||
| 218 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | 220 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
| 219 | } | 221 | } |
| 220 | 222 | ||
| 221 | /* | 223 | static struct nfs_page *nfs_find_and_lock_request(struct page *page) |
| 222 | * Find an associated nfs write request, and prepare to flush it out | ||
| 223 | * May return an error if the user signalled nfs_wait_on_request(). | ||
| 224 | */ | ||
| 225 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | ||
| 226 | struct page *page) | ||
| 227 | { | 224 | { |
| 228 | struct inode *inode = page->mapping->host; | 225 | struct inode *inode = page->mapping->host; |
| 229 | struct nfs_page *req; | 226 | struct nfs_page *req; |
| 230 | int ret; | 227 | int ret; |
| 231 | 228 | ||
| 232 | spin_lock(&inode->i_lock); | 229 | spin_lock(&inode->i_lock); |
| 233 | for(;;) { | 230 | for (;;) { |
| 234 | req = nfs_page_find_request_locked(page); | 231 | req = nfs_page_find_request_locked(page); |
| 235 | if (req == NULL) { | 232 | if (req == NULL) |
| 236 | spin_unlock(&inode->i_lock); | 233 | break; |
| 237 | return 0; | ||
| 238 | } | ||
| 239 | if (nfs_set_page_tag_locked(req)) | 234 | if (nfs_set_page_tag_locked(req)) |
| 240 | break; | 235 | break; |
| 241 | /* Note: If we hold the page lock, as is the case in nfs_writepage, | 236 | /* Note: If we hold the page lock, as is the case in nfs_writepage, |
| @@ -247,23 +242,40 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
| 247 | ret = nfs_wait_on_request(req); | 242 | ret = nfs_wait_on_request(req); |
| 248 | nfs_release_request(req); | 243 | nfs_release_request(req); |
| 249 | if (ret != 0) | 244 | if (ret != 0) |
| 250 | return ret; | 245 | return ERR_PTR(ret); |
| 251 | spin_lock(&inode->i_lock); | 246 | spin_lock(&inode->i_lock); |
| 252 | } | 247 | } |
| 253 | if (test_bit(PG_CLEAN, &req->wb_flags)) { | ||
| 254 | spin_unlock(&inode->i_lock); | ||
| 255 | BUG(); | ||
| 256 | } | ||
| 257 | if (nfs_set_page_writeback(page) != 0) { | ||
| 258 | spin_unlock(&inode->i_lock); | ||
| 259 | BUG(); | ||
| 260 | } | ||
| 261 | spin_unlock(&inode->i_lock); | 248 | spin_unlock(&inode->i_lock); |
| 249 | return req; | ||
| 250 | } | ||
| 251 | |||
| 252 | /* | ||
| 253 | * Find an associated nfs write request, and prepare to flush it out | ||
| 254 | * May return an error if the user signalled nfs_wait_on_request(). | ||
| 255 | */ | ||
| 256 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | ||
| 257 | struct page *page) | ||
| 258 | { | ||
| 259 | struct nfs_page *req; | ||
| 260 | int ret = 0; | ||
| 261 | |||
| 262 | req = nfs_find_and_lock_request(page); | ||
| 263 | if (!req) | ||
| 264 | goto out; | ||
| 265 | ret = PTR_ERR(req); | ||
| 266 | if (IS_ERR(req)) | ||
| 267 | goto out; | ||
| 268 | |||
| 269 | ret = nfs_set_page_writeback(page); | ||
| 270 | BUG_ON(ret != 0); | ||
| 271 | BUG_ON(test_bit(PG_CLEAN, &req->wb_flags)); | ||
| 272 | |||
| 262 | if (!nfs_pageio_add_request(pgio, req)) { | 273 | if (!nfs_pageio_add_request(pgio, req)) { |
| 263 | nfs_redirty_request(req); | 274 | nfs_redirty_request(req); |
| 264 | return pgio->pg_error; | 275 | ret = pgio->pg_error; |
| 265 | } | 276 | } |
| 266 | return 0; | 277 | out: |
| 278 | return ret; | ||
| 267 | } | 279 | } |
| 268 | 280 | ||
| 269 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) | 281 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) |
| @@ -1478,7 +1490,6 @@ static int nfs_write_mapping(struct address_space *mapping, int how) | |||
| 1478 | .nr_to_write = LONG_MAX, | 1490 | .nr_to_write = LONG_MAX, |
| 1479 | .range_start = 0, | 1491 | .range_start = 0, |
| 1480 | .range_end = LLONG_MAX, | 1492 | .range_end = LLONG_MAX, |
| 1481 | .for_writepages = 1, | ||
| 1482 | }; | 1493 | }; |
| 1483 | 1494 | ||
| 1484 | return __nfs_write_mapping(mapping, &wbc, how); | 1495 | return __nfs_write_mapping(mapping, &wbc, how); |
| @@ -1580,6 +1591,41 @@ int nfs_wb_page(struct inode *inode, struct page* page) | |||
| 1580 | return nfs_wb_page_priority(inode, page, FLUSH_STABLE); | 1591 | return nfs_wb_page_priority(inode, page, FLUSH_STABLE); |
| 1581 | } | 1592 | } |
| 1582 | 1593 | ||
| 1594 | #ifdef CONFIG_MIGRATION | ||
| 1595 | int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | ||
| 1596 | struct page *page) | ||
| 1597 | { | ||
| 1598 | struct nfs_page *req; | ||
| 1599 | int ret; | ||
| 1600 | |||
| 1601 | if (PageFsCache(page)) | ||
| 1602 | nfs_fscache_release_page(page, GFP_KERNEL); | ||
| 1603 | |||
| 1604 | req = nfs_find_and_lock_request(page); | ||
| 1605 | ret = PTR_ERR(req); | ||
| 1606 | if (IS_ERR(req)) | ||
| 1607 | goto out; | ||
| 1608 | |||
| 1609 | ret = migrate_page(mapping, newpage, page); | ||
| 1610 | if (!req) | ||
| 1611 | goto out; | ||
| 1612 | if (ret) | ||
| 1613 | goto out_unlock; | ||
| 1614 | page_cache_get(newpage); | ||
| 1615 | req->wb_page = newpage; | ||
| 1616 | SetPagePrivate(newpage); | ||
| 1617 | set_page_private(newpage, page_private(page)); | ||
| 1618 | ClearPagePrivate(page); | ||
| 1619 | set_page_private(page, 0); | ||
| 1620 | page_cache_release(page); | ||
| 1621 | out_unlock: | ||
| 1622 | nfs_clear_page_tag_locked(req); | ||
| 1623 | nfs_release_request(req); | ||
| 1624 | out: | ||
| 1625 | return ret; | ||
| 1626 | } | ||
| 1627 | #endif | ||
| 1628 | |||
| 1583 | int __init nfs_init_writepagecache(void) | 1629 | int __init nfs_init_writepagecache(void) |
| 1584 | { | 1630 | { |
| 1585 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", | 1631 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", |
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 5573508f707..36fcabbf518 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
| @@ -34,6 +34,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | |||
| 34 | int flags = nfsexp_flags(rqstp, exp); | 34 | int flags = nfsexp_flags(rqstp, exp); |
| 35 | int ret; | 35 | int ret; |
| 36 | 36 | ||
| 37 | validate_process_creds(); | ||
| 38 | |||
| 37 | /* discard any old override before preparing the new set */ | 39 | /* discard any old override before preparing the new set */ |
| 38 | revert_creds(get_cred(current->real_cred)); | 40 | revert_creds(get_cred(current->real_cred)); |
| 39 | new = prepare_creds(); | 41 | new = prepare_creds(); |
| @@ -86,8 +88,10 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | |||
| 86 | else | 88 | else |
| 87 | new->cap_effective = cap_raise_nfsd_set(new->cap_effective, | 89 | new->cap_effective = cap_raise_nfsd_set(new->cap_effective, |
| 88 | new->cap_permitted); | 90 | new->cap_permitted); |
| 91 | validate_process_creds(); | ||
| 89 | put_cred(override_creds(new)); | 92 | put_cred(override_creds(new)); |
| 90 | put_cred(new); | 93 | put_cred(new); |
| 94 | validate_process_creds(); | ||
| 91 | return 0; | 95 | return 0; |
| 92 | 96 | ||
| 93 | oom: | 97 | oom: |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index b92a27629fb..d9462643155 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
| @@ -85,6 +85,11 @@ static void expkey_request(struct cache_detail *cd, | |||
| 85 | (*bpp)[-1] = '\n'; | 85 | (*bpp)[-1] = '\n'; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | static int expkey_upcall(struct cache_detail *cd, struct cache_head *h) | ||
| 89 | { | ||
| 90 | return sunrpc_cache_pipe_upcall(cd, h, expkey_request); | ||
| 91 | } | ||
| 92 | |||
| 88 | static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old); | 93 | static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old); |
| 89 | static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *); | 94 | static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *); |
| 90 | static struct cache_detail svc_expkey_cache; | 95 | static struct cache_detail svc_expkey_cache; |
| @@ -259,7 +264,7 @@ static struct cache_detail svc_expkey_cache = { | |||
| 259 | .hash_table = expkey_table, | 264 | .hash_table = expkey_table, |
| 260 | .name = "nfsd.fh", | 265 | .name = "nfsd.fh", |
| 261 | .cache_put = expkey_put, | 266 | .cache_put = expkey_put, |
| 262 | .cache_request = expkey_request, | 267 | .cache_upcall = expkey_upcall, |
| 263 | .cache_parse = expkey_parse, | 268 | .cache_parse = expkey_parse, |
| 264 | .cache_show = expkey_show, | 269 | .cache_show = expkey_show, |
| 265 | .match = expkey_match, | 270 | .match = expkey_match, |
| @@ -355,6 +360,11 @@ static void svc_export_request(struct cache_detail *cd, | |||
| 355 | (*bpp)[-1] = '\n'; | 360 | (*bpp)[-1] = '\n'; |
| 356 | } | 361 | } |
| 357 | 362 | ||
| 363 | static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h) | ||
| 364 | { | ||
| 365 | return sunrpc_cache_pipe_upcall(cd, h, svc_export_request); | ||
| 366 | } | ||
| 367 | |||
| 358 | static struct svc_export *svc_export_update(struct svc_export *new, | 368 | static struct svc_export *svc_export_update(struct svc_export *new, |
| 359 | struct svc_export *old); | 369 | struct svc_export *old); |
| 360 | static struct svc_export *svc_export_lookup(struct svc_export *); | 370 | static struct svc_export *svc_export_lookup(struct svc_export *); |
| @@ -724,7 +734,7 @@ struct cache_detail svc_export_cache = { | |||
| 724 | .hash_table = export_table, | 734 | .hash_table = export_table, |
| 725 | .name = "nfsd.export", | 735 | .name = "nfsd.export", |
| 726 | .cache_put = svc_export_put, | 736 | .cache_put = svc_export_put, |
| 727 | .cache_request = svc_export_request, | 737 | .cache_upcall = svc_export_upcall, |
| 728 | .cache_parse = svc_export_parse, | 738 | .cache_parse = svc_export_parse, |
| 729 | .cache_show = svc_export_show, | 739 | .cache_show = svc_export_show, |
| 730 | .match = svc_export_match, | 740 | .match = svc_export_match, |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 5b398421b05..cdfa86fa147 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c | |||
| @@ -146,6 +146,12 @@ idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, | |||
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | static int | 148 | static int |
| 149 | idtoname_upcall(struct cache_detail *cd, struct cache_head *ch) | ||
| 150 | { | ||
| 151 | return sunrpc_cache_pipe_upcall(cd, ch, idtoname_request); | ||
| 152 | } | ||
| 153 | |||
| 154 | static int | ||
| 149 | idtoname_match(struct cache_head *ca, struct cache_head *cb) | 155 | idtoname_match(struct cache_head *ca, struct cache_head *cb) |
| 150 | { | 156 | { |
| 151 | struct ent *a = container_of(ca, struct ent, h); | 157 | struct ent *a = container_of(ca, struct ent, h); |
| @@ -175,10 +181,10 @@ idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) | |||
| 175 | } | 181 | } |
| 176 | 182 | ||
| 177 | static void | 183 | static void |
| 178 | warn_no_idmapd(struct cache_detail *detail) | 184 | warn_no_idmapd(struct cache_detail *detail, int has_died) |
| 179 | { | 185 | { |
| 180 | printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n", | 186 | printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n", |
| 181 | detail->last_close? "died" : "not been started"); | 187 | has_died ? "died" : "not been started"); |
| 182 | } | 188 | } |
| 183 | 189 | ||
| 184 | 190 | ||
| @@ -192,7 +198,7 @@ static struct cache_detail idtoname_cache = { | |||
| 192 | .hash_table = idtoname_table, | 198 | .hash_table = idtoname_table, |
| 193 | .name = "nfs4.idtoname", | 199 | .name = "nfs4.idtoname", |
| 194 | .cache_put = ent_put, | 200 | .cache_put = ent_put, |
| 195 | .cache_request = idtoname_request, | 201 | .cache_upcall = idtoname_upcall, |
| 196 | .cache_parse = idtoname_parse, | 202 | .cache_parse = idtoname_parse, |
| 197 | .cache_show = idtoname_show, | 203 | .cache_show = idtoname_show, |
| 198 | .warn_no_listener = warn_no_idmapd, | 204 | .warn_no_listener = warn_no_idmapd, |
| @@ -325,6 +331,12 @@ nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, | |||
| 325 | } | 331 | } |
| 326 | 332 | ||
| 327 | static int | 333 | static int |
| 334 | nametoid_upcall(struct cache_detail *cd, struct cache_head *ch) | ||
| 335 | { | ||
| 336 | return sunrpc_cache_pipe_upcall(cd, ch, nametoid_request); | ||
| 337 | } | ||
| 338 | |||
| 339 | static int | ||
| 328 | nametoid_match(struct cache_head *ca, struct cache_head *cb) | 340 | nametoid_match(struct cache_head *ca, struct cache_head *cb) |
| 329 | { | 341 | { |
| 330 | struct ent *a = container_of(ca, struct ent, h); | 342 | struct ent *a = container_of(ca, struct ent, h); |
| @@ -363,7 +375,7 @@ static struct cache_detail nametoid_cache = { | |||
| 363 | .hash_table = nametoid_table, | 375 | .hash_table = nametoid_table, |
| 364 | .name = "nfs4.nametoid", | 376 | .name = "nfs4.nametoid", |
| 365 | .cache_put = ent_put, | 377 | .cache_put = ent_put, |
| 366 | .cache_request = nametoid_request, | 378 | .cache_upcall = nametoid_upcall, |
| 367 | .cache_parse = nametoid_parse, | 379 | .cache_parse = nametoid_parse, |
| 368 | .cache_show = nametoid_show, | 380 | .cache_show = nametoid_show, |
| 369 | .warn_no_listener = warn_no_idmapd, | 381 | .warn_no_listener = warn_no_idmapd, |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 6d0847562d8..7e906c5b767 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/nfsd/xdr.h> | 37 | #include <linux/nfsd/xdr.h> |
| 38 | #include <linux/nfsd/syscall.h> | 38 | #include <linux/nfsd/syscall.h> |
| 39 | #include <linux/lockd/lockd.h> | 39 | #include <linux/lockd/lockd.h> |
| 40 | #include <linux/sunrpc/clnt.h> | ||
| 40 | 41 | ||
| 41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
| 42 | #include <net/ipv6.h> | 43 | #include <net/ipv6.h> |
| @@ -490,22 +491,18 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size) | |||
| 490 | * | 491 | * |
| 491 | * Input: | 492 | * Input: |
| 492 | * buf: '\n'-terminated C string containing a | 493 | * buf: '\n'-terminated C string containing a |
| 493 | * presentation format IPv4 address | 494 | * presentation format IP address |
| 494 | * size: length of C string in @buf | 495 | * size: length of C string in @buf |
| 495 | * Output: | 496 | * Output: |
| 496 | * On success: returns zero if all specified locks were released; | 497 | * On success: returns zero if all specified locks were released; |
| 497 | * returns one if one or more locks were not released | 498 | * returns one if one or more locks were not released |
| 498 | * On error: return code is negative errno value | 499 | * On error: return code is negative errno value |
| 499 | * | ||
| 500 | * Note: Only AF_INET client addresses are passed in | ||
| 501 | */ | 500 | */ |
| 502 | static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size) | 501 | static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size) |
| 503 | { | 502 | { |
| 504 | struct sockaddr_in sin = { | 503 | struct sockaddr_storage address; |
| 505 | .sin_family = AF_INET, | 504 | struct sockaddr *sap = (struct sockaddr *)&address; |
| 506 | }; | 505 | size_t salen = sizeof(address); |
| 507 | int b1, b2, b3, b4; | ||
| 508 | char c; | ||
| 509 | char *fo_path; | 506 | char *fo_path; |
| 510 | 507 | ||
| 511 | /* sanity check */ | 508 | /* sanity check */ |
| @@ -519,14 +516,10 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size) | |||
| 519 | if (qword_get(&buf, fo_path, size) < 0) | 516 | if (qword_get(&buf, fo_path, size) < 0) |
| 520 | return -EINVAL; | 517 | return -EINVAL; |
| 521 | 518 | ||
| 522 | /* get ipv4 address */ | 519 | if (rpc_pton(fo_path, size, sap, salen) == 0) |
| 523 | if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4) | ||
| 524 | return -EINVAL; | ||
| 525 | if (b1 > 255 || b2 > 255 || b3 > 255 || b4 > 255) | ||
| 526 | return -EINVAL; | 520 | return -EINVAL; |
| 527 | sin.sin_addr.s_addr = htonl((b1 << 24) | (b2 << 16) | (b3 << 8) | b4); | ||
| 528 | 521 | ||
| 529 | return nlmsvc_unlock_all_by_ip((struct sockaddr *)&sin); | 522 | return nlmsvc_unlock_all_by_ip(sap); |
| 530 | } | 523 | } |
| 531 | 524 | ||
| 532 | /** | 525 | /** |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 492c79b7800..24d58adfe5f 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
| @@ -496,7 +496,9 @@ nfsd(void *vrqstp) | |||
| 496 | /* Lock the export hash tables for reading. */ | 496 | /* Lock the export hash tables for reading. */ |
| 497 | exp_readlock(); | 497 | exp_readlock(); |
| 498 | 498 | ||
| 499 | validate_process_creds(); | ||
| 499 | svc_process(rqstp); | 500 | svc_process(rqstp); |
| 501 | validate_process_creds(); | ||
| 500 | 502 | ||
| 501 | /* Unlock export hash tables */ | 503 | /* Unlock export hash tables */ |
| 502 | exp_readunlock(); | 504 | exp_readunlock(); |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 23341c1063b..8fa09bfbcba 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -684,6 +684,8 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 684 | __be32 err; | 684 | __be32 err; |
| 685 | int host_err; | 685 | int host_err; |
| 686 | 686 | ||
| 687 | validate_process_creds(); | ||
| 688 | |||
| 687 | /* | 689 | /* |
| 688 | * If we get here, then the client has already done an "open", | 690 | * If we get here, then the client has already done an "open", |
| 689 | * and (hopefully) checked permission - so allow OWNER_OVERRIDE | 691 | * and (hopefully) checked permission - so allow OWNER_OVERRIDE |
| @@ -740,6 +742,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 740 | out_nfserr: | 742 | out_nfserr: |
| 741 | err = nfserrno(host_err); | 743 | err = nfserrno(host_err); |
| 742 | out: | 744 | out: |
| 745 | validate_process_creds(); | ||
| 743 | return err; | 746 | return err; |
| 744 | } | 747 | } |
| 745 | 748 | ||
diff --git a/fs/nilfs2/Kconfig b/fs/nilfs2/Kconfig index 72da095d400..251da07b2a1 100644 --- a/fs/nilfs2/Kconfig +++ b/fs/nilfs2/Kconfig | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | config NILFS2_FS | 1 | config NILFS2_FS |
| 2 | tristate "NILFS2 file system support (EXPERIMENTAL)" | 2 | tristate "NILFS2 file system support (EXPERIMENTAL)" |
| 3 | depends on BLOCK && EXPERIMENTAL | 3 | depends on EXPERIMENTAL |
| 4 | select CRC32 | 4 | select CRC32 |
| 5 | help | 5 | help |
| 6 | NILFS2 is a log-structured file system (LFS) supporting continuous | 6 | NILFS2 is a log-structured file system (LFS) supporting continuous |
diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index 99d58a028b9..08834df6ec6 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c | |||
| @@ -36,6 +36,26 @@ struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap) | |||
| 36 | return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode)); | 36 | return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode)); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | /** | ||
| 40 | * nilfs_bmap_lookup_at_level - find a data block or node block | ||
| 41 | * @bmap: bmap | ||
| 42 | * @key: key | ||
| 43 | * @level: level | ||
| 44 | * @ptrp: place to store the value associated to @key | ||
| 45 | * | ||
| 46 | * Description: nilfs_bmap_lookup_at_level() finds a record whose key | ||
| 47 | * matches @key in the block at @level of the bmap. | ||
| 48 | * | ||
| 49 | * Return Value: On success, 0 is returned and the record associated with @key | ||
| 50 | * is stored in the place pointed by @ptrp. On error, one of the following | ||
| 51 | * negative error codes is returned. | ||
| 52 | * | ||
| 53 | * %-EIO - I/O error. | ||
| 54 | * | ||
| 55 | * %-ENOMEM - Insufficient amount of memory available. | ||
| 56 | * | ||
| 57 | * %-ENOENT - A record associated with @key does not exist. | ||
| 58 | */ | ||
| 39 | int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level, | 59 | int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level, |
| 40 | __u64 *ptrp) | 60 | __u64 *ptrp) |
| 41 | { | 61 | { |
| @@ -69,39 +89,6 @@ int nilfs_bmap_lookup_contig(struct nilfs_bmap *bmap, __u64 key, __u64 *ptrp, | |||
| 69 | return ret; | 89 | return ret; |
| 70 | } | 90 | } |
| 71 | 91 | ||
| 72 | /** | ||
| 73 | * nilfs_bmap_lookup - find a record | ||
| 74 | * @bmap: bmap | ||
| 75 | * @key: key | ||
| 76 | * @recp: pointer to record | ||
| 77 | * | ||
| 78 | * Description: nilfs_bmap_lookup() finds a record whose key matches @key in | ||
| 79 | * @bmap. | ||
| 80 | * | ||
| 81 | * Return Value: On success, 0 is returned and the record associated with @key | ||
| 82 | * is stored in the place pointed by @recp. On error, one of the following | ||
| 83 | * negative error codes is returned. | ||
| 84 | * | ||
| 85 | * %-EIO - I/O error. | ||
| 86 | * | ||
| 87 | * %-ENOMEM - Insufficient amount of memory available. | ||
| 88 | * | ||
| 89 | * %-ENOENT - A record associated with @key does not exist. | ||
| 90 | */ | ||
| 91 | int nilfs_bmap_lookup(struct nilfs_bmap *bmap, | ||
| 92 | unsigned long key, | ||
| 93 | unsigned long *recp) | ||
| 94 | { | ||
| 95 | __u64 ptr; | ||
| 96 | int ret; | ||
| 97 | |||
| 98 | /* XXX: use macro for level 1 */ | ||
| 99 | ret = nilfs_bmap_lookup_at_level(bmap, key, 1, &ptr); | ||
| 100 | if (recp != NULL) | ||
| 101 | *recp = ptr; | ||
| 102 | return ret; | ||
| 103 | } | ||
| 104 | |||
| 105 | static int nilfs_bmap_do_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) | 92 | static int nilfs_bmap_do_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) |
| 106 | { | 93 | { |
| 107 | __u64 keys[NILFS_BMAP_SMALL_HIGH + 1]; | 94 | __u64 keys[NILFS_BMAP_SMALL_HIGH + 1]; |
| @@ -469,104 +456,6 @@ __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *bmap) | |||
| 469 | (entries_per_group / NILFS_BMAP_GROUP_DIV); | 456 | (entries_per_group / NILFS_BMAP_GROUP_DIV); |
| 470 | } | 457 | } |
| 471 | 458 | ||
| 472 | int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *bmap, | ||
| 473 | union nilfs_bmap_ptr_req *req) | ||
| 474 | { | ||
| 475 | return nilfs_dat_prepare_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); | ||
| 476 | } | ||
| 477 | |||
| 478 | void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *bmap, | ||
| 479 | union nilfs_bmap_ptr_req *req) | ||
| 480 | { | ||
| 481 | nilfs_dat_commit_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); | ||
| 482 | } | ||
| 483 | |||
| 484 | void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *bmap, | ||
| 485 | union nilfs_bmap_ptr_req *req) | ||
| 486 | { | ||
| 487 | nilfs_dat_abort_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); | ||
| 488 | } | ||
| 489 | |||
| 490 | int nilfs_bmap_start_v(struct nilfs_bmap *bmap, union nilfs_bmap_ptr_req *req, | ||
| 491 | sector_t blocknr) | ||
| 492 | { | ||
| 493 | struct inode *dat = nilfs_bmap_get_dat(bmap); | ||
| 494 | int ret; | ||
| 495 | |||
| 496 | ret = nilfs_dat_prepare_start(dat, &req->bpr_req); | ||
| 497 | if (likely(!ret)) | ||
| 498 | nilfs_dat_commit_start(dat, &req->bpr_req, blocknr); | ||
| 499 | return ret; | ||
| 500 | } | ||
| 501 | |||
| 502 | int nilfs_bmap_prepare_end_v(struct nilfs_bmap *bmap, | ||
| 503 | union nilfs_bmap_ptr_req *req) | ||
| 504 | { | ||
| 505 | return nilfs_dat_prepare_end(nilfs_bmap_get_dat(bmap), &req->bpr_req); | ||
| 506 | } | ||
| 507 | |||
| 508 | void nilfs_bmap_commit_end_v(struct nilfs_bmap *bmap, | ||
| 509 | union nilfs_bmap_ptr_req *req) | ||
| 510 | { | ||
| 511 | nilfs_dat_commit_end(nilfs_bmap_get_dat(bmap), &req->bpr_req, | ||
| 512 | bmap->b_ptr_type == NILFS_BMAP_PTR_VS); | ||
| 513 | } | ||
| 514 | |||
| 515 | void nilfs_bmap_abort_end_v(struct nilfs_bmap *bmap, | ||
| 516 | union nilfs_bmap_ptr_req *req) | ||
| 517 | { | ||
| 518 | nilfs_dat_abort_end(nilfs_bmap_get_dat(bmap), &req->bpr_req); | ||
| 519 | } | ||
| 520 | |||
| 521 | int nilfs_bmap_move_v(const struct nilfs_bmap *bmap, __u64 vblocknr, | ||
| 522 | sector_t blocknr) | ||
| 523 | { | ||
| 524 | return nilfs_dat_move(nilfs_bmap_get_dat(bmap), vblocknr, blocknr); | ||
| 525 | } | ||
| 526 | |||
| 527 | int nilfs_bmap_mark_dirty(const struct nilfs_bmap *bmap, __u64 vblocknr) | ||
| 528 | { | ||
| 529 | return nilfs_dat_mark_dirty(nilfs_bmap_get_dat(bmap), vblocknr); | ||
| 530 | } | ||
| 531 | |||
| 532 | int nilfs_bmap_prepare_update_v(struct nilfs_bmap *bmap, | ||
| 533 | union nilfs_bmap_ptr_req *oldreq, | ||
| 534 | union nilfs_bmap_ptr_req *newreq) | ||
| 535 | { | ||
| 536 | struct inode *dat = nilfs_bmap_get_dat(bmap); | ||
| 537 | int ret; | ||
| 538 | |||
| 539 | ret = nilfs_dat_prepare_end(dat, &oldreq->bpr_req); | ||
| 540 | if (ret < 0) | ||
| 541 | return ret; | ||
| 542 | ret = nilfs_dat_prepare_alloc(dat, &newreq->bpr_req); | ||
| 543 | if (ret < 0) | ||
| 544 | nilfs_dat_abort_end(dat, &oldreq->bpr_req); | ||
| 545 | |||
| 546 | return ret; | ||
| 547 | } | ||
| 548 | |||
| 549 | void nilfs_bmap_commit_update_v(struct nilfs_bmap *bmap, | ||
| 550 | union nilfs_bmap_ptr_req *oldreq, | ||
| 551 | union nilfs_bmap_ptr_req *newreq) | ||
| 552 | { | ||
| 553 | struct inode *dat = nilfs_bmap_get_dat(bmap); | ||
| 554 | |||
| 555 | nilfs_dat_commit_end(dat, &oldreq->bpr_req, | ||
| 556 | bmap->b_ptr_type == NILFS_BMAP_PTR_VS); | ||
| 557 | nilfs_dat_commit_alloc(dat, &newreq->bpr_req); | ||
| 558 | } | ||
| 559 | |||
| 560 | void nilfs_bmap_abort_update_v(struct nilfs_bmap *bmap, | ||
| 561 | union nilfs_bmap_ptr_req *oldreq, | ||
| 562 | union nilfs_bmap_ptr_req *newreq) | ||
| 563 | { | ||
| 564 | struct inode *dat = nilfs_bmap_get_dat(bmap); | ||
| 565 | |||
| 566 | nilfs_dat_abort_end(dat, &oldreq->bpr_req); | ||
| 567 | nilfs_dat_abort_alloc(dat, &newreq->bpr_req); | ||
| 568 | } | ||
| 569 | |||
| 570 | static struct lock_class_key nilfs_bmap_dat_lock_key; | 459 | static struct lock_class_key nilfs_bmap_dat_lock_key; |
| 571 | static struct lock_class_key nilfs_bmap_mdt_lock_key; | 460 | static struct lock_class_key nilfs_bmap_mdt_lock_key; |
| 572 | 461 | ||
diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index b2890cdcef1..9980d7dbab9 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/buffer_head.h> | 28 | #include <linux/buffer_head.h> |
| 29 | #include <linux/nilfs2_fs.h> | 29 | #include <linux/nilfs2_fs.h> |
| 30 | #include "alloc.h" | 30 | #include "alloc.h" |
| 31 | #include "dat.h" | ||
| 31 | 32 | ||
| 32 | #define NILFS_BMAP_INVALID_PTR 0 | 33 | #define NILFS_BMAP_INVALID_PTR 0 |
| 33 | 34 | ||
| @@ -141,7 +142,6 @@ struct nilfs_bmap { | |||
| 141 | int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *); | 142 | int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *); |
| 142 | int nilfs_bmap_read(struct nilfs_bmap *, struct nilfs_inode *); | 143 | int nilfs_bmap_read(struct nilfs_bmap *, struct nilfs_inode *); |
| 143 | void nilfs_bmap_write(struct nilfs_bmap *, struct nilfs_inode *); | 144 | void nilfs_bmap_write(struct nilfs_bmap *, struct nilfs_inode *); |
| 144 | int nilfs_bmap_lookup(struct nilfs_bmap *, unsigned long, unsigned long *); | ||
| 145 | int nilfs_bmap_lookup_contig(struct nilfs_bmap *, __u64, __u64 *, unsigned); | 145 | int nilfs_bmap_lookup_contig(struct nilfs_bmap *, __u64, __u64 *, unsigned); |
| 146 | int nilfs_bmap_insert(struct nilfs_bmap *, unsigned long, unsigned long); | 146 | int nilfs_bmap_insert(struct nilfs_bmap *, unsigned long, unsigned long); |
| 147 | int nilfs_bmap_delete(struct nilfs_bmap *, unsigned long); | 147 | int nilfs_bmap_delete(struct nilfs_bmap *, unsigned long); |
| @@ -160,90 +160,76 @@ void nilfs_bmap_init_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); | |||
| 160 | void nilfs_bmap_commit_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); | 160 | void nilfs_bmap_commit_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); |
| 161 | 161 | ||
| 162 | 162 | ||
| 163 | static inline int nilfs_bmap_lookup(struct nilfs_bmap *bmap, __u64 key, | ||
| 164 | __u64 *ptr) | ||
| 165 | { | ||
| 166 | return nilfs_bmap_lookup_at_level(bmap, key, 1, ptr); | ||
| 167 | } | ||
| 168 | |||
| 163 | /* | 169 | /* |
| 164 | * Internal use only | 170 | * Internal use only |
| 165 | */ | 171 | */ |
| 166 | struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *); | 172 | struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *); |
| 167 | int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *, | ||
| 168 | union nilfs_bmap_ptr_req *); | ||
| 169 | void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *, | ||
| 170 | union nilfs_bmap_ptr_req *); | ||
| 171 | void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *, | ||
| 172 | union nilfs_bmap_ptr_req *); | ||
| 173 | 173 | ||
| 174 | static inline int nilfs_bmap_prepare_alloc_ptr(struct nilfs_bmap *bmap, | 174 | static inline int nilfs_bmap_prepare_alloc_ptr(struct nilfs_bmap *bmap, |
| 175 | union nilfs_bmap_ptr_req *req) | 175 | union nilfs_bmap_ptr_req *req, |
| 176 | struct inode *dat) | ||
| 176 | { | 177 | { |
| 177 | if (NILFS_BMAP_USE_VBN(bmap)) | 178 | if (dat) |
| 178 | return nilfs_bmap_prepare_alloc_v(bmap, req); | 179 | return nilfs_dat_prepare_alloc(dat, &req->bpr_req); |
| 179 | /* ignore target ptr */ | 180 | /* ignore target ptr */ |
| 180 | req->bpr_ptr = bmap->b_last_allocated_ptr++; | 181 | req->bpr_ptr = bmap->b_last_allocated_ptr++; |
| 181 | return 0; | 182 | return 0; |
| 182 | } | 183 | } |
| 183 | 184 | ||
| 184 | static inline void nilfs_bmap_commit_alloc_ptr(struct nilfs_bmap *bmap, | 185 | static inline void nilfs_bmap_commit_alloc_ptr(struct nilfs_bmap *bmap, |
| 185 | union nilfs_bmap_ptr_req *req) | 186 | union nilfs_bmap_ptr_req *req, |
| 187 | struct inode *dat) | ||
| 186 | { | 188 | { |
| 187 | if (NILFS_BMAP_USE_VBN(bmap)) | 189 | if (dat) |
| 188 | nilfs_bmap_commit_alloc_v(bmap, req); | 190 | nilfs_dat_commit_alloc(dat, &req->bpr_req); |
| 189 | } | 191 | } |
| 190 | 192 | ||
| 191 | static inline void nilfs_bmap_abort_alloc_ptr(struct nilfs_bmap *bmap, | 193 | static inline void nilfs_bmap_abort_alloc_ptr(struct nilfs_bmap *bmap, |
| 192 | union nilfs_bmap_ptr_req *req) | 194 | union nilfs_bmap_ptr_req *req, |
| 195 | struct inode *dat) | ||
| 193 | { | 196 | { |
| 194 | if (NILFS_BMAP_USE_VBN(bmap)) | 197 | if (dat) |
| 195 | nilfs_bmap_abort_alloc_v(bmap, req); | 198 | nilfs_dat_abort_alloc(dat, &req->bpr_req); |
| 196 | else | 199 | else |
| 197 | bmap->b_last_allocated_ptr--; | 200 | bmap->b_last_allocated_ptr--; |
| 198 | } | 201 | } |
| 199 | 202 | ||
| 200 | int nilfs_bmap_prepare_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); | ||
| 201 | void nilfs_bmap_commit_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); | ||
| 202 | void nilfs_bmap_abort_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); | ||
| 203 | |||
| 204 | static inline int nilfs_bmap_prepare_end_ptr(struct nilfs_bmap *bmap, | 203 | static inline int nilfs_bmap_prepare_end_ptr(struct nilfs_bmap *bmap, |
| 205 | union nilfs_bmap_ptr_req *req) | 204 | union nilfs_bmap_ptr_req *req, |
| 205 | struct inode *dat) | ||
| 206 | { | 206 | { |
| 207 | return NILFS_BMAP_USE_VBN(bmap) ? | 207 | return dat ? nilfs_dat_prepare_end(dat, &req->bpr_req) : 0; |
| 208 | nilfs_bmap_prepare_end_v(bmap, req) : 0; | ||
| 209 | } | 208 | } |
| 210 | 209 | ||
| 211 | static inline void nilfs_bmap_commit_end_ptr(struct nilfs_bmap *bmap, | 210 | static inline void nilfs_bmap_commit_end_ptr(struct nilfs_bmap *bmap, |
| 212 | union nilfs_bmap_ptr_req *req) | 211 | union nilfs_bmap_ptr_req *req, |
| 212 | struct inode *dat) | ||
| 213 | { | 213 | { |
| 214 | if (NILFS_BMAP_USE_VBN(bmap)) | 214 | if (dat) |
| 215 | nilfs_bmap_commit_end_v(bmap, req); | 215 | nilfs_dat_commit_end(dat, &req->bpr_req, |
| 216 | bmap->b_ptr_type == NILFS_BMAP_PTR_VS); | ||
| 216 | } | 217 | } |
| 217 | 218 | ||
| 218 | static inline void nilfs_bmap_abort_end_ptr(struct nilfs_bmap *bmap, | 219 | static inline void nilfs_bmap_abort_end_ptr(struct nilfs_bmap *bmap, |
| 219 | union nilfs_bmap_ptr_req *req) | 220 | union nilfs_bmap_ptr_req *req, |
| 221 | struct inode *dat) | ||
| 220 | { | 222 | { |
| 221 | if (NILFS_BMAP_USE_VBN(bmap)) | 223 | if (dat) |
| 222 | nilfs_bmap_abort_end_v(bmap, req); | 224 | nilfs_dat_abort_end(dat, &req->bpr_req); |
| 223 | } | 225 | } |
| 224 | 226 | ||
| 225 | int nilfs_bmap_start_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *, | ||
| 226 | sector_t); | ||
| 227 | int nilfs_bmap_move_v(const struct nilfs_bmap *, __u64, sector_t); | ||
| 228 | int nilfs_bmap_mark_dirty(const struct nilfs_bmap *, __u64); | ||
| 229 | |||
| 230 | |||
| 231 | __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *, | 227 | __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *, |
| 232 | const struct buffer_head *); | 228 | const struct buffer_head *); |
| 233 | 229 | ||
| 234 | __u64 nilfs_bmap_find_target_seq(const struct nilfs_bmap *, __u64); | 230 | __u64 nilfs_bmap_find_target_seq(const struct nilfs_bmap *, __u64); |
| 235 | __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *); | 231 | __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *); |
| 236 | 232 | ||
| 237 | int nilfs_bmap_prepare_update_v(struct nilfs_bmap *, | ||
| 238 | union nilfs_bmap_ptr_req *, | ||
| 239 | union nilfs_bmap_ptr_req *); | ||
| 240 | void nilfs_bmap_commit_update_v(struct nilfs_bmap *, | ||
| 241 | union nilfs_bmap_ptr_req *, | ||
| 242 | union nilfs_bmap_ptr_req *); | ||
| 243 | void nilfs_bmap_abort_update_v(struct nilfs_bmap *, | ||
| 244 | union nilfs_bmap_ptr_req *, | ||
| 245 | union nilfs_bmap_ptr_req *); | ||
| 246 | |||
| 247 | void nilfs_bmap_add_blocks(const struct nilfs_bmap *, int); | 233 | void nilfs_bmap_add_blocks(const struct nilfs_bmap *, int); |
| 248 | void nilfs_bmap_sub_blocks(const struct nilfs_bmap *, int); | 234 | void nilfs_bmap_sub_blocks(const struct nilfs_bmap *, int); |
| 249 | 235 | ||
diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c index 7e0b61be212..c668bca579c 100644 --- a/fs/nilfs2/btnode.c +++ b/fs/nilfs2/btnode.c | |||
| @@ -209,6 +209,7 @@ int nilfs_btnode_prepare_change_key(struct address_space *btnc, | |||
| 209 | * We cannot call radix_tree_preload for the kernels older | 209 | * We cannot call radix_tree_preload for the kernels older |
| 210 | * than 2.6.23, because it is not exported for modules. | 210 | * than 2.6.23, because it is not exported for modules. |
| 211 | */ | 211 | */ |
| 212 | retry: | ||
| 212 | err = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM); | 213 | err = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM); |
| 213 | if (err) | 214 | if (err) |
| 214 | goto failed_unlock; | 215 | goto failed_unlock; |
| @@ -219,7 +220,6 @@ int nilfs_btnode_prepare_change_key(struct address_space *btnc, | |||
| 219 | (unsigned long long)oldkey, | 220 | (unsigned long long)oldkey, |
| 220 | (unsigned long long)newkey); | 221 | (unsigned long long)newkey); |
| 221 | 222 | ||
| 222 | retry: | ||
| 223 | spin_lock_irq(&btnc->tree_lock); | 223 | spin_lock_irq(&btnc->tree_lock); |
| 224 | err = radix_tree_insert(&btnc->page_tree, newkey, obh->b_page); | 224 | err = radix_tree_insert(&btnc->page_tree, newkey, obh->b_page); |
| 225 | spin_unlock_irq(&btnc->tree_lock); | 225 | spin_unlock_irq(&btnc->tree_lock); |
diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index aa412724b64..e25b507a474 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c | |||
| @@ -71,21 +71,17 @@ void nilfs_btree_path_cache_destroy(void) | |||
| 71 | kmem_cache_destroy(nilfs_btree_path_cache); | 71 | kmem_cache_destroy(nilfs_btree_path_cache); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static inline struct nilfs_btree_path * | 74 | static inline struct nilfs_btree_path *nilfs_btree_alloc_path(void) |
| 75 | nilfs_btree_alloc_path(const struct nilfs_btree *btree) | ||
| 76 | { | 75 | { |
| 77 | return (struct nilfs_btree_path *) | 76 | return kmem_cache_alloc(nilfs_btree_path_cache, GFP_NOFS); |
| 78 | kmem_cache_alloc(nilfs_btree_path_cache, GFP_NOFS); | ||
| 79 | } | 77 | } |
| 80 | 78 | ||
| 81 | static inline void nilfs_btree_free_path(const struct nilfs_btree *btree, | 79 | static inline void nilfs_btree_free_path(struct nilfs_btree_path *path) |
| 82 | struct nilfs_btree_path *path) | ||
| 83 | { | 80 | { |
| 84 | kmem_cache_free(nilfs_btree_path_cache, path); | 81 | kmem_cache_free(nilfs_btree_path_cache, path); |
| 85 | } | 82 | } |
| 86 | 83 | ||
| 87 | static void nilfs_btree_init_path(const struct nilfs_btree *btree, | 84 | static void nilfs_btree_init_path(struct nilfs_btree_path *path) |
| 88 | struct nilfs_btree_path *path) | ||
| 89 | { | 85 | { |
| 90 | int level; | 86 | int level; |
| 91 | 87 | ||
| @@ -101,26 +97,13 @@ static void nilfs_btree_init_path(const struct nilfs_btree *btree, | |||
| 101 | } | 97 | } |
| 102 | } | 98 | } |
| 103 | 99 | ||
| 104 | static void nilfs_btree_clear_path(const struct nilfs_btree *btree, | 100 | static void nilfs_btree_release_path(struct nilfs_btree_path *path) |
| 105 | struct nilfs_btree_path *path) | ||
| 106 | { | 101 | { |
| 107 | int level; | 102 | int level; |
| 108 | 103 | ||
| 109 | for (level = NILFS_BTREE_LEVEL_DATA; | 104 | for (level = NILFS_BTREE_LEVEL_DATA; level < NILFS_BTREE_LEVEL_MAX; |
| 110 | level < NILFS_BTREE_LEVEL_MAX; | 105 | level++) |
| 111 | level++) { | 106 | brelse(path[level].bp_bh); |
| 112 | if (path[level].bp_bh != NULL) { | ||
| 113 | brelse(path[level].bp_bh); | ||
| 114 | path[level].bp_bh = NULL; | ||
| 115 | } | ||
| 116 | /* sib_bh is released or deleted by prepare or commit | ||
| 117 | * operations. */ | ||
| 118 | path[level].bp_sib_bh = NULL; | ||
| 119 | path[level].bp_index = 0; | ||
| 120 | path[level].bp_oldreq.bpr_ptr = NILFS_BMAP_INVALID_PTR; | ||
| 121 | path[level].bp_newreq.bpr_ptr = NILFS_BMAP_INVALID_PTR; | ||
| 122 | path[level].bp_op = NULL; | ||
| 123 | } | ||
| 124 | } | 107 | } |
| 125 | 108 | ||
| 126 | /* | 109 | /* |
| @@ -148,129 +131,110 @@ static int nilfs_btree_get_new_block(const struct nilfs_btree *btree, | |||
| 148 | } | 131 | } |
| 149 | 132 | ||
| 150 | static inline int | 133 | static inline int |
| 151 | nilfs_btree_node_get_flags(const struct nilfs_btree *btree, | 134 | nilfs_btree_node_get_flags(const struct nilfs_btree_node *node) |
| 152 | const struct nilfs_btree_node *node) | ||
| 153 | { | 135 | { |
| 154 | return node->bn_flags; | 136 | return node->bn_flags; |
| 155 | } | 137 | } |
| 156 | 138 | ||
| 157 | static inline void | 139 | static inline void |
| 158 | nilfs_btree_node_set_flags(struct nilfs_btree *btree, | 140 | nilfs_btree_node_set_flags(struct nilfs_btree_node *node, int flags) |
| 159 | struct nilfs_btree_node *node, | ||
| 160 | int flags) | ||
| 161 | { | 141 | { |
| 162 | node->bn_flags = flags; | 142 | node->bn_flags = flags; |
| 163 | } | 143 | } |
| 164 | 144 | ||
| 165 | static inline int nilfs_btree_node_root(const struct nilfs_btree *btree, | 145 | static inline int nilfs_btree_node_root(const struct nilfs_btree_node *node) |
| 166 | const struct nilfs_btree_node *node) | ||
| 167 | { | 146 | { |
| 168 | return nilfs_btree_node_get_flags(btree, node) & NILFS_BTREE_NODE_ROOT; | 147 | return nilfs_btree_node_get_flags(node) & NILFS_BTREE_NODE_ROOT; |
| 169 | } | 148 | } |
| 170 | 149 | ||
| 171 | static inline int | 150 | static inline int |
| 172 | nilfs_btree_node_get_level(const struct nilfs_btree *btree, | 151 | nilfs_btree_node_get_level(const struct nilfs_btree_node *node) |
| 173 | const struct nilfs_btree_node *node) | ||
| 174 | { | 152 | { |
| 175 | return node->bn_level; | 153 | return node->bn_level; |
| 176 | } | 154 | } |
| 177 | 155 | ||
| 178 | static inline void | 156 | static inline void |
| 179 | nilfs_btree_node_set_level(struct nilfs_btree *btree, | 157 | nilfs_btree_node_set_level(struct nilfs_btree_node *node, int level) |
| 180 | struct nilfs_btree_node *node, | ||
| 181 | int level) | ||
| 182 | { | 158 | { |
| 183 | node->bn_level = level; | 159 | node->bn_level = level; |
| 184 | } | 160 | } |
| 185 | 161 | ||
| 186 | static inline int | 162 | static inline int |
| 187 | nilfs_btree_node_get_nchildren(const struct nilfs_btree *btree, | 163 | nilfs_btree_node_get_nchildren(const struct nilfs_btree_node *node) |
| 188 | const struct nilfs_btree_node *node) | ||
| 189 | { | 164 | { |
| 190 | return le16_to_cpu(node->bn_nchildren); | 165 | return le16_to_cpu(node->bn_nchildren); |
| 191 | } | 166 | } |
| 192 | 167 | ||
| 193 | static inline void | 168 | static inline void |
| 194 | nilfs_btree_node_set_nchildren(struct nilfs_btree *btree, | 169 | nilfs_btree_node_set_nchildren(struct nilfs_btree_node *node, int nchildren) |
| 195 | struct nilfs_btree_node *node, | ||
| 196 | int nchildren) | ||
| 197 | { | 170 | { |
| 198 | node->bn_nchildren = cpu_to_le16(nchildren); | 171 | node->bn_nchildren = cpu_to_le16(nchildren); |
| 199 | } | 172 | } |
| 200 | 173 | ||
| 201 | static inline int | 174 | static inline int nilfs_btree_node_size(const struct nilfs_btree *btree) |
| 202 | nilfs_btree_node_size(const struct nilfs_btree *btree) | ||
| 203 | { | 175 | { |
| 204 | return 1 << btree->bt_bmap.b_inode->i_blkbits; | 176 | return 1 << btree->bt_bmap.b_inode->i_blkbits; |
| 205 | } | 177 | } |
| 206 | 178 | ||
| 207 | static inline int | 179 | static inline int |
| 208 | nilfs_btree_node_nchildren_min(const struct nilfs_btree *btree, | 180 | nilfs_btree_node_nchildren_min(const struct nilfs_btree_node *node, |
| 209 | const struct nilfs_btree_node *node) | 181 | const struct nilfs_btree *btree) |
| 210 | { | 182 | { |
| 211 | return nilfs_btree_node_root(btree, node) ? | 183 | return nilfs_btree_node_root(node) ? |
| 212 | NILFS_BTREE_ROOT_NCHILDREN_MIN : | 184 | NILFS_BTREE_ROOT_NCHILDREN_MIN : |
| 213 | NILFS_BTREE_NODE_NCHILDREN_MIN(nilfs_btree_node_size(btree)); | 185 | NILFS_BTREE_NODE_NCHILDREN_MIN(nilfs_btree_node_size(btree)); |
| 214 | } | 186 | } |
| 215 | 187 | ||
| 216 | static inline int | 188 | static inline int |
| 217 | nilfs_btree_node_nchildren_max(const struct nilfs_btree *btree, | 189 | nilfs_btree_node_nchildren_max(const struct nilfs_btree_node *node, |
| 218 | const struct nilfs_btree_node *node) | 190 | const struct nilfs_btree *btree) |
| 219 | { | 191 | { |
| 220 | return nilfs_btree_node_root(btree, node) ? | 192 | return nilfs_btree_node_root(node) ? |
| 221 | NILFS_BTREE_ROOT_NCHILDREN_MAX : | 193 | NILFS_BTREE_ROOT_NCHILDREN_MAX : |
| 222 | NILFS_BTREE_NODE_NCHILDREN_MAX(nilfs_btree_node_size(btree)); | 194 | NILFS_BTREE_NODE_NCHILDREN_MAX(nilfs_btree_node_size(btree)); |
| 223 | } | 195 | } |
| 224 | 196 | ||
| 225 | static inline __le64 * | 197 | static inline __le64 * |
| 226 | nilfs_btree_node_dkeys(const struct nilfs_btree *btree, | 198 | nilfs_btree_node_dkeys(const struct nilfs_btree_node *node) |
| 227 | const struct nilfs_btree_node *node) | ||
| 228 | { | 199 | { |
| 229 | return (__le64 *)((char *)(node + 1) + | 200 | return (__le64 *)((char *)(node + 1) + |
| 230 | (nilfs_btree_node_root(btree, node) ? | 201 | (nilfs_btree_node_root(node) ? |
| 231 | 0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE)); | 202 | 0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE)); |
| 232 | } | 203 | } |
| 233 | 204 | ||
| 234 | static inline __le64 * | 205 | static inline __le64 * |
| 235 | nilfs_btree_node_dptrs(const struct nilfs_btree *btree, | 206 | nilfs_btree_node_dptrs(const struct nilfs_btree_node *node, |
| 236 | const struct nilfs_btree_node *node) | 207 | const struct nilfs_btree *btree) |
| 237 | { | 208 | { |
| 238 | return (__le64 *)(nilfs_btree_node_dkeys(btree, node) + | 209 | return (__le64 *)(nilfs_btree_node_dkeys(node) + |
| 239 | nilfs_btree_node_nchildren_max(btree, node)); | 210 | nilfs_btree_node_nchildren_max(node, btree)); |
| 240 | } | 211 | } |
| 241 | 212 | ||
| 242 | static inline __u64 | 213 | static inline __u64 |
| 243 | nilfs_btree_node_get_key(const struct nilfs_btree *btree, | 214 | nilfs_btree_node_get_key(const struct nilfs_btree_node *node, int index) |
| 244 | const struct nilfs_btree_node *node, int index) | ||
| 245 | { | 215 | { |
| 246 | return nilfs_bmap_dkey_to_key(*(nilfs_btree_node_dkeys(btree, node) + | 216 | return nilfs_bmap_dkey_to_key(*(nilfs_btree_node_dkeys(node) + index)); |
| 247 | index)); | ||
| 248 | } | 217 | } |
| 249 | 218 | ||
| 250 | static inline void | 219 | static inline void |
| 251 | nilfs_btree_node_set_key(struct nilfs_btree *btree, | 220 | nilfs_btree_node_set_key(struct nilfs_btree_node *node, int index, __u64 key) |
| 252 | struct nilfs_btree_node *node, int index, __u64 key) | ||
| 253 | { | 221 | { |
| 254 | *(nilfs_btree_node_dkeys(btree, node) + index) = | 222 | *(nilfs_btree_node_dkeys(node) + index) = nilfs_bmap_key_to_dkey(key); |
| 255 | nilfs_bmap_key_to_dkey(key); | ||
| 256 | } | 223 | } |
| 257 | 224 | ||
| 258 | static inline __u64 | 225 | static inline __u64 |
| 259 | nilfs_btree_node_get_ptr(const struct nilfs_btree *btree, | 226 | nilfs_btree_node_get_ptr(const struct nilfs_btree *btree, |
| 260 | const struct nilfs_btree_node *node, | 227 | const struct nilfs_btree_node *node, int index) |
| 261 | int index) | ||
| 262 | { | 228 | { |
| 263 | return nilfs_bmap_dptr_to_ptr(*(nilfs_btree_node_dptrs(btree, node) + | 229 | return nilfs_bmap_dptr_to_ptr(*(nilfs_btree_node_dptrs(node, btree) + |
| 264 | index)); | 230 | index)); |
| 265 | } | 231 | } |
| 266 | 232 | ||
| 267 | static inline void | 233 | static inline void |
| 268 | nilfs_btree_node_set_ptr(struct nilfs_btree *btree, | 234 | nilfs_btree_node_set_ptr(struct nilfs_btree *btree, |
| 269 | struct nilfs_btree_node *node, | 235 | struct nilfs_btree_node *node, int index, __u64 ptr) |
| 270 | int index, | ||
| 271 | __u64 ptr) | ||
| 272 | { | 236 | { |
| 273 | *(nilfs_btree_node_dptrs(btree, node) + index) = | 237 | *(nilfs_btree_node_dptrs(node, btree) + index) = |
| 274 | nilfs_bmap_ptr_to_dptr(ptr); | 238 | nilfs_bmap_ptr_to_dptr(ptr); |
| 275 | } | 239 | } |
| 276 | 240 | ||
| @@ -283,12 +247,12 @@ static void nilfs_btree_node_init(struct nilfs_btree *btree, | |||
| 283 | __le64 *dptrs; | 247 | __le64 *dptrs; |
| 284 | int i; | 248 | int i; |
| 285 | 249 | ||
| 286 | nilfs_btree_node_set_flags(btree, node, flags); | 250 | nilfs_btree_node_set_flags(node, flags); |
| 287 | nilfs_btree_node_set_level(btree, node, level); | 251 | nilfs_btree_node_set_level(node, level); |
| 288 | nilfs_btree_node_set_nchildren(btree, node, nchildren); | 252 | nilfs_btree_node_set_nchildren(node, nchildren); |
| 289 | 253 | ||
| 290 | dkeys = nilfs_btree_node_dkeys(btree, node); | 254 | dkeys = nilfs_btree_node_dkeys(node); |
| 291 | dptrs = nilfs_btree_node_dptrs(btree, node); | 255 | dptrs = nilfs_btree_node_dptrs(node, btree); |
| 292 | for (i = 0; i < nchildren; i++) { | 256 | for (i = 0; i < nchildren; i++) { |
| 293 | dkeys[i] = nilfs_bmap_key_to_dkey(keys[i]); | 257 | dkeys[i] = nilfs_bmap_key_to_dkey(keys[i]); |
| 294 | dptrs[i] = nilfs_bmap_ptr_to_dptr(ptrs[i]); | 258 | dptrs[i] = nilfs_bmap_ptr_to_dptr(ptrs[i]); |
| @@ -305,13 +269,13 @@ static void nilfs_btree_node_move_left(struct nilfs_btree *btree, | |||
| 305 | __le64 *ldptrs, *rdptrs; | 269 | __le64 *ldptrs, *rdptrs; |
| 306 | int lnchildren, rnchildren; | 270 | int lnchildren, rnchildren; |
| 307 | 271 | ||
| 308 | ldkeys = nilfs_btree_node_dkeys(btree, left); | 272 | ldkeys = nilfs_btree_node_dkeys(left); |
| 309 | ldptrs = nilfs_btree_node_dptrs(btree, left); | 273 | ldptrs = nilfs_btree_node_dptrs(left, btree); |
| 310 | lnchildren = nilfs_btree_node_get_nchildren(btree, left); | 274 | lnchildren = nilfs_btree_node_get_nchildren(left); |
| 311 | 275 | ||
| 312 | rdkeys = nilfs_btree_node_dkeys(btree, right); | 276 | rdkeys = nilfs_btree_node_dkeys(right); |
| 313 | rdptrs = nilfs_btree_node_dptrs(btree, right); | 277 | rdptrs = nilfs_btree_node_dptrs(right, btree); |
| 314 | rnchildren = nilfs_btree_node_get_nchildren(btree, right); | 278 | rnchildren = nilfs_btree_node_get_nchildren(right); |
| 315 | 279 | ||
| 316 | memcpy(ldkeys + lnchildren, rdkeys, n * sizeof(*rdkeys)); | 280 | memcpy(ldkeys + lnchildren, rdkeys, n * sizeof(*rdkeys)); |
| 317 | memcpy(ldptrs + lnchildren, rdptrs, n * sizeof(*rdptrs)); | 281 | memcpy(ldptrs + lnchildren, rdptrs, n * sizeof(*rdptrs)); |
| @@ -320,8 +284,8 @@ static void nilfs_btree_node_move_left(struct nilfs_btree *btree, | |||
| 320 | 284 | ||
| 321 | lnchildren += n; | 285 | lnchildren += n; |
| 322 | rnchildren -= n; | 286 | rnchildren -= n; |
| 323 | nilfs_btree_node_set_nchildren(btree, left, lnchildren); | 287 | nilfs_btree_node_set_nchildren(left, lnchildren); |
| 324 | nilfs_btree_node_set_nchildren(btree, right, rnchildren); | 288 | nilfs_btree_node_set_nchildren(right, rnchildren); |
| 325 | } | 289 | } |
| 326 | 290 | ||
| 327 | /* Assume that the buffer heads corresponding to left and right are locked. */ | 291 | /* Assume that the buffer heads corresponding to left and right are locked. */ |
| @@ -334,13 +298,13 @@ static void nilfs_btree_node_move_right(struct nilfs_btree *btree, | |||
| 334 | __le64 *ldptrs, *rdptrs; | 298 | __le64 *ldptrs, *rdptrs; |
| 335 | int lnchildren, rnchildren; | 299 | int lnchildren, rnchildren; |
| 336 | 300 | ||
| 337 | ldkeys = nilfs_btree_node_dkeys(btree, left); | 301 | ldkeys = nilfs_btree_node_dkeys(left); |
| 338 | ldptrs = nilfs_btree_node_dptrs(btree, left); | 302 | ldptrs = nilfs_btree_node_dptrs(left, btree); |
| 339 | lnchildren = nilfs_btree_node_get_nchildren(btree, left); | 303 | lnchildren = nilfs_btree_node_get_nchildren(left); |
| 340 | 304 | ||
| 341 | rdkeys = nilfs_btree_node_dkeys(btree, right); | 305 | rdkeys = nilfs_btree_node_dkeys(right); |
| 342 | rdptrs = nilfs_btree_node_dptrs(btree, right); | 306 | rdptrs = nilfs_btree_node_dptrs(right, btree); |
| 343 | rnchildren = nilfs_btree_node_get_nchildren(btree, right); | 307 | rnchildren = nilfs_btree_node_get_nchildren(right); |
| 344 | 308 | ||
| 345 | memmove(rdkeys + n, rdkeys, rnchildren * sizeof(*rdkeys)); | 309 | memmove(rdkeys + n, rdkeys, rnchildren * sizeof(*rdkeys)); |
| 346 | memmove(rdptrs + n, rdptrs, rnchildren * sizeof(*rdptrs)); | 310 | memmove(rdptrs + n, rdptrs, rnchildren * sizeof(*rdptrs)); |
| @@ -349,8 +313,8 @@ static void nilfs_btree_node_move_right(struct nilfs_btree *btree, | |||
| 349 | 313 | ||
| 350 | lnchildren -= n; | 314 | lnchildren -= n; |
| 351 | rnchildren += n; | 315 | rnchildren += n; |
| 352 | nilfs_btree_node_set_nchildren(btree, left, lnchildren); | 316 | nilfs_btree_node_set_nchildren(left, lnchildren); |
| 353 | nilfs_btree_node_set_nchildren(btree, right, rnchildren); | 317 | nilfs_btree_node_set_nchildren(right, rnchildren); |
| 354 | } | 318 | } |
| 355 | 319 | ||
| 356 | /* Assume that the buffer head corresponding to node is locked. */ | 320 | /* Assume that the buffer head corresponding to node is locked. */ |
| @@ -362,9 +326,9 @@ static void nilfs_btree_node_insert(struct nilfs_btree *btree, | |||
| 362 | __le64 *dptrs; | 326 | __le64 *dptrs; |
| 363 | int nchildren; | 327 | int nchildren; |
| 364 | 328 | ||
| 365 | dkeys = nilfs_btree_node_dkeys(btree, node); | 329 | dkeys = nilfs_btree_node_dkeys(node); |
| 366 | dptrs = nilfs_btree_node_dptrs(btree, node); | 330 | dptrs = nilfs_btree_node_dptrs(node, btree); |
| 367 | nchildren = nilfs_btree_node_get_nchildren(btree, node); | 331 | nchildren = nilfs_btree_node_get_nchildren(node); |
| 368 | if (index < nchildren) { | 332 | if (index < nchildren) { |
| 369 | memmove(dkeys + index + 1, dkeys + index, | 333 | memmove(dkeys + index + 1, dkeys + index, |
| 370 | (nchildren - index) * sizeof(*dkeys)); | 334 | (nchildren - index) * sizeof(*dkeys)); |
| @@ -374,7 +338,7 @@ static void nilfs_btree_node_insert(struct nilfs_btree *btree, | |||
| 374 | dkeys[index] = nilfs_bmap_key_to_dkey(key); | 338 | dkeys[index] = nilfs_bmap_key_to_dkey(key); |
| 375 | dptrs[index] = nilfs_bmap_ptr_to_dptr(ptr); | 339 | dptrs[index] = nilfs_bmap_ptr_to_dptr(ptr); |
| 376 | nchildren++; | 340 | nchildren++; |
| 377 | nilfs_btree_node_set_nchildren(btree, node, nchildren); | 341 | nilfs_btree_node_set_nchildren(node, nchildren); |
| 378 | } | 342 | } |
| 379 | 343 | ||
| 380 | /* Assume that the buffer head corresponding to node is locked. */ | 344 | /* Assume that the buffer head corresponding to node is locked. */ |
| @@ -388,11 +352,11 @@ static void nilfs_btree_node_delete(struct nilfs_btree *btree, | |||
| 388 | __le64 *dptrs; | 352 | __le64 *dptrs; |
| 389 | int nchildren; | 353 | int nchildren; |
| 390 | 354 | ||
| 391 | dkeys = nilfs_btree_node_dkeys(btree, node); | 355 | dkeys = nilfs_btree_node_dkeys(node); |
| 392 | dptrs = nilfs_btree_node_dptrs(btree, node); | 356 | dptrs = nilfs_btree_node_dptrs(node, btree); |
| 393 | key = nilfs_bmap_dkey_to_key(dkeys[index]); | 357 | key = nilfs_bmap_dkey_to_key(dkeys[index]); |
| 394 | ptr = nilfs_bmap_dptr_to_ptr(dptrs[index]); | 358 | ptr = nilfs_bmap_dptr_to_ptr(dptrs[index]); |
| 395 | nchildren = nilfs_btree_node_get_nchildren(btree, node); | 359 | nchildren = nilfs_btree_node_get_nchildren(node); |
| 396 | if (keyp != NULL) | 360 | if (keyp != NULL) |
| 397 | *keyp = key; | 361 | *keyp = key; |
| 398 | if (ptrp != NULL) | 362 | if (ptrp != NULL) |
| @@ -405,11 +369,10 @@ static void nilfs_btree_node_delete(struct nilfs_btree *btree, | |||
| 405 | (nchildren - index - 1) * sizeof(*dptrs)); | 369 | (nchildren - index - 1) * sizeof(*dptrs)); |
| 406 | } | 370 | } |
| 407 | nchildren--; | 371 | nchildren--; |
| 408 | nilfs_btree_node_set_nchildren(btree, node, nchildren); | 372 | nilfs_btree_node_set_nchildren(node, nchildren); |
| 409 | } | 373 | } |
| 410 | 374 | ||
| 411 | static int nilfs_btree_node_lookup(const struct nilfs_btree *btree, | 375 | static int nilfs_btree_node_lookup(const struct nilfs_btree_node *node, |
| 412 | const struct nilfs_btree_node *node, | ||
| 413 | __u64 key, int *indexp) | 376 | __u64 key, int *indexp) |
| 414 | { | 377 | { |
| 415 | __u64 nkey; | 378 | __u64 nkey; |
| @@ -417,12 +380,12 @@ static int nilfs_btree_node_lookup(const struct nilfs_btree *btree, | |||
| 417 | 380 | ||
| 418 | /* binary search */ | 381 | /* binary search */ |
| 419 | low = 0; | 382 | low = 0; |
| 420 | high = nilfs_btree_node_get_nchildren(btree, node) - 1; | 383 | high = nilfs_btree_node_get_nchildren(node) - 1; |
| 421 | index = 0; | 384 | index = 0; |
| 422 | s = 0; | 385 | s = 0; |
| 423 | while (low <= high) { | 386 | while (low <= high) { |
| 424 | index = (low + high) / 2; | 387 | index = (low + high) / 2; |
| 425 | nkey = nilfs_btree_node_get_key(btree, node, index); | 388 | nkey = nilfs_btree_node_get_key(node, index); |
| 426 | if (nkey == key) { | 389 | if (nkey == key) { |
| 427 | s = 0; | 390 | s = 0; |
| 428 | goto out; | 391 | goto out; |
| @@ -436,9 +399,8 @@ static int nilfs_btree_node_lookup(const struct nilfs_btree *btree, | |||
| 436 | } | 399 | } |
| 437 | 400 | ||
| 438 | /* adjust index */ | 401 | /* adjust index */ |
| 439 | if (nilfs_btree_node_get_level(btree, node) > | 402 | if (nilfs_btree_node_get_level(node) > NILFS_BTREE_LEVEL_NODE_MIN) { |
| 440 | NILFS_BTREE_LEVEL_NODE_MIN) { | 403 | if (s > 0 && index > 0) |
| 441 | if ((s > 0) && (index > 0)) | ||
| 442 | index--; | 404 | index--; |
| 443 | } else if (s < 0) | 405 | } else if (s < 0) |
| 444 | index++; | 406 | index++; |
| @@ -456,25 +418,20 @@ nilfs_btree_get_root(const struct nilfs_btree *btree) | |||
| 456 | } | 418 | } |
| 457 | 419 | ||
| 458 | static inline struct nilfs_btree_node * | 420 | static inline struct nilfs_btree_node * |
| 459 | nilfs_btree_get_nonroot_node(const struct nilfs_btree *btree, | 421 | nilfs_btree_get_nonroot_node(const struct nilfs_btree_path *path, int level) |
| 460 | const struct nilfs_btree_path *path, | ||
| 461 | int level) | ||
| 462 | { | 422 | { |
| 463 | return (struct nilfs_btree_node *)path[level].bp_bh->b_data; | 423 | return (struct nilfs_btree_node *)path[level].bp_bh->b_data; |
| 464 | } | 424 | } |
| 465 | 425 | ||
| 466 | static inline struct nilfs_btree_node * | 426 | static inline struct nilfs_btree_node * |
| 467 | nilfs_btree_get_sib_node(const struct nilfs_btree *btree, | 427 | nilfs_btree_get_sib_node(const struct nilfs_btree_path *path, int level) |
| 468 | const struct nilfs_btree_path *path, | ||
| 469 | int level) | ||
| 470 | { | 428 | { |
| 471 | return (struct nilfs_btree_node *)path[level].bp_sib_bh->b_data; | 429 | return (struct nilfs_btree_node *)path[level].bp_sib_bh->b_data; |
| 472 | } | 430 | } |
| 473 | 431 | ||
| 474 | static inline int nilfs_btree_height(const struct nilfs_btree *btree) | 432 | static inline int nilfs_btree_height(const struct nilfs_btree *btree) |
| 475 | { | 433 | { |
| 476 | return nilfs_btree_node_get_level(btree, nilfs_btree_get_root(btree)) | 434 | return nilfs_btree_node_get_level(nilfs_btree_get_root(btree)) + 1; |
| 477 | + 1; | ||
| 478 | } | 435 | } |
| 479 | 436 | ||
| 480 | static inline struct nilfs_btree_node * | 437 | static inline struct nilfs_btree_node * |
| @@ -484,7 +441,7 @@ nilfs_btree_get_node(const struct nilfs_btree *btree, | |||
| 484 | { | 441 | { |
| 485 | return (level == nilfs_btree_height(btree) - 1) ? | 442 | return (level == nilfs_btree_height(btree) - 1) ? |
| 486 | nilfs_btree_get_root(btree) : | 443 | nilfs_btree_get_root(btree) : |
| 487 | nilfs_btree_get_nonroot_node(btree, path, level); | 444 | nilfs_btree_get_nonroot_node(path, level); |
| 488 | } | 445 | } |
| 489 | 446 | ||
| 490 | static int nilfs_btree_do_lookup(const struct nilfs_btree *btree, | 447 | static int nilfs_btree_do_lookup(const struct nilfs_btree *btree, |
| @@ -496,12 +453,11 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree, | |||
| 496 | int level, index, found, ret; | 453 | int level, index, found, ret; |
| 497 | 454 | ||
| 498 | node = nilfs_btree_get_root(btree); | 455 | node = nilfs_btree_get_root(btree); |
| 499 | level = nilfs_btree_node_get_level(btree, node); | 456 | level = nilfs_btree_node_get_level(node); |
| 500 | if ((level < minlevel) || | 457 | if (level < minlevel || nilfs_btree_node_get_nchildren(node) <= 0) |
| 501 | (nilfs_btree_node_get_nchildren(btree, node) <= 0)) | ||
| 502 | return -ENOENT; | 458 | return -ENOENT; |
| 503 | 459 | ||
| 504 | found = nilfs_btree_node_lookup(btree, node, key, &index); | 460 | found = nilfs_btree_node_lookup(node, key, &index); |
| 505 | ptr = nilfs_btree_node_get_ptr(btree, node, index); | 461 | ptr = nilfs_btree_node_get_ptr(btree, node, index); |
| 506 | path[level].bp_bh = NULL; | 462 | path[level].bp_bh = NULL; |
| 507 | path[level].bp_index = index; | 463 | path[level].bp_index = index; |
| @@ -510,14 +466,13 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree, | |||
| 510 | ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh); | 466 | ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh); |
| 511 | if (ret < 0) | 467 | if (ret < 0) |
| 512 | return ret; | 468 | return ret; |
| 513 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 469 | node = nilfs_btree_get_nonroot_node(path, level); |
| 514 | BUG_ON(level != nilfs_btree_node_get_level(btree, node)); | 470 | BUG_ON(level != nilfs_btree_node_get_level(node)); |
| 515 | if (!found) | 471 | if (!found) |
| 516 | found = nilfs_btree_node_lookup(btree, node, key, | 472 | found = nilfs_btree_node_lookup(node, key, &index); |
| 517 | &index); | ||
| 518 | else | 473 | else |
| 519 | index = 0; | 474 | index = 0; |
| 520 | if (index < nilfs_btree_node_nchildren_max(btree, node)) | 475 | if (index < nilfs_btree_node_nchildren_max(node, btree)) |
| 521 | ptr = nilfs_btree_node_get_ptr(btree, node, index); | 476 | ptr = nilfs_btree_node_get_ptr(btree, node, index); |
| 522 | else { | 477 | else { |
| 523 | WARN_ON(found || level != NILFS_BTREE_LEVEL_NODE_MIN); | 478 | WARN_ON(found || level != NILFS_BTREE_LEVEL_NODE_MIN); |
| @@ -544,10 +499,10 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_btree *btree, | |||
| 544 | int index, level, ret; | 499 | int index, level, ret; |
| 545 | 500 | ||
| 546 | node = nilfs_btree_get_root(btree); | 501 | node = nilfs_btree_get_root(btree); |
| 547 | index = nilfs_btree_node_get_nchildren(btree, node) - 1; | 502 | index = nilfs_btree_node_get_nchildren(node) - 1; |
| 548 | if (index < 0) | 503 | if (index < 0) |
| 549 | return -ENOENT; | 504 | return -ENOENT; |
| 550 | level = nilfs_btree_node_get_level(btree, node); | 505 | level = nilfs_btree_node_get_level(node); |
| 551 | ptr = nilfs_btree_node_get_ptr(btree, node, index); | 506 | ptr = nilfs_btree_node_get_ptr(btree, node, index); |
| 552 | path[level].bp_bh = NULL; | 507 | path[level].bp_bh = NULL; |
| 553 | path[level].bp_index = index; | 508 | path[level].bp_index = index; |
| @@ -556,15 +511,15 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_btree *btree, | |||
| 556 | ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh); | 511 | ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh); |
| 557 | if (ret < 0) | 512 | if (ret < 0) |
| 558 | return ret; | 513 | return ret; |
| 559 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 514 | node = nilfs_btree_get_nonroot_node(path, level); |
| 560 | BUG_ON(level != nilfs_btree_node_get_level(btree, node)); | 515 | BUG_ON(level != nilfs_btree_node_get_level(node)); |
| 561 | index = nilfs_btree_node_get_nchildren(btree, node) - 1; | 516 | index = nilfs_btree_node_get_nchildren(node) - 1; |
| 562 | ptr = nilfs_btree_node_get_ptr(btree, node, index); | 517 | ptr = nilfs_btree_node_get_ptr(btree, node, index); |
| 563 | path[level].bp_index = index; | 518 | path[level].bp_index = index; |
| 564 | } | 519 | } |
| 565 | 520 | ||
| 566 | if (keyp != NULL) | 521 | if (keyp != NULL) |
| 567 | *keyp = nilfs_btree_node_get_key(btree, node, index); | 522 | *keyp = nilfs_btree_node_get_key(node, index); |
| 568 | if (ptrp != NULL) | 523 | if (ptrp != NULL) |
| 569 | *ptrp = ptr; | 524 | *ptrp = ptr; |
| 570 | 525 | ||
| @@ -580,18 +535,18 @@ static int nilfs_btree_lookup(const struct nilfs_bmap *bmap, | |||
| 580 | int ret; | 535 | int ret; |
| 581 | 536 | ||
| 582 | btree = (struct nilfs_btree *)bmap; | 537 | btree = (struct nilfs_btree *)bmap; |
| 583 | path = nilfs_btree_alloc_path(btree); | 538 | path = nilfs_btree_alloc_path(); |
| 584 | if (path == NULL) | 539 | if (path == NULL) |
| 585 | return -ENOMEM; | 540 | return -ENOMEM; |
| 586 | nilfs_btree_init_path(btree, path); | 541 | nilfs_btree_init_path(path); |
| 587 | 542 | ||
| 588 | ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level); | 543 | ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level); |
| 589 | 544 | ||
| 590 | if (ptrp != NULL) | 545 | if (ptrp != NULL) |
| 591 | *ptrp = ptr; | 546 | *ptrp = ptr; |
| 592 | 547 | ||
| 593 | nilfs_btree_clear_path(btree, path); | 548 | nilfs_btree_release_path(path); |
| 594 | nilfs_btree_free_path(btree, path); | 549 | nilfs_btree_free_path(path); |
| 595 | 550 | ||
| 596 | return ret; | 551 | return ret; |
| 597 | } | 552 | } |
| @@ -608,10 +563,10 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap, | |||
| 608 | int level = NILFS_BTREE_LEVEL_NODE_MIN; | 563 | int level = NILFS_BTREE_LEVEL_NODE_MIN; |
| 609 | int ret, cnt, index, maxlevel; | 564 | int ret, cnt, index, maxlevel; |
| 610 | 565 | ||
| 611 | path = nilfs_btree_alloc_path(btree); | 566 | path = nilfs_btree_alloc_path(); |
| 612 | if (path == NULL) | 567 | if (path == NULL) |
| 613 | return -ENOMEM; | 568 | return -ENOMEM; |
| 614 | nilfs_btree_init_path(btree, path); | 569 | nilfs_btree_init_path(path); |
| 615 | ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level); | 570 | ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level); |
| 616 | if (ret < 0) | 571 | if (ret < 0) |
| 617 | goto out; | 572 | goto out; |
| @@ -631,8 +586,8 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap, | |||
| 631 | node = nilfs_btree_get_node(btree, path, level); | 586 | node = nilfs_btree_get_node(btree, path, level); |
| 632 | index = path[level].bp_index + 1; | 587 | index = path[level].bp_index + 1; |
| 633 | for (;;) { | 588 | for (;;) { |
| 634 | while (index < nilfs_btree_node_get_nchildren(btree, node)) { | 589 | while (index < nilfs_btree_node_get_nchildren(node)) { |
| 635 | if (nilfs_btree_node_get_key(btree, node, index) != | 590 | if (nilfs_btree_node_get_key(node, index) != |
| 636 | key + cnt) | 591 | key + cnt) |
| 637 | goto end; | 592 | goto end; |
| 638 | ptr2 = nilfs_btree_node_get_ptr(btree, node, index); | 593 | ptr2 = nilfs_btree_node_get_ptr(btree, node, index); |
| @@ -653,8 +608,8 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap, | |||
| 653 | /* look-up right sibling node */ | 608 | /* look-up right sibling node */ |
| 654 | node = nilfs_btree_get_node(btree, path, level + 1); | 609 | node = nilfs_btree_get_node(btree, path, level + 1); |
| 655 | index = path[level + 1].bp_index + 1; | 610 | index = path[level + 1].bp_index + 1; |
| 656 | if (index >= nilfs_btree_node_get_nchildren(btree, node) || | 611 | if (index >= nilfs_btree_node_get_nchildren(node) || |
| 657 | nilfs_btree_node_get_key(btree, node, index) != key + cnt) | 612 | nilfs_btree_node_get_key(node, index) != key + cnt) |
| 658 | break; | 613 | break; |
| 659 | ptr2 = nilfs_btree_node_get_ptr(btree, node, index); | 614 | ptr2 = nilfs_btree_node_get_ptr(btree, node, index); |
| 660 | path[level + 1].bp_index = index; | 615 | path[level + 1].bp_index = index; |
| @@ -664,7 +619,7 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap, | |||
| 664 | ret = nilfs_btree_get_block(btree, ptr2, &path[level].bp_bh); | 619 | ret = nilfs_btree_get_block(btree, ptr2, &path[level].bp_bh); |
| 665 | if (ret < 0) | 620 | if (ret < 0) |
| 666 | goto out; | 621 | goto out; |
| 667 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 622 | node = nilfs_btree_get_nonroot_node(path, level); |
| 668 | index = 0; | 623 | index = 0; |
| 669 | path[level].bp_index = index; | 624 | path[level].bp_index = index; |
| 670 | } | 625 | } |
| @@ -672,8 +627,8 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap, | |||
| 672 | *ptrp = ptr; | 627 | *ptrp = ptr; |
| 673 | ret = cnt; | 628 | ret = cnt; |
| 674 | out: | 629 | out: |
| 675 | nilfs_btree_clear_path(btree, path); | 630 | nilfs_btree_release_path(path); |
| 676 | nilfs_btree_free_path(btree, path); | 631 | nilfs_btree_free_path(path); |
| 677 | return ret; | 632 | return ret; |
| 678 | } | 633 | } |
| 679 | 634 | ||
| @@ -685,9 +640,7 @@ static void nilfs_btree_promote_key(struct nilfs_btree *btree, | |||
| 685 | do { | 640 | do { |
| 686 | lock_buffer(path[level].bp_bh); | 641 | lock_buffer(path[level].bp_bh); |
| 687 | nilfs_btree_node_set_key( | 642 | nilfs_btree_node_set_key( |
| 688 | btree, | 643 | nilfs_btree_get_nonroot_node(path, level), |
| 689 | nilfs_btree_get_nonroot_node( | ||
| 690 | btree, path, level), | ||
| 691 | path[level].bp_index, key); | 644 | path[level].bp_index, key); |
| 692 | if (!buffer_dirty(path[level].bp_bh)) | 645 | if (!buffer_dirty(path[level].bp_bh)) |
| 693 | nilfs_btnode_mark_dirty(path[level].bp_bh); | 646 | nilfs_btnode_mark_dirty(path[level].bp_bh); |
| @@ -698,8 +651,7 @@ static void nilfs_btree_promote_key(struct nilfs_btree *btree, | |||
| 698 | 651 | ||
| 699 | /* root */ | 652 | /* root */ |
| 700 | if (level == nilfs_btree_height(btree) - 1) { | 653 | if (level == nilfs_btree_height(btree) - 1) { |
| 701 | nilfs_btree_node_set_key(btree, | 654 | nilfs_btree_node_set_key(nilfs_btree_get_root(btree), |
| 702 | nilfs_btree_get_root(btree), | ||
| 703 | path[level].bp_index, key); | 655 | path[level].bp_index, key); |
| 704 | } | 656 | } |
| 705 | } | 657 | } |
| @@ -712,7 +664,7 @@ static void nilfs_btree_do_insert(struct nilfs_btree *btree, | |||
| 712 | 664 | ||
| 713 | if (level < nilfs_btree_height(btree) - 1) { | 665 | if (level < nilfs_btree_height(btree) - 1) { |
| 714 | lock_buffer(path[level].bp_bh); | 666 | lock_buffer(path[level].bp_bh); |
| 715 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 667 | node = nilfs_btree_get_nonroot_node(path, level); |
| 716 | nilfs_btree_node_insert(btree, node, *keyp, *ptrp, | 668 | nilfs_btree_node_insert(btree, node, *keyp, *ptrp, |
| 717 | path[level].bp_index); | 669 | path[level].bp_index); |
| 718 | if (!buffer_dirty(path[level].bp_bh)) | 670 | if (!buffer_dirty(path[level].bp_bh)) |
| @@ -721,8 +673,8 @@ static void nilfs_btree_do_insert(struct nilfs_btree *btree, | |||
| 721 | 673 | ||
| 722 | if (path[level].bp_index == 0) | 674 | if (path[level].bp_index == 0) |
| 723 | nilfs_btree_promote_key(btree, path, level + 1, | 675 | nilfs_btree_promote_key(btree, path, level + 1, |
| 724 | nilfs_btree_node_get_key( | 676 | nilfs_btree_node_get_key(node, |
| 725 | btree, node, 0)); | 677 | 0)); |
| 726 | } else { | 678 | } else { |
| 727 | node = nilfs_btree_get_root(btree); | 679 | node = nilfs_btree_get_root(btree); |
| 728 | nilfs_btree_node_insert(btree, node, *keyp, *ptrp, | 680 | nilfs_btree_node_insert(btree, node, *keyp, *ptrp, |
| @@ -740,10 +692,10 @@ static void nilfs_btree_carry_left(struct nilfs_btree *btree, | |||
| 740 | lock_buffer(path[level].bp_bh); | 692 | lock_buffer(path[level].bp_bh); |
| 741 | lock_buffer(path[level].bp_sib_bh); | 693 | lock_buffer(path[level].bp_sib_bh); |
| 742 | 694 | ||
| 743 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 695 | node = nilfs_btree_get_nonroot_node(path, level); |
| 744 | left = nilfs_btree_get_sib_node(btree, path, level); | 696 | left = nilfs_btree_get_sib_node(path, level); |
| 745 | nchildren = nilfs_btree_node_get_nchildren(btree, node); | 697 | nchildren = nilfs_btree_node_get_nchildren(node); |
| 746 | lnchildren = nilfs_btree_node_get_nchildren(btree, left); | 698 | lnchildren = nilfs_btree_node_get_nchildren(left); |
| 747 | move = 0; | 699 | move = 0; |
| 748 | 700 | ||
| 749 | n = (nchildren + lnchildren + 1) / 2 - lnchildren; | 701 | n = (nchildren + lnchildren + 1) / 2 - lnchildren; |
| @@ -764,7 +716,7 @@ static void nilfs_btree_carry_left(struct nilfs_btree *btree, | |||
| 764 | unlock_buffer(path[level].bp_sib_bh); | 716 | unlock_buffer(path[level].bp_sib_bh); |
| 765 | 717 | ||
| 766 | nilfs_btree_promote_key(btree, path, level + 1, | 718 | nilfs_btree_promote_key(btree, path, level + 1, |
| 767 | nilfs_btree_node_get_key(btree, node, 0)); | 719 | nilfs_btree_node_get_key(node, 0)); |
| 768 | 720 | ||
| 769 | if (move) { | 721 | if (move) { |
| 770 | brelse(path[level].bp_bh); | 722 | brelse(path[level].bp_bh); |
| @@ -791,10 +743,10 @@ static void nilfs_btree_carry_right(struct nilfs_btree *btree, | |||
| 791 | lock_buffer(path[level].bp_bh); | 743 | lock_buffer(path[level].bp_bh); |
| 792 | lock_buffer(path[level].bp_sib_bh); | 744 | lock_buffer(path[level].bp_sib_bh); |
| 793 | 745 | ||
| 794 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 746 | node = nilfs_btree_get_nonroot_node(path, level); |
| 795 | right = nilfs_btree_get_sib_node(btree, path, level); | 747 | right = nilfs_btree_get_sib_node(path, level); |
| 796 | nchildren = nilfs_btree_node_get_nchildren(btree, node); | 748 | nchildren = nilfs_btree_node_get_nchildren(node); |
| 797 | rnchildren = nilfs_btree_node_get_nchildren(btree, right); | 749 | rnchildren = nilfs_btree_node_get_nchildren(right); |
| 798 | move = 0; | 750 | move = 0; |
| 799 | 751 | ||
| 800 | n = (nchildren + rnchildren + 1) / 2 - rnchildren; | 752 | n = (nchildren + rnchildren + 1) / 2 - rnchildren; |
| @@ -816,15 +768,14 @@ static void nilfs_btree_carry_right(struct nilfs_btree *btree, | |||
| 816 | 768 | ||
| 817 | path[level + 1].bp_index++; | 769 | path[level + 1].bp_index++; |
| 818 | nilfs_btree_promote_key(btree, path, level + 1, | 770 | nilfs_btree_promote_key(btree, path, level + 1, |
| 819 | nilfs_btree_node_get_key(btree, right, 0)); | 771 | nilfs_btree_node_get_key(right, 0)); |
| 820 | path[level + 1].bp_index--; | 772 | path[level + 1].bp_index--; |
| 821 | 773 | ||
| 822 | if (move) { | 774 | if (move) { |
| 823 | brelse(path[level].bp_bh); | 775 | brelse(path[level].bp_bh); |
| 824 | path[level].bp_bh = path[level].bp_sib_bh; | 776 | path[level].bp_bh = path[level].bp_sib_bh; |
| 825 | path[level].bp_sib_bh = NULL; | 777 | path[level].bp_sib_bh = NULL; |
| 826 | path[level].bp_index -= | 778 | path[level].bp_index -= nilfs_btree_node_get_nchildren(node); |
| 827 | nilfs_btree_node_get_nchildren(btree, node); | ||
| 828 | path[level + 1].bp_index++; | 779 | path[level + 1].bp_index++; |
| 829 | } else { | 780 | } else { |
| 830 | brelse(path[level].bp_sib_bh); | 781 | brelse(path[level].bp_sib_bh); |
| @@ -846,9 +797,9 @@ static void nilfs_btree_split(struct nilfs_btree *btree, | |||
| 846 | lock_buffer(path[level].bp_bh); | 797 | lock_buffer(path[level].bp_bh); |
| 847 | lock_buffer(path[level].bp_sib_bh); | 798 | lock_buffer(path[level].bp_sib_bh); |
| 848 | 799 | ||
| 849 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 800 | node = nilfs_btree_get_nonroot_node(path, level); |
| 850 | right = nilfs_btree_get_sib_node(btree, path, level); | 801 | right = nilfs_btree_get_sib_node(path, level); |
| 851 | nchildren = nilfs_btree_node_get_nchildren(btree, node); | 802 | nchildren = nilfs_btree_node_get_nchildren(node); |
| 852 | move = 0; | 803 | move = 0; |
| 853 | 804 | ||
| 854 | n = (nchildren + 1) / 2; | 805 | n = (nchildren + 1) / 2; |
| @@ -867,16 +818,15 @@ static void nilfs_btree_split(struct nilfs_btree *btree, | |||
| 867 | unlock_buffer(path[level].bp_bh); | 818 | unlock_buffer(path[level].bp_bh); |
| 868 | unlock_buffer(path[level].bp_sib_bh); | 819 | unlock_buffer(path[level].bp_sib_bh); |
| 869 | 820 | ||
| 870 | newkey = nilfs_btree_node_get_key(btree, right, 0); | 821 | newkey = nilfs_btree_node_get_key(right, 0); |
| 871 | newptr = path[level].bp_newreq.bpr_ptr; | 822 | newptr = path[level].bp_newreq.bpr_ptr; |
| 872 | 823 | ||
| 873 | if (move) { | 824 | if (move) { |
| 874 | path[level].bp_index -= | 825 | path[level].bp_index -= nilfs_btree_node_get_nchildren(node); |
| 875 | nilfs_btree_node_get_nchildren(btree, node); | ||
| 876 | nilfs_btree_node_insert(btree, right, *keyp, *ptrp, | 826 | nilfs_btree_node_insert(btree, right, *keyp, *ptrp, |
| 877 | path[level].bp_index); | 827 | path[level].bp_index); |
| 878 | 828 | ||
| 879 | *keyp = nilfs_btree_node_get_key(btree, right, 0); | 829 | *keyp = nilfs_btree_node_get_key(right, 0); |
| 880 | *ptrp = path[level].bp_newreq.bpr_ptr; | 830 | *ptrp = path[level].bp_newreq.bpr_ptr; |
| 881 | 831 | ||
| 882 | brelse(path[level].bp_bh); | 832 | brelse(path[level].bp_bh); |
| @@ -885,7 +835,7 @@ static void nilfs_btree_split(struct nilfs_btree *btree, | |||
| 885 | } else { | 835 | } else { |
| 886 | nilfs_btree_do_insert(btree, path, level, keyp, ptrp); | 836 | nilfs_btree_do_insert(btree, path, level, keyp, ptrp); |
| 887 | 837 | ||
| 888 | *keyp = nilfs_btree_node_get_key(btree, right, 0); | 838 | *keyp = nilfs_btree_node_get_key(right, 0); |
| 889 | *ptrp = path[level].bp_newreq.bpr_ptr; | 839 | *ptrp = path[level].bp_newreq.bpr_ptr; |
| 890 | 840 | ||
| 891 | brelse(path[level].bp_sib_bh); | 841 | brelse(path[level].bp_sib_bh); |
| @@ -905,12 +855,12 @@ static void nilfs_btree_grow(struct nilfs_btree *btree, | |||
| 905 | lock_buffer(path[level].bp_sib_bh); | 855 | lock_buffer(path[level].bp_sib_bh); |
| 906 | 856 | ||
| 907 | root = nilfs_btree_get_root(btree); | 857 | root = nilfs_btree_get_root(btree); |
| 908 | child = nilfs_btree_get_sib_node(btree, path, level); | 858 | child = nilfs_btree_get_sib_node(path, level); |
| 909 | 859 | ||
| 910 | n = nilfs_btree_node_get_nchildren(btree, root); | 860 | n = nilfs_btree_node_get_nchildren(root); |
| 911 | 861 | ||
| 912 | nilfs_btree_node_move_right(btree, root, child, n); | 862 | nilfs_btree_node_move_right(btree, root, child, n); |
| 913 | nilfs_btree_node_set_level(btree, root, level + 1); | 863 | nilfs_btree_node_set_level(root, level + 1); |
| 914 | 864 | ||
| 915 | if (!buffer_dirty(path[level].bp_sib_bh)) | 865 | if (!buffer_dirty(path[level].bp_sib_bh)) |
| 916 | nilfs_btnode_mark_dirty(path[level].bp_sib_bh); | 866 | nilfs_btnode_mark_dirty(path[level].bp_sib_bh); |
| @@ -922,7 +872,7 @@ static void nilfs_btree_grow(struct nilfs_btree *btree, | |||
| 922 | 872 | ||
| 923 | nilfs_btree_do_insert(btree, path, level, keyp, ptrp); | 873 | nilfs_btree_do_insert(btree, path, level, keyp, ptrp); |
| 924 | 874 | ||
| 925 | *keyp = nilfs_btree_node_get_key(btree, child, 0); | 875 | *keyp = nilfs_btree_node_get_key(child, 0); |
| 926 | *ptrp = path[level].bp_newreq.bpr_ptr; | 876 | *ptrp = path[level].bp_newreq.bpr_ptr; |
| 927 | } | 877 | } |
| 928 | 878 | ||
| @@ -990,26 +940,29 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
| 990 | struct nilfs_btree_node *node, *parent, *sib; | 940 | struct nilfs_btree_node *node, *parent, *sib; |
| 991 | __u64 sibptr; | 941 | __u64 sibptr; |
| 992 | int pindex, level, ret; | 942 | int pindex, level, ret; |
| 943 | struct inode *dat = NULL; | ||
| 993 | 944 | ||
| 994 | stats->bs_nblocks = 0; | 945 | stats->bs_nblocks = 0; |
| 995 | level = NILFS_BTREE_LEVEL_DATA; | 946 | level = NILFS_BTREE_LEVEL_DATA; |
| 996 | 947 | ||
| 997 | /* allocate a new ptr for data block */ | 948 | /* allocate a new ptr for data block */ |
| 998 | if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) | 949 | if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) { |
| 999 | path[level].bp_newreq.bpr_ptr = | 950 | path[level].bp_newreq.bpr_ptr = |
| 1000 | nilfs_btree_find_target_v(btree, path, key); | 951 | nilfs_btree_find_target_v(btree, path, key); |
| 952 | dat = nilfs_bmap_get_dat(&btree->bt_bmap); | ||
| 953 | } | ||
| 1001 | 954 | ||
| 1002 | ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, | 955 | ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, |
| 1003 | &path[level].bp_newreq); | 956 | &path[level].bp_newreq, dat); |
| 1004 | if (ret < 0) | 957 | if (ret < 0) |
| 1005 | goto err_out_data; | 958 | goto err_out_data; |
| 1006 | 959 | ||
| 1007 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; | 960 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; |
| 1008 | level < nilfs_btree_height(btree) - 1; | 961 | level < nilfs_btree_height(btree) - 1; |
| 1009 | level++) { | 962 | level++) { |
| 1010 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 963 | node = nilfs_btree_get_nonroot_node(path, level); |
| 1011 | if (nilfs_btree_node_get_nchildren(btree, node) < | 964 | if (nilfs_btree_node_get_nchildren(node) < |
| 1012 | nilfs_btree_node_nchildren_max(btree, node)) { | 965 | nilfs_btree_node_nchildren_max(node, btree)) { |
| 1013 | path[level].bp_op = nilfs_btree_do_insert; | 966 | path[level].bp_op = nilfs_btree_do_insert; |
| 1014 | stats->bs_nblocks++; | 967 | stats->bs_nblocks++; |
| 1015 | goto out; | 968 | goto out; |
| @@ -1026,8 +979,8 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
| 1026 | if (ret < 0) | 979 | if (ret < 0) |
| 1027 | goto err_out_child_node; | 980 | goto err_out_child_node; |
| 1028 | sib = (struct nilfs_btree_node *)bh->b_data; | 981 | sib = (struct nilfs_btree_node *)bh->b_data; |
| 1029 | if (nilfs_btree_node_get_nchildren(btree, sib) < | 982 | if (nilfs_btree_node_get_nchildren(sib) < |
| 1030 | nilfs_btree_node_nchildren_max(btree, sib)) { | 983 | nilfs_btree_node_nchildren_max(sib, btree)) { |
| 1031 | path[level].bp_sib_bh = bh; | 984 | path[level].bp_sib_bh = bh; |
| 1032 | path[level].bp_op = nilfs_btree_carry_left; | 985 | path[level].bp_op = nilfs_btree_carry_left; |
| 1033 | stats->bs_nblocks++; | 986 | stats->bs_nblocks++; |
| @@ -1038,15 +991,15 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
| 1038 | 991 | ||
| 1039 | /* right sibling */ | 992 | /* right sibling */ |
| 1040 | if (pindex < | 993 | if (pindex < |
| 1041 | nilfs_btree_node_get_nchildren(btree, parent) - 1) { | 994 | nilfs_btree_node_get_nchildren(parent) - 1) { |
| 1042 | sibptr = nilfs_btree_node_get_ptr(btree, parent, | 995 | sibptr = nilfs_btree_node_get_ptr(btree, parent, |
| 1043 | pindex + 1); | 996 | pindex + 1); |
| 1044 | ret = nilfs_btree_get_block(btree, sibptr, &bh); | 997 | ret = nilfs_btree_get_block(btree, sibptr, &bh); |
| 1045 | if (ret < 0) | 998 | if (ret < 0) |
| 1046 | goto err_out_child_node; | 999 | goto err_out_child_node; |
| 1047 | sib = (struct nilfs_btree_node *)bh->b_data; | 1000 | sib = (struct nilfs_btree_node *)bh->b_data; |
| 1048 | if (nilfs_btree_node_get_nchildren(btree, sib) < | 1001 | if (nilfs_btree_node_get_nchildren(sib) < |
| 1049 | nilfs_btree_node_nchildren_max(btree, sib)) { | 1002 | nilfs_btree_node_nchildren_max(sib, btree)) { |
| 1050 | path[level].bp_sib_bh = bh; | 1003 | path[level].bp_sib_bh = bh; |
| 1051 | path[level].bp_op = nilfs_btree_carry_right; | 1004 | path[level].bp_op = nilfs_btree_carry_right; |
| 1052 | stats->bs_nblocks++; | 1005 | stats->bs_nblocks++; |
| @@ -1059,7 +1012,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
| 1059 | path[level].bp_newreq.bpr_ptr = | 1012 | path[level].bp_newreq.bpr_ptr = |
| 1060 | path[level - 1].bp_newreq.bpr_ptr + 1; | 1013 | path[level - 1].bp_newreq.bpr_ptr + 1; |
| 1061 | ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, | 1014 | ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, |
| 1062 | &path[level].bp_newreq); | 1015 | &path[level].bp_newreq, dat); |
| 1063 | if (ret < 0) | 1016 | if (ret < 0) |
| 1064 | goto err_out_child_node; | 1017 | goto err_out_child_node; |
| 1065 | ret = nilfs_btree_get_new_block(btree, | 1018 | ret = nilfs_btree_get_new_block(btree, |
| @@ -1081,8 +1034,8 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
| 1081 | 1034 | ||
| 1082 | /* root */ | 1035 | /* root */ |
| 1083 | node = nilfs_btree_get_root(btree); | 1036 | node = nilfs_btree_get_root(btree); |
| 1084 | if (nilfs_btree_node_get_nchildren(btree, node) < | 1037 | if (nilfs_btree_node_get_nchildren(node) < |
| 1085 | nilfs_btree_node_nchildren_max(btree, node)) { | 1038 | nilfs_btree_node_nchildren_max(node, btree)) { |
| 1086 | path[level].bp_op = nilfs_btree_do_insert; | 1039 | path[level].bp_op = nilfs_btree_do_insert; |
| 1087 | stats->bs_nblocks++; | 1040 | stats->bs_nblocks++; |
| 1088 | goto out; | 1041 | goto out; |
| @@ -1091,7 +1044,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
| 1091 | /* grow */ | 1044 | /* grow */ |
| 1092 | path[level].bp_newreq.bpr_ptr = path[level - 1].bp_newreq.bpr_ptr + 1; | 1045 | path[level].bp_newreq.bpr_ptr = path[level - 1].bp_newreq.bpr_ptr + 1; |
| 1093 | ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, | 1046 | ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, |
| 1094 | &path[level].bp_newreq); | 1047 | &path[level].bp_newreq, dat); |
| 1095 | if (ret < 0) | 1048 | if (ret < 0) |
| 1096 | goto err_out_child_node; | 1049 | goto err_out_child_node; |
| 1097 | ret = nilfs_btree_get_new_block(btree, path[level].bp_newreq.bpr_ptr, | 1050 | ret = nilfs_btree_get_new_block(btree, path[level].bp_newreq.bpr_ptr, |
| @@ -1119,16 +1072,18 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
| 1119 | 1072 | ||
| 1120 | /* error */ | 1073 | /* error */ |
| 1121 | err_out_curr_node: | 1074 | err_out_curr_node: |
| 1122 | nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq); | 1075 | nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq, |
| 1076 | dat); | ||
| 1123 | err_out_child_node: | 1077 | err_out_child_node: |
| 1124 | for (level--; level > NILFS_BTREE_LEVEL_DATA; level--) { | 1078 | for (level--; level > NILFS_BTREE_LEVEL_DATA; level--) { |
| 1125 | nilfs_btnode_delete(path[level].bp_sib_bh); | 1079 | nilfs_btnode_delete(path[level].bp_sib_bh); |
| 1126 | nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, | 1080 | nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, |
| 1127 | &path[level].bp_newreq); | 1081 | &path[level].bp_newreq, dat); |
| 1128 | 1082 | ||
| 1129 | } | 1083 | } |
| 1130 | 1084 | ||
| 1131 | nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq); | 1085 | nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq, |
| 1086 | dat); | ||
| 1132 | err_out_data: | 1087 | err_out_data: |
| 1133 | *levelp = level; | 1088 | *levelp = level; |
| 1134 | stats->bs_nblocks = 0; | 1089 | stats->bs_nblocks = 0; |
| @@ -1139,16 +1094,19 @@ static void nilfs_btree_commit_insert(struct nilfs_btree *btree, | |||
| 1139 | struct nilfs_btree_path *path, | 1094 | struct nilfs_btree_path *path, |
| 1140 | int maxlevel, __u64 key, __u64 ptr) | 1095 | int maxlevel, __u64 key, __u64 ptr) |
| 1141 | { | 1096 | { |
| 1097 | struct inode *dat = NULL; | ||
| 1142 | int level; | 1098 | int level; |
| 1143 | 1099 | ||
| 1144 | set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr)); | 1100 | set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr)); |
| 1145 | ptr = path[NILFS_BTREE_LEVEL_DATA].bp_newreq.bpr_ptr; | 1101 | ptr = path[NILFS_BTREE_LEVEL_DATA].bp_newreq.bpr_ptr; |
| 1146 | if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) | 1102 | if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) { |
| 1147 | nilfs_btree_set_target_v(btree, key, ptr); | 1103 | nilfs_btree_set_target_v(btree, key, ptr); |
| 1104 | dat = nilfs_bmap_get_dat(&btree->bt_bmap); | ||
| 1105 | } | ||
| 1148 | 1106 | ||
| 1149 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { | 1107 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { |
| 1150 | nilfs_bmap_commit_alloc_ptr(&btree->bt_bmap, | 1108 | nilfs_bmap_commit_alloc_ptr(&btree->bt_bmap, |
| 1151 | &path[level - 1].bp_newreq); | 1109 | &path[level - 1].bp_newreq, dat); |
| 1152 | path[level].bp_op(btree, path, level, &key, &ptr); | 1110 | path[level].bp_op(btree, path, level, &key, &ptr); |
| 1153 | } | 1111 | } |
| 1154 | 1112 | ||
| @@ -1164,10 +1122,10 @@ static int nilfs_btree_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) | |||
| 1164 | int level, ret; | 1122 | int level, ret; |
| 1165 | 1123 | ||
| 1166 | btree = (struct nilfs_btree *)bmap; | 1124 | btree = (struct nilfs_btree *)bmap; |
| 1167 | path = nilfs_btree_alloc_path(btree); | 1125 | path = nilfs_btree_alloc_path(); |
| 1168 | if (path == NULL) | 1126 | if (path == NULL) |
| 1169 | return -ENOMEM; | 1127 | return -ENOMEM; |
| 1170 | nilfs_btree_init_path(btree, path); | 1128 | nilfs_btree_init_path(path); |
| 1171 | 1129 | ||
| 1172 | ret = nilfs_btree_do_lookup(btree, path, key, NULL, | 1130 | ret = nilfs_btree_do_lookup(btree, path, key, NULL, |
| 1173 | NILFS_BTREE_LEVEL_NODE_MIN); | 1131 | NILFS_BTREE_LEVEL_NODE_MIN); |
| @@ -1184,8 +1142,8 @@ static int nilfs_btree_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) | |||
| 1184 | nilfs_bmap_add_blocks(bmap, stats.bs_nblocks); | 1142 | nilfs_bmap_add_blocks(bmap, stats.bs_nblocks); |
| 1185 | 1143 | ||
| 1186 | out: | 1144 | out: |
| 1187 | nilfs_btree_clear_path(btree, path); | 1145 | nilfs_btree_release_path(path); |
| 1188 | nilfs_btree_free_path(btree, path); | 1146 | nilfs_btree_free_path(path); |
| 1189 | return ret; | 1147 | return ret; |
| 1190 | } | 1148 | } |
| 1191 | 1149 | ||
| @@ -1197,7 +1155,7 @@ static void nilfs_btree_do_delete(struct nilfs_btree *btree, | |||
| 1197 | 1155 | ||
| 1198 | if (level < nilfs_btree_height(btree) - 1) { | 1156 | if (level < nilfs_btree_height(btree) - 1) { |
| 1199 | lock_buffer(path[level].bp_bh); | 1157 | lock_buffer(path[level].bp_bh); |
| 1200 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 1158 | node = nilfs_btree_get_nonroot_node(path, level); |
| 1201 | nilfs_btree_node_delete(btree, node, keyp, ptrp, | 1159 | nilfs_btree_node_delete(btree, node, keyp, ptrp, |
| 1202 | path[level].bp_index); | 1160 | path[level].bp_index); |
| 1203 | if (!buffer_dirty(path[level].bp_bh)) | 1161 | if (!buffer_dirty(path[level].bp_bh)) |
| @@ -1205,7 +1163,7 @@ static void nilfs_btree_do_delete(struct nilfs_btree *btree, | |||
| 1205 | unlock_buffer(path[level].bp_bh); | 1163 | unlock_buffer(path[level].bp_bh); |
| 1206 | if (path[level].bp_index == 0) | 1164 | if (path[level].bp_index == 0) |
| 1207 | nilfs_btree_promote_key(btree, path, level + 1, | 1165 | nilfs_btree_promote_key(btree, path, level + 1, |
| 1208 | nilfs_btree_node_get_key(btree, node, 0)); | 1166 | nilfs_btree_node_get_key(node, 0)); |
| 1209 | } else { | 1167 | } else { |
| 1210 | node = nilfs_btree_get_root(btree); | 1168 | node = nilfs_btree_get_root(btree); |
| 1211 | nilfs_btree_node_delete(btree, node, keyp, ptrp, | 1169 | nilfs_btree_node_delete(btree, node, keyp, ptrp, |
| @@ -1225,10 +1183,10 @@ static void nilfs_btree_borrow_left(struct nilfs_btree *btree, | |||
| 1225 | lock_buffer(path[level].bp_bh); | 1183 | lock_buffer(path[level].bp_bh); |
| 1226 | lock_buffer(path[level].bp_sib_bh); | 1184 | lock_buffer(path[level].bp_sib_bh); |
| 1227 | 1185 | ||
| 1228 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 1186 | node = nilfs_btree_get_nonroot_node(path, level); |
| 1229 | left = nilfs_btree_get_sib_node(btree, path, level); | 1187 | left = nilfs_btree_get_sib_node(path, level); |
| 1230 | nchildren = nilfs_btree_node_get_nchildren(btree, node); | 1188 | nchildren = nilfs_btree_node_get_nchildren(node); |
| 1231 | lnchildren = nilfs_btree_node_get_nchildren(btree, left); | 1189 | lnchildren = nilfs_btree_node_get_nchildren(left); |
| 1232 | 1190 | ||
| 1233 | n = (nchildren + lnchildren) / 2 - nchildren; | 1191 | n = (nchildren + lnchildren) / 2 - nchildren; |
| 1234 | 1192 | ||
| @@ -1243,7 +1201,7 @@ static void nilfs_btree_borrow_left(struct nilfs_btree *btree, | |||
| 1243 | unlock_buffer(path[level].bp_sib_bh); | 1201 | unlock_buffer(path[level].bp_sib_bh); |
| 1244 | 1202 | ||
| 1245 | nilfs_btree_promote_key(btree, path, level + 1, | 1203 | nilfs_btree_promote_key(btree, path, level + 1, |
| 1246 | nilfs_btree_node_get_key(btree, node, 0)); | 1204 | nilfs_btree_node_get_key(node, 0)); |
| 1247 | 1205 | ||
| 1248 | brelse(path[level].bp_sib_bh); | 1206 | brelse(path[level].bp_sib_bh); |
| 1249 | path[level].bp_sib_bh = NULL; | 1207 | path[level].bp_sib_bh = NULL; |
| @@ -1262,10 +1220,10 @@ static void nilfs_btree_borrow_right(struct nilfs_btree *btree, | |||
| 1262 | lock_buffer(path[level].bp_bh); | 1220 | lock_buffer(path[level].bp_bh); |
| 1263 | lock_buffer(path[level].bp_sib_bh); | 1221 | lock_buffer(path[level].bp_sib_bh); |
| 1264 | 1222 | ||
| 1265 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 1223 | node = nilfs_btree_get_nonroot_node(path, level); |
| 1266 | right = nilfs_btree_get_sib_node(btree, path, level); | 1224 | right = nilfs_btree_get_sib_node(path, level); |
| 1267 | nchildren = nilfs_btree_node_get_nchildren(btree, node); | 1225 | nchildren = nilfs_btree_node_get_nchildren(node); |
| 1268 | rnchildren = nilfs_btree_node_get_nchildren(btree, right); | 1226 | rnchildren = nilfs_btree_node_get_nchildren(right); |
| 1269 | 1227 | ||
| 1270 | n = (nchildren + rnchildren) / 2 - nchildren; | 1228 | n = (nchildren + rnchildren) / 2 - nchildren; |
| 1271 | 1229 | ||
| @@ -1281,7 +1239,7 @@ static void nilfs_btree_borrow_right(struct nilfs_btree *btree, | |||
| 1281 | 1239 | ||
| 1282 | path[level + 1].bp_index++; | 1240 | path[level + 1].bp_index++; |
| 1283 | nilfs_btree_promote_key(btree, path, level + 1, | 1241 | nilfs_btree_promote_key(btree, path, level + 1, |
| 1284 | nilfs_btree_node_get_key(btree, right, 0)); | 1242 | nilfs_btree_node_get_key(right, 0)); |
| 1285 | path[level + 1].bp_index--; | 1243 | path[level + 1].bp_index--; |
| 1286 | 1244 | ||
| 1287 | brelse(path[level].bp_sib_bh); | 1245 | brelse(path[level].bp_sib_bh); |
| @@ -1300,10 +1258,10 @@ static void nilfs_btree_concat_left(struct nilfs_btree *btree, | |||
| 1300 | lock_buffer(path[level].bp_bh); | 1258 | lock_buffer(path[level].bp_bh); |
| 1301 | lock_buffer(path[level].bp_sib_bh); | 1259 | lock_buffer(path[level].bp_sib_bh); |
| 1302 | 1260 | ||
| 1303 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 1261 | node = nilfs_btree_get_nonroot_node(path, level); |
| 1304 | left = nilfs_btree_get_sib_node(btree, path, level); | 1262 | left = nilfs_btree_get_sib_node(path, level); |
| 1305 | 1263 | ||
| 1306 | n = nilfs_btree_node_get_nchildren(btree, node); | 1264 | n = nilfs_btree_node_get_nchildren(node); |
| 1307 | 1265 | ||
| 1308 | nilfs_btree_node_move_left(btree, left, node, n); | 1266 | nilfs_btree_node_move_left(btree, left, node, n); |
| 1309 | 1267 | ||
| @@ -1316,7 +1274,7 @@ static void nilfs_btree_concat_left(struct nilfs_btree *btree, | |||
| 1316 | nilfs_btnode_delete(path[level].bp_bh); | 1274 | nilfs_btnode_delete(path[level].bp_bh); |
| 1317 | path[level].bp_bh = path[level].bp_sib_bh; | 1275 | path[level].bp_bh = path[level].bp_sib_bh; |
| 1318 | path[level].bp_sib_bh = NULL; | 1276 | path[level].bp_sib_bh = NULL; |
| 1319 | path[level].bp_index += nilfs_btree_node_get_nchildren(btree, left); | 1277 | path[level].bp_index += nilfs_btree_node_get_nchildren(left); |
| 1320 | } | 1278 | } |
| 1321 | 1279 | ||
| 1322 | static void nilfs_btree_concat_right(struct nilfs_btree *btree, | 1280 | static void nilfs_btree_concat_right(struct nilfs_btree *btree, |
| @@ -1331,10 +1289,10 @@ static void nilfs_btree_concat_right(struct nilfs_btree *btree, | |||
| 1331 | lock_buffer(path[level].bp_bh); | 1289 | lock_buffer(path[level].bp_bh); |
| 1332 | lock_buffer(path[level].bp_sib_bh); | 1290 | lock_buffer(path[level].bp_sib_bh); |
| 1333 | 1291 | ||
| 1334 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 1292 | node = nilfs_btree_get_nonroot_node(path, level); |
| 1335 | right = nilfs_btree_get_sib_node(btree, path, level); | 1293 | right = nilfs_btree_get_sib_node(path, level); |
| 1336 | 1294 | ||
| 1337 | n = nilfs_btree_node_get_nchildren(btree, right); | 1295 | n = nilfs_btree_node_get_nchildren(right); |
| 1338 | 1296 | ||
| 1339 | nilfs_btree_node_move_left(btree, node, right, n); | 1297 | nilfs_btree_node_move_left(btree, node, right, n); |
| 1340 | 1298 | ||
| @@ -1360,11 +1318,11 @@ static void nilfs_btree_shrink(struct nilfs_btree *btree, | |||
| 1360 | 1318 | ||
| 1361 | lock_buffer(path[level].bp_bh); | 1319 | lock_buffer(path[level].bp_bh); |
| 1362 | root = nilfs_btree_get_root(btree); | 1320 | root = nilfs_btree_get_root(btree); |
| 1363 | child = nilfs_btree_get_nonroot_node(btree, path, level); | 1321 | child = nilfs_btree_get_nonroot_node(path, level); |
| 1364 | 1322 | ||
| 1365 | nilfs_btree_node_delete(btree, root, NULL, NULL, 0); | 1323 | nilfs_btree_node_delete(btree, root, NULL, NULL, 0); |
| 1366 | nilfs_btree_node_set_level(btree, root, level); | 1324 | nilfs_btree_node_set_level(root, level); |
| 1367 | n = nilfs_btree_node_get_nchildren(btree, child); | 1325 | n = nilfs_btree_node_get_nchildren(child); |
| 1368 | nilfs_btree_node_move_left(btree, root, child, n); | 1326 | nilfs_btree_node_move_left(btree, root, child, n); |
| 1369 | unlock_buffer(path[level].bp_bh); | 1327 | unlock_buffer(path[level].bp_bh); |
| 1370 | 1328 | ||
| @@ -1376,7 +1334,8 @@ static void nilfs_btree_shrink(struct nilfs_btree *btree, | |||
| 1376 | static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | 1334 | static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, |
| 1377 | struct nilfs_btree_path *path, | 1335 | struct nilfs_btree_path *path, |
| 1378 | int *levelp, | 1336 | int *levelp, |
| 1379 | struct nilfs_bmap_stats *stats) | 1337 | struct nilfs_bmap_stats *stats, |
| 1338 | struct inode *dat) | ||
| 1380 | { | 1339 | { |
| 1381 | struct buffer_head *bh; | 1340 | struct buffer_head *bh; |
| 1382 | struct nilfs_btree_node *node, *parent, *sib; | 1341 | struct nilfs_btree_node *node, *parent, *sib; |
| @@ -1388,17 +1347,17 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
| 1388 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; | 1347 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; |
| 1389 | level < nilfs_btree_height(btree) - 1; | 1348 | level < nilfs_btree_height(btree) - 1; |
| 1390 | level++) { | 1349 | level++) { |
| 1391 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 1350 | node = nilfs_btree_get_nonroot_node(path, level); |
| 1392 | path[level].bp_oldreq.bpr_ptr = | 1351 | path[level].bp_oldreq.bpr_ptr = |
| 1393 | nilfs_btree_node_get_ptr(btree, node, | 1352 | nilfs_btree_node_get_ptr(btree, node, |
| 1394 | path[level].bp_index); | 1353 | path[level].bp_index); |
| 1395 | ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap, | 1354 | ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap, |
| 1396 | &path[level].bp_oldreq); | 1355 | &path[level].bp_oldreq, dat); |
| 1397 | if (ret < 0) | 1356 | if (ret < 0) |
| 1398 | goto err_out_child_node; | 1357 | goto err_out_child_node; |
| 1399 | 1358 | ||
| 1400 | if (nilfs_btree_node_get_nchildren(btree, node) > | 1359 | if (nilfs_btree_node_get_nchildren(node) > |
| 1401 | nilfs_btree_node_nchildren_min(btree, node)) { | 1360 | nilfs_btree_node_nchildren_min(node, btree)) { |
| 1402 | path[level].bp_op = nilfs_btree_do_delete; | 1361 | path[level].bp_op = nilfs_btree_do_delete; |
| 1403 | stats->bs_nblocks++; | 1362 | stats->bs_nblocks++; |
| 1404 | goto out; | 1363 | goto out; |
| @@ -1415,8 +1374,8 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
| 1415 | if (ret < 0) | 1374 | if (ret < 0) |
| 1416 | goto err_out_curr_node; | 1375 | goto err_out_curr_node; |
| 1417 | sib = (struct nilfs_btree_node *)bh->b_data; | 1376 | sib = (struct nilfs_btree_node *)bh->b_data; |
| 1418 | if (nilfs_btree_node_get_nchildren(btree, sib) > | 1377 | if (nilfs_btree_node_get_nchildren(sib) > |
| 1419 | nilfs_btree_node_nchildren_min(btree, sib)) { | 1378 | nilfs_btree_node_nchildren_min(sib, btree)) { |
| 1420 | path[level].bp_sib_bh = bh; | 1379 | path[level].bp_sib_bh = bh; |
| 1421 | path[level].bp_op = nilfs_btree_borrow_left; | 1380 | path[level].bp_op = nilfs_btree_borrow_left; |
| 1422 | stats->bs_nblocks++; | 1381 | stats->bs_nblocks++; |
| @@ -1428,7 +1387,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
| 1428 | /* continue; */ | 1387 | /* continue; */ |
| 1429 | } | 1388 | } |
| 1430 | } else if (pindex < | 1389 | } else if (pindex < |
| 1431 | nilfs_btree_node_get_nchildren(btree, parent) - 1) { | 1390 | nilfs_btree_node_get_nchildren(parent) - 1) { |
| 1432 | /* right sibling */ | 1391 | /* right sibling */ |
| 1433 | sibptr = nilfs_btree_node_get_ptr(btree, parent, | 1392 | sibptr = nilfs_btree_node_get_ptr(btree, parent, |
| 1434 | pindex + 1); | 1393 | pindex + 1); |
| @@ -1436,8 +1395,8 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
| 1436 | if (ret < 0) | 1395 | if (ret < 0) |
| 1437 | goto err_out_curr_node; | 1396 | goto err_out_curr_node; |
| 1438 | sib = (struct nilfs_btree_node *)bh->b_data; | 1397 | sib = (struct nilfs_btree_node *)bh->b_data; |
| 1439 | if (nilfs_btree_node_get_nchildren(btree, sib) > | 1398 | if (nilfs_btree_node_get_nchildren(sib) > |
| 1440 | nilfs_btree_node_nchildren_min(btree, sib)) { | 1399 | nilfs_btree_node_nchildren_min(sib, btree)) { |
| 1441 | path[level].bp_sib_bh = bh; | 1400 | path[level].bp_sib_bh = bh; |
| 1442 | path[level].bp_op = nilfs_btree_borrow_right; | 1401 | path[level].bp_op = nilfs_btree_borrow_right; |
| 1443 | stats->bs_nblocks++; | 1402 | stats->bs_nblocks++; |
| @@ -1452,7 +1411,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
| 1452 | /* no siblings */ | 1411 | /* no siblings */ |
| 1453 | /* the only child of the root node */ | 1412 | /* the only child of the root node */ |
| 1454 | WARN_ON(level != nilfs_btree_height(btree) - 2); | 1413 | WARN_ON(level != nilfs_btree_height(btree) - 2); |
| 1455 | if (nilfs_btree_node_get_nchildren(btree, node) - 1 <= | 1414 | if (nilfs_btree_node_get_nchildren(node) - 1 <= |
| 1456 | NILFS_BTREE_ROOT_NCHILDREN_MAX) { | 1415 | NILFS_BTREE_ROOT_NCHILDREN_MAX) { |
| 1457 | path[level].bp_op = nilfs_btree_shrink; | 1416 | path[level].bp_op = nilfs_btree_shrink; |
| 1458 | stats->bs_nblocks += 2; | 1417 | stats->bs_nblocks += 2; |
| @@ -1471,7 +1430,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
| 1471 | nilfs_btree_node_get_ptr(btree, node, path[level].bp_index); | 1430 | nilfs_btree_node_get_ptr(btree, node, path[level].bp_index); |
| 1472 | 1431 | ||
| 1473 | ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap, | 1432 | ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap, |
| 1474 | &path[level].bp_oldreq); | 1433 | &path[level].bp_oldreq, dat); |
| 1475 | if (ret < 0) | 1434 | if (ret < 0) |
| 1476 | goto err_out_child_node; | 1435 | goto err_out_child_node; |
| 1477 | 1436 | ||
| @@ -1486,12 +1445,12 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
| 1486 | 1445 | ||
| 1487 | /* error */ | 1446 | /* error */ |
| 1488 | err_out_curr_node: | 1447 | err_out_curr_node: |
| 1489 | nilfs_bmap_abort_end_ptr(&btree->bt_bmap, &path[level].bp_oldreq); | 1448 | nilfs_bmap_abort_end_ptr(&btree->bt_bmap, &path[level].bp_oldreq, dat); |
| 1490 | err_out_child_node: | 1449 | err_out_child_node: |
| 1491 | for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--) { | 1450 | for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--) { |
| 1492 | brelse(path[level].bp_sib_bh); | 1451 | brelse(path[level].bp_sib_bh); |
| 1493 | nilfs_bmap_abort_end_ptr(&btree->bt_bmap, | 1452 | nilfs_bmap_abort_end_ptr(&btree->bt_bmap, |
| 1494 | &path[level].bp_oldreq); | 1453 | &path[level].bp_oldreq, dat); |
| 1495 | } | 1454 | } |
| 1496 | *levelp = level; | 1455 | *levelp = level; |
| 1497 | stats->bs_nblocks = 0; | 1456 | stats->bs_nblocks = 0; |
| @@ -1500,13 +1459,13 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
| 1500 | 1459 | ||
| 1501 | static void nilfs_btree_commit_delete(struct nilfs_btree *btree, | 1460 | static void nilfs_btree_commit_delete(struct nilfs_btree *btree, |
| 1502 | struct nilfs_btree_path *path, | 1461 | struct nilfs_btree_path *path, |
| 1503 | int maxlevel) | 1462 | int maxlevel, struct inode *dat) |
| 1504 | { | 1463 | { |
| 1505 | int level; | 1464 | int level; |
| 1506 | 1465 | ||
| 1507 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { | 1466 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { |
| 1508 | nilfs_bmap_commit_end_ptr(&btree->bt_bmap, | 1467 | nilfs_bmap_commit_end_ptr(&btree->bt_bmap, |
| 1509 | &path[level].bp_oldreq); | 1468 | &path[level].bp_oldreq, dat); |
| 1510 | path[level].bp_op(btree, path, level, NULL, NULL); | 1469 | path[level].bp_op(btree, path, level, NULL, NULL); |
| 1511 | } | 1470 | } |
| 1512 | 1471 | ||
| @@ -1520,27 +1479,32 @@ static int nilfs_btree_delete(struct nilfs_bmap *bmap, __u64 key) | |||
| 1520 | struct nilfs_btree *btree; | 1479 | struct nilfs_btree *btree; |
| 1521 | struct nilfs_btree_path *path; | 1480 | struct nilfs_btree_path *path; |
| 1522 | struct nilfs_bmap_stats stats; | 1481 | struct nilfs_bmap_stats stats; |
| 1482 | struct inode *dat; | ||
| 1523 | int level, ret; | 1483 | int level, ret; |
| 1524 | 1484 | ||
| 1525 | btree = (struct nilfs_btree *)bmap; | 1485 | btree = (struct nilfs_btree *)bmap; |
| 1526 | path = nilfs_btree_alloc_path(btree); | 1486 | path = nilfs_btree_alloc_path(); |
| 1527 | if (path == NULL) | 1487 | if (path == NULL) |
| 1528 | return -ENOMEM; | 1488 | return -ENOMEM; |
| 1529 | nilfs_btree_init_path(btree, path); | 1489 | nilfs_btree_init_path(path); |
| 1530 | ret = nilfs_btree_do_lookup(btree, path, key, NULL, | 1490 | ret = nilfs_btree_do_lookup(btree, path, key, NULL, |
| 1531 | NILFS_BTREE_LEVEL_NODE_MIN); | 1491 | NILFS_BTREE_LEVEL_NODE_MIN); |
| 1532 | if (ret < 0) | 1492 | if (ret < 0) |
| 1533 | goto out; | 1493 | goto out; |
| 1534 | 1494 | ||
| 1535 | ret = nilfs_btree_prepare_delete(btree, path, &level, &stats); | 1495 | |
| 1496 | dat = NILFS_BMAP_USE_VBN(&btree->bt_bmap) ? | ||
| 1497 | nilfs_bmap_get_dat(&btree->bt_bmap) : NULL; | ||
| 1498 | |||
| 1499 | ret = nilfs_btree_prepare_delete(btree, path, &level, &stats, dat); | ||
| 1536 | if (ret < 0) | 1500 | if (ret < 0) |
| 1537 | goto out; | 1501 | goto out; |
| 1538 | nilfs_btree_commit_delete(btree, path, level); | 1502 | nilfs_btree_commit_delete(btree, path, level, dat); |
| 1539 | nilfs_bmap_sub_blocks(bmap, stats.bs_nblocks); | 1503 | nilfs_bmap_sub_blocks(bmap, stats.bs_nblocks); |
| 1540 | 1504 | ||
| 1541 | out: | 1505 | out: |
| 1542 | nilfs_btree_clear_path(btree, path); | 1506 | nilfs_btree_release_path(path); |
| 1543 | nilfs_btree_free_path(btree, path); | 1507 | nilfs_btree_free_path(path); |
| 1544 | return ret; | 1508 | return ret; |
| 1545 | } | 1509 | } |
| 1546 | 1510 | ||
| @@ -1551,15 +1515,15 @@ static int nilfs_btree_last_key(const struct nilfs_bmap *bmap, __u64 *keyp) | |||
| 1551 | int ret; | 1515 | int ret; |
| 1552 | 1516 | ||
| 1553 | btree = (struct nilfs_btree *)bmap; | 1517 | btree = (struct nilfs_btree *)bmap; |
| 1554 | path = nilfs_btree_alloc_path(btree); | 1518 | path = nilfs_btree_alloc_path(); |
| 1555 | if (path == NULL) | 1519 | if (path == NULL) |
| 1556 | return -ENOMEM; | 1520 | return -ENOMEM; |
| 1557 | nilfs_btree_init_path(btree, path); | 1521 | nilfs_btree_init_path(path); |
| 1558 | 1522 | ||
| 1559 | ret = nilfs_btree_do_lookup_last(btree, path, keyp, NULL); | 1523 | ret = nilfs_btree_do_lookup_last(btree, path, keyp, NULL); |
| 1560 | 1524 | ||
| 1561 | nilfs_btree_clear_path(btree, path); | 1525 | nilfs_btree_release_path(path); |
| 1562 | nilfs_btree_free_path(btree, path); | 1526 | nilfs_btree_free_path(path); |
| 1563 | 1527 | ||
| 1564 | return ret; | 1528 | return ret; |
| 1565 | } | 1529 | } |
| @@ -1581,7 +1545,7 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *bmap, __u64 key) | |||
| 1581 | node = root; | 1545 | node = root; |
| 1582 | break; | 1546 | break; |
| 1583 | case 3: | 1547 | case 3: |
| 1584 | nchildren = nilfs_btree_node_get_nchildren(btree, root); | 1548 | nchildren = nilfs_btree_node_get_nchildren(root); |
| 1585 | if (nchildren > 1) | 1549 | if (nchildren > 1) |
| 1586 | return 0; | 1550 | return 0; |
| 1587 | ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); | 1551 | ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); |
| @@ -1594,10 +1558,10 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *bmap, __u64 key) | |||
| 1594 | return 0; | 1558 | return 0; |
| 1595 | } | 1559 | } |
| 1596 | 1560 | ||
| 1597 | nchildren = nilfs_btree_node_get_nchildren(btree, node); | 1561 | nchildren = nilfs_btree_node_get_nchildren(node); |
| 1598 | maxkey = nilfs_btree_node_get_key(btree, node, nchildren - 1); | 1562 | maxkey = nilfs_btree_node_get_key(node, nchildren - 1); |
| 1599 | nextmaxkey = (nchildren > 1) ? | 1563 | nextmaxkey = (nchildren > 1) ? |
| 1600 | nilfs_btree_node_get_key(btree, node, nchildren - 2) : 0; | 1564 | nilfs_btree_node_get_key(node, nchildren - 2) : 0; |
| 1601 | if (bh != NULL) | 1565 | if (bh != NULL) |
| 1602 | brelse(bh); | 1566 | brelse(bh); |
| 1603 | 1567 | ||
| @@ -1623,7 +1587,7 @@ static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, | |||
| 1623 | node = root; | 1587 | node = root; |
| 1624 | break; | 1588 | break; |
| 1625 | case 3: | 1589 | case 3: |
| 1626 | nchildren = nilfs_btree_node_get_nchildren(btree, root); | 1590 | nchildren = nilfs_btree_node_get_nchildren(root); |
| 1627 | WARN_ON(nchildren > 1); | 1591 | WARN_ON(nchildren > 1); |
| 1628 | ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); | 1592 | ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); |
| 1629 | ret = nilfs_btree_get_block(btree, ptr, &bh); | 1593 | ret = nilfs_btree_get_block(btree, ptr, &bh); |
| @@ -1636,11 +1600,11 @@ static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, | |||
| 1636 | return -EINVAL; | 1600 | return -EINVAL; |
| 1637 | } | 1601 | } |
| 1638 | 1602 | ||
| 1639 | nchildren = nilfs_btree_node_get_nchildren(btree, node); | 1603 | nchildren = nilfs_btree_node_get_nchildren(node); |
| 1640 | if (nchildren < nitems) | 1604 | if (nchildren < nitems) |
| 1641 | nitems = nchildren; | 1605 | nitems = nchildren; |
| 1642 | dkeys = nilfs_btree_node_dkeys(btree, node); | 1606 | dkeys = nilfs_btree_node_dkeys(node); |
| 1643 | dptrs = nilfs_btree_node_dptrs(btree, node); | 1607 | dptrs = nilfs_btree_node_dptrs(node, btree); |
| 1644 | for (i = 0; i < nitems; i++) { | 1608 | for (i = 0; i < nitems; i++) { |
| 1645 | keys[i] = nilfs_bmap_dkey_to_key(dkeys[i]); | 1609 | keys[i] = nilfs_bmap_dkey_to_key(dkeys[i]); |
| 1646 | ptrs[i] = nilfs_bmap_dptr_to_ptr(dptrs[i]); | 1610 | ptrs[i] = nilfs_bmap_dptr_to_ptr(dptrs[i]); |
| @@ -1660,18 +1624,20 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, | |||
| 1660 | struct nilfs_bmap_stats *stats) | 1624 | struct nilfs_bmap_stats *stats) |
| 1661 | { | 1625 | { |
| 1662 | struct buffer_head *bh; | 1626 | struct buffer_head *bh; |
| 1663 | struct nilfs_btree *btree; | 1627 | struct nilfs_btree *btree = (struct nilfs_btree *)bmap; |
| 1628 | struct inode *dat = NULL; | ||
| 1664 | int ret; | 1629 | int ret; |
| 1665 | 1630 | ||
| 1666 | btree = (struct nilfs_btree *)bmap; | ||
| 1667 | stats->bs_nblocks = 0; | 1631 | stats->bs_nblocks = 0; |
| 1668 | 1632 | ||
| 1669 | /* for data */ | 1633 | /* for data */ |
| 1670 | /* cannot find near ptr */ | 1634 | /* cannot find near ptr */ |
| 1671 | if (NILFS_BMAP_USE_VBN(bmap)) | 1635 | if (NILFS_BMAP_USE_VBN(bmap)) { |
| 1672 | dreq->bpr_ptr = nilfs_btree_find_target_v(btree, NULL, key); | 1636 | dreq->bpr_ptr = nilfs_btree_find_target_v(btree, NULL, key); |
| 1637 | dat = nilfs_bmap_get_dat(bmap); | ||
| 1638 | } | ||
| 1673 | 1639 | ||
| 1674 | ret = nilfs_bmap_prepare_alloc_ptr(bmap, dreq); | 1640 | ret = nilfs_bmap_prepare_alloc_ptr(bmap, dreq, dat); |
| 1675 | if (ret < 0) | 1641 | if (ret < 0) |
| 1676 | return ret; | 1642 | return ret; |
| 1677 | 1643 | ||
| @@ -1679,7 +1645,7 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, | |||
| 1679 | stats->bs_nblocks++; | 1645 | stats->bs_nblocks++; |
| 1680 | if (nreq != NULL) { | 1646 | if (nreq != NULL) { |
| 1681 | nreq->bpr_ptr = dreq->bpr_ptr + 1; | 1647 | nreq->bpr_ptr = dreq->bpr_ptr + 1; |
| 1682 | ret = nilfs_bmap_prepare_alloc_ptr(bmap, nreq); | 1648 | ret = nilfs_bmap_prepare_alloc_ptr(bmap, nreq, dat); |
| 1683 | if (ret < 0) | 1649 | if (ret < 0) |
| 1684 | goto err_out_dreq; | 1650 | goto err_out_dreq; |
| 1685 | 1651 | ||
| @@ -1696,9 +1662,9 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, | |||
| 1696 | 1662 | ||
| 1697 | /* error */ | 1663 | /* error */ |
| 1698 | err_out_nreq: | 1664 | err_out_nreq: |
| 1699 | nilfs_bmap_abort_alloc_ptr(bmap, nreq); | 1665 | nilfs_bmap_abort_alloc_ptr(bmap, nreq, dat); |
| 1700 | err_out_dreq: | 1666 | err_out_dreq: |
| 1701 | nilfs_bmap_abort_alloc_ptr(bmap, dreq); | 1667 | nilfs_bmap_abort_alloc_ptr(bmap, dreq, dat); |
| 1702 | stats->bs_nblocks = 0; | 1668 | stats->bs_nblocks = 0; |
| 1703 | return ret; | 1669 | return ret; |
| 1704 | 1670 | ||
| @@ -1713,8 +1679,9 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, | |||
| 1713 | union nilfs_bmap_ptr_req *nreq, | 1679 | union nilfs_bmap_ptr_req *nreq, |
| 1714 | struct buffer_head *bh) | 1680 | struct buffer_head *bh) |
| 1715 | { | 1681 | { |
| 1716 | struct nilfs_btree *btree; | 1682 | struct nilfs_btree *btree = (struct nilfs_btree *)bmap; |
| 1717 | struct nilfs_btree_node *node; | 1683 | struct nilfs_btree_node *node; |
| 1684 | struct inode *dat; | ||
| 1718 | __u64 tmpptr; | 1685 | __u64 tmpptr; |
| 1719 | 1686 | ||
| 1720 | /* free resources */ | 1687 | /* free resources */ |
| @@ -1725,11 +1692,11 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, | |||
| 1725 | set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr)); | 1692 | set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr)); |
| 1726 | 1693 | ||
| 1727 | /* convert and insert */ | 1694 | /* convert and insert */ |
| 1728 | btree = (struct nilfs_btree *)bmap; | 1695 | dat = NILFS_BMAP_USE_VBN(bmap) ? nilfs_bmap_get_dat(bmap) : NULL; |
| 1729 | nilfs_btree_init(bmap); | 1696 | nilfs_btree_init(bmap); |
| 1730 | if (nreq != NULL) { | 1697 | if (nreq != NULL) { |
| 1731 | nilfs_bmap_commit_alloc_ptr(bmap, dreq); | 1698 | nilfs_bmap_commit_alloc_ptr(bmap, dreq, dat); |
| 1732 | nilfs_bmap_commit_alloc_ptr(bmap, nreq); | 1699 | nilfs_bmap_commit_alloc_ptr(bmap, nreq, dat); |
| 1733 | 1700 | ||
| 1734 | /* create child node at level 1 */ | 1701 | /* create child node at level 1 */ |
| 1735 | lock_buffer(bh); | 1702 | lock_buffer(bh); |
| @@ -1751,7 +1718,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, | |||
| 1751 | nilfs_btree_node_init(btree, node, NILFS_BTREE_NODE_ROOT, | 1718 | nilfs_btree_node_init(btree, node, NILFS_BTREE_NODE_ROOT, |
| 1752 | 2, 1, &keys[0], &tmpptr); | 1719 | 2, 1, &keys[0], &tmpptr); |
| 1753 | } else { | 1720 | } else { |
| 1754 | nilfs_bmap_commit_alloc_ptr(bmap, dreq); | 1721 | nilfs_bmap_commit_alloc_ptr(bmap, dreq, dat); |
| 1755 | 1722 | ||
| 1756 | /* create root node at level 1 */ | 1723 | /* create root node at level 1 */ |
| 1757 | node = nilfs_btree_get_root(btree); | 1724 | node = nilfs_btree_get_root(btree); |
| @@ -1822,7 +1789,7 @@ static int nilfs_btree_propagate_p(struct nilfs_btree *btree, | |||
| 1822 | 1789 | ||
| 1823 | static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree, | 1790 | static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree, |
| 1824 | struct nilfs_btree_path *path, | 1791 | struct nilfs_btree_path *path, |
| 1825 | int level) | 1792 | int level, struct inode *dat) |
| 1826 | { | 1793 | { |
| 1827 | struct nilfs_btree_node *parent; | 1794 | struct nilfs_btree_node *parent; |
| 1828 | int ret; | 1795 | int ret; |
| @@ -1832,9 +1799,8 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree, | |||
| 1832 | nilfs_btree_node_get_ptr(btree, parent, | 1799 | nilfs_btree_node_get_ptr(btree, parent, |
| 1833 | path[level + 1].bp_index); | 1800 | path[level + 1].bp_index); |
| 1834 | path[level].bp_newreq.bpr_ptr = path[level].bp_oldreq.bpr_ptr + 1; | 1801 | path[level].bp_newreq.bpr_ptr = path[level].bp_oldreq.bpr_ptr + 1; |
| 1835 | ret = nilfs_bmap_prepare_update_v(&btree->bt_bmap, | 1802 | ret = nilfs_dat_prepare_update(dat, &path[level].bp_oldreq.bpr_req, |
| 1836 | &path[level].bp_oldreq, | 1803 | &path[level].bp_newreq.bpr_req); |
| 1837 | &path[level].bp_newreq); | ||
| 1838 | if (ret < 0) | 1804 | if (ret < 0) |
| 1839 | return ret; | 1805 | return ret; |
| 1840 | 1806 | ||
| @@ -1846,9 +1812,9 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree, | |||
| 1846 | &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache, | 1812 | &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache, |
| 1847 | &path[level].bp_ctxt); | 1813 | &path[level].bp_ctxt); |
| 1848 | if (ret < 0) { | 1814 | if (ret < 0) { |
| 1849 | nilfs_bmap_abort_update_v(&btree->bt_bmap, | 1815 | nilfs_dat_abort_update(dat, |
| 1850 | &path[level].bp_oldreq, | 1816 | &path[level].bp_oldreq.bpr_req, |
| 1851 | &path[level].bp_newreq); | 1817 | &path[level].bp_newreq.bpr_req); |
| 1852 | return ret; | 1818 | return ret; |
| 1853 | } | 1819 | } |
| 1854 | } | 1820 | } |
| @@ -1858,13 +1824,13 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree, | |||
| 1858 | 1824 | ||
| 1859 | static void nilfs_btree_commit_update_v(struct nilfs_btree *btree, | 1825 | static void nilfs_btree_commit_update_v(struct nilfs_btree *btree, |
| 1860 | struct nilfs_btree_path *path, | 1826 | struct nilfs_btree_path *path, |
| 1861 | int level) | 1827 | int level, struct inode *dat) |
| 1862 | { | 1828 | { |
| 1863 | struct nilfs_btree_node *parent; | 1829 | struct nilfs_btree_node *parent; |
| 1864 | 1830 | ||
| 1865 | nilfs_bmap_commit_update_v(&btree->bt_bmap, | 1831 | nilfs_dat_commit_update(dat, &path[level].bp_oldreq.bpr_req, |
| 1866 | &path[level].bp_oldreq, | 1832 | &path[level].bp_newreq.bpr_req, |
| 1867 | &path[level].bp_newreq); | 1833 | btree->bt_bmap.b_ptr_type == NILFS_BMAP_PTR_VS); |
| 1868 | 1834 | ||
| 1869 | if (buffer_nilfs_node(path[level].bp_bh)) { | 1835 | if (buffer_nilfs_node(path[level].bp_bh)) { |
| 1870 | nilfs_btnode_commit_change_key( | 1836 | nilfs_btnode_commit_change_key( |
| @@ -1881,11 +1847,10 @@ static void nilfs_btree_commit_update_v(struct nilfs_btree *btree, | |||
| 1881 | 1847 | ||
| 1882 | static void nilfs_btree_abort_update_v(struct nilfs_btree *btree, | 1848 | static void nilfs_btree_abort_update_v(struct nilfs_btree *btree, |
| 1883 | struct nilfs_btree_path *path, | 1849 | struct nilfs_btree_path *path, |
| 1884 | int level) | 1850 | int level, struct inode *dat) |
| 1885 | { | 1851 | { |
| 1886 | nilfs_bmap_abort_update_v(&btree->bt_bmap, | 1852 | nilfs_dat_abort_update(dat, &path[level].bp_oldreq.bpr_req, |
| 1887 | &path[level].bp_oldreq, | 1853 | &path[level].bp_newreq.bpr_req); |
| 1888 | &path[level].bp_newreq); | ||
| 1889 | if (buffer_nilfs_node(path[level].bp_bh)) | 1854 | if (buffer_nilfs_node(path[level].bp_bh)) |
| 1890 | nilfs_btnode_abort_change_key( | 1855 | nilfs_btnode_abort_change_key( |
| 1891 | &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache, | 1856 | &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache, |
| @@ -1894,14 +1859,14 @@ static void nilfs_btree_abort_update_v(struct nilfs_btree *btree, | |||
| 1894 | 1859 | ||
| 1895 | static int nilfs_btree_prepare_propagate_v(struct nilfs_btree *btree, | 1860 | static int nilfs_btree_prepare_propagate_v(struct nilfs_btree *btree, |
| 1896 | struct nilfs_btree_path *path, | 1861 | struct nilfs_btree_path *path, |
| 1897 | int minlevel, | 1862 | int minlevel, int *maxlevelp, |
| 1898 | int *maxlevelp) | 1863 | struct inode *dat) |
| 1899 | { | 1864 | { |
| 1900 | int level, ret; | 1865 | int level, ret; |
| 1901 | 1866 | ||
| 1902 | level = minlevel; | 1867 | level = minlevel; |
| 1903 | if (!buffer_nilfs_volatile(path[level].bp_bh)) { | 1868 | if (!buffer_nilfs_volatile(path[level].bp_bh)) { |
| 1904 | ret = nilfs_btree_prepare_update_v(btree, path, level); | 1869 | ret = nilfs_btree_prepare_update_v(btree, path, level, dat); |
| 1905 | if (ret < 0) | 1870 | if (ret < 0) |
| 1906 | return ret; | 1871 | return ret; |
| 1907 | } | 1872 | } |
| @@ -1909,7 +1874,7 @@ static int nilfs_btree_prepare_propagate_v(struct nilfs_btree *btree, | |||
| 1909 | !buffer_dirty(path[level].bp_bh)) { | 1874 | !buffer_dirty(path[level].bp_bh)) { |
| 1910 | 1875 | ||
| 1911 | WARN_ON(buffer_nilfs_volatile(path[level].bp_bh)); | 1876 | WARN_ON(buffer_nilfs_volatile(path[level].bp_bh)); |
| 1912 | ret = nilfs_btree_prepare_update_v(btree, path, level); | 1877 | ret = nilfs_btree_prepare_update_v(btree, path, level, dat); |
| 1913 | if (ret < 0) | 1878 | if (ret < 0) |
| 1914 | goto out; | 1879 | goto out; |
| 1915 | } | 1880 | } |
| @@ -1921,39 +1886,40 @@ static int nilfs_btree_prepare_propagate_v(struct nilfs_btree *btree, | |||
| 1921 | /* error */ | 1886 | /* error */ |
| 1922 | out: | 1887 | out: |
| 1923 | while (--level > minlevel) | 1888 | while (--level > minlevel) |
| 1924 | nilfs_btree_abort_update_v(btree, path, level); | 1889 | nilfs_btree_abort_update_v(btree, path, level, dat); |
| 1925 | if (!buffer_nilfs_volatile(path[level].bp_bh)) | 1890 | if (!buffer_nilfs_volatile(path[level].bp_bh)) |
| 1926 | nilfs_btree_abort_update_v(btree, path, level); | 1891 | nilfs_btree_abort_update_v(btree, path, level, dat); |
| 1927 | return ret; | 1892 | return ret; |
| 1928 | } | 1893 | } |
| 1929 | 1894 | ||
| 1930 | static void nilfs_btree_commit_propagate_v(struct nilfs_btree *btree, | 1895 | static void nilfs_btree_commit_propagate_v(struct nilfs_btree *btree, |
| 1931 | struct nilfs_btree_path *path, | 1896 | struct nilfs_btree_path *path, |
| 1932 | int minlevel, | 1897 | int minlevel, int maxlevel, |
| 1933 | int maxlevel, | 1898 | struct buffer_head *bh, |
| 1934 | struct buffer_head *bh) | 1899 | struct inode *dat) |
| 1935 | { | 1900 | { |
| 1936 | int level; | 1901 | int level; |
| 1937 | 1902 | ||
| 1938 | if (!buffer_nilfs_volatile(path[minlevel].bp_bh)) | 1903 | if (!buffer_nilfs_volatile(path[minlevel].bp_bh)) |
| 1939 | nilfs_btree_commit_update_v(btree, path, minlevel); | 1904 | nilfs_btree_commit_update_v(btree, path, minlevel, dat); |
| 1940 | 1905 | ||
| 1941 | for (level = minlevel + 1; level <= maxlevel; level++) | 1906 | for (level = minlevel + 1; level <= maxlevel; level++) |
| 1942 | nilfs_btree_commit_update_v(btree, path, level); | 1907 | nilfs_btree_commit_update_v(btree, path, level, dat); |
| 1943 | } | 1908 | } |
| 1944 | 1909 | ||
| 1945 | static int nilfs_btree_propagate_v(struct nilfs_btree *btree, | 1910 | static int nilfs_btree_propagate_v(struct nilfs_btree *btree, |
| 1946 | struct nilfs_btree_path *path, | 1911 | struct nilfs_btree_path *path, |
| 1947 | int level, | 1912 | int level, struct buffer_head *bh) |
| 1948 | struct buffer_head *bh) | ||
| 1949 | { | 1913 | { |
| 1950 | int maxlevel, ret; | 1914 | int maxlevel, ret; |
| 1951 | struct nilfs_btree_node *parent; | 1915 | struct nilfs_btree_node *parent; |
| 1916 | struct inode *dat = nilfs_bmap_get_dat(&btree->bt_bmap); | ||
| 1952 | __u64 ptr; | 1917 | __u64 ptr; |
| 1953 | 1918 | ||
| 1954 | get_bh(bh); | 1919 | get_bh(bh); |
| 1955 | path[level].bp_bh = bh; | 1920 | path[level].bp_bh = bh; |
| 1956 | ret = nilfs_btree_prepare_propagate_v(btree, path, level, &maxlevel); | 1921 | ret = nilfs_btree_prepare_propagate_v(btree, path, level, &maxlevel, |
| 1922 | dat); | ||
| 1957 | if (ret < 0) | 1923 | if (ret < 0) |
| 1958 | goto out; | 1924 | goto out; |
| 1959 | 1925 | ||
| @@ -1961,12 +1927,12 @@ static int nilfs_btree_propagate_v(struct nilfs_btree *btree, | |||
| 1961 | parent = nilfs_btree_get_node(btree, path, level + 1); | 1927 | parent = nilfs_btree_get_node(btree, path, level + 1); |
| 1962 | ptr = nilfs_btree_node_get_ptr(btree, parent, | 1928 | ptr = nilfs_btree_node_get_ptr(btree, parent, |
| 1963 | path[level + 1].bp_index); | 1929 | path[level + 1].bp_index); |
| 1964 | ret = nilfs_bmap_mark_dirty(&btree->bt_bmap, ptr); | 1930 | ret = nilfs_dat_mark_dirty(dat, ptr); |
| 1965 | if (ret < 0) | 1931 | if (ret < 0) |
| 1966 | goto out; | 1932 | goto out; |
| 1967 | } | 1933 | } |
| 1968 | 1934 | ||
| 1969 | nilfs_btree_commit_propagate_v(btree, path, level, maxlevel, bh); | 1935 | nilfs_btree_commit_propagate_v(btree, path, level, maxlevel, bh, dat); |
| 1970 | 1936 | ||
| 1971 | out: | 1937 | out: |
| 1972 | brelse(path[level].bp_bh); | 1938 | brelse(path[level].bp_bh); |
| @@ -1986,15 +1952,15 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap, | |||
| 1986 | WARN_ON(!buffer_dirty(bh)); | 1952 | WARN_ON(!buffer_dirty(bh)); |
| 1987 | 1953 | ||
| 1988 | btree = (struct nilfs_btree *)bmap; | 1954 | btree = (struct nilfs_btree *)bmap; |
| 1989 | path = nilfs_btree_alloc_path(btree); | 1955 | path = nilfs_btree_alloc_path(); |
| 1990 | if (path == NULL) | 1956 | if (path == NULL) |
| 1991 | return -ENOMEM; | 1957 | return -ENOMEM; |
| 1992 | nilfs_btree_init_path(btree, path); | 1958 | nilfs_btree_init_path(path); |
| 1993 | 1959 | ||
| 1994 | if (buffer_nilfs_node(bh)) { | 1960 | if (buffer_nilfs_node(bh)) { |
| 1995 | node = (struct nilfs_btree_node *)bh->b_data; | 1961 | node = (struct nilfs_btree_node *)bh->b_data; |
| 1996 | key = nilfs_btree_node_get_key(btree, node, 0); | 1962 | key = nilfs_btree_node_get_key(node, 0); |
| 1997 | level = nilfs_btree_node_get_level(btree, node); | 1963 | level = nilfs_btree_node_get_level(node); |
| 1998 | } else { | 1964 | } else { |
| 1999 | key = nilfs_bmap_data_get_key(bmap, bh); | 1965 | key = nilfs_bmap_data_get_key(bmap, bh); |
| 2000 | level = NILFS_BTREE_LEVEL_DATA; | 1966 | level = NILFS_BTREE_LEVEL_DATA; |
| @@ -2013,8 +1979,8 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap, | |||
| 2013 | nilfs_btree_propagate_p(btree, path, level, bh); | 1979 | nilfs_btree_propagate_p(btree, path, level, bh); |
| 2014 | 1980 | ||
| 2015 | out: | 1981 | out: |
| 2016 | nilfs_btree_clear_path(btree, path); | 1982 | nilfs_btree_release_path(path); |
| 2017 | nilfs_btree_free_path(btree, path); | 1983 | nilfs_btree_free_path(path); |
| 2018 | 1984 | ||
| 2019 | return ret; | 1985 | return ret; |
| 2020 | } | 1986 | } |
| @@ -2022,7 +1988,7 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap, | |||
| 2022 | static int nilfs_btree_propagate_gc(const struct nilfs_bmap *bmap, | 1988 | static int nilfs_btree_propagate_gc(const struct nilfs_bmap *bmap, |
| 2023 | struct buffer_head *bh) | 1989 | struct buffer_head *bh) |
| 2024 | { | 1990 | { |
| 2025 | return nilfs_bmap_mark_dirty(bmap, bh->b_blocknr); | 1991 | return nilfs_dat_mark_dirty(nilfs_bmap_get_dat(bmap), bh->b_blocknr); |
| 2026 | } | 1992 | } |
| 2027 | 1993 | ||
| 2028 | static void nilfs_btree_add_dirty_buffer(struct nilfs_btree *btree, | 1994 | static void nilfs_btree_add_dirty_buffer(struct nilfs_btree *btree, |
| @@ -2037,12 +2003,12 @@ static void nilfs_btree_add_dirty_buffer(struct nilfs_btree *btree, | |||
| 2037 | 2003 | ||
| 2038 | get_bh(bh); | 2004 | get_bh(bh); |
| 2039 | node = (struct nilfs_btree_node *)bh->b_data; | 2005 | node = (struct nilfs_btree_node *)bh->b_data; |
| 2040 | key = nilfs_btree_node_get_key(btree, node, 0); | 2006 | key = nilfs_btree_node_get_key(node, 0); |
| 2041 | level = nilfs_btree_node_get_level(btree, node); | 2007 | level = nilfs_btree_node_get_level(node); |
| 2042 | list_for_each(head, &lists[level]) { | 2008 | list_for_each(head, &lists[level]) { |
| 2043 | cbh = list_entry(head, struct buffer_head, b_assoc_buffers); | 2009 | cbh = list_entry(head, struct buffer_head, b_assoc_buffers); |
| 2044 | cnode = (struct nilfs_btree_node *)cbh->b_data; | 2010 | cnode = (struct nilfs_btree_node *)cbh->b_data; |
| 2045 | ckey = nilfs_btree_node_get_key(btree, cnode, 0); | 2011 | ckey = nilfs_btree_node_get_key(cnode, 0); |
| 2046 | if (key < ckey) | 2012 | if (key < ckey) |
| 2047 | break; | 2013 | break; |
| 2048 | } | 2014 | } |
| @@ -2120,8 +2086,7 @@ static int nilfs_btree_assign_p(struct nilfs_btree *btree, | |||
| 2120 | nilfs_btree_node_set_ptr(btree, parent, | 2086 | nilfs_btree_node_set_ptr(btree, parent, |
| 2121 | path[level + 1].bp_index, blocknr); | 2087 | path[level + 1].bp_index, blocknr); |
| 2122 | 2088 | ||
| 2123 | key = nilfs_btree_node_get_key(btree, parent, | 2089 | key = nilfs_btree_node_get_key(parent, path[level + 1].bp_index); |
| 2124 | path[level + 1].bp_index); | ||
| 2125 | /* on-disk format */ | 2090 | /* on-disk format */ |
| 2126 | binfo->bi_dat.bi_blkoff = nilfs_bmap_key_to_dkey(key); | 2091 | binfo->bi_dat.bi_blkoff = nilfs_bmap_key_to_dkey(key); |
| 2127 | binfo->bi_dat.bi_level = level; | 2092 | binfo->bi_dat.bi_level = level; |
| @@ -2137,6 +2102,7 @@ static int nilfs_btree_assign_v(struct nilfs_btree *btree, | |||
| 2137 | union nilfs_binfo *binfo) | 2102 | union nilfs_binfo *binfo) |
| 2138 | { | 2103 | { |
| 2139 | struct nilfs_btree_node *parent; | 2104 | struct nilfs_btree_node *parent; |
| 2105 | struct inode *dat = nilfs_bmap_get_dat(&btree->bt_bmap); | ||
| 2140 | __u64 key; | 2106 | __u64 key; |
| 2141 | __u64 ptr; | 2107 | __u64 ptr; |
| 2142 | union nilfs_bmap_ptr_req req; | 2108 | union nilfs_bmap_ptr_req req; |
| @@ -2146,12 +2112,12 @@ static int nilfs_btree_assign_v(struct nilfs_btree *btree, | |||
| 2146 | ptr = nilfs_btree_node_get_ptr(btree, parent, | 2112 | ptr = nilfs_btree_node_get_ptr(btree, parent, |
| 2147 | path[level + 1].bp_index); | 2113 | path[level + 1].bp_index); |
| 2148 | req.bpr_ptr = ptr; | 2114 | req.bpr_ptr = ptr; |
| 2149 | ret = nilfs_bmap_start_v(&btree->bt_bmap, &req, blocknr); | 2115 | ret = nilfs_dat_prepare_start(dat, &req.bpr_req); |
| 2150 | if (unlikely(ret < 0)) | 2116 | if (ret < 0) |
| 2151 | return ret; | 2117 | return ret; |
| 2118 | nilfs_dat_commit_start(dat, &req.bpr_req, blocknr); | ||
| 2152 | 2119 | ||
| 2153 | key = nilfs_btree_node_get_key(btree, parent, | 2120 | key = nilfs_btree_node_get_key(parent, path[level + 1].bp_index); |
| 2154 | path[level + 1].bp_index); | ||
| 2155 | /* on-disk format */ | 2121 | /* on-disk format */ |
| 2156 | binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr); | 2122 | binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr); |
| 2157 | binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key); | 2123 | binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key); |
| @@ -2171,15 +2137,15 @@ static int nilfs_btree_assign(struct nilfs_bmap *bmap, | |||
| 2171 | int level, ret; | 2137 | int level, ret; |
| 2172 | 2138 | ||
| 2173 | btree = (struct nilfs_btree *)bmap; | 2139 | btree = (struct nilfs_btree *)bmap; |
| 2174 | path = nilfs_btree_alloc_path(btree); | 2140 | path = nilfs_btree_alloc_path(); |
| 2175 | if (path == NULL) | 2141 | if (path == NULL) |
| 2176 | return -ENOMEM; | 2142 | return -ENOMEM; |
| 2177 | nilfs_btree_init_path(btree, path); | 2143 | nilfs_btree_init_path(path); |
| 2178 | 2144 | ||
| 2179 | if (buffer_nilfs_node(*bh)) { | 2145 | if (buffer_nilfs_node(*bh)) { |
| 2180 | node = (struct nilfs_btree_node *)(*bh)->b_data; | 2146 | node = (struct nilfs_btree_node *)(*bh)->b_data; |
| 2181 | key = nilfs_btree_node_get_key(btree, node, 0); | 2147 | key = nilfs_btree_node_get_key(node, 0); |
| 2182 | level = nilfs_btree_node_get_level(btree, node); | 2148 | level = nilfs_btree_node_get_level(node); |
| 2183 | } else { | 2149 | } else { |
| 2184 | key = nilfs_bmap_data_get_key(bmap, *bh); | 2150 | key = nilfs_bmap_data_get_key(bmap, *bh); |
| 2185 | level = NILFS_BTREE_LEVEL_DATA; | 2151 | level = NILFS_BTREE_LEVEL_DATA; |
| @@ -2196,8 +2162,8 @@ static int nilfs_btree_assign(struct nilfs_bmap *bmap, | |||
| 2196 | nilfs_btree_assign_p(btree, path, level, bh, blocknr, binfo); | 2162 | nilfs_btree_assign_p(btree, path, level, bh, blocknr, binfo); |
| 2197 | 2163 | ||
| 2198 | out: | 2164 | out: |
| 2199 | nilfs_btree_clear_path(btree, path); | 2165 | nilfs_btree_release_path(path); |
| 2200 | nilfs_btree_free_path(btree, path); | 2166 | nilfs_btree_free_path(path); |
| 2201 | 2167 | ||
| 2202 | return ret; | 2168 | return ret; |
| 2203 | } | 2169 | } |
| @@ -2207,19 +2173,18 @@ static int nilfs_btree_assign_gc(struct nilfs_bmap *bmap, | |||
| 2207 | sector_t blocknr, | 2173 | sector_t blocknr, |
| 2208 | union nilfs_binfo *binfo) | 2174 | union nilfs_binfo *binfo) |
| 2209 | { | 2175 | { |
| 2210 | struct nilfs_btree *btree; | ||
| 2211 | struct nilfs_btree_node *node; | 2176 | struct nilfs_btree_node *node; |
| 2212 | __u64 key; | 2177 | __u64 key; |
| 2213 | int ret; | 2178 | int ret; |
| 2214 | 2179 | ||
| 2215 | btree = (struct nilfs_btree *)bmap; | 2180 | ret = nilfs_dat_move(nilfs_bmap_get_dat(bmap), (*bh)->b_blocknr, |
| 2216 | ret = nilfs_bmap_move_v(bmap, (*bh)->b_blocknr, blocknr); | 2181 | blocknr); |
| 2217 | if (ret < 0) | 2182 | if (ret < 0) |
| 2218 | return ret; | 2183 | return ret; |
| 2219 | 2184 | ||
| 2220 | if (buffer_nilfs_node(*bh)) { | 2185 | if (buffer_nilfs_node(*bh)) { |
| 2221 | node = (struct nilfs_btree_node *)(*bh)->b_data; | 2186 | node = (struct nilfs_btree_node *)(*bh)->b_data; |
| 2222 | key = nilfs_btree_node_get_key(btree, node, 0); | 2187 | key = nilfs_btree_node_get_key(node, 0); |
| 2223 | } else | 2188 | } else |
| 2224 | key = nilfs_bmap_data_get_key(bmap, *bh); | 2189 | key = nilfs_bmap_data_get_key(bmap, *bh); |
| 2225 | 2190 | ||
| @@ -2239,10 +2204,10 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level) | |||
| 2239 | int ret; | 2204 | int ret; |
| 2240 | 2205 | ||
| 2241 | btree = (struct nilfs_btree *)bmap; | 2206 | btree = (struct nilfs_btree *)bmap; |
| 2242 | path = nilfs_btree_alloc_path(btree); | 2207 | path = nilfs_btree_alloc_path(); |
| 2243 | if (path == NULL) | 2208 | if (path == NULL) |
| 2244 | return -ENOMEM; | 2209 | return -ENOMEM; |
| 2245 | nilfs_btree_init_path(btree, path); | 2210 | nilfs_btree_init_path(path); |
| 2246 | 2211 | ||
| 2247 | ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level + 1); | 2212 | ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level + 1); |
| 2248 | if (ret < 0) { | 2213 | if (ret < 0) { |
| @@ -2262,8 +2227,8 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level) | |||
| 2262 | nilfs_bmap_set_dirty(&btree->bt_bmap); | 2227 | nilfs_bmap_set_dirty(&btree->bt_bmap); |
| 2263 | 2228 | ||
| 2264 | out: | 2229 | out: |
| 2265 | nilfs_btree_clear_path(btree, path); | 2230 | nilfs_btree_release_path(path); |
| 2266 | nilfs_btree_free_path(btree, path); | 2231 | nilfs_btree_free_path(path); |
| 2267 | return ret; | 2232 | return ret; |
| 2268 | } | 2233 | } |
| 2269 | 2234 | ||
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index aec942cf79e..1c6cfb59128 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c | |||
| @@ -815,8 +815,10 @@ int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno) | |||
| 815 | void *kaddr; | 815 | void *kaddr; |
| 816 | int ret; | 816 | int ret; |
| 817 | 817 | ||
| 818 | if (cno == 0) | 818 | /* CP number is invalid if it's zero or larger than the |
| 819 | return -ENOENT; /* checkpoint number 0 is invalid */ | 819 | largest exist one.*/ |
| 820 | if (cno == 0 || cno >= nilfs_mdt_cno(cpfile)) | ||
| 821 | return -ENOENT; | ||
| 820 | down_read(&NILFS_MDT(cpfile)->mi_sem); | 822 | down_read(&NILFS_MDT(cpfile)->mi_sem); |
| 821 | 823 | ||
| 822 | ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh); | 824 | ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh); |
| @@ -824,7 +826,10 @@ int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno) | |||
| 824 | goto out; | 826 | goto out; |
| 825 | kaddr = kmap_atomic(bh->b_page, KM_USER0); | 827 | kaddr = kmap_atomic(bh->b_page, KM_USER0); |
| 826 | cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); | 828 | cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); |
| 827 | ret = nilfs_checkpoint_snapshot(cp); | 829 | if (nilfs_checkpoint_invalid(cp)) |
| 830 | ret = -ENOENT; | ||
| 831 | else | ||
| 832 | ret = nilfs_checkpoint_snapshot(cp); | ||
| 828 | kunmap_atomic(kaddr, KM_USER0); | 833 | kunmap_atomic(kaddr, KM_USER0); |
| 829 | brelse(bh); | 834 | brelse(bh); |
| 830 | 835 | ||
diff --git a/fs/nilfs2/cpfile.h b/fs/nilfs2/cpfile.h index 788a4595019..debea896e70 100644 --- a/fs/nilfs2/cpfile.h +++ b/fs/nilfs2/cpfile.h | |||
| @@ -27,8 +27,6 @@ | |||
| 27 | #include <linux/buffer_head.h> | 27 | #include <linux/buffer_head.h> |
| 28 | #include <linux/nilfs2_fs.h> | 28 | #include <linux/nilfs2_fs.h> |
| 29 | 29 | ||
| 30 | #define NILFS_CPFILE_GFP NILFS_MDT_GFP | ||
| 31 | |||
| 32 | 30 | ||
| 33 | int nilfs_cpfile_get_checkpoint(struct inode *, __u64, int, | 31 | int nilfs_cpfile_get_checkpoint(struct inode *, __u64, int, |
| 34 | struct nilfs_checkpoint **, | 32 | struct nilfs_checkpoint **, |
diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index 8927ca27e6f..1ff8e15bd36 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c | |||
| @@ -109,12 +109,6 @@ void nilfs_dat_commit_free(struct inode *dat, struct nilfs_palloc_req *req) | |||
| 109 | nilfs_palloc_commit_free_entry(dat, req); | 109 | nilfs_palloc_commit_free_entry(dat, req); |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | void nilfs_dat_abort_free(struct inode *dat, struct nilfs_palloc_req *req) | ||
| 113 | { | ||
| 114 | nilfs_dat_abort_entry(dat, req); | ||
| 115 | nilfs_palloc_abort_free_entry(dat, req); | ||
| 116 | } | ||
| 117 | |||
| 118 | int nilfs_dat_prepare_start(struct inode *dat, struct nilfs_palloc_req *req) | 112 | int nilfs_dat_prepare_start(struct inode *dat, struct nilfs_palloc_req *req) |
| 119 | { | 113 | { |
| 120 | int ret; | 114 | int ret; |
| @@ -140,11 +134,6 @@ void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req, | |||
| 140 | nilfs_dat_commit_entry(dat, req); | 134 | nilfs_dat_commit_entry(dat, req); |
| 141 | } | 135 | } |
| 142 | 136 | ||
| 143 | void nilfs_dat_abort_start(struct inode *dat, struct nilfs_palloc_req *req) | ||
| 144 | { | ||
| 145 | nilfs_dat_abort_entry(dat, req); | ||
| 146 | } | ||
| 147 | |||
| 148 | int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req) | 137 | int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req) |
| 149 | { | 138 | { |
| 150 | struct nilfs_dat_entry *entry; | 139 | struct nilfs_dat_entry *entry; |
| @@ -222,6 +211,37 @@ void nilfs_dat_abort_end(struct inode *dat, struct nilfs_palloc_req *req) | |||
| 222 | nilfs_dat_abort_entry(dat, req); | 211 | nilfs_dat_abort_entry(dat, req); |
| 223 | } | 212 | } |
| 224 | 213 | ||
| 214 | int nilfs_dat_prepare_update(struct inode *dat, | ||
| 215 | struct nilfs_palloc_req *oldreq, | ||
| 216 | struct nilfs_palloc_req *newreq) | ||
| 217 | { | ||
| 218 | int ret; | ||
| 219 | |||
| 220 | ret = nilfs_dat_prepare_end(dat, oldreq); | ||
| 221 | if (!ret) { | ||
| 222 | ret = nilfs_dat_prepare_alloc(dat, newreq); | ||
| 223 | if (ret < 0) | ||
| 224 | nilfs_dat_abort_end(dat, oldreq); | ||
| 225 | } | ||
| 226 | return ret; | ||
| 227 | } | ||
| 228 | |||
| 229 | void nilfs_dat_commit_update(struct inode *dat, | ||
| 230 | struct nilfs_palloc_req *oldreq, | ||
| 231 | struct nilfs_palloc_req *newreq, int dead) | ||
| 232 | { | ||
| 233 | nilfs_dat_commit_end(dat, oldreq, dead); | ||
| 234 | nilfs_dat_commit_alloc(dat, newreq); | ||
| 235 | } | ||
| 236 | |||
| 237 | void nilfs_dat_abort_update(struct inode *dat, | ||
| 238 | struct nilfs_palloc_req *oldreq, | ||
| 239 | struct nilfs_palloc_req *newreq) | ||
| 240 | { | ||
| 241 | nilfs_dat_abort_end(dat, oldreq); | ||
| 242 | nilfs_dat_abort_alloc(dat, newreq); | ||
| 243 | } | ||
| 244 | |||
| 225 | /** | 245 | /** |
| 226 | * nilfs_dat_mark_dirty - | 246 | * nilfs_dat_mark_dirty - |
| 227 | * @dat: DAT file inode | 247 | * @dat: DAT file inode |
diff --git a/fs/nilfs2/dat.h b/fs/nilfs2/dat.h index d328b81eead..406070d3ff4 100644 --- a/fs/nilfs2/dat.h +++ b/fs/nilfs2/dat.h | |||
| @@ -27,7 +27,6 @@ | |||
| 27 | #include <linux/buffer_head.h> | 27 | #include <linux/buffer_head.h> |
| 28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
| 29 | 29 | ||
| 30 | #define NILFS_DAT_GFP NILFS_MDT_GFP | ||
| 31 | 30 | ||
| 32 | struct nilfs_palloc_req; | 31 | struct nilfs_palloc_req; |
| 33 | 32 | ||
| @@ -39,10 +38,15 @@ void nilfs_dat_abort_alloc(struct inode *, struct nilfs_palloc_req *); | |||
| 39 | int nilfs_dat_prepare_start(struct inode *, struct nilfs_palloc_req *); | 38 | int nilfs_dat_prepare_start(struct inode *, struct nilfs_palloc_req *); |
| 40 | void nilfs_dat_commit_start(struct inode *, struct nilfs_palloc_req *, | 39 | void nilfs_dat_commit_start(struct inode *, struct nilfs_palloc_req *, |
| 41 | sector_t); | 40 | sector_t); |
| 42 | void nilfs_dat_abort_start(struct inode *, struct nilfs_palloc_req *); | ||
| 43 | int nilfs_dat_prepare_end(struct inode *, struct nilfs_palloc_req *); | 41 | int nilfs_dat_prepare_end(struct inode *, struct nilfs_palloc_req *); |
| 44 | void nilfs_dat_commit_end(struct inode *, struct nilfs_palloc_req *, int); | 42 | void nilfs_dat_commit_end(struct inode *, struct nilfs_palloc_req *, int); |
| 45 | void nilfs_dat_abort_end(struct inode *, struct nilfs_palloc_req *); | 43 | void nilfs_dat_abort_end(struct inode *, struct nilfs_palloc_req *); |
| 44 | int nilfs_dat_prepare_update(struct inode *, struct nilfs_palloc_req *, | ||
| 45 | struct nilfs_palloc_req *); | ||
| 46 | void nilfs_dat_commit_update(struct inode *, struct nilfs_palloc_req *, | ||
| 47 | struct nilfs_palloc_req *, int); | ||
| 48 | void nilfs_dat_abort_update(struct inode *, struct nilfs_palloc_req *, | ||
| 49 | struct nilfs_palloc_req *); | ||
| 46 | 50 | ||
| 47 | int nilfs_dat_mark_dirty(struct inode *, __u64); | 51 | int nilfs_dat_mark_dirty(struct inode *, __u64); |
| 48 | int nilfs_dat_freev(struct inode *, __u64 *, size_t); | 52 | int nilfs_dat_freev(struct inode *, __u64 *, size_t); |
diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c index 342d9765df8..d369ac71827 100644 --- a/fs/nilfs2/direct.c +++ b/fs/nilfs2/direct.c | |||
| @@ -125,106 +125,64 @@ static void nilfs_direct_set_target_v(struct nilfs_direct *direct, | |||
| 125 | direct->d_bmap.b_last_allocated_ptr = ptr; | 125 | direct->d_bmap.b_last_allocated_ptr = ptr; |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | static int nilfs_direct_prepare_insert(struct nilfs_direct *direct, | ||
| 129 | __u64 key, | ||
| 130 | union nilfs_bmap_ptr_req *req, | ||
| 131 | struct nilfs_bmap_stats *stats) | ||
| 132 | { | ||
| 133 | int ret; | ||
| 134 | |||
| 135 | if (NILFS_BMAP_USE_VBN(&direct->d_bmap)) | ||
| 136 | req->bpr_ptr = nilfs_direct_find_target_v(direct, key); | ||
| 137 | ret = nilfs_bmap_prepare_alloc_ptr(&direct->d_bmap, req); | ||
| 138 | if (ret < 0) | ||
| 139 | return ret; | ||
| 140 | |||
| 141 | stats->bs_nblocks = 1; | ||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | static void nilfs_direct_commit_insert(struct nilfs_direct *direct, | ||
| 146 | union nilfs_bmap_ptr_req *req, | ||
| 147 | __u64 key, __u64 ptr) | ||
| 148 | { | ||
| 149 | struct buffer_head *bh; | ||
| 150 | |||
| 151 | /* ptr must be a pointer to a buffer head. */ | ||
| 152 | bh = (struct buffer_head *)((unsigned long)ptr); | ||
| 153 | set_buffer_nilfs_volatile(bh); | ||
| 154 | |||
| 155 | nilfs_bmap_commit_alloc_ptr(&direct->d_bmap, req); | ||
| 156 | nilfs_direct_set_ptr(direct, key, req->bpr_ptr); | ||
| 157 | |||
| 158 | if (!nilfs_bmap_dirty(&direct->d_bmap)) | ||
| 159 | nilfs_bmap_set_dirty(&direct->d_bmap); | ||
| 160 | |||
| 161 | if (NILFS_BMAP_USE_VBN(&direct->d_bmap)) | ||
| 162 | nilfs_direct_set_target_v(direct, key, req->bpr_ptr); | ||
| 163 | } | ||
| 164 | |||
| 165 | static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) | 128 | static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) |
| 166 | { | 129 | { |
| 167 | struct nilfs_direct *direct; | 130 | struct nilfs_direct *direct = (struct nilfs_direct *)bmap; |
| 168 | union nilfs_bmap_ptr_req req; | 131 | union nilfs_bmap_ptr_req req; |
| 169 | struct nilfs_bmap_stats stats; | 132 | struct inode *dat = NULL; |
| 133 | struct buffer_head *bh; | ||
| 170 | int ret; | 134 | int ret; |
| 171 | 135 | ||
| 172 | direct = (struct nilfs_direct *)bmap; | ||
| 173 | if (key > NILFS_DIRECT_KEY_MAX) | 136 | if (key > NILFS_DIRECT_KEY_MAX) |
| 174 | return -ENOENT; | 137 | return -ENOENT; |
| 175 | if (nilfs_direct_get_ptr(direct, key) != NILFS_BMAP_INVALID_PTR) | 138 | if (nilfs_direct_get_ptr(direct, key) != NILFS_BMAP_INVALID_PTR) |
| 176 | return -EEXIST; | 139 | return -EEXIST; |
| 177 | 140 | ||
| 178 | ret = nilfs_direct_prepare_insert(direct, key, &req, &stats); | 141 | if (NILFS_BMAP_USE_VBN(bmap)) { |
| 179 | if (ret < 0) | 142 | req.bpr_ptr = nilfs_direct_find_target_v(direct, key); |
| 180 | return ret; | 143 | dat = nilfs_bmap_get_dat(bmap); |
| 181 | nilfs_direct_commit_insert(direct, &req, key, ptr); | 144 | } |
| 182 | nilfs_bmap_add_blocks(bmap, stats.bs_nblocks); | 145 | ret = nilfs_bmap_prepare_alloc_ptr(bmap, &req, dat); |
| 146 | if (!ret) { | ||
| 147 | /* ptr must be a pointer to a buffer head. */ | ||
| 148 | bh = (struct buffer_head *)((unsigned long)ptr); | ||
| 149 | set_buffer_nilfs_volatile(bh); | ||
| 183 | 150 | ||
| 184 | return 0; | 151 | nilfs_bmap_commit_alloc_ptr(bmap, &req, dat); |
| 185 | } | 152 | nilfs_direct_set_ptr(direct, key, req.bpr_ptr); |
| 186 | 153 | ||
| 187 | static int nilfs_direct_prepare_delete(struct nilfs_direct *direct, | 154 | if (!nilfs_bmap_dirty(bmap)) |
| 188 | union nilfs_bmap_ptr_req *req, | 155 | nilfs_bmap_set_dirty(bmap); |
| 189 | __u64 key, | ||
| 190 | struct nilfs_bmap_stats *stats) | ||
| 191 | { | ||
| 192 | int ret; | ||
| 193 | 156 | ||
| 194 | req->bpr_ptr = nilfs_direct_get_ptr(direct, key); | 157 | if (NILFS_BMAP_USE_VBN(bmap)) |
| 195 | ret = nilfs_bmap_prepare_end_ptr(&direct->d_bmap, req); | 158 | nilfs_direct_set_target_v(direct, key, req.bpr_ptr); |
| 196 | if (!ret) | ||
| 197 | stats->bs_nblocks = 1; | ||
| 198 | return ret; | ||
| 199 | } | ||
| 200 | 159 | ||
| 201 | static void nilfs_direct_commit_delete(struct nilfs_direct *direct, | 160 | nilfs_bmap_add_blocks(bmap, 1); |
| 202 | union nilfs_bmap_ptr_req *req, | 161 | } |
| 203 | __u64 key) | 162 | return ret; |
| 204 | { | ||
| 205 | nilfs_bmap_commit_end_ptr(&direct->d_bmap, req); | ||
| 206 | nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR); | ||
| 207 | } | 163 | } |
| 208 | 164 | ||
| 209 | static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key) | 165 | static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key) |
| 210 | { | 166 | { |
| 211 | struct nilfs_direct *direct; | 167 | struct nilfs_direct *direct = (struct nilfs_direct *)bmap; |
| 212 | union nilfs_bmap_ptr_req req; | 168 | union nilfs_bmap_ptr_req req; |
| 213 | struct nilfs_bmap_stats stats; | 169 | struct inode *dat; |
| 214 | int ret; | 170 | int ret; |
| 215 | 171 | ||
| 216 | direct = (struct nilfs_direct *)bmap; | 172 | if (key > NILFS_DIRECT_KEY_MAX || |
| 217 | if ((key > NILFS_DIRECT_KEY_MAX) || | ||
| 218 | nilfs_direct_get_ptr(direct, key) == NILFS_BMAP_INVALID_PTR) | 173 | nilfs_direct_get_ptr(direct, key) == NILFS_BMAP_INVALID_PTR) |
| 219 | return -ENOENT; | 174 | return -ENOENT; |
| 220 | 175 | ||
| 221 | ret = nilfs_direct_prepare_delete(direct, &req, key, &stats); | 176 | dat = NILFS_BMAP_USE_VBN(bmap) ? nilfs_bmap_get_dat(bmap) : NULL; |
| 222 | if (ret < 0) | 177 | req.bpr_ptr = nilfs_direct_get_ptr(direct, key); |
| 223 | return ret; | ||
| 224 | nilfs_direct_commit_delete(direct, &req, key); | ||
| 225 | nilfs_bmap_sub_blocks(bmap, stats.bs_nblocks); | ||
| 226 | 178 | ||
| 227 | return 0; | 179 | ret = nilfs_bmap_prepare_end_ptr(bmap, &req, dat); |
| 180 | if (!ret) { | ||
| 181 | nilfs_bmap_commit_end_ptr(bmap, &req, dat); | ||
| 182 | nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR); | ||
| 183 | nilfs_bmap_sub_blocks(bmap, 1); | ||
| 184 | } | ||
| 185 | return ret; | ||
| 228 | } | 186 | } |
| 229 | 187 | ||
| 230 | static int nilfs_direct_last_key(const struct nilfs_bmap *bmap, __u64 *keyp) | 188 | static int nilfs_direct_last_key(const struct nilfs_bmap *bmap, __u64 *keyp) |
| @@ -310,59 +268,56 @@ int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, | |||
| 310 | return 0; | 268 | return 0; |
| 311 | } | 269 | } |
| 312 | 270 | ||
| 313 | static int nilfs_direct_propagate_v(struct nilfs_direct *direct, | 271 | static int nilfs_direct_propagate(const struct nilfs_bmap *bmap, |
| 314 | struct buffer_head *bh) | 272 | struct buffer_head *bh) |
| 315 | { | 273 | { |
| 316 | union nilfs_bmap_ptr_req oldreq, newreq; | 274 | struct nilfs_direct *direct = (struct nilfs_direct *)bmap; |
| 275 | struct nilfs_palloc_req oldreq, newreq; | ||
| 276 | struct inode *dat; | ||
| 317 | __u64 key; | 277 | __u64 key; |
| 318 | __u64 ptr; | 278 | __u64 ptr; |
| 319 | int ret; | 279 | int ret; |
| 320 | 280 | ||
| 321 | key = nilfs_bmap_data_get_key(&direct->d_bmap, bh); | 281 | if (!NILFS_BMAP_USE_VBN(bmap)) |
| 282 | return 0; | ||
| 283 | |||
| 284 | dat = nilfs_bmap_get_dat(bmap); | ||
| 285 | key = nilfs_bmap_data_get_key(bmap, bh); | ||
| 322 | ptr = nilfs_direct_get_ptr(direct, key); | 286 | ptr = nilfs_direct_get_ptr(direct, key); |
| 323 | if (!buffer_nilfs_volatile(bh)) { | 287 | if (!buffer_nilfs_volatile(bh)) { |
| 324 | oldreq.bpr_ptr = ptr; | 288 | oldreq.pr_entry_nr = ptr; |
| 325 | newreq.bpr_ptr = ptr; | 289 | newreq.pr_entry_nr = ptr; |
| 326 | ret = nilfs_bmap_prepare_update_v(&direct->d_bmap, &oldreq, | 290 | ret = nilfs_dat_prepare_update(dat, &oldreq, &newreq); |
| 327 | &newreq); | ||
| 328 | if (ret < 0) | 291 | if (ret < 0) |
| 329 | return ret; | 292 | return ret; |
| 330 | nilfs_bmap_commit_update_v(&direct->d_bmap, &oldreq, &newreq); | 293 | nilfs_dat_commit_update(dat, &oldreq, &newreq, |
| 294 | bmap->b_ptr_type == NILFS_BMAP_PTR_VS); | ||
| 331 | set_buffer_nilfs_volatile(bh); | 295 | set_buffer_nilfs_volatile(bh); |
| 332 | nilfs_direct_set_ptr(direct, key, newreq.bpr_ptr); | 296 | nilfs_direct_set_ptr(direct, key, newreq.pr_entry_nr); |
| 333 | } else | 297 | } else |
| 334 | ret = nilfs_bmap_mark_dirty(&direct->d_bmap, ptr); | 298 | ret = nilfs_dat_mark_dirty(dat, ptr); |
| 335 | 299 | ||
| 336 | return ret; | 300 | return ret; |
| 337 | } | 301 | } |
| 338 | 302 | ||
| 339 | static int nilfs_direct_propagate(const struct nilfs_bmap *bmap, | ||
| 340 | struct buffer_head *bh) | ||
| 341 | { | ||
| 342 | struct nilfs_direct *direct = (struct nilfs_direct *)bmap; | ||
| 343 | |||
| 344 | return NILFS_BMAP_USE_VBN(bmap) ? | ||
| 345 | nilfs_direct_propagate_v(direct, bh) : 0; | ||
| 346 | } | ||
| 347 | |||
| 348 | static int nilfs_direct_assign_v(struct nilfs_direct *direct, | 303 | static int nilfs_direct_assign_v(struct nilfs_direct *direct, |
| 349 | __u64 key, __u64 ptr, | 304 | __u64 key, __u64 ptr, |
| 350 | struct buffer_head **bh, | 305 | struct buffer_head **bh, |
| 351 | sector_t blocknr, | 306 | sector_t blocknr, |
| 352 | union nilfs_binfo *binfo) | 307 | union nilfs_binfo *binfo) |
| 353 | { | 308 | { |
| 309 | struct inode *dat = nilfs_bmap_get_dat(&direct->d_bmap); | ||
| 354 | union nilfs_bmap_ptr_req req; | 310 | union nilfs_bmap_ptr_req req; |
| 355 | int ret; | 311 | int ret; |
| 356 | 312 | ||
| 357 | req.bpr_ptr = ptr; | 313 | req.bpr_ptr = ptr; |
| 358 | ret = nilfs_bmap_start_v(&direct->d_bmap, &req, blocknr); | 314 | ret = nilfs_dat_prepare_start(dat, &req.bpr_req); |
| 359 | if (unlikely(ret < 0)) | 315 | if (!ret) { |
| 360 | return ret; | 316 | nilfs_dat_commit_start(dat, &req.bpr_req, blocknr); |
| 361 | 317 | binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr); | |
| 362 | binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr); | 318 | binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key); |
| 363 | binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key); | 319 | } |
| 364 | 320 | return ret; | |
| 365 | return 0; | ||
| 366 | } | 321 | } |
| 367 | 322 | ||
| 368 | static int nilfs_direct_assign_p(struct nilfs_direct *direct, | 323 | static int nilfs_direct_assign_p(struct nilfs_direct *direct, |
diff --git a/fs/nilfs2/ifile.h b/fs/nilfs2/ifile.h index 5d30a35679b..ecc3ba76db4 100644 --- a/fs/nilfs2/ifile.h +++ b/fs/nilfs2/ifile.h | |||
| @@ -31,7 +31,6 @@ | |||
| 31 | #include "mdt.h" | 31 | #include "mdt.h" |
| 32 | #include "alloc.h" | 32 | #include "alloc.h" |
| 33 | 33 | ||
| 34 | #define NILFS_IFILE_GFP NILFS_MDT_GFP | ||
| 35 | 34 | ||
| 36 | static inline struct nilfs_inode * | 35 | static inline struct nilfs_inode * |
| 37 | nilfs_ifile_map_inode(struct inode *ifile, ino_t ino, struct buffer_head *ibh) | 36 | nilfs_ifile_map_inode(struct inode *ifile, ino_t ino, struct buffer_head *ibh) |
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index fe9d8f2a13f..807e584b163 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c | |||
| @@ -430,7 +430,8 @@ static int __nilfs_read_inode(struct super_block *sb, unsigned long ino, | |||
| 430 | 430 | ||
| 431 | raw_inode = nilfs_ifile_map_inode(sbi->s_ifile, ino, bh); | 431 | raw_inode = nilfs_ifile_map_inode(sbi->s_ifile, ino, bh); |
| 432 | 432 | ||
| 433 | if (nilfs_read_inode_common(inode, raw_inode)) | 433 | err = nilfs_read_inode_common(inode, raw_inode); |
| 434 | if (err) | ||
| 434 | goto failed_unmap; | 435 | goto failed_unmap; |
| 435 | 436 | ||
| 436 | if (S_ISREG(inode->i_mode)) { | 437 | if (S_ISREG(inode->i_mode)) { |
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 6ea5f872e2d..6572ea4bc4d 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
| @@ -442,12 +442,6 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, | |||
| 442 | const char *msg; | 442 | const char *msg; |
| 443 | int ret; | 443 | int ret; |
| 444 | 444 | ||
| 445 | ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], kbufs[0]); | ||
| 446 | if (ret < 0) { | ||
| 447 | msg = "cannot read source blocks"; | ||
| 448 | goto failed; | ||
| 449 | } | ||
| 450 | |||
| 451 | ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]); | 445 | ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]); |
| 452 | if (ret < 0) { | 446 | if (ret < 0) { |
| 453 | /* | 447 | /* |
| @@ -548,7 +542,25 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, | |||
| 548 | } | 542 | } |
| 549 | } | 543 | } |
| 550 | 544 | ||
| 551 | ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); | 545 | /* |
| 546 | * nilfs_ioctl_move_blocks() will call nilfs_gc_iget(), | ||
| 547 | * which will operates an inode list without blocking. | ||
| 548 | * To protect the list from concurrent operations, | ||
| 549 | * nilfs_ioctl_move_blocks should be atomic operation. | ||
| 550 | */ | ||
| 551 | if (test_and_set_bit(THE_NILFS_GC_RUNNING, &nilfs->ns_flags)) { | ||
| 552 | ret = -EBUSY; | ||
| 553 | goto out_free; | ||
| 554 | } | ||
| 555 | |||
| 556 | ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], kbufs[0]); | ||
| 557 | if (ret < 0) | ||
| 558 | printk(KERN_ERR "NILFS: GC failed during preparation: " | ||
| 559 | "cannot read source blocks: err=%d\n", ret); | ||
| 560 | else | ||
| 561 | ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); | ||
| 562 | |||
| 563 | clear_nilfs_gc_running(nilfs); | ||
| 552 | 564 | ||
| 553 | out_free: | 565 | out_free: |
| 554 | while (--n >= 0) | 566 | while (--n >= 0) |
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 2dfd47714ae..156bf6091a9 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c | |||
| @@ -103,15 +103,12 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block, | |||
| 103 | goto failed_unlock; | 103 | goto failed_unlock; |
| 104 | 104 | ||
| 105 | err = -EEXIST; | 105 | err = -EEXIST; |
| 106 | if (buffer_uptodate(bh) || buffer_mapped(bh)) | 106 | if (buffer_uptodate(bh)) |
| 107 | goto failed_bh; | 107 | goto failed_bh; |
| 108 | #if 0 | 108 | |
| 109 | /* The uptodate flag is not protected by the page lock, but | ||
| 110 | the mapped flag is. Thus, we don't have to wait the buffer. */ | ||
| 111 | wait_on_buffer(bh); | 109 | wait_on_buffer(bh); |
| 112 | if (buffer_uptodate(bh)) | 110 | if (buffer_uptodate(bh)) |
| 113 | goto failed_bh; | 111 | goto failed_bh; |
| 114 | #endif | ||
| 115 | 112 | ||
| 116 | bh->b_bdev = nilfs->ns_bdev; | 113 | bh->b_bdev = nilfs->ns_bdev; |
| 117 | err = nilfs_mdt_insert_new_block(inode, block, bh, init_block); | 114 | err = nilfs_mdt_insert_new_block(inode, block, bh, init_block); |
| @@ -139,7 +136,7 @@ nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff, | |||
| 139 | int mode, struct buffer_head **out_bh) | 136 | int mode, struct buffer_head **out_bh) |
| 140 | { | 137 | { |
| 141 | struct buffer_head *bh; | 138 | struct buffer_head *bh; |
| 142 | unsigned long blknum = 0; | 139 | __u64 blknum = 0; |
| 143 | int ret = -ENOMEM; | 140 | int ret = -ENOMEM; |
| 144 | 141 | ||
| 145 | bh = nilfs_grab_buffer(inode, inode->i_mapping, blkoff, 0); | 142 | bh = nilfs_grab_buffer(inode, inode->i_mapping, blkoff, 0); |
| @@ -162,17 +159,15 @@ nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff, | |||
| 162 | unlock_buffer(bh); | 159 | unlock_buffer(bh); |
| 163 | goto out; | 160 | goto out; |
| 164 | } | 161 | } |
| 165 | if (!buffer_mapped(bh)) { /* unused buffer */ | 162 | |
| 166 | ret = nilfs_bmap_lookup(NILFS_I(inode)->i_bmap, blkoff, | 163 | ret = nilfs_bmap_lookup(NILFS_I(inode)->i_bmap, blkoff, &blknum); |
| 167 | &blknum); | 164 | if (unlikely(ret)) { |
| 168 | if (unlikely(ret)) { | 165 | unlock_buffer(bh); |
| 169 | unlock_buffer(bh); | 166 | goto failed_bh; |
| 170 | goto failed_bh; | ||
| 171 | } | ||
| 172 | bh->b_bdev = NILFS_MDT(inode)->mi_nilfs->ns_bdev; | ||
| 173 | bh->b_blocknr = blknum; | ||
| 174 | set_buffer_mapped(bh); | ||
| 175 | } | 167 | } |
| 168 | bh->b_bdev = NILFS_MDT(inode)->mi_nilfs->ns_bdev; | ||
| 169 | bh->b_blocknr = (sector_t)blknum; | ||
| 170 | set_buffer_mapped(bh); | ||
| 176 | 171 | ||
| 177 | bh->b_end_io = end_buffer_read_sync; | 172 | bh->b_end_io = end_buffer_read_sync; |
| 178 | get_bh(bh); | 173 | get_bh(bh); |
| @@ -402,6 +397,7 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) | |||
| 402 | struct inode *inode = container_of(page->mapping, | 397 | struct inode *inode = container_of(page->mapping, |
| 403 | struct inode, i_data); | 398 | struct inode, i_data); |
| 404 | struct super_block *sb = inode->i_sb; | 399 | struct super_block *sb = inode->i_sb; |
| 400 | struct the_nilfs *nilfs = NILFS_MDT(inode)->mi_nilfs; | ||
| 405 | struct nilfs_sb_info *writer = NULL; | 401 | struct nilfs_sb_info *writer = NULL; |
| 406 | int err = 0; | 402 | int err = 0; |
| 407 | 403 | ||
| @@ -411,9 +407,10 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) | |||
| 411 | if (page->mapping->assoc_mapping) | 407 | if (page->mapping->assoc_mapping) |
| 412 | return 0; /* Do not request flush for shadow page cache */ | 408 | return 0; /* Do not request flush for shadow page cache */ |
| 413 | if (!sb) { | 409 | if (!sb) { |
| 414 | writer = nilfs_get_writer(NILFS_MDT(inode)->mi_nilfs); | 410 | down_read(&nilfs->ns_writer_sem); |
| 411 | writer = nilfs->ns_writer; | ||
| 415 | if (!writer) { | 412 | if (!writer) { |
| 416 | nilfs_put_writer(NILFS_MDT(inode)->mi_nilfs); | 413 | up_read(&nilfs->ns_writer_sem); |
| 417 | return -EROFS; | 414 | return -EROFS; |
| 418 | } | 415 | } |
| 419 | sb = writer->s_super; | 416 | sb = writer->s_super; |
| @@ -425,7 +422,7 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) | |||
| 425 | nilfs_flush_segment(sb, inode->i_ino); | 422 | nilfs_flush_segment(sb, inode->i_ino); |
| 426 | 423 | ||
| 427 | if (writer) | 424 | if (writer) |
| 428 | nilfs_put_writer(NILFS_MDT(inode)->mi_nilfs); | 425 | up_read(&nilfs->ns_writer_sem); |
| 429 | return err; | 426 | return err; |
| 430 | } | 427 | } |
| 431 | 428 | ||
| @@ -516,9 +513,10 @@ nilfs_mdt_new_common(struct the_nilfs *nilfs, struct super_block *sb, | |||
| 516 | } | 513 | } |
| 517 | 514 | ||
| 518 | struct inode *nilfs_mdt_new(struct the_nilfs *nilfs, struct super_block *sb, | 515 | struct inode *nilfs_mdt_new(struct the_nilfs *nilfs, struct super_block *sb, |
| 519 | ino_t ino, gfp_t gfp_mask) | 516 | ino_t ino) |
| 520 | { | 517 | { |
| 521 | struct inode *inode = nilfs_mdt_new_common(nilfs, sb, ino, gfp_mask); | 518 | struct inode *inode = nilfs_mdt_new_common(nilfs, sb, ino, |
| 519 | NILFS_MDT_GFP); | ||
| 522 | 520 | ||
| 523 | if (!inode) | 521 | if (!inode) |
| 524 | return NULL; | 522 | return NULL; |
diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h index df683e0bca6..431599733c9 100644 --- a/fs/nilfs2/mdt.h +++ b/fs/nilfs2/mdt.h | |||
| @@ -74,8 +74,7 @@ int nilfs_mdt_forget_block(struct inode *, unsigned long); | |||
| 74 | int nilfs_mdt_mark_block_dirty(struct inode *, unsigned long); | 74 | int nilfs_mdt_mark_block_dirty(struct inode *, unsigned long); |
| 75 | int nilfs_mdt_fetch_dirty(struct inode *); | 75 | int nilfs_mdt_fetch_dirty(struct inode *); |
| 76 | 76 | ||
| 77 | struct inode *nilfs_mdt_new(struct the_nilfs *, struct super_block *, ino_t, | 77 | struct inode *nilfs_mdt_new(struct the_nilfs *, struct super_block *, ino_t); |
| 78 | gfp_t); | ||
| 79 | struct inode *nilfs_mdt_new_common(struct the_nilfs *, struct super_block *, | 78 | struct inode *nilfs_mdt_new_common(struct the_nilfs *, struct super_block *, |
| 80 | ino_t, gfp_t); | 79 | ino_t, gfp_t); |
| 81 | void nilfs_mdt_destroy(struct inode *); | 80 | void nilfs_mdt_destroy(struct inode *); |
diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index d80cc71be74..6dc83591d11 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c | |||
| @@ -552,7 +552,8 @@ static int recover_dsync_blocks(struct nilfs_sb_info *sbi, | |||
| 552 | printk(KERN_WARNING | 552 | printk(KERN_WARNING |
| 553 | "NILFS warning: error recovering data block " | 553 | "NILFS warning: error recovering data block " |
| 554 | "(err=%d, ino=%lu, block-offset=%llu)\n", | 554 | "(err=%d, ino=%lu, block-offset=%llu)\n", |
| 555 | err, rb->ino, (unsigned long long)rb->blkoff); | 555 | err, (unsigned long)rb->ino, |
| 556 | (unsigned long long)rb->blkoff); | ||
| 556 | if (!err2) | 557 | if (!err2) |
| 557 | err2 = err; | 558 | err2 = err; |
| 558 | next: | 559 | next: |
diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 9e3fe17bb96..e6d9e37fa24 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c | |||
| @@ -316,10 +316,10 @@ static struct bio *nilfs_alloc_seg_bio(struct super_block *sb, sector_t start, | |||
| 316 | { | 316 | { |
| 317 | struct bio *bio; | 317 | struct bio *bio; |
| 318 | 318 | ||
| 319 | bio = bio_alloc(GFP_NOWAIT, nr_vecs); | 319 | bio = bio_alloc(GFP_NOIO, nr_vecs); |
| 320 | if (bio == NULL) { | 320 | if (bio == NULL) { |
| 321 | while (!bio && (nr_vecs >>= 1)) | 321 | while (!bio && (nr_vecs >>= 1)) |
| 322 | bio = bio_alloc(GFP_NOWAIT, nr_vecs); | 322 | bio = bio_alloc(GFP_NOIO, nr_vecs); |
| 323 | } | 323 | } |
| 324 | if (likely(bio)) { | 324 | if (likely(bio)) { |
| 325 | bio->bi_bdev = sb->s_bdev; | 325 | bio->bi_bdev = sb->s_bdev; |
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 51ff3d0a4ee..683df89dbae 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c | |||
| @@ -2501,7 +2501,8 @@ static int nilfs_segctor_construct(struct nilfs_sc_info *sci, | |||
| 2501 | if (test_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags) && | 2501 | if (test_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags) && |
| 2502 | nilfs_discontinued(nilfs)) { | 2502 | nilfs_discontinued(nilfs)) { |
| 2503 | down_write(&nilfs->ns_sem); | 2503 | down_write(&nilfs->ns_sem); |
| 2504 | req->sb_err = nilfs_commit_super(sbi, 0); | 2504 | req->sb_err = nilfs_commit_super(sbi, |
| 2505 | nilfs_altsb_need_update(nilfs)); | ||
| 2505 | up_write(&nilfs->ns_sem); | 2506 | up_write(&nilfs->ns_sem); |
| 2506 | } | 2507 | } |
| 2507 | } | 2508 | } |
| @@ -2689,6 +2690,7 @@ static int nilfs_segctor_thread(void *arg) | |||
| 2689 | } else { | 2690 | } else { |
| 2690 | DEFINE_WAIT(wait); | 2691 | DEFINE_WAIT(wait); |
| 2691 | int should_sleep = 1; | 2692 | int should_sleep = 1; |
| 2693 | struct the_nilfs *nilfs; | ||
| 2692 | 2694 | ||
| 2693 | prepare_to_wait(&sci->sc_wait_daemon, &wait, | 2695 | prepare_to_wait(&sci->sc_wait_daemon, &wait, |
| 2694 | TASK_INTERRUPTIBLE); | 2696 | TASK_INTERRUPTIBLE); |
| @@ -2709,6 +2711,9 @@ static int nilfs_segctor_thread(void *arg) | |||
| 2709 | finish_wait(&sci->sc_wait_daemon, &wait); | 2711 | finish_wait(&sci->sc_wait_daemon, &wait); |
| 2710 | timeout = ((sci->sc_state & NILFS_SEGCTOR_COMMIT) && | 2712 | timeout = ((sci->sc_state & NILFS_SEGCTOR_COMMIT) && |
| 2711 | time_after_eq(jiffies, sci->sc_timer->expires)); | 2713 | time_after_eq(jiffies, sci->sc_timer->expires)); |
| 2714 | nilfs = sci->sc_sbi->s_nilfs; | ||
| 2715 | if (sci->sc_super->s_dirt && nilfs_sb_need_update(nilfs)) | ||
| 2716 | set_nilfs_discontinued(nilfs); | ||
| 2712 | } | 2717 | } |
| 2713 | goto loop; | 2718 | goto loop; |
| 2714 | 2719 | ||
diff --git a/fs/nilfs2/sufile.h b/fs/nilfs2/sufile.h index a2c4d76c336..0e99e5c0bd0 100644 --- a/fs/nilfs2/sufile.h +++ b/fs/nilfs2/sufile.h | |||
| @@ -28,7 +28,6 @@ | |||
| 28 | #include <linux/nilfs2_fs.h> | 28 | #include <linux/nilfs2_fs.h> |
| 29 | #include "mdt.h" | 29 | #include "mdt.h" |
| 30 | 30 | ||
| 31 | #define NILFS_SUFILE_GFP NILFS_MDT_GFP | ||
| 32 | 31 | ||
| 33 | static inline unsigned long nilfs_sufile_get_nsegments(struct inode *sufile) | 32 | static inline unsigned long nilfs_sufile_get_nsegments(struct inode *sufile) |
| 34 | { | 33 | { |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 151964f0de4..55f3d6b6073 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
| @@ -50,6 +50,8 @@ | |||
| 50 | #include <linux/writeback.h> | 50 | #include <linux/writeback.h> |
| 51 | #include <linux/kobject.h> | 51 | #include <linux/kobject.h> |
| 52 | #include <linux/exportfs.h> | 52 | #include <linux/exportfs.h> |
| 53 | #include <linux/seq_file.h> | ||
| 54 | #include <linux/mount.h> | ||
| 53 | #include "nilfs.h" | 55 | #include "nilfs.h" |
| 54 | #include "mdt.h" | 56 | #include "mdt.h" |
| 55 | #include "alloc.h" | 57 | #include "alloc.h" |
| @@ -65,7 +67,6 @@ MODULE_DESCRIPTION("A New Implementation of the Log-structured Filesystem " | |||
| 65 | "(NILFS)"); | 67 | "(NILFS)"); |
| 66 | MODULE_LICENSE("GPL"); | 68 | MODULE_LICENSE("GPL"); |
| 67 | 69 | ||
| 68 | static void nilfs_write_super(struct super_block *sb); | ||
| 69 | static int nilfs_remount(struct super_block *sb, int *flags, char *data); | 70 | static int nilfs_remount(struct super_block *sb, int *flags, char *data); |
| 70 | 71 | ||
| 71 | /** | 72 | /** |
| @@ -311,9 +312,6 @@ static void nilfs_put_super(struct super_block *sb) | |||
| 311 | 312 | ||
| 312 | lock_kernel(); | 313 | lock_kernel(); |
| 313 | 314 | ||
| 314 | if (sb->s_dirt) | ||
| 315 | nilfs_write_super(sb); | ||
| 316 | |||
| 317 | nilfs_detach_segment_constructor(sbi); | 315 | nilfs_detach_segment_constructor(sbi); |
| 318 | 316 | ||
| 319 | if (!(sb->s_flags & MS_RDONLY)) { | 317 | if (!(sb->s_flags & MS_RDONLY)) { |
| @@ -336,63 +334,21 @@ static void nilfs_put_super(struct super_block *sb) | |||
| 336 | unlock_kernel(); | 334 | unlock_kernel(); |
| 337 | } | 335 | } |
| 338 | 336 | ||
| 339 | /** | 337 | static int nilfs_sync_fs(struct super_block *sb, int wait) |
| 340 | * nilfs_write_super - write super block(s) of NILFS | ||
| 341 | * @sb: super_block | ||
| 342 | * | ||
| 343 | * nilfs_write_super() gets a fs-dependent lock, writes super block(s), and | ||
| 344 | * clears s_dirt. This function is called in the section protected by | ||
| 345 | * lock_super(). | ||
| 346 | * | ||
| 347 | * The s_dirt flag is managed by each filesystem and we protect it by ns_sem | ||
| 348 | * of the struct the_nilfs. Lock order must be as follows: | ||
| 349 | * | ||
| 350 | * 1. lock_super() | ||
| 351 | * 2. down_write(&nilfs->ns_sem) | ||
| 352 | * | ||
| 353 | * Inside NILFS, locking ns_sem is enough to protect s_dirt and the buffer | ||
| 354 | * of the super block (nilfs->ns_sbp[]). | ||
| 355 | * | ||
| 356 | * In most cases, VFS functions call lock_super() before calling these | ||
| 357 | * methods. So we must be careful not to bring on deadlocks when using | ||
| 358 | * lock_super(); see generic_shutdown_super(), write_super(), and so on. | ||
| 359 | * | ||
| 360 | * Note that order of lock_kernel() and lock_super() depends on contexts | ||
| 361 | * of VFS. We should also note that lock_kernel() can be used in its | ||
| 362 | * protective section and only the outermost one has an effect. | ||
| 363 | */ | ||
| 364 | static void nilfs_write_super(struct super_block *sb) | ||
| 365 | { | 338 | { |
| 366 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | 339 | struct nilfs_sb_info *sbi = NILFS_SB(sb); |
| 367 | struct the_nilfs *nilfs = sbi->s_nilfs; | 340 | struct the_nilfs *nilfs = sbi->s_nilfs; |
| 368 | |||
| 369 | down_write(&nilfs->ns_sem); | ||
| 370 | if (!(sb->s_flags & MS_RDONLY)) { | ||
| 371 | struct nilfs_super_block **sbp = nilfs->ns_sbp; | ||
| 372 | u64 t = get_seconds(); | ||
| 373 | int dupsb; | ||
| 374 | |||
| 375 | if (!nilfs_discontinued(nilfs) && t >= nilfs->ns_sbwtime[0] && | ||
| 376 | t < nilfs->ns_sbwtime[0] + NILFS_SB_FREQ) { | ||
| 377 | up_write(&nilfs->ns_sem); | ||
| 378 | return; | ||
| 379 | } | ||
| 380 | dupsb = sbp[1] && t > nilfs->ns_sbwtime[1] + NILFS_ALTSB_FREQ; | ||
| 381 | nilfs_commit_super(sbi, dupsb); | ||
| 382 | } | ||
| 383 | sb->s_dirt = 0; | ||
| 384 | up_write(&nilfs->ns_sem); | ||
| 385 | } | ||
| 386 | |||
| 387 | static int nilfs_sync_fs(struct super_block *sb, int wait) | ||
| 388 | { | ||
| 389 | int err = 0; | 341 | int err = 0; |
| 390 | 342 | ||
| 391 | nilfs_write_super(sb); | ||
| 392 | |||
| 393 | /* This function is called when super block should be written back */ | 343 | /* This function is called when super block should be written back */ |
| 394 | if (wait) | 344 | if (wait) |
| 395 | err = nilfs_construct_segment(sb); | 345 | err = nilfs_construct_segment(sb); |
| 346 | |||
| 347 | down_write(&nilfs->ns_sem); | ||
| 348 | if (sb->s_dirt) | ||
| 349 | nilfs_commit_super(sbi, 1); | ||
| 350 | up_write(&nilfs->ns_sem); | ||
| 351 | |||
| 396 | return err; | 352 | return err; |
| 397 | } | 353 | } |
| 398 | 354 | ||
| @@ -407,8 +363,7 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) | |||
| 407 | list_add(&sbi->s_list, &nilfs->ns_supers); | 363 | list_add(&sbi->s_list, &nilfs->ns_supers); |
| 408 | up_write(&nilfs->ns_super_sem); | 364 | up_write(&nilfs->ns_super_sem); |
| 409 | 365 | ||
| 410 | sbi->s_ifile = nilfs_mdt_new( | 366 | sbi->s_ifile = nilfs_mdt_new(nilfs, sbi->s_super, NILFS_IFILE_INO); |
| 411 | nilfs, sbi->s_super, NILFS_IFILE_INO, NILFS_IFILE_GFP); | ||
| 412 | if (!sbi->s_ifile) | 367 | if (!sbi->s_ifile) |
| 413 | return -ENOMEM; | 368 | return -ENOMEM; |
| 414 | 369 | ||
| @@ -529,6 +484,26 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 529 | return 0; | 484 | return 0; |
| 530 | } | 485 | } |
| 531 | 486 | ||
| 487 | static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs) | ||
| 488 | { | ||
| 489 | struct super_block *sb = vfs->mnt_sb; | ||
| 490 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | ||
| 491 | |||
| 492 | if (!nilfs_test_opt(sbi, BARRIER)) | ||
| 493 | seq_printf(seq, ",barrier=off"); | ||
| 494 | if (nilfs_test_opt(sbi, SNAPSHOT)) | ||
| 495 | seq_printf(seq, ",cp=%llu", | ||
| 496 | (unsigned long long int)sbi->s_snapshot_cno); | ||
| 497 | if (nilfs_test_opt(sbi, ERRORS_RO)) | ||
| 498 | seq_printf(seq, ",errors=remount-ro"); | ||
| 499 | if (nilfs_test_opt(sbi, ERRORS_PANIC)) | ||
| 500 | seq_printf(seq, ",errors=panic"); | ||
| 501 | if (nilfs_test_opt(sbi, STRICT_ORDER)) | ||
| 502 | seq_printf(seq, ",order=strict"); | ||
| 503 | |||
| 504 | return 0; | ||
| 505 | } | ||
| 506 | |||
| 532 | static struct super_operations nilfs_sops = { | 507 | static struct super_operations nilfs_sops = { |
| 533 | .alloc_inode = nilfs_alloc_inode, | 508 | .alloc_inode = nilfs_alloc_inode, |
| 534 | .destroy_inode = nilfs_destroy_inode, | 509 | .destroy_inode = nilfs_destroy_inode, |
| @@ -538,7 +513,7 @@ static struct super_operations nilfs_sops = { | |||
| 538 | /* .drop_inode = nilfs_drop_inode, */ | 513 | /* .drop_inode = nilfs_drop_inode, */ |
| 539 | .delete_inode = nilfs_delete_inode, | 514 | .delete_inode = nilfs_delete_inode, |
| 540 | .put_super = nilfs_put_super, | 515 | .put_super = nilfs_put_super, |
| 541 | .write_super = nilfs_write_super, | 516 | /* .write_super = nilfs_write_super, */ |
| 542 | .sync_fs = nilfs_sync_fs, | 517 | .sync_fs = nilfs_sync_fs, |
| 543 | /* .write_super_lockfs */ | 518 | /* .write_super_lockfs */ |
| 544 | /* .unlockfs */ | 519 | /* .unlockfs */ |
| @@ -546,7 +521,7 @@ static struct super_operations nilfs_sops = { | |||
| 546 | .remount_fs = nilfs_remount, | 521 | .remount_fs = nilfs_remount, |
| 547 | .clear_inode = nilfs_clear_inode, | 522 | .clear_inode = nilfs_clear_inode, |
| 548 | /* .umount_begin */ | 523 | /* .umount_begin */ |
| 549 | /* .show_options */ | 524 | .show_options = nilfs_show_options |
| 550 | }; | 525 | }; |
| 551 | 526 | ||
| 552 | static struct inode * | 527 | static struct inode * |
| @@ -816,10 +791,15 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
| 816 | 791 | ||
| 817 | if (sb->s_flags & MS_RDONLY) { | 792 | if (sb->s_flags & MS_RDONLY) { |
| 818 | if (nilfs_test_opt(sbi, SNAPSHOT)) { | 793 | if (nilfs_test_opt(sbi, SNAPSHOT)) { |
| 794 | down_read(&nilfs->ns_segctor_sem); | ||
| 819 | err = nilfs_cpfile_is_snapshot(nilfs->ns_cpfile, | 795 | err = nilfs_cpfile_is_snapshot(nilfs->ns_cpfile, |
| 820 | sbi->s_snapshot_cno); | 796 | sbi->s_snapshot_cno); |
| 821 | if (err < 0) | 797 | up_read(&nilfs->ns_segctor_sem); |
| 798 | if (err < 0) { | ||
| 799 | if (err == -ENOENT) | ||
| 800 | err = -EINVAL; | ||
| 822 | goto failed_sbi; | 801 | goto failed_sbi; |
| 802 | } | ||
| 823 | if (!err) { | 803 | if (!err) { |
| 824 | printk(KERN_ERR | 804 | printk(KERN_ERR |
| 825 | "NILFS: The specified checkpoint is " | 805 | "NILFS: The specified checkpoint is " |
| @@ -1127,10 +1107,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 1127 | */ | 1107 | */ |
| 1128 | sd.sbi = nilfs_find_sbinfo(nilfs, !(flags & MS_RDONLY), sd.cno); | 1108 | sd.sbi = nilfs_find_sbinfo(nilfs, !(flags & MS_RDONLY), sd.cno); |
| 1129 | 1109 | ||
| 1130 | if (!sd.cno) | ||
| 1131 | /* trying to get the latest checkpoint. */ | ||
| 1132 | sd.cno = nilfs_last_cno(nilfs); | ||
| 1133 | |||
| 1134 | /* | 1110 | /* |
| 1135 | * Get super block instance holding the nilfs_sb_info struct. | 1111 | * Get super block instance holding the nilfs_sb_info struct. |
| 1136 | * A new instance is allocated if no existing mount is present or | 1112 | * A new instance is allocated if no existing mount is present or |
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 8b888982571..ad391a8c3e7 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
| @@ -68,12 +68,11 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev) | |||
| 68 | 68 | ||
| 69 | nilfs->ns_bdev = bdev; | 69 | nilfs->ns_bdev = bdev; |
| 70 | atomic_set(&nilfs->ns_count, 1); | 70 | atomic_set(&nilfs->ns_count, 1); |
| 71 | atomic_set(&nilfs->ns_writer_refcount, -1); | ||
| 72 | atomic_set(&nilfs->ns_ndirtyblks, 0); | 71 | atomic_set(&nilfs->ns_ndirtyblks, 0); |
| 73 | init_rwsem(&nilfs->ns_sem); | 72 | init_rwsem(&nilfs->ns_sem); |
| 74 | init_rwsem(&nilfs->ns_super_sem); | 73 | init_rwsem(&nilfs->ns_super_sem); |
| 75 | mutex_init(&nilfs->ns_mount_mutex); | 74 | mutex_init(&nilfs->ns_mount_mutex); |
| 76 | mutex_init(&nilfs->ns_writer_mutex); | 75 | init_rwsem(&nilfs->ns_writer_sem); |
| 77 | INIT_LIST_HEAD(&nilfs->ns_list); | 76 | INIT_LIST_HEAD(&nilfs->ns_list); |
| 78 | INIT_LIST_HEAD(&nilfs->ns_supers); | 77 | INIT_LIST_HEAD(&nilfs->ns_supers); |
| 79 | spin_lock_init(&nilfs->ns_last_segment_lock); | 78 | spin_lock_init(&nilfs->ns_last_segment_lock); |
| @@ -188,23 +187,19 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, | |||
| 188 | inode_size = nilfs->ns_inode_size; | 187 | inode_size = nilfs->ns_inode_size; |
| 189 | 188 | ||
| 190 | err = -ENOMEM; | 189 | err = -ENOMEM; |
| 191 | nilfs->ns_dat = nilfs_mdt_new( | 190 | nilfs->ns_dat = nilfs_mdt_new(nilfs, NULL, NILFS_DAT_INO); |
| 192 | nilfs, NULL, NILFS_DAT_INO, NILFS_DAT_GFP); | ||
| 193 | if (unlikely(!nilfs->ns_dat)) | 191 | if (unlikely(!nilfs->ns_dat)) |
| 194 | goto failed; | 192 | goto failed; |
| 195 | 193 | ||
| 196 | nilfs->ns_gc_dat = nilfs_mdt_new( | 194 | nilfs->ns_gc_dat = nilfs_mdt_new(nilfs, NULL, NILFS_DAT_INO); |
| 197 | nilfs, NULL, NILFS_DAT_INO, NILFS_DAT_GFP); | ||
| 198 | if (unlikely(!nilfs->ns_gc_dat)) | 195 | if (unlikely(!nilfs->ns_gc_dat)) |
| 199 | goto failed_dat; | 196 | goto failed_dat; |
| 200 | 197 | ||
| 201 | nilfs->ns_cpfile = nilfs_mdt_new( | 198 | nilfs->ns_cpfile = nilfs_mdt_new(nilfs, NULL, NILFS_CPFILE_INO); |
| 202 | nilfs, NULL, NILFS_CPFILE_INO, NILFS_CPFILE_GFP); | ||
| 203 | if (unlikely(!nilfs->ns_cpfile)) | 199 | if (unlikely(!nilfs->ns_cpfile)) |
| 204 | goto failed_gc_dat; | 200 | goto failed_gc_dat; |
| 205 | 201 | ||
| 206 | nilfs->ns_sufile = nilfs_mdt_new( | 202 | nilfs->ns_sufile = nilfs_mdt_new(nilfs, NULL, NILFS_SUFILE_INO); |
| 207 | nilfs, NULL, NILFS_SUFILE_INO, NILFS_SUFILE_GFP); | ||
| 208 | if (unlikely(!nilfs->ns_sufile)) | 203 | if (unlikely(!nilfs->ns_sufile)) |
| 209 | goto failed_cpfile; | 204 | goto failed_cpfile; |
| 210 | 205 | ||
| @@ -596,9 +591,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
| 596 | 591 | ||
| 597 | nilfs->ns_mount_state = le16_to_cpu(sbp->s_state); | 592 | nilfs->ns_mount_state = le16_to_cpu(sbp->s_state); |
| 598 | 593 | ||
| 599 | bdi = nilfs->ns_bdev->bd_inode_backing_dev_info; | 594 | bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info; |
| 600 | if (!bdi) | ||
| 601 | bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info; | ||
| 602 | nilfs->ns_bdi = bdi ? : &default_backing_dev_info; | 595 | nilfs->ns_bdi = bdi ? : &default_backing_dev_info; |
| 603 | 596 | ||
| 604 | /* Finding last segment */ | 597 | /* Finding last segment */ |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 1b9caafb866..20abd55881e 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
| @@ -37,6 +37,7 @@ enum { | |||
| 37 | THE_NILFS_LOADED, /* Roll-back/roll-forward has done and | 37 | THE_NILFS_LOADED, /* Roll-back/roll-forward has done and |
| 38 | the latest checkpoint was loaded */ | 38 | the latest checkpoint was loaded */ |
| 39 | THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */ | 39 | THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */ |
| 40 | THE_NILFS_GC_RUNNING, /* gc process is running */ | ||
| 40 | }; | 41 | }; |
| 41 | 42 | ||
| 42 | /** | 43 | /** |
| @@ -50,8 +51,7 @@ enum { | |||
| 50 | * @ns_sem: semaphore for shared states | 51 | * @ns_sem: semaphore for shared states |
| 51 | * @ns_super_sem: semaphore for global operations across super block instances | 52 | * @ns_super_sem: semaphore for global operations across super block instances |
| 52 | * @ns_mount_mutex: mutex protecting mount process of nilfs | 53 | * @ns_mount_mutex: mutex protecting mount process of nilfs |
| 53 | * @ns_writer_mutex: mutex protecting ns_writer attach/detach | 54 | * @ns_writer_sem: semaphore protecting ns_writer attach/detach |
| 54 | * @ns_writer_refcount: number of referrers on ns_writer | ||
| 55 | * @ns_current: back pointer to current mount | 55 | * @ns_current: back pointer to current mount |
| 56 | * @ns_sbh: buffer heads of on-disk super blocks | 56 | * @ns_sbh: buffer heads of on-disk super blocks |
| 57 | * @ns_sbp: pointers to super block data | 57 | * @ns_sbp: pointers to super block data |
| @@ -100,8 +100,7 @@ struct the_nilfs { | |||
| 100 | struct rw_semaphore ns_sem; | 100 | struct rw_semaphore ns_sem; |
| 101 | struct rw_semaphore ns_super_sem; | 101 | struct rw_semaphore ns_super_sem; |
| 102 | struct mutex ns_mount_mutex; | 102 | struct mutex ns_mount_mutex; |
| 103 | struct mutex ns_writer_mutex; | 103 | struct rw_semaphore ns_writer_sem; |
| 104 | atomic_t ns_writer_refcount; | ||
| 105 | 104 | ||
| 106 | /* | 105 | /* |
| 107 | * components protected by ns_super_sem | 106 | * components protected by ns_super_sem |
| @@ -197,11 +196,26 @@ static inline int nilfs_##name(struct the_nilfs *nilfs) \ | |||
| 197 | THE_NILFS_FNS(INIT, init) | 196 | THE_NILFS_FNS(INIT, init) |
| 198 | THE_NILFS_FNS(LOADED, loaded) | 197 | THE_NILFS_FNS(LOADED, loaded) |
| 199 | THE_NILFS_FNS(DISCONTINUED, discontinued) | 198 | THE_NILFS_FNS(DISCONTINUED, discontinued) |
| 199 | THE_NILFS_FNS(GC_RUNNING, gc_running) | ||
| 200 | 200 | ||
| 201 | /* Minimum interval of periodical update of superblocks (in seconds) */ | 201 | /* Minimum interval of periodical update of superblocks (in seconds) */ |
| 202 | #define NILFS_SB_FREQ 10 | 202 | #define NILFS_SB_FREQ 10 |
| 203 | #define NILFS_ALTSB_FREQ 60 /* spare superblock */ | 203 | #define NILFS_ALTSB_FREQ 60 /* spare superblock */ |
| 204 | 204 | ||
| 205 | static inline int nilfs_sb_need_update(struct the_nilfs *nilfs) | ||
| 206 | { | ||
| 207 | u64 t = get_seconds(); | ||
| 208 | return t < nilfs->ns_sbwtime[0] || | ||
| 209 | t > nilfs->ns_sbwtime[0] + NILFS_SB_FREQ; | ||
| 210 | } | ||
| 211 | |||
| 212 | static inline int nilfs_altsb_need_update(struct the_nilfs *nilfs) | ||
| 213 | { | ||
| 214 | u64 t = get_seconds(); | ||
| 215 | struct nilfs_super_block **sbp = nilfs->ns_sbp; | ||
| 216 | return sbp[1] && t > nilfs->ns_sbwtime[1] + NILFS_ALTSB_FREQ; | ||
| 217 | } | ||
| 218 | |||
| 205 | void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); | 219 | void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); |
| 206 | struct the_nilfs *find_or_create_nilfs(struct block_device *); | 220 | struct the_nilfs *find_or_create_nilfs(struct block_device *); |
| 207 | void put_nilfs(struct the_nilfs *); | 221 | void put_nilfs(struct the_nilfs *); |
| @@ -221,34 +235,21 @@ static inline void get_nilfs(struct the_nilfs *nilfs) | |||
| 221 | atomic_inc(&nilfs->ns_count); | 235 | atomic_inc(&nilfs->ns_count); |
| 222 | } | 236 | } |
| 223 | 237 | ||
| 224 | static inline struct nilfs_sb_info *nilfs_get_writer(struct the_nilfs *nilfs) | ||
| 225 | { | ||
| 226 | if (atomic_inc_and_test(&nilfs->ns_writer_refcount)) | ||
| 227 | mutex_lock(&nilfs->ns_writer_mutex); | ||
| 228 | return nilfs->ns_writer; | ||
| 229 | } | ||
| 230 | |||
| 231 | static inline void nilfs_put_writer(struct the_nilfs *nilfs) | ||
| 232 | { | ||
| 233 | if (atomic_add_negative(-1, &nilfs->ns_writer_refcount)) | ||
| 234 | mutex_unlock(&nilfs->ns_writer_mutex); | ||
| 235 | } | ||
| 236 | |||
| 237 | static inline void | 238 | static inline void |
| 238 | nilfs_attach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | 239 | nilfs_attach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) |
| 239 | { | 240 | { |
| 240 | mutex_lock(&nilfs->ns_writer_mutex); | 241 | down_write(&nilfs->ns_writer_sem); |
| 241 | nilfs->ns_writer = sbi; | 242 | nilfs->ns_writer = sbi; |
| 242 | mutex_unlock(&nilfs->ns_writer_mutex); | 243 | up_write(&nilfs->ns_writer_sem); |
| 243 | } | 244 | } |
| 244 | 245 | ||
| 245 | static inline void | 246 | static inline void |
| 246 | nilfs_detach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | 247 | nilfs_detach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) |
| 247 | { | 248 | { |
| 248 | mutex_lock(&nilfs->ns_writer_mutex); | 249 | down_write(&nilfs->ns_writer_sem); |
| 249 | if (sbi == nilfs->ns_writer) | 250 | if (sbi == nilfs->ns_writer) |
| 250 | nilfs->ns_writer = NULL; | 251 | nilfs->ns_writer = NULL; |
| 251 | mutex_unlock(&nilfs->ns_writer_mutex); | 252 | up_write(&nilfs->ns_writer_sem); |
| 252 | } | 253 | } |
| 253 | 254 | ||
| 254 | static inline void nilfs_put_sbinfo(struct nilfs_sb_info *sbi) | 255 | static inline void nilfs_put_sbinfo(struct nilfs_sb_info *sbi) |
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 3140a4429af..4350d4993b1 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
| @@ -2076,14 +2076,6 @@ err_out: | |||
| 2076 | *ppos = pos; | 2076 | *ppos = pos; |
| 2077 | if (cached_page) | 2077 | if (cached_page) |
| 2078 | page_cache_release(cached_page); | 2078 | page_cache_release(cached_page); |
| 2079 | /* For now, when the user asks for O_SYNC, we actually give O_DSYNC. */ | ||
| 2080 | if (likely(!status)) { | ||
| 2081 | if (unlikely((file->f_flags & O_SYNC) || IS_SYNC(vi))) { | ||
| 2082 | if (!mapping->a_ops->writepage || !is_sync_kiocb(iocb)) | ||
| 2083 | status = generic_osync_inode(vi, mapping, | ||
| 2084 | OSYNC_METADATA|OSYNC_DATA); | ||
| 2085 | } | ||
| 2086 | } | ||
| 2087 | pagevec_lru_add_file(&lru_pvec); | 2079 | pagevec_lru_add_file(&lru_pvec); |
| 2088 | ntfs_debug("Done. Returning %s (written 0x%lx, status %li).", | 2080 | ntfs_debug("Done. Returning %s (written 0x%lx, status %li).", |
| 2089 | written ? "written" : "status", (unsigned long)written, | 2081 | written ? "written" : "status", (unsigned long)written, |
| @@ -2145,8 +2137,8 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 2145 | mutex_lock(&inode->i_mutex); | 2137 | mutex_lock(&inode->i_mutex); |
| 2146 | ret = ntfs_file_aio_write_nolock(iocb, iov, nr_segs, &iocb->ki_pos); | 2138 | ret = ntfs_file_aio_write_nolock(iocb, iov, nr_segs, &iocb->ki_pos); |
| 2147 | mutex_unlock(&inode->i_mutex); | 2139 | mutex_unlock(&inode->i_mutex); |
| 2148 | if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { | 2140 | if (ret > 0) { |
| 2149 | int err = sync_page_range(inode, mapping, pos, ret); | 2141 | int err = generic_write_sync(file, pos, ret); |
| 2150 | if (err < 0) | 2142 | if (err < 0) |
| 2151 | ret = err; | 2143 | ret = err; |
| 2152 | } | 2144 | } |
| @@ -2173,8 +2165,8 @@ static ssize_t ntfs_file_writev(struct file *file, const struct iovec *iov, | |||
| 2173 | if (ret == -EIOCBQUEUED) | 2165 | if (ret == -EIOCBQUEUED) |
| 2174 | ret = wait_on_sync_kiocb(&kiocb); | 2166 | ret = wait_on_sync_kiocb(&kiocb); |
| 2175 | mutex_unlock(&inode->i_mutex); | 2167 | mutex_unlock(&inode->i_mutex); |
| 2176 | if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { | 2168 | if (ret > 0) { |
| 2177 | int err = sync_page_range(inode, mapping, *ppos - ret, ret); | 2169 | int err = generic_write_sync(file, *ppos - ret, ret); |
| 2178 | if (err < 0) | 2170 | if (err < 0) |
| 2179 | ret = err; | 2171 | ret = err; |
| 2180 | } | 2172 | } |
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 23bf68453d7..1caa0ef0b2b 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c | |||
| @@ -384,13 +384,12 @@ unm_err_out: | |||
| 384 | * it is dirty in the inode meta data rather than the data page cache of the | 384 | * it is dirty in the inode meta data rather than the data page cache of the |
| 385 | * inode, and thus there are no data pages that need writing out. Therefore, a | 385 | * inode, and thus there are no data pages that need writing out. Therefore, a |
| 386 | * full mark_inode_dirty() is overkill. A mark_inode_dirty_sync(), on the | 386 | * full mark_inode_dirty() is overkill. A mark_inode_dirty_sync(), on the |
| 387 | * other hand, is not sufficient, because I_DIRTY_DATASYNC needs to be set to | 387 | * other hand, is not sufficient, because ->write_inode needs to be called even |
| 388 | * ensure ->write_inode is called from generic_osync_inode() and this needs to | 388 | * in case of fdatasync. This needs to happen or the file data would not |
| 389 | * happen or the file data would not necessarily hit the device synchronously, | 389 | * necessarily hit the device synchronously, even though the vfs inode has the |
| 390 | * even though the vfs inode has the O_SYNC flag set. Also, I_DIRTY_DATASYNC | 390 | * O_SYNC flag set. Also, I_DIRTY_DATASYNC simply "feels" better than just |
| 391 | * simply "feels" better than just I_DIRTY_SYNC, since the file data has not | 391 | * I_DIRTY_SYNC, since the file data has not actually hit the block device yet, |
| 392 | * actually hit the block device yet, which is not what I_DIRTY_SYNC on its own | 392 | * which is not what I_DIRTY_SYNC on its own would suggest. |
| 393 | * would suggest. | ||
| 394 | */ | 393 | */ |
| 395 | void __mark_mft_record_dirty(ntfs_inode *ni) | 394 | void __mark_mft_record_dirty(ntfs_inode *ni) |
| 396 | { | 395 | { |
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index b401654011a..8a1e61545f4 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
| @@ -1747,8 +1747,8 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, | |||
| 1747 | * we know zeros will only be needed in the first and/or last cluster. | 1747 | * we know zeros will only be needed in the first and/or last cluster. |
| 1748 | */ | 1748 | */ |
| 1749 | if (clusters_to_alloc || extents_to_split || | 1749 | if (clusters_to_alloc || extents_to_split || |
| 1750 | wc->w_desc[0].c_needs_zero || | 1750 | (wc->w_clen && (wc->w_desc[0].c_needs_zero || |
| 1751 | wc->w_desc[wc->w_clen - 1].c_needs_zero) | 1751 | wc->w_desc[wc->w_clen - 1].c_needs_zero))) |
| 1752 | cluster_of_pages = 1; | 1752 | cluster_of_pages = 1; |
| 1753 | else | 1753 | else |
| 1754 | cluster_of_pages = 0; | 1754 | cluster_of_pages = 0; |
diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c index 2f28b7de2c8..b4957c7d9fe 100644 --- a/fs/ocfs2/dcache.c +++ b/fs/ocfs2/dcache.c | |||
| @@ -85,6 +85,17 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry, | |||
| 85 | goto bail; | 85 | goto bail; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | /* | ||
| 89 | * If the last lookup failed to create dentry lock, let us | ||
| 90 | * redo it. | ||
| 91 | */ | ||
| 92 | if (!dentry->d_fsdata) { | ||
| 93 | mlog(0, "Inode %llu doesn't have dentry lock, " | ||
| 94 | "returning false\n", | ||
| 95 | (unsigned long long)OCFS2_I(inode)->ip_blkno); | ||
| 96 | goto bail; | ||
| 97 | } | ||
| 98 | |||
| 88 | ret = 1; | 99 | ret = 1; |
| 89 | 100 | ||
| 90 | bail: | 101 | bail: |
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index 1c9efb406a9..02bf17808bd 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c | |||
| @@ -325,6 +325,7 @@ clear_fields: | |||
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | static struct backing_dev_info dlmfs_backing_dev_info = { | 327 | static struct backing_dev_info dlmfs_backing_dev_info = { |
| 328 | .name = "ocfs2-dlmfs", | ||
| 328 | .ra_pages = 0, /* No readahead */ | 329 | .ra_pages = 0, /* No readahead */ |
| 329 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, | 330 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, |
| 330 | }; | 331 | }; |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index aa501d3f93f..221c5e98957 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
| @@ -1871,8 +1871,7 @@ relock: | |||
| 1871 | goto out_dio; | 1871 | goto out_dio; |
| 1872 | } | 1872 | } |
| 1873 | } else { | 1873 | } else { |
| 1874 | written = generic_file_aio_write_nolock(iocb, iov, nr_segs, | 1874 | written = __generic_file_aio_write(iocb, iov, nr_segs, ppos); |
| 1875 | *ppos); | ||
| 1876 | } | 1875 | } |
| 1877 | 1876 | ||
| 1878 | out_dio: | 1877 | out_dio: |
| @@ -1880,18 +1879,21 @@ out_dio: | |||
| 1880 | BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT)); | 1879 | BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT)); |
| 1881 | 1880 | ||
| 1882 | if ((file->f_flags & O_SYNC && !direct_io) || IS_SYNC(inode)) { | 1881 | if ((file->f_flags & O_SYNC && !direct_io) || IS_SYNC(inode)) { |
| 1883 | /* | 1882 | ret = filemap_fdatawrite_range(file->f_mapping, pos, |
| 1884 | * The generic write paths have handled getting data | 1883 | pos + count - 1); |
| 1885 | * to disk, but since we don't make use of the dirty | 1884 | if (ret < 0) |
| 1886 | * inode list, a manual journal commit is necessary | 1885 | written = ret; |
| 1887 | * here. | 1886 | |
| 1888 | */ | 1887 | if (!ret && (old_size != i_size_read(inode) || |
| 1889 | if (old_size != i_size_read(inode) || | 1888 | old_clusters != OCFS2_I(inode)->ip_clusters)) { |
| 1890 | old_clusters != OCFS2_I(inode)->ip_clusters) { | ||
| 1891 | ret = jbd2_journal_force_commit(osb->journal->j_journal); | 1889 | ret = jbd2_journal_force_commit(osb->journal->j_journal); |
| 1892 | if (ret < 0) | 1890 | if (ret < 0) |
| 1893 | written = ret; | 1891 | written = ret; |
| 1894 | } | 1892 | } |
| 1893 | |||
| 1894 | if (!ret) | ||
| 1895 | ret = filemap_fdatawait_range(file->f_mapping, pos, | ||
| 1896 | pos + count - 1); | ||
| 1895 | } | 1897 | } |
| 1896 | 1898 | ||
| 1897 | /* | 1899 | /* |
| @@ -1991,31 +1993,16 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, | |||
| 1991 | 1993 | ||
| 1992 | if (ret > 0) { | 1994 | if (ret > 0) { |
| 1993 | unsigned long nr_pages; | 1995 | unsigned long nr_pages; |
| 1996 | int err; | ||
| 1994 | 1997 | ||
| 1995 | *ppos += ret; | ||
| 1996 | nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 1998 | nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
| 1997 | 1999 | ||
| 1998 | /* | 2000 | err = generic_write_sync(out, *ppos, ret); |
| 1999 | * If file or inode is SYNC and we actually wrote some data, | 2001 | if (err) |
| 2000 | * sync it. | 2002 | ret = err; |
| 2001 | */ | 2003 | else |
| 2002 | if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) { | 2004 | *ppos += ret; |
| 2003 | int err; | ||
| 2004 | |||
| 2005 | mutex_lock(&inode->i_mutex); | ||
| 2006 | err = ocfs2_rw_lock(inode, 1); | ||
| 2007 | if (err < 0) { | ||
| 2008 | mlog_errno(err); | ||
| 2009 | } else { | ||
| 2010 | err = generic_osync_inode(inode, mapping, | ||
| 2011 | OSYNC_METADATA|OSYNC_DATA); | ||
| 2012 | ocfs2_rw_unlock(inode, 1); | ||
| 2013 | } | ||
| 2014 | mutex_unlock(&inode->i_mutex); | ||
| 2015 | 2005 | ||
| 2016 | if (err) | ||
| 2017 | ret = err; | ||
| 2018 | } | ||
| 2019 | balance_dirty_pages_ratelimited_nr(mapping, nr_pages); | 2006 | balance_dirty_pages_ratelimited_nr(mapping, nr_pages); |
| 2020 | } | 2007 | } |
| 2021 | 2008 | ||
| @@ -199,7 +199,7 @@ out: | |||
| 199 | int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, | 199 | int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, |
| 200 | struct file *filp) | 200 | struct file *filp) |
| 201 | { | 201 | { |
| 202 | int err; | 202 | int ret; |
| 203 | struct iattr newattrs; | 203 | struct iattr newattrs; |
| 204 | 204 | ||
| 205 | /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ | 205 | /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ |
| @@ -214,12 +214,14 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, | |||
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | /* Remove suid/sgid on truncate too */ | 216 | /* Remove suid/sgid on truncate too */ |
| 217 | newattrs.ia_valid |= should_remove_suid(dentry); | 217 | ret = should_remove_suid(dentry); |
| 218 | if (ret) | ||
| 219 | newattrs.ia_valid |= ret | ATTR_FORCE; | ||
| 218 | 220 | ||
| 219 | mutex_lock(&dentry->d_inode->i_mutex); | 221 | mutex_lock(&dentry->d_inode->i_mutex); |
| 220 | err = notify_change(dentry, &newattrs); | 222 | ret = notify_change(dentry, &newattrs); |
| 221 | mutex_unlock(&dentry->d_inode->i_mutex); | 223 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 222 | return err; | 224 | return ret; |
| 223 | } | 225 | } |
| 224 | 226 | ||
| 225 | static long do_sys_truncate(const char __user *pathname, loff_t length) | 227 | static long do_sys_truncate(const char __user *pathname, loff_t length) |
| @@ -957,6 +959,8 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, | |||
| 957 | int error; | 959 | int error; |
| 958 | struct file *f; | 960 | struct file *f; |
| 959 | 961 | ||
| 962 | validate_creds(cred); | ||
| 963 | |||
| 960 | /* | 964 | /* |
| 961 | * We must always pass in a valid mount pointer. Historically | 965 | * We must always pass in a valid mount pointer. Historically |
| 962 | * callers got away with not passing it, but we must enforce this at | 966 | * callers got away with not passing it, but we must enforce this at |
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index ea4e6cb29e1..fbeaddf595d 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
| @@ -248,11 +248,19 @@ ssize_t part_stat_show(struct device *dev, | |||
| 248 | part_stat_read(p, merges[WRITE]), | 248 | part_stat_read(p, merges[WRITE]), |
| 249 | (unsigned long long)part_stat_read(p, sectors[WRITE]), | 249 | (unsigned long long)part_stat_read(p, sectors[WRITE]), |
| 250 | jiffies_to_msecs(part_stat_read(p, ticks[WRITE])), | 250 | jiffies_to_msecs(part_stat_read(p, ticks[WRITE])), |
| 251 | p->in_flight, | 251 | part_in_flight(p), |
| 252 | jiffies_to_msecs(part_stat_read(p, io_ticks)), | 252 | jiffies_to_msecs(part_stat_read(p, io_ticks)), |
| 253 | jiffies_to_msecs(part_stat_read(p, time_in_queue))); | 253 | jiffies_to_msecs(part_stat_read(p, time_in_queue))); |
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | ssize_t part_inflight_show(struct device *dev, | ||
| 257 | struct device_attribute *attr, char *buf) | ||
| 258 | { | ||
| 259 | struct hd_struct *p = dev_to_part(dev); | ||
| 260 | |||
| 261 | return sprintf(buf, "%8u %8u\n", p->in_flight[0], p->in_flight[1]); | ||
| 262 | } | ||
| 263 | |||
| 256 | #ifdef CONFIG_FAIL_MAKE_REQUEST | 264 | #ifdef CONFIG_FAIL_MAKE_REQUEST |
| 257 | ssize_t part_fail_show(struct device *dev, | 265 | ssize_t part_fail_show(struct device *dev, |
| 258 | struct device_attribute *attr, char *buf) | 266 | struct device_attribute *attr, char *buf) |
| @@ -281,6 +289,7 @@ static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); | |||
| 281 | static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); | 289 | static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); |
| 282 | static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL); | 290 | static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL); |
| 283 | static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); | 291 | static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); |
| 292 | static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); | ||
| 284 | #ifdef CONFIG_FAIL_MAKE_REQUEST | 293 | #ifdef CONFIG_FAIL_MAKE_REQUEST |
| 285 | static struct device_attribute dev_attr_fail = | 294 | static struct device_attribute dev_attr_fail = |
| 286 | __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); | 295 | __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); |
| @@ -292,6 +301,7 @@ static struct attribute *part_attrs[] = { | |||
| 292 | &dev_attr_size.attr, | 301 | &dev_attr_size.attr, |
| 293 | &dev_attr_alignment_offset.attr, | 302 | &dev_attr_alignment_offset.attr, |
| 294 | &dev_attr_stat.attr, | 303 | &dev_attr_stat.attr, |
| 304 | &dev_attr_inflight.attr, | ||
| 295 | #ifdef CONFIG_FAIL_MAKE_REQUEST | 305 | #ifdef CONFIG_FAIL_MAKE_REQUEST |
| 296 | &dev_attr_fail.attr, | 306 | &dev_attr_fail.attr, |
| 297 | #endif | 307 | #endif |
| @@ -302,7 +312,7 @@ static struct attribute_group part_attr_group = { | |||
| 302 | .attrs = part_attrs, | 312 | .attrs = part_attrs, |
| 303 | }; | 313 | }; |
| 304 | 314 | ||
| 305 | static struct attribute_group *part_attr_groups[] = { | 315 | static const struct attribute_group *part_attr_groups[] = { |
| 306 | &part_attr_group, | 316 | &part_attr_group, |
| 307 | #ifdef CONFIG_BLK_DEV_IO_TRACE | 317 | #ifdef CONFIG_BLK_DEV_IO_TRACE |
| 308 | &blk_trace_attr_group, | 318 | &blk_trace_attr_group, |
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 0ff7566c767..a7f0110fca4 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c | |||
| @@ -46,6 +46,7 @@ static const struct super_operations ramfs_ops; | |||
| 46 | static const struct inode_operations ramfs_dir_inode_operations; | 46 | static const struct inode_operations ramfs_dir_inode_operations; |
| 47 | 47 | ||
| 48 | static struct backing_dev_info ramfs_backing_dev_info = { | 48 | static struct backing_dev_info ramfs_backing_dev_info = { |
| 49 | .name = "ramfs", | ||
| 49 | .ra_pages = 0, /* No readahead */ | 50 | .ra_pages = 0, /* No readahead */ |
| 50 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK | | 51 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK | |
| 51 | BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY | | 52 | BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY | |
diff --git a/fs/splice.c b/fs/splice.c index 73766d24f97..7394e9e1753 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
| @@ -502,8 +502,10 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, | |||
| 502 | len = left; | 502 | len = left; |
| 503 | 503 | ||
| 504 | ret = __generic_file_splice_read(in, ppos, pipe, len, flags); | 504 | ret = __generic_file_splice_read(in, ppos, pipe, len, flags); |
| 505 | if (ret > 0) | 505 | if (ret > 0) { |
| 506 | *ppos += ret; | 506 | *ppos += ret; |
| 507 | file_accessed(in); | ||
| 508 | } | ||
| 507 | 509 | ||
| 508 | return ret; | 510 | return ret; |
| 509 | } | 511 | } |
| @@ -963,8 +965,10 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, | |||
| 963 | 965 | ||
| 964 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); | 966 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); |
| 965 | ret = file_remove_suid(out); | 967 | ret = file_remove_suid(out); |
| 966 | if (!ret) | 968 | if (!ret) { |
| 969 | file_update_time(out); | ||
| 967 | ret = splice_from_pipe_feed(pipe, &sd, pipe_to_file); | 970 | ret = splice_from_pipe_feed(pipe, &sd, pipe_to_file); |
| 971 | } | ||
| 968 | mutex_unlock(&inode->i_mutex); | 972 | mutex_unlock(&inode->i_mutex); |
| 969 | } while (ret > 0); | 973 | } while (ret > 0); |
| 970 | splice_from_pipe_end(pipe, &sd); | 974 | splice_from_pipe_end(pipe, &sd); |
| @@ -976,25 +980,15 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, | |||
| 976 | 980 | ||
| 977 | if (ret > 0) { | 981 | if (ret > 0) { |
| 978 | unsigned long nr_pages; | 982 | unsigned long nr_pages; |
| 983 | int err; | ||
| 979 | 984 | ||
| 980 | *ppos += ret; | ||
| 981 | nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 985 | nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
| 982 | 986 | ||
| 983 | /* | 987 | err = generic_write_sync(out, *ppos, ret); |
| 984 | * If file or inode is SYNC and we actually wrote some data, | 988 | if (err) |
| 985 | * sync it. | 989 | ret = err; |
| 986 | */ | 990 | else |
| 987 | if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) { | 991 | *ppos += ret; |
| 988 | int err; | ||
| 989 | |||
| 990 | mutex_lock(&inode->i_mutex); | ||
| 991 | err = generic_osync_inode(inode, mapping, | ||
| 992 | OSYNC_METADATA|OSYNC_DATA); | ||
| 993 | mutex_unlock(&inode->i_mutex); | ||
| 994 | |||
| 995 | if (err) | ||
| 996 | ret = err; | ||
| 997 | } | ||
| 998 | balance_dirty_pages_ratelimited_nr(mapping, nr_pages); | 992 | balance_dirty_pages_ratelimited_nr(mapping, nr_pages); |
| 999 | } | 993 | } |
| 1000 | 994 | ||
diff --git a/fs/super.c b/fs/super.c index 2761d3e22ed..b03fea8fbfb 100644 --- a/fs/super.c +++ b/fs/super.c | |||
| @@ -62,9 +62,6 @@ static struct super_block *alloc_super(struct file_system_type *type) | |||
| 62 | s = NULL; | 62 | s = NULL; |
| 63 | goto out; | 63 | goto out; |
| 64 | } | 64 | } |
| 65 | INIT_LIST_HEAD(&s->s_dirty); | ||
| 66 | INIT_LIST_HEAD(&s->s_io); | ||
| 67 | INIT_LIST_HEAD(&s->s_more_io); | ||
| 68 | INIT_LIST_HEAD(&s->s_files); | 65 | INIT_LIST_HEAD(&s->s_files); |
| 69 | INIT_LIST_HEAD(&s->s_instances); | 66 | INIT_LIST_HEAD(&s->s_instances); |
| 70 | INIT_HLIST_HEAD(&s->s_anon); | 67 | INIT_HLIST_HEAD(&s->s_anon); |
| @@ -171,7 +168,7 @@ int __put_super_and_need_restart(struct super_block *sb) | |||
| 171 | * Drops a temporary reference, frees superblock if there's no | 168 | * Drops a temporary reference, frees superblock if there's no |
| 172 | * references left. | 169 | * references left. |
| 173 | */ | 170 | */ |
| 174 | static void put_super(struct super_block *sb) | 171 | void put_super(struct super_block *sb) |
| 175 | { | 172 | { |
| 176 | spin_lock(&sb_lock); | 173 | spin_lock(&sb_lock); |
| 177 | __put_super(sb); | 174 | __put_super(sb); |
| @@ -710,6 +707,12 @@ static int set_bdev_super(struct super_block *s, void *data) | |||
| 710 | { | 707 | { |
| 711 | s->s_bdev = data; | 708 | s->s_bdev = data; |
| 712 | s->s_dev = s->s_bdev->bd_dev; | 709 | s->s_dev = s->s_bdev->bd_dev; |
| 710 | |||
| 711 | /* | ||
| 712 | * We set the bdi here to the queue backing, file systems can | ||
| 713 | * overwrite this in ->fill_super() | ||
| 714 | */ | ||
| 715 | s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info; | ||
| 713 | return 0; | 716 | return 0; |
| 714 | } | 717 | } |
| 715 | 718 | ||
| @@ -19,20 +19,29 @@ | |||
| 19 | SYNC_FILE_RANGE_WAIT_AFTER) | 19 | SYNC_FILE_RANGE_WAIT_AFTER) |
| 20 | 20 | ||
| 21 | /* | 21 | /* |
| 22 | * Do the filesystem syncing work. For simple filesystems sync_inodes_sb(sb, 0) | 22 | * Do the filesystem syncing work. For simple filesystems |
| 23 | * just dirties buffers with inodes so we have to submit IO for these buffers | 23 | * writeback_inodes_sb(sb) just dirties buffers with inodes so we have to |
| 24 | * via __sync_blockdev(). This also speeds up the wait == 1 case since in that | 24 | * submit IO for these buffers via __sync_blockdev(). This also speeds up the |
| 25 | * case write_inode() functions do sync_dirty_buffer() and thus effectively | 25 | * wait == 1 case since in that case write_inode() functions do |
| 26 | * write one block at a time. | 26 | * sync_dirty_buffer() and thus effectively write one block at a time. |
| 27 | */ | 27 | */ |
| 28 | static int __sync_filesystem(struct super_block *sb, int wait) | 28 | static int __sync_filesystem(struct super_block *sb, int wait) |
| 29 | { | 29 | { |
| 30 | /* | ||
| 31 | * This should be safe, as we require bdi backing to actually | ||
| 32 | * write out data in the first place | ||
| 33 | */ | ||
| 34 | if (!sb->s_bdi) | ||
| 35 | return 0; | ||
| 36 | |||
| 30 | /* Avoid doing twice syncing and cache pruning for quota sync */ | 37 | /* Avoid doing twice syncing and cache pruning for quota sync */ |
| 31 | if (!wait) | 38 | if (!wait) { |
| 32 | writeout_quota_sb(sb, -1); | 39 | writeout_quota_sb(sb, -1); |
| 33 | else | 40 | writeback_inodes_sb(sb); |
| 41 | } else { | ||
| 34 | sync_quota_sb(sb, -1); | 42 | sync_quota_sb(sb, -1); |
| 35 | sync_inodes_sb(sb, wait); | 43 | sync_inodes_sb(sb); |
| 44 | } | ||
| 36 | if (sb->s_op->sync_fs) | 45 | if (sb->s_op->sync_fs) |
| 37 | sb->s_op->sync_fs(sb, wait); | 46 | sb->s_op->sync_fs(sb, wait); |
| 38 | return __sync_blockdev(sb->s_bdev, wait); | 47 | return __sync_blockdev(sb->s_bdev, wait); |
| @@ -99,7 +108,7 @@ restart: | |||
| 99 | spin_unlock(&sb_lock); | 108 | spin_unlock(&sb_lock); |
| 100 | 109 | ||
| 101 | down_read(&sb->s_umount); | 110 | down_read(&sb->s_umount); |
| 102 | if (!(sb->s_flags & MS_RDONLY) && sb->s_root) | 111 | if (!(sb->s_flags & MS_RDONLY) && sb->s_root && sb->s_bdi) |
| 103 | __sync_filesystem(sb, wait); | 112 | __sync_filesystem(sb, wait); |
| 104 | up_read(&sb->s_umount); | 113 | up_read(&sb->s_umount); |
| 105 | 114 | ||
| @@ -118,7 +127,7 @@ restart: | |||
| 118 | */ | 127 | */ |
| 119 | SYSCALL_DEFINE0(sync) | 128 | SYSCALL_DEFINE0(sync) |
| 120 | { | 129 | { |
| 121 | wakeup_pdflush(0); | 130 | wakeup_flusher_threads(0); |
| 122 | sync_filesystems(0); | 131 | sync_filesystems(0); |
| 123 | sync_filesystems(1); | 132 | sync_filesystems(1); |
| 124 | if (unlikely(laptop_mode)) | 133 | if (unlikely(laptop_mode)) |
| @@ -176,19 +185,23 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync) | |||
| 176 | } | 185 | } |
| 177 | 186 | ||
| 178 | /** | 187 | /** |
| 179 | * vfs_fsync - perform a fsync or fdatasync on a file | 188 | * vfs_fsync_range - helper to sync a range of data & metadata to disk |
| 180 | * @file: file to sync | 189 | * @file: file to sync |
| 181 | * @dentry: dentry of @file | 190 | * @dentry: dentry of @file |
| 182 | * @data: only perform a fdatasync operation | 191 | * @start: offset in bytes of the beginning of data range to sync |
| 192 | * @end: offset in bytes of the end of data range (inclusive) | ||
| 193 | * @datasync: perform only datasync | ||
| 183 | * | 194 | * |
| 184 | * Write back data and metadata for @file to disk. If @datasync is | 195 | * Write back data in range @start..@end and metadata for @file to disk. If |
| 185 | * set only metadata needed to access modified file data is written. | 196 | * @datasync is set only metadata needed to access modified file data is |
| 197 | * written. | ||
| 186 | * | 198 | * |
| 187 | * In case this function is called from nfsd @file may be %NULL and | 199 | * In case this function is called from nfsd @file may be %NULL and |
| 188 | * only @dentry is set. This can only happen when the filesystem | 200 | * only @dentry is set. This can only happen when the filesystem |
| 189 | * implements the export_operations API. | 201 | * implements the export_operations API. |
| 190 | */ | 202 | */ |
| 191 | int vfs_fsync(struct file *file, struct dentry *dentry, int datasync) | 203 | int vfs_fsync_range(struct file *file, struct dentry *dentry, loff_t start, |
| 204 | loff_t end, int datasync) | ||
| 192 | { | 205 | { |
| 193 | const struct file_operations *fop; | 206 | const struct file_operations *fop; |
| 194 | struct address_space *mapping; | 207 | struct address_space *mapping; |
| @@ -212,7 +225,7 @@ int vfs_fsync(struct file *file, struct dentry *dentry, int datasync) | |||
| 212 | goto out; | 225 | goto out; |
| 213 | } | 226 | } |
| 214 | 227 | ||
| 215 | ret = filemap_fdatawrite(mapping); | 228 | ret = filemap_write_and_wait_range(mapping, start, end); |
| 216 | 229 | ||
| 217 | /* | 230 | /* |
| 218 | * We need to protect against concurrent writers, which could cause | 231 | * We need to protect against concurrent writers, which could cause |
| @@ -223,12 +236,29 @@ int vfs_fsync(struct file *file, struct dentry *dentry, int datasync) | |||
| 223 | if (!ret) | 236 | if (!ret) |
| 224 | ret = err; | 237 | ret = err; |
| 225 | mutex_unlock(&mapping->host->i_mutex); | 238 | mutex_unlock(&mapping->host->i_mutex); |
| 226 | err = filemap_fdatawait(mapping); | 239 | |
| 227 | if (!ret) | ||
| 228 | ret = err; | ||
| 229 | out: | 240 | out: |
| 230 | return ret; | 241 | return ret; |
| 231 | } | 242 | } |
| 243 | EXPORT_SYMBOL(vfs_fsync_range); | ||
| 244 | |||
| 245 | /** | ||
| 246 | * vfs_fsync - perform a fsync or fdatasync on a file | ||
| 247 | * @file: file to sync | ||
| 248 | * @dentry: dentry of @file | ||
| 249 | * @datasync: only perform a fdatasync operation | ||
| 250 | * | ||
| 251 | * Write back data and metadata for @file to disk. If @datasync is | ||
| 252 | * set only metadata needed to access modified file data is written. | ||
| 253 | * | ||
| 254 | * In case this function is called from nfsd @file may be %NULL and | ||
| 255 | * only @dentry is set. This can only happen when the filesystem | ||
| 256 | * implements the export_operations API. | ||
| 257 | */ | ||
| 258 | int vfs_fsync(struct file *file, struct dentry *dentry, int datasync) | ||
| 259 | { | ||
| 260 | return vfs_fsync_range(file, dentry, 0, LLONG_MAX, datasync); | ||
| 261 | } | ||
| 232 | EXPORT_SYMBOL(vfs_fsync); | 262 | EXPORT_SYMBOL(vfs_fsync); |
| 233 | 263 | ||
| 234 | static int do_fsync(unsigned int fd, int datasync) | 264 | static int do_fsync(unsigned int fd, int datasync) |
| @@ -254,6 +284,23 @@ SYSCALL_DEFINE1(fdatasync, unsigned int, fd) | |||
| 254 | return do_fsync(fd, 1); | 284 | return do_fsync(fd, 1); |
| 255 | } | 285 | } |
| 256 | 286 | ||
| 287 | /** | ||
| 288 | * generic_write_sync - perform syncing after a write if file / inode is sync | ||
| 289 | * @file: file to which the write happened | ||
| 290 | * @pos: offset where the write started | ||
| 291 | * @count: length of the write | ||
| 292 | * | ||
| 293 | * This is just a simple wrapper about our general syncing function. | ||
| 294 | */ | ||
| 295 | int generic_write_sync(struct file *file, loff_t pos, loff_t count) | ||
| 296 | { | ||
| 297 | if (!(file->f_flags & O_SYNC) && !IS_SYNC(file->f_mapping->host)) | ||
| 298 | return 0; | ||
| 299 | return vfs_fsync_range(file, file->f_path.dentry, pos, | ||
| 300 | pos + count - 1, 1); | ||
| 301 | } | ||
| 302 | EXPORT_SYMBOL(generic_write_sync); | ||
| 303 | |||
| 257 | /* | 304 | /* |
| 258 | * sys_sync_file_range() permits finely controlled syncing over a segment of | 305 | * sys_sync_file_range() permits finely controlled syncing over a segment of |
| 259 | * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is | 306 | * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 14f2d71ea3c..0050fc40e8c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
| @@ -760,6 +760,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 760 | const struct inode_operations sysfs_dir_inode_operations = { | 760 | const struct inode_operations sysfs_dir_inode_operations = { |
| 761 | .lookup = sysfs_lookup, | 761 | .lookup = sysfs_lookup, |
| 762 | .setattr = sysfs_setattr, | 762 | .setattr = sysfs_setattr, |
| 763 | .setxattr = sysfs_setxattr, | ||
| 763 | }; | 764 | }; |
| 764 | 765 | ||
| 765 | static void remove_dir(struct sysfs_dirent *sd) | 766 | static void remove_dir(struct sysfs_dirent *sd) |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 555f0ff988d..e28cecf179f 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
| @@ -18,6 +18,8 @@ | |||
| 18 | #include <linux/capability.h> | 18 | #include <linux/capability.h> |
| 19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
| 20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
| 21 | #include <linux/xattr.h> | ||
| 22 | #include <linux/security.h> | ||
| 21 | #include "sysfs.h" | 23 | #include "sysfs.h" |
| 22 | 24 | ||
| 23 | extern struct super_block * sysfs_sb; | 25 | extern struct super_block * sysfs_sb; |
| @@ -29,12 +31,14 @@ static const struct address_space_operations sysfs_aops = { | |||
| 29 | }; | 31 | }; |
| 30 | 32 | ||
| 31 | static struct backing_dev_info sysfs_backing_dev_info = { | 33 | static struct backing_dev_info sysfs_backing_dev_info = { |
| 34 | .name = "sysfs", | ||
| 32 | .ra_pages = 0, /* No readahead */ | 35 | .ra_pages = 0, /* No readahead */ |
| 33 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, | 36 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, |
| 34 | }; | 37 | }; |
| 35 | 38 | ||
| 36 | static const struct inode_operations sysfs_inode_operations ={ | 39 | static const struct inode_operations sysfs_inode_operations ={ |
| 37 | .setattr = sysfs_setattr, | 40 | .setattr = sysfs_setattr, |
| 41 | .setxattr = sysfs_setxattr, | ||
| 38 | }; | 42 | }; |
| 39 | 43 | ||
| 40 | int __init sysfs_inode_init(void) | 44 | int __init sysfs_inode_init(void) |
| @@ -42,18 +46,37 @@ int __init sysfs_inode_init(void) | |||
| 42 | return bdi_init(&sysfs_backing_dev_info); | 46 | return bdi_init(&sysfs_backing_dev_info); |
| 43 | } | 47 | } |
| 44 | 48 | ||
| 49 | struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | ||
| 50 | { | ||
| 51 | struct sysfs_inode_attrs *attrs; | ||
| 52 | struct iattr *iattrs; | ||
| 53 | |||
| 54 | attrs = kzalloc(sizeof(struct sysfs_inode_attrs), GFP_KERNEL); | ||
| 55 | if (!attrs) | ||
| 56 | return NULL; | ||
| 57 | iattrs = &attrs->ia_iattr; | ||
| 58 | |||
| 59 | /* assign default attributes */ | ||
| 60 | iattrs->ia_mode = sd->s_mode; | ||
| 61 | iattrs->ia_uid = 0; | ||
| 62 | iattrs->ia_gid = 0; | ||
| 63 | iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; | ||
| 64 | |||
| 65 | return attrs; | ||
| 66 | } | ||
| 45 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | 67 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) |
| 46 | { | 68 | { |
| 47 | struct inode * inode = dentry->d_inode; | 69 | struct inode * inode = dentry->d_inode; |
| 48 | struct sysfs_dirent * sd = dentry->d_fsdata; | 70 | struct sysfs_dirent * sd = dentry->d_fsdata; |
| 49 | struct iattr * sd_iattr; | 71 | struct sysfs_inode_attrs *sd_attrs; |
| 72 | struct iattr *iattrs; | ||
| 50 | unsigned int ia_valid = iattr->ia_valid; | 73 | unsigned int ia_valid = iattr->ia_valid; |
| 51 | int error; | 74 | int error; |
| 52 | 75 | ||
| 53 | if (!sd) | 76 | if (!sd) |
| 54 | return -EINVAL; | 77 | return -EINVAL; |
| 55 | 78 | ||
| 56 | sd_iattr = sd->s_iattr; | 79 | sd_attrs = sd->s_iattr; |
| 57 | 80 | ||
| 58 | error = inode_change_ok(inode, iattr); | 81 | error = inode_change_ok(inode, iattr); |
| 59 | if (error) | 82 | if (error) |
| @@ -65,42 +88,77 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | |||
| 65 | if (error) | 88 | if (error) |
| 66 | return error; | 89 | return error; |
| 67 | 90 | ||
| 68 | if (!sd_iattr) { | 91 | if (!sd_attrs) { |
| 69 | /* setting attributes for the first time, allocate now */ | 92 | /* setting attributes for the first time, allocate now */ |
| 70 | sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); | 93 | sd_attrs = sysfs_init_inode_attrs(sd); |
| 71 | if (!sd_iattr) | 94 | if (!sd_attrs) |
| 72 | return -ENOMEM; | 95 | return -ENOMEM; |
| 73 | /* assign default attributes */ | 96 | sd->s_iattr = sd_attrs; |
| 74 | sd_iattr->ia_mode = sd->s_mode; | 97 | } else { |
| 75 | sd_iattr->ia_uid = 0; | 98 | /* attributes were changed at least once in past */ |
| 76 | sd_iattr->ia_gid = 0; | 99 | iattrs = &sd_attrs->ia_iattr; |
| 77 | sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; | 100 | |
| 78 | sd->s_iattr = sd_iattr; | 101 | if (ia_valid & ATTR_UID) |
| 102 | iattrs->ia_uid = iattr->ia_uid; | ||
| 103 | if (ia_valid & ATTR_GID) | ||
| 104 | iattrs->ia_gid = iattr->ia_gid; | ||
| 105 | if (ia_valid & ATTR_ATIME) | ||
| 106 | iattrs->ia_atime = timespec_trunc(iattr->ia_atime, | ||
| 107 | inode->i_sb->s_time_gran); | ||
| 108 | if (ia_valid & ATTR_MTIME) | ||
| 109 | iattrs->ia_mtime = timespec_trunc(iattr->ia_mtime, | ||
| 110 | inode->i_sb->s_time_gran); | ||
| 111 | if (ia_valid & ATTR_CTIME) | ||
| 112 | iattrs->ia_ctime = timespec_trunc(iattr->ia_ctime, | ||
| 113 | inode->i_sb->s_time_gran); | ||
| 114 | if (ia_valid & ATTR_MODE) { | ||
| 115 | umode_t mode = iattr->ia_mode; | ||
| 116 | |||
| 117 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
| 118 | mode &= ~S_ISGID; | ||
| 119 | iattrs->ia_mode = sd->s_mode = mode; | ||
| 120 | } | ||
| 79 | } | 121 | } |
| 122 | return error; | ||
| 123 | } | ||
| 80 | 124 | ||
| 81 | /* attributes were changed atleast once in past */ | 125 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
| 82 | 126 | size_t size, int flags) | |
| 83 | if (ia_valid & ATTR_UID) | 127 | { |
| 84 | sd_iattr->ia_uid = iattr->ia_uid; | 128 | struct sysfs_dirent *sd = dentry->d_fsdata; |
| 85 | if (ia_valid & ATTR_GID) | 129 | struct sysfs_inode_attrs *iattrs; |
| 86 | sd_iattr->ia_gid = iattr->ia_gid; | 130 | void *secdata; |
| 87 | if (ia_valid & ATTR_ATIME) | 131 | int error; |
| 88 | sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime, | 132 | u32 secdata_len = 0; |
| 89 | inode->i_sb->s_time_gran); | 133 | |
| 90 | if (ia_valid & ATTR_MTIME) | 134 | if (!sd) |
| 91 | sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime, | 135 | return -EINVAL; |
| 92 | inode->i_sb->s_time_gran); | 136 | if (!sd->s_iattr) |
| 93 | if (ia_valid & ATTR_CTIME) | 137 | sd->s_iattr = sysfs_init_inode_attrs(sd); |
| 94 | sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime, | 138 | if (!sd->s_iattr) |
| 95 | inode->i_sb->s_time_gran); | 139 | return -ENOMEM; |
| 96 | if (ia_valid & ATTR_MODE) { | 140 | |
| 97 | umode_t mode = iattr->ia_mode; | 141 | iattrs = sd->s_iattr; |
| 98 | 142 | ||
| 99 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | 143 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { |
| 100 | mode &= ~S_ISGID; | 144 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; |
| 101 | sd_iattr->ia_mode = sd->s_mode = mode; | 145 | error = security_inode_setsecurity(dentry->d_inode, suffix, |
| 102 | } | 146 | value, size, flags); |
| 147 | if (error) | ||
| 148 | goto out; | ||
| 149 | error = security_inode_getsecctx(dentry->d_inode, | ||
| 150 | &secdata, &secdata_len); | ||
| 151 | if (error) | ||
| 152 | goto out; | ||
| 153 | if (iattrs->ia_secdata) | ||
| 154 | security_release_secctx(iattrs->ia_secdata, | ||
| 155 | iattrs->ia_secdata_len); | ||
| 156 | iattrs->ia_secdata = secdata; | ||
| 157 | iattrs->ia_secdata_len = secdata_len; | ||
| 103 | 158 | ||
| 159 | } else | ||
| 160 | return -EINVAL; | ||
| 161 | out: | ||
| 104 | return error; | 162 | return error; |
| 105 | } | 163 | } |
| 106 | 164 | ||
| @@ -146,6 +204,7 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd) | |||
| 146 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | 204 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
| 147 | { | 205 | { |
| 148 | struct bin_attribute *bin_attr; | 206 | struct bin_attribute *bin_attr; |
| 207 | struct sysfs_inode_attrs *iattrs; | ||
| 149 | 208 | ||
| 150 | inode->i_private = sysfs_get(sd); | 209 | inode->i_private = sysfs_get(sd); |
| 151 | inode->i_mapping->a_ops = &sysfs_aops; | 210 | inode->i_mapping->a_ops = &sysfs_aops; |
| @@ -154,16 +213,20 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | |||
| 154 | inode->i_ino = sd->s_ino; | 213 | inode->i_ino = sd->s_ino; |
| 155 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); | 214 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); |
| 156 | 215 | ||
| 157 | if (sd->s_iattr) { | 216 | iattrs = sd->s_iattr; |
| 217 | if (iattrs) { | ||
| 158 | /* sysfs_dirent has non-default attributes | 218 | /* sysfs_dirent has non-default attributes |
| 159 | * get them for the new inode from persistent copy | 219 | * get them for the new inode from persistent copy |
| 160 | * in sysfs_dirent | 220 | * in sysfs_dirent |
| 161 | */ | 221 | */ |
| 162 | set_inode_attr(inode, sd->s_iattr); | 222 | set_inode_attr(inode, &iattrs->ia_iattr); |
| 223 | if (iattrs->ia_secdata) | ||
| 224 | security_inode_notifysecctx(inode, | ||
| 225 | iattrs->ia_secdata, | ||
| 226 | iattrs->ia_secdata_len); | ||
| 163 | } else | 227 | } else |
| 164 | set_default_inode_attr(inode, sd->s_mode); | 228 | set_default_inode_attr(inode, sd->s_mode); |
| 165 | 229 | ||
| 166 | |||
| 167 | /* initialize inode according to type */ | 230 | /* initialize inode according to type */ |
| 168 | switch (sysfs_type(sd)) { | 231 | switch (sysfs_type(sd)) { |
| 169 | case SYSFS_DIR: | 232 | case SYSFS_DIR: |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 1d897ad808e..c5081ad7702 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/kobject.h> | 16 | #include <linux/kobject.h> |
| 17 | #include <linux/namei.h> | 17 | #include <linux/namei.h> |
| 18 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
| 19 | #include <linux/security.h> | ||
| 19 | 20 | ||
| 20 | #include "sysfs.h" | 21 | #include "sysfs.h" |
| 21 | 22 | ||
| @@ -209,6 +210,7 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co | |||
| 209 | } | 210 | } |
| 210 | 211 | ||
| 211 | const struct inode_operations sysfs_symlink_inode_operations = { | 212 | const struct inode_operations sysfs_symlink_inode_operations = { |
| 213 | .setxattr = sysfs_setxattr, | ||
| 212 | .readlink = generic_readlink, | 214 | .readlink = generic_readlink, |
| 213 | .follow_link = sysfs_follow_link, | 215 | .follow_link = sysfs_follow_link, |
| 214 | .put_link = sysfs_put_link, | 216 | .put_link = sysfs_put_link, |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3fa0d98481e..af4c4e7482a 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
| @@ -8,6 +8,8 @@ | |||
| 8 | * This file is released under the GPLv2. | 8 | * This file is released under the GPLv2. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/fs.h> | ||
| 12 | |||
| 11 | struct sysfs_open_dirent; | 13 | struct sysfs_open_dirent; |
| 12 | 14 | ||
| 13 | /* type-specific structures for sysfs_dirent->s_* union members */ | 15 | /* type-specific structures for sysfs_dirent->s_* union members */ |
| @@ -31,6 +33,12 @@ struct sysfs_elem_bin_attr { | |||
| 31 | struct hlist_head buffers; | 33 | struct hlist_head buffers; |
| 32 | }; | 34 | }; |
| 33 | 35 | ||
| 36 | struct sysfs_inode_attrs { | ||
| 37 | struct iattr ia_iattr; | ||
| 38 | void *ia_secdata; | ||
| 39 | u32 ia_secdata_len; | ||
| 40 | }; | ||
| 41 | |||
| 34 | /* | 42 | /* |
| 35 | * sysfs_dirent - the building block of sysfs hierarchy. Each and | 43 | * sysfs_dirent - the building block of sysfs hierarchy. Each and |
| 36 | * every sysfs node is represented by single sysfs_dirent. | 44 | * every sysfs node is represented by single sysfs_dirent. |
| @@ -56,7 +64,7 @@ struct sysfs_dirent { | |||
| 56 | unsigned int s_flags; | 64 | unsigned int s_flags; |
| 57 | ino_t s_ino; | 65 | ino_t s_ino; |
| 58 | umode_t s_mode; | 66 | umode_t s_mode; |
| 59 | struct iattr *s_iattr; | 67 | struct sysfs_inode_attrs *s_iattr; |
| 60 | }; | 68 | }; |
| 61 | 69 | ||
| 62 | #define SD_DEACTIVATED_BIAS INT_MIN | 70 | #define SD_DEACTIVATED_BIAS INT_MIN |
| @@ -148,6 +156,8 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) | |||
| 148 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); | 156 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); |
| 149 | void sysfs_delete_inode(struct inode *inode); | 157 | void sysfs_delete_inode(struct inode *inode); |
| 150 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | 158 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); |
| 159 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | ||
| 160 | size_t size, int flags); | ||
| 151 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); | 161 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); |
| 152 | int sysfs_inode_init(void); | 162 | int sysfs_inode_init(void); |
| 153 | 163 | ||
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c index eaf6d891d46..ee1ce68fd98 100644 --- a/fs/ubifs/budget.c +++ b/fs/ubifs/budget.c | |||
| @@ -54,41 +54,15 @@ | |||
| 54 | * @nr_to_write: how many dirty pages to write-back | 54 | * @nr_to_write: how many dirty pages to write-back |
| 55 | * | 55 | * |
| 56 | * This function shrinks UBIFS liability by means of writing back some amount | 56 | * This function shrinks UBIFS liability by means of writing back some amount |
| 57 | * of dirty inodes and their pages. Returns the amount of pages which were | 57 | * of dirty inodes and their pages. |
| 58 | * written back. The returned value does not include dirty inodes which were | ||
| 59 | * synchronized. | ||
| 60 | * | 58 | * |
| 61 | * Note, this function synchronizes even VFS inodes which are locked | 59 | * Note, this function synchronizes even VFS inodes which are locked |
| 62 | * (@i_mutex) by the caller of the budgeting function, because write-back does | 60 | * (@i_mutex) by the caller of the budgeting function, because write-back does |
| 63 | * not touch @i_mutex. | 61 | * not touch @i_mutex. |
| 64 | */ | 62 | */ |
| 65 | static int shrink_liability(struct ubifs_info *c, int nr_to_write) | 63 | static void shrink_liability(struct ubifs_info *c, int nr_to_write) |
| 66 | { | 64 | { |
| 67 | int nr_written; | 65 | writeback_inodes_sb(c->vfs_sb); |
| 68 | struct writeback_control wbc = { | ||
| 69 | .sync_mode = WB_SYNC_NONE, | ||
| 70 | .range_end = LLONG_MAX, | ||
| 71 | .nr_to_write = nr_to_write, | ||
| 72 | }; | ||
| 73 | |||
| 74 | generic_sync_sb_inodes(c->vfs_sb, &wbc); | ||
| 75 | nr_written = nr_to_write - wbc.nr_to_write; | ||
| 76 | |||
| 77 | if (!nr_written) { | ||
| 78 | /* | ||
| 79 | * Re-try again but wait on pages/inodes which are being | ||
| 80 | * written-back concurrently (e.g., by pdflush). | ||
| 81 | */ | ||
| 82 | memset(&wbc, 0, sizeof(struct writeback_control)); | ||
| 83 | wbc.sync_mode = WB_SYNC_ALL; | ||
| 84 | wbc.range_end = LLONG_MAX; | ||
| 85 | wbc.nr_to_write = nr_to_write; | ||
| 86 | generic_sync_sb_inodes(c->vfs_sb, &wbc); | ||
| 87 | nr_written = nr_to_write - wbc.nr_to_write; | ||
| 88 | } | ||
| 89 | |||
| 90 | dbg_budg("%d pages were written back", nr_written); | ||
| 91 | return nr_written; | ||
| 92 | } | 66 | } |
| 93 | 67 | ||
| 94 | /** | 68 | /** |
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 26d2e0d8046..c4af069df1a 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
| @@ -438,12 +438,6 @@ static int ubifs_sync_fs(struct super_block *sb, int wait) | |||
| 438 | { | 438 | { |
| 439 | int i, err; | 439 | int i, err; |
| 440 | struct ubifs_info *c = sb->s_fs_info; | 440 | struct ubifs_info *c = sb->s_fs_info; |
| 441 | struct writeback_control wbc = { | ||
| 442 | .sync_mode = WB_SYNC_ALL, | ||
| 443 | .range_start = 0, | ||
| 444 | .range_end = LLONG_MAX, | ||
| 445 | .nr_to_write = LONG_MAX, | ||
| 446 | }; | ||
| 447 | 441 | ||
| 448 | /* | 442 | /* |
| 449 | * Zero @wait is just an advisory thing to help the file system shove | 443 | * Zero @wait is just an advisory thing to help the file system shove |
| @@ -462,7 +456,7 @@ static int ubifs_sync_fs(struct super_block *sb, int wait) | |||
| 462 | * the user be able to get more accurate results of 'statfs()' after | 456 | * the user be able to get more accurate results of 'statfs()' after |
| 463 | * they synchronize the file system. | 457 | * they synchronize the file system. |
| 464 | */ | 458 | */ |
| 465 | generic_sync_sb_inodes(sb, &wbc); | 459 | sync_inodes_sb(sb); |
| 466 | 460 | ||
| 467 | /* | 461 | /* |
| 468 | * Synchronize write buffers, because 'ubifs_run_commit()' does not | 462 | * Synchronize write buffers, because 'ubifs_run_commit()' does not |
| @@ -1971,6 +1965,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1971 | * | 1965 | * |
| 1972 | * Read-ahead will be disabled because @c->bdi.ra_pages is 0. | 1966 | * Read-ahead will be disabled because @c->bdi.ra_pages is 0. |
| 1973 | */ | 1967 | */ |
| 1968 | c->bdi.name = "ubifs", | ||
| 1974 | c->bdi.capabilities = BDI_CAP_MAP_COPY; | 1969 | c->bdi.capabilities = BDI_CAP_MAP_COPY; |
| 1975 | c->bdi.unplug_io_fn = default_unplug_io_fn; | 1970 | c->bdi.unplug_io_fn = default_unplug_io_fn; |
| 1976 | err = bdi_init(&c->bdi); | 1971 | err = bdi_init(&c->bdi); |
| @@ -1985,6 +1980,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1985 | if (err) | 1980 | if (err) |
| 1986 | goto out_bdi; | 1981 | goto out_bdi; |
| 1987 | 1982 | ||
| 1983 | sb->s_bdi = &c->bdi; | ||
| 1988 | sb->s_fs_info = c; | 1984 | sb->s_fs_info = c; |
| 1989 | sb->s_magic = UBIFS_SUPER_MAGIC; | 1985 | sb->s_magic = UBIFS_SUPER_MAGIC; |
| 1990 | sb->s_blocksize = UBIFS_BLOCK_SIZE; | 1986 | sb->s_blocksize = UBIFS_BLOCK_SIZE; |
diff --git a/fs/udf/directory.c b/fs/udf/directory.c index 1d2c570704c..2ffdb6733af 100644 --- a/fs/udf/directory.c +++ b/fs/udf/directory.c | |||
| @@ -18,59 +18,6 @@ | |||
| 18 | #include <linux/string.h> | 18 | #include <linux/string.h> |
| 19 | #include <linux/buffer_head.h> | 19 | #include <linux/buffer_head.h> |
| 20 | 20 | ||
| 21 | #if 0 | ||
| 22 | static uint8_t *udf_filead_read(struct inode *dir, uint8_t *tmpad, | ||
| 23 | uint8_t ad_size, struct kernel_lb_addr fe_loc, | ||
| 24 | int *pos, int *offset, struct buffer_head **bh, | ||
| 25 | int *error) | ||
| 26 | { | ||
| 27 | int loffset = *offset; | ||
| 28 | int block; | ||
| 29 | uint8_t *ad; | ||
| 30 | int remainder; | ||
| 31 | |||
| 32 | *error = 0; | ||
| 33 | |||
| 34 | ad = (uint8_t *)(*bh)->b_data + *offset; | ||
| 35 | *offset += ad_size; | ||
| 36 | |||
| 37 | if (!ad) { | ||
| 38 | brelse(*bh); | ||
| 39 | *error = 1; | ||
| 40 | return NULL; | ||
| 41 | } | ||
| 42 | |||
| 43 | if (*offset == dir->i_sb->s_blocksize) { | ||
| 44 | brelse(*bh); | ||
| 45 | block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos); | ||
| 46 | if (!block) | ||
| 47 | return NULL; | ||
| 48 | *bh = udf_tread(dir->i_sb, block); | ||
| 49 | if (!*bh) | ||
| 50 | return NULL; | ||
| 51 | } else if (*offset > dir->i_sb->s_blocksize) { | ||
| 52 | ad = tmpad; | ||
| 53 | |||
| 54 | remainder = dir->i_sb->s_blocksize - loffset; | ||
| 55 | memcpy((uint8_t *)ad, (*bh)->b_data + loffset, remainder); | ||
| 56 | |||
| 57 | brelse(*bh); | ||
| 58 | block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos); | ||
| 59 | if (!block) | ||
| 60 | return NULL; | ||
| 61 | (*bh) = udf_tread(dir->i_sb, block); | ||
| 62 | if (!*bh) | ||
| 63 | return NULL; | ||
| 64 | |||
| 65 | memcpy((uint8_t *)ad + remainder, (*bh)->b_data, | ||
| 66 | ad_size - remainder); | ||
| 67 | *offset = ad_size - remainder; | ||
| 68 | } | ||
| 69 | |||
| 70 | return ad; | ||
| 71 | } | ||
| 72 | #endif | ||
| 73 | |||
| 74 | struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos, | 21 | struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos, |
| 75 | struct udf_fileident_bh *fibh, | 22 | struct udf_fileident_bh *fibh, |
| 76 | struct fileIdentDesc *cfi, | 23 | struct fileIdentDesc *cfi, |
| @@ -248,39 +195,6 @@ struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset) | |||
| 248 | return fi; | 195 | return fi; |
| 249 | } | 196 | } |
| 250 | 197 | ||
| 251 | #if 0 | ||
| 252 | static struct extent_ad *udf_get_fileextent(void *buffer, int bufsize, int *offset) | ||
| 253 | { | ||
| 254 | struct extent_ad *ext; | ||
| 255 | struct fileEntry *fe; | ||
| 256 | uint8_t *ptr; | ||
| 257 | |||
| 258 | if ((!buffer) || (!offset)) { | ||
| 259 | printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n"); | ||
| 260 | return NULL; | ||
| 261 | } | ||
| 262 | |||
| 263 | fe = (struct fileEntry *)buffer; | ||
| 264 | |||
| 265 | if (fe->descTag.tagIdent != cpu_to_le16(TAG_IDENT_FE)) { | ||
| 266 | udf_debug("0x%x != TAG_IDENT_FE\n", | ||
| 267 | le16_to_cpu(fe->descTag.tagIdent)); | ||
| 268 | return NULL; | ||
| 269 | } | ||
| 270 | |||
| 271 | ptr = (uint8_t *)(fe->extendedAttr) + | ||
| 272 | le32_to_cpu(fe->lengthExtendedAttr); | ||
| 273 | |||
| 274 | if ((*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs))) | ||
| 275 | ptr += *offset; | ||
| 276 | |||
| 277 | ext = (struct extent_ad *)ptr; | ||
| 278 | |||
| 279 | *offset = *offset + sizeof(struct extent_ad); | ||
| 280 | return ext; | ||
| 281 | } | ||
| 282 | #endif | ||
| 283 | |||
| 284 | struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset, | 198 | struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset, |
| 285 | int inc) | 199 | int inc) |
| 286 | { | 200 | { |
diff --git a/fs/udf/file.c b/fs/udf/file.c index 7464305382b..b80cbd78833 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c | |||
| @@ -193,9 +193,11 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
| 193 | static int udf_release_file(struct inode *inode, struct file *filp) | 193 | static int udf_release_file(struct inode *inode, struct file *filp) |
| 194 | { | 194 | { |
| 195 | if (filp->f_mode & FMODE_WRITE) { | 195 | if (filp->f_mode & FMODE_WRITE) { |
| 196 | mutex_lock(&inode->i_mutex); | ||
| 196 | lock_kernel(); | 197 | lock_kernel(); |
| 197 | udf_discard_prealloc(inode); | 198 | udf_discard_prealloc(inode); |
| 198 | unlock_kernel(); | 199 | unlock_kernel(); |
| 200 | mutex_unlock(&inode->i_mutex); | ||
| 199 | } | 201 | } |
| 200 | return 0; | 202 | return 0; |
| 201 | } | 203 | } |
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index e7533f78563..6d24c2c63f9 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c | |||
| @@ -90,19 +90,16 @@ no_delete: | |||
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | /* | 92 | /* |
| 93 | * If we are going to release inode from memory, we discard preallocation and | 93 | * If we are going to release inode from memory, we truncate last inode extent |
| 94 | * truncate last inode extent to proper length. We could use drop_inode() but | 94 | * to proper length. We could use drop_inode() but it's called under inode_lock |
| 95 | * it's called under inode_lock and thus we cannot mark inode dirty there. We | 95 | * and thus we cannot mark inode dirty there. We use clear_inode() but we have |
| 96 | * use clear_inode() but we have to make sure to write inode as it's not written | 96 | * to make sure to write inode as it's not written automatically. |
| 97 | * automatically. | ||
| 98 | */ | 97 | */ |
| 99 | void udf_clear_inode(struct inode *inode) | 98 | void udf_clear_inode(struct inode *inode) |
| 100 | { | 99 | { |
| 101 | struct udf_inode_info *iinfo; | 100 | struct udf_inode_info *iinfo; |
| 102 | if (!(inode->i_sb->s_flags & MS_RDONLY)) { | 101 | if (!(inode->i_sb->s_flags & MS_RDONLY)) { |
| 103 | lock_kernel(); | 102 | lock_kernel(); |
| 104 | /* Discard preallocation for directories, symlinks, etc. */ | ||
| 105 | udf_discard_prealloc(inode); | ||
| 106 | udf_truncate_tail_extent(inode); | 103 | udf_truncate_tail_extent(inode); |
| 107 | unlock_kernel(); | 104 | unlock_kernel(); |
| 108 | write_inode_now(inode, 0); | 105 | write_inode_now(inode, 0); |
| @@ -664,8 +661,12 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block, | |||
| 664 | udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum); | 661 | udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum); |
| 665 | 662 | ||
| 666 | #ifdef UDF_PREALLOCATE | 663 | #ifdef UDF_PREALLOCATE |
| 667 | /* preallocate blocks */ | 664 | /* We preallocate blocks only for regular files. It also makes sense |
| 668 | udf_prealloc_extents(inode, c, lastblock, laarr, &endnum); | 665 | * for directories but there's a problem when to drop the |
| 666 | * preallocation. We might use some delayed work for that but I feel | ||
| 667 | * it's overengineering for a filesystem like UDF. */ | ||
| 668 | if (S_ISREG(inode->i_mode)) | ||
| 669 | udf_prealloc_extents(inode, c, lastblock, laarr, &endnum); | ||
| 669 | #endif | 670 | #endif |
| 670 | 671 | ||
| 671 | /* merge any continuous blocks in laarr */ | 672 | /* merge any continuous blocks in laarr */ |
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c index 1b88fd5df05..43e24a3b8e1 100644 --- a/fs/udf/lowlevel.c +++ b/fs/udf/lowlevel.c | |||
| @@ -36,14 +36,10 @@ unsigned int udf_get_last_session(struct super_block *sb) | |||
| 36 | ms_info.addr_format = CDROM_LBA; | 36 | ms_info.addr_format = CDROM_LBA; |
| 37 | i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long)&ms_info); | 37 | i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long)&ms_info); |
| 38 | 38 | ||
| 39 | #define WE_OBEY_THE_WRITTEN_STANDARDS 1 | ||
| 40 | |||
| 41 | if (i == 0) { | 39 | if (i == 0) { |
| 42 | udf_debug("XA disk: %s, vol_desc_start=%d\n", | 40 | udf_debug("XA disk: %s, vol_desc_start=%d\n", |
| 43 | (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba); | 41 | (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba); |
| 44 | #if WE_OBEY_THE_WRITTEN_STANDARDS | ||
| 45 | if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */ | 42 | if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */ |
| 46 | #endif | ||
| 47 | vol_desc_start = ms_info.addr.lba; | 43 | vol_desc_start = ms_info.addr.lba; |
| 48 | } else { | 44 | } else { |
| 49 | udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i); | 45 | udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i); |
diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 6a29fa34c47..21dad8c608f 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c | |||
| @@ -943,7 +943,6 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
| 943 | pc->componentType = 1; | 943 | pc->componentType = 1; |
| 944 | pc->lengthComponentIdent = 0; | 944 | pc->lengthComponentIdent = 0; |
| 945 | pc->componentFileVersionNum = 0; | 945 | pc->componentFileVersionNum = 0; |
| 946 | pc += sizeof(struct pathComponent); | ||
| 947 | elen += sizeof(struct pathComponent); | 946 | elen += sizeof(struct pathComponent); |
| 948 | } | 947 | } |
| 949 | 948 | ||
diff --git a/fs/xattr.c b/fs/xattr.c index 1c3d0af59dd..6d4f6d3449f 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
| @@ -66,22 +66,28 @@ xattr_permission(struct inode *inode, const char *name, int mask) | |||
| 66 | return inode_permission(inode, mask); | 66 | return inode_permission(inode, mask); |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | int | 69 | /** |
| 70 | vfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 70 | * __vfs_setxattr_noperm - perform setxattr operation without performing |
| 71 | size_t size, int flags) | 71 | * permission checks. |
| 72 | * | ||
| 73 | * @dentry - object to perform setxattr on | ||
| 74 | * @name - xattr name to set | ||
| 75 | * @value - value to set @name to | ||
| 76 | * @size - size of @value | ||
| 77 | * @flags - flags to pass into filesystem operations | ||
| 78 | * | ||
| 79 | * returns the result of the internal setxattr or setsecurity operations. | ||
| 80 | * | ||
| 81 | * This function requires the caller to lock the inode's i_mutex before it | ||
| 82 | * is executed. It also assumes that the caller will make the appropriate | ||
| 83 | * permission checks. | ||
| 84 | */ | ||
| 85 | int __vfs_setxattr_noperm(struct dentry *dentry, const char *name, | ||
| 86 | const void *value, size_t size, int flags) | ||
| 72 | { | 87 | { |
| 73 | struct inode *inode = dentry->d_inode; | 88 | struct inode *inode = dentry->d_inode; |
| 74 | int error; | 89 | int error = -EOPNOTSUPP; |
| 75 | |||
| 76 | error = xattr_permission(inode, name, MAY_WRITE); | ||
| 77 | if (error) | ||
| 78 | return error; | ||
| 79 | 90 | ||
| 80 | mutex_lock(&inode->i_mutex); | ||
| 81 | error = security_inode_setxattr(dentry, name, value, size, flags); | ||
| 82 | if (error) | ||
| 83 | goto out; | ||
| 84 | error = -EOPNOTSUPP; | ||
| 85 | if (inode->i_op->setxattr) { | 91 | if (inode->i_op->setxattr) { |
| 86 | error = inode->i_op->setxattr(dentry, name, value, size, flags); | 92 | error = inode->i_op->setxattr(dentry, name, value, size, flags); |
| 87 | if (!error) { | 93 | if (!error) { |
| @@ -97,6 +103,29 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value, | |||
| 97 | if (!error) | 103 | if (!error) |
| 98 | fsnotify_xattr(dentry); | 104 | fsnotify_xattr(dentry); |
| 99 | } | 105 | } |
| 106 | |||
| 107 | return error; | ||
| 108 | } | ||
| 109 | |||
| 110 | |||
| 111 | int | ||
| 112 | vfs_setxattr(struct dentry *dentry, const char *name, const void *value, | ||
| 113 | size_t size, int flags) | ||
| 114 | { | ||
| 115 | struct inode *inode = dentry->d_inode; | ||
| 116 | int error; | ||
| 117 | |||
| 118 | error = xattr_permission(inode, name, MAY_WRITE); | ||
| 119 | if (error) | ||
| 120 | return error; | ||
| 121 | |||
| 122 | mutex_lock(&inode->i_mutex); | ||
| 123 | error = security_inode_setxattr(dentry, name, value, size, flags); | ||
| 124 | if (error) | ||
| 125 | goto out; | ||
| 126 | |||
| 127 | error = __vfs_setxattr_noperm(dentry, name, value, size, flags); | ||
| 128 | |||
| 100 | out: | 129 | out: |
| 101 | mutex_unlock(&inode->i_mutex); | 130 | mutex_unlock(&inode->i_mutex); |
| 102 | return error; | 131 | return error; |
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index aecf2519db7..d5e5559e31d 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
| @@ -216,7 +216,6 @@ xfs_setfilesize( | |||
| 216 | if (ip->i_d.di_size < isize) { | 216 | if (ip->i_d.di_size < isize) { |
| 217 | ip->i_d.di_size = isize; | 217 | ip->i_d.di_size = isize; |
| 218 | ip->i_update_core = 1; | 218 | ip->i_update_core = 1; |
| 219 | ip->i_update_size = 1; | ||
| 220 | xfs_mark_inode_dirty_sync(ip); | 219 | xfs_mark_inode_dirty_sync(ip); |
| 221 | } | 220 | } |
| 222 | 221 | ||
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 0542fd50764..988d8f87bc0 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
| @@ -172,12 +172,21 @@ xfs_file_release( | |||
| 172 | */ | 172 | */ |
| 173 | STATIC int | 173 | STATIC int |
| 174 | xfs_file_fsync( | 174 | xfs_file_fsync( |
| 175 | struct file *filp, | 175 | struct file *file, |
| 176 | struct dentry *dentry, | 176 | struct dentry *dentry, |
| 177 | int datasync) | 177 | int datasync) |
| 178 | { | 178 | { |
| 179 | xfs_iflags_clear(XFS_I(dentry->d_inode), XFS_ITRUNCATED); | 179 | struct inode *inode = dentry->d_inode; |
| 180 | return -xfs_fsync(XFS_I(dentry->d_inode)); | 180 | struct xfs_inode *ip = XFS_I(inode); |
| 181 | int error; | ||
| 182 | |||
| 183 | /* capture size updates in I/O completion before writing the inode. */ | ||
| 184 | error = filemap_fdatawait(inode->i_mapping); | ||
| 185 | if (error) | ||
| 186 | return error; | ||
| 187 | |||
| 188 | xfs_iflags_clear(ip, XFS_ITRUNCATED); | ||
| 189 | return -xfs_fsync(ip); | ||
| 181 | } | 190 | } |
| 182 | 191 | ||
| 183 | STATIC int | 192 | STATIC int |
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index 0882d166239..eafcc7c1870 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c | |||
| @@ -619,7 +619,7 @@ xfs_file_compat_ioctl( | |||
| 619 | case XFS_IOC_GETVERSION_32: | 619 | case XFS_IOC_GETVERSION_32: |
| 620 | cmd = _NATIVE_IOC(cmd, long); | 620 | cmd = _NATIVE_IOC(cmd, long); |
| 621 | return xfs_file_ioctl(filp, cmd, p); | 621 | return xfs_file_ioctl(filp, cmd, p); |
| 622 | case XFS_IOC_SWAPEXT: { | 622 | case XFS_IOC_SWAPEXT_32: { |
| 623 | struct xfs_swapext sxp; | 623 | struct xfs_swapext sxp; |
| 624 | struct compat_xfs_swapext __user *sxu = arg; | 624 | struct compat_xfs_swapext __user *sxu = arg; |
| 625 | 625 | ||
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 8070b34cc28..da0159d99f8 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c | |||
| @@ -43,7 +43,6 @@ | |||
| 43 | #include "xfs_error.h" | 43 | #include "xfs_error.h" |
| 44 | #include "xfs_itable.h" | 44 | #include "xfs_itable.h" |
| 45 | #include "xfs_rw.h" | 45 | #include "xfs_rw.h" |
| 46 | #include "xfs_acl.h" | ||
| 47 | #include "xfs_attr.h" | 46 | #include "xfs_attr.h" |
| 48 | #include "xfs_buf_item.h" | 47 | #include "xfs_buf_item.h" |
| 49 | #include "xfs_utils.h" | 48 | #include "xfs_utils.h" |
| @@ -485,14 +484,6 @@ xfs_vn_put_link( | |||
| 485 | } | 484 | } |
| 486 | 485 | ||
| 487 | STATIC int | 486 | STATIC int |
| 488 | xfs_vn_permission( | ||
| 489 | struct inode *inode, | ||
| 490 | int mask) | ||
| 491 | { | ||
| 492 | return generic_permission(inode, mask, xfs_check_acl); | ||
| 493 | } | ||
| 494 | |||
| 495 | STATIC int | ||
| 496 | xfs_vn_getattr( | 487 | xfs_vn_getattr( |
| 497 | struct vfsmount *mnt, | 488 | struct vfsmount *mnt, |
| 498 | struct dentry *dentry, | 489 | struct dentry *dentry, |
| @@ -696,7 +687,7 @@ xfs_vn_fiemap( | |||
| 696 | } | 687 | } |
| 697 | 688 | ||
| 698 | static const struct inode_operations xfs_inode_operations = { | 689 | static const struct inode_operations xfs_inode_operations = { |
| 699 | .permission = xfs_vn_permission, | 690 | .check_acl = xfs_check_acl, |
| 700 | .truncate = xfs_vn_truncate, | 691 | .truncate = xfs_vn_truncate, |
| 701 | .getattr = xfs_vn_getattr, | 692 | .getattr = xfs_vn_getattr, |
| 702 | .setattr = xfs_vn_setattr, | 693 | .setattr = xfs_vn_setattr, |
| @@ -724,7 +715,7 @@ static const struct inode_operations xfs_dir_inode_operations = { | |||
| 724 | .rmdir = xfs_vn_unlink, | 715 | .rmdir = xfs_vn_unlink, |
| 725 | .mknod = xfs_vn_mknod, | 716 | .mknod = xfs_vn_mknod, |
| 726 | .rename = xfs_vn_rename, | 717 | .rename = xfs_vn_rename, |
| 727 | .permission = xfs_vn_permission, | 718 | .check_acl = xfs_check_acl, |
| 728 | .getattr = xfs_vn_getattr, | 719 | .getattr = xfs_vn_getattr, |
| 729 | .setattr = xfs_vn_setattr, | 720 | .setattr = xfs_vn_setattr, |
| 730 | .setxattr = generic_setxattr, | 721 | .setxattr = generic_setxattr, |
| @@ -749,7 +740,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { | |||
| 749 | .rmdir = xfs_vn_unlink, | 740 | .rmdir = xfs_vn_unlink, |
| 750 | .mknod = xfs_vn_mknod, | 741 | .mknod = xfs_vn_mknod, |
| 751 | .rename = xfs_vn_rename, | 742 | .rename = xfs_vn_rename, |
| 752 | .permission = xfs_vn_permission, | 743 | .check_acl = xfs_check_acl, |
| 753 | .getattr = xfs_vn_getattr, | 744 | .getattr = xfs_vn_getattr, |
| 754 | .setattr = xfs_vn_setattr, | 745 | .setattr = xfs_vn_setattr, |
| 755 | .setxattr = generic_setxattr, | 746 | .setxattr = generic_setxattr, |
| @@ -762,7 +753,7 @@ static const struct inode_operations xfs_symlink_inode_operations = { | |||
| 762 | .readlink = generic_readlink, | 753 | .readlink = generic_readlink, |
| 763 | .follow_link = xfs_vn_follow_link, | 754 | .follow_link = xfs_vn_follow_link, |
| 764 | .put_link = xfs_vn_put_link, | 755 | .put_link = xfs_vn_put_link, |
| 765 | .permission = xfs_vn_permission, | 756 | .check_acl = xfs_check_acl, |
| 766 | .getattr = xfs_vn_getattr, | 757 | .getattr = xfs_vn_getattr, |
| 767 | .setattr = xfs_vn_setattr, | 758 | .setattr = xfs_vn_setattr, |
| 768 | .setxattr = generic_setxattr, | 759 | .setxattr = generic_setxattr, |
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 7078974a6ee..49e4a6aea73 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c | |||
| @@ -812,18 +812,21 @@ write_retry: | |||
| 812 | 812 | ||
| 813 | /* Handle various SYNC-type writes */ | 813 | /* Handle various SYNC-type writes */ |
| 814 | if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) { | 814 | if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) { |
| 815 | loff_t end = pos + ret - 1; | ||
| 815 | int error2; | 816 | int error2; |
| 816 | 817 | ||
| 817 | xfs_iunlock(xip, iolock); | 818 | xfs_iunlock(xip, iolock); |
| 818 | if (need_i_mutex) | 819 | if (need_i_mutex) |
| 819 | mutex_unlock(&inode->i_mutex); | 820 | mutex_unlock(&inode->i_mutex); |
| 820 | error2 = sync_page_range(inode, mapping, pos, ret); | 821 | |
| 822 | error2 = filemap_write_and_wait_range(mapping, pos, end); | ||
| 821 | if (!error) | 823 | if (!error) |
| 822 | error = error2; | 824 | error = error2; |
| 823 | if (need_i_mutex) | 825 | if (need_i_mutex) |
| 824 | mutex_lock(&inode->i_mutex); | 826 | mutex_lock(&inode->i_mutex); |
| 825 | xfs_ilock(xip, iolock); | 827 | xfs_ilock(xip, iolock); |
| 826 | error2 = xfs_write_sync_logforce(mp, xip); | 828 | |
| 829 | error2 = xfs_fsync(xip); | ||
| 827 | if (!error) | 830 | if (!error) |
| 828 | error = error2; | 831 | error = error2; |
| 829 | } | 832 | } |
diff --git a/fs/xfs/linux-2.6/xfs_stats.c b/fs/xfs/linux-2.6/xfs_stats.c index c3526d445f6..76fdc586193 100644 --- a/fs/xfs/linux-2.6/xfs_stats.c +++ b/fs/xfs/linux-2.6/xfs_stats.c | |||
| @@ -20,16 +20,9 @@ | |||
| 20 | 20 | ||
| 21 | DEFINE_PER_CPU(struct xfsstats, xfsstats); | 21 | DEFINE_PER_CPU(struct xfsstats, xfsstats); |
| 22 | 22 | ||
| 23 | STATIC int | 23 | static int xfs_stat_proc_show(struct seq_file *m, void *v) |
| 24 | xfs_read_xfsstats( | ||
| 25 | char *buffer, | ||
| 26 | char **start, | ||
| 27 | off_t offset, | ||
| 28 | int count, | ||
| 29 | int *eof, | ||
| 30 | void *data) | ||
| 31 | { | 24 | { |
| 32 | int c, i, j, len, val; | 25 | int c, i, j, val; |
| 33 | __uint64_t xs_xstrat_bytes = 0; | 26 | __uint64_t xs_xstrat_bytes = 0; |
| 34 | __uint64_t xs_write_bytes = 0; | 27 | __uint64_t xs_write_bytes = 0; |
| 35 | __uint64_t xs_read_bytes = 0; | 28 | __uint64_t xs_read_bytes = 0; |
| @@ -60,18 +53,18 @@ xfs_read_xfsstats( | |||
| 60 | }; | 53 | }; |
| 61 | 54 | ||
| 62 | /* Loop over all stats groups */ | 55 | /* Loop over all stats groups */ |
| 63 | for (i=j=len = 0; i < ARRAY_SIZE(xstats); i++) { | 56 | for (i=j = 0; i < ARRAY_SIZE(xstats); i++) { |
| 64 | len += sprintf(buffer + len, "%s", xstats[i].desc); | 57 | seq_printf(m, "%s", xstats[i].desc); |
| 65 | /* inner loop does each group */ | 58 | /* inner loop does each group */ |
| 66 | while (j < xstats[i].endpoint) { | 59 | while (j < xstats[i].endpoint) { |
| 67 | val = 0; | 60 | val = 0; |
| 68 | /* sum over all cpus */ | 61 | /* sum over all cpus */ |
| 69 | for_each_possible_cpu(c) | 62 | for_each_possible_cpu(c) |
| 70 | val += *(((__u32*)&per_cpu(xfsstats, c) + j)); | 63 | val += *(((__u32*)&per_cpu(xfsstats, c) + j)); |
| 71 | len += sprintf(buffer + len, " %u", val); | 64 | seq_printf(m, " %u", val); |
| 72 | j++; | 65 | j++; |
| 73 | } | 66 | } |
| 74 | buffer[len++] = '\n'; | 67 | seq_putc(m, '\n'); |
| 75 | } | 68 | } |
| 76 | /* extra precision counters */ | 69 | /* extra precision counters */ |
| 77 | for_each_possible_cpu(i) { | 70 | for_each_possible_cpu(i) { |
| @@ -80,36 +73,38 @@ xfs_read_xfsstats( | |||
| 80 | xs_read_bytes += per_cpu(xfsstats, i).xs_read_bytes; | 73 | xs_read_bytes += per_cpu(xfsstats, i).xs_read_bytes; |
| 81 | } | 74 | } |
| 82 | 75 | ||
| 83 | len += sprintf(buffer + len, "xpc %Lu %Lu %Lu\n", | 76 | seq_printf(m, "xpc %Lu %Lu %Lu\n", |
| 84 | xs_xstrat_bytes, xs_write_bytes, xs_read_bytes); | 77 | xs_xstrat_bytes, xs_write_bytes, xs_read_bytes); |
| 85 | len += sprintf(buffer + len, "debug %u\n", | 78 | seq_printf(m, "debug %u\n", |
| 86 | #if defined(DEBUG) | 79 | #if defined(DEBUG) |
| 87 | 1); | 80 | 1); |
| 88 | #else | 81 | #else |
| 89 | 0); | 82 | 0); |
| 90 | #endif | 83 | #endif |
| 84 | return 0; | ||
| 85 | } | ||
| 91 | 86 | ||
| 92 | if (offset >= len) { | 87 | static int xfs_stat_proc_open(struct inode *inode, struct file *file) |
| 93 | *start = buffer; | 88 | { |
| 94 | *eof = 1; | 89 | return single_open(file, xfs_stat_proc_show, NULL); |
| 95 | return 0; | ||
| 96 | } | ||
| 97 | *start = buffer + offset; | ||
| 98 | if ((len -= offset) > count) | ||
| 99 | return count; | ||
| 100 | *eof = 1; | ||
| 101 | |||
| 102 | return len; | ||
| 103 | } | 90 | } |
| 104 | 91 | ||
| 92 | static const struct file_operations xfs_stat_proc_fops = { | ||
| 93 | .owner = THIS_MODULE, | ||
| 94 | .open = xfs_stat_proc_open, | ||
| 95 | .read = seq_read, | ||
| 96 | .llseek = seq_lseek, | ||
| 97 | .release = single_release, | ||
| 98 | }; | ||
| 99 | |||
| 105 | int | 100 | int |
| 106 | xfs_init_procfs(void) | 101 | xfs_init_procfs(void) |
| 107 | { | 102 | { |
| 108 | if (!proc_mkdir("fs/xfs", NULL)) | 103 | if (!proc_mkdir("fs/xfs", NULL)) |
| 109 | goto out; | 104 | goto out; |
| 110 | 105 | ||
| 111 | if (!create_proc_read_entry("fs/xfs/stat", 0, NULL, | 106 | if (!proc_create("fs/xfs/stat", 0, NULL, |
| 112 | xfs_read_xfsstats, NULL)) | 107 | &xfs_stat_proc_fops)) |
| 113 | goto out_remove_entry; | 108 | goto out_remove_entry; |
| 114 | return 0; | 109 | return 0; |
| 115 | 110 | ||
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index a220d36f789..5d7c60ac77b 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
| @@ -579,15 +579,19 @@ xfs_showargs( | |||
| 579 | else if (mp->m_qflags & XFS_UQUOTA_ACCT) | 579 | else if (mp->m_qflags & XFS_UQUOTA_ACCT) |
| 580 | seq_puts(m, "," MNTOPT_UQUOTANOENF); | 580 | seq_puts(m, "," MNTOPT_UQUOTANOENF); |
| 581 | 581 | ||
| 582 | if (mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD)) | 582 | /* Either project or group quotas can be active, not both */ |
| 583 | seq_puts(m, "," MNTOPT_PRJQUOTA); | 583 | |
| 584 | else if (mp->m_qflags & XFS_PQUOTA_ACCT) | 584 | if (mp->m_qflags & XFS_PQUOTA_ACCT) { |
| 585 | seq_puts(m, "," MNTOPT_PQUOTANOENF); | 585 | if (mp->m_qflags & XFS_OQUOTA_ENFD) |
| 586 | 586 | seq_puts(m, "," MNTOPT_PRJQUOTA); | |
| 587 | if (mp->m_qflags & (XFS_GQUOTA_ACCT|XFS_OQUOTA_ENFD)) | 587 | else |
| 588 | seq_puts(m, "," MNTOPT_GRPQUOTA); | 588 | seq_puts(m, "," MNTOPT_PQUOTANOENF); |
| 589 | else if (mp->m_qflags & XFS_GQUOTA_ACCT) | 589 | } else if (mp->m_qflags & XFS_GQUOTA_ACCT) { |
| 590 | seq_puts(m, "," MNTOPT_GQUOTANOENF); | 590 | if (mp->m_qflags & XFS_OQUOTA_ENFD) |
| 591 | seq_puts(m, "," MNTOPT_GRPQUOTA); | ||
| 592 | else | ||
| 593 | seq_puts(m, "," MNTOPT_GQUOTANOENF); | ||
| 594 | } | ||
| 591 | 595 | ||
| 592 | if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) | 596 | if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) |
| 593 | seq_puts(m, "," MNTOPT_NOQUOTA); | 597 | seq_puts(m, "," MNTOPT_NOQUOTA); |
| @@ -687,7 +691,7 @@ xfs_barrier_test( | |||
| 687 | return error; | 691 | return error; |
| 688 | } | 692 | } |
| 689 | 693 | ||
| 690 | void | 694 | STATIC void |
| 691 | xfs_mountfs_check_barriers(xfs_mount_t *mp) | 695 | xfs_mountfs_check_barriers(xfs_mount_t *mp) |
| 692 | { | 696 | { |
| 693 | int error; | 697 | int error; |
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 98ef624d9ba..320be6aea49 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
| @@ -749,21 +749,6 @@ __xfs_inode_clear_reclaim_tag( | |||
| 749 | XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); | 749 | XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); |
| 750 | } | 750 | } |
| 751 | 751 | ||
| 752 | void | ||
| 753 | xfs_inode_clear_reclaim_tag( | ||
| 754 | xfs_inode_t *ip) | ||
| 755 | { | ||
| 756 | xfs_mount_t *mp = ip->i_mount; | ||
| 757 | xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino); | ||
| 758 | |||
| 759 | read_lock(&pag->pag_ici_lock); | ||
| 760 | spin_lock(&ip->i_flags_lock); | ||
| 761 | __xfs_inode_clear_reclaim_tag(mp, pag, ip); | ||
| 762 | spin_unlock(&ip->i_flags_lock); | ||
| 763 | read_unlock(&pag->pag_ici_lock); | ||
| 764 | xfs_put_perag(mp, pag); | ||
| 765 | } | ||
| 766 | |||
| 767 | STATIC int | 752 | STATIC int |
| 768 | xfs_reclaim_inode_now( | 753 | xfs_reclaim_inode_now( |
| 769 | struct xfs_inode *ip, | 754 | struct xfs_inode *ip, |
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h index 59120602588..27920eb7a82 100644 --- a/fs/xfs/linux-2.6/xfs_sync.h +++ b/fs/xfs/linux-2.6/xfs_sync.h | |||
| @@ -49,7 +49,6 @@ int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); | |||
| 49 | 49 | ||
| 50 | void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); | 50 | void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); |
| 51 | void __xfs_inode_set_reclaim_tag(struct xfs_perag *pag, struct xfs_inode *ip); | 51 | void __xfs_inode_set_reclaim_tag(struct xfs_perag *pag, struct xfs_inode *ip); |
| 52 | void xfs_inode_clear_reclaim_tag(struct xfs_inode *ip); | ||
| 53 | void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag, | 52 | void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag, |
| 54 | struct xfs_inode *ip); | 53 | struct xfs_inode *ip); |
| 55 | 54 | ||
diff --git a/fs/xfs/quota/xfs_qm_stats.c b/fs/xfs/quota/xfs_qm_stats.c index 21b08c0396a..83e7ea3e25f 100644 --- a/fs/xfs/quota/xfs_qm_stats.c +++ b/fs/xfs/quota/xfs_qm_stats.c | |||
| @@ -48,50 +48,34 @@ | |||
| 48 | 48 | ||
| 49 | struct xqmstats xqmstats; | 49 | struct xqmstats xqmstats; |
| 50 | 50 | ||
| 51 | STATIC int | 51 | static int xqm_proc_show(struct seq_file *m, void *v) |
| 52 | xfs_qm_read_xfsquota( | ||
| 53 | char *buffer, | ||
| 54 | char **start, | ||
| 55 | off_t offset, | ||
| 56 | int count, | ||
| 57 | int *eof, | ||
| 58 | void *data) | ||
| 59 | { | 52 | { |
| 60 | int len; | ||
| 61 | |||
| 62 | /* maximum; incore; ratio free to inuse; freelist */ | 53 | /* maximum; incore; ratio free to inuse; freelist */ |
| 63 | len = sprintf(buffer, "%d\t%d\t%d\t%u\n", | 54 | seq_printf(m, "%d\t%d\t%d\t%u\n", |
| 64 | ndquot, | 55 | ndquot, |
| 65 | xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0, | 56 | xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0, |
| 66 | xfs_Gqm? xfs_Gqm->qm_dqfree_ratio : 0, | 57 | xfs_Gqm? xfs_Gqm->qm_dqfree_ratio : 0, |
| 67 | xfs_Gqm? xfs_Gqm->qm_dqfreelist.qh_nelems : 0); | 58 | xfs_Gqm? xfs_Gqm->qm_dqfreelist.qh_nelems : 0); |
| 68 | 59 | return 0; | |
| 69 | if (offset >= len) { | ||
| 70 | *start = buffer; | ||
| 71 | *eof = 1; | ||
| 72 | return 0; | ||
| 73 | } | ||
| 74 | *start = buffer + offset; | ||
| 75 | if ((len -= offset) > count) | ||
| 76 | return count; | ||
| 77 | *eof = 1; | ||
| 78 | |||
| 79 | return len; | ||
| 80 | } | 60 | } |
| 81 | 61 | ||
| 82 | STATIC int | 62 | static int xqm_proc_open(struct inode *inode, struct file *file) |
| 83 | xfs_qm_read_stats( | ||
| 84 | char *buffer, | ||
| 85 | char **start, | ||
| 86 | off_t offset, | ||
| 87 | int count, | ||
| 88 | int *eof, | ||
| 89 | void *data) | ||
| 90 | { | 63 | { |
| 91 | int len; | 64 | return single_open(file, xqm_proc_show, NULL); |
| 65 | } | ||
| 66 | |||
| 67 | static const struct file_operations xqm_proc_fops = { | ||
| 68 | .owner = THIS_MODULE, | ||
| 69 | .open = xqm_proc_open, | ||
| 70 | .read = seq_read, | ||
| 71 | .llseek = seq_lseek, | ||
| 72 | .release = single_release, | ||
| 73 | }; | ||
| 92 | 74 | ||
| 75 | static int xqmstat_proc_show(struct seq_file *m, void *v) | ||
| 76 | { | ||
| 93 | /* quota performance statistics */ | 77 | /* quota performance statistics */ |
| 94 | len = sprintf(buffer, "qm %u %u %u %u %u %u %u %u\n", | 78 | seq_printf(m, "qm %u %u %u %u %u %u %u %u\n", |
| 95 | xqmstats.xs_qm_dqreclaims, | 79 | xqmstats.xs_qm_dqreclaims, |
| 96 | xqmstats.xs_qm_dqreclaim_misses, | 80 | xqmstats.xs_qm_dqreclaim_misses, |
| 97 | xqmstats.xs_qm_dquot_dups, | 81 | xqmstats.xs_qm_dquot_dups, |
| @@ -100,25 +84,27 @@ xfs_qm_read_stats( | |||
| 100 | xqmstats.xs_qm_dqwants, | 84 | xqmstats.xs_qm_dqwants, |
| 101 | xqmstats.xs_qm_dqshake_reclaims, | 85 | xqmstats.xs_qm_dqshake_reclaims, |
| 102 | xqmstats.xs_qm_dqinact_reclaims); | 86 | xqmstats.xs_qm_dqinact_reclaims); |
| 87 | return 0; | ||
| 88 | } | ||
| 103 | 89 | ||
| 104 | if (offset >= len) { | 90 | static int xqmstat_proc_open(struct inode *inode, struct file *file) |
| 105 | *start = buffer; | 91 | { |
| 106 | *eof = 1; | 92 | return single_open(file, xqmstat_proc_show, NULL); |
| 107 | return 0; | ||
| 108 | } | ||
| 109 | *start = buffer + offset; | ||
| 110 | if ((len -= offset) > count) | ||
| 111 | return count; | ||
| 112 | *eof = 1; | ||
| 113 | |||
| 114 | return len; | ||
| 115 | } | 93 | } |
| 116 | 94 | ||
| 95 | static const struct file_operations xqmstat_proc_fops = { | ||
| 96 | .owner = THIS_MODULE, | ||
| 97 | .open = xqmstat_proc_open, | ||
| 98 | .read = seq_read, | ||
| 99 | .llseek = seq_lseek, | ||
| 100 | .release = single_release, | ||
| 101 | }; | ||
| 102 | |||
| 117 | void | 103 | void |
| 118 | xfs_qm_init_procfs(void) | 104 | xfs_qm_init_procfs(void) |
| 119 | { | 105 | { |
| 120 | create_proc_read_entry("fs/xfs/xqmstat", 0, NULL, xfs_qm_read_stats, NULL); | 106 | proc_create("fs/xfs/xqmstat", 0, NULL, &xqmstat_proc_fops); |
| 121 | create_proc_read_entry("fs/xfs/xqm", 0, NULL, xfs_qm_read_xfsquota, NULL); | 107 | proc_create("fs/xfs/xqm", 0, NULL, &xqm_proc_fops); |
| 122 | } | 108 | } |
| 123 | 109 | ||
| 124 | void | 110 | void |
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index f24b50b68d0..a5d54bf4931 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h | |||
| @@ -198,6 +198,15 @@ typedef struct xfs_perag | |||
| 198 | xfs_agino_t pagi_count; /* number of allocated inodes */ | 198 | xfs_agino_t pagi_count; /* number of allocated inodes */ |
| 199 | int pagb_count; /* pagb slots in use */ | 199 | int pagb_count; /* pagb slots in use */ |
| 200 | xfs_perag_busy_t *pagb_list; /* unstable blocks */ | 200 | xfs_perag_busy_t *pagb_list; /* unstable blocks */ |
| 201 | |||
| 202 | /* | ||
| 203 | * Inode allocation search lookup optimisation. | ||
| 204 | * If the pagino matches, the search for new inodes | ||
| 205 | * doesn't need to search the near ones again straight away | ||
| 206 | */ | ||
| 207 | xfs_agino_t pagl_pagino; | ||
| 208 | xfs_agino_t pagl_leftrec; | ||
| 209 | xfs_agino_t pagl_rightrec; | ||
| 201 | #ifdef __KERNEL__ | 210 | #ifdef __KERNEL__ |
| 202 | spinlock_t pagb_lock; /* lock for pagb_list */ | 211 | spinlock_t pagb_lock; /* lock for pagb_list */ |
| 203 | 212 | ||
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 8ee5b5a76a2..8971fb09d38 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
| @@ -3713,7 +3713,7 @@ done: | |||
| 3713 | * entry (null if none). Else, *lastxp will be set to the index | 3713 | * entry (null if none). Else, *lastxp will be set to the index |
| 3714 | * of the found entry; *gotp will contain the entry. | 3714 | * of the found entry; *gotp will contain the entry. |
| 3715 | */ | 3715 | */ |
| 3716 | xfs_bmbt_rec_host_t * /* pointer to found extent entry */ | 3716 | STATIC xfs_bmbt_rec_host_t * /* pointer to found extent entry */ |
| 3717 | xfs_bmap_search_multi_extents( | 3717 | xfs_bmap_search_multi_extents( |
| 3718 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3718 | xfs_ifork_t *ifp, /* inode fork pointer */ |
| 3719 | xfs_fileoff_t bno, /* block number searched for */ | 3719 | xfs_fileoff_t bno, /* block number searched for */ |
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h index 1b8ff9256bd..56f62d2edc3 100644 --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h | |||
| @@ -392,17 +392,6 @@ xfs_bmap_count_blocks( | |||
| 392 | int whichfork, | 392 | int whichfork, |
| 393 | int *count); | 393 | int *count); |
| 394 | 394 | ||
| 395 | /* | ||
| 396 | * Search the extent records for the entry containing block bno. | ||
| 397 | * If bno lies in a hole, point to the next entry. If bno lies | ||
| 398 | * past eof, *eofp will be set, and *prevp will contain the last | ||
| 399 | * entry (null if none). Else, *lastxp will be set to the index | ||
| 400 | * of the found entry; *gotp will contain the entry. | ||
| 401 | */ | ||
| 402 | xfs_bmbt_rec_host_t * | ||
| 403 | xfs_bmap_search_multi_extents(struct xfs_ifork *, xfs_fileoff_t, int *, | ||
| 404 | xfs_extnum_t *, xfs_bmbt_irec_t *, xfs_bmbt_irec_t *); | ||
| 405 | |||
| 406 | #endif /* __KERNEL__ */ | 395 | #endif /* __KERNEL__ */ |
| 407 | 396 | ||
| 408 | #endif /* __XFS_BMAP_H__ */ | 397 | #endif /* __XFS_BMAP_H__ */ |
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 5c1ade06578..eb7b702d069 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c | |||
| @@ -202,16 +202,6 @@ xfs_bmbt_get_state( | |||
| 202 | ext_flag); | 202 | ext_flag); |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | /* Endian flipping versions of the bmbt extraction functions */ | ||
| 206 | void | ||
| 207 | xfs_bmbt_disk_get_all( | ||
| 208 | xfs_bmbt_rec_t *r, | ||
| 209 | xfs_bmbt_irec_t *s) | ||
| 210 | { | ||
| 211 | __xfs_bmbt_get_all(get_unaligned_be64(&r->l0), | ||
| 212 | get_unaligned_be64(&r->l1), s); | ||
| 213 | } | ||
| 214 | |||
| 215 | /* | 205 | /* |
| 216 | * Extract the blockcount field from an on disk bmap extent record. | 206 | * Extract the blockcount field from an on disk bmap extent record. |
| 217 | */ | 207 | */ |
| @@ -816,6 +806,16 @@ xfs_bmbt_trace_key( | |||
| 816 | *l1 = 0; | 806 | *l1 = 0; |
| 817 | } | 807 | } |
| 818 | 808 | ||
| 809 | /* Endian flipping versions of the bmbt extraction functions */ | ||
| 810 | STATIC void | ||
| 811 | xfs_bmbt_disk_get_all( | ||
| 812 | xfs_bmbt_rec_t *r, | ||
| 813 | xfs_bmbt_irec_t *s) | ||
| 814 | { | ||
| 815 | __xfs_bmbt_get_all(get_unaligned_be64(&r->l0), | ||
| 816 | get_unaligned_be64(&r->l1), s); | ||
| 817 | } | ||
| 818 | |||
| 819 | STATIC void | 819 | STATIC void |
| 820 | xfs_bmbt_trace_record( | 820 | xfs_bmbt_trace_record( |
| 821 | struct xfs_btree_cur *cur, | 821 | struct xfs_btree_cur *cur, |
diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h index 0e8df007615..5549d495947 100644 --- a/fs/xfs/xfs_bmap_btree.h +++ b/fs/xfs/xfs_bmap_btree.h | |||
| @@ -220,7 +220,6 @@ extern xfs_fsblock_t xfs_bmbt_get_startblock(xfs_bmbt_rec_host_t *r); | |||
| 220 | extern xfs_fileoff_t xfs_bmbt_get_startoff(xfs_bmbt_rec_host_t *r); | 220 | extern xfs_fileoff_t xfs_bmbt_get_startoff(xfs_bmbt_rec_host_t *r); |
| 221 | extern xfs_exntst_t xfs_bmbt_get_state(xfs_bmbt_rec_host_t *r); | 221 | extern xfs_exntst_t xfs_bmbt_get_state(xfs_bmbt_rec_host_t *r); |
| 222 | 222 | ||
| 223 | extern void xfs_bmbt_disk_get_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s); | ||
| 224 | extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r); | 223 | extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r); |
| 225 | extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r); | 224 | extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r); |
| 226 | 225 | ||
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index 26717388acf..52b5f14d0c3 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c | |||
| @@ -646,46 +646,6 @@ xfs_btree_read_bufl( | |||
| 646 | } | 646 | } |
| 647 | 647 | ||
| 648 | /* | 648 | /* |
| 649 | * Get a buffer for the block, return it read in. | ||
| 650 | * Short-form addressing. | ||
| 651 | */ | ||
| 652 | int /* error */ | ||
| 653 | xfs_btree_read_bufs( | ||
| 654 | xfs_mount_t *mp, /* file system mount point */ | ||
| 655 | xfs_trans_t *tp, /* transaction pointer */ | ||
| 656 | xfs_agnumber_t agno, /* allocation group number */ | ||
| 657 | xfs_agblock_t agbno, /* allocation group block number */ | ||
| 658 | uint lock, /* lock flags for read_buf */ | ||
| 659 | xfs_buf_t **bpp, /* buffer for agno/agbno */ | ||
| 660 | int refval) /* ref count value for buffer */ | ||
| 661 | { | ||
| 662 | xfs_buf_t *bp; /* return value */ | ||
| 663 | xfs_daddr_t d; /* real disk block address */ | ||
| 664 | int error; | ||
| 665 | |||
| 666 | ASSERT(agno != NULLAGNUMBER); | ||
| 667 | ASSERT(agbno != NULLAGBLOCK); | ||
| 668 | d = XFS_AGB_TO_DADDR(mp, agno, agbno); | ||
| 669 | if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, | ||
| 670 | mp->m_bsize, lock, &bp))) { | ||
| 671 | return error; | ||
| 672 | } | ||
| 673 | ASSERT(!bp || !XFS_BUF_GETERROR(bp)); | ||
| 674 | if (bp != NULL) { | ||
| 675 | switch (refval) { | ||
| 676 | case XFS_ALLOC_BTREE_REF: | ||
| 677 | XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval); | ||
| 678 | break; | ||
| 679 | case XFS_INO_BTREE_REF: | ||
| 680 | XFS_BUF_SET_VTYPE_REF(bp, B_FS_INOMAP, refval); | ||
| 681 | break; | ||
| 682 | } | ||
| 683 | } | ||
| 684 | *bpp = bp; | ||
| 685 | return 0; | ||
| 686 | } | ||
| 687 | |||
| 688 | /* | ||
| 689 | * Read-ahead the block, don't wait for it, don't return a buffer. | 649 | * Read-ahead the block, don't wait for it, don't return a buffer. |
| 690 | * Long-form addressing. | 650 | * Long-form addressing. |
| 691 | */ | 651 | */ |
| @@ -2951,7 +2911,7 @@ error0: | |||
| 2951 | * inode we have to copy the single block it was pointing to into the | 2911 | * inode we have to copy the single block it was pointing to into the |
| 2952 | * inode. | 2912 | * inode. |
| 2953 | */ | 2913 | */ |
| 2954 | int | 2914 | STATIC int |
| 2955 | xfs_btree_kill_iroot( | 2915 | xfs_btree_kill_iroot( |
| 2956 | struct xfs_btree_cur *cur) | 2916 | struct xfs_btree_cur *cur) |
| 2957 | { | 2917 | { |
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h index 4f852b735b9..7fa07062bdd 100644 --- a/fs/xfs/xfs_btree.h +++ b/fs/xfs/xfs_btree.h | |||
| @@ -379,20 +379,6 @@ xfs_btree_read_bufl( | |||
| 379 | int refval);/* ref count value for buffer */ | 379 | int refval);/* ref count value for buffer */ |
| 380 | 380 | ||
| 381 | /* | 381 | /* |
| 382 | * Get a buffer for the block, return it read in. | ||
| 383 | * Short-form addressing. | ||
| 384 | */ | ||
| 385 | int /* error */ | ||
| 386 | xfs_btree_read_bufs( | ||
| 387 | struct xfs_mount *mp, /* file system mount point */ | ||
| 388 | struct xfs_trans *tp, /* transaction pointer */ | ||
| 389 | xfs_agnumber_t agno, /* allocation group number */ | ||
| 390 | xfs_agblock_t agbno, /* allocation group block number */ | ||
| 391 | uint lock, /* lock flags for read_buf */ | ||
| 392 | struct xfs_buf **bpp, /* buffer for agno/agbno */ | ||
| 393 | int refval);/* ref count value for buffer */ | ||
| 394 | |||
| 395 | /* | ||
| 396 | * Read-ahead the block, don't wait for it, don't return a buffer. | 382 | * Read-ahead the block, don't wait for it, don't return a buffer. |
| 397 | * Long-form addressing. | 383 | * Long-form addressing. |
| 398 | */ | 384 | */ |
| @@ -432,7 +418,6 @@ int xfs_btree_decrement(struct xfs_btree_cur *, int, int *); | |||
| 432 | int xfs_btree_lookup(struct xfs_btree_cur *, xfs_lookup_t, int *); | 418 | int xfs_btree_lookup(struct xfs_btree_cur *, xfs_lookup_t, int *); |
| 433 | int xfs_btree_update(struct xfs_btree_cur *, union xfs_btree_rec *); | 419 | int xfs_btree_update(struct xfs_btree_cur *, union xfs_btree_rec *); |
| 434 | int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *); | 420 | int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *); |
| 435 | int xfs_btree_kill_iroot(struct xfs_btree_cur *); | ||
| 436 | int xfs_btree_insert(struct xfs_btree_cur *, int *); | 421 | int xfs_btree_insert(struct xfs_btree_cur *, int *); |
| 437 | int xfs_btree_delete(struct xfs_btree_cur *, int *); | 422 | int xfs_btree_delete(struct xfs_btree_cur *, int *); |
| 438 | int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *); | 423 | int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *); |
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 3120a3a5e20..ab64f3efb43 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
| @@ -57,75 +57,35 @@ xfs_ialloc_cluster_alignment( | |||
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | /* | 59 | /* |
| 60 | * Lookup the record equal to ino in the btree given by cur. | 60 | * Lookup a record by ino in the btree given by cur. |
| 61 | */ | ||
| 62 | STATIC int /* error */ | ||
| 63 | xfs_inobt_lookup_eq( | ||
| 64 | struct xfs_btree_cur *cur, /* btree cursor */ | ||
| 65 | xfs_agino_t ino, /* starting inode of chunk */ | ||
| 66 | __int32_t fcnt, /* free inode count */ | ||
| 67 | xfs_inofree_t free, /* free inode mask */ | ||
| 68 | int *stat) /* success/failure */ | ||
| 69 | { | ||
| 70 | cur->bc_rec.i.ir_startino = ino; | ||
| 71 | cur->bc_rec.i.ir_freecount = fcnt; | ||
| 72 | cur->bc_rec.i.ir_free = free; | ||
| 73 | return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); | ||
| 74 | } | ||
| 75 | |||
| 76 | /* | ||
| 77 | * Lookup the first record greater than or equal to ino | ||
| 78 | * in the btree given by cur. | ||
| 79 | */ | 61 | */ |
| 80 | int /* error */ | 62 | int /* error */ |
| 81 | xfs_inobt_lookup_ge( | 63 | xfs_inobt_lookup( |
| 82 | struct xfs_btree_cur *cur, /* btree cursor */ | 64 | struct xfs_btree_cur *cur, /* btree cursor */ |
| 83 | xfs_agino_t ino, /* starting inode of chunk */ | 65 | xfs_agino_t ino, /* starting inode of chunk */ |
| 84 | __int32_t fcnt, /* free inode count */ | 66 | xfs_lookup_t dir, /* <=, >=, == */ |
| 85 | xfs_inofree_t free, /* free inode mask */ | ||
| 86 | int *stat) /* success/failure */ | 67 | int *stat) /* success/failure */ |
| 87 | { | 68 | { |
| 88 | cur->bc_rec.i.ir_startino = ino; | 69 | cur->bc_rec.i.ir_startino = ino; |
| 89 | cur->bc_rec.i.ir_freecount = fcnt; | 70 | cur->bc_rec.i.ir_freecount = 0; |
| 90 | cur->bc_rec.i.ir_free = free; | 71 | cur->bc_rec.i.ir_free = 0; |
| 91 | return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); | 72 | return xfs_btree_lookup(cur, dir, stat); |
| 92 | } | 73 | } |
| 93 | 74 | ||
| 94 | /* | 75 | /* |
| 95 | * Lookup the first record less than or equal to ino | 76 | * Update the record referred to by cur to the value given. |
| 96 | * in the btree given by cur. | ||
| 97 | */ | ||
| 98 | int /* error */ | ||
| 99 | xfs_inobt_lookup_le( | ||
| 100 | struct xfs_btree_cur *cur, /* btree cursor */ | ||
| 101 | xfs_agino_t ino, /* starting inode of chunk */ | ||
| 102 | __int32_t fcnt, /* free inode count */ | ||
| 103 | xfs_inofree_t free, /* free inode mask */ | ||
| 104 | int *stat) /* success/failure */ | ||
| 105 | { | ||
| 106 | cur->bc_rec.i.ir_startino = ino; | ||
| 107 | cur->bc_rec.i.ir_freecount = fcnt; | ||
| 108 | cur->bc_rec.i.ir_free = free; | ||
| 109 | return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); | ||
| 110 | } | ||
| 111 | |||
| 112 | /* | ||
| 113 | * Update the record referred to by cur to the value given | ||
| 114 | * by [ino, fcnt, free]. | ||
| 115 | * This either works (return 0) or gets an EFSCORRUPTED error. | 77 | * This either works (return 0) or gets an EFSCORRUPTED error. |
| 116 | */ | 78 | */ |
| 117 | STATIC int /* error */ | 79 | STATIC int /* error */ |
| 118 | xfs_inobt_update( | 80 | xfs_inobt_update( |
| 119 | struct xfs_btree_cur *cur, /* btree cursor */ | 81 | struct xfs_btree_cur *cur, /* btree cursor */ |
| 120 | xfs_agino_t ino, /* starting inode of chunk */ | 82 | xfs_inobt_rec_incore_t *irec) /* btree record */ |
| 121 | __int32_t fcnt, /* free inode count */ | ||
| 122 | xfs_inofree_t free) /* free inode mask */ | ||
| 123 | { | 83 | { |
| 124 | union xfs_btree_rec rec; | 84 | union xfs_btree_rec rec; |
| 125 | 85 | ||
| 126 | rec.inobt.ir_startino = cpu_to_be32(ino); | 86 | rec.inobt.ir_startino = cpu_to_be32(irec->ir_startino); |
| 127 | rec.inobt.ir_freecount = cpu_to_be32(fcnt); | 87 | rec.inobt.ir_freecount = cpu_to_be32(irec->ir_freecount); |
| 128 | rec.inobt.ir_free = cpu_to_be64(free); | 88 | rec.inobt.ir_free = cpu_to_be64(irec->ir_free); |
| 129 | return xfs_btree_update(cur, &rec); | 89 | return xfs_btree_update(cur, &rec); |
| 130 | } | 90 | } |
| 131 | 91 | ||
| @@ -135,9 +95,7 @@ xfs_inobt_update( | |||
| 135 | int /* error */ | 95 | int /* error */ |
| 136 | xfs_inobt_get_rec( | 96 | xfs_inobt_get_rec( |
| 137 | struct xfs_btree_cur *cur, /* btree cursor */ | 97 | struct xfs_btree_cur *cur, /* btree cursor */ |
| 138 | xfs_agino_t *ino, /* output: starting inode of chunk */ | 98 | xfs_inobt_rec_incore_t *irec, /* btree record */ |
| 139 | __int32_t *fcnt, /* output: number of free inodes */ | ||
| 140 | xfs_inofree_t *free, /* output: free inode mask */ | ||
| 141 | int *stat) /* output: success/failure */ | 99 | int *stat) /* output: success/failure */ |
| 142 | { | 100 | { |
| 143 | union xfs_btree_rec *rec; | 101 | union xfs_btree_rec *rec; |
| @@ -145,14 +103,136 @@ xfs_inobt_get_rec( | |||
| 145 | 103 | ||
| 146 | error = xfs_btree_get_rec(cur, &rec, stat); | 104 | error = xfs_btree_get_rec(cur, &rec, stat); |
| 147 | if (!error && *stat == 1) { | 105 | if (!error && *stat == 1) { |
| 148 | *ino = be32_to_cpu(rec->inobt.ir_startino); | 106 | irec->ir_startino = be32_to_cpu(rec->inobt.ir_startino); |
| 149 | *fcnt = be32_to_cpu(rec->inobt.ir_freecount); | 107 | irec->ir_freecount = be32_to_cpu(rec->inobt.ir_freecount); |
| 150 | *free = be64_to_cpu(rec->inobt.ir_free); | 108 | irec->ir_free = be64_to_cpu(rec->inobt.ir_free); |
| 151 | } | 109 | } |
| 152 | return error; | 110 | return error; |
| 153 | } | 111 | } |
| 154 | 112 | ||
| 155 | /* | 113 | /* |
| 114 | * Verify that the number of free inodes in the AGI is correct. | ||
| 115 | */ | ||
| 116 | #ifdef DEBUG | ||
| 117 | STATIC int | ||
| 118 | xfs_check_agi_freecount( | ||
| 119 | struct xfs_btree_cur *cur, | ||
| 120 | struct xfs_agi *agi) | ||
| 121 | { | ||
| 122 | if (cur->bc_nlevels == 1) { | ||
| 123 | xfs_inobt_rec_incore_t rec; | ||
| 124 | int freecount = 0; | ||
| 125 | int error; | ||
| 126 | int i; | ||
| 127 | |||
| 128 | error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); | ||
| 129 | if (error) | ||
| 130 | return error; | ||
| 131 | |||
| 132 | do { | ||
| 133 | error = xfs_inobt_get_rec(cur, &rec, &i); | ||
| 134 | if (error) | ||
| 135 | return error; | ||
| 136 | |||
| 137 | if (i) { | ||
| 138 | freecount += rec.ir_freecount; | ||
| 139 | error = xfs_btree_increment(cur, 0, &i); | ||
| 140 | if (error) | ||
| 141 | return error; | ||
| 142 | } | ||
| 143 | } while (i == 1); | ||
| 144 | |||
| 145 | if (!XFS_FORCED_SHUTDOWN(cur->bc_mp)) | ||
| 146 | ASSERT(freecount == be32_to_cpu(agi->agi_freecount)); | ||
| 147 | } | ||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | #else | ||
| 151 | #define xfs_check_agi_freecount(cur, agi) 0 | ||
| 152 | #endif | ||
| 153 | |||
| 154 | /* | ||
| 155 | * Initialise a new set of inodes. | ||
| 156 | */ | ||
| 157 | STATIC void | ||
| 158 | xfs_ialloc_inode_init( | ||
| 159 | struct xfs_mount *mp, | ||
| 160 | struct xfs_trans *tp, | ||
| 161 | xfs_agnumber_t agno, | ||
| 162 | xfs_agblock_t agbno, | ||
| 163 | xfs_agblock_t length, | ||
| 164 | unsigned int gen) | ||
| 165 | { | ||
| 166 | struct xfs_buf *fbuf; | ||
| 167 | struct xfs_dinode *free; | ||
| 168 | int blks_per_cluster, nbufs, ninodes; | ||
| 169 | int version; | ||
| 170 | int i, j; | ||
| 171 | xfs_daddr_t d; | ||
| 172 | |||
| 173 | /* | ||
| 174 | * Loop over the new block(s), filling in the inodes. | ||
| 175 | * For small block sizes, manipulate the inodes in buffers | ||
| 176 | * which are multiples of the blocks size. | ||
| 177 | */ | ||
| 178 | if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) { | ||
| 179 | blks_per_cluster = 1; | ||
| 180 | nbufs = length; | ||
| 181 | ninodes = mp->m_sb.sb_inopblock; | ||
| 182 | } else { | ||
| 183 | blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) / | ||
| 184 | mp->m_sb.sb_blocksize; | ||
| 185 | nbufs = length / blks_per_cluster; | ||
| 186 | ninodes = blks_per_cluster * mp->m_sb.sb_inopblock; | ||
| 187 | } | ||
| 188 | |||
| 189 | /* | ||
| 190 | * Figure out what version number to use in the inodes we create. | ||
| 191 | * If the superblock version has caught up to the one that supports | ||
| 192 | * the new inode format, then use the new inode version. Otherwise | ||
| 193 | * use the old version so that old kernels will continue to be | ||
| 194 | * able to use the file system. | ||
| 195 | */ | ||
| 196 | if (xfs_sb_version_hasnlink(&mp->m_sb)) | ||
| 197 | version = 2; | ||
| 198 | else | ||
| 199 | version = 1; | ||
| 200 | |||
| 201 | for (j = 0; j < nbufs; j++) { | ||
| 202 | /* | ||
| 203 | * Get the block. | ||
| 204 | */ | ||
| 205 | d = XFS_AGB_TO_DADDR(mp, agno, agbno + (j * blks_per_cluster)); | ||
| 206 | fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, | ||
| 207 | mp->m_bsize * blks_per_cluster, | ||
| 208 | XFS_BUF_LOCK); | ||
| 209 | ASSERT(fbuf); | ||
| 210 | ASSERT(!XFS_BUF_GETERROR(fbuf)); | ||
| 211 | |||
| 212 | /* | ||
| 213 | * Initialize all inodes in this buffer and then log them. | ||
| 214 | * | ||
| 215 | * XXX: It would be much better if we had just one transaction | ||
| 216 | * to log a whole cluster of inodes instead of all the | ||
| 217 | * individual transactions causing a lot of log traffic. | ||
| 218 | */ | ||
| 219 | xfs_biozero(fbuf, 0, ninodes << mp->m_sb.sb_inodelog); | ||
| 220 | for (i = 0; i < ninodes; i++) { | ||
| 221 | int ioffset = i << mp->m_sb.sb_inodelog; | ||
| 222 | uint isize = sizeof(struct xfs_dinode); | ||
| 223 | |||
| 224 | free = xfs_make_iptr(mp, fbuf, i); | ||
| 225 | free->di_magic = cpu_to_be16(XFS_DINODE_MAGIC); | ||
| 226 | free->di_version = version; | ||
| 227 | free->di_gen = cpu_to_be32(gen); | ||
| 228 | free->di_next_unlinked = cpu_to_be32(NULLAGINO); | ||
| 229 | xfs_trans_log_buf(tp, fbuf, ioffset, ioffset + isize - 1); | ||
| 230 | } | ||
| 231 | xfs_trans_inode_alloc_buf(tp, fbuf); | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | /* | ||
| 156 | * Allocate new inodes in the allocation group specified by agbp. | 236 | * Allocate new inodes in the allocation group specified by agbp. |
| 157 | * Return 0 for success, else error code. | 237 | * Return 0 for success, else error code. |
| 158 | */ | 238 | */ |
| @@ -164,24 +244,15 @@ xfs_ialloc_ag_alloc( | |||
| 164 | { | 244 | { |
| 165 | xfs_agi_t *agi; /* allocation group header */ | 245 | xfs_agi_t *agi; /* allocation group header */ |
| 166 | xfs_alloc_arg_t args; /* allocation argument structure */ | 246 | xfs_alloc_arg_t args; /* allocation argument structure */ |
| 167 | int blks_per_cluster; /* fs blocks per inode cluster */ | ||
| 168 | xfs_btree_cur_t *cur; /* inode btree cursor */ | 247 | xfs_btree_cur_t *cur; /* inode btree cursor */ |
| 169 | xfs_daddr_t d; /* disk addr of buffer */ | ||
| 170 | xfs_agnumber_t agno; | 248 | xfs_agnumber_t agno; |
| 171 | int error; | 249 | int error; |
| 172 | xfs_buf_t *fbuf; /* new free inodes' buffer */ | 250 | int i; |
| 173 | xfs_dinode_t *free; /* new free inode structure */ | ||
| 174 | int i; /* inode counter */ | ||
| 175 | int j; /* block counter */ | ||
| 176 | int nbufs; /* num bufs of new inodes */ | ||
| 177 | xfs_agino_t newino; /* new first inode's number */ | 251 | xfs_agino_t newino; /* new first inode's number */ |
| 178 | xfs_agino_t newlen; /* new number of inodes */ | 252 | xfs_agino_t newlen; /* new number of inodes */ |
| 179 | int ninodes; /* num inodes per buf */ | ||
| 180 | xfs_agino_t thisino; /* current inode number, for loop */ | 253 | xfs_agino_t thisino; /* current inode number, for loop */ |
| 181 | int version; /* inode version number to use */ | ||
| 182 | int isaligned = 0; /* inode allocation at stripe unit */ | 254 | int isaligned = 0; /* inode allocation at stripe unit */ |
| 183 | /* boundary */ | 255 | /* boundary */ |
| 184 | unsigned int gen; | ||
| 185 | 256 | ||
| 186 | args.tp = tp; | 257 | args.tp = tp; |
| 187 | args.mp = tp->t_mountp; | 258 | args.mp = tp->t_mountp; |
| @@ -202,12 +273,12 @@ xfs_ialloc_ag_alloc( | |||
| 202 | */ | 273 | */ |
| 203 | agi = XFS_BUF_TO_AGI(agbp); | 274 | agi = XFS_BUF_TO_AGI(agbp); |
| 204 | newino = be32_to_cpu(agi->agi_newino); | 275 | newino = be32_to_cpu(agi->agi_newino); |
| 276 | agno = be32_to_cpu(agi->agi_seqno); | ||
| 205 | args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) + | 277 | args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) + |
| 206 | XFS_IALLOC_BLOCKS(args.mp); | 278 | XFS_IALLOC_BLOCKS(args.mp); |
| 207 | if (likely(newino != NULLAGINO && | 279 | if (likely(newino != NULLAGINO && |
| 208 | (args.agbno < be32_to_cpu(agi->agi_length)))) { | 280 | (args.agbno < be32_to_cpu(agi->agi_length)))) { |
| 209 | args.fsbno = XFS_AGB_TO_FSB(args.mp, | 281 | args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); |
| 210 | be32_to_cpu(agi->agi_seqno), args.agbno); | ||
| 211 | args.type = XFS_ALLOCTYPE_THIS_BNO; | 282 | args.type = XFS_ALLOCTYPE_THIS_BNO; |
| 212 | args.mod = args.total = args.wasdel = args.isfl = | 283 | args.mod = args.total = args.wasdel = args.isfl = |
| 213 | args.userdata = args.minalignslop = 0; | 284 | args.userdata = args.minalignslop = 0; |
| @@ -258,8 +329,7 @@ xfs_ialloc_ag_alloc( | |||
| 258 | * For now, just allocate blocks up front. | 329 | * For now, just allocate blocks up front. |
| 259 | */ | 330 | */ |
| 260 | args.agbno = be32_to_cpu(agi->agi_root); | 331 | args.agbno = be32_to_cpu(agi->agi_root); |
| 261 | args.fsbno = XFS_AGB_TO_FSB(args.mp, | 332 | args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); |
| 262 | be32_to_cpu(agi->agi_seqno), args.agbno); | ||
| 263 | /* | 333 | /* |
| 264 | * Allocate a fixed-size extent of inodes. | 334 | * Allocate a fixed-size extent of inodes. |
| 265 | */ | 335 | */ |
| @@ -282,8 +352,7 @@ xfs_ialloc_ag_alloc( | |||
| 282 | if (isaligned && args.fsbno == NULLFSBLOCK) { | 352 | if (isaligned && args.fsbno == NULLFSBLOCK) { |
| 283 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 353 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
| 284 | args.agbno = be32_to_cpu(agi->agi_root); | 354 | args.agbno = be32_to_cpu(agi->agi_root); |
| 285 | args.fsbno = XFS_AGB_TO_FSB(args.mp, | 355 | args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); |
| 286 | be32_to_cpu(agi->agi_seqno), args.agbno); | ||
| 287 | args.alignment = xfs_ialloc_cluster_alignment(&args); | 356 | args.alignment = xfs_ialloc_cluster_alignment(&args); |
| 288 | if ((error = xfs_alloc_vextent(&args))) | 357 | if ((error = xfs_alloc_vextent(&args))) |
| 289 | return error; | 358 | return error; |
| @@ -294,85 +363,30 @@ xfs_ialloc_ag_alloc( | |||
| 294 | return 0; | 363 | return 0; |
| 295 | } | 364 | } |
| 296 | ASSERT(args.len == args.minlen); | 365 | ASSERT(args.len == args.minlen); |
| 297 | /* | ||
| 298 | * Convert the results. | ||
| 299 | */ | ||
| 300 | newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0); | ||
| 301 | /* | ||
| 302 | * Loop over the new block(s), filling in the inodes. | ||
| 303 | * For small block sizes, manipulate the inodes in buffers | ||
| 304 | * which are multiples of the blocks size. | ||
| 305 | */ | ||
| 306 | if (args.mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(args.mp)) { | ||
| 307 | blks_per_cluster = 1; | ||
| 308 | nbufs = (int)args.len; | ||
| 309 | ninodes = args.mp->m_sb.sb_inopblock; | ||
| 310 | } else { | ||
| 311 | blks_per_cluster = XFS_INODE_CLUSTER_SIZE(args.mp) / | ||
| 312 | args.mp->m_sb.sb_blocksize; | ||
| 313 | nbufs = (int)args.len / blks_per_cluster; | ||
| 314 | ninodes = blks_per_cluster * args.mp->m_sb.sb_inopblock; | ||
| 315 | } | ||
| 316 | /* | ||
| 317 | * Figure out what version number to use in the inodes we create. | ||
| 318 | * If the superblock version has caught up to the one that supports | ||
| 319 | * the new inode format, then use the new inode version. Otherwise | ||
| 320 | * use the old version so that old kernels will continue to be | ||
| 321 | * able to use the file system. | ||
| 322 | */ | ||
| 323 | if (xfs_sb_version_hasnlink(&args.mp->m_sb)) | ||
| 324 | version = 2; | ||
| 325 | else | ||
| 326 | version = 1; | ||
| 327 | 366 | ||
| 328 | /* | 367 | /* |
| 368 | * Stamp and write the inode buffers. | ||
| 369 | * | ||
| 329 | * Seed the new inode cluster with a random generation number. This | 370 | * Seed the new inode cluster with a random generation number. This |
| 330 | * prevents short-term reuse of generation numbers if a chunk is | 371 | * prevents short-term reuse of generation numbers if a chunk is |
| 331 | * freed and then immediately reallocated. We use random numbers | 372 | * freed and then immediately reallocated. We use random numbers |
| 332 | * rather than a linear progression to prevent the next generation | 373 | * rather than a linear progression to prevent the next generation |
| 333 | * number from being easily guessable. | 374 | * number from being easily guessable. |
| 334 | */ | 375 | */ |
| 335 | gen = random32(); | 376 | xfs_ialloc_inode_init(args.mp, tp, agno, args.agbno, args.len, |
| 336 | for (j = 0; j < nbufs; j++) { | 377 | random32()); |
| 337 | /* | ||
| 338 | * Get the block. | ||
| 339 | */ | ||
| 340 | d = XFS_AGB_TO_DADDR(args.mp, be32_to_cpu(agi->agi_seqno), | ||
| 341 | args.agbno + (j * blks_per_cluster)); | ||
| 342 | fbuf = xfs_trans_get_buf(tp, args.mp->m_ddev_targp, d, | ||
| 343 | args.mp->m_bsize * blks_per_cluster, | ||
| 344 | XFS_BUF_LOCK); | ||
| 345 | ASSERT(fbuf); | ||
| 346 | ASSERT(!XFS_BUF_GETERROR(fbuf)); | ||
| 347 | 378 | ||
| 348 | /* | 379 | /* |
| 349 | * Initialize all inodes in this buffer and then log them. | 380 | * Convert the results. |
| 350 | * | 381 | */ |
| 351 | * XXX: It would be much better if we had just one transaction to | 382 | newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0); |
| 352 | * log a whole cluster of inodes instead of all the individual | ||
| 353 | * transactions causing a lot of log traffic. | ||
| 354 | */ | ||
| 355 | xfs_biozero(fbuf, 0, ninodes << args.mp->m_sb.sb_inodelog); | ||
| 356 | for (i = 0; i < ninodes; i++) { | ||
| 357 | int ioffset = i << args.mp->m_sb.sb_inodelog; | ||
| 358 | uint isize = sizeof(struct xfs_dinode); | ||
| 359 | |||
| 360 | free = xfs_make_iptr(args.mp, fbuf, i); | ||
| 361 | free->di_magic = cpu_to_be16(XFS_DINODE_MAGIC); | ||
| 362 | free->di_version = version; | ||
| 363 | free->di_gen = cpu_to_be32(gen); | ||
| 364 | free->di_next_unlinked = cpu_to_be32(NULLAGINO); | ||
| 365 | xfs_trans_log_buf(tp, fbuf, ioffset, ioffset + isize - 1); | ||
| 366 | } | ||
| 367 | xfs_trans_inode_alloc_buf(tp, fbuf); | ||
| 368 | } | ||
| 369 | be32_add_cpu(&agi->agi_count, newlen); | 383 | be32_add_cpu(&agi->agi_count, newlen); |
| 370 | be32_add_cpu(&agi->agi_freecount, newlen); | 384 | be32_add_cpu(&agi->agi_freecount, newlen); |
| 371 | agno = be32_to_cpu(agi->agi_seqno); | ||
| 372 | down_read(&args.mp->m_peraglock); | 385 | down_read(&args.mp->m_peraglock); |
| 373 | args.mp->m_perag[agno].pagi_freecount += newlen; | 386 | args.mp->m_perag[agno].pagi_freecount += newlen; |
| 374 | up_read(&args.mp->m_peraglock); | 387 | up_read(&args.mp->m_peraglock); |
| 375 | agi->agi_newino = cpu_to_be32(newino); | 388 | agi->agi_newino = cpu_to_be32(newino); |
| 389 | |||
| 376 | /* | 390 | /* |
| 377 | * Insert records describing the new inode chunk into the btree. | 391 | * Insert records describing the new inode chunk into the btree. |
| 378 | */ | 392 | */ |
| @@ -380,13 +394,17 @@ xfs_ialloc_ag_alloc( | |||
| 380 | for (thisino = newino; | 394 | for (thisino = newino; |
| 381 | thisino < newino + newlen; | 395 | thisino < newino + newlen; |
| 382 | thisino += XFS_INODES_PER_CHUNK) { | 396 | thisino += XFS_INODES_PER_CHUNK) { |
| 383 | if ((error = xfs_inobt_lookup_eq(cur, thisino, | 397 | cur->bc_rec.i.ir_startino = thisino; |
| 384 | XFS_INODES_PER_CHUNK, XFS_INOBT_ALL_FREE, &i))) { | 398 | cur->bc_rec.i.ir_freecount = XFS_INODES_PER_CHUNK; |
| 399 | cur->bc_rec.i.ir_free = XFS_INOBT_ALL_FREE; | ||
| 400 | error = xfs_btree_lookup(cur, XFS_LOOKUP_EQ, &i); | ||
| 401 | if (error) { | ||
| 385 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); | 402 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); |
| 386 | return error; | 403 | return error; |
| 387 | } | 404 | } |
| 388 | ASSERT(i == 0); | 405 | ASSERT(i == 0); |
| 389 | if ((error = xfs_btree_insert(cur, &i))) { | 406 | error = xfs_btree_insert(cur, &i); |
| 407 | if (error) { | ||
| 390 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); | 408 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); |
| 391 | return error; | 409 | return error; |
| 392 | } | 410 | } |
| @@ -539,6 +557,62 @@ nextag: | |||
| 539 | } | 557 | } |
| 540 | 558 | ||
| 541 | /* | 559 | /* |
| 560 | * Try to retrieve the next record to the left/right from the current one. | ||
| 561 | */ | ||
| 562 | STATIC int | ||
| 563 | xfs_ialloc_next_rec( | ||
| 564 | struct xfs_btree_cur *cur, | ||
| 565 | xfs_inobt_rec_incore_t *rec, | ||
| 566 | int *done, | ||
| 567 | int left) | ||
| 568 | { | ||
| 569 | int error; | ||
| 570 | int i; | ||
| 571 | |||
| 572 | if (left) | ||
| 573 | error = xfs_btree_decrement(cur, 0, &i); | ||
| 574 | else | ||
| 575 | error = xfs_btree_increment(cur, 0, &i); | ||
| 576 | |||
| 577 | if (error) | ||
| 578 | return error; | ||
| 579 | *done = !i; | ||
| 580 | if (i) { | ||
| 581 | error = xfs_inobt_get_rec(cur, rec, &i); | ||
| 582 | if (error) | ||
| 583 | return error; | ||
| 584 | XFS_WANT_CORRUPTED_RETURN(i == 1); | ||
| 585 | } | ||
| 586 | |||
| 587 | return 0; | ||
| 588 | } | ||
| 589 | |||
| 590 | STATIC int | ||
| 591 | xfs_ialloc_get_rec( | ||
| 592 | struct xfs_btree_cur *cur, | ||
| 593 | xfs_agino_t agino, | ||
| 594 | xfs_inobt_rec_incore_t *rec, | ||
| 595 | int *done, | ||
| 596 | int left) | ||
| 597 | { | ||
| 598 | int error; | ||
| 599 | int i; | ||
| 600 | |||
| 601 | error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_EQ, &i); | ||
| 602 | if (error) | ||
| 603 | return error; | ||
| 604 | *done = !i; | ||
| 605 | if (i) { | ||
| 606 | error = xfs_inobt_get_rec(cur, rec, &i); | ||
| 607 | if (error) | ||
| 608 | return error; | ||
| 609 | XFS_WANT_CORRUPTED_RETURN(i == 1); | ||
| 610 | } | ||
| 611 | |||
| 612 | return 0; | ||
| 613 | } | ||
| 614 | |||
| 615 | /* | ||
| 542 | * Visible inode allocation functions. | 616 | * Visible inode allocation functions. |
| 543 | */ | 617 | */ |
| 544 | 618 | ||
| @@ -592,8 +666,8 @@ xfs_dialloc( | |||
| 592 | int j; /* result code */ | 666 | int j; /* result code */ |
| 593 | xfs_mount_t *mp; /* file system mount structure */ | 667 | xfs_mount_t *mp; /* file system mount structure */ |
| 594 | int offset; /* index of inode in chunk */ | 668 | int offset; /* index of inode in chunk */ |
| 595 | xfs_agino_t pagino; /* parent's a.g. relative inode # */ | 669 | xfs_agino_t pagino; /* parent's AG relative inode # */ |
| 596 | xfs_agnumber_t pagno; /* parent's allocation group number */ | 670 | xfs_agnumber_t pagno; /* parent's AG number */ |
| 597 | xfs_inobt_rec_incore_t rec; /* inode allocation record */ | 671 | xfs_inobt_rec_incore_t rec; /* inode allocation record */ |
| 598 | xfs_agnumber_t tagno; /* testing allocation group number */ | 672 | xfs_agnumber_t tagno; /* testing allocation group number */ |
| 599 | xfs_btree_cur_t *tcur; /* temp cursor */ | 673 | xfs_btree_cur_t *tcur; /* temp cursor */ |
| @@ -716,6 +790,8 @@ nextag: | |||
| 716 | */ | 790 | */ |
| 717 | agno = tagno; | 791 | agno = tagno; |
| 718 | *IO_agbp = NULL; | 792 | *IO_agbp = NULL; |
| 793 | |||
| 794 | restart_pagno: | ||
| 719 | cur = xfs_inobt_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno)); | 795 | cur = xfs_inobt_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno)); |
| 720 | /* | 796 | /* |
| 721 | * If pagino is 0 (this is the root inode allocation) use newino. | 797 | * If pagino is 0 (this is the root inode allocation) use newino. |
| @@ -723,220 +799,199 @@ nextag: | |||
| 723 | */ | 799 | */ |
| 724 | if (!pagino) | 800 | if (!pagino) |
| 725 | pagino = be32_to_cpu(agi->agi_newino); | 801 | pagino = be32_to_cpu(agi->agi_newino); |
| 726 | #ifdef DEBUG | ||
| 727 | if (cur->bc_nlevels == 1) { | ||
| 728 | int freecount = 0; | ||
| 729 | 802 | ||
| 730 | if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) | 803 | error = xfs_check_agi_freecount(cur, agi); |
| 731 | goto error0; | 804 | if (error) |
| 732 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 805 | goto error0; |
| 733 | do { | ||
| 734 | if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, | ||
| 735 | &rec.ir_freecount, &rec.ir_free, &i))) | ||
| 736 | goto error0; | ||
| 737 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
| 738 | freecount += rec.ir_freecount; | ||
| 739 | if ((error = xfs_btree_increment(cur, 0, &i))) | ||
| 740 | goto error0; | ||
| 741 | } while (i == 1); | ||
| 742 | 806 | ||
| 743 | ASSERT(freecount == be32_to_cpu(agi->agi_freecount) || | ||
| 744 | XFS_FORCED_SHUTDOWN(mp)); | ||
| 745 | } | ||
| 746 | #endif | ||
| 747 | /* | 807 | /* |
| 748 | * If in the same a.g. as the parent, try to get near the parent. | 808 | * If in the same AG as the parent, try to get near the parent. |
| 749 | */ | 809 | */ |
| 750 | if (pagno == agno) { | 810 | if (pagno == agno) { |
| 751 | if ((error = xfs_inobt_lookup_le(cur, pagino, 0, 0, &i))) | 811 | xfs_perag_t *pag = &mp->m_perag[agno]; |
| 812 | int doneleft; /* done, to the left */ | ||
| 813 | int doneright; /* done, to the right */ | ||
| 814 | int searchdistance = 10; | ||
| 815 | |||
| 816 | error = xfs_inobt_lookup(cur, pagino, XFS_LOOKUP_LE, &i); | ||
| 817 | if (error) | ||
| 818 | goto error0; | ||
| 819 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
| 820 | |||
| 821 | error = xfs_inobt_get_rec(cur, &rec, &j); | ||
| 822 | if (error) | ||
| 752 | goto error0; | 823 | goto error0; |
| 753 | if (i != 0 && | 824 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
| 754 | (error = xfs_inobt_get_rec(cur, &rec.ir_startino, | 825 | |
| 755 | &rec.ir_freecount, &rec.ir_free, &j)) == 0 && | 826 | if (rec.ir_freecount > 0) { |
| 756 | j == 1 && | ||
| 757 | rec.ir_freecount > 0) { | ||
| 758 | /* | 827 | /* |
| 759 | * Found a free inode in the same chunk | 828 | * Found a free inode in the same chunk |
| 760 | * as parent, done. | 829 | * as the parent, done. |
| 761 | */ | 830 | */ |
| 831 | goto alloc_inode; | ||
| 762 | } | 832 | } |
| 833 | |||
| 834 | |||
| 835 | /* | ||
| 836 | * In the same AG as parent, but parent's chunk is full. | ||
| 837 | */ | ||
| 838 | |||
| 839 | /* duplicate the cursor, search left & right simultaneously */ | ||
| 840 | error = xfs_btree_dup_cursor(cur, &tcur); | ||
| 841 | if (error) | ||
| 842 | goto error0; | ||
| 843 | |||
| 763 | /* | 844 | /* |
| 764 | * In the same a.g. as parent, but parent's chunk is full. | 845 | * Skip to last blocks looked up if same parent inode. |
| 765 | */ | 846 | */ |
| 766 | else { | 847 | if (pagino != NULLAGINO && |
| 767 | int doneleft; /* done, to the left */ | 848 | pag->pagl_pagino == pagino && |
| 768 | int doneright; /* done, to the right */ | 849 | pag->pagl_leftrec != NULLAGINO && |
| 850 | pag->pagl_rightrec != NULLAGINO) { | ||
| 851 | error = xfs_ialloc_get_rec(tcur, pag->pagl_leftrec, | ||
| 852 | &trec, &doneleft, 1); | ||
| 853 | if (error) | ||
| 854 | goto error1; | ||
| 769 | 855 | ||
| 856 | error = xfs_ialloc_get_rec(cur, pag->pagl_rightrec, | ||
| 857 | &rec, &doneright, 0); | ||
| 770 | if (error) | 858 | if (error) |
| 771 | goto error0; | ||
| 772 | ASSERT(i == 1); | ||
| 773 | ASSERT(j == 1); | ||
| 774 | /* | ||
| 775 | * Duplicate the cursor, search left & right | ||
| 776 | * simultaneously. | ||
| 777 | */ | ||
| 778 | if ((error = xfs_btree_dup_cursor(cur, &tcur))) | ||
| 779 | goto error0; | ||
| 780 | /* | ||
| 781 | * Search left with tcur, back up 1 record. | ||
| 782 | */ | ||
| 783 | if ((error = xfs_btree_decrement(tcur, 0, &i))) | ||
| 784 | goto error1; | 859 | goto error1; |
| 785 | doneleft = !i; | 860 | } else { |
| 786 | if (!doneleft) { | 861 | /* search left with tcur, back up 1 record */ |
| 787 | if ((error = xfs_inobt_get_rec(tcur, | 862 | error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1); |
| 788 | &trec.ir_startino, | 863 | if (error) |
| 789 | &trec.ir_freecount, | ||
| 790 | &trec.ir_free, &i))) | ||
| 791 | goto error1; | ||
| 792 | XFS_WANT_CORRUPTED_GOTO(i == 1, error1); | ||
| 793 | } | ||
| 794 | /* | ||
| 795 | * Search right with cur, go forward 1 record. | ||
| 796 | */ | ||
| 797 | if ((error = xfs_btree_increment(cur, 0, &i))) | ||
| 798 | goto error1; | 864 | goto error1; |
| 799 | doneright = !i; | ||
| 800 | if (!doneright) { | ||
| 801 | if ((error = xfs_inobt_get_rec(cur, | ||
| 802 | &rec.ir_startino, | ||
| 803 | &rec.ir_freecount, | ||
| 804 | &rec.ir_free, &i))) | ||
| 805 | goto error1; | ||
| 806 | XFS_WANT_CORRUPTED_GOTO(i == 1, error1); | ||
| 807 | } | ||
| 808 | /* | ||
| 809 | * Loop until we find the closest inode chunk | ||
| 810 | * with a free one. | ||
| 811 | */ | ||
| 812 | while (!doneleft || !doneright) { | ||
| 813 | int useleft; /* using left inode | ||
| 814 | chunk this time */ | ||
| 815 | 865 | ||
| 866 | /* search right with cur, go forward 1 record. */ | ||
| 867 | error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0); | ||
| 868 | if (error) | ||
| 869 | goto error1; | ||
| 870 | } | ||
| 871 | |||
| 872 | /* | ||
| 873 | * Loop until we find an inode chunk with a free inode. | ||
| 874 | */ | ||
| 875 | while (!doneleft || !doneright) { | ||
| 876 | int useleft; /* using left inode chunk this time */ | ||
| 877 | |||
| 878 | if (!--searchdistance) { | ||
| 816 | /* | 879 | /* |
| 817 | * Figure out which block is closer, | 880 | * Not in range - save last search |
| 818 | * if both are valid. | 881 | * location and allocate a new inode |
| 819 | */ | ||
| 820 | if (!doneleft && !doneright) | ||
| 821 | useleft = | ||
| 822 | pagino - | ||
| 823 | (trec.ir_startino + | ||
| 824 | XFS_INODES_PER_CHUNK - 1) < | ||
| 825 | rec.ir_startino - pagino; | ||
| 826 | else | ||
| 827 | useleft = !doneleft; | ||
| 828 | /* | ||
| 829 | * If checking the left, does it have | ||
| 830 | * free inodes? | ||
| 831 | */ | ||
| 832 | if (useleft && trec.ir_freecount) { | ||
| 833 | /* | ||
| 834 | * Yes, set it up as the chunk to use. | ||
| 835 | */ | ||
| 836 | rec = trec; | ||
| 837 | xfs_btree_del_cursor(cur, | ||
| 838 | XFS_BTREE_NOERROR); | ||
| 839 | cur = tcur; | ||
| 840 | break; | ||
| 841 | } | ||
| 842 | /* | ||
| 843 | * If checking the right, does it have | ||
| 844 | * free inodes? | ||
| 845 | */ | ||
| 846 | if (!useleft && rec.ir_freecount) { | ||
| 847 | /* | ||
| 848 | * Yes, it's already set up. | ||
| 849 | */ | ||
| 850 | xfs_btree_del_cursor(tcur, | ||
| 851 | XFS_BTREE_NOERROR); | ||
| 852 | break; | ||
| 853 | } | ||
| 854 | /* | ||
| 855 | * If used the left, get another one | ||
| 856 | * further left. | ||
| 857 | */ | ||
| 858 | if (useleft) { | ||
| 859 | if ((error = xfs_btree_decrement(tcur, 0, | ||
| 860 | &i))) | ||
| 861 | goto error1; | ||
| 862 | doneleft = !i; | ||
| 863 | if (!doneleft) { | ||
| 864 | if ((error = xfs_inobt_get_rec( | ||
| 865 | tcur, | ||
| 866 | &trec.ir_startino, | ||
| 867 | &trec.ir_freecount, | ||
| 868 | &trec.ir_free, &i))) | ||
| 869 | goto error1; | ||
| 870 | XFS_WANT_CORRUPTED_GOTO(i == 1, | ||
| 871 | error1); | ||
| 872 | } | ||
| 873 | } | ||
| 874 | /* | ||
| 875 | * If used the right, get another one | ||
| 876 | * further right. | ||
| 877 | */ | 882 | */ |
| 878 | else { | 883 | pag->pagl_leftrec = trec.ir_startino; |
| 879 | if ((error = xfs_btree_increment(cur, 0, | 884 | pag->pagl_rightrec = rec.ir_startino; |
| 880 | &i))) | 885 | pag->pagl_pagino = pagino; |
| 881 | goto error1; | 886 | goto newino; |
| 882 | doneright = !i; | 887 | } |
| 883 | if (!doneright) { | 888 | |
| 884 | if ((error = xfs_inobt_get_rec( | 889 | /* figure out the closer block if both are valid. */ |
| 885 | cur, | 890 | if (!doneleft && !doneright) { |
| 886 | &rec.ir_startino, | 891 | useleft = pagino - |
| 887 | &rec.ir_freecount, | 892 | (trec.ir_startino + XFS_INODES_PER_CHUNK - 1) < |
| 888 | &rec.ir_free, &i))) | 893 | rec.ir_startino - pagino; |
| 889 | goto error1; | 894 | } else { |
| 890 | XFS_WANT_CORRUPTED_GOTO(i == 1, | 895 | useleft = !doneleft; |
| 891 | error1); | ||
| 892 | } | ||
| 893 | } | ||
| 894 | } | 896 | } |
| 895 | ASSERT(!doneleft || !doneright); | 897 | |
| 898 | /* free inodes to the left? */ | ||
| 899 | if (useleft && trec.ir_freecount) { | ||
| 900 | rec = trec; | ||
| 901 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); | ||
| 902 | cur = tcur; | ||
| 903 | |||
| 904 | pag->pagl_leftrec = trec.ir_startino; | ||
| 905 | pag->pagl_rightrec = rec.ir_startino; | ||
| 906 | pag->pagl_pagino = pagino; | ||
| 907 | goto alloc_inode; | ||
| 908 | } | ||
| 909 | |||
| 910 | /* free inodes to the right? */ | ||
| 911 | if (!useleft && rec.ir_freecount) { | ||
| 912 | xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); | ||
| 913 | |||
| 914 | pag->pagl_leftrec = trec.ir_startino; | ||
| 915 | pag->pagl_rightrec = rec.ir_startino; | ||
| 916 | pag->pagl_pagino = pagino; | ||
| 917 | goto alloc_inode; | ||
| 918 | } | ||
| 919 | |||
| 920 | /* get next record to check */ | ||
| 921 | if (useleft) { | ||
| 922 | error = xfs_ialloc_next_rec(tcur, &trec, | ||
| 923 | &doneleft, 1); | ||
| 924 | } else { | ||
| 925 | error = xfs_ialloc_next_rec(cur, &rec, | ||
| 926 | &doneright, 0); | ||
| 927 | } | ||
| 928 | if (error) | ||
| 929 | goto error1; | ||
| 896 | } | 930 | } |
| 931 | |||
| 932 | /* | ||
| 933 | * We've reached the end of the btree. because | ||
| 934 | * we are only searching a small chunk of the | ||
| 935 | * btree each search, there is obviously free | ||
| 936 | * inodes closer to the parent inode than we | ||
| 937 | * are now. restart the search again. | ||
| 938 | */ | ||
| 939 | pag->pagl_pagino = NULLAGINO; | ||
| 940 | pag->pagl_leftrec = NULLAGINO; | ||
| 941 | pag->pagl_rightrec = NULLAGINO; | ||
| 942 | xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); | ||
| 943 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); | ||
| 944 | goto restart_pagno; | ||
| 897 | } | 945 | } |
| 946 | |||
| 898 | /* | 947 | /* |
| 899 | * In a different a.g. from the parent. | 948 | * In a different AG from the parent. |
| 900 | * See if the most recently allocated block has any free. | 949 | * See if the most recently allocated block has any free. |
| 901 | */ | 950 | */ |
| 902 | else if (be32_to_cpu(agi->agi_newino) != NULLAGINO) { | 951 | newino: |
| 903 | if ((error = xfs_inobt_lookup_eq(cur, | 952 | if (be32_to_cpu(agi->agi_newino) != NULLAGINO) { |
| 904 | be32_to_cpu(agi->agi_newino), 0, 0, &i))) | 953 | error = xfs_inobt_lookup(cur, be32_to_cpu(agi->agi_newino), |
| 954 | XFS_LOOKUP_EQ, &i); | ||
| 955 | if (error) | ||
| 905 | goto error0; | 956 | goto error0; |
| 906 | if (i == 1 && | 957 | |
| 907 | (error = xfs_inobt_get_rec(cur, &rec.ir_startino, | 958 | if (i == 1) { |
| 908 | &rec.ir_freecount, &rec.ir_free, &j)) == 0 && | 959 | error = xfs_inobt_get_rec(cur, &rec, &j); |
| 909 | j == 1 && | ||
| 910 | rec.ir_freecount > 0) { | ||
| 911 | /* | ||
| 912 | * The last chunk allocated in the group still has | ||
| 913 | * a free inode. | ||
| 914 | */ | ||
| 915 | } | ||
| 916 | /* | ||
| 917 | * None left in the last group, search the whole a.g. | ||
| 918 | */ | ||
| 919 | else { | ||
| 920 | if (error) | 960 | if (error) |
| 921 | goto error0; | 961 | goto error0; |
| 922 | if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) | 962 | |
| 923 | goto error0; | 963 | if (j == 1 && rec.ir_freecount > 0) { |
| 924 | ASSERT(i == 1); | 964 | /* |
| 925 | for (;;) { | 965 | * The last chunk allocated in the group |
| 926 | if ((error = xfs_inobt_get_rec(cur, | 966 | * still has a free inode. |
| 927 | &rec.ir_startino, | 967 | */ |
| 928 | &rec.ir_freecount, &rec.ir_free, | 968 | goto alloc_inode; |
| 929 | &i))) | ||
| 930 | goto error0; | ||
| 931 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
| 932 | if (rec.ir_freecount > 0) | ||
| 933 | break; | ||
| 934 | if ((error = xfs_btree_increment(cur, 0, &i))) | ||
| 935 | goto error0; | ||
| 936 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
| 937 | } | 969 | } |
| 938 | } | 970 | } |
| 939 | } | 971 | } |
| 972 | |||
| 973 | /* | ||
| 974 | * None left in the last group, search the whole AG | ||
| 975 | */ | ||
| 976 | error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); | ||
| 977 | if (error) | ||
| 978 | goto error0; | ||
| 979 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
| 980 | |||
| 981 | for (;;) { | ||
| 982 | error = xfs_inobt_get_rec(cur, &rec, &i); | ||
| 983 | if (error) | ||
| 984 | goto error0; | ||
| 985 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
| 986 | if (rec.ir_freecount > 0) | ||
| 987 | break; | ||
| 988 | error = xfs_btree_increment(cur, 0, &i); | ||
| 989 | if (error) | ||
| 990 | goto error0; | ||
| 991 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
| 992 | } | ||
| 993 | |||
| 994 | alloc_inode: | ||
| 940 | offset = xfs_ialloc_find_free(&rec.ir_free); | 995 | offset = xfs_ialloc_find_free(&rec.ir_free); |
| 941 | ASSERT(offset >= 0); | 996 | ASSERT(offset >= 0); |
| 942 | ASSERT(offset < XFS_INODES_PER_CHUNK); | 997 | ASSERT(offset < XFS_INODES_PER_CHUNK); |
| @@ -945,33 +1000,19 @@ nextag: | |||
| 945 | ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); | 1000 | ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); |
| 946 | rec.ir_free &= ~XFS_INOBT_MASK(offset); | 1001 | rec.ir_free &= ~XFS_INOBT_MASK(offset); |
| 947 | rec.ir_freecount--; | 1002 | rec.ir_freecount--; |
| 948 | if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount, | 1003 | error = xfs_inobt_update(cur, &rec); |
| 949 | rec.ir_free))) | 1004 | if (error) |
| 950 | goto error0; | 1005 | goto error0; |
| 951 | be32_add_cpu(&agi->agi_freecount, -1); | 1006 | be32_add_cpu(&agi->agi_freecount, -1); |
| 952 | xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); | 1007 | xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); |
| 953 | down_read(&mp->m_peraglock); | 1008 | down_read(&mp->m_peraglock); |
| 954 | mp->m_perag[tagno].pagi_freecount--; | 1009 | mp->m_perag[tagno].pagi_freecount--; |
| 955 | up_read(&mp->m_peraglock); | 1010 | up_read(&mp->m_peraglock); |
| 956 | #ifdef DEBUG | ||
| 957 | if (cur->bc_nlevels == 1) { | ||
| 958 | int freecount = 0; | ||
| 959 | 1011 | ||
| 960 | if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) | 1012 | error = xfs_check_agi_freecount(cur, agi); |
| 961 | goto error0; | 1013 | if (error) |
| 962 | do { | 1014 | goto error0; |
| 963 | if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, | 1015 | |
| 964 | &rec.ir_freecount, &rec.ir_free, &i))) | ||
| 965 | goto error0; | ||
| 966 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
| 967 | freecount += rec.ir_freecount; | ||
| 968 | if ((error = xfs_btree_increment(cur, 0, &i))) | ||
| 969 | goto error0; | ||
| 970 | } while (i == 1); | ||
| 971 | ASSERT(freecount == be32_to_cpu(agi->agi_freecount) || | ||
| 972 | XFS_FORCED_SHUTDOWN(mp)); | ||
| 973 | } | ||
| 974 | #endif | ||
| 975 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); | 1016 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); |
| 976 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); | 1017 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); |
| 977 | *inop = ino; | 1018 | *inop = ino; |
| @@ -1062,38 +1103,23 @@ xfs_difree( | |||
| 1062 | * Initialize the cursor. | 1103 | * Initialize the cursor. |
| 1063 | */ | 1104 | */ |
| 1064 | cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); | 1105 | cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); |
| 1065 | #ifdef DEBUG | ||
| 1066 | if (cur->bc_nlevels == 1) { | ||
| 1067 | int freecount = 0; | ||
| 1068 | 1106 | ||
| 1069 | if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) | 1107 | error = xfs_check_agi_freecount(cur, agi); |
| 1070 | goto error0; | 1108 | if (error) |
| 1071 | do { | 1109 | goto error0; |
| 1072 | if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, | 1110 | |
| 1073 | &rec.ir_freecount, &rec.ir_free, &i))) | ||
| 1074 | goto error0; | ||
| 1075 | if (i) { | ||
| 1076 | freecount += rec.ir_freecount; | ||
| 1077 | if ((error = xfs_btree_increment(cur, 0, &i))) | ||
| 1078 | goto error0; | ||
| 1079 | } | ||
| 1080 | } while (i == 1); | ||
| 1081 | ASSERT(freecount == be32_to_cpu(agi->agi_freecount) || | ||
| 1082 | XFS_FORCED_SHUTDOWN(mp)); | ||
| 1083 | } | ||
| 1084 | #endif | ||
| 1085 | /* | 1111 | /* |
| 1086 | * Look for the entry describing this inode. | 1112 | * Look for the entry describing this inode. |
| 1087 | */ | 1113 | */ |
| 1088 | if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) { | 1114 | if ((error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i))) { |
| 1089 | cmn_err(CE_WARN, | 1115 | cmn_err(CE_WARN, |
| 1090 | "xfs_difree: xfs_inobt_lookup_le returned() an error %d on %s. Returning error.", | 1116 | "xfs_difree: xfs_inobt_lookup returned() an error %d on %s. Returning error.", |
| 1091 | error, mp->m_fsname); | 1117 | error, mp->m_fsname); |
| 1092 | goto error0; | 1118 | goto error0; |
| 1093 | } | 1119 | } |
| 1094 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 1120 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
| 1095 | if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, &rec.ir_freecount, | 1121 | error = xfs_inobt_get_rec(cur, &rec, &i); |
| 1096 | &rec.ir_free, &i))) { | 1122 | if (error) { |
| 1097 | cmn_err(CE_WARN, | 1123 | cmn_err(CE_WARN, |
| 1098 | "xfs_difree: xfs_inobt_get_rec() returned an error %d on %s. Returning error.", | 1124 | "xfs_difree: xfs_inobt_get_rec() returned an error %d on %s. Returning error.", |
| 1099 | error, mp->m_fsname); | 1125 | error, mp->m_fsname); |
| @@ -1148,12 +1174,14 @@ xfs_difree( | |||
| 1148 | } else { | 1174 | } else { |
| 1149 | *delete = 0; | 1175 | *delete = 0; |
| 1150 | 1176 | ||
| 1151 | if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount, rec.ir_free))) { | 1177 | error = xfs_inobt_update(cur, &rec); |
| 1178 | if (error) { | ||
| 1152 | cmn_err(CE_WARN, | 1179 | cmn_err(CE_WARN, |
| 1153 | "xfs_difree: xfs_inobt_update() returned an error %d on %s. Returning error.", | 1180 | "xfs_difree: xfs_inobt_update returned an error %d on %s.", |
| 1154 | error, mp->m_fsname); | 1181 | error, mp->m_fsname); |
| 1155 | goto error0; | 1182 | goto error0; |
| 1156 | } | 1183 | } |
| 1184 | |||
| 1157 | /* | 1185 | /* |
| 1158 | * Change the inode free counts and log the ag/sb changes. | 1186 | * Change the inode free counts and log the ag/sb changes. |
| 1159 | */ | 1187 | */ |
| @@ -1165,28 +1193,10 @@ xfs_difree( | |||
| 1165 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); | 1193 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); |
| 1166 | } | 1194 | } |
| 1167 | 1195 | ||
| 1168 | #ifdef DEBUG | 1196 | error = xfs_check_agi_freecount(cur, agi); |
| 1169 | if (cur->bc_nlevels == 1) { | 1197 | if (error) |
| 1170 | int freecount = 0; | 1198 | goto error0; |
| 1171 | 1199 | ||
| 1172 | if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) | ||
| 1173 | goto error0; | ||
| 1174 | do { | ||
| 1175 | if ((error = xfs_inobt_get_rec(cur, | ||
| 1176 | &rec.ir_startino, | ||
| 1177 | &rec.ir_freecount, | ||
| 1178 | &rec.ir_free, &i))) | ||
| 1179 | goto error0; | ||
| 1180 | if (i) { | ||
| 1181 | freecount += rec.ir_freecount; | ||
| 1182 | if ((error = xfs_btree_increment(cur, 0, &i))) | ||
| 1183 | goto error0; | ||
| 1184 | } | ||
| 1185 | } while (i == 1); | ||
| 1186 | ASSERT(freecount == be32_to_cpu(agi->agi_freecount) || | ||
| 1187 | XFS_FORCED_SHUTDOWN(mp)); | ||
| 1188 | } | ||
| 1189 | #endif | ||
| 1190 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); | 1200 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); |
| 1191 | return 0; | 1201 | return 0; |
| 1192 | 1202 | ||
| @@ -1297,9 +1307,7 @@ xfs_imap( | |||
| 1297 | chunk_agbno = agbno - offset_agbno; | 1307 | chunk_agbno = agbno - offset_agbno; |
| 1298 | } else { | 1308 | } else { |
| 1299 | xfs_btree_cur_t *cur; /* inode btree cursor */ | 1309 | xfs_btree_cur_t *cur; /* inode btree cursor */ |
| 1300 | xfs_agino_t chunk_agino; /* first agino in inode chunk */ | 1310 | xfs_inobt_rec_incore_t chunk_rec; |
| 1301 | __int32_t chunk_cnt; /* count of free inodes in chunk */ | ||
| 1302 | xfs_inofree_t chunk_free; /* mask of free inodes in chunk */ | ||
| 1303 | xfs_buf_t *agbp; /* agi buffer */ | 1311 | xfs_buf_t *agbp; /* agi buffer */ |
| 1304 | int i; /* temp state */ | 1312 | int i; /* temp state */ |
| 1305 | 1313 | ||
| @@ -1315,15 +1323,14 @@ xfs_imap( | |||
| 1315 | } | 1323 | } |
| 1316 | 1324 | ||
| 1317 | cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); | 1325 | cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); |
| 1318 | error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i); | 1326 | error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i); |
| 1319 | if (error) { | 1327 | if (error) { |
| 1320 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " | 1328 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " |
| 1321 | "xfs_inobt_lookup_le() failed"); | 1329 | "xfs_inobt_lookup() failed"); |
| 1322 | goto error0; | 1330 | goto error0; |
| 1323 | } | 1331 | } |
| 1324 | 1332 | ||
| 1325 | error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt, | 1333 | error = xfs_inobt_get_rec(cur, &chunk_rec, &i); |
| 1326 | &chunk_free, &i); | ||
| 1327 | if (error) { | 1334 | if (error) { |
| 1328 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " | 1335 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " |
| 1329 | "xfs_inobt_get_rec() failed"); | 1336 | "xfs_inobt_get_rec() failed"); |
| @@ -1341,7 +1348,7 @@ xfs_imap( | |||
| 1341 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); | 1348 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); |
| 1342 | if (error) | 1349 | if (error) |
| 1343 | return error; | 1350 | return error; |
| 1344 | chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_agino); | 1351 | chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_rec.ir_startino); |
| 1345 | offset_agbno = agbno - chunk_agbno; | 1352 | offset_agbno = agbno - chunk_agbno; |
| 1346 | } | 1353 | } |
| 1347 | 1354 | ||
diff --git a/fs/xfs/xfs_ialloc.h b/fs/xfs/xfs_ialloc.h index aeee8278f92..bb5385475e1 100644 --- a/fs/xfs/xfs_ialloc.h +++ b/fs/xfs/xfs_ialloc.h | |||
| @@ -150,23 +150,15 @@ xfs_ialloc_pagi_init( | |||
| 150 | xfs_agnumber_t agno); /* allocation group number */ | 150 | xfs_agnumber_t agno); /* allocation group number */ |
| 151 | 151 | ||
| 152 | /* | 152 | /* |
| 153 | * Lookup the first record greater than or equal to ino | 153 | * Lookup a record by ino in the btree given by cur. |
| 154 | * in the btree given by cur. | ||
| 155 | */ | 154 | */ |
| 156 | int xfs_inobt_lookup_ge(struct xfs_btree_cur *cur, xfs_agino_t ino, | 155 | int xfs_inobt_lookup(struct xfs_btree_cur *cur, xfs_agino_t ino, |
| 157 | __int32_t fcnt, xfs_inofree_t free, int *stat); | 156 | xfs_lookup_t dir, int *stat); |
| 158 | |||
| 159 | /* | ||
| 160 | * Lookup the first record less than or equal to ino | ||
| 161 | * in the btree given by cur. | ||
| 162 | */ | ||
| 163 | int xfs_inobt_lookup_le(struct xfs_btree_cur *cur, xfs_agino_t ino, | ||
| 164 | __int32_t fcnt, xfs_inofree_t free, int *stat); | ||
| 165 | 157 | ||
| 166 | /* | 158 | /* |
| 167 | * Get the data from the pointed-to record. | 159 | * Get the data from the pointed-to record. |
| 168 | */ | 160 | */ |
| 169 | extern int xfs_inobt_get_rec(struct xfs_btree_cur *cur, xfs_agino_t *ino, | 161 | extern int xfs_inobt_get_rec(struct xfs_btree_cur *cur, |
| 170 | __int32_t *fcnt, xfs_inofree_t *free, int *stat); | 162 | xfs_inobt_rec_incore_t *rec, int *stat); |
| 171 | 163 | ||
| 172 | #endif /* __XFS_IALLOC_H__ */ | 164 | #endif /* __XFS_IALLOC_H__ */ |
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index ecbf8b4d2e2..80e526489be 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c | |||
| @@ -82,7 +82,6 @@ xfs_inode_alloc( | |||
| 82 | memset(&ip->i_df, 0, sizeof(xfs_ifork_t)); | 82 | memset(&ip->i_df, 0, sizeof(xfs_ifork_t)); |
| 83 | ip->i_flags = 0; | 83 | ip->i_flags = 0; |
| 84 | ip->i_update_core = 0; | 84 | ip->i_update_core = 0; |
| 85 | ip->i_update_size = 0; | ||
| 86 | ip->i_delayed_blks = 0; | 85 | ip->i_delayed_blks = 0; |
| 87 | memset(&ip->i_d, 0, sizeof(xfs_icdinode_t)); | 86 | memset(&ip->i_d, 0, sizeof(xfs_icdinode_t)); |
| 88 | ip->i_size = 0; | 87 | ip->i_size = 0; |
| @@ -456,32 +455,6 @@ out_error_or_again: | |||
| 456 | return error; | 455 | return error; |
| 457 | } | 456 | } |
| 458 | 457 | ||
| 459 | |||
| 460 | /* | ||
| 461 | * Look for the inode corresponding to the given ino in the hash table. | ||
| 462 | * If it is there and its i_transp pointer matches tp, return it. | ||
| 463 | * Otherwise, return NULL. | ||
| 464 | */ | ||
| 465 | xfs_inode_t * | ||
| 466 | xfs_inode_incore(xfs_mount_t *mp, | ||
| 467 | xfs_ino_t ino, | ||
| 468 | xfs_trans_t *tp) | ||
| 469 | { | ||
| 470 | xfs_inode_t *ip; | ||
| 471 | xfs_perag_t *pag; | ||
| 472 | |||
| 473 | pag = xfs_get_perag(mp, ino); | ||
| 474 | read_lock(&pag->pag_ici_lock); | ||
| 475 | ip = radix_tree_lookup(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, ino)); | ||
| 476 | read_unlock(&pag->pag_ici_lock); | ||
| 477 | xfs_put_perag(mp, pag); | ||
| 478 | |||
| 479 | /* the returned inode must match the transaction */ | ||
| 480 | if (ip && (ip->i_transp != tp)) | ||
| 481 | return NULL; | ||
| 482 | return ip; | ||
| 483 | } | ||
| 484 | |||
| 485 | /* | 458 | /* |
| 486 | * Decrement reference count of an inode structure and unlock it. | 459 | * Decrement reference count of an inode structure and unlock it. |
| 487 | * | 460 | * |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index da428b3fe0f..c1dc7ef5a1d 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -651,7 +651,7 @@ xfs_iformat_btree( | |||
| 651 | return 0; | 651 | return 0; |
| 652 | } | 652 | } |
| 653 | 653 | ||
| 654 | void | 654 | STATIC void |
| 655 | xfs_dinode_from_disk( | 655 | xfs_dinode_from_disk( |
| 656 | xfs_icdinode_t *to, | 656 | xfs_icdinode_t *to, |
| 657 | xfs_dinode_t *from) | 657 | xfs_dinode_t *from) |
| @@ -1247,7 +1247,7 @@ xfs_isize_check( | |||
| 1247 | * In that case the pages will still be in memory, but the inode size | 1247 | * In that case the pages will still be in memory, but the inode size |
| 1248 | * will never have been updated. | 1248 | * will never have been updated. |
| 1249 | */ | 1249 | */ |
| 1250 | xfs_fsize_t | 1250 | STATIC xfs_fsize_t |
| 1251 | xfs_file_last_byte( | 1251 | xfs_file_last_byte( |
| 1252 | xfs_inode_t *ip) | 1252 | xfs_inode_t *ip) |
| 1253 | { | 1253 | { |
| @@ -3837,7 +3837,7 @@ xfs_iext_inline_to_direct( | |||
| 3837 | /* | 3837 | /* |
| 3838 | * Resize an extent indirection array to new_size bytes. | 3838 | * Resize an extent indirection array to new_size bytes. |
| 3839 | */ | 3839 | */ |
| 3840 | void | 3840 | STATIC void |
| 3841 | xfs_iext_realloc_indirect( | 3841 | xfs_iext_realloc_indirect( |
| 3842 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3842 | xfs_ifork_t *ifp, /* inode fork pointer */ |
| 3843 | int new_size) /* new indirection array size */ | 3843 | int new_size) /* new indirection array size */ |
| @@ -3862,7 +3862,7 @@ xfs_iext_realloc_indirect( | |||
| 3862 | /* | 3862 | /* |
| 3863 | * Switch from indirection array to linear (direct) extent allocations. | 3863 | * Switch from indirection array to linear (direct) extent allocations. |
| 3864 | */ | 3864 | */ |
| 3865 | void | 3865 | STATIC void |
| 3866 | xfs_iext_indirect_to_direct( | 3866 | xfs_iext_indirect_to_direct( |
| 3867 | xfs_ifork_t *ifp) /* inode fork pointer */ | 3867 | xfs_ifork_t *ifp) /* inode fork pointer */ |
| 3868 | { | 3868 | { |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 65f24a3cc99..0b38b9a869e 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
| @@ -261,7 +261,6 @@ typedef struct xfs_inode { | |||
| 261 | /* Miscellaneous state. */ | 261 | /* Miscellaneous state. */ |
| 262 | unsigned short i_flags; /* see defined flags below */ | 262 | unsigned short i_flags; /* see defined flags below */ |
| 263 | unsigned char i_update_core; /* timestamps/size is dirty */ | 263 | unsigned char i_update_core; /* timestamps/size is dirty */ |
| 264 | unsigned char i_update_size; /* di_size field is dirty */ | ||
| 265 | unsigned int i_delayed_blks; /* count of delay alloc blks */ | 264 | unsigned int i_delayed_blks; /* count of delay alloc blks */ |
| 266 | 265 | ||
| 267 | xfs_icdinode_t i_d; /* most of ondisk inode */ | 266 | xfs_icdinode_t i_d; /* most of ondisk inode */ |
| @@ -468,8 +467,6 @@ static inline void xfs_ifunlock(xfs_inode_t *ip) | |||
| 468 | /* | 467 | /* |
| 469 | * xfs_iget.c prototypes. | 468 | * xfs_iget.c prototypes. |
| 470 | */ | 469 | */ |
| 471 | xfs_inode_t *xfs_inode_incore(struct xfs_mount *, xfs_ino_t, | ||
| 472 | struct xfs_trans *); | ||
| 473 | int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, | 470 | int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, |
| 474 | uint, uint, xfs_inode_t **, xfs_daddr_t); | 471 | uint, uint, xfs_inode_t **, xfs_daddr_t); |
| 475 | void xfs_iput(xfs_inode_t *, uint); | 472 | void xfs_iput(xfs_inode_t *, uint); |
| @@ -504,7 +501,6 @@ void xfs_ipin(xfs_inode_t *); | |||
| 504 | void xfs_iunpin(xfs_inode_t *); | 501 | void xfs_iunpin(xfs_inode_t *); |
| 505 | int xfs_iflush(xfs_inode_t *, uint); | 502 | int xfs_iflush(xfs_inode_t *, uint); |
| 506 | void xfs_ichgtime(xfs_inode_t *, int); | 503 | void xfs_ichgtime(xfs_inode_t *, int); |
| 507 | xfs_fsize_t xfs_file_last_byte(xfs_inode_t *); | ||
| 508 | void xfs_lock_inodes(xfs_inode_t **, int, uint); | 504 | void xfs_lock_inodes(xfs_inode_t **, int, uint); |
| 509 | void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint); | 505 | void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint); |
| 510 | 506 | ||
| @@ -572,8 +568,6 @@ int xfs_itobp(struct xfs_mount *, struct xfs_trans *, | |||
| 572 | struct xfs_buf **, uint); | 568 | struct xfs_buf **, uint); |
| 573 | int xfs_iread(struct xfs_mount *, struct xfs_trans *, | 569 | int xfs_iread(struct xfs_mount *, struct xfs_trans *, |
| 574 | struct xfs_inode *, xfs_daddr_t, uint); | 570 | struct xfs_inode *, xfs_daddr_t, uint); |
| 575 | void xfs_dinode_from_disk(struct xfs_icdinode *, | ||
| 576 | struct xfs_dinode *); | ||
| 577 | void xfs_dinode_to_disk(struct xfs_dinode *, | 571 | void xfs_dinode_to_disk(struct xfs_dinode *, |
| 578 | struct xfs_icdinode *); | 572 | struct xfs_icdinode *); |
| 579 | void xfs_idestroy_fork(struct xfs_inode *, int); | 573 | void xfs_idestroy_fork(struct xfs_inode *, int); |
| @@ -592,8 +586,6 @@ void xfs_iext_remove_inline(xfs_ifork_t *, xfs_extnum_t, int); | |||
| 592 | void xfs_iext_remove_direct(xfs_ifork_t *, xfs_extnum_t, int); | 586 | void xfs_iext_remove_direct(xfs_ifork_t *, xfs_extnum_t, int); |
| 593 | void xfs_iext_remove_indirect(xfs_ifork_t *, xfs_extnum_t, int); | 587 | void xfs_iext_remove_indirect(xfs_ifork_t *, xfs_extnum_t, int); |
| 594 | void xfs_iext_realloc_direct(xfs_ifork_t *, int); | 588 | void xfs_iext_realloc_direct(xfs_ifork_t *, int); |
| 595 | void xfs_iext_realloc_indirect(xfs_ifork_t *, int); | ||
| 596 | void xfs_iext_indirect_to_direct(xfs_ifork_t *); | ||
| 597 | void xfs_iext_direct_to_inline(xfs_ifork_t *, xfs_extnum_t); | 589 | void xfs_iext_direct_to_inline(xfs_ifork_t *, xfs_extnum_t); |
| 598 | void xfs_iext_inline_to_direct(xfs_ifork_t *, int); | 590 | void xfs_iext_inline_to_direct(xfs_ifork_t *, int); |
| 599 | void xfs_iext_destroy(xfs_ifork_t *); | 591 | void xfs_iext_destroy(xfs_ifork_t *); |
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 977c4aec587..47d5b663c37 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c | |||
| @@ -263,14 +263,6 @@ xfs_inode_item_format( | |||
| 263 | } | 263 | } |
| 264 | 264 | ||
| 265 | /* | 265 | /* |
| 266 | * We don't have to worry about re-ordering here because | ||
| 267 | * the update_size field is protected by the inode lock | ||
| 268 | * and we have that held in exclusive mode. | ||
| 269 | */ | ||
| 270 | if (ip->i_update_size) | ||
| 271 | ip->i_update_size = 0; | ||
| 272 | |||
| 273 | /* | ||
| 274 | * Make sure to get the latest atime from the Linux inode. | 266 | * Make sure to get the latest atime from the Linux inode. |
| 275 | */ | 267 | */ |
| 276 | xfs_synchronize_atime(ip); | 268 | xfs_synchronize_atime(ip); |
| @@ -712,8 +704,6 @@ xfs_inode_item_unlock( | |||
| 712 | * Clear out the fields of the inode log item particular | 704 | * Clear out the fields of the inode log item particular |
| 713 | * to the current transaction. | 705 | * to the current transaction. |
| 714 | */ | 706 | */ |
| 715 | iip->ili_ilock_recur = 0; | ||
| 716 | iip->ili_iolock_recur = 0; | ||
| 717 | iip->ili_flags = 0; | 707 | iip->ili_flags = 0; |
| 718 | 708 | ||
| 719 | /* | 709 | /* |
diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h index a52ac125f05..65bae4c9b8b 100644 --- a/fs/xfs/xfs_inode_item.h +++ b/fs/xfs/xfs_inode_item.h | |||
| @@ -137,8 +137,6 @@ typedef struct xfs_inode_log_item { | |||
| 137 | struct xfs_inode *ili_inode; /* inode ptr */ | 137 | struct xfs_inode *ili_inode; /* inode ptr */ |
| 138 | xfs_lsn_t ili_flush_lsn; /* lsn at last flush */ | 138 | xfs_lsn_t ili_flush_lsn; /* lsn at last flush */ |
| 139 | xfs_lsn_t ili_last_lsn; /* lsn at last transaction */ | 139 | xfs_lsn_t ili_last_lsn; /* lsn at last transaction */ |
| 140 | unsigned short ili_ilock_recur; /* lock recursion count */ | ||
| 141 | unsigned short ili_iolock_recur; /* lock recursion count */ | ||
| 142 | unsigned short ili_flags; /* misc flags */ | 140 | unsigned short ili_flags; /* misc flags */ |
| 143 | unsigned short ili_logged; /* flushed logged data */ | 141 | unsigned short ili_logged; /* flushed logged data */ |
| 144 | unsigned int ili_last_fields; /* fields when flushed */ | 142 | unsigned int ili_last_fields; /* fields when flushed */ |
diff --git a/fs/xfs/xfs_inum.h b/fs/xfs/xfs_inum.h index 7a28191cb0d..b8e4ee4e89a 100644 --- a/fs/xfs/xfs_inum.h +++ b/fs/xfs/xfs_inum.h | |||
| @@ -72,7 +72,6 @@ struct xfs_mount; | |||
| 72 | 72 | ||
| 73 | #if XFS_BIG_INUMS | 73 | #if XFS_BIG_INUMS |
| 74 | #define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 56) - 1ULL)) | 74 | #define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 56) - 1ULL)) |
| 75 | #define XFS_INO64_OFFSET ((xfs_ino_t)(1ULL << 32)) | ||
| 76 | #else | 75 | #else |
| 77 | #define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 32) - 1ULL)) | 76 | #define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 32) - 1ULL)) |
| 78 | #endif | 77 | #endif |
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index aeb2d2221c7..b68f9107e26 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
| @@ -39,7 +39,7 @@ | |||
| 39 | #include "xfs_error.h" | 39 | #include "xfs_error.h" |
| 40 | #include "xfs_btree.h" | 40 | #include "xfs_btree.h" |
| 41 | 41 | ||
| 42 | int | 42 | STATIC int |
| 43 | xfs_internal_inum( | 43 | xfs_internal_inum( |
| 44 | xfs_mount_t *mp, | 44 | xfs_mount_t *mp, |
| 45 | xfs_ino_t ino) | 45 | xfs_ino_t ino) |
| @@ -353,9 +353,6 @@ xfs_bulkstat( | |||
| 353 | int end_of_ag; /* set if we've seen the ag end */ | 353 | int end_of_ag; /* set if we've seen the ag end */ |
| 354 | int error; /* error code */ | 354 | int error; /* error code */ |
| 355 | int fmterror;/* bulkstat formatter result */ | 355 | int fmterror;/* bulkstat formatter result */ |
| 356 | __int32_t gcnt; /* current btree rec's count */ | ||
| 357 | xfs_inofree_t gfree; /* current btree rec's free mask */ | ||
| 358 | xfs_agino_t gino; /* current btree rec's start inode */ | ||
| 359 | int i; /* loop index */ | 356 | int i; /* loop index */ |
| 360 | int icount; /* count of inodes good in irbuf */ | 357 | int icount; /* count of inodes good in irbuf */ |
| 361 | size_t irbsize; /* size of irec buffer in bytes */ | 358 | size_t irbsize; /* size of irec buffer in bytes */ |
| @@ -442,40 +439,43 @@ xfs_bulkstat( | |||
| 442 | * we need to get the remainder of the chunk we're in. | 439 | * we need to get the remainder of the chunk we're in. |
| 443 | */ | 440 | */ |
| 444 | if (agino > 0) { | 441 | if (agino > 0) { |
| 442 | xfs_inobt_rec_incore_t r; | ||
| 443 | |||
| 445 | /* | 444 | /* |
| 446 | * Lookup the inode chunk that this inode lives in. | 445 | * Lookup the inode chunk that this inode lives in. |
| 447 | */ | 446 | */ |
| 448 | error = xfs_inobt_lookup_le(cur, agino, 0, 0, &tmp); | 447 | error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, |
| 448 | &tmp); | ||
| 449 | if (!error && /* no I/O error */ | 449 | if (!error && /* no I/O error */ |
| 450 | tmp && /* lookup succeeded */ | 450 | tmp && /* lookup succeeded */ |
| 451 | /* got the record, should always work */ | 451 | /* got the record, should always work */ |
| 452 | !(error = xfs_inobt_get_rec(cur, &gino, &gcnt, | 452 | !(error = xfs_inobt_get_rec(cur, &r, &i)) && |
| 453 | &gfree, &i)) && | ||
| 454 | i == 1 && | 453 | i == 1 && |
| 455 | /* this is the right chunk */ | 454 | /* this is the right chunk */ |
| 456 | agino < gino + XFS_INODES_PER_CHUNK && | 455 | agino < r.ir_startino + XFS_INODES_PER_CHUNK && |
| 457 | /* lastino was not last in chunk */ | 456 | /* lastino was not last in chunk */ |
| 458 | (chunkidx = agino - gino + 1) < | 457 | (chunkidx = agino - r.ir_startino + 1) < |
| 459 | XFS_INODES_PER_CHUNK && | 458 | XFS_INODES_PER_CHUNK && |
| 460 | /* there are some left allocated */ | 459 | /* there are some left allocated */ |
| 461 | xfs_inobt_maskn(chunkidx, | 460 | xfs_inobt_maskn(chunkidx, |
| 462 | XFS_INODES_PER_CHUNK - chunkidx) & ~gfree) { | 461 | XFS_INODES_PER_CHUNK - chunkidx) & |
| 462 | ~r.ir_free) { | ||
| 463 | /* | 463 | /* |
| 464 | * Grab the chunk record. Mark all the | 464 | * Grab the chunk record. Mark all the |
| 465 | * uninteresting inodes (because they're | 465 | * uninteresting inodes (because they're |
| 466 | * before our start point) free. | 466 | * before our start point) free. |
| 467 | */ | 467 | */ |
| 468 | for (i = 0; i < chunkidx; i++) { | 468 | for (i = 0; i < chunkidx; i++) { |
| 469 | if (XFS_INOBT_MASK(i) & ~gfree) | 469 | if (XFS_INOBT_MASK(i) & ~r.ir_free) |
| 470 | gcnt++; | 470 | r.ir_freecount++; |
| 471 | } | 471 | } |
| 472 | gfree |= xfs_inobt_maskn(0, chunkidx); | 472 | r.ir_free |= xfs_inobt_maskn(0, chunkidx); |
| 473 | irbp->ir_startino = gino; | 473 | irbp->ir_startino = r.ir_startino; |
| 474 | irbp->ir_freecount = gcnt; | 474 | irbp->ir_freecount = r.ir_freecount; |
| 475 | irbp->ir_free = gfree; | 475 | irbp->ir_free = r.ir_free; |
| 476 | irbp++; | 476 | irbp++; |
| 477 | agino = gino + XFS_INODES_PER_CHUNK; | 477 | agino = r.ir_startino + XFS_INODES_PER_CHUNK; |
| 478 | icount = XFS_INODES_PER_CHUNK - gcnt; | 478 | icount = XFS_INODES_PER_CHUNK - r.ir_freecount; |
| 479 | } else { | 479 | } else { |
| 480 | /* | 480 | /* |
| 481 | * If any of those tests failed, bump the | 481 | * If any of those tests failed, bump the |
| @@ -493,7 +493,7 @@ xfs_bulkstat( | |||
| 493 | /* | 493 | /* |
| 494 | * Start of ag. Lookup the first inode chunk. | 494 | * Start of ag. Lookup the first inode chunk. |
| 495 | */ | 495 | */ |
| 496 | error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &tmp); | 496 | error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &tmp); |
| 497 | icount = 0; | 497 | icount = 0; |
| 498 | } | 498 | } |
| 499 | /* | 499 | /* |
| @@ -501,6 +501,8 @@ xfs_bulkstat( | |||
| 501 | * until we run out of inodes or space in the buffer. | 501 | * until we run out of inodes or space in the buffer. |
| 502 | */ | 502 | */ |
| 503 | while (irbp < irbufend && icount < ubcount) { | 503 | while (irbp < irbufend && icount < ubcount) { |
| 504 | xfs_inobt_rec_incore_t r; | ||
| 505 | |||
| 504 | /* | 506 | /* |
| 505 | * Loop as long as we're unable to read the | 507 | * Loop as long as we're unable to read the |
| 506 | * inode btree. | 508 | * inode btree. |
| @@ -510,51 +512,55 @@ xfs_bulkstat( | |||
| 510 | if (XFS_AGINO_TO_AGBNO(mp, agino) >= | 512 | if (XFS_AGINO_TO_AGBNO(mp, agino) >= |
| 511 | be32_to_cpu(agi->agi_length)) | 513 | be32_to_cpu(agi->agi_length)) |
| 512 | break; | 514 | break; |
| 513 | error = xfs_inobt_lookup_ge(cur, agino, 0, 0, | 515 | error = xfs_inobt_lookup(cur, agino, |
| 514 | &tmp); | 516 | XFS_LOOKUP_GE, &tmp); |
| 515 | cond_resched(); | 517 | cond_resched(); |
| 516 | } | 518 | } |
| 517 | /* | 519 | /* |
| 518 | * If ran off the end of the ag either with an error, | 520 | * If ran off the end of the ag either with an error, |
| 519 | * or the normal way, set end and stop collecting. | 521 | * or the normal way, set end and stop collecting. |
| 520 | */ | 522 | */ |
| 521 | if (error || | 523 | if (error) { |
| 522 | (error = xfs_inobt_get_rec(cur, &gino, &gcnt, | ||
| 523 | &gfree, &i)) || | ||
| 524 | i == 0) { | ||
| 525 | end_of_ag = 1; | 524 | end_of_ag = 1; |
| 526 | break; | 525 | break; |
| 527 | } | 526 | } |
| 527 | |||
| 528 | error = xfs_inobt_get_rec(cur, &r, &i); | ||
| 529 | if (error || i == 0) { | ||
| 530 | end_of_ag = 1; | ||
| 531 | break; | ||
| 532 | } | ||
| 533 | |||
| 528 | /* | 534 | /* |
| 529 | * If this chunk has any allocated inodes, save it. | 535 | * If this chunk has any allocated inodes, save it. |
| 530 | * Also start read-ahead now for this chunk. | 536 | * Also start read-ahead now for this chunk. |
| 531 | */ | 537 | */ |
| 532 | if (gcnt < XFS_INODES_PER_CHUNK) { | 538 | if (r.ir_freecount < XFS_INODES_PER_CHUNK) { |
| 533 | /* | 539 | /* |
| 534 | * Loop over all clusters in the next chunk. | 540 | * Loop over all clusters in the next chunk. |
| 535 | * Do a readahead if there are any allocated | 541 | * Do a readahead if there are any allocated |
| 536 | * inodes in that cluster. | 542 | * inodes in that cluster. |
| 537 | */ | 543 | */ |
| 538 | for (agbno = XFS_AGINO_TO_AGBNO(mp, gino), | 544 | agbno = XFS_AGINO_TO_AGBNO(mp, r.ir_startino); |
| 539 | chunkidx = 0; | 545 | for (chunkidx = 0; |
| 540 | chunkidx < XFS_INODES_PER_CHUNK; | 546 | chunkidx < XFS_INODES_PER_CHUNK; |
| 541 | chunkidx += nicluster, | 547 | chunkidx += nicluster, |
| 542 | agbno += nbcluster) { | 548 | agbno += nbcluster) { |
| 543 | if (xfs_inobt_maskn(chunkidx, | 549 | if (xfs_inobt_maskn(chunkidx, nicluster) |
| 544 | nicluster) & ~gfree) | 550 | & ~r.ir_free) |
| 545 | xfs_btree_reada_bufs(mp, agno, | 551 | xfs_btree_reada_bufs(mp, agno, |
| 546 | agbno, nbcluster); | 552 | agbno, nbcluster); |
| 547 | } | 553 | } |
| 548 | irbp->ir_startino = gino; | 554 | irbp->ir_startino = r.ir_startino; |
| 549 | irbp->ir_freecount = gcnt; | 555 | irbp->ir_freecount = r.ir_freecount; |
| 550 | irbp->ir_free = gfree; | 556 | irbp->ir_free = r.ir_free; |
| 551 | irbp++; | 557 | irbp++; |
| 552 | icount += XFS_INODES_PER_CHUNK - gcnt; | 558 | icount += XFS_INODES_PER_CHUNK - r.ir_freecount; |
| 553 | } | 559 | } |
| 554 | /* | 560 | /* |
| 555 | * Set agino to after this chunk and bump the cursor. | 561 | * Set agino to after this chunk and bump the cursor. |
| 556 | */ | 562 | */ |
| 557 | agino = gino + XFS_INODES_PER_CHUNK; | 563 | agino = r.ir_startino + XFS_INODES_PER_CHUNK; |
| 558 | error = xfs_btree_increment(cur, 0, &tmp); | 564 | error = xfs_btree_increment(cur, 0, &tmp); |
| 559 | cond_resched(); | 565 | cond_resched(); |
| 560 | } | 566 | } |
| @@ -820,9 +826,7 @@ xfs_inumbers( | |||
| 820 | int bufidx; | 826 | int bufidx; |
| 821 | xfs_btree_cur_t *cur; | 827 | xfs_btree_cur_t *cur; |
| 822 | int error; | 828 | int error; |
| 823 | __int32_t gcnt; | 829 | xfs_inobt_rec_incore_t r; |
| 824 | xfs_inofree_t gfree; | ||
| 825 | xfs_agino_t gino; | ||
| 826 | int i; | 830 | int i; |
| 827 | xfs_ino_t ino; | 831 | xfs_ino_t ino; |
| 828 | int left; | 832 | int left; |
| @@ -855,7 +859,8 @@ xfs_inumbers( | |||
| 855 | continue; | 859 | continue; |
| 856 | } | 860 | } |
| 857 | cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno); | 861 | cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno); |
| 858 | error = xfs_inobt_lookup_ge(cur, agino, 0, 0, &tmp); | 862 | error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE, |
| 863 | &tmp); | ||
| 859 | if (error) { | 864 | if (error) { |
| 860 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); | 865 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); |
| 861 | cur = NULL; | 866 | cur = NULL; |
| @@ -870,9 +875,8 @@ xfs_inumbers( | |||
| 870 | continue; | 875 | continue; |
| 871 | } | 876 | } |
| 872 | } | 877 | } |
| 873 | if ((error = xfs_inobt_get_rec(cur, &gino, &gcnt, &gfree, | 878 | error = xfs_inobt_get_rec(cur, &r, &i); |
| 874 | &i)) || | 879 | if (error || i == 0) { |
| 875 | i == 0) { | ||
| 876 | xfs_buf_relse(agbp); | 880 | xfs_buf_relse(agbp); |
| 877 | agbp = NULL; | 881 | agbp = NULL; |
| 878 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); | 882 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); |
| @@ -881,10 +885,12 @@ xfs_inumbers( | |||
| 881 | agino = 0; | 885 | agino = 0; |
| 882 | continue; | 886 | continue; |
| 883 | } | 887 | } |
| 884 | agino = gino + XFS_INODES_PER_CHUNK - 1; | 888 | agino = r.ir_startino + XFS_INODES_PER_CHUNK - 1; |
| 885 | buffer[bufidx].xi_startino = XFS_AGINO_TO_INO(mp, agno, gino); | 889 | buffer[bufidx].xi_startino = |
| 886 | buffer[bufidx].xi_alloccount = XFS_INODES_PER_CHUNK - gcnt; | 890 | XFS_AGINO_TO_INO(mp, agno, r.ir_startino); |
| 887 | buffer[bufidx].xi_allocmask = ~gfree; | 891 | buffer[bufidx].xi_alloccount = |
| 892 | XFS_INODES_PER_CHUNK - r.ir_freecount; | ||
| 893 | buffer[bufidx].xi_allocmask = ~r.ir_free; | ||
| 888 | bufidx++; | 894 | bufidx++; |
| 889 | left--; | 895 | left--; |
| 890 | if (bufidx == bcount) { | 896 | if (bufidx == bcount) { |
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h index 1fb04e7deb6..20792bf4594 100644 --- a/fs/xfs/xfs_itable.h +++ b/fs/xfs/xfs_itable.h | |||
| @@ -99,11 +99,6 @@ xfs_bulkstat_one( | |||
| 99 | void *dibuff, | 99 | void *dibuff, |
| 100 | int *stat); | 100 | int *stat); |
| 101 | 101 | ||
| 102 | int | ||
| 103 | xfs_internal_inum( | ||
| 104 | xfs_mount_t *mp, | ||
| 105 | xfs_ino_t ino); | ||
| 106 | |||
| 107 | typedef int (*inumbers_fmt_pf)( | 102 | typedef int (*inumbers_fmt_pf)( |
| 108 | void __user *ubuffer, /* buffer to write to */ | 103 | void __user *ubuffer, /* buffer to write to */ |
| 109 | const xfs_inogrp_t *buffer, /* buffer to read from */ | 104 | const xfs_inogrp_t *buffer, /* buffer to read from */ |
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index bcad5f4c1fd..679c7c4926a 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h | |||
| @@ -451,8 +451,6 @@ extern int xlog_find_tail(xlog_t *log, | |||
| 451 | extern int xlog_recover(xlog_t *log); | 451 | extern int xlog_recover(xlog_t *log); |
| 452 | extern int xlog_recover_finish(xlog_t *log); | 452 | extern int xlog_recover_finish(xlog_t *log); |
| 453 | extern void xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int); | 453 | extern void xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int); |
| 454 | extern void xlog_recover_process_iunlinks(xlog_t *log); | ||
| 455 | |||
| 456 | extern struct xfs_buf *xlog_get_bp(xlog_t *, int); | 454 | extern struct xfs_buf *xlog_get_bp(xlog_t *, int); |
| 457 | extern void xlog_put_bp(struct xfs_buf *); | 455 | extern void xlog_put_bp(struct xfs_buf *); |
| 458 | 456 | ||
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 47da2fb4537..1099395d7d6 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
| @@ -3263,7 +3263,7 @@ xlog_recover_process_one_iunlink( | |||
| 3263 | * freeing of the inode and its removal from the list must be | 3263 | * freeing of the inode and its removal from the list must be |
| 3264 | * atomic. | 3264 | * atomic. |
| 3265 | */ | 3265 | */ |
| 3266 | void | 3266 | STATIC void |
| 3267 | xlog_recover_process_iunlinks( | 3267 | xlog_recover_process_iunlinks( |
| 3268 | xlog_t *log) | 3268 | xlog_t *log) |
| 3269 | { | 3269 | { |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 5c6f092659c..8b6c9e807ef 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
| @@ -1568,7 +1568,7 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) | |||
| 1568 | * | 1568 | * |
| 1569 | * The m_sb_lock must be held when this routine is called. | 1569 | * The m_sb_lock must be held when this routine is called. |
| 1570 | */ | 1570 | */ |
| 1571 | int | 1571 | STATIC int |
| 1572 | xfs_mod_incore_sb_unlocked( | 1572 | xfs_mod_incore_sb_unlocked( |
| 1573 | xfs_mount_t *mp, | 1573 | xfs_mount_t *mp, |
| 1574 | xfs_sb_field_t field, | 1574 | xfs_sb_field_t field, |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index a5122382afd..a6c023bc0fb 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
| @@ -414,13 +414,10 @@ typedef struct xfs_mod_sb { | |||
| 414 | 414 | ||
| 415 | extern int xfs_log_sbcount(xfs_mount_t *, uint); | 415 | extern int xfs_log_sbcount(xfs_mount_t *, uint); |
| 416 | extern int xfs_mountfs(xfs_mount_t *mp); | 416 | extern int xfs_mountfs(xfs_mount_t *mp); |
| 417 | extern void xfs_mountfs_check_barriers(xfs_mount_t *mp); | ||
| 418 | 417 | ||
| 419 | extern void xfs_unmountfs(xfs_mount_t *); | 418 | extern void xfs_unmountfs(xfs_mount_t *); |
| 420 | extern int xfs_unmountfs_writesb(xfs_mount_t *); | 419 | extern int xfs_unmountfs_writesb(xfs_mount_t *); |
| 421 | extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int); | 420 | extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int); |
| 422 | extern int xfs_mod_incore_sb_unlocked(xfs_mount_t *, xfs_sb_field_t, | ||
| 423 | int64_t, int); | ||
| 424 | extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, | 421 | extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, |
| 425 | uint, int); | 422 | uint, int); |
| 426 | extern int xfs_mount_log_sb(xfs_mount_t *, __int64_t); | 423 | extern int xfs_mount_log_sb(xfs_mount_t *, __int64_t); |
diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c index afee7eb2432..4b0613d99fa 100644 --- a/fs/xfs/xfs_mru_cache.c +++ b/fs/xfs/xfs_mru_cache.c | |||
| @@ -564,35 +564,6 @@ xfs_mru_cache_lookup( | |||
| 564 | } | 564 | } |
| 565 | 565 | ||
| 566 | /* | 566 | /* |
| 567 | * To look up an element using its key, but leave its location in the internal | ||
| 568 | * lists alone, call xfs_mru_cache_peek(). If the element isn't found, this | ||
| 569 | * function returns NULL. | ||
| 570 | * | ||
| 571 | * See the comments above the declaration of the xfs_mru_cache_lookup() function | ||
| 572 | * for important locking information pertaining to this call. | ||
| 573 | */ | ||
| 574 | void * | ||
| 575 | xfs_mru_cache_peek( | ||
| 576 | xfs_mru_cache_t *mru, | ||
| 577 | unsigned long key) | ||
| 578 | { | ||
| 579 | xfs_mru_cache_elem_t *elem; | ||
| 580 | |||
| 581 | ASSERT(mru && mru->lists); | ||
| 582 | if (!mru || !mru->lists) | ||
| 583 | return NULL; | ||
| 584 | |||
| 585 | spin_lock(&mru->lock); | ||
| 586 | elem = radix_tree_lookup(&mru->store, key); | ||
| 587 | if (!elem) | ||
| 588 | spin_unlock(&mru->lock); | ||
| 589 | else | ||
| 590 | __release(mru_lock); /* help sparse not be stupid */ | ||
| 591 | |||
| 592 | return elem ? elem->value : NULL; | ||
| 593 | } | ||
| 594 | |||
| 595 | /* | ||
| 596 | * To release the internal data structure spinlock after having performed an | 567 | * To release the internal data structure spinlock after having performed an |
| 597 | * xfs_mru_cache_lookup() or an xfs_mru_cache_peek(), call xfs_mru_cache_done() | 568 | * xfs_mru_cache_lookup() or an xfs_mru_cache_peek(), call xfs_mru_cache_done() |
| 598 | * with the data store pointer. | 569 | * with the data store pointer. |
diff --git a/fs/xfs/xfs_mru_cache.h b/fs/xfs/xfs_mru_cache.h index dd58ea1bbeb..5d439f34b0c 100644 --- a/fs/xfs/xfs_mru_cache.h +++ b/fs/xfs/xfs_mru_cache.h | |||
| @@ -49,7 +49,6 @@ int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key, | |||
| 49 | void * xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key); | 49 | void * xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key); |
| 50 | void xfs_mru_cache_delete(struct xfs_mru_cache *mru, unsigned long key); | 50 | void xfs_mru_cache_delete(struct xfs_mru_cache *mru, unsigned long key); |
| 51 | void *xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key); | 51 | void *xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key); |
| 52 | void *xfs_mru_cache_peek(struct xfs_mru_cache *mru, unsigned long key); | ||
| 53 | void xfs_mru_cache_done(struct xfs_mru_cache *mru); | 52 | void xfs_mru_cache_done(struct xfs_mru_cache *mru); |
| 54 | 53 | ||
| 55 | #endif /* __XFS_MRU_CACHE_H__ */ | 54 | #endif /* __XFS_MRU_CACHE_H__ */ |
diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c index fea68615ed2..3f816ad7ff1 100644 --- a/fs/xfs/xfs_rw.c +++ b/fs/xfs/xfs_rw.c | |||
| @@ -88,90 +88,6 @@ xfs_write_clear_setuid( | |||
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | /* | 90 | /* |
| 91 | * Handle logging requirements of various synchronous types of write. | ||
| 92 | */ | ||
| 93 | int | ||
| 94 | xfs_write_sync_logforce( | ||
| 95 | xfs_mount_t *mp, | ||
| 96 | xfs_inode_t *ip) | ||
| 97 | { | ||
| 98 | int error = 0; | ||
| 99 | |||
| 100 | /* | ||
| 101 | * If we're treating this as O_DSYNC and we have not updated the | ||
| 102 | * size, force the log. | ||
| 103 | */ | ||
| 104 | if (!(mp->m_flags & XFS_MOUNT_OSYNCISOSYNC) && | ||
| 105 | !(ip->i_update_size)) { | ||
| 106 | xfs_inode_log_item_t *iip = ip->i_itemp; | ||
| 107 | |||
| 108 | /* | ||
| 109 | * If an allocation transaction occurred | ||
| 110 | * without extending the size, then we have to force | ||
| 111 | * the log up the proper point to ensure that the | ||
| 112 | * allocation is permanent. We can't count on | ||
| 113 | * the fact that buffered writes lock out direct I/O | ||
| 114 | * writes - the direct I/O write could have extended | ||
| 115 | * the size nontransactionally, then finished before | ||
| 116 | * we started. xfs_write_file will think that the file | ||
| 117 | * didn't grow but the update isn't safe unless the | ||
| 118 | * size change is logged. | ||
| 119 | * | ||
| 120 | * Force the log if we've committed a transaction | ||
| 121 | * against the inode or if someone else has and | ||
| 122 | * the commit record hasn't gone to disk (e.g. | ||
| 123 | * the inode is pinned). This guarantees that | ||
| 124 | * all changes affecting the inode are permanent | ||
| 125 | * when we return. | ||
| 126 | */ | ||
| 127 | if (iip && iip->ili_last_lsn) { | ||
| 128 | error = _xfs_log_force(mp, iip->ili_last_lsn, | ||
| 129 | XFS_LOG_FORCE | XFS_LOG_SYNC, NULL); | ||
| 130 | } else if (xfs_ipincount(ip) > 0) { | ||
| 131 | error = _xfs_log_force(mp, (xfs_lsn_t)0, | ||
| 132 | XFS_LOG_FORCE | XFS_LOG_SYNC, NULL); | ||
| 133 | } | ||
| 134 | |||
| 135 | } else { | ||
| 136 | xfs_trans_t *tp; | ||
| 137 | |||
| 138 | /* | ||
| 139 | * O_SYNC or O_DSYNC _with_ a size update are handled | ||
| 140 | * the same way. | ||
| 141 | * | ||
| 142 | * If the write was synchronous then we need to make | ||
| 143 | * sure that the inode modification time is permanent. | ||
| 144 | * We'll have updated the timestamp above, so here | ||
| 145 | * we use a synchronous transaction to log the inode. | ||
| 146 | * It's not fast, but it's necessary. | ||
| 147 | * | ||
| 148 | * If this a dsync write and the size got changed | ||
| 149 | * non-transactionally, then we need to ensure that | ||
| 150 | * the size change gets logged in a synchronous | ||
| 151 | * transaction. | ||
| 152 | */ | ||
| 153 | tp = xfs_trans_alloc(mp, XFS_TRANS_WRITE_SYNC); | ||
| 154 | if ((error = xfs_trans_reserve(tp, 0, | ||
| 155 | XFS_SWRITE_LOG_RES(mp), | ||
| 156 | 0, 0, 0))) { | ||
| 157 | /* Transaction reserve failed */ | ||
| 158 | xfs_trans_cancel(tp, 0); | ||
| 159 | } else { | ||
| 160 | /* Transaction reserve successful */ | ||
| 161 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
| 162 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | ||
| 163 | xfs_trans_ihold(tp, ip); | ||
| 164 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
| 165 | xfs_trans_set_sync(tp); | ||
| 166 | error = xfs_trans_commit(tp, 0); | ||
| 167 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | return error; | ||
| 172 | } | ||
| 173 | |||
| 174 | /* | ||
| 175 | * Force a shutdown of the filesystem instantly while keeping | 91 | * Force a shutdown of the filesystem instantly while keeping |
| 176 | * the filesystem consistent. We don't do an unmount here; just shutdown | 92 | * the filesystem consistent. We don't do an unmount here; just shutdown |
| 177 | * the shop, make sure that absolutely nothing persistent happens to | 93 | * the shop, make sure that absolutely nothing persistent happens to |
diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h index f76c003ec55..f5e4874c37d 100644 --- a/fs/xfs/xfs_rw.h +++ b/fs/xfs/xfs_rw.h | |||
| @@ -68,7 +68,6 @@ xfs_get_extsz_hint( | |||
| 68 | * Prototypes for functions in xfs_rw.c. | 68 | * Prototypes for functions in xfs_rw.c. |
| 69 | */ | 69 | */ |
| 70 | extern int xfs_write_clear_setuid(struct xfs_inode *ip); | 70 | extern int xfs_write_clear_setuid(struct xfs_inode *ip); |
| 71 | extern int xfs_write_sync_logforce(struct xfs_mount *mp, struct xfs_inode *ip); | ||
| 72 | extern int xfs_bwrite(struct xfs_mount *mp, struct xfs_buf *bp); | 71 | extern int xfs_bwrite(struct xfs_mount *mp, struct xfs_buf *bp); |
| 73 | extern int xfs_bioerror(struct xfs_buf *bp); | 72 | extern int xfs_bioerror(struct xfs_buf *bp); |
| 74 | extern int xfs_bioerror_relse(struct xfs_buf *bp); | 73 | extern int xfs_bioerror_relse(struct xfs_buf *bp); |
| @@ -78,10 +77,4 @@ extern int xfs_read_buf(struct xfs_mount *mp, xfs_buftarg_t *btp, | |||
| 78 | extern void xfs_ioerror_alert(char *func, struct xfs_mount *mp, | 77 | extern void xfs_ioerror_alert(char *func, struct xfs_mount *mp, |
| 79 | xfs_buf_t *bp, xfs_daddr_t blkno); | 78 | xfs_buf_t *bp, xfs_daddr_t blkno); |
| 80 | 79 | ||
| 81 | /* | ||
| 82 | * Prototypes for functions in xfs_vnodeops.c. | ||
| 83 | */ | ||
| 84 | extern int xfs_free_eofblocks(struct xfs_mount *mp, struct xfs_inode *ip, | ||
| 85 | int flags); | ||
| 86 | |||
| 87 | #endif /* __XFS_RW_H__ */ | 80 | #endif /* __XFS_RW_H__ */ |
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 775249a54f6..ed47fc77759 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h | |||
| @@ -68,7 +68,7 @@ typedef struct xfs_trans_header { | |||
| 68 | #define XFS_TRANS_GROWFS 14 | 68 | #define XFS_TRANS_GROWFS 14 |
| 69 | #define XFS_TRANS_STRAT_WRITE 15 | 69 | #define XFS_TRANS_STRAT_WRITE 15 |
| 70 | #define XFS_TRANS_DIOSTRAT 16 | 70 | #define XFS_TRANS_DIOSTRAT 16 |
| 71 | #define XFS_TRANS_WRITE_SYNC 17 | 71 | /* 17 was XFS_TRANS_WRITE_SYNC */ |
| 72 | #define XFS_TRANS_WRITEID 18 | 72 | #define XFS_TRANS_WRITEID 18 |
| 73 | #define XFS_TRANS_ADDAFORK 19 | 73 | #define XFS_TRANS_ADDAFORK 19 |
| 74 | #define XFS_TRANS_ATTRINVAL 20 | 74 | #define XFS_TRANS_ATTRINVAL 20 |
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index 8ee2f8c8b0a..218829e6a15 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c | |||
| @@ -307,7 +307,7 @@ xfs_trans_read_buf( | |||
| 307 | return (flags & XFS_BUF_TRYLOCK) ? | 307 | return (flags & XFS_BUF_TRYLOCK) ? |
| 308 | EAGAIN : XFS_ERROR(ENOMEM); | 308 | EAGAIN : XFS_ERROR(ENOMEM); |
| 309 | 309 | ||
| 310 | if ((bp != NULL) && (XFS_BUF_GETERROR(bp) != 0)) { | 310 | if (XFS_BUF_GETERROR(bp) != 0) { |
| 311 | xfs_ioerror_alert("xfs_trans_read_buf", mp, | 311 | xfs_ioerror_alert("xfs_trans_read_buf", mp, |
| 312 | bp, blkno); | 312 | bp, blkno); |
| 313 | error = XFS_BUF_GETERROR(bp); | 313 | error = XFS_BUF_GETERROR(bp); |
| @@ -315,7 +315,7 @@ xfs_trans_read_buf( | |||
| 315 | return error; | 315 | return error; |
| 316 | } | 316 | } |
| 317 | #ifdef DEBUG | 317 | #ifdef DEBUG |
| 318 | if (xfs_do_error && (bp != NULL)) { | 318 | if (xfs_do_error) { |
| 319 | if (xfs_error_target == target) { | 319 | if (xfs_error_target == target) { |
| 320 | if (((xfs_req_num++) % xfs_error_mod) == 0) { | 320 | if (((xfs_req_num++) % xfs_error_mod) == 0) { |
| 321 | xfs_buf_relse(bp); | 321 | xfs_buf_relse(bp); |
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c index 23d276af2e0..785ff101da0 100644 --- a/fs/xfs/xfs_trans_inode.c +++ b/fs/xfs/xfs_trans_inode.c | |||
| @@ -49,30 +49,7 @@ xfs_trans_inode_broot_debug( | |||
| 49 | 49 | ||
| 50 | 50 | ||
| 51 | /* | 51 | /* |
| 52 | * Get and lock the inode for the caller if it is not already | 52 | * Get an inode and join it to the transaction. |
| 53 | * locked within the given transaction. If it is already locked | ||
| 54 | * within the transaction, just increment its lock recursion count | ||
| 55 | * and return a pointer to it. | ||
| 56 | * | ||
| 57 | * For an inode to be locked in a transaction, the inode lock, as | ||
| 58 | * opposed to the io lock, must be taken exclusively. This ensures | ||
| 59 | * that the inode can be involved in only 1 transaction at a time. | ||
| 60 | * Lock recursion is handled on the io lock, but only for lock modes | ||
| 61 | * of equal or lesser strength. That is, you can recur on the io lock | ||
| 62 | * held EXCL with a SHARED request but not vice versa. Also, if | ||
| 63 | * the inode is already a part of the transaction then you cannot | ||
| 64 | * go from not holding the io lock to having it EXCL or SHARED. | ||
| 65 | * | ||
| 66 | * Use the inode cache routine xfs_inode_incore() to find the inode | ||
| 67 | * if it is already owned by this transaction. | ||
| 68 | * | ||
| 69 | * If we don't already own the inode, use xfs_iget() to get it. | ||
| 70 | * Since the inode log item structure is embedded in the incore | ||
| 71 | * inode structure and is initialized when the inode is brought | ||
| 72 | * into memory, there is nothing to do with it here. | ||
| 73 | * | ||
| 74 | * If the given transaction pointer is NULL, just call xfs_iget(). | ||
| 75 | * This simplifies code which must handle both cases. | ||
| 76 | */ | 53 | */ |
| 77 | int | 54 | int |
| 78 | xfs_trans_iget( | 55 | xfs_trans_iget( |
| @@ -84,62 +61,11 @@ xfs_trans_iget( | |||
| 84 | xfs_inode_t **ipp) | 61 | xfs_inode_t **ipp) |
| 85 | { | 62 | { |
| 86 | int error; | 63 | int error; |
| 87 | xfs_inode_t *ip; | ||
| 88 | |||
| 89 | /* | ||
| 90 | * If the transaction pointer is NULL, just call the normal | ||
| 91 | * xfs_iget(). | ||
| 92 | */ | ||
| 93 | if (tp == NULL) | ||
| 94 | return xfs_iget(mp, NULL, ino, flags, lock_flags, ipp, 0); | ||
| 95 | |||
| 96 | /* | ||
| 97 | * If we find the inode in core with this transaction | ||
| 98 | * pointer in its i_transp field, then we know we already | ||
| 99 | * have it locked. In this case we just increment the lock | ||
| 100 | * recursion count and return the inode to the caller. | ||
| 101 | * Assert that the inode is already locked in the mode requested | ||
| 102 | * by the caller. We cannot do lock promotions yet, so | ||
| 103 | * die if someone gets this wrong. | ||
| 104 | */ | ||
| 105 | if ((ip = xfs_inode_incore(tp->t_mountp, ino, tp)) != NULL) { | ||
| 106 | /* | ||
| 107 | * Make sure that the inode lock is held EXCL and | ||
| 108 | * that the io lock is never upgraded when the inode | ||
| 109 | * is already a part of the transaction. | ||
| 110 | */ | ||
| 111 | ASSERT(ip->i_itemp != NULL); | ||
| 112 | ASSERT(lock_flags & XFS_ILOCK_EXCL); | ||
| 113 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); | ||
| 114 | ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) || | ||
| 115 | xfs_isilocked(ip, XFS_IOLOCK_EXCL)); | ||
| 116 | ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) || | ||
| 117 | (ip->i_itemp->ili_flags & XFS_ILI_IOLOCKED_EXCL)); | ||
| 118 | ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) || | ||
| 119 | xfs_isilocked(ip, XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)); | ||
| 120 | ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) || | ||
| 121 | (ip->i_itemp->ili_flags & XFS_ILI_IOLOCKED_ANY)); | ||
| 122 | |||
| 123 | if (lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) { | ||
| 124 | ip->i_itemp->ili_iolock_recur++; | ||
| 125 | } | ||
| 126 | if (lock_flags & XFS_ILOCK_EXCL) { | ||
| 127 | ip->i_itemp->ili_ilock_recur++; | ||
| 128 | } | ||
| 129 | *ipp = ip; | ||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | ASSERT(lock_flags & XFS_ILOCK_EXCL); | ||
| 134 | error = xfs_iget(tp->t_mountp, tp, ino, flags, lock_flags, &ip, 0); | ||
| 135 | if (error) { | ||
| 136 | return error; | ||
| 137 | } | ||
| 138 | ASSERT(ip != NULL); | ||
| 139 | 64 | ||
| 140 | xfs_trans_ijoin(tp, ip, lock_flags); | 65 | error = xfs_iget(mp, tp, ino, flags, lock_flags, ipp, 0); |
| 141 | *ipp = ip; | 66 | if (!error && tp) |
| 142 | return 0; | 67 | xfs_trans_ijoin(tp, *ipp, lock_flags); |
| 68 | return error; | ||
| 143 | } | 69 | } |
| 144 | 70 | ||
| 145 | /* | 71 | /* |
| @@ -163,8 +89,6 @@ xfs_trans_ijoin( | |||
| 163 | xfs_inode_item_init(ip, ip->i_mount); | 89 | xfs_inode_item_init(ip, ip->i_mount); |
| 164 | iip = ip->i_itemp; | 90 | iip = ip->i_itemp; |
| 165 | ASSERT(iip->ili_flags == 0); | 91 | ASSERT(iip->ili_flags == 0); |
| 166 | ASSERT(iip->ili_ilock_recur == 0); | ||
| 167 | ASSERT(iip->ili_iolock_recur == 0); | ||
| 168 | 92 | ||
| 169 | /* | 93 | /* |
| 170 | * Get a log_item_desc to point at the new item. | 94 | * Get a log_item_desc to point at the new item. |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 492d75bae2b..a434f287962 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
| @@ -611,7 +611,7 @@ xfs_fsync( | |||
| 611 | xfs_inode_t *ip) | 611 | xfs_inode_t *ip) |
| 612 | { | 612 | { |
| 613 | xfs_trans_t *tp; | 613 | xfs_trans_t *tp; |
| 614 | int error; | 614 | int error = 0; |
| 615 | int log_flushed = 0, changed = 1; | 615 | int log_flushed = 0, changed = 1; |
| 616 | 616 | ||
| 617 | xfs_itrace_entry(ip); | 617 | xfs_itrace_entry(ip); |
| @@ -619,14 +619,9 @@ xfs_fsync( | |||
| 619 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | 619 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) |
| 620 | return XFS_ERROR(EIO); | 620 | return XFS_ERROR(EIO); |
| 621 | 621 | ||
| 622 | /* capture size updates in I/O completion before writing the inode. */ | ||
| 623 | error = xfs_wait_on_pages(ip, 0, -1); | ||
| 624 | if (error) | ||
| 625 | return XFS_ERROR(error); | ||
| 626 | |||
| 627 | /* | 622 | /* |
| 628 | * We always need to make sure that the required inode state is safe on | 623 | * We always need to make sure that the required inode state is safe on |
| 629 | * disk. The vnode might be clean but we still might need to force the | 624 | * disk. The inode might be clean but we still might need to force the |
| 630 | * log because of committed transactions that haven't hit the disk yet. | 625 | * log because of committed transactions that haven't hit the disk yet. |
| 631 | * Likewise, there could be unflushed non-transactional changes to the | 626 | * Likewise, there could be unflushed non-transactional changes to the |
| 632 | * inode core that have to go to disk and this requires us to issue | 627 | * inode core that have to go to disk and this requires us to issue |
| @@ -638,7 +633,7 @@ xfs_fsync( | |||
| 638 | */ | 633 | */ |
| 639 | xfs_ilock(ip, XFS_ILOCK_SHARED); | 634 | xfs_ilock(ip, XFS_ILOCK_SHARED); |
| 640 | 635 | ||
| 641 | if (!(ip->i_update_size || ip->i_update_core)) { | 636 | if (!ip->i_update_core) { |
| 642 | /* | 637 | /* |
| 643 | * Timestamps/size haven't changed since last inode flush or | 638 | * Timestamps/size haven't changed since last inode flush or |
| 644 | * inode transaction commit. That means either nothing got | 639 | * inode transaction commit. That means either nothing got |
| @@ -718,7 +713,7 @@ xfs_fsync( | |||
| 718 | * when the link count isn't zero and by xfs_dm_punch_hole() when | 713 | * when the link count isn't zero and by xfs_dm_punch_hole() when |
| 719 | * punching a hole to EOF. | 714 | * punching a hole to EOF. |
| 720 | */ | 715 | */ |
| 721 | int | 716 | STATIC int |
| 722 | xfs_free_eofblocks( | 717 | xfs_free_eofblocks( |
| 723 | xfs_mount_t *mp, | 718 | xfs_mount_t *mp, |
| 724 | xfs_inode_t *ip, | 719 | xfs_inode_t *ip, |
| @@ -1476,8 +1471,8 @@ xfs_create( | |||
| 1476 | if (error == ENOSPC) { | 1471 | if (error == ENOSPC) { |
| 1477 | /* flush outstanding delalloc blocks and retry */ | 1472 | /* flush outstanding delalloc blocks and retry */ |
| 1478 | xfs_flush_inodes(dp); | 1473 | xfs_flush_inodes(dp); |
| 1479 | error = xfs_trans_reserve(tp, resblks, XFS_CREATE_LOG_RES(mp), 0, | 1474 | error = xfs_trans_reserve(tp, resblks, log_res, 0, |
| 1480 | XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); | 1475 | XFS_TRANS_PERM_LOG_RES, log_count); |
| 1481 | } | 1476 | } |
| 1482 | if (error == ENOSPC) { | 1477 | if (error == ENOSPC) { |
| 1483 | /* No space at all so try a "no-allocation" reservation */ | 1478 | /* No space at all so try a "no-allocation" reservation */ |
