diff options
author | Yan, Zheng <zyan@redhat.com> | 2016-05-05 04:40:17 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2016-05-25 19:15:38 -0400 |
commit | 224a7542b8fdde3cc7c600f8b0870c5541a9f678 (patch) | |
tree | 71875474331a7743a051bfb273d419982d0b3741 /fs | |
parent | 1b1bc16d66a7c7af3b4f30d1cf5a363168b217f4 (diff) |
ceph: tolerate bad i_size for symlink inode
A mds bug can cause symlink's size to be truncated to zero.
Signed-off-by: Yan, Zheng <zyan@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ceph/inode.c | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 7ba8e1c2557b..89d08155986d 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -582,6 +582,11 @@ int ceph_drop_inode(struct inode *inode) | |||
582 | return 1; | 582 | return 1; |
583 | } | 583 | } |
584 | 584 | ||
585 | static inline blkcnt_t calc_inode_blocks(u64 size) | ||
586 | { | ||
587 | return (size + (1<<9) - 1) >> 9; | ||
588 | } | ||
589 | |||
585 | /* | 590 | /* |
586 | * Helpers to fill in size, ctime, mtime, and atime. We have to be | 591 | * Helpers to fill in size, ctime, mtime, and atime. We have to be |
587 | * careful because either the client or MDS may have more up to date | 592 | * careful because either the client or MDS may have more up to date |
@@ -604,7 +609,7 @@ int ceph_fill_file_size(struct inode *inode, int issued, | |||
604 | size = 0; | 609 | size = 0; |
605 | } | 610 | } |
606 | i_size_write(inode, size); | 611 | i_size_write(inode, size); |
607 | inode->i_blocks = (size + (1<<9) - 1) >> 9; | 612 | inode->i_blocks = calc_inode_blocks(size); |
608 | ci->i_reported_size = size; | 613 | ci->i_reported_size = size; |
609 | if (truncate_seq != ci->i_truncate_seq) { | 614 | if (truncate_seq != ci->i_truncate_seq) { |
610 | dout("truncate_seq %u -> %u\n", | 615 | dout("truncate_seq %u -> %u\n", |
@@ -863,9 +868,13 @@ static int fill_inode(struct inode *inode, struct page *locked_page, | |||
863 | 868 | ||
864 | spin_unlock(&ci->i_ceph_lock); | 869 | spin_unlock(&ci->i_ceph_lock); |
865 | 870 | ||
866 | err = -EINVAL; | 871 | if (symlen != i_size_read(inode)) { |
867 | if (WARN_ON(symlen != i_size_read(inode))) | 872 | pr_err("fill_inode %llx.%llx BAD symlink " |
868 | goto out; | 873 | "size %lld\n", ceph_vinop(inode), |
874 | i_size_read(inode)); | ||
875 | i_size_write(inode, symlen); | ||
876 | inode->i_blocks = calc_inode_blocks(symlen); | ||
877 | } | ||
869 | 878 | ||
870 | err = -ENOMEM; | 879 | err = -ENOMEM; |
871 | sym = kstrndup(iinfo->symlink, symlen, GFP_NOFS); | 880 | sym = kstrndup(iinfo->symlink, symlen, GFP_NOFS); |
@@ -1629,7 +1638,7 @@ int ceph_inode_set_size(struct inode *inode, loff_t size) | |||
1629 | spin_lock(&ci->i_ceph_lock); | 1638 | spin_lock(&ci->i_ceph_lock); |
1630 | dout("set_size %p %llu -> %llu\n", inode, inode->i_size, size); | 1639 | dout("set_size %p %llu -> %llu\n", inode, inode->i_size, size); |
1631 | i_size_write(inode, size); | 1640 | i_size_write(inode, size); |
1632 | inode->i_blocks = (size + (1 << 9) - 1) >> 9; | 1641 | inode->i_blocks = calc_inode_blocks(size); |
1633 | 1642 | ||
1634 | /* tell the MDS if we are approaching max_size */ | 1643 | /* tell the MDS if we are approaching max_size */ |
1635 | if ((size << 1) >= ci->i_max_size && | 1644 | if ((size << 1) >= ci->i_max_size && |
@@ -2002,8 +2011,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) | |||
2002 | if ((issued & CEPH_CAP_FILE_EXCL) && | 2011 | if ((issued & CEPH_CAP_FILE_EXCL) && |
2003 | attr->ia_size > inode->i_size) { | 2012 | attr->ia_size > inode->i_size) { |
2004 | i_size_write(inode, attr->ia_size); | 2013 | i_size_write(inode, attr->ia_size); |
2005 | inode->i_blocks = | 2014 | inode->i_blocks = calc_inode_blocks(attr->ia_size); |
2006 | (attr->ia_size + (1 << 9) - 1) >> 9; | ||
2007 | inode->i_ctime = attr->ia_ctime; | 2015 | inode->i_ctime = attr->ia_ctime; |
2008 | ci->i_reported_size = attr->ia_size; | 2016 | ci->i_reported_size = attr->ia_size; |
2009 | dirtied |= CEPH_CAP_FILE_EXCL; | 2017 | dirtied |= CEPH_CAP_FILE_EXCL; |