diff options
author | Jan Kara <jack@suse.cz> | 2010-09-15 11:38:58 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2011-01-12 13:14:55 -0500 |
commit | f00c9e44ad1a9660fe8cd3ca15b6cd9497172eab (patch) | |
tree | cbb47ae0d8aba9d8b3c44714b000156715cdf969 /fs/reiserfs/super.c | |
parent | 4162cf64973df51fc885825bc9ca4d055891c49f (diff) |
quota: Fix deadlock during path resolution
As Al Viro pointed out path resolution during Q_QUOTAON calls to quotactl
is prone to deadlocks. We hold s_umount semaphore for reading during the
path resolution and resolution itself may need to acquire the semaphore
for writing when e. g. autofs mountpoint is passed.
Solve the problem by performing the resolution before we get hold of the
superblock (and thus s_umount semaphore). The whole thing is complicated
by the fact that some filesystems (OCFS2) ignore the path argument. So to
distinguish between filesystem which want the path and which do not we
introduce new .quota_on_meta callback which does not get the path. OCFS2
then uses this callback instead of old .quota_on.
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Christoph Hellwig <hch@lst.de>
CC: Ted Ts'o <tytso@mit.edu>
CC: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/reiserfs/super.c')
-rw-r--r-- | fs/reiserfs/super.c | 17 |
1 files changed, 6 insertions, 11 deletions
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 2575682a9ead..0aab04f46827 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -632,7 +632,7 @@ static int reiserfs_acquire_dquot(struct dquot *); | |||
632 | static int reiserfs_release_dquot(struct dquot *); | 632 | static int reiserfs_release_dquot(struct dquot *); |
633 | static int reiserfs_mark_dquot_dirty(struct dquot *); | 633 | static int reiserfs_mark_dquot_dirty(struct dquot *); |
634 | static int reiserfs_write_info(struct super_block *, int); | 634 | static int reiserfs_write_info(struct super_block *, int); |
635 | static int reiserfs_quota_on(struct super_block *, int, int, char *); | 635 | static int reiserfs_quota_on(struct super_block *, int, int, struct path *); |
636 | 636 | ||
637 | static const struct dquot_operations reiserfs_quota_operations = { | 637 | static const struct dquot_operations reiserfs_quota_operations = { |
638 | .write_dquot = reiserfs_write_dquot, | 638 | .write_dquot = reiserfs_write_dquot, |
@@ -2048,25 +2048,21 @@ static int reiserfs_quota_on_mount(struct super_block *sb, int type) | |||
2048 | * Standard function to be called on quota_on | 2048 | * Standard function to be called on quota_on |
2049 | */ | 2049 | */ |
2050 | static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, | 2050 | static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, |
2051 | char *name) | 2051 | struct path *path) |
2052 | { | 2052 | { |
2053 | int err; | 2053 | int err; |
2054 | struct path path; | ||
2055 | struct inode *inode; | 2054 | struct inode *inode; |
2056 | struct reiserfs_transaction_handle th; | 2055 | struct reiserfs_transaction_handle th; |
2057 | 2056 | ||
2058 | if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA))) | 2057 | if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA))) |
2059 | return -EINVAL; | 2058 | return -EINVAL; |
2060 | 2059 | ||
2061 | err = kern_path(name, LOOKUP_FOLLOW, &path); | ||
2062 | if (err) | ||
2063 | return err; | ||
2064 | /* Quotafile not on the same filesystem? */ | 2060 | /* Quotafile not on the same filesystem? */ |
2065 | if (path.mnt->mnt_sb != sb) { | 2061 | if (path->mnt->mnt_sb != sb) { |
2066 | err = -EXDEV; | 2062 | err = -EXDEV; |
2067 | goto out; | 2063 | goto out; |
2068 | } | 2064 | } |
2069 | inode = path.dentry->d_inode; | 2065 | inode = path->dentry->d_inode; |
2070 | /* We must not pack tails for quota files on reiserfs for quota IO to work */ | 2066 | /* We must not pack tails for quota files on reiserfs for quota IO to work */ |
2071 | if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) { | 2067 | if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) { |
2072 | err = reiserfs_unpack(inode, NULL); | 2068 | err = reiserfs_unpack(inode, NULL); |
@@ -2082,7 +2078,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, | |||
2082 | /* Journaling quota? */ | 2078 | /* Journaling quota? */ |
2083 | if (REISERFS_SB(sb)->s_qf_names[type]) { | 2079 | if (REISERFS_SB(sb)->s_qf_names[type]) { |
2084 | /* Quotafile not of fs root? */ | 2080 | /* Quotafile not of fs root? */ |
2085 | if (path.dentry->d_parent != sb->s_root) | 2081 | if (path->dentry->d_parent != sb->s_root) |
2086 | reiserfs_warning(sb, "super-6521", | 2082 | reiserfs_warning(sb, "super-6521", |
2087 | "Quota file not on filesystem root. " | 2083 | "Quota file not on filesystem root. " |
2088 | "Journalled quota will not work."); | 2084 | "Journalled quota will not work."); |
@@ -2101,9 +2097,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, | |||
2101 | if (err) | 2097 | if (err) |
2102 | goto out; | 2098 | goto out; |
2103 | } | 2099 | } |
2104 | err = dquot_quota_on_path(sb, type, format_id, &path); | 2100 | err = dquot_quota_on(sb, type, format_id, path); |
2105 | out: | 2101 | out: |
2106 | path_put(&path); | ||
2107 | return err; | 2102 | return err; |
2108 | } | 2103 | } |
2109 | 2104 | ||