diff options
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 96 |
1 files changed, 74 insertions, 22 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index d4a9195c7f0d..740e67bbe249 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/falloc.h> | 38 | #include <linux/falloc.h> |
39 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
40 | #include <linux/ratelimit.h> | 40 | #include <linux/ratelimit.h> |
41 | #include <linux/mount.h> | ||
41 | #include "compat.h" | 42 | #include "compat.h" |
42 | #include "ctree.h" | 43 | #include "ctree.h" |
43 | #include "disk-io.h" | 44 | #include "disk-io.h" |
@@ -2031,7 +2032,7 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode) | |||
2031 | /* insert an orphan item to track this unlinked/truncated file */ | 2032 | /* insert an orphan item to track this unlinked/truncated file */ |
2032 | if (insert >= 1) { | 2033 | if (insert >= 1) { |
2033 | ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode)); | 2034 | ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode)); |
2034 | BUG_ON(ret); | 2035 | BUG_ON(ret && ret != -EEXIST); |
2035 | } | 2036 | } |
2036 | 2037 | ||
2037 | /* insert an orphan item to track subvolume contains orphan files */ | 2038 | /* insert an orphan item to track subvolume contains orphan files */ |
@@ -2223,7 +2224,14 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) | |||
2223 | continue; | 2224 | continue; |
2224 | } | 2225 | } |
2225 | nr_truncate++; | 2226 | nr_truncate++; |
2227 | /* | ||
2228 | * Need to hold the imutex for reservation purposes, not | ||
2229 | * a huge deal here but I have a WARN_ON in | ||
2230 | * btrfs_delalloc_reserve_space to catch offenders. | ||
2231 | */ | ||
2232 | mutex_lock(&inode->i_mutex); | ||
2226 | ret = btrfs_truncate(inode); | 2233 | ret = btrfs_truncate(inode); |
2234 | mutex_unlock(&inode->i_mutex); | ||
2227 | } else { | 2235 | } else { |
2228 | nr_unlink++; | 2236 | nr_unlink++; |
2229 | } | 2237 | } |
@@ -3426,7 +3434,6 @@ static int btrfs_setsize(struct inode *inode, loff_t newsize) | |||
3426 | i_size_write(inode, newsize); | 3434 | i_size_write(inode, newsize); |
3427 | btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL); | 3435 | btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL); |
3428 | ret = btrfs_update_inode(trans, root, inode); | 3436 | ret = btrfs_update_inode(trans, root, inode); |
3429 | |||
3430 | btrfs_end_transaction_throttle(trans, root); | 3437 | btrfs_end_transaction_throttle(trans, root); |
3431 | } else { | 3438 | } else { |
3432 | 3439 | ||
@@ -3467,9 +3474,9 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
3467 | 3474 | ||
3468 | if (attr->ia_valid) { | 3475 | if (attr->ia_valid) { |
3469 | setattr_copy(inode, attr); | 3476 | setattr_copy(inode, attr); |
3470 | mark_inode_dirty(inode); | 3477 | err = btrfs_dirty_inode(inode); |
3471 | 3478 | ||
3472 | if (attr->ia_valid & ATTR_MODE) | 3479 | if (!err && attr->ia_valid & ATTR_MODE) |
3473 | err = btrfs_acl_chmod(inode); | 3480 | err = btrfs_acl_chmod(inode); |
3474 | } | 3481 | } |
3475 | 3482 | ||
@@ -4245,42 +4252,80 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
4245 | * FIXME, needs more benchmarking...there are no reasons other than performance | 4252 | * FIXME, needs more benchmarking...there are no reasons other than performance |
4246 | * to keep or drop this code. | 4253 | * to keep or drop this code. |
4247 | */ | 4254 | */ |
4248 | void btrfs_dirty_inode(struct inode *inode, int flags) | 4255 | int btrfs_dirty_inode(struct inode *inode) |
4249 | { | 4256 | { |
4250 | struct btrfs_root *root = BTRFS_I(inode)->root; | 4257 | struct btrfs_root *root = BTRFS_I(inode)->root; |
4251 | struct btrfs_trans_handle *trans; | 4258 | struct btrfs_trans_handle *trans; |
4252 | int ret; | 4259 | int ret; |
4253 | 4260 | ||
4254 | if (BTRFS_I(inode)->dummy_inode) | 4261 | if (BTRFS_I(inode)->dummy_inode) |
4255 | return; | 4262 | return 0; |
4256 | 4263 | ||
4257 | trans = btrfs_join_transaction(root); | 4264 | trans = btrfs_join_transaction(root); |
4258 | BUG_ON(IS_ERR(trans)); | 4265 | if (IS_ERR(trans)) |
4266 | return PTR_ERR(trans); | ||
4259 | 4267 | ||
4260 | ret = btrfs_update_inode(trans, root, inode); | 4268 | ret = btrfs_update_inode(trans, root, inode); |
4261 | if (ret && ret == -ENOSPC) { | 4269 | if (ret && ret == -ENOSPC) { |
4262 | /* whoops, lets try again with the full transaction */ | 4270 | /* whoops, lets try again with the full transaction */ |
4263 | btrfs_end_transaction(trans, root); | 4271 | btrfs_end_transaction(trans, root); |
4264 | trans = btrfs_start_transaction(root, 1); | 4272 | trans = btrfs_start_transaction(root, 1); |
4265 | if (IS_ERR(trans)) { | 4273 | if (IS_ERR(trans)) |
4266 | printk_ratelimited(KERN_ERR "btrfs: fail to " | 4274 | return PTR_ERR(trans); |
4267 | "dirty inode %llu error %ld\n", | ||
4268 | (unsigned long long)btrfs_ino(inode), | ||
4269 | PTR_ERR(trans)); | ||
4270 | return; | ||
4271 | } | ||
4272 | 4275 | ||
4273 | ret = btrfs_update_inode(trans, root, inode); | 4276 | ret = btrfs_update_inode(trans, root, inode); |
4274 | if (ret) { | ||
4275 | printk_ratelimited(KERN_ERR "btrfs: fail to " | ||
4276 | "dirty inode %llu error %d\n", | ||
4277 | (unsigned long long)btrfs_ino(inode), | ||
4278 | ret); | ||
4279 | } | ||
4280 | } | 4277 | } |
4281 | btrfs_end_transaction(trans, root); | 4278 | btrfs_end_transaction(trans, root); |
4282 | if (BTRFS_I(inode)->delayed_node) | 4279 | if (BTRFS_I(inode)->delayed_node) |
4283 | btrfs_balance_delayed_items(root); | 4280 | btrfs_balance_delayed_items(root); |
4281 | |||
4282 | return ret; | ||
4283 | } | ||
4284 | |||
4285 | /* | ||
4286 | * This is a copy of file_update_time. We need this so we can return error on | ||
4287 | * ENOSPC for updating the inode in the case of file write and mmap writes. | ||
4288 | */ | ||
4289 | int btrfs_update_time(struct file *file) | ||
4290 | { | ||
4291 | struct inode *inode = file->f_path.dentry->d_inode; | ||
4292 | struct timespec now; | ||
4293 | int ret; | ||
4294 | enum { S_MTIME = 1, S_CTIME = 2, S_VERSION = 4 } sync_it = 0; | ||
4295 | |||
4296 | /* First try to exhaust all avenues to not sync */ | ||
4297 | if (IS_NOCMTIME(inode)) | ||
4298 | return 0; | ||
4299 | |||
4300 | now = current_fs_time(inode->i_sb); | ||
4301 | if (!timespec_equal(&inode->i_mtime, &now)) | ||
4302 | sync_it = S_MTIME; | ||
4303 | |||
4304 | if (!timespec_equal(&inode->i_ctime, &now)) | ||
4305 | sync_it |= S_CTIME; | ||
4306 | |||
4307 | if (IS_I_VERSION(inode)) | ||
4308 | sync_it |= S_VERSION; | ||
4309 | |||
4310 | if (!sync_it) | ||
4311 | return 0; | ||
4312 | |||
4313 | /* Finally allowed to write? Takes lock. */ | ||
4314 | if (mnt_want_write_file(file)) | ||
4315 | return 0; | ||
4316 | |||
4317 | /* Only change inode inside the lock region */ | ||
4318 | if (sync_it & S_VERSION) | ||
4319 | inode_inc_iversion(inode); | ||
4320 | if (sync_it & S_CTIME) | ||
4321 | inode->i_ctime = now; | ||
4322 | if (sync_it & S_MTIME) | ||
4323 | inode->i_mtime = now; | ||
4324 | ret = btrfs_dirty_inode(inode); | ||
4325 | if (!ret) | ||
4326 | mark_inode_dirty_sync(inode); | ||
4327 | mnt_drop_write(file->f_path.mnt); | ||
4328 | return ret; | ||
4284 | } | 4329 | } |
4285 | 4330 | ||
4286 | /* | 4331 | /* |
@@ -6358,7 +6403,12 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
6358 | u64 page_start; | 6403 | u64 page_start; |
6359 | u64 page_end; | 6404 | u64 page_end; |
6360 | 6405 | ||
6406 | /* Need this to keep space reservations serialized */ | ||
6407 | mutex_lock(&inode->i_mutex); | ||
6361 | ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE); | 6408 | ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE); |
6409 | mutex_unlock(&inode->i_mutex); | ||
6410 | if (!ret) | ||
6411 | ret = btrfs_update_time(vma->vm_file); | ||
6362 | if (ret) { | 6412 | if (ret) { |
6363 | if (ret == -ENOMEM) | 6413 | if (ret == -ENOMEM) |
6364 | ret = VM_FAULT_OOM; | 6414 | ret = VM_FAULT_OOM; |
@@ -6570,8 +6620,9 @@ static int btrfs_truncate(struct inode *inode) | |||
6570 | /* Just need the 1 for updating the inode */ | 6620 | /* Just need the 1 for updating the inode */ |
6571 | trans = btrfs_start_transaction(root, 1); | 6621 | trans = btrfs_start_transaction(root, 1); |
6572 | if (IS_ERR(trans)) { | 6622 | if (IS_ERR(trans)) { |
6573 | err = PTR_ERR(trans); | 6623 | ret = err = PTR_ERR(trans); |
6574 | goto out; | 6624 | trans = NULL; |
6625 | break; | ||
6575 | } | 6626 | } |
6576 | } | 6627 | } |
6577 | 6628 | ||
@@ -7415,6 +7466,7 @@ static const struct inode_operations btrfs_symlink_inode_operations = { | |||
7415 | .follow_link = page_follow_link_light, | 7466 | .follow_link = page_follow_link_light, |
7416 | .put_link = page_put_link, | 7467 | .put_link = page_put_link, |
7417 | .getattr = btrfs_getattr, | 7468 | .getattr = btrfs_getattr, |
7469 | .setattr = btrfs_setattr, | ||
7418 | .permission = btrfs_permission, | 7470 | .permission = btrfs_permission, |
7419 | .setxattr = btrfs_setxattr, | 7471 | .setxattr = btrfs_setxattr, |
7420 | .getxattr = btrfs_getxattr, | 7472 | .getxattr = btrfs_getxattr, |