diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/file.c | 33 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 18 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 32 | ||||
-rw-r--r-- | fs/btrfs/xattr.c | 50 |
4 files changed, 87 insertions, 46 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 3c3abff731a7..e4e57d59edb7 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -1036,11 +1036,13 @@ out: | |||
1036 | * on error we return an unlocked page and the error value | 1036 | * on error we return an unlocked page and the error value |
1037 | * on success we return a locked page and 0 | 1037 | * on success we return a locked page and 0 |
1038 | */ | 1038 | */ |
1039 | static int prepare_uptodate_page(struct page *page, u64 pos) | 1039 | static int prepare_uptodate_page(struct page *page, u64 pos, |
1040 | bool force_uptodate) | ||
1040 | { | 1041 | { |
1041 | int ret = 0; | 1042 | int ret = 0; |
1042 | 1043 | ||
1043 | if ((pos & (PAGE_CACHE_SIZE - 1)) && !PageUptodate(page)) { | 1044 | if (((pos & (PAGE_CACHE_SIZE - 1)) || force_uptodate) && |
1045 | !PageUptodate(page)) { | ||
1044 | ret = btrfs_readpage(NULL, page); | 1046 | ret = btrfs_readpage(NULL, page); |
1045 | if (ret) | 1047 | if (ret) |
1046 | return ret; | 1048 | return ret; |
@@ -1061,7 +1063,7 @@ static int prepare_uptodate_page(struct page *page, u64 pos) | |||
1061 | static noinline int prepare_pages(struct btrfs_root *root, struct file *file, | 1063 | static noinline int prepare_pages(struct btrfs_root *root, struct file *file, |
1062 | struct page **pages, size_t num_pages, | 1064 | struct page **pages, size_t num_pages, |
1063 | loff_t pos, unsigned long first_index, | 1065 | loff_t pos, unsigned long first_index, |
1064 | size_t write_bytes) | 1066 | size_t write_bytes, bool force_uptodate) |
1065 | { | 1067 | { |
1066 | struct extent_state *cached_state = NULL; | 1068 | struct extent_state *cached_state = NULL; |
1067 | int i; | 1069 | int i; |
@@ -1086,10 +1088,11 @@ again: | |||
1086 | } | 1088 | } |
1087 | 1089 | ||
1088 | if (i == 0) | 1090 | if (i == 0) |
1089 | err = prepare_uptodate_page(pages[i], pos); | 1091 | err = prepare_uptodate_page(pages[i], pos, |
1092 | force_uptodate); | ||
1090 | if (i == num_pages - 1) | 1093 | if (i == num_pages - 1) |
1091 | err = prepare_uptodate_page(pages[i], | 1094 | err = prepare_uptodate_page(pages[i], |
1092 | pos + write_bytes); | 1095 | pos + write_bytes, false); |
1093 | if (err) { | 1096 | if (err) { |
1094 | page_cache_release(pages[i]); | 1097 | page_cache_release(pages[i]); |
1095 | faili = i - 1; | 1098 | faili = i - 1; |
@@ -1158,6 +1161,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, | |||
1158 | size_t num_written = 0; | 1161 | size_t num_written = 0; |
1159 | int nrptrs; | 1162 | int nrptrs; |
1160 | int ret = 0; | 1163 | int ret = 0; |
1164 | bool force_page_uptodate = false; | ||
1161 | 1165 | ||
1162 | nrptrs = min((iov_iter_count(i) + PAGE_CACHE_SIZE - 1) / | 1166 | nrptrs = min((iov_iter_count(i) + PAGE_CACHE_SIZE - 1) / |
1163 | PAGE_CACHE_SIZE, PAGE_CACHE_SIZE / | 1167 | PAGE_CACHE_SIZE, PAGE_CACHE_SIZE / |
@@ -1200,7 +1204,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, | |||
1200 | * contents of pages from loop to loop | 1204 | * contents of pages from loop to loop |
1201 | */ | 1205 | */ |
1202 | ret = prepare_pages(root, file, pages, num_pages, | 1206 | ret = prepare_pages(root, file, pages, num_pages, |
1203 | pos, first_index, write_bytes); | 1207 | pos, first_index, write_bytes, |
1208 | force_page_uptodate); | ||
1204 | if (ret) { | 1209 | if (ret) { |
1205 | btrfs_delalloc_release_space(inode, | 1210 | btrfs_delalloc_release_space(inode, |
1206 | num_pages << PAGE_CACHE_SHIFT); | 1211 | num_pages << PAGE_CACHE_SHIFT); |
@@ -1217,12 +1222,15 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, | |||
1217 | if (copied < write_bytes) | 1222 | if (copied < write_bytes) |
1218 | nrptrs = 1; | 1223 | nrptrs = 1; |
1219 | 1224 | ||
1220 | if (copied == 0) | 1225 | if (copied == 0) { |
1226 | force_page_uptodate = true; | ||
1221 | dirty_pages = 0; | 1227 | dirty_pages = 0; |
1222 | else | 1228 | } else { |
1229 | force_page_uptodate = false; | ||
1223 | dirty_pages = (copied + offset + | 1230 | dirty_pages = (copied + offset + |
1224 | PAGE_CACHE_SIZE - 1) >> | 1231 | PAGE_CACHE_SIZE - 1) >> |
1225 | PAGE_CACHE_SHIFT; | 1232 | PAGE_CACHE_SHIFT; |
1233 | } | ||
1226 | 1234 | ||
1227 | /* | 1235 | /* |
1228 | * If we had a short copy we need to release the excess delaloc | 1236 | * If we had a short copy we need to release the excess delaloc |
@@ -1817,6 +1825,11 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin) | |||
1817 | goto out; | 1825 | goto out; |
1818 | case SEEK_DATA: | 1826 | case SEEK_DATA: |
1819 | case SEEK_HOLE: | 1827 | case SEEK_HOLE: |
1828 | if (offset >= i_size_read(inode)) { | ||
1829 | mutex_unlock(&inode->i_mutex); | ||
1830 | return -ENXIO; | ||
1831 | } | ||
1832 | |||
1820 | ret = find_desired_extent(inode, &offset, origin); | 1833 | ret = find_desired_extent(inode, &offset, origin); |
1821 | if (ret) { | 1834 | if (ret) { |
1822 | mutex_unlock(&inode->i_mutex); | 1835 | mutex_unlock(&inode->i_mutex); |
@@ -1825,11 +1838,11 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin) | |||
1825 | } | 1838 | } |
1826 | 1839 | ||
1827 | if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) { | 1840 | if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) { |
1828 | ret = -EINVAL; | 1841 | offset = -EINVAL; |
1829 | goto out; | 1842 | goto out; |
1830 | } | 1843 | } |
1831 | if (offset > inode->i_sb->s_maxbytes) { | 1844 | if (offset > inode->i_sb->s_maxbytes) { |
1832 | ret = -EINVAL; | 1845 | offset = -EINVAL; |
1833 | goto out; | 1846 | goto out; |
1834 | } | 1847 | } |
1835 | 1848 | ||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 4d14de6d121b..b2d004ad66a0 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -4018,7 +4018,8 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) | |||
4018 | memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key)); | 4018 | memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key)); |
4019 | kfree(dentry->d_fsdata); | 4019 | kfree(dentry->d_fsdata); |
4020 | dentry->d_fsdata = NULL; | 4020 | dentry->d_fsdata = NULL; |
4021 | d_clear_need_lookup(dentry); | 4021 | /* This thing is hashed, drop it for now */ |
4022 | d_drop(dentry); | ||
4022 | } else { | 4023 | } else { |
4023 | ret = btrfs_inode_by_name(dir, dentry, &location); | 4024 | ret = btrfs_inode_by_name(dir, dentry, &location); |
4024 | } | 4025 | } |
@@ -4085,7 +4086,15 @@ static void btrfs_dentry_release(struct dentry *dentry) | |||
4085 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | 4086 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, |
4086 | struct nameidata *nd) | 4087 | struct nameidata *nd) |
4087 | { | 4088 | { |
4088 | return d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry); | 4089 | struct dentry *ret; |
4090 | |||
4091 | ret = d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry); | ||
4092 | if (unlikely(d_need_lookup(dentry))) { | ||
4093 | spin_lock(&dentry->d_lock); | ||
4094 | dentry->d_flags &= ~DCACHE_NEED_LOOKUP; | ||
4095 | spin_unlock(&dentry->d_lock); | ||
4096 | } | ||
4097 | return ret; | ||
4089 | } | 4098 | } |
4090 | 4099 | ||
4091 | unsigned char btrfs_filetype_table[] = { | 4100 | unsigned char btrfs_filetype_table[] = { |
@@ -4125,7 +4134,8 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
4125 | 4134 | ||
4126 | /* special case for "." */ | 4135 | /* special case for "." */ |
4127 | if (filp->f_pos == 0) { | 4136 | if (filp->f_pos == 0) { |
4128 | over = filldir(dirent, ".", 1, 1, btrfs_ino(inode), DT_DIR); | 4137 | over = filldir(dirent, ".", 1, |
4138 | filp->f_pos, btrfs_ino(inode), DT_DIR); | ||
4129 | if (over) | 4139 | if (over) |
4130 | return 0; | 4140 | return 0; |
4131 | filp->f_pos = 1; | 4141 | filp->f_pos = 1; |
@@ -4134,7 +4144,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
4134 | if (filp->f_pos == 1) { | 4144 | if (filp->f_pos == 1) { |
4135 | u64 pino = parent_ino(filp->f_path.dentry); | 4145 | u64 pino = parent_ino(filp->f_path.dentry); |
4136 | over = filldir(dirent, "..", 2, | 4146 | over = filldir(dirent, "..", 2, |
4137 | 2, pino, DT_DIR); | 4147 | filp->f_pos, pino, DT_DIR); |
4138 | if (over) | 4148 | if (over) |
4139 | return 0; | 4149 | return 0; |
4140 | filp->f_pos = 2; | 4150 | filp->f_pos = 2; |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 3351b1b24574..dae5dfe41ba5 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -1047,7 +1047,16 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
1047 | if (!max_to_defrag) | 1047 | if (!max_to_defrag) |
1048 | max_to_defrag = last_index - 1; | 1048 | max_to_defrag = last_index - 1; |
1049 | 1049 | ||
1050 | while (i <= last_index && defrag_count < max_to_defrag) { | 1050 | /* |
1051 | * make writeback starts from i, so the defrag range can be | ||
1052 | * written sequentially. | ||
1053 | */ | ||
1054 | if (i < inode->i_mapping->writeback_index) | ||
1055 | inode->i_mapping->writeback_index = i; | ||
1056 | |||
1057 | while (i <= last_index && defrag_count < max_to_defrag && | ||
1058 | (i < (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> | ||
1059 | PAGE_CACHE_SHIFT)) { | ||
1051 | /* | 1060 | /* |
1052 | * make sure we stop running if someone unmounts | 1061 | * make sure we stop running if someone unmounts |
1053 | * the FS | 1062 | * the FS |
@@ -2177,6 +2186,11 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
2177 | if (!(src_file->f_mode & FMODE_READ)) | 2186 | if (!(src_file->f_mode & FMODE_READ)) |
2178 | goto out_fput; | 2187 | goto out_fput; |
2179 | 2188 | ||
2189 | /* don't make the dst file partly checksummed */ | ||
2190 | if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != | ||
2191 | (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) | ||
2192 | goto out_fput; | ||
2193 | |||
2180 | ret = -EISDIR; | 2194 | ret = -EISDIR; |
2181 | if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) | 2195 | if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) |
2182 | goto out_fput; | 2196 | goto out_fput; |
@@ -2226,6 +2240,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
2226 | goto out_unlock; | 2240 | goto out_unlock; |
2227 | } | 2241 | } |
2228 | 2242 | ||
2243 | /* truncate page cache pages from target inode range */ | ||
2244 | truncate_inode_pages_range(&inode->i_data, destoff, | ||
2245 | PAGE_CACHE_ALIGN(destoff + len) - 1); | ||
2246 | |||
2229 | /* do any pending delalloc/csum calc on src, one way or | 2247 | /* do any pending delalloc/csum calc on src, one way or |
2230 | another, and lock file content */ | 2248 | another, and lock file content */ |
2231 | while (1) { | 2249 | while (1) { |
@@ -2242,10 +2260,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
2242 | btrfs_wait_ordered_range(src, off, len); | 2260 | btrfs_wait_ordered_range(src, off, len); |
2243 | } | 2261 | } |
2244 | 2262 | ||
2245 | /* truncate page cache pages from target inode range */ | ||
2246 | truncate_inode_pages_range(&inode->i_data, off, | ||
2247 | ALIGN(off + len, PAGE_CACHE_SIZE) - 1); | ||
2248 | |||
2249 | /* clone data */ | 2263 | /* clone data */ |
2250 | key.objectid = btrfs_ino(src); | 2264 | key.objectid = btrfs_ino(src); |
2251 | key.type = BTRFS_EXTENT_DATA_KEY; | 2265 | key.type = BTRFS_EXTENT_DATA_KEY; |
@@ -2323,7 +2337,12 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
2323 | else | 2337 | else |
2324 | new_key.offset = destoff; | 2338 | new_key.offset = destoff; |
2325 | 2339 | ||
2326 | trans = btrfs_start_transaction(root, 1); | 2340 | /* |
2341 | * 1 - adjusting old extent (we may have to split it) | ||
2342 | * 1 - add new extent | ||
2343 | * 1 - inode update | ||
2344 | */ | ||
2345 | trans = btrfs_start_transaction(root, 3); | ||
2327 | if (IS_ERR(trans)) { | 2346 | if (IS_ERR(trans)) { |
2328 | ret = PTR_ERR(trans); | 2347 | ret = PTR_ERR(trans); |
2329 | goto out; | 2348 | goto out; |
@@ -2442,7 +2461,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
2442 | if (endoff > inode->i_size) | 2461 | if (endoff > inode->i_size) |
2443 | btrfs_i_size_write(inode, endoff); | 2462 | btrfs_i_size_write(inode, endoff); |
2444 | 2463 | ||
2445 | BTRFS_I(inode)->flags = BTRFS_I(src)->flags; | ||
2446 | ret = btrfs_update_inode(trans, root, inode); | 2464 | ret = btrfs_update_inode(trans, root, inode); |
2447 | BUG_ON(ret); | 2465 | BUG_ON(ret); |
2448 | btrfs_end_transaction(trans, root); | 2466 | btrfs_end_transaction(trans, root); |
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index 69565e5fc6a0..426aa464f1af 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c | |||
@@ -383,36 +383,36 @@ int btrfs_removexattr(struct dentry *dentry, const char *name) | |||
383 | XATTR_REPLACE); | 383 | XATTR_REPLACE); |
384 | } | 384 | } |
385 | 385 | ||
386 | int btrfs_xattr_security_init(struct btrfs_trans_handle *trans, | 386 | int btrfs_initxattrs(struct inode *inode, const struct xattr *xattr_array, |
387 | struct inode *inode, struct inode *dir, | 387 | void *fs_info) |
388 | const struct qstr *qstr) | ||
389 | { | 388 | { |
390 | int err; | 389 | const struct xattr *xattr; |
391 | size_t len; | 390 | struct btrfs_trans_handle *trans = fs_info; |
392 | void *value; | ||
393 | char *suffix; | ||
394 | char *name; | 391 | char *name; |
392 | int err = 0; | ||
395 | 393 | ||
396 | err = security_inode_init_security(inode, dir, qstr, &suffix, &value, | 394 | for (xattr = xattr_array; xattr->name != NULL; xattr++) { |
397 | &len); | 395 | name = kmalloc(XATTR_SECURITY_PREFIX_LEN + |
398 | if (err) { | 396 | strlen(xattr->name) + 1, GFP_NOFS); |
399 | if (err == -EOPNOTSUPP) | 397 | if (!name) { |
400 | return 0; | 398 | err = -ENOMEM; |
401 | return err; | 399 | break; |
402 | } | 400 | } |
403 | |||
404 | name = kmalloc(XATTR_SECURITY_PREFIX_LEN + strlen(suffix) + 1, | ||
405 | GFP_NOFS); | ||
406 | if (!name) { | ||
407 | err = -ENOMEM; | ||
408 | } else { | ||
409 | strcpy(name, XATTR_SECURITY_PREFIX); | 401 | strcpy(name, XATTR_SECURITY_PREFIX); |
410 | strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix); | 402 | strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name); |
411 | err = __btrfs_setxattr(trans, inode, name, value, len, 0); | 403 | err = __btrfs_setxattr(trans, inode, name, |
404 | xattr->value, xattr->value_len, 0); | ||
412 | kfree(name); | 405 | kfree(name); |
406 | if (err < 0) | ||
407 | break; | ||
413 | } | 408 | } |
414 | |||
415 | kfree(suffix); | ||
416 | kfree(value); | ||
417 | return err; | 409 | return err; |
418 | } | 410 | } |
411 | |||
412 | int btrfs_xattr_security_init(struct btrfs_trans_handle *trans, | ||
413 | struct inode *inode, struct inode *dir, | ||
414 | const struct qstr *qstr) | ||
415 | { | ||
416 | return security_inode_init_security(inode, dir, qstr, | ||
417 | &btrfs_initxattrs, trans); | ||
418 | } | ||