aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2016-05-05 04:40:17 -0400
committerIlya Dryomov <idryomov@gmail.com>2016-05-25 19:15:38 -0400
commit224a7542b8fdde3cc7c600f8b0870c5541a9f678 (patch)
tree71875474331a7743a051bfb273d419982d0b3741 /fs
parent1b1bc16d66a7c7af3b4f30d1cf5a363168b217f4 (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.c22
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
585static 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;