|
@@ -64,18 +64,15 @@ static int quota_sync_all(int type)
|
|
|
}
|
|
|
|
|
|
static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
|
|
|
- void __user *addr)
|
|
|
+ struct path *path)
|
|
|
{
|
|
|
- char *pathname;
|
|
|
- int ret = -ENOSYS;
|
|
|
-
|
|
|
- pathname = getname(addr);
|
|
|
- if (IS_ERR(pathname))
|
|
|
- return PTR_ERR(pathname);
|
|
|
- if (sb->s_qcop->quota_on)
|
|
|
- ret = sb->s_qcop->quota_on(sb, type, id, pathname);
|
|
|
- putname(pathname);
|
|
|
- return ret;
|
|
|
+ if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta)
|
|
|
+ return -ENOSYS;
|
|
|
+ if (sb->s_qcop->quota_on_meta)
|
|
|
+ return sb->s_qcop->quota_on_meta(sb, type, id);
|
|
|
+ if (IS_ERR(path))
|
|
|
+ return PTR_ERR(path);
|
|
|
+ return sb->s_qcop->quota_on(sb, type, id, path);
|
|
|
}
|
|
|
|
|
|
static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
|
|
@@ -241,7 +238,7 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id,
|
|
|
|
|
|
/* Copy parameters and call proper function */
|
|
|
static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
|
|
|
- void __user *addr)
|
|
|
+ void __user *addr, struct path *path)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
@@ -256,7 +253,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
|
|
|
|
|
|
switch (cmd) {
|
|
|
case Q_QUOTAON:
|
|
|
- return quota_quotaon(sb, type, cmd, id, addr);
|
|
|
+ return quota_quotaon(sb, type, cmd, id, path);
|
|
|
case Q_QUOTAOFF:
|
|
|
if (!sb->s_qcop->quota_off)
|
|
|
return -ENOSYS;
|
|
@@ -335,6 +332,7 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
|
|
|
{
|
|
|
uint cmds, type;
|
|
|
struct super_block *sb = NULL;
|
|
|
+ struct path path, *pathp = NULL;
|
|
|
int ret;
|
|
|
|
|
|
cmds = cmd >> SUBCMDSHIFT;
|
|
@@ -351,12 +349,27 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Path for quotaon has to be resolved before grabbing superblock
|
|
|
+ * because that gets s_umount sem which is also possibly needed by path
|
|
|
+ * resolution (think about autofs) and thus deadlocks could arise.
|
|
|
+ */
|
|
|
+ if (cmds == Q_QUOTAON) {
|
|
|
+ ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW, &path);
|
|
|
+ if (ret)
|
|
|
+ pathp = ERR_PTR(ret);
|
|
|
+ else
|
|
|
+ pathp = &path;
|
|
|
+ }
|
|
|
+
|
|
|
sb = quotactl_block(special);
|
|
|
if (IS_ERR(sb))
|
|
|
return PTR_ERR(sb);
|
|
|
|
|
|
- ret = do_quotactl(sb, type, cmds, id, addr);
|
|
|
+ ret = do_quotactl(sb, type, cmds, id, addr, pathp);
|
|
|
|
|
|
drop_super(sb);
|
|
|
+ if (pathp && !IS_ERR(pathp))
|
|
|
+ path_put(pathp);
|
|
|
return ret;
|
|
|
}
|