diff options
| author | Ross Zwisler <ross.zwisler@linux.intel.com> | 2018-02-03 02:26:10 -0500 |
|---|---|---|
| committer | Ross Zwisler <ross.zwisler@linux.intel.com> | 2018-02-03 02:26:10 -0500 |
| commit | d121f07691415df824e6b60520f782f6d13b3c81 (patch) | |
| tree | 422ad3cc6fd631604fef4e469e49bacba8202e52 /fs | |
| parent | 59858d3d54cfad1f8db67c2c07e4dd33bb6ed955 (diff) | |
| parent | 569d0365f571fa6421a5c80bc30d1b2cdab857fe (diff) | |
Merge branch 'for-4.16/dax' into libnvdimm-for-next
Diffstat (limited to 'fs')
63 files changed, 541 insertions, 260 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 7aee6d699fd6..b40128bf6d1a 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
| @@ -58,6 +58,13 @@ config FS_DAX_PMD | |||
| 58 | depends on ZONE_DEVICE | 58 | depends on ZONE_DEVICE |
| 59 | depends on TRANSPARENT_HUGEPAGE | 59 | depends on TRANSPARENT_HUGEPAGE |
| 60 | 60 | ||
| 61 | # Selected by DAX drivers that do not expect filesystem DAX to support | ||
| 62 | # get_user_pages() of DAX mappings. I.e. "limited" indicates no support | ||
| 63 | # for fork() of processes with MAP_SHARED mappings or support for | ||
| 64 | # direct-I/O to a DAX mapping. | ||
| 65 | config FS_DAX_LIMITED | ||
| 66 | bool | ||
| 67 | |||
| 61 | endif # BLOCK | 68 | endif # BLOCK |
| 62 | 69 | ||
| 63 | # Posix ACL utility routines | 70 | # Posix ACL utility routines |
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 8fc41705c7cd..961a12dc6dc8 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
| @@ -170,7 +170,6 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, | |||
| 170 | 170 | ||
| 171 | mutex_unlock(&sbi->wq_mutex); | 171 | mutex_unlock(&sbi->wq_mutex); |
| 172 | 172 | ||
| 173 | if (autofs4_write(sbi, pipe, &pkt, pktsz)) | ||
| 174 | switch (ret = autofs4_write(sbi, pipe, &pkt, pktsz)) { | 173 | switch (ret = autofs4_write(sbi, pipe, &pkt, pktsz)) { |
| 175 | case 0: | 174 | case 0: |
| 176 | break; | 175 | break; |
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 531e0a8645b0..1e74cf826532 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
| @@ -1032,14 +1032,17 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, | |||
| 1032 | root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) && | 1032 | root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) && |
| 1033 | !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) { | 1033 | !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) { |
| 1034 | ret = btrfs_inc_ref(trans, root, buf, 1); | 1034 | ret = btrfs_inc_ref(trans, root, buf, 1); |
| 1035 | BUG_ON(ret); /* -ENOMEM */ | 1035 | if (ret) |
| 1036 | return ret; | ||
| 1036 | 1037 | ||
| 1037 | if (root->root_key.objectid == | 1038 | if (root->root_key.objectid == |
| 1038 | BTRFS_TREE_RELOC_OBJECTID) { | 1039 | BTRFS_TREE_RELOC_OBJECTID) { |
| 1039 | ret = btrfs_dec_ref(trans, root, buf, 0); | 1040 | ret = btrfs_dec_ref(trans, root, buf, 0); |
| 1040 | BUG_ON(ret); /* -ENOMEM */ | 1041 | if (ret) |
| 1042 | return ret; | ||
| 1041 | ret = btrfs_inc_ref(trans, root, cow, 1); | 1043 | ret = btrfs_inc_ref(trans, root, cow, 1); |
| 1042 | BUG_ON(ret); /* -ENOMEM */ | 1044 | if (ret) |
| 1045 | return ret; | ||
| 1043 | } | 1046 | } |
| 1044 | new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF; | 1047 | new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF; |
| 1045 | } else { | 1048 | } else { |
| @@ -1049,7 +1052,8 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, | |||
| 1049 | ret = btrfs_inc_ref(trans, root, cow, 1); | 1052 | ret = btrfs_inc_ref(trans, root, cow, 1); |
| 1050 | else | 1053 | else |
| 1051 | ret = btrfs_inc_ref(trans, root, cow, 0); | 1054 | ret = btrfs_inc_ref(trans, root, cow, 0); |
| 1052 | BUG_ON(ret); /* -ENOMEM */ | 1055 | if (ret) |
| 1056 | return ret; | ||
| 1053 | } | 1057 | } |
| 1054 | if (new_flags != 0) { | 1058 | if (new_flags != 0) { |
| 1055 | int level = btrfs_header_level(buf); | 1059 | int level = btrfs_header_level(buf); |
| @@ -1068,9 +1072,11 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, | |||
| 1068 | ret = btrfs_inc_ref(trans, root, cow, 1); | 1072 | ret = btrfs_inc_ref(trans, root, cow, 1); |
| 1069 | else | 1073 | else |
| 1070 | ret = btrfs_inc_ref(trans, root, cow, 0); | 1074 | ret = btrfs_inc_ref(trans, root, cow, 0); |
| 1071 | BUG_ON(ret); /* -ENOMEM */ | 1075 | if (ret) |
| 1076 | return ret; | ||
| 1072 | ret = btrfs_dec_ref(trans, root, buf, 1); | 1077 | ret = btrfs_dec_ref(trans, root, buf, 1); |
| 1073 | BUG_ON(ret); /* -ENOMEM */ | 1078 | if (ret) |
| 1079 | return ret; | ||
| 1074 | } | 1080 | } |
| 1075 | clean_tree_block(fs_info, buf); | 1081 | clean_tree_block(fs_info, buf); |
| 1076 | *last_ref = 1; | 1082 | *last_ref = 1; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 10a2a579cc7f..a8ecccfc36de 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -3231,6 +3231,7 @@ static int write_dev_supers(struct btrfs_device *device, | |||
| 3231 | int errors = 0; | 3231 | int errors = 0; |
| 3232 | u32 crc; | 3232 | u32 crc; |
| 3233 | u64 bytenr; | 3233 | u64 bytenr; |
| 3234 | int op_flags; | ||
| 3234 | 3235 | ||
| 3235 | if (max_mirrors == 0) | 3236 | if (max_mirrors == 0) |
| 3236 | max_mirrors = BTRFS_SUPER_MIRROR_MAX; | 3237 | max_mirrors = BTRFS_SUPER_MIRROR_MAX; |
| @@ -3273,13 +3274,10 @@ static int write_dev_supers(struct btrfs_device *device, | |||
| 3273 | * we fua the first super. The others we allow | 3274 | * we fua the first super. The others we allow |
| 3274 | * to go down lazy. | 3275 | * to go down lazy. |
| 3275 | */ | 3276 | */ |
| 3276 | if (i == 0) { | 3277 | op_flags = REQ_SYNC | REQ_META | REQ_PRIO; |
| 3277 | ret = btrfsic_submit_bh(REQ_OP_WRITE, | 3278 | if (i == 0 && !btrfs_test_opt(device->fs_info, NOBARRIER)) |
| 3278 | REQ_SYNC | REQ_FUA | REQ_META | REQ_PRIO, bh); | 3279 | op_flags |= REQ_FUA; |
| 3279 | } else { | 3280 | ret = btrfsic_submit_bh(REQ_OP_WRITE, op_flags, bh); |
| 3280 | ret = btrfsic_submit_bh(REQ_OP_WRITE, | ||
| 3281 | REQ_SYNC | REQ_META | REQ_PRIO, bh); | ||
| 3282 | } | ||
| 3283 | if (ret) | 3281 | if (ret) |
| 3284 | errors++; | 3282 | errors++; |
| 3285 | } | 3283 | } |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 4497f937e8fb..2f4328511ac8 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -9206,6 +9206,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
| 9206 | ret = btrfs_del_root(trans, fs_info, &root->root_key); | 9206 | ret = btrfs_del_root(trans, fs_info, &root->root_key); |
| 9207 | if (ret) { | 9207 | if (ret) { |
| 9208 | btrfs_abort_transaction(trans, ret); | 9208 | btrfs_abort_transaction(trans, ret); |
| 9209 | err = ret; | ||
| 9209 | goto out_end_trans; | 9210 | goto out_end_trans; |
| 9210 | } | 9211 | } |
| 9211 | 9212 | ||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 993061f83067..e1a7f3cb5be9 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -3005,6 +3005,8 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) | |||
| 3005 | compress_type = ordered_extent->compress_type; | 3005 | compress_type = ordered_extent->compress_type; |
| 3006 | if (test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) { | 3006 | if (test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) { |
| 3007 | BUG_ON(compress_type); | 3007 | BUG_ON(compress_type); |
| 3008 | btrfs_qgroup_free_data(inode, NULL, ordered_extent->file_offset, | ||
| 3009 | ordered_extent->len); | ||
| 3008 | ret = btrfs_mark_extent_written(trans, BTRFS_I(inode), | 3010 | ret = btrfs_mark_extent_written(trans, BTRFS_I(inode), |
| 3009 | ordered_extent->file_offset, | 3011 | ordered_extent->file_offset, |
| 3010 | ordered_extent->file_offset + | 3012 | ordered_extent->file_offset + |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index d748ad1c3620..2ef8acaac688 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -2206,7 +2206,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, | |||
| 2206 | if (!path) | 2206 | if (!path) |
| 2207 | return -ENOMEM; | 2207 | return -ENOMEM; |
| 2208 | 2208 | ||
| 2209 | ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX]; | 2209 | ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX - 1]; |
| 2210 | 2210 | ||
| 2211 | key.objectid = tree_id; | 2211 | key.objectid = tree_id; |
| 2212 | key.type = BTRFS_ROOT_ITEM_KEY; | 2212 | key.type = BTRFS_ROOT_ITEM_KEY; |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index ab69dcb70e8a..1b468250e947 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
| @@ -1440,6 +1440,29 @@ static int __close_session(struct ceph_mds_client *mdsc, | |||
| 1440 | return request_close_session(mdsc, session); | 1440 | return request_close_session(mdsc, session); |
| 1441 | } | 1441 | } |
| 1442 | 1442 | ||
| 1443 | static bool drop_negative_children(struct dentry *dentry) | ||
| 1444 | { | ||
| 1445 | struct dentry *child; | ||
| 1446 | bool all_negative = true; | ||
| 1447 | |||
| 1448 | if (!d_is_dir(dentry)) | ||
| 1449 | goto out; | ||
| 1450 | |||
| 1451 | spin_lock(&dentry->d_lock); | ||
| 1452 | list_for_each_entry(child, &dentry->d_subdirs, d_child) { | ||
| 1453 | if (d_really_is_positive(child)) { | ||
| 1454 | all_negative = false; | ||
| 1455 | break; | ||
| 1456 | } | ||
| 1457 | } | ||
| 1458 | spin_unlock(&dentry->d_lock); | ||
| 1459 | |||
| 1460 | if (all_negative) | ||
| 1461 | shrink_dcache_parent(dentry); | ||
| 1462 | out: | ||
| 1463 | return all_negative; | ||
| 1464 | } | ||
| 1465 | |||
| 1443 | /* | 1466 | /* |
| 1444 | * Trim old(er) caps. | 1467 | * Trim old(er) caps. |
| 1445 | * | 1468 | * |
| @@ -1490,16 +1513,27 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg) | |||
| 1490 | if ((used | wanted) & ~oissued & mine) | 1513 | if ((used | wanted) & ~oissued & mine) |
| 1491 | goto out; /* we need these caps */ | 1514 | goto out; /* we need these caps */ |
| 1492 | 1515 | ||
| 1493 | session->s_trim_caps--; | ||
| 1494 | if (oissued) { | 1516 | if (oissued) { |
| 1495 | /* we aren't the only cap.. just remove us */ | 1517 | /* we aren't the only cap.. just remove us */ |
| 1496 | __ceph_remove_cap(cap, true); | 1518 | __ceph_remove_cap(cap, true); |
| 1519 | session->s_trim_caps--; | ||
| 1497 | } else { | 1520 | } else { |
| 1521 | struct dentry *dentry; | ||
| 1498 | /* try dropping referring dentries */ | 1522 | /* try dropping referring dentries */ |
| 1499 | spin_unlock(&ci->i_ceph_lock); | 1523 | spin_unlock(&ci->i_ceph_lock); |
| 1500 | d_prune_aliases(inode); | 1524 | dentry = d_find_any_alias(inode); |
| 1501 | dout("trim_caps_cb %p cap %p pruned, count now %d\n", | 1525 | if (dentry && drop_negative_children(dentry)) { |
| 1502 | inode, cap, atomic_read(&inode->i_count)); | 1526 | int count; |
| 1527 | dput(dentry); | ||
| 1528 | d_prune_aliases(inode); | ||
| 1529 | count = atomic_read(&inode->i_count); | ||
| 1530 | if (count == 1) | ||
| 1531 | session->s_trim_caps--; | ||
| 1532 | dout("trim_caps_cb %p cap %p pruned, count now %d\n", | ||
| 1533 | inode, cap, count); | ||
| 1534 | } else { | ||
| 1535 | dput(dentry); | ||
| 1536 | } | ||
| 1503 | return 0; | 1537 | return 0; |
| 1504 | } | 1538 | } |
| 1505 | 1539 | ||
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index e06740436b92..ed88ab8a4774 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
| @@ -1406,7 +1406,8 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses, | |||
| 1406 | } while (rc == -EAGAIN); | 1406 | } while (rc == -EAGAIN); |
| 1407 | 1407 | ||
| 1408 | if (rc) { | 1408 | if (rc) { |
| 1409 | cifs_dbg(VFS, "ioctl error in smb2_get_dfs_refer rc=%d\n", rc); | 1409 | if (rc != -ENOENT) |
| 1410 | cifs_dbg(VFS, "ioctl error in smb2_get_dfs_refer rc=%d\n", rc); | ||
| 1410 | goto out; | 1411 | goto out; |
| 1411 | } | 1412 | } |
| 1412 | 1413 | ||
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 5331631386a2..01346b8b6edb 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
| @@ -2678,27 +2678,27 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, | |||
| 2678 | cifs_small_buf_release(req); | 2678 | cifs_small_buf_release(req); |
| 2679 | 2679 | ||
| 2680 | rsp = (struct smb2_read_rsp *)rsp_iov.iov_base; | 2680 | rsp = (struct smb2_read_rsp *)rsp_iov.iov_base; |
| 2681 | shdr = get_sync_hdr(rsp); | ||
| 2682 | 2681 | ||
| 2683 | if (shdr->Status == STATUS_END_OF_FILE) { | 2682 | if (rc) { |
| 2683 | if (rc != -ENODATA) { | ||
| 2684 | cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE); | ||
| 2685 | cifs_dbg(VFS, "Send error in read = %d\n", rc); | ||
| 2686 | } | ||
| 2684 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); | 2687 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
| 2685 | return 0; | 2688 | return rc == -ENODATA ? 0 : rc; |
| 2686 | } | 2689 | } |
| 2687 | 2690 | ||
| 2688 | if (rc) { | 2691 | *nbytes = le32_to_cpu(rsp->DataLength); |
| 2689 | cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE); | 2692 | if ((*nbytes > CIFS_MAX_MSGSIZE) || |
| 2690 | cifs_dbg(VFS, "Send error in read = %d\n", rc); | 2693 | (*nbytes > io_parms->length)) { |
| 2691 | } else { | 2694 | cifs_dbg(FYI, "bad length %d for count %d\n", |
| 2692 | *nbytes = le32_to_cpu(rsp->DataLength); | 2695 | *nbytes, io_parms->length); |
| 2693 | if ((*nbytes > CIFS_MAX_MSGSIZE) || | 2696 | rc = -EIO; |
| 2694 | (*nbytes > io_parms->length)) { | 2697 | *nbytes = 0; |
| 2695 | cifs_dbg(FYI, "bad length %d for count %d\n", | ||
| 2696 | *nbytes, io_parms->length); | ||
| 2697 | rc = -EIO; | ||
| 2698 | *nbytes = 0; | ||
| 2699 | } | ||
| 2700 | } | 2698 | } |
| 2701 | 2699 | ||
| 2700 | shdr = get_sync_hdr(rsp); | ||
| 2701 | |||
| 2702 | if (*buf) { | 2702 | if (*buf) { |
| 2703 | memcpy(*buf, (char *)shdr + rsp->DataOffset, *nbytes); | 2703 | memcpy(*buf, (char *)shdr + rsp->DataOffset, *nbytes); |
| 2704 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); | 2704 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
diff --git a/fs/cramfs/Kconfig b/fs/cramfs/Kconfig index f937082f3244..58e2fe40b2a0 100644 --- a/fs/cramfs/Kconfig +++ b/fs/cramfs/Kconfig | |||
| @@ -34,6 +34,7 @@ config CRAMFS_BLOCKDEV | |||
| 34 | config CRAMFS_MTD | 34 | config CRAMFS_MTD |
| 35 | bool "Support CramFs image directly mapped in physical memory" | 35 | bool "Support CramFs image directly mapped in physical memory" |
| 36 | depends on CRAMFS && MTD | 36 | depends on CRAMFS && MTD |
| 37 | depends on CRAMFS=m || MTD=y | ||
| 37 | default y if !CRAMFS_BLOCKDEV | 38 | default y if !CRAMFS_BLOCKDEV |
| 38 | help | 39 | help |
| 39 | This option allows the CramFs driver to load data directly from | 40 | This option allows the CramFs driver to load data directly from |
| @@ -627,8 +627,7 @@ static void dax_mapping_entry_mkclean(struct address_space *mapping, | |||
| 627 | 627 | ||
| 628 | if (pfn != pmd_pfn(*pmdp)) | 628 | if (pfn != pmd_pfn(*pmdp)) |
| 629 | goto unlock_pmd; | 629 | goto unlock_pmd; |
| 630 | if (!pmd_dirty(*pmdp) | 630 | if (!pmd_dirty(*pmdp) && !pmd_write(*pmdp)) |
| 631 | && !pmd_access_permitted(*pmdp, WRITE)) | ||
| 632 | goto unlock_pmd; | 631 | goto unlock_pmd; |
| 633 | 632 | ||
| 634 | flush_cache_page(vma, address, pfn); | 633 | flush_cache_page(vma, address, pfn); |
| @@ -1216,15 +1216,14 @@ killed: | |||
| 1216 | return -EAGAIN; | 1216 | return -EAGAIN; |
| 1217 | } | 1217 | } |
| 1218 | 1218 | ||
| 1219 | char *get_task_comm(char *buf, struct task_struct *tsk) | 1219 | char *__get_task_comm(char *buf, size_t buf_size, struct task_struct *tsk) |
| 1220 | { | 1220 | { |
| 1221 | /* buf must be at least sizeof(tsk->comm) in size */ | ||
| 1222 | task_lock(tsk); | 1221 | task_lock(tsk); |
| 1223 | strncpy(buf, tsk->comm, sizeof(tsk->comm)); | 1222 | strncpy(buf, tsk->comm, buf_size); |
| 1224 | task_unlock(tsk); | 1223 | task_unlock(tsk); |
| 1225 | return buf; | 1224 | return buf; |
| 1226 | } | 1225 | } |
| 1227 | EXPORT_SYMBOL_GPL(get_task_comm); | 1226 | EXPORT_SYMBOL_GPL(__get_task_comm); |
| 1228 | 1227 | ||
| 1229 | /* | 1228 | /* |
| 1230 | * These functions flushes out all traces of the currently running executable | 1229 | * These functions flushes out all traces of the currently running executable |
| @@ -1340,15 +1339,10 @@ void setup_new_exec(struct linux_binprm * bprm) | |||
| 1340 | * avoid bad behavior from the prior rlimits. This has to | 1339 | * avoid bad behavior from the prior rlimits. This has to |
| 1341 | * happen before arch_pick_mmap_layout(), which examines | 1340 | * happen before arch_pick_mmap_layout(), which examines |
| 1342 | * RLIMIT_STACK, but after the point of no return to avoid | 1341 | * RLIMIT_STACK, but after the point of no return to avoid |
| 1343 | * races from other threads changing the limits. This also | 1342 | * needing to clean up the change on failure. |
| 1344 | * must be protected from races with prlimit() calls. | ||
| 1345 | */ | 1343 | */ |
| 1346 | task_lock(current->group_leader); | ||
| 1347 | if (current->signal->rlim[RLIMIT_STACK].rlim_cur > _STK_LIM) | 1344 | if (current->signal->rlim[RLIMIT_STACK].rlim_cur > _STK_LIM) |
| 1348 | current->signal->rlim[RLIMIT_STACK].rlim_cur = _STK_LIM; | 1345 | current->signal->rlim[RLIMIT_STACK].rlim_cur = _STK_LIM; |
| 1349 | if (current->signal->rlim[RLIMIT_STACK].rlim_max > _STK_LIM) | ||
| 1350 | current->signal->rlim[RLIMIT_STACK].rlim_max = _STK_LIM; | ||
| 1351 | task_unlock(current->group_leader); | ||
| 1352 | } | 1346 | } |
| 1353 | 1347 | ||
| 1354 | arch_pick_mmap_layout(current->mm); | 1348 | arch_pick_mmap_layout(current->mm); |
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 7646818ab266..38f9222606ee 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
| @@ -959,8 +959,11 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) | |||
| 959 | 959 | ||
| 960 | if (sbi->s_mount_opt & EXT2_MOUNT_DAX) { | 960 | if (sbi->s_mount_opt & EXT2_MOUNT_DAX) { |
| 961 | err = bdev_dax_supported(sb, blocksize); | 961 | err = bdev_dax_supported(sb, blocksize); |
| 962 | if (err) | 962 | if (err) { |
| 963 | goto failed_mount; | 963 | ext2_msg(sb, KERN_ERR, |
| 964 | "DAX unsupported by block device. Turning off DAX."); | ||
| 965 | sbi->s_mount_opt &= ~EXT2_MOUNT_DAX; | ||
| 966 | } | ||
| 964 | } | 967 | } |
| 965 | 968 | ||
| 966 | /* If the blocksize doesn't match, re-read the thing.. */ | 969 | /* If the blocksize doesn't match, re-read the thing.. */ |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 07bca11749d4..c941251ac0c0 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
| @@ -4722,6 +4722,7 @@ retry: | |||
| 4722 | EXT4_INODE_EOFBLOCKS); | 4722 | EXT4_INODE_EOFBLOCKS); |
| 4723 | } | 4723 | } |
| 4724 | ext4_mark_inode_dirty(handle, inode); | 4724 | ext4_mark_inode_dirty(handle, inode); |
| 4725 | ext4_update_inode_fsync_trans(handle, inode, 1); | ||
| 4725 | ret2 = ext4_journal_stop(handle); | 4726 | ret2 = ext4_journal_stop(handle); |
| 4726 | if (ret2) | 4727 | if (ret2) |
| 4727 | break; | 4728 | break; |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index b4267d72f249..b32cf263750d 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
| @@ -816,6 +816,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, | |||
| 816 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | 816 | #ifdef CONFIG_EXT4_FS_POSIX_ACL |
| 817 | struct posix_acl *p = get_acl(dir, ACL_TYPE_DEFAULT); | 817 | struct posix_acl *p = get_acl(dir, ACL_TYPE_DEFAULT); |
| 818 | 818 | ||
| 819 | if (IS_ERR(p)) | ||
| 820 | return ERR_CAST(p); | ||
| 819 | if (p) { | 821 | if (p) { |
| 820 | int acl_size = p->a_count * sizeof(ext4_acl_entry); | 822 | int acl_size = p->a_count * sizeof(ext4_acl_entry); |
| 821 | 823 | ||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 7df2c5644e59..534a9130f625 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -149,6 +149,15 @@ static int ext4_meta_trans_blocks(struct inode *inode, int lblocks, | |||
| 149 | */ | 149 | */ |
| 150 | int ext4_inode_is_fast_symlink(struct inode *inode) | 150 | int ext4_inode_is_fast_symlink(struct inode *inode) |
| 151 | { | 151 | { |
| 152 | if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) { | ||
| 153 | int ea_blocks = EXT4_I(inode)->i_file_acl ? | ||
| 154 | EXT4_CLUSTER_SIZE(inode->i_sb) >> 9 : 0; | ||
| 155 | |||
| 156 | if (ext4_has_inline_data(inode)) | ||
| 157 | return 0; | ||
| 158 | |||
| 159 | return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0); | ||
| 160 | } | ||
| 152 | return S_ISLNK(inode->i_mode) && inode->i_size && | 161 | return S_ISLNK(inode->i_mode) && inode->i_size && |
| 153 | (inode->i_size < EXT4_N_BLOCKS * 4); | 162 | (inode->i_size < EXT4_N_BLOCKS * 4); |
| 154 | } | 163 | } |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 798b3ac680db..e750d68fbcb5 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
| @@ -1399,6 +1399,10 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, | |||
| 1399 | "falling back\n")); | 1399 | "falling back\n")); |
| 1400 | } | 1400 | } |
| 1401 | nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb); | 1401 | nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb); |
| 1402 | if (!nblocks) { | ||
| 1403 | ret = NULL; | ||
| 1404 | goto cleanup_and_exit; | ||
| 1405 | } | ||
| 1402 | start = EXT4_I(dir)->i_dir_start_lookup; | 1406 | start = EXT4_I(dir)->i_dir_start_lookup; |
| 1403 | if (start >= nblocks) | 1407 | if (start >= nblocks) |
| 1404 | start = 0; | 1408 | start = 0; |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 7c46693a14d7..18873ea89e08 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -3710,11 +3710,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
| 3710 | if (ext4_has_feature_inline_data(sb)) { | 3710 | if (ext4_has_feature_inline_data(sb)) { |
| 3711 | ext4_msg(sb, KERN_ERR, "Cannot use DAX on a filesystem" | 3711 | ext4_msg(sb, KERN_ERR, "Cannot use DAX on a filesystem" |
| 3712 | " that may contain inline data"); | 3712 | " that may contain inline data"); |
| 3713 | goto failed_mount; | 3713 | sbi->s_mount_opt &= ~EXT4_MOUNT_DAX; |
| 3714 | } | 3714 | } |
| 3715 | err = bdev_dax_supported(sb, blocksize); | 3715 | err = bdev_dax_supported(sb, blocksize); |
| 3716 | if (err) | 3716 | if (err) { |
| 3717 | goto failed_mount; | 3717 | ext4_msg(sb, KERN_ERR, |
| 3718 | "DAX unsupported by block device. Turning off DAX."); | ||
| 3719 | sbi->s_mount_opt &= ~EXT4_MOUNT_DAX; | ||
| 3720 | } | ||
| 3718 | } | 3721 | } |
| 3719 | 3722 | ||
| 3720 | if (ext4_has_feature_encrypt(sb) && es->s_encryption_level) { | 3723 | if (ext4_has_feature_encrypt(sb) && es->s_encryption_level) { |
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c index 8d6b7e35faf9..c83ece7facc5 100644 --- a/fs/hpfs/dir.c +++ b/fs/hpfs/dir.c | |||
| @@ -150,7 +150,6 @@ static int hpfs_readdir(struct file *file, struct dir_context *ctx) | |||
| 150 | if (unlikely(ret < 0)) | 150 | if (unlikely(ret < 0)) |
| 151 | goto out; | 151 | goto out; |
| 152 | ctx->pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1; | 152 | ctx->pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1; |
| 153 | file->f_version = inode->i_version; | ||
| 154 | } | 153 | } |
| 155 | next_pos = ctx->pos; | 154 | next_pos = ctx->pos; |
| 156 | if (!(de = map_pos_dirent(inode, &next_pos, &qbh))) { | 155 | if (!(de = map_pos_dirent(inode, &next_pos, &qbh))) { |
diff --git a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c index 3b834563b1f1..a4ad18afbdec 100644 --- a/fs/hpfs/dnode.c +++ b/fs/hpfs/dnode.c | |||
| @@ -419,7 +419,6 @@ int hpfs_add_dirent(struct inode *i, | |||
| 419 | c = 1; | 419 | c = 1; |
| 420 | goto ret; | 420 | goto ret; |
| 421 | } | 421 | } |
| 422 | i->i_version++; | ||
| 423 | c = hpfs_add_to_dnode(i, dno, name, namelen, new_de, 0); | 422 | c = hpfs_add_to_dnode(i, dno, name, namelen, new_de, 0); |
| 424 | ret: | 423 | ret: |
| 425 | return c; | 424 | return c; |
| @@ -726,7 +725,6 @@ int hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de, | |||
| 726 | return 2; | 725 | return 2; |
| 727 | } | 726 | } |
| 728 | } | 727 | } |
| 729 | i->i_version++; | ||
| 730 | for_all_poss(i, hpfs_pos_del, (t = get_pos(dnode, de)) + 1, 1); | 728 | for_all_poss(i, hpfs_pos_del, (t = get_pos(dnode, de)) + 1, 1); |
| 731 | hpfs_delete_de(i->i_sb, dnode, de); | 729 | hpfs_delete_de(i->i_sb, dnode, de); |
| 732 | hpfs_mark_4buffers_dirty(qbh); | 730 | hpfs_mark_4buffers_dirty(qbh); |
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index c45a3b9b9ac7..f2c3ebcd309c 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c | |||
| @@ -235,7 +235,6 @@ static struct inode *hpfs_alloc_inode(struct super_block *sb) | |||
| 235 | ei = kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS); | 235 | ei = kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS); |
| 236 | if (!ei) | 236 | if (!ei) |
| 237 | return NULL; | 237 | return NULL; |
| 238 | ei->vfs_inode.i_version = 1; | ||
| 239 | return &ei->vfs_inode; | 238 | return &ei->vfs_inode; |
| 240 | } | 239 | } |
| 241 | 240 | ||
diff --git a/fs/namespace.c b/fs/namespace.c index e158ec6b527b..9d1374ab6e06 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -2826,6 +2826,7 @@ long do_mount(const char *dev_name, const char __user *dir_name, | |||
| 2826 | SB_DIRSYNC | | 2826 | SB_DIRSYNC | |
| 2827 | SB_SILENT | | 2827 | SB_SILENT | |
| 2828 | SB_POSIXACL | | 2828 | SB_POSIXACL | |
| 2829 | SB_LAZYTIME | | ||
| 2829 | SB_I_VERSION); | 2830 | SB_I_VERSION); |
| 2830 | 2831 | ||
| 2831 | if (flags & MS_REMOUNT) | 2832 | if (flags & MS_REMOUNT) |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 0ac2fb1c6b63..b9129e2befea 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -291,12 +291,23 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat | |||
| 291 | const struct sockaddr *sap = data->addr; | 291 | const struct sockaddr *sap = data->addr; |
| 292 | struct nfs_net *nn = net_generic(data->net, nfs_net_id); | 292 | struct nfs_net *nn = net_generic(data->net, nfs_net_id); |
| 293 | 293 | ||
| 294 | again: | ||
| 294 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { | 295 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { |
| 295 | const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | 296 | const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; |
| 296 | /* Don't match clients that failed to initialise properly */ | 297 | /* Don't match clients that failed to initialise properly */ |
| 297 | if (clp->cl_cons_state < 0) | 298 | if (clp->cl_cons_state < 0) |
| 298 | continue; | 299 | continue; |
| 299 | 300 | ||
| 301 | /* If a client is still initializing then we need to wait */ | ||
| 302 | if (clp->cl_cons_state > NFS_CS_READY) { | ||
| 303 | refcount_inc(&clp->cl_count); | ||
| 304 | spin_unlock(&nn->nfs_client_lock); | ||
| 305 | nfs_wait_client_init_complete(clp); | ||
| 306 | nfs_put_client(clp); | ||
| 307 | spin_lock(&nn->nfs_client_lock); | ||
| 308 | goto again; | ||
| 309 | } | ||
| 310 | |||
| 300 | /* Different NFS versions cannot share the same nfs_client */ | 311 | /* Different NFS versions cannot share the same nfs_client */ |
| 301 | if (clp->rpc_ops != data->nfs_mod->rpc_ops) | 312 | if (clp->rpc_ops != data->nfs_mod->rpc_ops) |
| 302 | continue; | 313 | continue; |
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 12bbab0becb4..65a7e5da508c 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
| @@ -404,15 +404,19 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp, | |||
| 404 | if (error < 0) | 404 | if (error < 0) |
| 405 | goto error; | 405 | goto error; |
| 406 | 406 | ||
| 407 | if (!nfs4_has_session(clp)) | ||
| 408 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
| 409 | |||
| 410 | error = nfs4_discover_server_trunking(clp, &old); | 407 | error = nfs4_discover_server_trunking(clp, &old); |
| 411 | if (error < 0) | 408 | if (error < 0) |
| 412 | goto error; | 409 | goto error; |
| 413 | 410 | ||
| 414 | if (clp != old) | 411 | if (clp != old) { |
| 415 | clp->cl_preserve_clid = true; | 412 | clp->cl_preserve_clid = true; |
| 413 | /* | ||
| 414 | * Mark the client as having failed initialization so other | ||
| 415 | * processes walking the nfs_client_list in nfs_match_client() | ||
| 416 | * won't try to use it. | ||
| 417 | */ | ||
| 418 | nfs_mark_client_ready(clp, -EPERM); | ||
| 419 | } | ||
| 416 | nfs_put_client(clp); | 420 | nfs_put_client(clp); |
| 417 | clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags); | 421 | clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags); |
| 418 | return old; | 422 | return old; |
| @@ -539,6 +543,9 @@ int nfs40_walk_client_list(struct nfs_client *new, | |||
| 539 | spin_lock(&nn->nfs_client_lock); | 543 | spin_lock(&nn->nfs_client_lock); |
| 540 | list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { | 544 | list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { |
| 541 | 545 | ||
| 546 | if (pos == new) | ||
| 547 | goto found; | ||
| 548 | |||
| 542 | status = nfs4_match_client(pos, new, &prev, nn); | 549 | status = nfs4_match_client(pos, new, &prev, nn); |
| 543 | if (status < 0) | 550 | if (status < 0) |
| 544 | goto out_unlock; | 551 | goto out_unlock; |
| @@ -559,6 +566,7 @@ int nfs40_walk_client_list(struct nfs_client *new, | |||
| 559 | * way that a SETCLIENTID_CONFIRM to pos can succeed is | 566 | * way that a SETCLIENTID_CONFIRM to pos can succeed is |
| 560 | * if new and pos point to the same server: | 567 | * if new and pos point to the same server: |
| 561 | */ | 568 | */ |
| 569 | found: | ||
| 562 | refcount_inc(&pos->cl_count); | 570 | refcount_inc(&pos->cl_count); |
| 563 | spin_unlock(&nn->nfs_client_lock); | 571 | spin_unlock(&nn->nfs_client_lock); |
| 564 | 572 | ||
| @@ -572,6 +580,7 @@ int nfs40_walk_client_list(struct nfs_client *new, | |||
| 572 | case 0: | 580 | case 0: |
| 573 | nfs4_swap_callback_idents(pos, new); | 581 | nfs4_swap_callback_idents(pos, new); |
| 574 | pos->cl_confirm = new->cl_confirm; | 582 | pos->cl_confirm = new->cl_confirm; |
| 583 | nfs_mark_client_ready(pos, NFS_CS_READY); | ||
| 575 | 584 | ||
| 576 | prev = NULL; | 585 | prev = NULL; |
| 577 | *result = pos; | 586 | *result = pos; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 5b5f464f6f2a..4a379d7918f2 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -1890,6 +1890,8 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
| 1890 | if (res) | 1890 | if (res) |
| 1891 | error = nfs_generic_commit_list(inode, &head, how, &cinfo); | 1891 | error = nfs_generic_commit_list(inode, &head, how, &cinfo); |
| 1892 | nfs_commit_end(cinfo.mds); | 1892 | nfs_commit_end(cinfo.mds); |
| 1893 | if (res == 0) | ||
| 1894 | return res; | ||
| 1893 | if (error < 0) | 1895 | if (error < 0) |
| 1894 | goto out_error; | 1896 | goto out_error; |
| 1895 | if (!may_wait) | 1897 | if (!may_wait) |
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 697f8ae7792d..f650e475d8f0 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
| @@ -60,6 +60,9 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | |||
| 60 | gi->gid[i] = exp->ex_anon_gid; | 60 | gi->gid[i] = exp->ex_anon_gid; |
| 61 | else | 61 | else |
| 62 | gi->gid[i] = rqgi->gid[i]; | 62 | gi->gid[i] = rqgi->gid[i]; |
| 63 | |||
| 64 | /* Each thread allocates its own gi, no race */ | ||
| 65 | groups_sort(gi); | ||
| 63 | } | 66 | } |
| 64 | } else { | 67 | } else { |
| 65 | gi = get_group_info(rqgi); | 68 | gi = get_group_info(rqgi); |
diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig index cbfc196e5dc5..5ac415466861 100644 --- a/fs/overlayfs/Kconfig +++ b/fs/overlayfs/Kconfig | |||
| @@ -24,6 +24,16 @@ config OVERLAY_FS_REDIRECT_DIR | |||
| 24 | an overlay which has redirects on a kernel that doesn't support this | 24 | an overlay which has redirects on a kernel that doesn't support this |
| 25 | feature will have unexpected results. | 25 | feature will have unexpected results. |
| 26 | 26 | ||
| 27 | config OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW | ||
| 28 | bool "Overlayfs: follow redirects even if redirects are turned off" | ||
| 29 | default y | ||
| 30 | depends on OVERLAY_FS | ||
| 31 | help | ||
| 32 | Disable this to get a possibly more secure configuration, but that | ||
| 33 | might not be backward compatible with previous kernels. | ||
| 34 | |||
| 35 | For more information, see Documentation/filesystems/overlayfs.txt | ||
| 36 | |||
| 27 | config OVERLAY_FS_INDEX | 37 | config OVERLAY_FS_INDEX |
| 28 | bool "Overlayfs: turn on inodes index feature by default" | 38 | bool "Overlayfs: turn on inodes index feature by default" |
| 29 | depends on OVERLAY_FS | 39 | depends on OVERLAY_FS |
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index e13921824c70..f9788bc116a8 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c | |||
| @@ -887,7 +887,8 @@ static int ovl_set_redirect(struct dentry *dentry, bool samedir) | |||
| 887 | spin_unlock(&dentry->d_lock); | 887 | spin_unlock(&dentry->d_lock); |
| 888 | } else { | 888 | } else { |
| 889 | kfree(redirect); | 889 | kfree(redirect); |
| 890 | pr_warn_ratelimited("overlay: failed to set redirect (%i)\n", err); | 890 | pr_warn_ratelimited("overlayfs: failed to set redirect (%i)\n", |
| 891 | err); | ||
| 891 | /* Fall back to userspace copy-up */ | 892 | /* Fall back to userspace copy-up */ |
| 892 | err = -EXDEV; | 893 | err = -EXDEV; |
| 893 | } | 894 | } |
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index 625ed8066570..beb945e1963c 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c | |||
| @@ -435,7 +435,7 @@ int ovl_verify_index(struct dentry *index, struct ovl_path *lower, | |||
| 435 | 435 | ||
| 436 | /* Check if index is orphan and don't warn before cleaning it */ | 436 | /* Check if index is orphan and don't warn before cleaning it */ |
| 437 | if (d_inode(index)->i_nlink == 1 && | 437 | if (d_inode(index)->i_nlink == 1 && |
| 438 | ovl_get_nlink(index, origin.dentry, 0) == 0) | 438 | ovl_get_nlink(origin.dentry, index, 0) == 0) |
| 439 | err = -ENOENT; | 439 | err = -ENOENT; |
| 440 | 440 | ||
| 441 | dput(origin.dentry); | 441 | dput(origin.dentry); |
| @@ -681,6 +681,22 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, | |||
| 681 | if (d.stop) | 681 | if (d.stop) |
| 682 | break; | 682 | break; |
| 683 | 683 | ||
| 684 | /* | ||
| 685 | * Following redirects can have security consequences: it's like | ||
| 686 | * a symlink into the lower layer without the permission checks. | ||
| 687 | * This is only a problem if the upper layer is untrusted (e.g | ||
| 688 | * comes from an USB drive). This can allow a non-readable file | ||
| 689 | * or directory to become readable. | ||
| 690 | * | ||
| 691 | * Only following redirects when redirects are enabled disables | ||
| 692 | * this attack vector when not necessary. | ||
| 693 | */ | ||
| 694 | err = -EPERM; | ||
| 695 | if (d.redirect && !ofs->config.redirect_follow) { | ||
| 696 | pr_warn_ratelimited("overlay: refusing to follow redirect for (%pd2)\n", dentry); | ||
| 697 | goto out_put; | ||
| 698 | } | ||
| 699 | |||
| 684 | if (d.redirect && d.redirect[0] == '/' && poe != roe) { | 700 | if (d.redirect && d.redirect[0] == '/' && poe != roe) { |
| 685 | poe = roe; | 701 | poe = roe; |
| 686 | 702 | ||
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 13eab09a6b6f..b489099ccd49 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h | |||
| @@ -180,7 +180,7 @@ static inline int ovl_do_whiteout(struct inode *dir, struct dentry *dentry) | |||
| 180 | static inline struct dentry *ovl_do_tmpfile(struct dentry *dentry, umode_t mode) | 180 | static inline struct dentry *ovl_do_tmpfile(struct dentry *dentry, umode_t mode) |
| 181 | { | 181 | { |
| 182 | struct dentry *ret = vfs_tmpfile(dentry, mode, 0); | 182 | struct dentry *ret = vfs_tmpfile(dentry, mode, 0); |
| 183 | int err = IS_ERR(ret) ? PTR_ERR(ret) : 0; | 183 | int err = PTR_ERR_OR_ZERO(ret); |
| 184 | 184 | ||
| 185 | pr_debug("tmpfile(%pd2, 0%o) = %i\n", dentry, mode, err); | 185 | pr_debug("tmpfile(%pd2, 0%o) = %i\n", dentry, mode, err); |
| 186 | return ret; | 186 | return ret; |
diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index 752bab645879..9d0bc03bf6e4 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h | |||
| @@ -14,6 +14,8 @@ struct ovl_config { | |||
| 14 | char *workdir; | 14 | char *workdir; |
| 15 | bool default_permissions; | 15 | bool default_permissions; |
| 16 | bool redirect_dir; | 16 | bool redirect_dir; |
| 17 | bool redirect_follow; | ||
| 18 | const char *redirect_mode; | ||
| 17 | bool index; | 19 | bool index; |
| 18 | }; | 20 | }; |
| 19 | 21 | ||
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 0daa4354fec4..8c98578d27a1 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c | |||
| @@ -499,7 +499,7 @@ out: | |||
| 499 | return err; | 499 | return err; |
| 500 | 500 | ||
| 501 | fail: | 501 | fail: |
| 502 | pr_warn_ratelimited("overlay: failed to look up (%s) for ino (%i)\n", | 502 | pr_warn_ratelimited("overlayfs: failed to look up (%s) for ino (%i)\n", |
| 503 | p->name, err); | 503 | p->name, err); |
| 504 | goto out; | 504 | goto out; |
| 505 | } | 505 | } |
| @@ -663,7 +663,10 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx) | |||
| 663 | return PTR_ERR(rdt.cache); | 663 | return PTR_ERR(rdt.cache); |
| 664 | } | 664 | } |
| 665 | 665 | ||
| 666 | return iterate_dir(od->realfile, &rdt.ctx); | 666 | err = iterate_dir(od->realfile, &rdt.ctx); |
| 667 | ctx->pos = rdt.ctx.pos; | ||
| 668 | |||
| 669 | return err; | ||
| 667 | } | 670 | } |
| 668 | 671 | ||
| 669 | 672 | ||
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 288d20f9a55a..76440feb79f6 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
| @@ -33,6 +33,13 @@ module_param_named(redirect_dir, ovl_redirect_dir_def, bool, 0644); | |||
| 33 | MODULE_PARM_DESC(ovl_redirect_dir_def, | 33 | MODULE_PARM_DESC(ovl_redirect_dir_def, |
| 34 | "Default to on or off for the redirect_dir feature"); | 34 | "Default to on or off for the redirect_dir feature"); |
| 35 | 35 | ||
| 36 | static bool ovl_redirect_always_follow = | ||
| 37 | IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW); | ||
| 38 | module_param_named(redirect_always_follow, ovl_redirect_always_follow, | ||
| 39 | bool, 0644); | ||
| 40 | MODULE_PARM_DESC(ovl_redirect_always_follow, | ||
| 41 | "Follow redirects even if redirect_dir feature is turned off"); | ||
| 42 | |||
| 36 | static bool ovl_index_def = IS_ENABLED(CONFIG_OVERLAY_FS_INDEX); | 43 | static bool ovl_index_def = IS_ENABLED(CONFIG_OVERLAY_FS_INDEX); |
| 37 | module_param_named(index, ovl_index_def, bool, 0644); | 44 | module_param_named(index, ovl_index_def, bool, 0644); |
| 38 | MODULE_PARM_DESC(ovl_index_def, | 45 | MODULE_PARM_DESC(ovl_index_def, |
| @@ -232,6 +239,7 @@ static void ovl_free_fs(struct ovl_fs *ofs) | |||
| 232 | kfree(ofs->config.lowerdir); | 239 | kfree(ofs->config.lowerdir); |
| 233 | kfree(ofs->config.upperdir); | 240 | kfree(ofs->config.upperdir); |
| 234 | kfree(ofs->config.workdir); | 241 | kfree(ofs->config.workdir); |
| 242 | kfree(ofs->config.redirect_mode); | ||
| 235 | if (ofs->creator_cred) | 243 | if (ofs->creator_cred) |
| 236 | put_cred(ofs->creator_cred); | 244 | put_cred(ofs->creator_cred); |
| 237 | kfree(ofs); | 245 | kfree(ofs); |
| @@ -244,6 +252,7 @@ static void ovl_put_super(struct super_block *sb) | |||
| 244 | ovl_free_fs(ofs); | 252 | ovl_free_fs(ofs); |
| 245 | } | 253 | } |
| 246 | 254 | ||
| 255 | /* Sync real dirty inodes in upper filesystem (if it exists) */ | ||
| 247 | static int ovl_sync_fs(struct super_block *sb, int wait) | 256 | static int ovl_sync_fs(struct super_block *sb, int wait) |
| 248 | { | 257 | { |
| 249 | struct ovl_fs *ofs = sb->s_fs_info; | 258 | struct ovl_fs *ofs = sb->s_fs_info; |
| @@ -252,14 +261,24 @@ static int ovl_sync_fs(struct super_block *sb, int wait) | |||
| 252 | 261 | ||
| 253 | if (!ofs->upper_mnt) | 262 | if (!ofs->upper_mnt) |
| 254 | return 0; | 263 | return 0; |
| 255 | upper_sb = ofs->upper_mnt->mnt_sb; | 264 | |
| 256 | if (!upper_sb->s_op->sync_fs) | 265 | /* |
| 266 | * If this is a sync(2) call or an emergency sync, all the super blocks | ||
| 267 | * will be iterated, including upper_sb, so no need to do anything. | ||
| 268 | * | ||
| 269 | * If this is a syncfs(2) call, then we do need to call | ||
| 270 | * sync_filesystem() on upper_sb, but enough if we do it when being | ||
| 271 | * called with wait == 1. | ||
| 272 | */ | ||
| 273 | if (!wait) | ||
| 257 | return 0; | 274 | return 0; |
| 258 | 275 | ||
| 259 | /* real inodes have already been synced by sync_filesystem(ovl_sb) */ | 276 | upper_sb = ofs->upper_mnt->mnt_sb; |
| 277 | |||
| 260 | down_read(&upper_sb->s_umount); | 278 | down_read(&upper_sb->s_umount); |
| 261 | ret = upper_sb->s_op->sync_fs(upper_sb, wait); | 279 | ret = sync_filesystem(upper_sb); |
| 262 | up_read(&upper_sb->s_umount); | 280 | up_read(&upper_sb->s_umount); |
| 281 | |||
| 263 | return ret; | 282 | return ret; |
| 264 | } | 283 | } |
| 265 | 284 | ||
| @@ -295,6 +314,11 @@ static bool ovl_force_readonly(struct ovl_fs *ofs) | |||
| 295 | return (!ofs->upper_mnt || !ofs->workdir); | 314 | return (!ofs->upper_mnt || !ofs->workdir); |
| 296 | } | 315 | } |
| 297 | 316 | ||
| 317 | static const char *ovl_redirect_mode_def(void) | ||
| 318 | { | ||
| 319 | return ovl_redirect_dir_def ? "on" : "off"; | ||
| 320 | } | ||
| 321 | |||
| 298 | /** | 322 | /** |
| 299 | * ovl_show_options | 323 | * ovl_show_options |
| 300 | * | 324 | * |
| @@ -313,12 +337,10 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry) | |||
| 313 | } | 337 | } |
| 314 | if (ofs->config.default_permissions) | 338 | if (ofs->config.default_permissions) |
| 315 | seq_puts(m, ",default_permissions"); | 339 | seq_puts(m, ",default_permissions"); |
| 316 | if (ofs->config.redirect_dir != ovl_redirect_dir_def) | 340 | if (strcmp(ofs->config.redirect_mode, ovl_redirect_mode_def()) != 0) |
| 317 | seq_printf(m, ",redirect_dir=%s", | 341 | seq_printf(m, ",redirect_dir=%s", ofs->config.redirect_mode); |
| 318 | ofs->config.redirect_dir ? "on" : "off"); | ||
| 319 | if (ofs->config.index != ovl_index_def) | 342 | if (ofs->config.index != ovl_index_def) |
| 320 | seq_printf(m, ",index=%s", | 343 | seq_printf(m, ",index=%s", ofs->config.index ? "on" : "off"); |
| 321 | ofs->config.index ? "on" : "off"); | ||
| 322 | return 0; | 344 | return 0; |
| 323 | } | 345 | } |
| 324 | 346 | ||
| @@ -348,8 +370,7 @@ enum { | |||
| 348 | OPT_UPPERDIR, | 370 | OPT_UPPERDIR, |
| 349 | OPT_WORKDIR, | 371 | OPT_WORKDIR, |
| 350 | OPT_DEFAULT_PERMISSIONS, | 372 | OPT_DEFAULT_PERMISSIONS, |
| 351 | OPT_REDIRECT_DIR_ON, | 373 | OPT_REDIRECT_DIR, |
| 352 | OPT_REDIRECT_DIR_OFF, | ||
| 353 | OPT_INDEX_ON, | 374 | OPT_INDEX_ON, |
| 354 | OPT_INDEX_OFF, | 375 | OPT_INDEX_OFF, |
| 355 | OPT_ERR, | 376 | OPT_ERR, |
| @@ -360,8 +381,7 @@ static const match_table_t ovl_tokens = { | |||
| 360 | {OPT_UPPERDIR, "upperdir=%s"}, | 381 | {OPT_UPPERDIR, "upperdir=%s"}, |
| 361 | {OPT_WORKDIR, "workdir=%s"}, | 382 | {OPT_WORKDIR, "workdir=%s"}, |
| 362 | {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, | 383 | {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, |
| 363 | {OPT_REDIRECT_DIR_ON, "redirect_dir=on"}, | 384 | {OPT_REDIRECT_DIR, "redirect_dir=%s"}, |
| 364 | {OPT_REDIRECT_DIR_OFF, "redirect_dir=off"}, | ||
| 365 | {OPT_INDEX_ON, "index=on"}, | 385 | {OPT_INDEX_ON, "index=on"}, |
| 366 | {OPT_INDEX_OFF, "index=off"}, | 386 | {OPT_INDEX_OFF, "index=off"}, |
| 367 | {OPT_ERR, NULL} | 387 | {OPT_ERR, NULL} |
| @@ -390,10 +410,37 @@ static char *ovl_next_opt(char **s) | |||
| 390 | return sbegin; | 410 | return sbegin; |
| 391 | } | 411 | } |
| 392 | 412 | ||
| 413 | static int ovl_parse_redirect_mode(struct ovl_config *config, const char *mode) | ||
| 414 | { | ||
| 415 | if (strcmp(mode, "on") == 0) { | ||
| 416 | config->redirect_dir = true; | ||
| 417 | /* | ||
| 418 | * Does not make sense to have redirect creation without | ||
| 419 | * redirect following. | ||
| 420 | */ | ||
| 421 | config->redirect_follow = true; | ||
| 422 | } else if (strcmp(mode, "follow") == 0) { | ||
| 423 | config->redirect_follow = true; | ||
| 424 | } else if (strcmp(mode, "off") == 0) { | ||
| 425 | if (ovl_redirect_always_follow) | ||
| 426 | config->redirect_follow = true; | ||
| 427 | } else if (strcmp(mode, "nofollow") != 0) { | ||
| 428 | pr_err("overlayfs: bad mount option \"redirect_dir=%s\"\n", | ||
| 429 | mode); | ||
| 430 | return -EINVAL; | ||
| 431 | } | ||
| 432 | |||
| 433 | return 0; | ||
| 434 | } | ||
| 435 | |||
| 393 | static int ovl_parse_opt(char *opt, struct ovl_config *config) | 436 | static int ovl_parse_opt(char *opt, struct ovl_config *config) |
| 394 | { | 437 | { |
| 395 | char *p; | 438 | char *p; |
| 396 | 439 | ||
| 440 | config->redirect_mode = kstrdup(ovl_redirect_mode_def(), GFP_KERNEL); | ||
| 441 | if (!config->redirect_mode) | ||
| 442 | return -ENOMEM; | ||
| 443 | |||
| 397 | while ((p = ovl_next_opt(&opt)) != NULL) { | 444 | while ((p = ovl_next_opt(&opt)) != NULL) { |
| 398 | int token; | 445 | int token; |
| 399 | substring_t args[MAX_OPT_ARGS]; | 446 | substring_t args[MAX_OPT_ARGS]; |
| @@ -428,12 +475,11 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) | |||
| 428 | config->default_permissions = true; | 475 | config->default_permissions = true; |
| 429 | break; | 476 | break; |
| 430 | 477 | ||
| 431 | case OPT_REDIRECT_DIR_ON: | 478 | case OPT_REDIRECT_DIR: |
| 432 | config->redirect_dir = true; | 479 | kfree(config->redirect_mode); |
| 433 | break; | 480 | config->redirect_mode = match_strdup(&args[0]); |
| 434 | 481 | if (!config->redirect_mode) | |
| 435 | case OPT_REDIRECT_DIR_OFF: | 482 | return -ENOMEM; |
| 436 | config->redirect_dir = false; | ||
| 437 | break; | 483 | break; |
| 438 | 484 | ||
| 439 | case OPT_INDEX_ON: | 485 | case OPT_INDEX_ON: |
| @@ -458,7 +504,7 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) | |||
| 458 | config->workdir = NULL; | 504 | config->workdir = NULL; |
| 459 | } | 505 | } |
| 460 | 506 | ||
| 461 | return 0; | 507 | return ovl_parse_redirect_mode(config, config->redirect_mode); |
| 462 | } | 508 | } |
| 463 | 509 | ||
| 464 | #define OVL_WORKDIR_NAME "work" | 510 | #define OVL_WORKDIR_NAME "work" |
| @@ -1160,7 +1206,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1160 | if (!cred) | 1206 | if (!cred) |
| 1161 | goto out_err; | 1207 | goto out_err; |
| 1162 | 1208 | ||
| 1163 | ofs->config.redirect_dir = ovl_redirect_dir_def; | ||
| 1164 | ofs->config.index = ovl_index_def; | 1209 | ofs->config.index = ovl_index_def; |
| 1165 | err = ovl_parse_opt((char *) data, &ofs->config); | 1210 | err = ovl_parse_opt((char *) data, &ofs->config); |
| 1166 | if (err) | 1211 | if (err) |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 28fa85276eec..60316b52d659 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -2268,7 +2268,7 @@ static int show_timer(struct seq_file *m, void *v) | |||
| 2268 | notify = timer->it_sigev_notify; | 2268 | notify = timer->it_sigev_notify; |
| 2269 | 2269 | ||
| 2270 | seq_printf(m, "ID: %d\n", timer->it_id); | 2270 | seq_printf(m, "ID: %d\n", timer->it_id); |
| 2271 | seq_printf(m, "signal: %d/%p\n", | 2271 | seq_printf(m, "signal: %d/%px\n", |
| 2272 | timer->sigq->info.si_signo, | 2272 | timer->sigq->info.si_signo, |
| 2273 | timer->sigq->info.si_value.sival_ptr); | 2273 | timer->sigq->info.si_value.sival_ptr); |
| 2274 | seq_printf(m, "notify: %s/%s.%d\n", | 2274 | seq_printf(m, "notify: %s/%s.%d\n", |
diff --git a/fs/super.c b/fs/super.c index d4e33e8f1e6f..7ff1349609e4 100644 --- a/fs/super.c +++ b/fs/super.c | |||
| @@ -191,6 +191,24 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, | |||
| 191 | 191 | ||
| 192 | INIT_LIST_HEAD(&s->s_mounts); | 192 | INIT_LIST_HEAD(&s->s_mounts); |
| 193 | s->s_user_ns = get_user_ns(user_ns); | 193 | s->s_user_ns = get_user_ns(user_ns); |
| 194 | init_rwsem(&s->s_umount); | ||
| 195 | lockdep_set_class(&s->s_umount, &type->s_umount_key); | ||
| 196 | /* | ||
| 197 | * sget() can have s_umount recursion. | ||
| 198 | * | ||
| 199 | * When it cannot find a suitable sb, it allocates a new | ||
| 200 | * one (this one), and tries again to find a suitable old | ||
| 201 | * one. | ||
| 202 | * | ||
| 203 | * In case that succeeds, it will acquire the s_umount | ||
| 204 | * lock of the old one. Since these are clearly distrinct | ||
| 205 | * locks, and this object isn't exposed yet, there's no | ||
| 206 | * risk of deadlocks. | ||
| 207 | * | ||
| 208 | * Annotate this by putting this lock in a different | ||
| 209 | * subclass. | ||
| 210 | */ | ||
| 211 | down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING); | ||
| 194 | 212 | ||
| 195 | if (security_sb_alloc(s)) | 213 | if (security_sb_alloc(s)) |
| 196 | goto fail; | 214 | goto fail; |
| @@ -218,25 +236,6 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, | |||
| 218 | goto fail; | 236 | goto fail; |
| 219 | if (list_lru_init_memcg(&s->s_inode_lru)) | 237 | if (list_lru_init_memcg(&s->s_inode_lru)) |
| 220 | goto fail; | 238 | goto fail; |
| 221 | |||
| 222 | init_rwsem(&s->s_umount); | ||
| 223 | lockdep_set_class(&s->s_umount, &type->s_umount_key); | ||
| 224 | /* | ||
| 225 | * sget() can have s_umount recursion. | ||
| 226 | * | ||
| 227 | * When it cannot find a suitable sb, it allocates a new | ||
| 228 | * one (this one), and tries again to find a suitable old | ||
| 229 | * one. | ||
| 230 | * | ||
| 231 | * In case that succeeds, it will acquire the s_umount | ||
| 232 | * lock of the old one. Since these are clearly distrinct | ||
| 233 | * locks, and this object isn't exposed yet, there's no | ||
| 234 | * risk of deadlocks. | ||
| 235 | * | ||
| 236 | * Annotate this by putting this lock in a different | ||
| 237 | * subclass. | ||
| 238 | */ | ||
| 239 | down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING); | ||
| 240 | s->s_count = 1; | 239 | s->s_count = 1; |
| 241 | atomic_set(&s->s_active, 1); | 240 | atomic_set(&s->s_active, 1); |
| 242 | mutex_init(&s->s_vfs_rename_mutex); | 241 | mutex_init(&s->s_vfs_rename_mutex); |
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index 0da80019a917..83ed7715f856 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c | |||
| @@ -702,7 +702,7 @@ xfs_alloc_ag_vextent( | |||
| 702 | ASSERT(args->agbno % args->alignment == 0); | 702 | ASSERT(args->agbno % args->alignment == 0); |
| 703 | 703 | ||
| 704 | /* if not file data, insert new block into the reverse map btree */ | 704 | /* if not file data, insert new block into the reverse map btree */ |
| 705 | if (args->oinfo.oi_owner != XFS_RMAP_OWN_UNKNOWN) { | 705 | if (!xfs_rmap_should_skip_owner_update(&args->oinfo)) { |
| 706 | error = xfs_rmap_alloc(args->tp, args->agbp, args->agno, | 706 | error = xfs_rmap_alloc(args->tp, args->agbp, args->agno, |
| 707 | args->agbno, args->len, &args->oinfo); | 707 | args->agbno, args->len, &args->oinfo); |
| 708 | if (error) | 708 | if (error) |
| @@ -1682,7 +1682,7 @@ xfs_free_ag_extent( | |||
| 1682 | bno_cur = cnt_cur = NULL; | 1682 | bno_cur = cnt_cur = NULL; |
| 1683 | mp = tp->t_mountp; | 1683 | mp = tp->t_mountp; |
| 1684 | 1684 | ||
| 1685 | if (oinfo->oi_owner != XFS_RMAP_OWN_UNKNOWN) { | 1685 | if (!xfs_rmap_should_skip_owner_update(oinfo)) { |
| 1686 | error = xfs_rmap_free(tp, agbp, agno, bno, len, oinfo); | 1686 | error = xfs_rmap_free(tp, agbp, agno, bno, len, oinfo); |
| 1687 | if (error) | 1687 | if (error) |
| 1688 | goto error0; | 1688 | goto error0; |
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 6249c92671de..a76914db72ef 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c | |||
| @@ -212,6 +212,7 @@ xfs_attr_set( | |||
| 212 | int flags) | 212 | int flags) |
| 213 | { | 213 | { |
| 214 | struct xfs_mount *mp = dp->i_mount; | 214 | struct xfs_mount *mp = dp->i_mount; |
| 215 | struct xfs_buf *leaf_bp = NULL; | ||
| 215 | struct xfs_da_args args; | 216 | struct xfs_da_args args; |
| 216 | struct xfs_defer_ops dfops; | 217 | struct xfs_defer_ops dfops; |
| 217 | struct xfs_trans_res tres; | 218 | struct xfs_trans_res tres; |
| @@ -327,9 +328,16 @@ xfs_attr_set( | |||
| 327 | * GROT: another possible req'mt for a double-split btree op. | 328 | * GROT: another possible req'mt for a double-split btree op. |
| 328 | */ | 329 | */ |
| 329 | xfs_defer_init(args.dfops, args.firstblock); | 330 | xfs_defer_init(args.dfops, args.firstblock); |
| 330 | error = xfs_attr_shortform_to_leaf(&args); | 331 | error = xfs_attr_shortform_to_leaf(&args, &leaf_bp); |
| 331 | if (error) | 332 | if (error) |
| 332 | goto out_defer_cancel; | 333 | goto out_defer_cancel; |
| 334 | /* | ||
| 335 | * Prevent the leaf buffer from being unlocked so that a | ||
| 336 | * concurrent AIL push cannot grab the half-baked leaf | ||
| 337 | * buffer and run into problems with the write verifier. | ||
| 338 | */ | ||
| 339 | xfs_trans_bhold(args.trans, leaf_bp); | ||
| 340 | xfs_defer_bjoin(args.dfops, leaf_bp); | ||
| 333 | xfs_defer_ijoin(args.dfops, dp); | 341 | xfs_defer_ijoin(args.dfops, dp); |
| 334 | error = xfs_defer_finish(&args.trans, args.dfops); | 342 | error = xfs_defer_finish(&args.trans, args.dfops); |
| 335 | if (error) | 343 | if (error) |
| @@ -337,13 +345,14 @@ xfs_attr_set( | |||
| 337 | 345 | ||
| 338 | /* | 346 | /* |
| 339 | * Commit the leaf transformation. We'll need another (linked) | 347 | * Commit the leaf transformation. We'll need another (linked) |
| 340 | * transaction to add the new attribute to the leaf. | 348 | * transaction to add the new attribute to the leaf, which |
| 349 | * means that we have to hold & join the leaf buffer here too. | ||
| 341 | */ | 350 | */ |
| 342 | |||
| 343 | error = xfs_trans_roll_inode(&args.trans, dp); | 351 | error = xfs_trans_roll_inode(&args.trans, dp); |
| 344 | if (error) | 352 | if (error) |
| 345 | goto out; | 353 | goto out; |
| 346 | 354 | xfs_trans_bjoin(args.trans, leaf_bp); | |
| 355 | leaf_bp = NULL; | ||
| 347 | } | 356 | } |
| 348 | 357 | ||
| 349 | if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) | 358 | if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) |
| @@ -374,8 +383,9 @@ xfs_attr_set( | |||
| 374 | 383 | ||
| 375 | out_defer_cancel: | 384 | out_defer_cancel: |
| 376 | xfs_defer_cancel(&dfops); | 385 | xfs_defer_cancel(&dfops); |
| 377 | args.trans = NULL; | ||
| 378 | out: | 386 | out: |
| 387 | if (leaf_bp) | ||
| 388 | xfs_trans_brelse(args.trans, leaf_bp); | ||
| 379 | if (args.trans) | 389 | if (args.trans) |
| 380 | xfs_trans_cancel(args.trans); | 390 | xfs_trans_cancel(args.trans); |
| 381 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 391 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 53cc8b986eac..601eaa36f1ad 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c | |||
| @@ -735,10 +735,13 @@ xfs_attr_shortform_getvalue(xfs_da_args_t *args) | |||
| 735 | } | 735 | } |
| 736 | 736 | ||
| 737 | /* | 737 | /* |
| 738 | * Convert from using the shortform to the leaf. | 738 | * Convert from using the shortform to the leaf. On success, return the |
| 739 | * buffer so that we can keep it locked until we're totally done with it. | ||
| 739 | */ | 740 | */ |
| 740 | int | 741 | int |
| 741 | xfs_attr_shortform_to_leaf(xfs_da_args_t *args) | 742 | xfs_attr_shortform_to_leaf( |
| 743 | struct xfs_da_args *args, | ||
| 744 | struct xfs_buf **leaf_bp) | ||
| 742 | { | 745 | { |
| 743 | xfs_inode_t *dp; | 746 | xfs_inode_t *dp; |
| 744 | xfs_attr_shortform_t *sf; | 747 | xfs_attr_shortform_t *sf; |
| @@ -818,7 +821,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args) | |||
| 818 | sfe = XFS_ATTR_SF_NEXTENTRY(sfe); | 821 | sfe = XFS_ATTR_SF_NEXTENTRY(sfe); |
| 819 | } | 822 | } |
| 820 | error = 0; | 823 | error = 0; |
| 821 | 824 | *leaf_bp = bp; | |
| 822 | out: | 825 | out: |
| 823 | kmem_free(tmpbuffer); | 826 | kmem_free(tmpbuffer); |
| 824 | return error; | 827 | return error; |
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h index f7dda0c237b0..894124efb421 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.h +++ b/fs/xfs/libxfs/xfs_attr_leaf.h | |||
| @@ -48,7 +48,8 @@ void xfs_attr_shortform_create(struct xfs_da_args *args); | |||
| 48 | void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff); | 48 | void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff); |
| 49 | int xfs_attr_shortform_lookup(struct xfs_da_args *args); | 49 | int xfs_attr_shortform_lookup(struct xfs_da_args *args); |
| 50 | int xfs_attr_shortform_getvalue(struct xfs_da_args *args); | 50 | int xfs_attr_shortform_getvalue(struct xfs_da_args *args); |
| 51 | int xfs_attr_shortform_to_leaf(struct xfs_da_args *args); | 51 | int xfs_attr_shortform_to_leaf(struct xfs_da_args *args, |
| 52 | struct xfs_buf **leaf_bp); | ||
| 52 | int xfs_attr_shortform_remove(struct xfs_da_args *args); | 53 | int xfs_attr_shortform_remove(struct xfs_da_args *args); |
| 53 | int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); | 54 | int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); |
| 54 | int xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes); | 55 | int xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes); |
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 1210f684d3c2..1bddbba6b80c 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c | |||
| @@ -5136,7 +5136,7 @@ __xfs_bunmapi( | |||
| 5136 | * blowing out the transaction with a mix of EFIs and reflink | 5136 | * blowing out the transaction with a mix of EFIs and reflink |
| 5137 | * adjustments. | 5137 | * adjustments. |
| 5138 | */ | 5138 | */ |
| 5139 | if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) | 5139 | if (tp && xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) |
| 5140 | max_len = min(len, xfs_refcount_max_unmap(tp->t_log_res)); | 5140 | max_len = min(len, xfs_refcount_max_unmap(tp->t_log_res)); |
| 5141 | else | 5141 | else |
| 5142 | max_len = len; | 5142 | max_len = len; |
diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index 072ebfe1d6ae..087fea02c389 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c | |||
| @@ -249,6 +249,10 @@ xfs_defer_trans_roll( | |||
| 249 | for (i = 0; i < XFS_DEFER_OPS_NR_INODES && dop->dop_inodes[i]; i++) | 249 | for (i = 0; i < XFS_DEFER_OPS_NR_INODES && dop->dop_inodes[i]; i++) |
| 250 | xfs_trans_log_inode(*tp, dop->dop_inodes[i], XFS_ILOG_CORE); | 250 | xfs_trans_log_inode(*tp, dop->dop_inodes[i], XFS_ILOG_CORE); |
| 251 | 251 | ||
| 252 | /* Hold the (previously bjoin'd) buffer locked across the roll. */ | ||
| 253 | for (i = 0; i < XFS_DEFER_OPS_NR_BUFS && dop->dop_bufs[i]; i++) | ||
| 254 | xfs_trans_dirty_buf(*tp, dop->dop_bufs[i]); | ||
| 255 | |||
| 252 | trace_xfs_defer_trans_roll((*tp)->t_mountp, dop); | 256 | trace_xfs_defer_trans_roll((*tp)->t_mountp, dop); |
| 253 | 257 | ||
| 254 | /* Roll the transaction. */ | 258 | /* Roll the transaction. */ |
| @@ -264,6 +268,12 @@ xfs_defer_trans_roll( | |||
| 264 | for (i = 0; i < XFS_DEFER_OPS_NR_INODES && dop->dop_inodes[i]; i++) | 268 | for (i = 0; i < XFS_DEFER_OPS_NR_INODES && dop->dop_inodes[i]; i++) |
| 265 | xfs_trans_ijoin(*tp, dop->dop_inodes[i], 0); | 269 | xfs_trans_ijoin(*tp, dop->dop_inodes[i], 0); |
| 266 | 270 | ||
| 271 | /* Rejoin the buffers and dirty them so the log moves forward. */ | ||
| 272 | for (i = 0; i < XFS_DEFER_OPS_NR_BUFS && dop->dop_bufs[i]; i++) { | ||
| 273 | xfs_trans_bjoin(*tp, dop->dop_bufs[i]); | ||
| 274 | xfs_trans_bhold(*tp, dop->dop_bufs[i]); | ||
| 275 | } | ||
| 276 | |||
| 267 | return error; | 277 | return error; |
| 268 | } | 278 | } |
| 269 | 279 | ||
| @@ -295,6 +305,31 @@ xfs_defer_ijoin( | |||
| 295 | } | 305 | } |
| 296 | } | 306 | } |
| 297 | 307 | ||
| 308 | ASSERT(0); | ||
| 309 | return -EFSCORRUPTED; | ||
| 310 | } | ||
| 311 | |||
| 312 | /* | ||
| 313 | * Add this buffer to the deferred op. Each joined buffer is relogged | ||
| 314 | * each time we roll the transaction. | ||
| 315 | */ | ||
| 316 | int | ||
| 317 | xfs_defer_bjoin( | ||
| 318 | struct xfs_defer_ops *dop, | ||
| 319 | struct xfs_buf *bp) | ||
| 320 | { | ||
| 321 | int i; | ||
| 322 | |||
| 323 | for (i = 0; i < XFS_DEFER_OPS_NR_BUFS; i++) { | ||
| 324 | if (dop->dop_bufs[i] == bp) | ||
| 325 | return 0; | ||
| 326 | else if (dop->dop_bufs[i] == NULL) { | ||
| 327 | dop->dop_bufs[i] = bp; | ||
| 328 | return 0; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | ASSERT(0); | ||
| 298 | return -EFSCORRUPTED; | 333 | return -EFSCORRUPTED; |
| 299 | } | 334 | } |
| 300 | 335 | ||
| @@ -493,9 +528,7 @@ xfs_defer_init( | |||
| 493 | struct xfs_defer_ops *dop, | 528 | struct xfs_defer_ops *dop, |
| 494 | xfs_fsblock_t *fbp) | 529 | xfs_fsblock_t *fbp) |
| 495 | { | 530 | { |
| 496 | dop->dop_committed = false; | 531 | memset(dop, 0, sizeof(struct xfs_defer_ops)); |
| 497 | dop->dop_low = false; | ||
| 498 | memset(&dop->dop_inodes, 0, sizeof(dop->dop_inodes)); | ||
| 499 | *fbp = NULLFSBLOCK; | 532 | *fbp = NULLFSBLOCK; |
| 500 | INIT_LIST_HEAD(&dop->dop_intake); | 533 | INIT_LIST_HEAD(&dop->dop_intake); |
| 501 | INIT_LIST_HEAD(&dop->dop_pending); | 534 | INIT_LIST_HEAD(&dop->dop_pending); |
diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h index d4f046dd44bd..045beacdd37d 100644 --- a/fs/xfs/libxfs/xfs_defer.h +++ b/fs/xfs/libxfs/xfs_defer.h | |||
| @@ -59,6 +59,7 @@ enum xfs_defer_ops_type { | |||
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | #define XFS_DEFER_OPS_NR_INODES 2 /* join up to two inodes */ | 61 | #define XFS_DEFER_OPS_NR_INODES 2 /* join up to two inodes */ |
| 62 | #define XFS_DEFER_OPS_NR_BUFS 2 /* join up to two buffers */ | ||
| 62 | 63 | ||
| 63 | struct xfs_defer_ops { | 64 | struct xfs_defer_ops { |
| 64 | bool dop_committed; /* did any trans commit? */ | 65 | bool dop_committed; /* did any trans commit? */ |
| @@ -66,8 +67,9 @@ struct xfs_defer_ops { | |||
| 66 | struct list_head dop_intake; /* unlogged pending work */ | 67 | struct list_head dop_intake; /* unlogged pending work */ |
| 67 | struct list_head dop_pending; /* logged pending work */ | 68 | struct list_head dop_pending; /* logged pending work */ |
| 68 | 69 | ||
| 69 | /* relog these inodes with each roll */ | 70 | /* relog these with each roll */ |
| 70 | struct xfs_inode *dop_inodes[XFS_DEFER_OPS_NR_INODES]; | 71 | struct xfs_inode *dop_inodes[XFS_DEFER_OPS_NR_INODES]; |
| 72 | struct xfs_buf *dop_bufs[XFS_DEFER_OPS_NR_BUFS]; | ||
| 71 | }; | 73 | }; |
| 72 | 74 | ||
| 73 | void xfs_defer_add(struct xfs_defer_ops *dop, enum xfs_defer_ops_type type, | 75 | void xfs_defer_add(struct xfs_defer_ops *dop, enum xfs_defer_ops_type type, |
| @@ -77,6 +79,7 @@ void xfs_defer_cancel(struct xfs_defer_ops *dop); | |||
| 77 | void xfs_defer_init(struct xfs_defer_ops *dop, xfs_fsblock_t *fbp); | 79 | void xfs_defer_init(struct xfs_defer_ops *dop, xfs_fsblock_t *fbp); |
| 78 | bool xfs_defer_has_unfinished_work(struct xfs_defer_ops *dop); | 80 | bool xfs_defer_has_unfinished_work(struct xfs_defer_ops *dop); |
| 79 | int xfs_defer_ijoin(struct xfs_defer_ops *dop, struct xfs_inode *ip); | 81 | int xfs_defer_ijoin(struct xfs_defer_ops *dop, struct xfs_inode *ip); |
| 82 | int xfs_defer_bjoin(struct xfs_defer_ops *dop, struct xfs_buf *bp); | ||
| 80 | 83 | ||
| 81 | /* Description of a deferred type. */ | 84 | /* Description of a deferred type. */ |
| 82 | struct xfs_defer_op_type { | 85 | struct xfs_defer_op_type { |
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index de3f04a98656..3b57ef0f2f76 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c | |||
| @@ -920,8 +920,7 @@ STATIC xfs_agnumber_t | |||
| 920 | xfs_ialloc_ag_select( | 920 | xfs_ialloc_ag_select( |
| 921 | xfs_trans_t *tp, /* transaction pointer */ | 921 | xfs_trans_t *tp, /* transaction pointer */ |
| 922 | xfs_ino_t parent, /* parent directory inode number */ | 922 | xfs_ino_t parent, /* parent directory inode number */ |
| 923 | umode_t mode, /* bits set to indicate file type */ | 923 | umode_t mode) /* bits set to indicate file type */ |
| 924 | int okalloc) /* ok to allocate more space */ | ||
| 925 | { | 924 | { |
| 926 | xfs_agnumber_t agcount; /* number of ag's in the filesystem */ | 925 | xfs_agnumber_t agcount; /* number of ag's in the filesystem */ |
| 927 | xfs_agnumber_t agno; /* current ag number */ | 926 | xfs_agnumber_t agno; /* current ag number */ |
| @@ -978,9 +977,6 @@ xfs_ialloc_ag_select( | |||
| 978 | return agno; | 977 | return agno; |
| 979 | } | 978 | } |
| 980 | 979 | ||
| 981 | if (!okalloc) | ||
| 982 | goto nextag; | ||
| 983 | |||
| 984 | if (!pag->pagf_init) { | 980 | if (!pag->pagf_init) { |
| 985 | error = xfs_alloc_pagf_init(mp, tp, agno, flags); | 981 | error = xfs_alloc_pagf_init(mp, tp, agno, flags); |
| 986 | if (error) | 982 | if (error) |
| @@ -1680,7 +1676,6 @@ xfs_dialloc( | |||
| 1680 | struct xfs_trans *tp, | 1676 | struct xfs_trans *tp, |
| 1681 | xfs_ino_t parent, | 1677 | xfs_ino_t parent, |
| 1682 | umode_t mode, | 1678 | umode_t mode, |
| 1683 | int okalloc, | ||
| 1684 | struct xfs_buf **IO_agbp, | 1679 | struct xfs_buf **IO_agbp, |
| 1685 | xfs_ino_t *inop) | 1680 | xfs_ino_t *inop) |
| 1686 | { | 1681 | { |
| @@ -1692,6 +1687,7 @@ xfs_dialloc( | |||
| 1692 | int noroom = 0; | 1687 | int noroom = 0; |
| 1693 | xfs_agnumber_t start_agno; | 1688 | xfs_agnumber_t start_agno; |
| 1694 | struct xfs_perag *pag; | 1689 | struct xfs_perag *pag; |
| 1690 | int okalloc = 1; | ||
| 1695 | 1691 | ||
| 1696 | if (*IO_agbp) { | 1692 | if (*IO_agbp) { |
| 1697 | /* | 1693 | /* |
| @@ -1707,7 +1703,7 @@ xfs_dialloc( | |||
| 1707 | * We do not have an agbp, so select an initial allocation | 1703 | * We do not have an agbp, so select an initial allocation |
| 1708 | * group for inode allocation. | 1704 | * group for inode allocation. |
| 1709 | */ | 1705 | */ |
| 1710 | start_agno = xfs_ialloc_ag_select(tp, parent, mode, okalloc); | 1706 | start_agno = xfs_ialloc_ag_select(tp, parent, mode); |
| 1711 | if (start_agno == NULLAGNUMBER) { | 1707 | if (start_agno == NULLAGNUMBER) { |
| 1712 | *inop = NULLFSINO; | 1708 | *inop = NULLFSINO; |
| 1713 | return 0; | 1709 | return 0; |
diff --git a/fs/xfs/libxfs/xfs_ialloc.h b/fs/xfs/libxfs/xfs_ialloc.h index d2bdcd5e7312..66a8de0b1caa 100644 --- a/fs/xfs/libxfs/xfs_ialloc.h +++ b/fs/xfs/libxfs/xfs_ialloc.h | |||
| @@ -81,7 +81,6 @@ xfs_dialloc( | |||
| 81 | struct xfs_trans *tp, /* transaction pointer */ | 81 | struct xfs_trans *tp, /* transaction pointer */ |
| 82 | xfs_ino_t parent, /* parent inode (directory) */ | 82 | xfs_ino_t parent, /* parent inode (directory) */ |
| 83 | umode_t mode, /* mode bits for new inode */ | 83 | umode_t mode, /* mode bits for new inode */ |
| 84 | int okalloc, /* ok to allocate more space */ | ||
| 85 | struct xfs_buf **agbp, /* buf for a.g. inode header */ | 84 | struct xfs_buf **agbp, /* buf for a.g. inode header */ |
| 86 | xfs_ino_t *inop); /* inode number allocated */ | 85 | xfs_ino_t *inop); /* inode number allocated */ |
| 87 | 86 | ||
diff --git a/fs/xfs/libxfs/xfs_iext_tree.c b/fs/xfs/libxfs/xfs_iext_tree.c index 89bf16b4d937..b0f31791c7e6 100644 --- a/fs/xfs/libxfs/xfs_iext_tree.c +++ b/fs/xfs/libxfs/xfs_iext_tree.c | |||
| @@ -632,8 +632,6 @@ xfs_iext_insert( | |||
| 632 | struct xfs_iext_leaf *new = NULL; | 632 | struct xfs_iext_leaf *new = NULL; |
| 633 | int nr_entries, i; | 633 | int nr_entries, i; |
| 634 | 634 | ||
| 635 | trace_xfs_iext_insert(ip, cur, state, _RET_IP_); | ||
| 636 | |||
| 637 | if (ifp->if_height == 0) | 635 | if (ifp->if_height == 0) |
| 638 | xfs_iext_alloc_root(ifp, cur); | 636 | xfs_iext_alloc_root(ifp, cur); |
| 639 | else if (ifp->if_height == 1) | 637 | else if (ifp->if_height == 1) |
| @@ -661,6 +659,8 @@ xfs_iext_insert( | |||
| 661 | xfs_iext_set(cur_rec(cur), irec); | 659 | xfs_iext_set(cur_rec(cur), irec); |
| 662 | ifp->if_bytes += sizeof(struct xfs_iext_rec); | 660 | ifp->if_bytes += sizeof(struct xfs_iext_rec); |
| 663 | 661 | ||
| 662 | trace_xfs_iext_insert(ip, cur, state, _RET_IP_); | ||
| 663 | |||
| 664 | if (new) | 664 | if (new) |
| 665 | xfs_iext_insert_node(ifp, xfs_iext_leaf_key(new, 0), new, 2); | 665 | xfs_iext_insert_node(ifp, xfs_iext_leaf_key(new, 0), new, 2); |
| 666 | } | 666 | } |
diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c index 585b35d34142..c40d26763075 100644 --- a/fs/xfs/libxfs/xfs_refcount.c +++ b/fs/xfs/libxfs/xfs_refcount.c | |||
| @@ -1488,27 +1488,12 @@ __xfs_refcount_cow_alloc( | |||
| 1488 | xfs_extlen_t aglen, | 1488 | xfs_extlen_t aglen, |
| 1489 | struct xfs_defer_ops *dfops) | 1489 | struct xfs_defer_ops *dfops) |
| 1490 | { | 1490 | { |
| 1491 | int error; | ||
| 1492 | |||
| 1493 | trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_private.a.agno, | 1491 | trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_private.a.agno, |
| 1494 | agbno, aglen); | 1492 | agbno, aglen); |
| 1495 | 1493 | ||
| 1496 | /* Add refcount btree reservation */ | 1494 | /* Add refcount btree reservation */ |
| 1497 | error = xfs_refcount_adjust_cow(rcur, agbno, aglen, | 1495 | return xfs_refcount_adjust_cow(rcur, agbno, aglen, |
| 1498 | XFS_REFCOUNT_ADJUST_COW_ALLOC, dfops); | 1496 | XFS_REFCOUNT_ADJUST_COW_ALLOC, dfops); |
| 1499 | if (error) | ||
| 1500 | return error; | ||
| 1501 | |||
| 1502 | /* Add rmap entry */ | ||
| 1503 | if (xfs_sb_version_hasrmapbt(&rcur->bc_mp->m_sb)) { | ||
| 1504 | error = xfs_rmap_alloc_extent(rcur->bc_mp, dfops, | ||
| 1505 | rcur->bc_private.a.agno, | ||
| 1506 | agbno, aglen, XFS_RMAP_OWN_COW); | ||
| 1507 | if (error) | ||
| 1508 | return error; | ||
| 1509 | } | ||
| 1510 | |||
| 1511 | return error; | ||
| 1512 | } | 1497 | } |
| 1513 | 1498 | ||
| 1514 | /* | 1499 | /* |
| @@ -1521,27 +1506,12 @@ __xfs_refcount_cow_free( | |||
| 1521 | xfs_extlen_t aglen, | 1506 | xfs_extlen_t aglen, |
| 1522 | struct xfs_defer_ops *dfops) | 1507 | struct xfs_defer_ops *dfops) |
| 1523 | { | 1508 | { |
| 1524 | int error; | ||
| 1525 | |||
| 1526 | trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_private.a.agno, | 1509 | trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_private.a.agno, |
| 1527 | agbno, aglen); | 1510 | agbno, aglen); |
| 1528 | 1511 | ||
| 1529 | /* Remove refcount btree reservation */ | 1512 | /* Remove refcount btree reservation */ |
| 1530 | error = xfs_refcount_adjust_cow(rcur, agbno, aglen, | 1513 | return xfs_refcount_adjust_cow(rcur, agbno, aglen, |
| 1531 | XFS_REFCOUNT_ADJUST_COW_FREE, dfops); | 1514 | XFS_REFCOUNT_ADJUST_COW_FREE, dfops); |
| 1532 | if (error) | ||
| 1533 | return error; | ||
| 1534 | |||
| 1535 | /* Remove rmap entry */ | ||
| 1536 | if (xfs_sb_version_hasrmapbt(&rcur->bc_mp->m_sb)) { | ||
| 1537 | error = xfs_rmap_free_extent(rcur->bc_mp, dfops, | ||
| 1538 | rcur->bc_private.a.agno, | ||
| 1539 | agbno, aglen, XFS_RMAP_OWN_COW); | ||
| 1540 | if (error) | ||
| 1541 | return error; | ||
| 1542 | } | ||
| 1543 | |||
| 1544 | return error; | ||
| 1545 | } | 1515 | } |
| 1546 | 1516 | ||
| 1547 | /* Record a CoW staging extent in the refcount btree. */ | 1517 | /* Record a CoW staging extent in the refcount btree. */ |
| @@ -1552,11 +1522,19 @@ xfs_refcount_alloc_cow_extent( | |||
| 1552 | xfs_fsblock_t fsb, | 1522 | xfs_fsblock_t fsb, |
| 1553 | xfs_extlen_t len) | 1523 | xfs_extlen_t len) |
| 1554 | { | 1524 | { |
| 1525 | int error; | ||
| 1526 | |||
| 1555 | if (!xfs_sb_version_hasreflink(&mp->m_sb)) | 1527 | if (!xfs_sb_version_hasreflink(&mp->m_sb)) |
| 1556 | return 0; | 1528 | return 0; |
| 1557 | 1529 | ||
| 1558 | return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_ALLOC_COW, | 1530 | error = __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_ALLOC_COW, |
| 1559 | fsb, len); | 1531 | fsb, len); |
| 1532 | if (error) | ||
| 1533 | return error; | ||
| 1534 | |||
| 1535 | /* Add rmap entry */ | ||
| 1536 | return xfs_rmap_alloc_extent(mp, dfops, XFS_FSB_TO_AGNO(mp, fsb), | ||
| 1537 | XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW); | ||
| 1560 | } | 1538 | } |
| 1561 | 1539 | ||
| 1562 | /* Forget a CoW staging event in the refcount btree. */ | 1540 | /* Forget a CoW staging event in the refcount btree. */ |
| @@ -1567,9 +1545,17 @@ xfs_refcount_free_cow_extent( | |||
| 1567 | xfs_fsblock_t fsb, | 1545 | xfs_fsblock_t fsb, |
| 1568 | xfs_extlen_t len) | 1546 | xfs_extlen_t len) |
| 1569 | { | 1547 | { |
| 1548 | int error; | ||
| 1549 | |||
| 1570 | if (!xfs_sb_version_hasreflink(&mp->m_sb)) | 1550 | if (!xfs_sb_version_hasreflink(&mp->m_sb)) |
| 1571 | return 0; | 1551 | return 0; |
| 1572 | 1552 | ||
| 1553 | /* Remove rmap entry */ | ||
| 1554 | error = xfs_rmap_free_extent(mp, dfops, XFS_FSB_TO_AGNO(mp, fsb), | ||
| 1555 | XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW); | ||
| 1556 | if (error) | ||
| 1557 | return error; | ||
| 1558 | |||
| 1573 | return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_FREE_COW, | 1559 | return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_FREE_COW, |
| 1574 | fsb, len); | 1560 | fsb, len); |
| 1575 | } | 1561 | } |
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c index dd019cee1b3b..50db920ceeeb 100644 --- a/fs/xfs/libxfs/xfs_rmap.c +++ b/fs/xfs/libxfs/xfs_rmap.c | |||
| @@ -368,6 +368,51 @@ xfs_rmap_lookup_le_range( | |||
| 368 | } | 368 | } |
| 369 | 369 | ||
| 370 | /* | 370 | /* |
| 371 | * Perform all the relevant owner checks for a removal op. If we're doing an | ||
| 372 | * unknown-owner removal then we have no owner information to check. | ||
| 373 | */ | ||
| 374 | static int | ||
| 375 | xfs_rmap_free_check_owner( | ||
| 376 | struct xfs_mount *mp, | ||
| 377 | uint64_t ltoff, | ||
| 378 | struct xfs_rmap_irec *rec, | ||
| 379 | xfs_fsblock_t bno, | ||
| 380 | xfs_filblks_t len, | ||
| 381 | uint64_t owner, | ||
| 382 | uint64_t offset, | ||
| 383 | unsigned int flags) | ||
| 384 | { | ||
| 385 | int error = 0; | ||
| 386 | |||
| 387 | if (owner == XFS_RMAP_OWN_UNKNOWN) | ||
| 388 | return 0; | ||
| 389 | |||
| 390 | /* Make sure the unwritten flag matches. */ | ||
| 391 | XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) == | ||
| 392 | (rec->rm_flags & XFS_RMAP_UNWRITTEN), out); | ||
| 393 | |||
| 394 | /* Make sure the owner matches what we expect to find in the tree. */ | ||
| 395 | XFS_WANT_CORRUPTED_GOTO(mp, owner == rec->rm_owner, out); | ||
| 396 | |||
| 397 | /* Check the offset, if necessary. */ | ||
| 398 | if (XFS_RMAP_NON_INODE_OWNER(owner)) | ||
| 399 | goto out; | ||
| 400 | |||
| 401 | if (flags & XFS_RMAP_BMBT_BLOCK) { | ||
| 402 | XFS_WANT_CORRUPTED_GOTO(mp, rec->rm_flags & XFS_RMAP_BMBT_BLOCK, | ||
| 403 | out); | ||
| 404 | } else { | ||
| 405 | XFS_WANT_CORRUPTED_GOTO(mp, rec->rm_offset <= offset, out); | ||
| 406 | XFS_WANT_CORRUPTED_GOTO(mp, | ||
| 407 | ltoff + rec->rm_blockcount >= offset + len, | ||
| 408 | out); | ||
| 409 | } | ||
| 410 | |||
| 411 | out: | ||
| 412 | return error; | ||
| 413 | } | ||
| 414 | |||
| 415 | /* | ||
| 371 | * Find the extent in the rmap btree and remove it. | 416 | * Find the extent in the rmap btree and remove it. |
| 372 | * | 417 | * |
| 373 | * The record we find should always be an exact match for the extent that we're | 418 | * The record we find should always be an exact match for the extent that we're |
| @@ -444,33 +489,40 @@ xfs_rmap_unmap( | |||
| 444 | goto out_done; | 489 | goto out_done; |
| 445 | } | 490 | } |
| 446 | 491 | ||
| 447 | /* Make sure the unwritten flag matches. */ | 492 | /* |
| 448 | XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) == | 493 | * If we're doing an unknown-owner removal for EFI recovery, we expect |
| 449 | (ltrec.rm_flags & XFS_RMAP_UNWRITTEN), out_error); | 494 | * to find the full range in the rmapbt or nothing at all. If we |
| 495 | * don't find any rmaps overlapping either end of the range, we're | ||
| 496 | * done. Hopefully this means that the EFI creator already queued | ||
| 497 | * (and finished) a RUI to remove the rmap. | ||
| 498 | */ | ||
| 499 | if (owner == XFS_RMAP_OWN_UNKNOWN && | ||
| 500 | ltrec.rm_startblock + ltrec.rm_blockcount <= bno) { | ||
| 501 | struct xfs_rmap_irec rtrec; | ||
| 502 | |||
| 503 | error = xfs_btree_increment(cur, 0, &i); | ||
| 504 | if (error) | ||
| 505 | goto out_error; | ||
| 506 | if (i == 0) | ||
| 507 | goto out_done; | ||
| 508 | error = xfs_rmap_get_rec(cur, &rtrec, &i); | ||
| 509 | if (error) | ||
| 510 | goto out_error; | ||
| 511 | XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); | ||
| 512 | if (rtrec.rm_startblock >= bno + len) | ||
| 513 | goto out_done; | ||
| 514 | } | ||
| 450 | 515 | ||
| 451 | /* Make sure the extent we found covers the entire freeing range. */ | 516 | /* Make sure the extent we found covers the entire freeing range. */ |
| 452 | XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno && | 517 | XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno && |
| 453 | ltrec.rm_startblock + ltrec.rm_blockcount >= | 518 | ltrec.rm_startblock + ltrec.rm_blockcount >= |
| 454 | bno + len, out_error); | 519 | bno + len, out_error); |
| 455 | 520 | ||
| 456 | /* Make sure the owner matches what we expect to find in the tree. */ | 521 | /* Check owner information. */ |
| 457 | XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner || | 522 | error = xfs_rmap_free_check_owner(mp, ltoff, <rec, bno, len, owner, |
| 458 | XFS_RMAP_NON_INODE_OWNER(owner), out_error); | 523 | offset, flags); |
| 459 | 524 | if (error) | |
| 460 | /* Check the offset, if necessary. */ | 525 | goto out_error; |
| 461 | if (!XFS_RMAP_NON_INODE_OWNER(owner)) { | ||
| 462 | if (flags & XFS_RMAP_BMBT_BLOCK) { | ||
| 463 | XFS_WANT_CORRUPTED_GOTO(mp, | ||
| 464 | ltrec.rm_flags & XFS_RMAP_BMBT_BLOCK, | ||
| 465 | out_error); | ||
| 466 | } else { | ||
| 467 | XFS_WANT_CORRUPTED_GOTO(mp, | ||
| 468 | ltrec.rm_offset <= offset, out_error); | ||
| 469 | XFS_WANT_CORRUPTED_GOTO(mp, | ||
| 470 | ltoff + ltrec.rm_blockcount >= offset + len, | ||
| 471 | out_error); | ||
| 472 | } | ||
| 473 | } | ||
| 474 | 526 | ||
| 475 | if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) { | 527 | if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) { |
| 476 | /* exact match, simply remove the record from rmap tree */ | 528 | /* exact match, simply remove the record from rmap tree */ |
| @@ -664,6 +716,7 @@ xfs_rmap_map( | |||
| 664 | flags |= XFS_RMAP_UNWRITTEN; | 716 | flags |= XFS_RMAP_UNWRITTEN; |
| 665 | trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len, | 717 | trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len, |
| 666 | unwritten, oinfo); | 718 | unwritten, oinfo); |
| 719 | ASSERT(!xfs_rmap_should_skip_owner_update(oinfo)); | ||
| 667 | 720 | ||
| 668 | /* | 721 | /* |
| 669 | * For the initial lookup, look for an exact match or the left-adjacent | 722 | * For the initial lookup, look for an exact match or the left-adjacent |
diff --git a/fs/xfs/libxfs/xfs_rmap.h b/fs/xfs/libxfs/xfs_rmap.h index 466ede637080..0fcd5b1ba729 100644 --- a/fs/xfs/libxfs/xfs_rmap.h +++ b/fs/xfs/libxfs/xfs_rmap.h | |||
| @@ -61,7 +61,21 @@ static inline void | |||
| 61 | xfs_rmap_skip_owner_update( | 61 | xfs_rmap_skip_owner_update( |
| 62 | struct xfs_owner_info *oi) | 62 | struct xfs_owner_info *oi) |
| 63 | { | 63 | { |
| 64 | oi->oi_owner = XFS_RMAP_OWN_UNKNOWN; | 64 | xfs_rmap_ag_owner(oi, XFS_RMAP_OWN_NULL); |
| 65 | } | ||
| 66 | |||
| 67 | static inline bool | ||
| 68 | xfs_rmap_should_skip_owner_update( | ||
| 69 | struct xfs_owner_info *oi) | ||
| 70 | { | ||
| 71 | return oi->oi_owner == XFS_RMAP_OWN_NULL; | ||
| 72 | } | ||
| 73 | |||
| 74 | static inline void | ||
| 75 | xfs_rmap_any_owner_update( | ||
| 76 | struct xfs_owner_info *oi) | ||
| 77 | { | ||
| 78 | xfs_rmap_ag_owner(oi, XFS_RMAP_OWN_UNKNOWN); | ||
| 65 | } | 79 | } |
| 66 | 80 | ||
| 67 | /* Reverse mapping functions. */ | 81 | /* Reverse mapping functions. */ |
diff --git a/fs/xfs/scrub/scrub.c b/fs/xfs/scrub/scrub.c index 9c42c4efd01e..ab3aef2ae823 100644 --- a/fs/xfs/scrub/scrub.c +++ b/fs/xfs/scrub/scrub.c | |||
| @@ -46,7 +46,6 @@ | |||
| 46 | #include "scrub/scrub.h" | 46 | #include "scrub/scrub.h" |
| 47 | #include "scrub/common.h" | 47 | #include "scrub/common.h" |
| 48 | #include "scrub/trace.h" | 48 | #include "scrub/trace.h" |
| 49 | #include "scrub/scrub.h" | ||
| 50 | #include "scrub/btree.h" | 49 | #include "scrub/btree.h" |
| 51 | 50 | ||
| 52 | /* | 51 | /* |
diff --git a/fs/xfs/scrub/trace.c b/fs/xfs/scrub/trace.c index 472080e75788..86daed0e3a45 100644 --- a/fs/xfs/scrub/trace.c +++ b/fs/xfs/scrub/trace.c | |||
| @@ -26,7 +26,6 @@ | |||
| 26 | #include "xfs_mount.h" | 26 | #include "xfs_mount.h" |
| 27 | #include "xfs_defer.h" | 27 | #include "xfs_defer.h" |
| 28 | #include "xfs_da_format.h" | 28 | #include "xfs_da_format.h" |
| 29 | #include "xfs_defer.h" | ||
| 30 | #include "xfs_inode.h" | 29 | #include "xfs_inode.h" |
| 31 | #include "xfs_btree.h" | 30 | #include "xfs_btree.h" |
| 32 | #include "xfs_trans.h" | 31 | #include "xfs_trans.h" |
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 44f8c5451210..64da90655e95 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c | |||
| @@ -538,7 +538,7 @@ xfs_efi_recover( | |||
| 538 | return error; | 538 | return error; |
| 539 | efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents); | 539 | efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents); |
| 540 | 540 | ||
| 541 | xfs_rmap_skip_owner_update(&oinfo); | 541 | xfs_rmap_any_owner_update(&oinfo); |
| 542 | for (i = 0; i < efip->efi_format.efi_nextents; i++) { | 542 | for (i = 0; i < efip->efi_format.efi_nextents; i++) { |
| 543 | extp = &efip->efi_format.efi_extents[i]; | 543 | extp = &efip->efi_format.efi_extents[i]; |
| 544 | error = xfs_trans_free_extent(tp, efdp, extp->ext_start, | 544 | error = xfs_trans_free_extent(tp, efdp, extp->ext_start, |
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 8f22fc579dbb..60a2e128cb6a 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c | |||
| @@ -571,6 +571,11 @@ xfs_growfs_data_private( | |||
| 571 | * this doesn't actually exist in the rmap btree. | 571 | * this doesn't actually exist in the rmap btree. |
| 572 | */ | 572 | */ |
| 573 | xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_NULL); | 573 | xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_NULL); |
| 574 | error = xfs_rmap_free(tp, bp, agno, | ||
| 575 | be32_to_cpu(agf->agf_length) - new, | ||
| 576 | new, &oinfo); | ||
| 577 | if (error) | ||
| 578 | goto error0; | ||
| 574 | error = xfs_free_extent(tp, | 579 | error = xfs_free_extent(tp, |
| 575 | XFS_AGB_TO_FSB(mp, agno, | 580 | XFS_AGB_TO_FSB(mp, agno, |
| 576 | be32_to_cpu(agf->agf_length) - new), | 581 | be32_to_cpu(agf->agf_length) - new), |
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 43005fbe8b1e..3861d61fb265 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c | |||
| @@ -870,7 +870,7 @@ xfs_eofblocks_worker( | |||
| 870 | * based on the 'speculative_cow_prealloc_lifetime' tunable (5m by default). | 870 | * based on the 'speculative_cow_prealloc_lifetime' tunable (5m by default). |
| 871 | * (We'll just piggyback on the post-EOF prealloc space workqueue.) | 871 | * (We'll just piggyback on the post-EOF prealloc space workqueue.) |
| 872 | */ | 872 | */ |
| 873 | STATIC void | 873 | void |
| 874 | xfs_queue_cowblocks( | 874 | xfs_queue_cowblocks( |
| 875 | struct xfs_mount *mp) | 875 | struct xfs_mount *mp) |
| 876 | { | 876 | { |
| @@ -1536,8 +1536,23 @@ xfs_inode_free_quota_eofblocks( | |||
| 1536 | return __xfs_inode_free_quota_eofblocks(ip, xfs_icache_free_eofblocks); | 1536 | return __xfs_inode_free_quota_eofblocks(ip, xfs_icache_free_eofblocks); |
| 1537 | } | 1537 | } |
| 1538 | 1538 | ||
| 1539 | static inline unsigned long | ||
| 1540 | xfs_iflag_for_tag( | ||
| 1541 | int tag) | ||
| 1542 | { | ||
| 1543 | switch (tag) { | ||
| 1544 | case XFS_ICI_EOFBLOCKS_TAG: | ||
| 1545 | return XFS_IEOFBLOCKS; | ||
| 1546 | case XFS_ICI_COWBLOCKS_TAG: | ||
| 1547 | return XFS_ICOWBLOCKS; | ||
| 1548 | default: | ||
| 1549 | ASSERT(0); | ||
| 1550 | return 0; | ||
| 1551 | } | ||
| 1552 | } | ||
| 1553 | |||
| 1539 | static void | 1554 | static void |
| 1540 | __xfs_inode_set_eofblocks_tag( | 1555 | __xfs_inode_set_blocks_tag( |
| 1541 | xfs_inode_t *ip, | 1556 | xfs_inode_t *ip, |
| 1542 | void (*execute)(struct xfs_mount *mp), | 1557 | void (*execute)(struct xfs_mount *mp), |
| 1543 | void (*set_tp)(struct xfs_mount *mp, xfs_agnumber_t agno, | 1558 | void (*set_tp)(struct xfs_mount *mp, xfs_agnumber_t agno, |
| @@ -1552,10 +1567,10 @@ __xfs_inode_set_eofblocks_tag( | |||
| 1552 | * Don't bother locking the AG and looking up in the radix trees | 1567 | * Don't bother locking the AG and looking up in the radix trees |
| 1553 | * if we already know that we have the tag set. | 1568 | * if we already know that we have the tag set. |
| 1554 | */ | 1569 | */ |
| 1555 | if (ip->i_flags & XFS_IEOFBLOCKS) | 1570 | if (ip->i_flags & xfs_iflag_for_tag(tag)) |
| 1556 | return; | 1571 | return; |
| 1557 | spin_lock(&ip->i_flags_lock); | 1572 | spin_lock(&ip->i_flags_lock); |
| 1558 | ip->i_flags |= XFS_IEOFBLOCKS; | 1573 | ip->i_flags |= xfs_iflag_for_tag(tag); |
| 1559 | spin_unlock(&ip->i_flags_lock); | 1574 | spin_unlock(&ip->i_flags_lock); |
| 1560 | 1575 | ||
| 1561 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); | 1576 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); |
| @@ -1587,13 +1602,13 @@ xfs_inode_set_eofblocks_tag( | |||
| 1587 | xfs_inode_t *ip) | 1602 | xfs_inode_t *ip) |
| 1588 | { | 1603 | { |
| 1589 | trace_xfs_inode_set_eofblocks_tag(ip); | 1604 | trace_xfs_inode_set_eofblocks_tag(ip); |
| 1590 | return __xfs_inode_set_eofblocks_tag(ip, xfs_queue_eofblocks, | 1605 | return __xfs_inode_set_blocks_tag(ip, xfs_queue_eofblocks, |
| 1591 | trace_xfs_perag_set_eofblocks, | 1606 | trace_xfs_perag_set_eofblocks, |
| 1592 | XFS_ICI_EOFBLOCKS_TAG); | 1607 | XFS_ICI_EOFBLOCKS_TAG); |
| 1593 | } | 1608 | } |
| 1594 | 1609 | ||
| 1595 | static void | 1610 | static void |
| 1596 | __xfs_inode_clear_eofblocks_tag( | 1611 | __xfs_inode_clear_blocks_tag( |
| 1597 | xfs_inode_t *ip, | 1612 | xfs_inode_t *ip, |
| 1598 | void (*clear_tp)(struct xfs_mount *mp, xfs_agnumber_t agno, | 1613 | void (*clear_tp)(struct xfs_mount *mp, xfs_agnumber_t agno, |
| 1599 | int error, unsigned long caller_ip), | 1614 | int error, unsigned long caller_ip), |
| @@ -1603,7 +1618,7 @@ __xfs_inode_clear_eofblocks_tag( | |||
| 1603 | struct xfs_perag *pag; | 1618 | struct xfs_perag *pag; |
| 1604 | 1619 | ||
| 1605 | spin_lock(&ip->i_flags_lock); | 1620 | spin_lock(&ip->i_flags_lock); |
| 1606 | ip->i_flags &= ~XFS_IEOFBLOCKS; | 1621 | ip->i_flags &= ~xfs_iflag_for_tag(tag); |
| 1607 | spin_unlock(&ip->i_flags_lock); | 1622 | spin_unlock(&ip->i_flags_lock); |
| 1608 | 1623 | ||
| 1609 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); | 1624 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); |
| @@ -1630,7 +1645,7 @@ xfs_inode_clear_eofblocks_tag( | |||
| 1630 | xfs_inode_t *ip) | 1645 | xfs_inode_t *ip) |
| 1631 | { | 1646 | { |
| 1632 | trace_xfs_inode_clear_eofblocks_tag(ip); | 1647 | trace_xfs_inode_clear_eofblocks_tag(ip); |
| 1633 | return __xfs_inode_clear_eofblocks_tag(ip, | 1648 | return __xfs_inode_clear_blocks_tag(ip, |
| 1634 | trace_xfs_perag_clear_eofblocks, XFS_ICI_EOFBLOCKS_TAG); | 1649 | trace_xfs_perag_clear_eofblocks, XFS_ICI_EOFBLOCKS_TAG); |
| 1635 | } | 1650 | } |
| 1636 | 1651 | ||
| @@ -1724,7 +1739,7 @@ xfs_inode_set_cowblocks_tag( | |||
| 1724 | xfs_inode_t *ip) | 1739 | xfs_inode_t *ip) |
| 1725 | { | 1740 | { |
| 1726 | trace_xfs_inode_set_cowblocks_tag(ip); | 1741 | trace_xfs_inode_set_cowblocks_tag(ip); |
| 1727 | return __xfs_inode_set_eofblocks_tag(ip, xfs_queue_cowblocks, | 1742 | return __xfs_inode_set_blocks_tag(ip, xfs_queue_cowblocks, |
| 1728 | trace_xfs_perag_set_cowblocks, | 1743 | trace_xfs_perag_set_cowblocks, |
| 1729 | XFS_ICI_COWBLOCKS_TAG); | 1744 | XFS_ICI_COWBLOCKS_TAG); |
| 1730 | } | 1745 | } |
| @@ -1734,6 +1749,6 @@ xfs_inode_clear_cowblocks_tag( | |||
| 1734 | xfs_inode_t *ip) | 1749 | xfs_inode_t *ip) |
| 1735 | { | 1750 | { |
| 1736 | trace_xfs_inode_clear_cowblocks_tag(ip); | 1751 | trace_xfs_inode_clear_cowblocks_tag(ip); |
| 1737 | return __xfs_inode_clear_eofblocks_tag(ip, | 1752 | return __xfs_inode_clear_blocks_tag(ip, |
| 1738 | trace_xfs_perag_clear_cowblocks, XFS_ICI_COWBLOCKS_TAG); | 1753 | trace_xfs_perag_clear_cowblocks, XFS_ICI_COWBLOCKS_TAG); |
| 1739 | } | 1754 | } |
diff --git a/fs/xfs/xfs_icache.h b/fs/xfs/xfs_icache.h index bff4d85e5498..d4a77588eca1 100644 --- a/fs/xfs/xfs_icache.h +++ b/fs/xfs/xfs_icache.h | |||
| @@ -81,6 +81,7 @@ void xfs_inode_clear_cowblocks_tag(struct xfs_inode *ip); | |||
| 81 | int xfs_icache_free_cowblocks(struct xfs_mount *, struct xfs_eofblocks *); | 81 | int xfs_icache_free_cowblocks(struct xfs_mount *, struct xfs_eofblocks *); |
| 82 | int xfs_inode_free_quota_cowblocks(struct xfs_inode *ip); | 82 | int xfs_inode_free_quota_cowblocks(struct xfs_inode *ip); |
| 83 | void xfs_cowblocks_worker(struct work_struct *); | 83 | void xfs_cowblocks_worker(struct work_struct *); |
| 84 | void xfs_queue_cowblocks(struct xfs_mount *); | ||
| 84 | 85 | ||
| 85 | int xfs_inode_ag_iterator(struct xfs_mount *mp, | 86 | int xfs_inode_ag_iterator(struct xfs_mount *mp, |
| 86 | int (*execute)(struct xfs_inode *ip, int flags, void *args), | 87 | int (*execute)(struct xfs_inode *ip, int flags, void *args), |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 801274126648..6f95bdb408ce 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -749,7 +749,6 @@ xfs_ialloc( | |||
| 749 | xfs_nlink_t nlink, | 749 | xfs_nlink_t nlink, |
| 750 | dev_t rdev, | 750 | dev_t rdev, |
| 751 | prid_t prid, | 751 | prid_t prid, |
| 752 | int okalloc, | ||
| 753 | xfs_buf_t **ialloc_context, | 752 | xfs_buf_t **ialloc_context, |
| 754 | xfs_inode_t **ipp) | 753 | xfs_inode_t **ipp) |
| 755 | { | 754 | { |
| @@ -765,7 +764,7 @@ xfs_ialloc( | |||
| 765 | * Call the space management code to pick | 764 | * Call the space management code to pick |
| 766 | * the on-disk inode to be allocated. | 765 | * the on-disk inode to be allocated. |
| 767 | */ | 766 | */ |
| 768 | error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc, | 767 | error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, |
| 769 | ialloc_context, &ino); | 768 | ialloc_context, &ino); |
| 770 | if (error) | 769 | if (error) |
| 771 | return error; | 770 | return error; |
| @@ -957,7 +956,6 @@ xfs_dir_ialloc( | |||
| 957 | xfs_nlink_t nlink, | 956 | xfs_nlink_t nlink, |
| 958 | dev_t rdev, | 957 | dev_t rdev, |
| 959 | prid_t prid, /* project id */ | 958 | prid_t prid, /* project id */ |
| 960 | int okalloc, /* ok to allocate new space */ | ||
| 961 | xfs_inode_t **ipp, /* pointer to inode; it will be | 959 | xfs_inode_t **ipp, /* pointer to inode; it will be |
| 962 | locked. */ | 960 | locked. */ |
| 963 | int *committed) | 961 | int *committed) |
| @@ -988,8 +986,8 @@ xfs_dir_ialloc( | |||
| 988 | * transaction commit so that no other process can steal | 986 | * transaction commit so that no other process can steal |
| 989 | * the inode(s) that we've just allocated. | 987 | * the inode(s) that we've just allocated. |
| 990 | */ | 988 | */ |
| 991 | code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, okalloc, | 989 | code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, &ialloc_context, |
| 992 | &ialloc_context, &ip); | 990 | &ip); |
| 993 | 991 | ||
| 994 | /* | 992 | /* |
| 995 | * Return an error if we were unable to allocate a new inode. | 993 | * Return an error if we were unable to allocate a new inode. |
| @@ -1061,7 +1059,7 @@ xfs_dir_ialloc( | |||
| 1061 | * this call should always succeed. | 1059 | * this call should always succeed. |
| 1062 | */ | 1060 | */ |
| 1063 | code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, | 1061 | code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, |
| 1064 | okalloc, &ialloc_context, &ip); | 1062 | &ialloc_context, &ip); |
| 1065 | 1063 | ||
| 1066 | /* | 1064 | /* |
| 1067 | * If we get an error at this point, return to the caller | 1065 | * If we get an error at this point, return to the caller |
| @@ -1182,11 +1180,6 @@ xfs_create( | |||
| 1182 | xfs_flush_inodes(mp); | 1180 | xfs_flush_inodes(mp); |
| 1183 | error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp); | 1181 | error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp); |
| 1184 | } | 1182 | } |
| 1185 | if (error == -ENOSPC) { | ||
| 1186 | /* No space at all so try a "no-allocation" reservation */ | ||
| 1187 | resblks = 0; | ||
| 1188 | error = xfs_trans_alloc(mp, tres, 0, 0, 0, &tp); | ||
| 1189 | } | ||
| 1190 | if (error) | 1183 | if (error) |
| 1191 | goto out_release_inode; | 1184 | goto out_release_inode; |
| 1192 | 1185 | ||
| @@ -1203,19 +1196,13 @@ xfs_create( | |||
| 1203 | if (error) | 1196 | if (error) |
| 1204 | goto out_trans_cancel; | 1197 | goto out_trans_cancel; |
| 1205 | 1198 | ||
| 1206 | if (!resblks) { | ||
| 1207 | error = xfs_dir_canenter(tp, dp, name); | ||
| 1208 | if (error) | ||
| 1209 | goto out_trans_cancel; | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | /* | 1199 | /* |
| 1213 | * A newly created regular or special file just has one directory | 1200 | * A newly created regular or special file just has one directory |
| 1214 | * entry pointing to them, but a directory also the "." entry | 1201 | * entry pointing to them, but a directory also the "." entry |
| 1215 | * pointing to itself. | 1202 | * pointing to itself. |
| 1216 | */ | 1203 | */ |
| 1217 | error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, | 1204 | error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip, |
| 1218 | prid, resblks > 0, &ip, NULL); | 1205 | NULL); |
| 1219 | if (error) | 1206 | if (error) |
| 1220 | goto out_trans_cancel; | 1207 | goto out_trans_cancel; |
| 1221 | 1208 | ||
| @@ -1340,11 +1327,6 @@ xfs_create_tmpfile( | |||
| 1340 | tres = &M_RES(mp)->tr_create_tmpfile; | 1327 | tres = &M_RES(mp)->tr_create_tmpfile; |
| 1341 | 1328 | ||
| 1342 | error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp); | 1329 | error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp); |
| 1343 | if (error == -ENOSPC) { | ||
| 1344 | /* No space at all so try a "no-allocation" reservation */ | ||
| 1345 | resblks = 0; | ||
| 1346 | error = xfs_trans_alloc(mp, tres, 0, 0, 0, &tp); | ||
| 1347 | } | ||
| 1348 | if (error) | 1330 | if (error) |
| 1349 | goto out_release_inode; | 1331 | goto out_release_inode; |
| 1350 | 1332 | ||
| @@ -1353,8 +1335,7 @@ xfs_create_tmpfile( | |||
| 1353 | if (error) | 1335 | if (error) |
| 1354 | goto out_trans_cancel; | 1336 | goto out_trans_cancel; |
| 1355 | 1337 | ||
| 1356 | error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, | 1338 | error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, prid, &ip, NULL); |
| 1357 | prid, resblks > 0, &ip, NULL); | ||
| 1358 | if (error) | 1339 | if (error) |
| 1359 | goto out_trans_cancel; | 1340 | goto out_trans_cancel; |
| 1360 | 1341 | ||
| @@ -1506,6 +1487,24 @@ xfs_link( | |||
| 1506 | return error; | 1487 | return error; |
| 1507 | } | 1488 | } |
| 1508 | 1489 | ||
| 1490 | /* Clear the reflink flag and the cowblocks tag if possible. */ | ||
| 1491 | static void | ||
| 1492 | xfs_itruncate_clear_reflink_flags( | ||
| 1493 | struct xfs_inode *ip) | ||
| 1494 | { | ||
| 1495 | struct xfs_ifork *dfork; | ||
| 1496 | struct xfs_ifork *cfork; | ||
| 1497 | |||
| 1498 | if (!xfs_is_reflink_inode(ip)) | ||
| 1499 | return; | ||
| 1500 | dfork = XFS_IFORK_PTR(ip, XFS_DATA_FORK); | ||
| 1501 | cfork = XFS_IFORK_PTR(ip, XFS_COW_FORK); | ||
| 1502 | if (dfork->if_bytes == 0 && cfork->if_bytes == 0) | ||
| 1503 | ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; | ||
| 1504 | if (cfork->if_bytes == 0) | ||
| 1505 | xfs_inode_clear_cowblocks_tag(ip); | ||
| 1506 | } | ||
| 1507 | |||
| 1509 | /* | 1508 | /* |
| 1510 | * Free up the underlying blocks past new_size. The new size must be smaller | 1509 | * Free up the underlying blocks past new_size. The new size must be smaller |
| 1511 | * than the current size. This routine can be used both for the attribute and | 1510 | * than the current size. This routine can be used both for the attribute and |
| @@ -1602,15 +1601,7 @@ xfs_itruncate_extents( | |||
| 1602 | if (error) | 1601 | if (error) |
| 1603 | goto out; | 1602 | goto out; |
| 1604 | 1603 | ||
| 1605 | /* | 1604 | xfs_itruncate_clear_reflink_flags(ip); |
| 1606 | * Clear the reflink flag if there are no data fork blocks and | ||
| 1607 | * there are no extents staged in the cow fork. | ||
| 1608 | */ | ||
| 1609 | if (xfs_is_reflink_inode(ip) && ip->i_cnextents == 0) { | ||
| 1610 | if (ip->i_d.di_nblocks == 0) | ||
| 1611 | ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; | ||
| 1612 | xfs_inode_clear_cowblocks_tag(ip); | ||
| 1613 | } | ||
| 1614 | 1605 | ||
| 1615 | /* | 1606 | /* |
| 1616 | * Always re-log the inode so that our permanent transaction can keep | 1607 | * Always re-log the inode so that our permanent transaction can keep |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index cc13c3763721..d383e392ec9d 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
| @@ -232,6 +232,7 @@ static inline bool xfs_is_reflink_inode(struct xfs_inode *ip) | |||
| 232 | * log recovery to replay a bmap operation on the inode. | 232 | * log recovery to replay a bmap operation on the inode. |
| 233 | */ | 233 | */ |
| 234 | #define XFS_IRECOVERY (1 << 11) | 234 | #define XFS_IRECOVERY (1 << 11) |
| 235 | #define XFS_ICOWBLOCKS (1 << 12)/* has the cowblocks tag set */ | ||
| 235 | 236 | ||
| 236 | /* | 237 | /* |
| 237 | * Per-lifetime flags need to be reset when re-using a reclaimable inode during | 238 | * Per-lifetime flags need to be reset when re-using a reclaimable inode during |
| @@ -428,7 +429,7 @@ xfs_extlen_t xfs_get_extsz_hint(struct xfs_inode *ip); | |||
| 428 | xfs_extlen_t xfs_get_cowextsz_hint(struct xfs_inode *ip); | 429 | xfs_extlen_t xfs_get_cowextsz_hint(struct xfs_inode *ip); |
| 429 | 430 | ||
| 430 | int xfs_dir_ialloc(struct xfs_trans **, struct xfs_inode *, umode_t, | 431 | int xfs_dir_ialloc(struct xfs_trans **, struct xfs_inode *, umode_t, |
| 431 | xfs_nlink_t, dev_t, prid_t, int, | 432 | xfs_nlink_t, dev_t, prid_t, |
| 432 | struct xfs_inode **, int *); | 433 | struct xfs_inode **, int *); |
| 433 | 434 | ||
| 434 | /* from xfs_file.c */ | 435 | /* from xfs_file.c */ |
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 33eb4fb2e3fd..7ab52a8bc0a9 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
| @@ -1213,7 +1213,7 @@ xfs_xattr_iomap_begin( | |||
| 1213 | 1213 | ||
| 1214 | ASSERT(ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL); | 1214 | ASSERT(ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL); |
| 1215 | error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap, | 1215 | error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap, |
| 1216 | &nimaps, XFS_BMAPI_ENTIRE | XFS_BMAPI_ATTRFORK); | 1216 | &nimaps, XFS_BMAPI_ATTRFORK); |
| 1217 | out_unlock: | 1217 | out_unlock: |
| 1218 | xfs_iunlock(ip, lockmode); | 1218 | xfs_iunlock(ip, lockmode); |
| 1219 | 1219 | ||
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index 010a13a201aa..ec952dfad359 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c | |||
| @@ -793,8 +793,8 @@ xfs_qm_qino_alloc( | |||
| 793 | return error; | 793 | return error; |
| 794 | 794 | ||
| 795 | if (need_alloc) { | 795 | if (need_alloc) { |
| 796 | error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, 1, ip, | 796 | error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, ip, |
| 797 | &committed); | 797 | &committed); |
| 798 | if (error) { | 798 | if (error) { |
| 799 | xfs_trans_cancel(tp); | 799 | xfs_trans_cancel(tp); |
| 800 | return error; | 800 | return error; |
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index cc041a29eb70..47aea2e82c26 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c | |||
| @@ -49,8 +49,6 @@ | |||
| 49 | #include "xfs_alloc.h" | 49 | #include "xfs_alloc.h" |
| 50 | #include "xfs_quota_defs.h" | 50 | #include "xfs_quota_defs.h" |
| 51 | #include "xfs_quota.h" | 51 | #include "xfs_quota.h" |
| 52 | #include "xfs_btree.h" | ||
| 53 | #include "xfs_bmap_btree.h" | ||
| 54 | #include "xfs_reflink.h" | 52 | #include "xfs_reflink.h" |
| 55 | #include "xfs_iomap.h" | 53 | #include "xfs_iomap.h" |
| 56 | #include "xfs_rmap_btree.h" | 54 | #include "xfs_rmap_btree.h" |
| @@ -456,6 +454,8 @@ retry: | |||
| 456 | if (error) | 454 | if (error) |
| 457 | goto out_bmap_cancel; | 455 | goto out_bmap_cancel; |
| 458 | 456 | ||
| 457 | xfs_inode_set_cowblocks_tag(ip); | ||
| 458 | |||
| 459 | /* Finish up. */ | 459 | /* Finish up. */ |
| 460 | error = xfs_defer_finish(&tp, &dfops); | 460 | error = xfs_defer_finish(&tp, &dfops); |
| 461 | if (error) | 461 | if (error) |
| @@ -492,8 +492,9 @@ xfs_reflink_find_cow_mapping( | |||
| 492 | struct xfs_iext_cursor icur; | 492 | struct xfs_iext_cursor icur; |
| 493 | 493 | ||
| 494 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED)); | 494 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED)); |
| 495 | ASSERT(xfs_is_reflink_inode(ip)); | ||
| 496 | 495 | ||
| 496 | if (!xfs_is_reflink_inode(ip)) | ||
| 497 | return false; | ||
| 497 | offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset); | 498 | offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset); |
| 498 | if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &icur, &got)) | 499 | if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &icur, &got)) |
| 499 | return false; | 500 | return false; |
| @@ -612,6 +613,9 @@ xfs_reflink_cancel_cow_blocks( | |||
| 612 | 613 | ||
| 613 | /* Remove the mapping from the CoW fork. */ | 614 | /* Remove the mapping from the CoW fork. */ |
| 614 | xfs_bmap_del_extent_cow(ip, &icur, &got, &del); | 615 | xfs_bmap_del_extent_cow(ip, &icur, &got, &del); |
| 616 | } else { | ||
| 617 | /* Didn't do anything, push cursor back. */ | ||
| 618 | xfs_iext_prev(ifp, &icur); | ||
| 615 | } | 619 | } |
| 616 | next_extent: | 620 | next_extent: |
| 617 | if (!xfs_iext_get_extent(ifp, &icur, &got)) | 621 | if (!xfs_iext_get_extent(ifp, &icur, &got)) |
| @@ -727,7 +731,7 @@ xfs_reflink_end_cow( | |||
| 727 | (unsigned int)(end_fsb - offset_fsb), | 731 | (unsigned int)(end_fsb - offset_fsb), |
| 728 | XFS_DATA_FORK); | 732 | XFS_DATA_FORK); |
| 729 | error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_write, | 733 | error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_write, |
| 730 | resblks, 0, 0, &tp); | 734 | resblks, 0, XFS_TRANS_RESERVE, &tp); |
| 731 | if (error) | 735 | if (error) |
| 732 | goto out; | 736 | goto out; |
| 733 | 737 | ||
| @@ -1293,6 +1297,17 @@ xfs_reflink_remap_range( | |||
| 1293 | 1297 | ||
| 1294 | trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out); | 1298 | trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out); |
| 1295 | 1299 | ||
| 1300 | /* | ||
| 1301 | * Clear out post-eof preallocations because we don't have page cache | ||
| 1302 | * backing the delayed allocations and they'll never get freed on | ||
| 1303 | * their own. | ||
| 1304 | */ | ||
| 1305 | if (xfs_can_free_eofblocks(dest, true)) { | ||
| 1306 | ret = xfs_free_eofblocks(dest); | ||
| 1307 | if (ret) | ||
| 1308 | goto out_unlock; | ||
| 1309 | } | ||
| 1310 | |||
| 1296 | /* Set flags and remap blocks. */ | 1311 | /* Set flags and remap blocks. */ |
| 1297 | ret = xfs_reflink_set_inode_flag(src, dest); | 1312 | ret = xfs_reflink_set_inode_flag(src, dest); |
| 1298 | if (ret) | 1313 | if (ret) |
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 5122d3021117..1dacccc367f8 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c | |||
| @@ -1360,6 +1360,7 @@ xfs_fs_remount( | |||
| 1360 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); | 1360 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); |
| 1361 | return error; | 1361 | return error; |
| 1362 | } | 1362 | } |
| 1363 | xfs_queue_cowblocks(mp); | ||
| 1363 | 1364 | ||
| 1364 | /* Create the per-AG metadata reservation pool .*/ | 1365 | /* Create the per-AG metadata reservation pool .*/ |
| 1365 | error = xfs_fs_reserve_ag_blocks(mp); | 1366 | error = xfs_fs_reserve_ag_blocks(mp); |
| @@ -1369,6 +1370,14 @@ xfs_fs_remount( | |||
| 1369 | 1370 | ||
| 1370 | /* rw -> ro */ | 1371 | /* rw -> ro */ |
| 1371 | if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & SB_RDONLY)) { | 1372 | if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & SB_RDONLY)) { |
| 1373 | /* Get rid of any leftover CoW reservations... */ | ||
| 1374 | cancel_delayed_work_sync(&mp->m_cowblocks_work); | ||
| 1375 | error = xfs_icache_free_cowblocks(mp, NULL); | ||
| 1376 | if (error) { | ||
| 1377 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); | ||
| 1378 | return error; | ||
| 1379 | } | ||
| 1380 | |||
| 1372 | /* Free the per-AG metadata reservation pool. */ | 1381 | /* Free the per-AG metadata reservation pool. */ |
| 1373 | error = xfs_fs_unreserve_ag_blocks(mp); | 1382 | error = xfs_fs_unreserve_ag_blocks(mp); |
| 1374 | if (error) { | 1383 | if (error) { |
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index 68d3ca2c4968..2e9e793a8f9d 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c | |||
| @@ -232,11 +232,6 @@ xfs_symlink( | |||
| 232 | resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks); | 232 | resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks); |
| 233 | 233 | ||
| 234 | error = xfs_trans_alloc(mp, &M_RES(mp)->tr_symlink, resblks, 0, 0, &tp); | 234 | error = xfs_trans_alloc(mp, &M_RES(mp)->tr_symlink, resblks, 0, 0, &tp); |
| 235 | if (error == -ENOSPC && fs_blocks == 0) { | ||
| 236 | resblks = 0; | ||
| 237 | error = xfs_trans_alloc(mp, &M_RES(mp)->tr_symlink, 0, 0, 0, | ||
| 238 | &tp); | ||
| 239 | } | ||
| 240 | if (error) | 235 | if (error) |
| 241 | goto out_release_inode; | 236 | goto out_release_inode; |
| 242 | 237 | ||
| @@ -260,14 +255,6 @@ xfs_symlink( | |||
| 260 | goto out_trans_cancel; | 255 | goto out_trans_cancel; |
| 261 | 256 | ||
| 262 | /* | 257 | /* |
| 263 | * Check for ability to enter directory entry, if no space reserved. | ||
| 264 | */ | ||
| 265 | if (!resblks) { | ||
| 266 | error = xfs_dir_canenter(tp, dp, link_name); | ||
| 267 | if (error) | ||
| 268 | goto out_trans_cancel; | ||
| 269 | } | ||
| 270 | /* | ||
| 271 | * Initialize the bmap freelist prior to calling either | 258 | * Initialize the bmap freelist prior to calling either |
| 272 | * bmapi or the directory create code. | 259 | * bmapi or the directory create code. |
| 273 | */ | 260 | */ |
| @@ -277,7 +264,7 @@ xfs_symlink( | |||
| 277 | * Allocate an inode for the symlink. | 264 | * Allocate an inode for the symlink. |
| 278 | */ | 265 | */ |
| 279 | error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0, | 266 | error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0, |
| 280 | prid, resblks > 0, &ip, NULL); | 267 | prid, &ip, NULL); |
| 281 | if (error) | 268 | if (error) |
| 282 | goto out_trans_cancel; | 269 | goto out_trans_cancel; |
| 283 | 270 | ||
diff --git a/fs/xfs/xfs_trace.c b/fs/xfs/xfs_trace.c index 5d95fe348294..35f3546b6af5 100644 --- a/fs/xfs/xfs_trace.c +++ b/fs/xfs/xfs_trace.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include "xfs_mount.h" | 24 | #include "xfs_mount.h" |
| 25 | #include "xfs_defer.h" | 25 | #include "xfs_defer.h" |
| 26 | #include "xfs_da_format.h" | 26 | #include "xfs_da_format.h" |
| 27 | #include "xfs_defer.h" | ||
| 28 | #include "xfs_inode.h" | 27 | #include "xfs_inode.h" |
| 29 | #include "xfs_btree.h" | 28 | #include "xfs_btree.h" |
| 30 | #include "xfs_da_btree.h" | 29 | #include "xfs_da_btree.h" |
