Commit e5472147 authored by Dmitry Monakhov's avatar Dmitry Monakhov Committed by Jan Kara

ext3: quota_write cross block boundary behaviour

We always assume what dquot update result in changes in one data block
But ext3_quota_write() function may handle cross block boundary writes
In fact if this ever happen it will result in incorrect journal credits
reservation. And later bug_on triggering. As soon this never happen the
boundary cross loop is NOOP. In order to make things straight
let's remove this loop and assert cross boundary condition.
Signed-off-by: default avatarDmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent ac0e7737
...@@ -2948,9 +2948,7 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type, ...@@ -2948,9 +2948,7 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type,
sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb); sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb);
int err = 0; int err = 0;
int offset = off & (sb->s_blocksize - 1); int offset = off & (sb->s_blocksize - 1);
int tocopy;
int journal_quota = EXT3_SB(sb)->s_qf_names[type] != NULL; int journal_quota = EXT3_SB(sb)->s_qf_names[type] != NULL;
size_t towrite = len;
struct buffer_head *bh; struct buffer_head *bh;
handle_t *handle = journal_current_handle(); handle_t *handle = journal_current_handle();
...@@ -2961,53 +2959,54 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type, ...@@ -2961,53 +2959,54 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type,
(unsigned long long)off, (unsigned long long)len); (unsigned long long)off, (unsigned long long)len);
return -EIO; return -EIO;
} }
/*
* Since we account only one data block in transaction credits,
* then it is impossible to cross a block boundary.
*/
if (sb->s_blocksize - offset < len) {
ext3_msg(sb, KERN_WARNING, "Quota write (off=%llu, len=%llu)"
" cancelled because not block aligned",
(unsigned long long)off, (unsigned long long)len);
return -EIO;
}
mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
while (towrite > 0) { bh = ext3_bread(handle, inode, blk, 1, &err);
tocopy = sb->s_blocksize - offset < towrite ? if (!bh)
sb->s_blocksize - offset : towrite; goto out;
bh = ext3_bread(handle, inode, blk, 1, &err); if (journal_quota) {
if (!bh) err = ext3_journal_get_write_access(handle, bh);
if (err) {
brelse(bh);
goto out; goto out;
if (journal_quota) {
err = ext3_journal_get_write_access(handle, bh);
if (err) {
brelse(bh);
goto out;
}
}
lock_buffer(bh);
memcpy(bh->b_data+offset, data, tocopy);
flush_dcache_page(bh->b_page);
unlock_buffer(bh);
if (journal_quota)
err = ext3_journal_dirty_metadata(handle, bh);
else {
/* Always do at least ordered writes for quotas */
err = ext3_journal_dirty_data(handle, bh);
mark_buffer_dirty(bh);
} }
brelse(bh);
if (err)
goto out;
offset = 0;
towrite -= tocopy;
data += tocopy;
blk++;
} }
lock_buffer(bh);
memcpy(bh->b_data+offset, data, len);
flush_dcache_page(bh->b_page);
unlock_buffer(bh);
if (journal_quota)
err = ext3_journal_dirty_metadata(handle, bh);
else {
/* Always do at least ordered writes for quotas */
err = ext3_journal_dirty_data(handle, bh);
mark_buffer_dirty(bh);
}
brelse(bh);
out: out:
if (len == towrite) { if (err) {
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
return err; return err;
} }
if (inode->i_size < off+len-towrite) { if (inode->i_size < off + len) {
i_size_write(inode, off+len-towrite); i_size_write(inode, off + len);
EXT3_I(inode)->i_disksize = inode->i_size; EXT3_I(inode)->i_disksize = inode->i_size;
} }
inode->i_version++; inode->i_version++;
inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_mtime = inode->i_ctime = CURRENT_TIME;
ext3_mark_inode_dirty(handle, inode); ext3_mark_inode_dirty(handle, inode);
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
return len - towrite; return len;
} }
#endif #endif
......
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