Commit 224a7542 authored by Yan, Zheng's avatar Yan, Zheng Committed by Ilya Dryomov

ceph: tolerate bad i_size for symlink inode

A mds bug can cause symlink's size to be truncated to zero.
Signed-off-by: default avatarYan, Zheng <zyan@redhat.com>
parent 1b1bc16d
...@@ -582,6 +582,11 @@ int ceph_drop_inode(struct inode *inode) ...@@ -582,6 +582,11 @@ int ceph_drop_inode(struct inode *inode)
return 1; return 1;
} }
static inline blkcnt_t calc_inode_blocks(u64 size)
{
return (size + (1<<9) - 1) >> 9;
}
/* /*
* Helpers to fill in size, ctime, mtime, and atime. We have to be * Helpers to fill in size, ctime, mtime, and atime. We have to be
* careful because either the client or MDS may have more up to date * 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,7 +609,7 @@ int ceph_fill_file_size(struct inode *inode, int issued,
size = 0; size = 0;
} }
i_size_write(inode, size); i_size_write(inode, size);
inode->i_blocks = (size + (1<<9) - 1) >> 9; inode->i_blocks = calc_inode_blocks(size);
ci->i_reported_size = size; ci->i_reported_size = size;
if (truncate_seq != ci->i_truncate_seq) { if (truncate_seq != ci->i_truncate_seq) {
dout("truncate_seq %u -> %u\n", dout("truncate_seq %u -> %u\n",
...@@ -863,9 +868,13 @@ static int fill_inode(struct inode *inode, struct page *locked_page, ...@@ -863,9 +868,13 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
spin_unlock(&ci->i_ceph_lock); spin_unlock(&ci->i_ceph_lock);
err = -EINVAL; if (symlen != i_size_read(inode)) {
if (WARN_ON(symlen != i_size_read(inode))) pr_err("fill_inode %llx.%llx BAD symlink "
goto out; "size %lld\n", ceph_vinop(inode),
i_size_read(inode));
i_size_write(inode, symlen);
inode->i_blocks = calc_inode_blocks(symlen);
}
err = -ENOMEM; err = -ENOMEM;
sym = kstrndup(iinfo->symlink, symlen, GFP_NOFS); sym = kstrndup(iinfo->symlink, symlen, GFP_NOFS);
...@@ -1629,7 +1638,7 @@ int ceph_inode_set_size(struct inode *inode, loff_t size) ...@@ -1629,7 +1638,7 @@ int ceph_inode_set_size(struct inode *inode, loff_t size)
spin_lock(&ci->i_ceph_lock); spin_lock(&ci->i_ceph_lock);
dout("set_size %p %llu -> %llu\n", inode, inode->i_size, size); dout("set_size %p %llu -> %llu\n", inode, inode->i_size, size);
i_size_write(inode, size); i_size_write(inode, size);
inode->i_blocks = (size + (1 << 9) - 1) >> 9; inode->i_blocks = calc_inode_blocks(size);
/* tell the MDS if we are approaching max_size */ /* tell the MDS if we are approaching max_size */
if ((size << 1) >= ci->i_max_size && if ((size << 1) >= ci->i_max_size &&
...@@ -2002,8 +2011,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -2002,8 +2011,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
if ((issued & CEPH_CAP_FILE_EXCL) && if ((issued & CEPH_CAP_FILE_EXCL) &&
attr->ia_size > inode->i_size) { attr->ia_size > inode->i_size) {
i_size_write(inode, attr->ia_size); i_size_write(inode, attr->ia_size);
inode->i_blocks = inode->i_blocks = calc_inode_blocks(attr->ia_size);
(attr->ia_size + (1 << 9) - 1) >> 9;
inode->i_ctime = attr->ia_ctime; inode->i_ctime = attr->ia_ctime;
ci->i_reported_size = attr->ia_size; ci->i_reported_size = attr->ia_size;
dirtied |= CEPH_CAP_FILE_EXCL; dirtied |= CEPH_CAP_FILE_EXCL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment