diff options
Diffstat (limited to 'fs')
35 files changed, 435 insertions, 191 deletions
diff --git a/fs/affs/Changes b/fs/affs/Changes index a29409c1ffe0..b41c2c9792ff 100644 --- a/fs/affs/Changes +++ b/fs/affs/Changes | |||
| @@ -91,7 +91,7 @@ more 2.4 fixes: [Roman Zippel] | |||
| 91 | Version 3.11 | 91 | Version 3.11 |
| 92 | ------------ | 92 | ------------ |
| 93 | 93 | ||
| 94 | - Converted to use 2.3.x page cache [Dave Jones <dave@powertweak.com>] | 94 | - Converted to use 2.3.x page cache [Dave Jones] |
| 95 | - Corruption in truncate() bugfix [Ken Tyler <kent@werple.net.au>] | 95 | - Corruption in truncate() bugfix [Ken Tyler <kent@werple.net.au>] |
| 96 | 96 | ||
| 97 | Version 3.10 | 97 | Version 3.10 |
| @@ -367,8 +367,10 @@ static int aio_setup_ring(struct kioctx *ctx) | |||
| 367 | if (nr_pages > AIO_RING_PAGES) { | 367 | if (nr_pages > AIO_RING_PAGES) { |
| 368 | ctx->ring_pages = kcalloc(nr_pages, sizeof(struct page *), | 368 | ctx->ring_pages = kcalloc(nr_pages, sizeof(struct page *), |
| 369 | GFP_KERNEL); | 369 | GFP_KERNEL); |
| 370 | if (!ctx->ring_pages) | 370 | if (!ctx->ring_pages) { |
| 371 | put_aio_ring_file(ctx); | ||
| 371 | return -ENOMEM; | 372 | return -ENOMEM; |
| 373 | } | ||
| 372 | } | 374 | } |
| 373 | 375 | ||
| 374 | ctx->mmap_size = nr_pages * PAGE_SIZE; | 376 | ctx->mmap_size = nr_pages * PAGE_SIZE; |
| @@ -645,7 +647,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) | |||
| 645 | aio_nr + nr_events < aio_nr) { | 647 | aio_nr + nr_events < aio_nr) { |
| 646 | spin_unlock(&aio_nr_lock); | 648 | spin_unlock(&aio_nr_lock); |
| 647 | err = -EAGAIN; | 649 | err = -EAGAIN; |
| 648 | goto err; | 650 | goto err_ctx; |
| 649 | } | 651 | } |
| 650 | aio_nr += ctx->max_reqs; | 652 | aio_nr += ctx->max_reqs; |
| 651 | spin_unlock(&aio_nr_lock); | 653 | spin_unlock(&aio_nr_lock); |
| @@ -662,6 +664,8 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) | |||
| 662 | 664 | ||
| 663 | err_cleanup: | 665 | err_cleanup: |
| 664 | aio_nr_sub(ctx->max_reqs); | 666 | aio_nr_sub(ctx->max_reqs); |
| 667 | err_ctx: | ||
| 668 | aio_free_ring(ctx); | ||
| 665 | err: | 669 | err: |
| 666 | free_percpu(ctx->cpu); | 670 | free_percpu(ctx->cpu); |
| 667 | free_percpu(ctx->reqs.pcpu_count); | 671 | free_percpu(ctx->reqs.pcpu_count); |
diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index b50764bef141..131d82800b3a 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c | |||
| @@ -333,7 +333,6 @@ static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx); | |||
| 333 | static int btrfsic_read_block(struct btrfsic_state *state, | 333 | static int btrfsic_read_block(struct btrfsic_state *state, |
| 334 | struct btrfsic_block_data_ctx *block_ctx); | 334 | struct btrfsic_block_data_ctx *block_ctx); |
| 335 | static void btrfsic_dump_database(struct btrfsic_state *state); | 335 | static void btrfsic_dump_database(struct btrfsic_state *state); |
| 336 | static void btrfsic_complete_bio_end_io(struct bio *bio, int err); | ||
| 337 | static int btrfsic_test_for_metadata(struct btrfsic_state *state, | 336 | static int btrfsic_test_for_metadata(struct btrfsic_state *state, |
| 338 | char **datav, unsigned int num_pages); | 337 | char **datav, unsigned int num_pages); |
| 339 | static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, | 338 | static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, |
| @@ -1687,7 +1686,6 @@ static int btrfsic_read_block(struct btrfsic_state *state, | |||
| 1687 | for (i = 0; i < num_pages;) { | 1686 | for (i = 0; i < num_pages;) { |
| 1688 | struct bio *bio; | 1687 | struct bio *bio; |
| 1689 | unsigned int j; | 1688 | unsigned int j; |
| 1690 | DECLARE_COMPLETION_ONSTACK(complete); | ||
| 1691 | 1689 | ||
| 1692 | bio = btrfs_io_bio_alloc(GFP_NOFS, num_pages - i); | 1690 | bio = btrfs_io_bio_alloc(GFP_NOFS, num_pages - i); |
| 1693 | if (!bio) { | 1691 | if (!bio) { |
| @@ -1698,8 +1696,6 @@ static int btrfsic_read_block(struct btrfsic_state *state, | |||
| 1698 | } | 1696 | } |
| 1699 | bio->bi_bdev = block_ctx->dev->bdev; | 1697 | bio->bi_bdev = block_ctx->dev->bdev; |
| 1700 | bio->bi_sector = dev_bytenr >> 9; | 1698 | bio->bi_sector = dev_bytenr >> 9; |
| 1701 | bio->bi_end_io = btrfsic_complete_bio_end_io; | ||
| 1702 | bio->bi_private = &complete; | ||
| 1703 | 1699 | ||
| 1704 | for (j = i; j < num_pages; j++) { | 1700 | for (j = i; j < num_pages; j++) { |
| 1705 | ret = bio_add_page(bio, block_ctx->pagev[j], | 1701 | ret = bio_add_page(bio, block_ctx->pagev[j], |
| @@ -1712,12 +1708,7 @@ static int btrfsic_read_block(struct btrfsic_state *state, | |||
| 1712 | "btrfsic: error, failed to add a single page!\n"); | 1708 | "btrfsic: error, failed to add a single page!\n"); |
| 1713 | return -1; | 1709 | return -1; |
| 1714 | } | 1710 | } |
| 1715 | submit_bio(READ, bio); | 1711 | if (submit_bio_wait(READ, bio)) { |
| 1716 | |||
| 1717 | /* this will also unplug the queue */ | ||
| 1718 | wait_for_completion(&complete); | ||
| 1719 | |||
| 1720 | if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { | ||
| 1721 | printk(KERN_INFO | 1712 | printk(KERN_INFO |
| 1722 | "btrfsic: read error at logical %llu dev %s!\n", | 1713 | "btrfsic: read error at logical %llu dev %s!\n", |
| 1723 | block_ctx->start, block_ctx->dev->name); | 1714 | block_ctx->start, block_ctx->dev->name); |
| @@ -1740,11 +1731,6 @@ static int btrfsic_read_block(struct btrfsic_state *state, | |||
| 1740 | return block_ctx->len; | 1731 | return block_ctx->len; |
| 1741 | } | 1732 | } |
| 1742 | 1733 | ||
| 1743 | static void btrfsic_complete_bio_end_io(struct bio *bio, int err) | ||
| 1744 | { | ||
| 1745 | complete((struct completion *)bio->bi_private); | ||
| 1746 | } | ||
| 1747 | |||
| 1748 | static void btrfsic_dump_database(struct btrfsic_state *state) | 1734 | static void btrfsic_dump_database(struct btrfsic_state *state) |
| 1749 | { | 1735 | { |
| 1750 | struct list_head *elem_all; | 1736 | struct list_head *elem_all; |
| @@ -3008,14 +2994,12 @@ int btrfsic_submit_bh(int rw, struct buffer_head *bh) | |||
| 3008 | return submit_bh(rw, bh); | 2994 | return submit_bh(rw, bh); |
| 3009 | } | 2995 | } |
| 3010 | 2996 | ||
| 3011 | void btrfsic_submit_bio(int rw, struct bio *bio) | 2997 | static void __btrfsic_submit_bio(int rw, struct bio *bio) |
| 3012 | { | 2998 | { |
| 3013 | struct btrfsic_dev_state *dev_state; | 2999 | struct btrfsic_dev_state *dev_state; |
| 3014 | 3000 | ||
| 3015 | if (!btrfsic_is_initialized) { | 3001 | if (!btrfsic_is_initialized) |
| 3016 | submit_bio(rw, bio); | ||
| 3017 | return; | 3002 | return; |
| 3018 | } | ||
| 3019 | 3003 | ||
| 3020 | mutex_lock(&btrfsic_mutex); | 3004 | mutex_lock(&btrfsic_mutex); |
| 3021 | /* since btrfsic_submit_bio() is also called before | 3005 | /* since btrfsic_submit_bio() is also called before |
| @@ -3106,10 +3090,20 @@ void btrfsic_submit_bio(int rw, struct bio *bio) | |||
| 3106 | } | 3090 | } |
| 3107 | leave: | 3091 | leave: |
| 3108 | mutex_unlock(&btrfsic_mutex); | 3092 | mutex_unlock(&btrfsic_mutex); |
| 3093 | } | ||
| 3109 | 3094 | ||
| 3095 | void btrfsic_submit_bio(int rw, struct bio *bio) | ||
| 3096 | { | ||
| 3097 | __btrfsic_submit_bio(rw, bio); | ||
| 3110 | submit_bio(rw, bio); | 3098 | submit_bio(rw, bio); |
| 3111 | } | 3099 | } |
| 3112 | 3100 | ||
| 3101 | int btrfsic_submit_bio_wait(int rw, struct bio *bio) | ||
| 3102 | { | ||
| 3103 | __btrfsic_submit_bio(rw, bio); | ||
| 3104 | return submit_bio_wait(rw, bio); | ||
| 3105 | } | ||
| 3106 | |||
| 3113 | int btrfsic_mount(struct btrfs_root *root, | 3107 | int btrfsic_mount(struct btrfs_root *root, |
| 3114 | struct btrfs_fs_devices *fs_devices, | 3108 | struct btrfs_fs_devices *fs_devices, |
| 3115 | int including_extent_data, u32 print_mask) | 3109 | int including_extent_data, u32 print_mask) |
diff --git a/fs/btrfs/check-integrity.h b/fs/btrfs/check-integrity.h index 8b59175cc502..13b8566c97ab 100644 --- a/fs/btrfs/check-integrity.h +++ b/fs/btrfs/check-integrity.h | |||
| @@ -22,9 +22,11 @@ | |||
| 22 | #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY | 22 | #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY |
| 23 | int btrfsic_submit_bh(int rw, struct buffer_head *bh); | 23 | int btrfsic_submit_bh(int rw, struct buffer_head *bh); |
| 24 | void btrfsic_submit_bio(int rw, struct bio *bio); | 24 | void btrfsic_submit_bio(int rw, struct bio *bio); |
| 25 | int btrfsic_submit_bio_wait(int rw, struct bio *bio); | ||
| 25 | #else | 26 | #else |
| 26 | #define btrfsic_submit_bh submit_bh | 27 | #define btrfsic_submit_bh submit_bh |
| 27 | #define btrfsic_submit_bio submit_bio | 28 | #define btrfsic_submit_bio submit_bio |
| 29 | #define btrfsic_submit_bio_wait submit_bio_wait | ||
| 28 | #endif | 30 | #endif |
| 29 | 31 | ||
| 30 | int btrfsic_mount(struct btrfs_root *root, | 32 | int btrfsic_mount(struct btrfs_root *root, |
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 8e457fca0a0b..ff43802a7c88 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
| @@ -1952,11 +1952,6 @@ static int free_io_failure(struct inode *inode, struct io_failure_record *rec, | |||
| 1952 | return err; | 1952 | return err; |
| 1953 | } | 1953 | } |
| 1954 | 1954 | ||
| 1955 | static void repair_io_failure_callback(struct bio *bio, int err) | ||
| 1956 | { | ||
| 1957 | complete(bio->bi_private); | ||
| 1958 | } | ||
| 1959 | |||
| 1960 | /* | 1955 | /* |
| 1961 | * this bypasses the standard btrfs submit functions deliberately, as | 1956 | * this bypasses the standard btrfs submit functions deliberately, as |
| 1962 | * the standard behavior is to write all copies in a raid setup. here we only | 1957 | * the standard behavior is to write all copies in a raid setup. here we only |
| @@ -1973,7 +1968,6 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start, | |||
| 1973 | { | 1968 | { |
| 1974 | struct bio *bio; | 1969 | struct bio *bio; |
| 1975 | struct btrfs_device *dev; | 1970 | struct btrfs_device *dev; |
| 1976 | DECLARE_COMPLETION_ONSTACK(compl); | ||
| 1977 | u64 map_length = 0; | 1971 | u64 map_length = 0; |
| 1978 | u64 sector; | 1972 | u64 sector; |
| 1979 | struct btrfs_bio *bbio = NULL; | 1973 | struct btrfs_bio *bbio = NULL; |
| @@ -1990,8 +1984,6 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start, | |||
| 1990 | bio = btrfs_io_bio_alloc(GFP_NOFS, 1); | 1984 | bio = btrfs_io_bio_alloc(GFP_NOFS, 1); |
| 1991 | if (!bio) | 1985 | if (!bio) |
| 1992 | return -EIO; | 1986 | return -EIO; |
| 1993 | bio->bi_private = &compl; | ||
| 1994 | bio->bi_end_io = repair_io_failure_callback; | ||
| 1995 | bio->bi_size = 0; | 1987 | bio->bi_size = 0; |
| 1996 | map_length = length; | 1988 | map_length = length; |
| 1997 | 1989 | ||
| @@ -2012,10 +2004,8 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start, | |||
| 2012 | } | 2004 | } |
| 2013 | bio->bi_bdev = dev->bdev; | 2005 | bio->bi_bdev = dev->bdev; |
| 2014 | bio_add_page(bio, page, length, start - page_offset(page)); | 2006 | bio_add_page(bio, page, length, start - page_offset(page)); |
| 2015 | btrfsic_submit_bio(WRITE_SYNC, bio); | ||
| 2016 | wait_for_completion(&compl); | ||
| 2017 | 2007 | ||
| 2018 | if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { | 2008 | if (btrfsic_submit_bio_wait(WRITE_SYNC, bio)) { |
| 2019 | /* try to remap that extent elsewhere? */ | 2009 | /* try to remap that extent elsewhere? */ |
| 2020 | bio_put(bio); | 2010 | bio_put(bio); |
| 2021 | btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS); | 2011 | btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS); |
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 561e2f16ba3e..1fd3f33c330a 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c | |||
| @@ -208,7 +208,6 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info, | |||
| 208 | int is_metadata, int have_csum, | 208 | int is_metadata, int have_csum, |
| 209 | const u8 *csum, u64 generation, | 209 | const u8 *csum, u64 generation, |
| 210 | u16 csum_size); | 210 | u16 csum_size); |
| 211 | static void scrub_complete_bio_end_io(struct bio *bio, int err); | ||
| 212 | static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad, | 211 | static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad, |
| 213 | struct scrub_block *sblock_good, | 212 | struct scrub_block *sblock_good, |
| 214 | int force_write); | 213 | int force_write); |
| @@ -1294,7 +1293,6 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info, | |||
| 1294 | for (page_num = 0; page_num < sblock->page_count; page_num++) { | 1293 | for (page_num = 0; page_num < sblock->page_count; page_num++) { |
| 1295 | struct bio *bio; | 1294 | struct bio *bio; |
| 1296 | struct scrub_page *page = sblock->pagev[page_num]; | 1295 | struct scrub_page *page = sblock->pagev[page_num]; |
| 1297 | DECLARE_COMPLETION_ONSTACK(complete); | ||
| 1298 | 1296 | ||
| 1299 | if (page->dev->bdev == NULL) { | 1297 | if (page->dev->bdev == NULL) { |
| 1300 | page->io_error = 1; | 1298 | page->io_error = 1; |
| @@ -1311,18 +1309,11 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info, | |||
| 1311 | } | 1309 | } |
| 1312 | bio->bi_bdev = page->dev->bdev; | 1310 | bio->bi_bdev = page->dev->bdev; |
| 1313 | bio->bi_sector = page->physical >> 9; | 1311 | bio->bi_sector = page->physical >> 9; |
| 1314 | bio->bi_end_io = scrub_complete_bio_end_io; | ||
| 1315 | bio->bi_private = &complete; | ||
| 1316 | 1312 | ||
| 1317 | bio_add_page(bio, page->page, PAGE_SIZE, 0); | 1313 | bio_add_page(bio, page->page, PAGE_SIZE, 0); |
| 1318 | btrfsic_submit_bio(READ, bio); | 1314 | if (btrfsic_submit_bio_wait(READ, bio)) |
| 1319 | |||
| 1320 | /* this will also unplug the queue */ | ||
| 1321 | wait_for_completion(&complete); | ||
| 1322 | |||
| 1323 | page->io_error = !test_bit(BIO_UPTODATE, &bio->bi_flags); | ||
| 1324 | if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) | ||
| 1325 | sblock->no_io_error_seen = 0; | 1315 | sblock->no_io_error_seen = 0; |
| 1316 | |||
| 1326 | bio_put(bio); | 1317 | bio_put(bio); |
| 1327 | } | 1318 | } |
| 1328 | 1319 | ||
| @@ -1391,11 +1382,6 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info, | |||
| 1391 | sblock->checksum_error = 1; | 1382 | sblock->checksum_error = 1; |
| 1392 | } | 1383 | } |
| 1393 | 1384 | ||
| 1394 | static void scrub_complete_bio_end_io(struct bio *bio, int err) | ||
| 1395 | { | ||
| 1396 | complete((struct completion *)bio->bi_private); | ||
| 1397 | } | ||
| 1398 | |||
| 1399 | static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad, | 1385 | static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad, |
| 1400 | struct scrub_block *sblock_good, | 1386 | struct scrub_block *sblock_good, |
| 1401 | int force_write) | 1387 | int force_write) |
| @@ -1430,7 +1416,6 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, | |||
| 1430 | sblock_bad->checksum_error || page_bad->io_error) { | 1416 | sblock_bad->checksum_error || page_bad->io_error) { |
| 1431 | struct bio *bio; | 1417 | struct bio *bio; |
| 1432 | int ret; | 1418 | int ret; |
| 1433 | DECLARE_COMPLETION_ONSTACK(complete); | ||
| 1434 | 1419 | ||
| 1435 | if (!page_bad->dev->bdev) { | 1420 | if (!page_bad->dev->bdev) { |
| 1436 | printk_ratelimited(KERN_WARNING | 1421 | printk_ratelimited(KERN_WARNING |
| @@ -1443,19 +1428,14 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, | |||
| 1443 | return -EIO; | 1428 | return -EIO; |
| 1444 | bio->bi_bdev = page_bad->dev->bdev; | 1429 | bio->bi_bdev = page_bad->dev->bdev; |
| 1445 | bio->bi_sector = page_bad->physical >> 9; | 1430 | bio->bi_sector = page_bad->physical >> 9; |
| 1446 | bio->bi_end_io = scrub_complete_bio_end_io; | ||
| 1447 | bio->bi_private = &complete; | ||
| 1448 | 1431 | ||
| 1449 | ret = bio_add_page(bio, page_good->page, PAGE_SIZE, 0); | 1432 | ret = bio_add_page(bio, page_good->page, PAGE_SIZE, 0); |
| 1450 | if (PAGE_SIZE != ret) { | 1433 | if (PAGE_SIZE != ret) { |
| 1451 | bio_put(bio); | 1434 | bio_put(bio); |
| 1452 | return -EIO; | 1435 | return -EIO; |
| 1453 | } | 1436 | } |
| 1454 | btrfsic_submit_bio(WRITE, bio); | ||
| 1455 | 1437 | ||
| 1456 | /* this will also unplug the queue */ | 1438 | if (btrfsic_submit_bio_wait(WRITE, bio)) { |
| 1457 | wait_for_completion(&complete); | ||
| 1458 | if (!bio_flagged(bio, BIO_UPTODATE)) { | ||
| 1459 | btrfs_dev_stat_inc_and_print(page_bad->dev, | 1439 | btrfs_dev_stat_inc_and_print(page_bad->dev, |
| 1460 | BTRFS_DEV_STAT_WRITE_ERRS); | 1440 | BTRFS_DEV_STAT_WRITE_ERRS); |
| 1461 | btrfs_dev_replace_stats_inc( | 1441 | btrfs_dev_replace_stats_inc( |
| @@ -3375,7 +3355,6 @@ static int write_page_nocow(struct scrub_ctx *sctx, | |||
| 3375 | struct bio *bio; | 3355 | struct bio *bio; |
| 3376 | struct btrfs_device *dev; | 3356 | struct btrfs_device *dev; |
| 3377 | int ret; | 3357 | int ret; |
| 3378 | DECLARE_COMPLETION_ONSTACK(compl); | ||
| 3379 | 3358 | ||
| 3380 | dev = sctx->wr_ctx.tgtdev; | 3359 | dev = sctx->wr_ctx.tgtdev; |
| 3381 | if (!dev) | 3360 | if (!dev) |
| @@ -3392,8 +3371,6 @@ static int write_page_nocow(struct scrub_ctx *sctx, | |||
| 3392 | spin_unlock(&sctx->stat_lock); | 3371 | spin_unlock(&sctx->stat_lock); |
| 3393 | return -ENOMEM; | 3372 | return -ENOMEM; |
| 3394 | } | 3373 | } |
| 3395 | bio->bi_private = &compl; | ||
| 3396 | bio->bi_end_io = scrub_complete_bio_end_io; | ||
| 3397 | bio->bi_size = 0; | 3374 | bio->bi_size = 0; |
| 3398 | bio->bi_sector = physical_for_dev_replace >> 9; | 3375 | bio->bi_sector = physical_for_dev_replace >> 9; |
| 3399 | bio->bi_bdev = dev->bdev; | 3376 | bio->bi_bdev = dev->bdev; |
| @@ -3404,10 +3381,8 @@ leave_with_eio: | |||
| 3404 | btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS); | 3381 | btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS); |
| 3405 | return -EIO; | 3382 | return -EIO; |
| 3406 | } | 3383 | } |
| 3407 | btrfsic_submit_bio(WRITE_SYNC, bio); | ||
| 3408 | wait_for_completion(&compl); | ||
| 3409 | 3384 | ||
| 3410 | if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) | 3385 | if (btrfsic_submit_bio_wait(WRITE_SYNC, bio)) |
| 3411 | goto leave_with_eio; | 3386 | goto leave_with_eio; |
| 3412 | 3387 | ||
| 3413 | bio_put(bio); | 3388 | bio_put(bio); |
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 6df8bd481425..1e561c059539 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
| @@ -216,7 +216,7 @@ static int readpage_nounlock(struct file *filp, struct page *page) | |||
| 216 | } | 216 | } |
| 217 | SetPageUptodate(page); | 217 | SetPageUptodate(page); |
| 218 | 218 | ||
| 219 | if (err == 0) | 219 | if (err >= 0) |
| 220 | ceph_readpage_to_fscache(inode, page); | 220 | ceph_readpage_to_fscache(inode, page); |
| 221 | 221 | ||
| 222 | out: | 222 | out: |
diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c index 7db2e6ca4b8f..8c44fdd4e1c3 100644 --- a/fs/ceph/cache.c +++ b/fs/ceph/cache.c | |||
| @@ -324,6 +324,9 @@ void ceph_invalidate_fscache_page(struct inode* inode, struct page *page) | |||
| 324 | { | 324 | { |
| 325 | struct ceph_inode_info *ci = ceph_inode(inode); | 325 | struct ceph_inode_info *ci = ceph_inode(inode); |
| 326 | 326 | ||
| 327 | if (!PageFsCache(page)) | ||
| 328 | return; | ||
| 329 | |||
| 327 | fscache_wait_on_page_write(ci->fscache, page); | 330 | fscache_wait_on_page_write(ci->fscache, page); |
| 328 | fscache_uncache_page(ci->fscache, page); | 331 | fscache_uncache_page(ci->fscache, page); |
| 329 | } | 332 | } |
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 13976c33332e..3c0a4bd74996 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
| @@ -897,7 +897,7 @@ static int __ceph_is_any_caps(struct ceph_inode_info *ci) | |||
| 897 | * caller should hold i_ceph_lock. | 897 | * caller should hold i_ceph_lock. |
| 898 | * caller will not hold session s_mutex if called from destroy_inode. | 898 | * caller will not hold session s_mutex if called from destroy_inode. |
| 899 | */ | 899 | */ |
| 900 | void __ceph_remove_cap(struct ceph_cap *cap) | 900 | void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) |
| 901 | { | 901 | { |
| 902 | struct ceph_mds_session *session = cap->session; | 902 | struct ceph_mds_session *session = cap->session; |
| 903 | struct ceph_inode_info *ci = cap->ci; | 903 | struct ceph_inode_info *ci = cap->ci; |
| @@ -909,6 +909,16 @@ void __ceph_remove_cap(struct ceph_cap *cap) | |||
| 909 | 909 | ||
| 910 | /* remove from session list */ | 910 | /* remove from session list */ |
| 911 | spin_lock(&session->s_cap_lock); | 911 | spin_lock(&session->s_cap_lock); |
| 912 | /* | ||
| 913 | * s_cap_reconnect is protected by s_cap_lock. no one changes | ||
| 914 | * s_cap_gen while session is in the reconnect state. | ||
| 915 | */ | ||
| 916 | if (queue_release && | ||
| 917 | (!session->s_cap_reconnect || | ||
| 918 | cap->cap_gen == session->s_cap_gen)) | ||
| 919 | __queue_cap_release(session, ci->i_vino.ino, cap->cap_id, | ||
| 920 | cap->mseq, cap->issue_seq); | ||
| 921 | |||
| 912 | if (session->s_cap_iterator == cap) { | 922 | if (session->s_cap_iterator == cap) { |
| 913 | /* not yet, we are iterating over this very cap */ | 923 | /* not yet, we are iterating over this very cap */ |
| 914 | dout("__ceph_remove_cap delaying %p removal from session %p\n", | 924 | dout("__ceph_remove_cap delaying %p removal from session %p\n", |
| @@ -1023,7 +1033,6 @@ void __queue_cap_release(struct ceph_mds_session *session, | |||
| 1023 | struct ceph_mds_cap_release *head; | 1033 | struct ceph_mds_cap_release *head; |
| 1024 | struct ceph_mds_cap_item *item; | 1034 | struct ceph_mds_cap_item *item; |
| 1025 | 1035 | ||
| 1026 | spin_lock(&session->s_cap_lock); | ||
| 1027 | BUG_ON(!session->s_num_cap_releases); | 1036 | BUG_ON(!session->s_num_cap_releases); |
| 1028 | msg = list_first_entry(&session->s_cap_releases, | 1037 | msg = list_first_entry(&session->s_cap_releases, |
| 1029 | struct ceph_msg, list_head); | 1038 | struct ceph_msg, list_head); |
| @@ -1052,7 +1061,6 @@ void __queue_cap_release(struct ceph_mds_session *session, | |||
| 1052 | (int)CEPH_CAPS_PER_RELEASE, | 1061 | (int)CEPH_CAPS_PER_RELEASE, |
| 1053 | (int)msg->front.iov_len); | 1062 | (int)msg->front.iov_len); |
| 1054 | } | 1063 | } |
| 1055 | spin_unlock(&session->s_cap_lock); | ||
| 1056 | } | 1064 | } |
| 1057 | 1065 | ||
| 1058 | /* | 1066 | /* |
| @@ -1067,12 +1075,8 @@ void ceph_queue_caps_release(struct inode *inode) | |||
| 1067 | p = rb_first(&ci->i_caps); | 1075 | p = rb_first(&ci->i_caps); |
| 1068 | while (p) { | 1076 | while (p) { |
| 1069 | struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node); | 1077 | struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node); |
| 1070 | struct ceph_mds_session *session = cap->session; | ||
| 1071 | |||
| 1072 | __queue_cap_release(session, ceph_ino(inode), cap->cap_id, | ||
| 1073 | cap->mseq, cap->issue_seq); | ||
| 1074 | p = rb_next(p); | 1078 | p = rb_next(p); |
| 1075 | __ceph_remove_cap(cap); | 1079 | __ceph_remove_cap(cap, true); |
| 1076 | } | 1080 | } |
| 1077 | } | 1081 | } |
| 1078 | 1082 | ||
| @@ -2791,7 +2795,7 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, | |||
| 2791 | } | 2795 | } |
| 2792 | spin_unlock(&mdsc->cap_dirty_lock); | 2796 | spin_unlock(&mdsc->cap_dirty_lock); |
| 2793 | } | 2797 | } |
| 2794 | __ceph_remove_cap(cap); | 2798 | __ceph_remove_cap(cap, false); |
| 2795 | } | 2799 | } |
| 2796 | /* else, we already released it */ | 2800 | /* else, we already released it */ |
| 2797 | 2801 | ||
| @@ -2931,9 +2935,12 @@ void ceph_handle_caps(struct ceph_mds_session *session, | |||
| 2931 | if (!inode) { | 2935 | if (!inode) { |
| 2932 | dout(" i don't have ino %llx\n", vino.ino); | 2936 | dout(" i don't have ino %llx\n", vino.ino); |
| 2933 | 2937 | ||
| 2934 | if (op == CEPH_CAP_OP_IMPORT) | 2938 | if (op == CEPH_CAP_OP_IMPORT) { |
| 2939 | spin_lock(&session->s_cap_lock); | ||
| 2935 | __queue_cap_release(session, vino.ino, cap_id, | 2940 | __queue_cap_release(session, vino.ino, cap_id, |
| 2936 | mseq, seq); | 2941 | mseq, seq); |
| 2942 | spin_unlock(&session->s_cap_lock); | ||
| 2943 | } | ||
| 2937 | goto flush_cap_releases; | 2944 | goto flush_cap_releases; |
| 2938 | } | 2945 | } |
| 2939 | 2946 | ||
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 868b61d56cac..2a0bcaeb189a 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
| @@ -352,8 +352,18 @@ more: | |||
| 352 | } | 352 | } |
| 353 | 353 | ||
| 354 | /* note next offset and last dentry name */ | 354 | /* note next offset and last dentry name */ |
| 355 | rinfo = &req->r_reply_info; | ||
| 356 | if (le32_to_cpu(rinfo->dir_dir->frag) != frag) { | ||
| 357 | frag = le32_to_cpu(rinfo->dir_dir->frag); | ||
| 358 | if (ceph_frag_is_leftmost(frag)) | ||
| 359 | fi->next_offset = 2; | ||
| 360 | else | ||
| 361 | fi->next_offset = 0; | ||
| 362 | off = fi->next_offset; | ||
| 363 | } | ||
| 355 | fi->offset = fi->next_offset; | 364 | fi->offset = fi->next_offset; |
| 356 | fi->last_readdir = req; | 365 | fi->last_readdir = req; |
| 366 | fi->frag = frag; | ||
| 357 | 367 | ||
| 358 | if (req->r_reply_info.dir_end) { | 368 | if (req->r_reply_info.dir_end) { |
| 359 | kfree(fi->last_name); | 369 | kfree(fi->last_name); |
| @@ -363,7 +373,6 @@ more: | |||
| 363 | else | 373 | else |
| 364 | fi->next_offset = 0; | 374 | fi->next_offset = 0; |
| 365 | } else { | 375 | } else { |
| 366 | rinfo = &req->r_reply_info; | ||
| 367 | err = note_last_dentry(fi, | 376 | err = note_last_dentry(fi, |
| 368 | rinfo->dir_dname[rinfo->dir_nr-1], | 377 | rinfo->dir_dname[rinfo->dir_nr-1], |
| 369 | rinfo->dir_dname_len[rinfo->dir_nr-1]); | 378 | rinfo->dir_dname_len[rinfo->dir_nr-1]); |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 8549a48115f7..9a8e396aed89 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
| @@ -577,6 +577,8 @@ static int fill_inode(struct inode *inode, | |||
| 577 | int issued = 0, implemented; | 577 | int issued = 0, implemented; |
| 578 | struct timespec mtime, atime, ctime; | 578 | struct timespec mtime, atime, ctime; |
| 579 | u32 nsplits; | 579 | u32 nsplits; |
| 580 | struct ceph_inode_frag *frag; | ||
| 581 | struct rb_node *rb_node; | ||
| 580 | struct ceph_buffer *xattr_blob = NULL; | 582 | struct ceph_buffer *xattr_blob = NULL; |
| 581 | int err = 0; | 583 | int err = 0; |
| 582 | int queue_trunc = 0; | 584 | int queue_trunc = 0; |
| @@ -751,15 +753,38 @@ no_change: | |||
| 751 | /* FIXME: move me up, if/when version reflects fragtree changes */ | 753 | /* FIXME: move me up, if/when version reflects fragtree changes */ |
| 752 | nsplits = le32_to_cpu(info->fragtree.nsplits); | 754 | nsplits = le32_to_cpu(info->fragtree.nsplits); |
| 753 | mutex_lock(&ci->i_fragtree_mutex); | 755 | mutex_lock(&ci->i_fragtree_mutex); |
| 756 | rb_node = rb_first(&ci->i_fragtree); | ||
| 754 | for (i = 0; i < nsplits; i++) { | 757 | for (i = 0; i < nsplits; i++) { |
| 755 | u32 id = le32_to_cpu(info->fragtree.splits[i].frag); | 758 | u32 id = le32_to_cpu(info->fragtree.splits[i].frag); |
| 756 | struct ceph_inode_frag *frag = __get_or_create_frag(ci, id); | 759 | frag = NULL; |
| 757 | 760 | while (rb_node) { | |
| 758 | if (IS_ERR(frag)) | 761 | frag = rb_entry(rb_node, struct ceph_inode_frag, node); |
| 759 | continue; | 762 | if (ceph_frag_compare(frag->frag, id) >= 0) { |
| 763 | if (frag->frag != id) | ||
| 764 | frag = NULL; | ||
| 765 | else | ||
| 766 | rb_node = rb_next(rb_node); | ||
| 767 | break; | ||
| 768 | } | ||
| 769 | rb_node = rb_next(rb_node); | ||
| 770 | rb_erase(&frag->node, &ci->i_fragtree); | ||
| 771 | kfree(frag); | ||
| 772 | frag = NULL; | ||
| 773 | } | ||
| 774 | if (!frag) { | ||
| 775 | frag = __get_or_create_frag(ci, id); | ||
| 776 | if (IS_ERR(frag)) | ||
| 777 | continue; | ||
| 778 | } | ||
| 760 | frag->split_by = le32_to_cpu(info->fragtree.splits[i].by); | 779 | frag->split_by = le32_to_cpu(info->fragtree.splits[i].by); |
| 761 | dout(" frag %x split by %d\n", frag->frag, frag->split_by); | 780 | dout(" frag %x split by %d\n", frag->frag, frag->split_by); |
| 762 | } | 781 | } |
| 782 | while (rb_node) { | ||
| 783 | frag = rb_entry(rb_node, struct ceph_inode_frag, node); | ||
| 784 | rb_node = rb_next(rb_node); | ||
| 785 | rb_erase(&frag->node, &ci->i_fragtree); | ||
| 786 | kfree(frag); | ||
| 787 | } | ||
| 763 | mutex_unlock(&ci->i_fragtree_mutex); | 788 | mutex_unlock(&ci->i_fragtree_mutex); |
| 764 | 789 | ||
| 765 | /* were we issued a capability? */ | 790 | /* were we issued a capability? */ |
| @@ -1250,8 +1275,20 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, | |||
| 1250 | int err = 0, i; | 1275 | int err = 0, i; |
| 1251 | struct inode *snapdir = NULL; | 1276 | struct inode *snapdir = NULL; |
| 1252 | struct ceph_mds_request_head *rhead = req->r_request->front.iov_base; | 1277 | struct ceph_mds_request_head *rhead = req->r_request->front.iov_base; |
| 1253 | u64 frag = le32_to_cpu(rhead->args.readdir.frag); | ||
| 1254 | struct ceph_dentry_info *di; | 1278 | struct ceph_dentry_info *di; |
| 1279 | u64 r_readdir_offset = req->r_readdir_offset; | ||
| 1280 | u32 frag = le32_to_cpu(rhead->args.readdir.frag); | ||
| 1281 | |||
| 1282 | if (rinfo->dir_dir && | ||
| 1283 | le32_to_cpu(rinfo->dir_dir->frag) != frag) { | ||
| 1284 | dout("readdir_prepopulate got new frag %x -> %x\n", | ||
| 1285 | frag, le32_to_cpu(rinfo->dir_dir->frag)); | ||
| 1286 | frag = le32_to_cpu(rinfo->dir_dir->frag); | ||
| 1287 | if (ceph_frag_is_leftmost(frag)) | ||
| 1288 | r_readdir_offset = 2; | ||
| 1289 | else | ||
| 1290 | r_readdir_offset = 0; | ||
| 1291 | } | ||
| 1255 | 1292 | ||
| 1256 | if (req->r_aborted) | 1293 | if (req->r_aborted) |
| 1257 | return readdir_prepopulate_inodes_only(req, session); | 1294 | return readdir_prepopulate_inodes_only(req, session); |
| @@ -1315,7 +1352,7 @@ retry_lookup: | |||
| 1315 | } | 1352 | } |
| 1316 | 1353 | ||
| 1317 | di = dn->d_fsdata; | 1354 | di = dn->d_fsdata; |
| 1318 | di->offset = ceph_make_fpos(frag, i + req->r_readdir_offset); | 1355 | di->offset = ceph_make_fpos(frag, i + r_readdir_offset); |
| 1319 | 1356 | ||
| 1320 | /* inode */ | 1357 | /* inode */ |
| 1321 | if (dn->d_inode) { | 1358 | if (dn->d_inode) { |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index b7bda5d9611d..d90861f45210 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
| @@ -43,6 +43,7 @@ | |||
| 43 | */ | 43 | */ |
| 44 | 44 | ||
| 45 | struct ceph_reconnect_state { | 45 | struct ceph_reconnect_state { |
| 46 | int nr_caps; | ||
| 46 | struct ceph_pagelist *pagelist; | 47 | struct ceph_pagelist *pagelist; |
| 47 | bool flock; | 48 | bool flock; |
| 48 | }; | 49 | }; |
| @@ -443,6 +444,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, | |||
| 443 | INIT_LIST_HEAD(&s->s_waiting); | 444 | INIT_LIST_HEAD(&s->s_waiting); |
| 444 | INIT_LIST_HEAD(&s->s_unsafe); | 445 | INIT_LIST_HEAD(&s->s_unsafe); |
| 445 | s->s_num_cap_releases = 0; | 446 | s->s_num_cap_releases = 0; |
| 447 | s->s_cap_reconnect = 0; | ||
| 446 | s->s_cap_iterator = NULL; | 448 | s->s_cap_iterator = NULL; |
| 447 | INIT_LIST_HEAD(&s->s_cap_releases); | 449 | INIT_LIST_HEAD(&s->s_cap_releases); |
| 448 | INIT_LIST_HEAD(&s->s_cap_releases_done); | 450 | INIT_LIST_HEAD(&s->s_cap_releases_done); |
| @@ -642,6 +644,8 @@ static void __unregister_request(struct ceph_mds_client *mdsc, | |||
| 642 | req->r_unsafe_dir = NULL; | 644 | req->r_unsafe_dir = NULL; |
| 643 | } | 645 | } |
| 644 | 646 | ||
| 647 | complete_all(&req->r_safe_completion); | ||
| 648 | |||
| 645 | ceph_mdsc_put_request(req); | 649 | ceph_mdsc_put_request(req); |
| 646 | } | 650 | } |
| 647 | 651 | ||
| @@ -986,7 +990,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, | |||
| 986 | dout("removing cap %p, ci is %p, inode is %p\n", | 990 | dout("removing cap %p, ci is %p, inode is %p\n", |
| 987 | cap, ci, &ci->vfs_inode); | 991 | cap, ci, &ci->vfs_inode); |
| 988 | spin_lock(&ci->i_ceph_lock); | 992 | spin_lock(&ci->i_ceph_lock); |
| 989 | __ceph_remove_cap(cap); | 993 | __ceph_remove_cap(cap, false); |
| 990 | if (!__ceph_is_any_real_caps(ci)) { | 994 | if (!__ceph_is_any_real_caps(ci)) { |
| 991 | struct ceph_mds_client *mdsc = | 995 | struct ceph_mds_client *mdsc = |
| 992 | ceph_sb_to_client(inode->i_sb)->mdsc; | 996 | ceph_sb_to_client(inode->i_sb)->mdsc; |
| @@ -1231,9 +1235,7 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg) | |||
| 1231 | session->s_trim_caps--; | 1235 | session->s_trim_caps--; |
| 1232 | if (oissued) { | 1236 | if (oissued) { |
| 1233 | /* we aren't the only cap.. just remove us */ | 1237 | /* we aren't the only cap.. just remove us */ |
| 1234 | __queue_cap_release(session, ceph_ino(inode), cap->cap_id, | 1238 | __ceph_remove_cap(cap, true); |
| 1235 | cap->mseq, cap->issue_seq); | ||
| 1236 | __ceph_remove_cap(cap); | ||
| 1237 | } else { | 1239 | } else { |
| 1238 | /* try to drop referring dentries */ | 1240 | /* try to drop referring dentries */ |
| 1239 | spin_unlock(&ci->i_ceph_lock); | 1241 | spin_unlock(&ci->i_ceph_lock); |
| @@ -1416,7 +1418,6 @@ static void discard_cap_releases(struct ceph_mds_client *mdsc, | |||
| 1416 | unsigned num; | 1418 | unsigned num; |
| 1417 | 1419 | ||
| 1418 | dout("discard_cap_releases mds%d\n", session->s_mds); | 1420 | dout("discard_cap_releases mds%d\n", session->s_mds); |
| 1419 | spin_lock(&session->s_cap_lock); | ||
| 1420 | 1421 | ||
| 1421 | /* zero out the in-progress message */ | 1422 | /* zero out the in-progress message */ |
| 1422 | msg = list_first_entry(&session->s_cap_releases, | 1423 | msg = list_first_entry(&session->s_cap_releases, |
| @@ -1443,8 +1444,6 @@ static void discard_cap_releases(struct ceph_mds_client *mdsc, | |||
| 1443 | msg->front.iov_len = sizeof(*head); | 1444 | msg->front.iov_len = sizeof(*head); |
| 1444 | list_add(&msg->list_head, &session->s_cap_releases); | 1445 | list_add(&msg->list_head, &session->s_cap_releases); |
| 1445 | } | 1446 | } |
| 1446 | |||
| 1447 | spin_unlock(&session->s_cap_lock); | ||
| 1448 | } | 1447 | } |
| 1449 | 1448 | ||
| 1450 | /* | 1449 | /* |
| @@ -1875,8 +1874,11 @@ static int __do_request(struct ceph_mds_client *mdsc, | |||
| 1875 | int mds = -1; | 1874 | int mds = -1; |
| 1876 | int err = -EAGAIN; | 1875 | int err = -EAGAIN; |
| 1877 | 1876 | ||
| 1878 | if (req->r_err || req->r_got_result) | 1877 | if (req->r_err || req->r_got_result) { |
| 1878 | if (req->r_aborted) | ||
| 1879 | __unregister_request(mdsc, req); | ||
| 1879 | goto out; | 1880 | goto out; |
| 1881 | } | ||
| 1880 | 1882 | ||
| 1881 | if (req->r_timeout && | 1883 | if (req->r_timeout && |
| 1882 | time_after_eq(jiffies, req->r_started + req->r_timeout)) { | 1884 | time_after_eq(jiffies, req->r_started + req->r_timeout)) { |
| @@ -2186,7 +2188,6 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) | |||
| 2186 | if (head->safe) { | 2188 | if (head->safe) { |
| 2187 | req->r_got_safe = true; | 2189 | req->r_got_safe = true; |
| 2188 | __unregister_request(mdsc, req); | 2190 | __unregister_request(mdsc, req); |
| 2189 | complete_all(&req->r_safe_completion); | ||
| 2190 | 2191 | ||
| 2191 | if (req->r_got_unsafe) { | 2192 | if (req->r_got_unsafe) { |
| 2192 | /* | 2193 | /* |
| @@ -2238,8 +2239,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) | |||
| 2238 | err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session); | 2239 | err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session); |
| 2239 | if (err == 0) { | 2240 | if (err == 0) { |
| 2240 | if (result == 0 && (req->r_op == CEPH_MDS_OP_READDIR || | 2241 | if (result == 0 && (req->r_op == CEPH_MDS_OP_READDIR || |
| 2241 | req->r_op == CEPH_MDS_OP_LSSNAP) && | 2242 | req->r_op == CEPH_MDS_OP_LSSNAP)) |
| 2242 | rinfo->dir_nr) | ||
| 2243 | ceph_readdir_prepopulate(req, req->r_session); | 2243 | ceph_readdir_prepopulate(req, req->r_session); |
| 2244 | ceph_unreserve_caps(mdsc, &req->r_caps_reservation); | 2244 | ceph_unreserve_caps(mdsc, &req->r_caps_reservation); |
| 2245 | } | 2245 | } |
| @@ -2490,6 +2490,7 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, | |||
| 2490 | cap->seq = 0; /* reset cap seq */ | 2490 | cap->seq = 0; /* reset cap seq */ |
| 2491 | cap->issue_seq = 0; /* and issue_seq */ | 2491 | cap->issue_seq = 0; /* and issue_seq */ |
| 2492 | cap->mseq = 0; /* and migrate_seq */ | 2492 | cap->mseq = 0; /* and migrate_seq */ |
| 2493 | cap->cap_gen = cap->session->s_cap_gen; | ||
| 2493 | 2494 | ||
| 2494 | if (recon_state->flock) { | 2495 | if (recon_state->flock) { |
| 2495 | rec.v2.cap_id = cpu_to_le64(cap->cap_id); | 2496 | rec.v2.cap_id = cpu_to_le64(cap->cap_id); |
| @@ -2552,6 +2553,8 @@ encode_again: | |||
| 2552 | } else { | 2553 | } else { |
| 2553 | err = ceph_pagelist_append(pagelist, &rec, reclen); | 2554 | err = ceph_pagelist_append(pagelist, &rec, reclen); |
| 2554 | } | 2555 | } |
| 2556 | |||
| 2557 | recon_state->nr_caps++; | ||
| 2555 | out_free: | 2558 | out_free: |
| 2556 | kfree(path); | 2559 | kfree(path); |
| 2557 | out_dput: | 2560 | out_dput: |
| @@ -2579,6 +2582,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, | |||
| 2579 | struct rb_node *p; | 2582 | struct rb_node *p; |
| 2580 | int mds = session->s_mds; | 2583 | int mds = session->s_mds; |
| 2581 | int err = -ENOMEM; | 2584 | int err = -ENOMEM; |
| 2585 | int s_nr_caps; | ||
| 2582 | struct ceph_pagelist *pagelist; | 2586 | struct ceph_pagelist *pagelist; |
| 2583 | struct ceph_reconnect_state recon_state; | 2587 | struct ceph_reconnect_state recon_state; |
| 2584 | 2588 | ||
| @@ -2610,20 +2614,38 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, | |||
| 2610 | dout("session %p state %s\n", session, | 2614 | dout("session %p state %s\n", session, |
| 2611 | session_state_name(session->s_state)); | 2615 | session_state_name(session->s_state)); |
| 2612 | 2616 | ||
| 2617 | spin_lock(&session->s_gen_ttl_lock); | ||
| 2618 | session->s_cap_gen++; | ||
| 2619 | spin_unlock(&session->s_gen_ttl_lock); | ||
| 2620 | |||
| 2621 | spin_lock(&session->s_cap_lock); | ||
| 2622 | /* | ||
| 2623 | * notify __ceph_remove_cap() that we are composing cap reconnect. | ||
| 2624 | * If a cap get released before being added to the cap reconnect, | ||
| 2625 | * __ceph_remove_cap() should skip queuing cap release. | ||
| 2626 | */ | ||
| 2627 | session->s_cap_reconnect = 1; | ||
| 2613 | /* drop old cap expires; we're about to reestablish that state */ | 2628 | /* drop old cap expires; we're about to reestablish that state */ |
| 2614 | discard_cap_releases(mdsc, session); | 2629 | discard_cap_releases(mdsc, session); |
| 2630 | spin_unlock(&session->s_cap_lock); | ||
| 2615 | 2631 | ||
| 2616 | /* traverse this session's caps */ | 2632 | /* traverse this session's caps */ |
| 2617 | err = ceph_pagelist_encode_32(pagelist, session->s_nr_caps); | 2633 | s_nr_caps = session->s_nr_caps; |
| 2634 | err = ceph_pagelist_encode_32(pagelist, s_nr_caps); | ||
| 2618 | if (err) | 2635 | if (err) |
| 2619 | goto fail; | 2636 | goto fail; |
| 2620 | 2637 | ||
| 2638 | recon_state.nr_caps = 0; | ||
| 2621 | recon_state.pagelist = pagelist; | 2639 | recon_state.pagelist = pagelist; |
| 2622 | recon_state.flock = session->s_con.peer_features & CEPH_FEATURE_FLOCK; | 2640 | recon_state.flock = session->s_con.peer_features & CEPH_FEATURE_FLOCK; |
| 2623 | err = iterate_session_caps(session, encode_caps_cb, &recon_state); | 2641 | err = iterate_session_caps(session, encode_caps_cb, &recon_state); |
| 2624 | if (err < 0) | 2642 | if (err < 0) |
| 2625 | goto fail; | 2643 | goto fail; |
| 2626 | 2644 | ||
| 2645 | spin_lock(&session->s_cap_lock); | ||
| 2646 | session->s_cap_reconnect = 0; | ||
| 2647 | spin_unlock(&session->s_cap_lock); | ||
| 2648 | |||
| 2627 | /* | 2649 | /* |
| 2628 | * snaprealms. we provide mds with the ino, seq (version), and | 2650 | * snaprealms. we provide mds with the ino, seq (version), and |
| 2629 | * parent for all of our realms. If the mds has any newer info, | 2651 | * parent for all of our realms. If the mds has any newer info, |
| @@ -2646,11 +2668,18 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, | |||
| 2646 | 2668 | ||
| 2647 | if (recon_state.flock) | 2669 | if (recon_state.flock) |
| 2648 | reply->hdr.version = cpu_to_le16(2); | 2670 | reply->hdr.version = cpu_to_le16(2); |
| 2649 | if (pagelist->length) { | 2671 | |
| 2650 | /* set up outbound data if we have any */ | 2672 | /* raced with cap release? */ |
| 2651 | reply->hdr.data_len = cpu_to_le32(pagelist->length); | 2673 | if (s_nr_caps != recon_state.nr_caps) { |
| 2652 | ceph_msg_data_add_pagelist(reply, pagelist); | 2674 | struct page *page = list_first_entry(&pagelist->head, |
| 2675 | struct page, lru); | ||
| 2676 | __le32 *addr = kmap_atomic(page); | ||
| 2677 | *addr = cpu_to_le32(recon_state.nr_caps); | ||
| 2678 | kunmap_atomic(addr); | ||
| 2653 | } | 2679 | } |
| 2680 | |||
| 2681 | reply->hdr.data_len = cpu_to_le32(pagelist->length); | ||
| 2682 | ceph_msg_data_add_pagelist(reply, pagelist); | ||
| 2654 | ceph_con_send(&session->s_con, reply); | 2683 | ceph_con_send(&session->s_con, reply); |
| 2655 | 2684 | ||
| 2656 | mutex_unlock(&session->s_mutex); | 2685 | mutex_unlock(&session->s_mutex); |
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index c2a19fbbe517..4c053d099ae4 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h | |||
| @@ -132,6 +132,7 @@ struct ceph_mds_session { | |||
| 132 | struct list_head s_caps; /* all caps issued by this session */ | 132 | struct list_head s_caps; /* all caps issued by this session */ |
| 133 | int s_nr_caps, s_trim_caps; | 133 | int s_nr_caps, s_trim_caps; |
| 134 | int s_num_cap_releases; | 134 | int s_num_cap_releases; |
| 135 | int s_cap_reconnect; | ||
| 135 | struct list_head s_cap_releases; /* waiting cap_release messages */ | 136 | struct list_head s_cap_releases; /* waiting cap_release messages */ |
| 136 | struct list_head s_cap_releases_done; /* ready to send */ | 137 | struct list_head s_cap_releases_done; /* ready to send */ |
| 137 | struct ceph_cap *s_cap_iterator; | 138 | struct ceph_cap *s_cap_iterator; |
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 6014b0a3c405..ef4ac38bb614 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
| @@ -741,13 +741,7 @@ extern int ceph_add_cap(struct inode *inode, | |||
| 741 | int fmode, unsigned issued, unsigned wanted, | 741 | int fmode, unsigned issued, unsigned wanted, |
| 742 | unsigned cap, unsigned seq, u64 realmino, int flags, | 742 | unsigned cap, unsigned seq, u64 realmino, int flags, |
| 743 | struct ceph_cap_reservation *caps_reservation); | 743 | struct ceph_cap_reservation *caps_reservation); |
| 744 | extern void __ceph_remove_cap(struct ceph_cap *cap); | 744 | extern void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release); |
| 745 | static inline void ceph_remove_cap(struct ceph_cap *cap) | ||
| 746 | { | ||
| 747 | spin_lock(&cap->ci->i_ceph_lock); | ||
| 748 | __ceph_remove_cap(cap); | ||
| 749 | spin_unlock(&cap->ci->i_ceph_lock); | ||
| 750 | } | ||
| 751 | extern void ceph_put_cap(struct ceph_mds_client *mdsc, | 745 | extern void ceph_put_cap(struct ceph_mds_client *mdsc, |
| 752 | struct ceph_cap *cap); | 746 | struct ceph_cap *cap); |
| 753 | 747 | ||
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d9ea7ada1378..f918a998a087 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -384,6 +384,7 @@ struct smb_version_operations { | |||
| 384 | int (*clone_range)(const unsigned int, struct cifsFileInfo *src_file, | 384 | int (*clone_range)(const unsigned int, struct cifsFileInfo *src_file, |
| 385 | struct cifsFileInfo *target_file, u64 src_off, u64 len, | 385 | struct cifsFileInfo *target_file, u64 src_off, u64 len, |
| 386 | u64 dest_off); | 386 | u64 dest_off); |
| 387 | int (*validate_negotiate)(const unsigned int, struct cifs_tcon *); | ||
| 387 | }; | 388 | }; |
| 388 | 389 | ||
| 389 | struct smb_version_values { | 390 | struct smb_version_values { |
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 409b45eefe70..77492301cc2b 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c | |||
| @@ -26,13 +26,15 @@ | |||
| 26 | #include <linux/mount.h> | 26 | #include <linux/mount.h> |
| 27 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
| 28 | #include <linux/pagemap.h> | 28 | #include <linux/pagemap.h> |
| 29 | #include <linux/btrfs.h> | ||
| 30 | #include "cifspdu.h" | 29 | #include "cifspdu.h" |
| 31 | #include "cifsglob.h" | 30 | #include "cifsglob.h" |
| 32 | #include "cifsproto.h" | 31 | #include "cifsproto.h" |
| 33 | #include "cifs_debug.h" | 32 | #include "cifs_debug.h" |
| 34 | #include "cifsfs.h" | 33 | #include "cifsfs.h" |
| 35 | 34 | ||
| 35 | #define CIFS_IOCTL_MAGIC 0xCF | ||
| 36 | #define CIFS_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int) | ||
| 37 | |||
| 36 | static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file, | 38 | static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file, |
| 37 | unsigned long srcfd, u64 off, u64 len, u64 destoff) | 39 | unsigned long srcfd, u64 off, u64 len, u64 destoff) |
| 38 | { | 40 | { |
| @@ -213,7 +215,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) | |||
| 213 | cifs_dbg(FYI, "set compress flag rc %d\n", rc); | 215 | cifs_dbg(FYI, "set compress flag rc %d\n", rc); |
| 214 | } | 216 | } |
| 215 | break; | 217 | break; |
| 216 | case BTRFS_IOC_CLONE: | 218 | case CIFS_IOC_COPYCHUNK_FILE: |
| 217 | rc = cifs_ioctl_clone(xid, filep, arg, 0, 0, 0); | 219 | rc = cifs_ioctl_clone(xid, filep, arg, 0, 0, 0); |
| 218 | break; | 220 | break; |
| 219 | default: | 221 | default: |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 11dde4b24f8a..757da3e54d3d 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
| @@ -532,7 +532,10 @@ smb2_clone_range(const unsigned int xid, | |||
| 532 | int rc; | 532 | int rc; |
| 533 | unsigned int ret_data_len; | 533 | unsigned int ret_data_len; |
| 534 | struct copychunk_ioctl *pcchunk; | 534 | struct copychunk_ioctl *pcchunk; |
| 535 | char *retbuf = NULL; | 535 | struct copychunk_ioctl_rsp *retbuf = NULL; |
| 536 | struct cifs_tcon *tcon; | ||
| 537 | int chunks_copied = 0; | ||
| 538 | bool chunk_sizes_updated = false; | ||
| 536 | 539 | ||
| 537 | pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL); | 540 | pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL); |
| 538 | 541 | ||
| @@ -547,27 +550,96 @@ smb2_clone_range(const unsigned int xid, | |||
| 547 | 550 | ||
| 548 | /* Note: request_res_key sets res_key null only if rc !=0 */ | 551 | /* Note: request_res_key sets res_key null only if rc !=0 */ |
| 549 | if (rc) | 552 | if (rc) |
| 550 | return rc; | 553 | goto cchunk_out; |
| 551 | 554 | ||
| 552 | /* For now array only one chunk long, will make more flexible later */ | 555 | /* For now array only one chunk long, will make more flexible later */ |
| 553 | pcchunk->ChunkCount = __constant_cpu_to_le32(1); | 556 | pcchunk->ChunkCount = __constant_cpu_to_le32(1); |
| 554 | pcchunk->Reserved = 0; | 557 | pcchunk->Reserved = 0; |
| 555 | pcchunk->SourceOffset = cpu_to_le64(src_off); | ||
| 556 | pcchunk->TargetOffset = cpu_to_le64(dest_off); | ||
| 557 | pcchunk->Length = cpu_to_le32(len); | ||
| 558 | pcchunk->Reserved2 = 0; | 558 | pcchunk->Reserved2 = 0; |
| 559 | 559 | ||
| 560 | /* Request that server copy to target from src file identified by key */ | 560 | tcon = tlink_tcon(trgtfile->tlink); |
| 561 | rc = SMB2_ioctl(xid, tlink_tcon(trgtfile->tlink), | ||
| 562 | trgtfile->fid.persistent_fid, | ||
| 563 | trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE, | ||
| 564 | true /* is_fsctl */, (char *)pcchunk, | ||
| 565 | sizeof(struct copychunk_ioctl), &retbuf, &ret_data_len); | ||
| 566 | 561 | ||
| 567 | /* BB need to special case rc = EINVAL to alter chunk size */ | 562 | while (len > 0) { |
| 563 | pcchunk->SourceOffset = cpu_to_le64(src_off); | ||
| 564 | pcchunk->TargetOffset = cpu_to_le64(dest_off); | ||
| 565 | pcchunk->Length = | ||
| 566 | cpu_to_le32(min_t(u32, len, tcon->max_bytes_chunk)); | ||
| 568 | 567 | ||
| 569 | cifs_dbg(FYI, "rc %d data length out %d\n", rc, ret_data_len); | 568 | /* Request server copy to target from src identified by key */ |
| 569 | rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid, | ||
| 570 | trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE, | ||
| 571 | true /* is_fsctl */, (char *)pcchunk, | ||
| 572 | sizeof(struct copychunk_ioctl), (char **)&retbuf, | ||
| 573 | &ret_data_len); | ||
| 574 | if (rc == 0) { | ||
| 575 | if (ret_data_len != | ||
| 576 | sizeof(struct copychunk_ioctl_rsp)) { | ||
| 577 | cifs_dbg(VFS, "invalid cchunk response size\n"); | ||
| 578 | rc = -EIO; | ||
| 579 | goto cchunk_out; | ||
| 580 | } | ||
| 581 | if (retbuf->TotalBytesWritten == 0) { | ||
| 582 | cifs_dbg(FYI, "no bytes copied\n"); | ||
| 583 | rc = -EIO; | ||
| 584 | goto cchunk_out; | ||
| 585 | } | ||
| 586 | /* | ||
| 587 | * Check if server claimed to write more than we asked | ||
| 588 | */ | ||
| 589 | if (le32_to_cpu(retbuf->TotalBytesWritten) > | ||
| 590 | le32_to_cpu(pcchunk->Length)) { | ||
| 591 | cifs_dbg(VFS, "invalid copy chunk response\n"); | ||
| 592 | rc = -EIO; | ||
| 593 | goto cchunk_out; | ||
| 594 | } | ||
| 595 | if (le32_to_cpu(retbuf->ChunksWritten) != 1) { | ||
| 596 | cifs_dbg(VFS, "invalid num chunks written\n"); | ||
| 597 | rc = -EIO; | ||
| 598 | goto cchunk_out; | ||
| 599 | } | ||
| 600 | chunks_copied++; | ||
| 601 | |||
| 602 | src_off += le32_to_cpu(retbuf->TotalBytesWritten); | ||
| 603 | dest_off += le32_to_cpu(retbuf->TotalBytesWritten); | ||
| 604 | len -= le32_to_cpu(retbuf->TotalBytesWritten); | ||
| 605 | |||
| 606 | cifs_dbg(FYI, "Chunks %d PartialChunk %d Total %d\n", | ||
| 607 | le32_to_cpu(retbuf->ChunksWritten), | ||
| 608 | le32_to_cpu(retbuf->ChunkBytesWritten), | ||
| 609 | le32_to_cpu(retbuf->TotalBytesWritten)); | ||
| 610 | } else if (rc == -EINVAL) { | ||
| 611 | if (ret_data_len != sizeof(struct copychunk_ioctl_rsp)) | ||
| 612 | goto cchunk_out; | ||
| 613 | |||
| 614 | cifs_dbg(FYI, "MaxChunks %d BytesChunk %d MaxCopy %d\n", | ||
| 615 | le32_to_cpu(retbuf->ChunksWritten), | ||
| 616 | le32_to_cpu(retbuf->ChunkBytesWritten), | ||
| 617 | le32_to_cpu(retbuf->TotalBytesWritten)); | ||
| 618 | |||
| 619 | /* | ||
| 620 | * Check if this is the first request using these sizes, | ||
| 621 | * (ie check if copy succeed once with original sizes | ||
| 622 | * and check if the server gave us different sizes after | ||
| 623 | * we already updated max sizes on previous request). | ||
| 624 | * if not then why is the server returning an error now | ||
| 625 | */ | ||
| 626 | if ((chunks_copied != 0) || chunk_sizes_updated) | ||
| 627 | goto cchunk_out; | ||
| 628 | |||
| 629 | /* Check that server is not asking us to grow size */ | ||
| 630 | if (le32_to_cpu(retbuf->ChunkBytesWritten) < | ||
| 631 | tcon->max_bytes_chunk) | ||
| 632 | tcon->max_bytes_chunk = | ||
| 633 | le32_to_cpu(retbuf->ChunkBytesWritten); | ||
| 634 | else | ||
| 635 | goto cchunk_out; /* server gave us bogus size */ | ||
| 636 | |||
| 637 | /* No need to change MaxChunks since already set to 1 */ | ||
| 638 | chunk_sizes_updated = true; | ||
| 639 | } | ||
| 640 | } | ||
| 570 | 641 | ||
| 642 | cchunk_out: | ||
| 571 | kfree(pcchunk); | 643 | kfree(pcchunk); |
| 572 | return rc; | 644 | return rc; |
| 573 | } | 645 | } |
| @@ -1247,6 +1319,7 @@ struct smb_version_operations smb30_operations = { | |||
| 1247 | .create_lease_buf = smb3_create_lease_buf, | 1319 | .create_lease_buf = smb3_create_lease_buf, |
| 1248 | .parse_lease_buf = smb3_parse_lease_buf, | 1320 | .parse_lease_buf = smb3_parse_lease_buf, |
| 1249 | .clone_range = smb2_clone_range, | 1321 | .clone_range = smb2_clone_range, |
| 1322 | .validate_negotiate = smb3_validate_negotiate, | ||
| 1250 | }; | 1323 | }; |
| 1251 | 1324 | ||
| 1252 | struct smb_version_values smb20_values = { | 1325 | struct smb_version_values smb20_values = { |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index d65270c290a1..2013234b73ad 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
| @@ -454,6 +454,81 @@ neg_exit: | |||
| 454 | return rc; | 454 | return rc; |
| 455 | } | 455 | } |
| 456 | 456 | ||
| 457 | int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) | ||
| 458 | { | ||
| 459 | int rc = 0; | ||
| 460 | struct validate_negotiate_info_req vneg_inbuf; | ||
| 461 | struct validate_negotiate_info_rsp *pneg_rsp; | ||
| 462 | u32 rsplen; | ||
| 463 | |||
| 464 | cifs_dbg(FYI, "validate negotiate\n"); | ||
| 465 | |||
| 466 | /* | ||
| 467 | * validation ioctl must be signed, so no point sending this if we | ||
| 468 | * can not sign it. We could eventually change this to selectively | ||
| 469 | * sign just this, the first and only signed request on a connection. | ||
| 470 | * This is good enough for now since a user who wants better security | ||
| 471 | * would also enable signing on the mount. Having validation of | ||
| 472 | * negotiate info for signed connections helps reduce attack vectors | ||
| 473 | */ | ||
| 474 | if (tcon->ses->server->sign == false) | ||
| 475 | return 0; /* validation requires signing */ | ||
| 476 | |||
| 477 | vneg_inbuf.Capabilities = | ||
| 478 | cpu_to_le32(tcon->ses->server->vals->req_capabilities); | ||
| 479 | memcpy(vneg_inbuf.Guid, cifs_client_guid, SMB2_CLIENT_GUID_SIZE); | ||
| 480 | |||
| 481 | if (tcon->ses->sign) | ||
| 482 | vneg_inbuf.SecurityMode = | ||
| 483 | cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED); | ||
| 484 | else if (global_secflags & CIFSSEC_MAY_SIGN) | ||
| 485 | vneg_inbuf.SecurityMode = | ||
| 486 | cpu_to_le16(SMB2_NEGOTIATE_SIGNING_ENABLED); | ||
| 487 | else | ||
| 488 | vneg_inbuf.SecurityMode = 0; | ||
| 489 | |||
| 490 | vneg_inbuf.DialectCount = cpu_to_le16(1); | ||
| 491 | vneg_inbuf.Dialects[0] = | ||
| 492 | cpu_to_le16(tcon->ses->server->vals->protocol_id); | ||
| 493 | |||
| 494 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, | ||
| 495 | FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, | ||
| 496 | (char *)&vneg_inbuf, sizeof(struct validate_negotiate_info_req), | ||
| 497 | (char **)&pneg_rsp, &rsplen); | ||
| 498 | |||
| 499 | if (rc != 0) { | ||
| 500 | cifs_dbg(VFS, "validate protocol negotiate failed: %d\n", rc); | ||
| 501 | return -EIO; | ||
| 502 | } | ||
| 503 | |||
| 504 | if (rsplen != sizeof(struct validate_negotiate_info_rsp)) { | ||
| 505 | cifs_dbg(VFS, "invalid size of protocol negotiate response\n"); | ||
| 506 | return -EIO; | ||
| 507 | } | ||
| 508 | |||
| 509 | /* check validate negotiate info response matches what we got earlier */ | ||
| 510 | if (pneg_rsp->Dialect != | ||
| 511 | cpu_to_le16(tcon->ses->server->vals->protocol_id)) | ||
| 512 | goto vneg_out; | ||
| 513 | |||
| 514 | if (pneg_rsp->SecurityMode != cpu_to_le16(tcon->ses->server->sec_mode)) | ||
| 515 | goto vneg_out; | ||
| 516 | |||
| 517 | /* do not validate server guid because not saved at negprot time yet */ | ||
| 518 | |||
| 519 | if ((le32_to_cpu(pneg_rsp->Capabilities) | SMB2_NT_FIND | | ||
| 520 | SMB2_LARGE_FILES) != tcon->ses->server->capabilities) | ||
| 521 | goto vneg_out; | ||
| 522 | |||
| 523 | /* validate negotiate successful */ | ||
| 524 | cifs_dbg(FYI, "validate negotiate info successful\n"); | ||
| 525 | return 0; | ||
| 526 | |||
| 527 | vneg_out: | ||
| 528 | cifs_dbg(VFS, "protocol revalidation - security settings mismatch\n"); | ||
| 529 | return -EIO; | ||
| 530 | } | ||
| 531 | |||
| 457 | int | 532 | int |
| 458 | SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, | 533 | SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, |
| 459 | const struct nls_table *nls_cp) | 534 | const struct nls_table *nls_cp) |
| @@ -829,6 +904,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, | |||
| 829 | ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) | 904 | ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) |
| 830 | cifs_dbg(VFS, "DFS capability contradicts DFS flag\n"); | 905 | cifs_dbg(VFS, "DFS capability contradicts DFS flag\n"); |
| 831 | init_copy_chunk_defaults(tcon); | 906 | init_copy_chunk_defaults(tcon); |
| 907 | if (tcon->ses->server->ops->validate_negotiate) | ||
| 908 | rc = tcon->ses->server->ops->validate_negotiate(xid, tcon); | ||
| 832 | tcon_exit: | 909 | tcon_exit: |
| 833 | free_rsp_buf(resp_buftype, rsp); | 910 | free_rsp_buf(resp_buftype, rsp); |
| 834 | kfree(unc_path); | 911 | kfree(unc_path); |
| @@ -1214,10 +1291,17 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, | |||
| 1214 | rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0); | 1291 | rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0); |
| 1215 | rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base; | 1292 | rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base; |
| 1216 | 1293 | ||
| 1217 | if (rc != 0) { | 1294 | if ((rc != 0) && (rc != -EINVAL)) { |
| 1218 | if (tcon) | 1295 | if (tcon) |
| 1219 | cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); | 1296 | cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); |
| 1220 | goto ioctl_exit; | 1297 | goto ioctl_exit; |
| 1298 | } else if (rc == -EINVAL) { | ||
| 1299 | if ((opcode != FSCTL_SRV_COPYCHUNK_WRITE) && | ||
| 1300 | (opcode != FSCTL_SRV_COPYCHUNK)) { | ||
| 1301 | if (tcon) | ||
| 1302 | cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); | ||
| 1303 | goto ioctl_exit; | ||
| 1304 | } | ||
| 1221 | } | 1305 | } |
| 1222 | 1306 | ||
| 1223 | /* check if caller wants to look at return data or just return rc */ | 1307 | /* check if caller wants to look at return data or just return rc */ |
| @@ -2154,11 +2238,9 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 2154 | rc = SendReceive2(xid, ses, iov, num, &resp_buftype, 0); | 2238 | rc = SendReceive2(xid, ses, iov, num, &resp_buftype, 0); |
| 2155 | rsp = (struct smb2_set_info_rsp *)iov[0].iov_base; | 2239 | rsp = (struct smb2_set_info_rsp *)iov[0].iov_base; |
| 2156 | 2240 | ||
| 2157 | if (rc != 0) { | 2241 | if (rc != 0) |
| 2158 | cifs_stats_fail_inc(tcon, SMB2_SET_INFO_HE); | 2242 | cifs_stats_fail_inc(tcon, SMB2_SET_INFO_HE); |
| 2159 | goto out; | 2243 | |
| 2160 | } | ||
| 2161 | out: | ||
| 2162 | free_rsp_buf(resp_buftype, rsp); | 2244 | free_rsp_buf(resp_buftype, rsp); |
| 2163 | kfree(iov); | 2245 | kfree(iov); |
| 2164 | return rc; | 2246 | return rc; |
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index f88320bbb477..2022c542ea3a 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h | |||
| @@ -577,13 +577,19 @@ struct copychunk_ioctl_rsp { | |||
| 577 | __le32 TotalBytesWritten; | 577 | __le32 TotalBytesWritten; |
| 578 | } __packed; | 578 | } __packed; |
| 579 | 579 | ||
| 580 | /* Response and Request are the same format */ | 580 | struct validate_negotiate_info_req { |
| 581 | struct validate_negotiate_info { | ||
| 582 | __le32 Capabilities; | 581 | __le32 Capabilities; |
| 583 | __u8 Guid[SMB2_CLIENT_GUID_SIZE]; | 582 | __u8 Guid[SMB2_CLIENT_GUID_SIZE]; |
| 584 | __le16 SecurityMode; | 583 | __le16 SecurityMode; |
| 585 | __le16 DialectCount; | 584 | __le16 DialectCount; |
| 586 | __le16 Dialect[1]; | 585 | __le16 Dialects[1]; /* dialect (someday maybe list) client asked for */ |
| 586 | } __packed; | ||
| 587 | |||
| 588 | struct validate_negotiate_info_rsp { | ||
| 589 | __le32 Capabilities; | ||
| 590 | __u8 Guid[SMB2_CLIENT_GUID_SIZE]; | ||
| 591 | __le16 SecurityMode; | ||
| 592 | __le16 Dialect; /* Dialect in use for the connection */ | ||
| 587 | } __packed; | 593 | } __packed; |
| 588 | 594 | ||
| 589 | #define RSS_CAPABLE 0x00000001 | 595 | #define RSS_CAPABLE 0x00000001 |
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index b4eea105b08c..93adc64666f3 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
| @@ -162,5 +162,6 @@ extern int smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 162 | struct smb2_lock_element *buf); | 162 | struct smb2_lock_element *buf); |
| 163 | extern int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, | 163 | extern int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, |
| 164 | __u8 *lease_key, const __le32 lease_state); | 164 | __u8 *lease_key, const __le32 lease_state); |
| 165 | extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); | ||
| 165 | 166 | ||
| 166 | #endif /* _SMB2PROTO_H */ | 167 | #endif /* _SMB2PROTO_H */ |
diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h index a4b2391fe66e..0e538b5c9622 100644 --- a/fs/cifs/smbfsctl.h +++ b/fs/cifs/smbfsctl.h | |||
| @@ -90,7 +90,7 @@ | |||
| 90 | #define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */ | 90 | #define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */ |
| 91 | #define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */ | 91 | #define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */ |
| 92 | #define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */ | 92 | #define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */ |
| 93 | #define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 /* BB add struct */ | 93 | #define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 |
| 94 | /* Perform server-side data movement */ | 94 | /* Perform server-side data movement */ |
| 95 | #define FSCTL_SRV_COPYCHUNK 0x001440F2 | 95 | #define FSCTL_SRV_COPYCHUNK 0x001440F2 |
| 96 | #define FSCTL_SRV_COPYCHUNK_WRITE 0x001480F2 | 96 | #define FSCTL_SRV_COPYCHUNK_WRITE 0x001480F2 |
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 79b65c3b9e87..8b5e2584c840 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
| @@ -1852,8 +1852,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, | |||
| 1852 | goto error_tgt_fput; | 1852 | goto error_tgt_fput; |
| 1853 | 1853 | ||
| 1854 | /* Check if EPOLLWAKEUP is allowed */ | 1854 | /* Check if EPOLLWAKEUP is allowed */ |
| 1855 | if ((epds.events & EPOLLWAKEUP) && !capable(CAP_BLOCK_SUSPEND)) | 1855 | ep_take_care_of_epollwakeup(&epds); |
| 1856 | epds.events &= ~EPOLLWAKEUP; | ||
| 1857 | 1856 | ||
| 1858 | /* | 1857 | /* |
| 1859 | * We have to check that the file structure underneath the file descriptor | 1858 | * We have to check that the file structure underneath the file descriptor |
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c index b51a6079108d..e9a97a0d4314 100644 --- a/fs/hfsplus/wrapper.c +++ b/fs/hfsplus/wrapper.c | |||
| @@ -24,13 +24,6 @@ struct hfsplus_wd { | |||
| 24 | u16 embed_count; | 24 | u16 embed_count; |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | static void hfsplus_end_io_sync(struct bio *bio, int err) | ||
| 28 | { | ||
| 29 | if (err) | ||
| 30 | clear_bit(BIO_UPTODATE, &bio->bi_flags); | ||
| 31 | complete(bio->bi_private); | ||
| 32 | } | ||
| 33 | |||
| 34 | /* | 27 | /* |
| 35 | * hfsplus_submit_bio - Perfrom block I/O | 28 | * hfsplus_submit_bio - Perfrom block I/O |
| 36 | * @sb: super block of volume for I/O | 29 | * @sb: super block of volume for I/O |
| @@ -53,7 +46,6 @@ static void hfsplus_end_io_sync(struct bio *bio, int err) | |||
| 53 | int hfsplus_submit_bio(struct super_block *sb, sector_t sector, | 46 | int hfsplus_submit_bio(struct super_block *sb, sector_t sector, |
| 54 | void *buf, void **data, int rw) | 47 | void *buf, void **data, int rw) |
| 55 | { | 48 | { |
| 56 | DECLARE_COMPLETION_ONSTACK(wait); | ||
| 57 | struct bio *bio; | 49 | struct bio *bio; |
| 58 | int ret = 0; | 50 | int ret = 0; |
| 59 | u64 io_size; | 51 | u64 io_size; |
| @@ -73,8 +65,6 @@ int hfsplus_submit_bio(struct super_block *sb, sector_t sector, | |||
| 73 | bio = bio_alloc(GFP_NOIO, 1); | 65 | bio = bio_alloc(GFP_NOIO, 1); |
| 74 | bio->bi_sector = sector; | 66 | bio->bi_sector = sector; |
| 75 | bio->bi_bdev = sb->s_bdev; | 67 | bio->bi_bdev = sb->s_bdev; |
| 76 | bio->bi_end_io = hfsplus_end_io_sync; | ||
| 77 | bio->bi_private = &wait; | ||
| 78 | 68 | ||
| 79 | if (!(rw & WRITE) && data) | 69 | if (!(rw & WRITE) && data) |
| 80 | *data = (u8 *)buf + offset; | 70 | *data = (u8 *)buf + offset; |
| @@ -93,12 +83,7 @@ int hfsplus_submit_bio(struct super_block *sb, sector_t sector, | |||
| 93 | buf = (u8 *)buf + len; | 83 | buf = (u8 *)buf + len; |
| 94 | } | 84 | } |
| 95 | 85 | ||
| 96 | submit_bio(rw, bio); | 86 | ret = submit_bio_wait(rw, bio); |
| 97 | wait_for_completion(&wait); | ||
| 98 | |||
| 99 | if (!bio_flagged(bio, BIO_UPTODATE)) | ||
| 100 | ret = -EIO; | ||
| 101 | |||
| 102 | out: | 87 | out: |
| 103 | bio_put(bio); | 88 | bio_put(bio); |
| 104 | return ret < 0 ? ret : 0; | 89 | return ret < 0 ? ret : 0; |
diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index 550475ca6a0e..0f95f0d0b313 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c | |||
| @@ -14,16 +14,10 @@ | |||
| 14 | 14 | ||
| 15 | #define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1)) | 15 | #define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1)) |
| 16 | 16 | ||
| 17 | static void request_complete(struct bio *bio, int err) | ||
| 18 | { | ||
| 19 | complete((struct completion *)bio->bi_private); | ||
| 20 | } | ||
| 21 | |||
| 22 | static int sync_request(struct page *page, struct block_device *bdev, int rw) | 17 | static int sync_request(struct page *page, struct block_device *bdev, int rw) |
| 23 | { | 18 | { |
| 24 | struct bio bio; | 19 | struct bio bio; |
| 25 | struct bio_vec bio_vec; | 20 | struct bio_vec bio_vec; |
| 26 | struct completion complete; | ||
| 27 | 21 | ||
| 28 | bio_init(&bio); | 22 | bio_init(&bio); |
| 29 | bio.bi_max_vecs = 1; | 23 | bio.bi_max_vecs = 1; |
| @@ -35,13 +29,8 @@ static int sync_request(struct page *page, struct block_device *bdev, int rw) | |||
| 35 | bio.bi_size = PAGE_SIZE; | 29 | bio.bi_size = PAGE_SIZE; |
| 36 | bio.bi_bdev = bdev; | 30 | bio.bi_bdev = bdev; |
| 37 | bio.bi_sector = page->index * (PAGE_SIZE >> 9); | 31 | bio.bi_sector = page->index * (PAGE_SIZE >> 9); |
| 38 | init_completion(&complete); | ||
| 39 | bio.bi_private = &complete; | ||
| 40 | bio.bi_end_io = request_complete; | ||
| 41 | 32 | ||
| 42 | submit_bio(rw, &bio); | 33 | return submit_bio_wait(rw, &bio); |
| 43 | wait_for_completion(&complete); | ||
| 44 | return test_bit(BIO_UPTODATE, &bio.bi_flags) ? 0 : -EIO; | ||
| 45 | } | 34 | } |
| 46 | 35 | ||
| 47 | static int bdev_readpage(void *_sb, struct page *page) | 36 | static int bdev_readpage(void *_sb, struct page *page) |
diff --git a/fs/namei.c b/fs/namei.c index 8f77a8cea289..c53d3a9547f9 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -513,8 +513,7 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry) | |||
| 513 | 513 | ||
| 514 | if (!lockref_get_not_dead(&parent->d_lockref)) { | 514 | if (!lockref_get_not_dead(&parent->d_lockref)) { |
| 515 | nd->path.dentry = NULL; | 515 | nd->path.dentry = NULL; |
| 516 | rcu_read_unlock(); | 516 | goto out; |
| 517 | return -ECHILD; | ||
| 518 | } | 517 | } |
| 519 | 518 | ||
| 520 | /* | 519 | /* |
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h index 8485978993e8..9838fb020473 100644 --- a/fs/nfs/blocklayout/blocklayout.h +++ b/fs/nfs/blocklayout/blocklayout.h | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/nfs_fs.h> | 36 | #include <linux/nfs_fs.h> |
| 37 | #include <linux/sunrpc/rpc_pipe_fs.h> | 37 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| 38 | 38 | ||
| 39 | #include "../nfs4_fs.h" | ||
| 39 | #include "../pnfs.h" | 40 | #include "../pnfs.h" |
| 40 | #include "../netns.h" | 41 | #include "../netns.h" |
| 41 | 42 | ||
diff --git a/fs/nfs/blocklayout/extents.c b/fs/nfs/blocklayout/extents.c index 9c3e117c3ed1..4d0161442565 100644 --- a/fs/nfs/blocklayout/extents.c +++ b/fs/nfs/blocklayout/extents.c | |||
| @@ -44,7 +44,7 @@ | |||
| 44 | static inline sector_t normalize(sector_t s, int base) | 44 | static inline sector_t normalize(sector_t s, int base) |
| 45 | { | 45 | { |
| 46 | sector_t tmp = s; /* Since do_div modifies its argument */ | 46 | sector_t tmp = s; /* Since do_div modifies its argument */ |
| 47 | return s - do_div(tmp, base); | 47 | return s - sector_div(tmp, base); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | static inline sector_t normalize_up(sector_t s, int base) | 50 | static inline sector_t normalize_up(sector_t s, int base) |
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index fc0f95ec7358..d25f10fb4926 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c | |||
| @@ -46,7 +46,9 @@ ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen, | |||
| 46 | #include <linux/sunrpc/cache.h> | 46 | #include <linux/sunrpc/cache.h> |
| 47 | #include <linux/sunrpc/svcauth.h> | 47 | #include <linux/sunrpc/svcauth.h> |
| 48 | #include <linux/sunrpc/rpc_pipe_fs.h> | 48 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| 49 | #include <linux/nfs_fs.h> | ||
| 49 | 50 | ||
| 51 | #include "nfs4_fs.h" | ||
| 50 | #include "dns_resolve.h" | 52 | #include "dns_resolve.h" |
| 51 | #include "cache_lib.h" | 53 | #include "cache_lib.h" |
| 52 | #include "netns.h" | 54 | #include "netns.h" |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 18ab2da4eeb6..00ad1c2b217d 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -312,7 +312,7 @@ struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) | |||
| 312 | } | 312 | } |
| 313 | EXPORT_SYMBOL_GPL(nfs4_label_alloc); | 313 | EXPORT_SYMBOL_GPL(nfs4_label_alloc); |
| 314 | #else | 314 | #else |
| 315 | void inline nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, | 315 | void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, |
| 316 | struct nfs4_label *label) | 316 | struct nfs4_label *label) |
| 317 | { | 317 | { |
| 318 | } | 318 | } |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index bca6a3e3c49c..8b5cc04a8611 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -269,6 +269,21 @@ extern const u32 nfs41_maxgetdevinfo_overhead; | |||
| 269 | extern struct rpc_procinfo nfs4_procedures[]; | 269 | extern struct rpc_procinfo nfs4_procedures[]; |
| 270 | #endif | 270 | #endif |
| 271 | 271 | ||
| 272 | #ifdef CONFIG_NFS_V4_SECURITY_LABEL | ||
| 273 | extern struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags); | ||
| 274 | static inline void nfs4_label_free(struct nfs4_label *label) | ||
| 275 | { | ||
| 276 | if (label) { | ||
| 277 | kfree(label->label); | ||
| 278 | kfree(label); | ||
| 279 | } | ||
| 280 | return; | ||
| 281 | } | ||
| 282 | #else | ||
| 283 | static inline struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) { return NULL; } | ||
| 284 | static inline void nfs4_label_free(void *label) {} | ||
| 285 | #endif /* CONFIG_NFS_V4_SECURITY_LABEL */ | ||
| 286 | |||
| 272 | /* proc.c */ | 287 | /* proc.c */ |
| 273 | void nfs_close_context(struct nfs_open_context *ctx, int is_sync); | 288 | void nfs_close_context(struct nfs_open_context *ctx, int is_sync); |
| 274 | extern struct nfs_client *nfs_init_client(struct nfs_client *clp, | 289 | extern struct nfs_client *nfs_init_client(struct nfs_client *clp, |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 3ce79b04522e..5609edc742a0 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -9,6 +9,14 @@ | |||
| 9 | #ifndef __LINUX_FS_NFS_NFS4_FS_H | 9 | #ifndef __LINUX_FS_NFS_NFS4_FS_H |
| 10 | #define __LINUX_FS_NFS_NFS4_FS_H | 10 | #define __LINUX_FS_NFS_NFS4_FS_H |
| 11 | 11 | ||
| 12 | #if defined(CONFIG_NFS_V4_2) | ||
| 13 | #define NFS4_MAX_MINOR_VERSION 2 | ||
| 14 | #elif defined(CONFIG_NFS_V4_1) | ||
| 15 | #define NFS4_MAX_MINOR_VERSION 1 | ||
| 16 | #else | ||
| 17 | #define NFS4_MAX_MINOR_VERSION 0 | ||
| 18 | #endif | ||
| 19 | |||
| 12 | #if IS_ENABLED(CONFIG_NFS_V4) | 20 | #if IS_ENABLED(CONFIG_NFS_V4) |
| 13 | 21 | ||
| 14 | #define NFS4_MAX_LOOP_ON_RECOVER (10) | 22 | #define NFS4_MAX_LOOP_ON_RECOVER (10) |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 659990c0109e..15052b81df42 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -2518,9 +2518,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
| 2518 | calldata->roc_barrier); | 2518 | calldata->roc_barrier); |
| 2519 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); | 2519 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); |
| 2520 | renew_lease(server, calldata->timestamp); | 2520 | renew_lease(server, calldata->timestamp); |
| 2521 | nfs4_close_clear_stateid_flags(state, | ||
| 2522 | calldata->arg.fmode); | ||
| 2523 | break; | 2521 | break; |
| 2522 | case -NFS4ERR_ADMIN_REVOKED: | ||
| 2524 | case -NFS4ERR_STALE_STATEID: | 2523 | case -NFS4ERR_STALE_STATEID: |
| 2525 | case -NFS4ERR_OLD_STATEID: | 2524 | case -NFS4ERR_OLD_STATEID: |
| 2526 | case -NFS4ERR_BAD_STATEID: | 2525 | case -NFS4ERR_BAD_STATEID: |
| @@ -2528,9 +2527,13 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
| 2528 | if (calldata->arg.fmode == 0) | 2527 | if (calldata->arg.fmode == 0) |
| 2529 | break; | 2528 | break; |
| 2530 | default: | 2529 | default: |
| 2531 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) | 2530 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { |
| 2532 | rpc_restart_call_prepare(task); | 2531 | rpc_restart_call_prepare(task); |
| 2532 | goto out_release; | ||
| 2533 | } | ||
| 2533 | } | 2534 | } |
| 2535 | nfs4_close_clear_stateid_flags(state, calldata->arg.fmode); | ||
| 2536 | out_release: | ||
| 2534 | nfs_release_seqid(calldata->arg.seqid); | 2537 | nfs_release_seqid(calldata->arg.seqid); |
| 2535 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 2538 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
| 2536 | dprintk("%s: done, ret = %d!\n", __func__, task->tk_status); | 2539 | dprintk("%s: done, ret = %d!\n", __func__, task->tk_status); |
| @@ -4802,7 +4805,7 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
| 4802 | dprintk("%s ERROR %d, Reset session\n", __func__, | 4805 | dprintk("%s ERROR %d, Reset session\n", __func__, |
| 4803 | task->tk_status); | 4806 | task->tk_status); |
| 4804 | nfs4_schedule_session_recovery(clp->cl_session, task->tk_status); | 4807 | nfs4_schedule_session_recovery(clp->cl_session, task->tk_status); |
| 4805 | goto restart_call; | 4808 | goto wait_on_recovery; |
| 4806 | #endif /* CONFIG_NFS_V4_1 */ | 4809 | #endif /* CONFIG_NFS_V4_1 */ |
| 4807 | case -NFS4ERR_DELAY: | 4810 | case -NFS4ERR_DELAY: |
| 4808 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 4811 | nfs_inc_server_stats(server, NFSIOS_DELAY); |
| @@ -4987,11 +4990,17 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
| 4987 | 4990 | ||
| 4988 | trace_nfs4_delegreturn_exit(&data->args, &data->res, task->tk_status); | 4991 | trace_nfs4_delegreturn_exit(&data->args, &data->res, task->tk_status); |
| 4989 | switch (task->tk_status) { | 4992 | switch (task->tk_status) { |
| 4990 | case -NFS4ERR_STALE_STATEID: | ||
| 4991 | case -NFS4ERR_EXPIRED: | ||
| 4992 | case 0: | 4993 | case 0: |
| 4993 | renew_lease(data->res.server, data->timestamp); | 4994 | renew_lease(data->res.server, data->timestamp); |
| 4994 | break; | 4995 | break; |
| 4996 | case -NFS4ERR_ADMIN_REVOKED: | ||
| 4997 | case -NFS4ERR_DELEG_REVOKED: | ||
| 4998 | case -NFS4ERR_BAD_STATEID: | ||
| 4999 | case -NFS4ERR_OLD_STATEID: | ||
| 5000 | case -NFS4ERR_STALE_STATEID: | ||
| 5001 | case -NFS4ERR_EXPIRED: | ||
| 5002 | task->tk_status = 0; | ||
| 5003 | break; | ||
| 4995 | default: | 5004 | default: |
| 4996 | if (nfs4_async_handle_error(task, data->res.server, NULL) == | 5005 | if (nfs4_async_handle_error(task, data->res.server, NULL) == |
| 4997 | -EAGAIN) { | 5006 | -EAGAIN) { |
| @@ -7589,7 +7598,14 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) | |||
| 7589 | return; | 7598 | return; |
| 7590 | 7599 | ||
| 7591 | server = NFS_SERVER(lrp->args.inode); | 7600 | server = NFS_SERVER(lrp->args.inode); |
| 7592 | if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) { | 7601 | switch (task->tk_status) { |
| 7602 | default: | ||
| 7603 | task->tk_status = 0; | ||
| 7604 | case 0: | ||
| 7605 | break; | ||
| 7606 | case -NFS4ERR_DELAY: | ||
| 7607 | if (nfs4_async_handle_error(task, server, NULL) != -EAGAIN) | ||
| 7608 | break; | ||
| 7593 | rpc_restart_call_prepare(task); | 7609 | rpc_restart_call_prepare(task); |
| 7594 | return; | 7610 | return; |
| 7595 | } | 7611 | } |
| @@ -726,11 +726,25 @@ pipe_poll(struct file *filp, poll_table *wait) | |||
| 726 | return mask; | 726 | return mask; |
| 727 | } | 727 | } |
| 728 | 728 | ||
| 729 | static void put_pipe_info(struct inode *inode, struct pipe_inode_info *pipe) | ||
| 730 | { | ||
| 731 | int kill = 0; | ||
| 732 | |||
| 733 | spin_lock(&inode->i_lock); | ||
| 734 | if (!--pipe->files) { | ||
| 735 | inode->i_pipe = NULL; | ||
| 736 | kill = 1; | ||
| 737 | } | ||
| 738 | spin_unlock(&inode->i_lock); | ||
| 739 | |||
| 740 | if (kill) | ||
| 741 | free_pipe_info(pipe); | ||
| 742 | } | ||
| 743 | |||
| 729 | static int | 744 | static int |
| 730 | pipe_release(struct inode *inode, struct file *file) | 745 | pipe_release(struct inode *inode, struct file *file) |
| 731 | { | 746 | { |
| 732 | struct pipe_inode_info *pipe = inode->i_pipe; | 747 | struct pipe_inode_info *pipe = file->private_data; |
| 733 | int kill = 0; | ||
| 734 | 748 | ||
| 735 | __pipe_lock(pipe); | 749 | __pipe_lock(pipe); |
| 736 | if (file->f_mode & FMODE_READ) | 750 | if (file->f_mode & FMODE_READ) |
| @@ -743,17 +757,9 @@ pipe_release(struct inode *inode, struct file *file) | |||
| 743 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); | 757 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); |
| 744 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); | 758 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); |
| 745 | } | 759 | } |
| 746 | spin_lock(&inode->i_lock); | ||
| 747 | if (!--pipe->files) { | ||
| 748 | inode->i_pipe = NULL; | ||
| 749 | kill = 1; | ||
| 750 | } | ||
| 751 | spin_unlock(&inode->i_lock); | ||
| 752 | __pipe_unlock(pipe); | 760 | __pipe_unlock(pipe); |
| 753 | 761 | ||
| 754 | if (kill) | 762 | put_pipe_info(inode, pipe); |
| 755 | free_pipe_info(pipe); | ||
| 756 | |||
| 757 | return 0; | 763 | return 0; |
| 758 | } | 764 | } |
| 759 | 765 | ||
| @@ -1014,7 +1020,6 @@ static int fifo_open(struct inode *inode, struct file *filp) | |||
| 1014 | { | 1020 | { |
| 1015 | struct pipe_inode_info *pipe; | 1021 | struct pipe_inode_info *pipe; |
| 1016 | bool is_pipe = inode->i_sb->s_magic == PIPEFS_MAGIC; | 1022 | bool is_pipe = inode->i_sb->s_magic == PIPEFS_MAGIC; |
| 1017 | int kill = 0; | ||
| 1018 | int ret; | 1023 | int ret; |
| 1019 | 1024 | ||
| 1020 | filp->f_version = 0; | 1025 | filp->f_version = 0; |
| @@ -1130,15 +1135,9 @@ err_wr: | |||
| 1130 | goto err; | 1135 | goto err; |
| 1131 | 1136 | ||
| 1132 | err: | 1137 | err: |
| 1133 | spin_lock(&inode->i_lock); | ||
| 1134 | if (!--pipe->files) { | ||
| 1135 | inode->i_pipe = NULL; | ||
| 1136 | kill = 1; | ||
| 1137 | } | ||
| 1138 | spin_unlock(&inode->i_lock); | ||
| 1139 | __pipe_unlock(pipe); | 1138 | __pipe_unlock(pipe); |
| 1140 | if (kill) | 1139 | |
| 1141 | free_pipe_info(pipe); | 1140 | put_pipe_info(inode, pipe); |
| 1142 | return ret; | 1141 | return ret; |
| 1143 | } | 1142 | } |
| 1144 | 1143 | ||
diff --git a/fs/squashfs/file_direct.c b/fs/squashfs/file_direct.c index 2943b2bfae48..62a0de6632e1 100644 --- a/fs/squashfs/file_direct.c +++ b/fs/squashfs/file_direct.c | |||
| @@ -84,6 +84,9 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize) | |||
| 84 | */ | 84 | */ |
| 85 | res = squashfs_read_cache(target_page, block, bsize, pages, | 85 | res = squashfs_read_cache(target_page, block, bsize, pages, |
| 86 | page); | 86 | page); |
| 87 | if (res < 0) | ||
| 88 | goto mark_errored; | ||
| 89 | |||
| 87 | goto out; | 90 | goto out; |
| 88 | } | 91 | } |
| 89 | 92 | ||
| @@ -119,7 +122,7 @@ mark_errored: | |||
| 119 | * dealt with by the caller | 122 | * dealt with by the caller |
| 120 | */ | 123 | */ |
| 121 | for (i = 0; i < pages; i++) { | 124 | for (i = 0; i < pages; i++) { |
| 122 | if (page[i] == target_page) | 125 | if (page[i] == NULL || page[i] == target_page) |
| 123 | continue; | 126 | continue; |
| 124 | flush_dcache_page(page[i]); | 127 | flush_dcache_page(page[i]); |
| 125 | SetPageError(page[i]); | 128 | SetPageError(page[i]); |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 79b5da2acbe1..b94f93685093 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
| @@ -609,7 +609,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
| 609 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; | 609 | struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; |
| 610 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 610 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; |
| 611 | struct sysfs_open_file *of; | 611 | struct sysfs_open_file *of; |
| 612 | bool has_read, has_write; | 612 | bool has_read, has_write, has_mmap; |
| 613 | int error = -EACCES; | 613 | int error = -EACCES; |
| 614 | 614 | ||
| 615 | /* need attr_sd for attr and ops, its parent for kobj */ | 615 | /* need attr_sd for attr and ops, its parent for kobj */ |
| @@ -621,6 +621,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
| 621 | 621 | ||
| 622 | has_read = battr->read || battr->mmap; | 622 | has_read = battr->read || battr->mmap; |
| 623 | has_write = battr->write || battr->mmap; | 623 | has_write = battr->write || battr->mmap; |
| 624 | has_mmap = battr->mmap; | ||
| 624 | } else { | 625 | } else { |
| 625 | const struct sysfs_ops *ops = sysfs_file_ops(attr_sd); | 626 | const struct sysfs_ops *ops = sysfs_file_ops(attr_sd); |
| 626 | 627 | ||
| @@ -632,6 +633,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
| 632 | 633 | ||
| 633 | has_read = ops->show; | 634 | has_read = ops->show; |
| 634 | has_write = ops->store; | 635 | has_write = ops->store; |
| 636 | has_mmap = false; | ||
| 635 | } | 637 | } |
| 636 | 638 | ||
| 637 | /* check perms and supported operations */ | 639 | /* check perms and supported operations */ |
| @@ -649,7 +651,23 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
| 649 | if (!of) | 651 | if (!of) |
| 650 | goto err_out; | 652 | goto err_out; |
| 651 | 653 | ||
| 652 | mutex_init(&of->mutex); | 654 | /* |
| 655 | * The following is done to give a different lockdep key to | ||
| 656 | * @of->mutex for files which implement mmap. This is a rather | ||
| 657 | * crude way to avoid false positive lockdep warning around | ||
| 658 | * mm->mmap_sem - mmap nests @of->mutex under mm->mmap_sem and | ||
| 659 | * reading /sys/block/sda/trace/act_mask grabs sr_mutex, under | ||
| 660 | * which mm->mmap_sem nests, while holding @of->mutex. As each | ||
| 661 | * open file has a separate mutex, it's okay as long as those don't | ||
| 662 | * happen on the same file. At this point, we can't easily give | ||
| 663 | * each file a separate locking class. Let's differentiate on | ||
| 664 | * whether the file has mmap or not for now. | ||
| 665 | */ | ||
| 666 | if (has_mmap) | ||
| 667 | mutex_init(&of->mutex); | ||
| 668 | else | ||
| 669 | mutex_init(&of->mutex); | ||
| 670 | |||
| 653 | of->sd = attr_sd; | 671 | of->sd = attr_sd; |
| 654 | of->file = file; | 672 | of->file = file; |
| 655 | 673 | ||
