Commit ca6215df authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull reiserfs and ext3 fixes from Jan Kara:
 "Fixes of reiserfs deadlocks when quotas are enabled (locking there was
  completely busted by BKL conversion) and also one small ext3 fix in
  the trim interface."

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  ext3: Avoid underflow of in ext3_trim_fs()
  reiserfs: Move quota calls out of write lock
  reiserfs: Protect reiserfs_quota_write() with write lock
  reiserfs: Protect reiserfs_quota_on() with write lock
  reiserfs: Fix lock ordering during remount
parents 3587b1b0 ae49eeec
...@@ -2101,8 +2101,9 @@ int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range) ...@@ -2101,8 +2101,9 @@ int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range)
end = start + (range->len >> sb->s_blocksize_bits) - 1; end = start + (range->len >> sb->s_blocksize_bits) - 1;
minlen = range->minlen >> sb->s_blocksize_bits; minlen = range->minlen >> sb->s_blocksize_bits;
if (unlikely(minlen > EXT3_BLOCKS_PER_GROUP(sb)) || if (minlen > EXT3_BLOCKS_PER_GROUP(sb) ||
unlikely(start >= max_blks)) start >= max_blks ||
range->len < sb->s_blocksize)
return -EINVAL; return -EINVAL;
if (end >= max_blks) if (end >= max_blks)
end = max_blks - 1; end = max_blks - 1;
......
...@@ -1782,8 +1782,9 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, ...@@ -1782,8 +1782,9 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
BUG_ON(!th->t_trans_id); BUG_ON(!th->t_trans_id);
dquot_initialize(inode); reiserfs_write_unlock(inode->i_sb);
err = dquot_alloc_inode(inode); err = dquot_alloc_inode(inode);
reiserfs_write_lock(inode->i_sb);
if (err) if (err)
goto out_end_trans; goto out_end_trans;
if (!dir->i_nlink) { if (!dir->i_nlink) {
...@@ -1979,8 +1980,10 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, ...@@ -1979,8 +1980,10 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
out_end_trans: out_end_trans:
journal_end(th, th->t_super, th->t_blocks_allocated); journal_end(th, th->t_super, th->t_blocks_allocated);
reiserfs_write_unlock(inode->i_sb);
/* Drop can be outside and it needs more credits so it's better to have it outside */ /* Drop can be outside and it needs more credits so it's better to have it outside */
dquot_drop(inode); dquot_drop(inode);
reiserfs_write_lock(inode->i_sb);
inode->i_flags |= S_NOQUOTA; inode->i_flags |= S_NOQUOTA;
make_bad_inode(inode); make_bad_inode(inode);
...@@ -3103,10 +3106,9 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -3103,10 +3106,9 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
/* must be turned off for recursive notify_change calls */ /* must be turned off for recursive notify_change calls */
ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID); ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID);
depth = reiserfs_write_lock_once(inode->i_sb);
if (is_quota_modification(inode, attr)) if (is_quota_modification(inode, attr))
dquot_initialize(inode); dquot_initialize(inode);
depth = reiserfs_write_lock_once(inode->i_sb);
if (attr->ia_valid & ATTR_SIZE) { if (attr->ia_valid & ATTR_SIZE) {
/* version 2 items will be caught by the s_maxbytes check /* version 2 items will be caught by the s_maxbytes check
** done for us in vmtruncate ** done for us in vmtruncate
...@@ -3170,7 +3172,9 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -3170,7 +3172,9 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
error = journal_begin(&th, inode->i_sb, jbegin_count); error = journal_begin(&th, inode->i_sb, jbegin_count);
if (error) if (error)
goto out; goto out;
reiserfs_write_unlock_once(inode->i_sb, depth);
error = dquot_transfer(inode, attr); error = dquot_transfer(inode, attr);
depth = reiserfs_write_lock_once(inode->i_sb);
if (error) { if (error) {
journal_end(&th, inode->i_sb, jbegin_count); journal_end(&th, inode->i_sb, jbegin_count);
goto out; goto out;
......
...@@ -1968,7 +1968,9 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct tree ...@@ -1968,7 +1968,9 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct tree
key2type(&(key->on_disk_key))); key2type(&(key->on_disk_key)));
#endif #endif
reiserfs_write_unlock(inode->i_sb);
retval = dquot_alloc_space_nodirty(inode, pasted_size); retval = dquot_alloc_space_nodirty(inode, pasted_size);
reiserfs_write_lock(inode->i_sb);
if (retval) { if (retval) {
pathrelse(search_path); pathrelse(search_path);
return retval; return retval;
...@@ -2061,9 +2063,11 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, ...@@ -2061,9 +2063,11 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
"reiserquota insert_item(): allocating %u id=%u type=%c", "reiserquota insert_item(): allocating %u id=%u type=%c",
quota_bytes, inode->i_uid, head2type(ih)); quota_bytes, inode->i_uid, head2type(ih));
#endif #endif
reiserfs_write_unlock(inode->i_sb);
/* We can't dirty inode here. It would be immediately written but /* We can't dirty inode here. It would be immediately written but
* appropriate stat item isn't inserted yet... */ * appropriate stat item isn't inserted yet... */
retval = dquot_alloc_space_nodirty(inode, quota_bytes); retval = dquot_alloc_space_nodirty(inode, quota_bytes);
reiserfs_write_lock(inode->i_sb);
if (retval) { if (retval) {
pathrelse(path); pathrelse(path);
return retval; return retval;
......
...@@ -298,7 +298,9 @@ static int finish_unfinished(struct super_block *s) ...@@ -298,7 +298,9 @@ static int finish_unfinished(struct super_block *s)
retval = remove_save_link_only(s, &save_link_key, 0); retval = remove_save_link_only(s, &save_link_key, 0);
continue; continue;
} }
reiserfs_write_unlock(s);
dquot_initialize(inode); dquot_initialize(inode);
reiserfs_write_lock(s);
if (truncate && S_ISDIR(inode->i_mode)) { if (truncate && S_ISDIR(inode->i_mode)) {
/* We got a truncate request for a dir which is impossible. /* We got a truncate request for a dir which is impossible.
...@@ -1335,7 +1337,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) ...@@ -1335,7 +1337,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
kfree(qf_names[i]); kfree(qf_names[i]);
#endif #endif
err = -EINVAL; err = -EINVAL;
goto out_err; goto out_unlock;
} }
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA
handle_quota_files(s, qf_names, &qfmt); handle_quota_files(s, qf_names, &qfmt);
...@@ -1379,7 +1381,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) ...@@ -1379,7 +1381,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
if (blocks) { if (blocks) {
err = reiserfs_resize(s, blocks); err = reiserfs_resize(s, blocks);
if (err != 0) if (err != 0)
goto out_err; goto out_unlock;
} }
if (*mount_flags & MS_RDONLY) { if (*mount_flags & MS_RDONLY) {
...@@ -1389,9 +1391,15 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) ...@@ -1389,9 +1391,15 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
/* it is read-only already */ /* it is read-only already */
goto out_ok; goto out_ok;
/*
* Drop write lock. Quota will retake it when needed and lock
* ordering requires calling dquot_suspend() without it.
*/
reiserfs_write_unlock(s);
err = dquot_suspend(s, -1); err = dquot_suspend(s, -1);
if (err < 0) if (err < 0)
goto out_err; goto out_err;
reiserfs_write_lock(s);
/* try to remount file system with read-only permissions */ /* try to remount file system with read-only permissions */
if (sb_umount_state(rs) == REISERFS_VALID_FS if (sb_umount_state(rs) == REISERFS_VALID_FS
...@@ -1401,7 +1409,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) ...@@ -1401,7 +1409,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
err = journal_begin(&th, s, 10); err = journal_begin(&th, s, 10);
if (err) if (err)
goto out_err; goto out_unlock;
/* Mounting a rw partition read-only. */ /* Mounting a rw partition read-only. */
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
...@@ -1416,7 +1424,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) ...@@ -1416,7 +1424,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
if (reiserfs_is_journal_aborted(journal)) { if (reiserfs_is_journal_aborted(journal)) {
err = journal->j_errno; err = journal->j_errno;
goto out_err; goto out_unlock;
} }
handle_data_mode(s, mount_options); handle_data_mode(s, mount_options);
...@@ -1425,7 +1433,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) ...@@ -1425,7 +1433,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
s->s_flags &= ~MS_RDONLY; /* now it is safe to call journal_begin */ s->s_flags &= ~MS_RDONLY; /* now it is safe to call journal_begin */
err = journal_begin(&th, s, 10); err = journal_begin(&th, s, 10);
if (err) if (err)
goto out_err; goto out_unlock;
/* Mount a partition which is read-only, read-write */ /* Mount a partition which is read-only, read-write */
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
...@@ -1442,10 +1450,16 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) ...@@ -1442,10 +1450,16 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
SB_JOURNAL(s)->j_must_wait = 1; SB_JOURNAL(s)->j_must_wait = 1;
err = journal_end(&th, s, 10); err = journal_end(&th, s, 10);
if (err) if (err)
goto out_err; goto out_unlock;
if (!(*mount_flags & MS_RDONLY)) { if (!(*mount_flags & MS_RDONLY)) {
/*
* Drop write lock. Quota will retake it when needed and lock
* ordering requires calling dquot_resume() without it.
*/
reiserfs_write_unlock(s);
dquot_resume(s, -1); dquot_resume(s, -1);
reiserfs_write_lock(s);
finish_unfinished(s); finish_unfinished(s);
reiserfs_xattr_init(s, *mount_flags); reiserfs_xattr_init(s, *mount_flags);
} }
...@@ -1455,9 +1469,10 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) ...@@ -1455,9 +1469,10 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
reiserfs_write_unlock(s); reiserfs_write_unlock(s);
return 0; return 0;
out_unlock:
reiserfs_write_unlock(s);
out_err: out_err:
kfree(new_opts); kfree(new_opts);
reiserfs_write_unlock(s);
return err; return err;
} }
...@@ -2095,13 +2110,15 @@ static int reiserfs_write_dquot(struct dquot *dquot) ...@@ -2095,13 +2110,15 @@ static int reiserfs_write_dquot(struct dquot *dquot)
REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
if (ret) if (ret)
goto out; goto out;
reiserfs_write_unlock(dquot->dq_sb);
ret = dquot_commit(dquot); ret = dquot_commit(dquot);
reiserfs_write_lock(dquot->dq_sb);
err = err =
journal_end(&th, dquot->dq_sb, journal_end(&th, dquot->dq_sb,
REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
if (!ret && err) if (!ret && err)
ret = err; ret = err;
out: out:
reiserfs_write_unlock(dquot->dq_sb); reiserfs_write_unlock(dquot->dq_sb);
return ret; return ret;
} }
...@@ -2117,13 +2134,15 @@ static int reiserfs_acquire_dquot(struct dquot *dquot) ...@@ -2117,13 +2134,15 @@ static int reiserfs_acquire_dquot(struct dquot *dquot)
REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb));
if (ret) if (ret)
goto out; goto out;
reiserfs_write_unlock(dquot->dq_sb);
ret = dquot_acquire(dquot); ret = dquot_acquire(dquot);
reiserfs_write_lock(dquot->dq_sb);
err = err =
journal_end(&th, dquot->dq_sb, journal_end(&th, dquot->dq_sb,
REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb));
if (!ret && err) if (!ret && err)
ret = err; ret = err;
out: out:
reiserfs_write_unlock(dquot->dq_sb); reiserfs_write_unlock(dquot->dq_sb);
return ret; return ret;
} }
...@@ -2137,19 +2156,21 @@ static int reiserfs_release_dquot(struct dquot *dquot) ...@@ -2137,19 +2156,21 @@ static int reiserfs_release_dquot(struct dquot *dquot)
ret = ret =
journal_begin(&th, dquot->dq_sb, journal_begin(&th, dquot->dq_sb,
REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
reiserfs_write_unlock(dquot->dq_sb);
if (ret) { if (ret) {
/* Release dquot anyway to avoid endless cycle in dqput() */ /* Release dquot anyway to avoid endless cycle in dqput() */
dquot_release(dquot); dquot_release(dquot);
goto out; goto out;
} }
ret = dquot_release(dquot); ret = dquot_release(dquot);
reiserfs_write_lock(dquot->dq_sb);
err = err =
journal_end(&th, dquot->dq_sb, journal_end(&th, dquot->dq_sb,
REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
if (!ret && err) if (!ret && err)
ret = err; ret = err;
out:
reiserfs_write_unlock(dquot->dq_sb); reiserfs_write_unlock(dquot->dq_sb);
out:
return ret; return ret;
} }
...@@ -2174,11 +2195,13 @@ static int reiserfs_write_info(struct super_block *sb, int type) ...@@ -2174,11 +2195,13 @@ static int reiserfs_write_info(struct super_block *sb, int type)
ret = journal_begin(&th, sb, 2); ret = journal_begin(&th, sb, 2);
if (ret) if (ret)
goto out; goto out;
reiserfs_write_unlock(sb);
ret = dquot_commit_info(sb, type); ret = dquot_commit_info(sb, type);
reiserfs_write_lock(sb);
err = journal_end(&th, sb, 2); err = journal_end(&th, sb, 2);
if (!ret && err) if (!ret && err)
ret = err; ret = err;
out: out:
reiserfs_write_unlock(sb); reiserfs_write_unlock(sb);
return ret; return ret;
} }
...@@ -2203,8 +2226,11 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, ...@@ -2203,8 +2226,11 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
struct reiserfs_transaction_handle th; struct reiserfs_transaction_handle th;
int opt = type == USRQUOTA ? REISERFS_USRQUOTA : REISERFS_GRPQUOTA; int opt = type == USRQUOTA ? REISERFS_USRQUOTA : REISERFS_GRPQUOTA;
if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt))) reiserfs_write_lock(sb);
return -EINVAL; if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt))) {
err = -EINVAL;
goto out;
}
/* Quotafile not on the same filesystem? */ /* Quotafile not on the same filesystem? */
if (path->dentry->d_sb != sb) { if (path->dentry->d_sb != sb) {
...@@ -2246,8 +2272,10 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, ...@@ -2246,8 +2272,10 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
if (err) if (err)
goto out; goto out;
} }
err = dquot_quota_on(sb, type, format_id, path); reiserfs_write_unlock(sb);
return dquot_quota_on(sb, type, format_id, path);
out: out:
reiserfs_write_unlock(sb);
return err; return err;
} }
...@@ -2320,7 +2348,9 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type, ...@@ -2320,7 +2348,9 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
tocopy = sb->s_blocksize - offset < towrite ? tocopy = sb->s_blocksize - offset < towrite ?
sb->s_blocksize - offset : towrite; sb->s_blocksize - offset : towrite;
tmp_bh.b_state = 0; tmp_bh.b_state = 0;
reiserfs_write_lock(sb);
err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE); err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE);
reiserfs_write_unlock(sb);
if (err) if (err)
goto out; goto out;
if (offset || tocopy != sb->s_blocksize) if (offset || tocopy != sb->s_blocksize)
...@@ -2336,10 +2366,12 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type, ...@@ -2336,10 +2366,12 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
flush_dcache_page(bh->b_page); flush_dcache_page(bh->b_page);
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
unlock_buffer(bh); unlock_buffer(bh);
reiserfs_write_lock(sb);
reiserfs_prepare_for_journal(sb, bh, 1); reiserfs_prepare_for_journal(sb, bh, 1);
journal_mark_dirty(current->journal_info, sb, bh); journal_mark_dirty(current->journal_info, sb, bh);
if (!journal_quota) if (!journal_quota)
reiserfs_add_ordered_list(inode, bh); reiserfs_add_ordered_list(inode, bh);
reiserfs_write_unlock(sb);
brelse(bh); brelse(bh);
offset = 0; offset = 0;
towrite -= tocopy; towrite -= tocopy;
......
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