mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-20 08:38:24 +08:00
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: Dmitry Monakhov <dmonakhov@openvz.org> Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
parent
ac0e773718
commit
e5472147e1
@ -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,
|
|||||||
(unsigned long long)off, (unsigned long long)len);
|
(unsigned long long)off, (unsigned long long)len);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
|
|
||||||
while (towrite > 0) {
|
/*
|
||||||
tocopy = sb->s_blocksize - offset < towrite ?
|
* Since we account only one data block in transaction credits,
|
||||||
sb->s_blocksize - offset : towrite;
|
* then it is impossible to cross a block boundary.
|
||||||
bh = ext3_bread(handle, inode, blk, 1, &err);
|
*/
|
||||||
if (!bh)
|
if (sb->s_blocksize - offset < len) {
|
||||||
goto out;
|
ext3_msg(sb, KERN_WARNING, "Quota write (off=%llu, len=%llu)"
|
||||||
if (journal_quota) {
|
" cancelled because not block aligned",
|
||||||
err = ext3_journal_get_write_access(handle, bh);
|
(unsigned long long)off, (unsigned long long)len);
|
||||||
if (err) {
|
return -EIO;
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
|
mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
|
||||||
|
bh = ext3_bread(handle, inode, blk, 1, &err);
|
||||||
|
if (!bh)
|
||||||
|
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, 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
|
||||||
|
Loading…
Reference in New Issue
Block a user