/* * This is the system call interface. This communicates with * the user-level programs. Currently this only supports diskquota * calls. Maybe we need to add the process quotas etc. in the future, * but we probably should use rlimits for that. */ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special, qid_t, id, void __user *, addr) { uint cmds, type; struct super_block *sb = NULL; struct path path, *pathp = NULL; int ret; cmds = cmd >> SUBCMDSHIFT; type = cmd & SUBCMDMASK; /* * As a special case Q_SYNC can be called without a specific device. * It will iterate all superblocks that have quota enabled and call * the sync action on each of them. */ if (!special) { if (cmds == Q_SYNC) return quota_sync_all(type); 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|LOOKUP_AUTOMOUNT, &path); if (ret) pathp = ERR_PTR(ret); else pathp = &path; } sb = quotactl_block(special, cmds); if (IS_ERR(sb)) { ret = PTR_ERR(sb); goto out; } ret = do_quotactl(sb, type, cmds, id, addr, pathp); drop_super(sb); out: if (pathp && !IS_ERR(pathp)) path_put(pathp); return ret; }
/* * This is the system call interface. This communicates with * the user-level programs. Currently this only supports diskquota * calls. Maybe we need to add the process quotas etc. in the future, * but we probably should use rlimits for that. */ asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, caddr_t addr) { uint cmds, type; struct super_block *sb = NULL; int ret = -EINVAL; lock_kernel(); cmds = cmd >> SUBCMDSHIFT; type = cmd & SUBCMDMASK; #ifdef CONFIG_QIFACE_COMPAT if (cmds != Q_V1_GETSTATS && cmds != Q_V2_GETSTATS && IS_ERR(sb = resolve_dev(special))) { ret = PTR_ERR(sb); sb = NULL; goto out; } if (!NEW_COMMAND(cmds) && !XQM_COMMAND(cmds)) { if ((ret = check_compat_quotactl_valid(sb, type, cmds, id)) < 0) goto out; ret = do_compat_quotactl(sb, type, cmds, id, addr); goto out; } #else if (IS_ERR(sb = resolve_dev(special))) { ret = PTR_ERR(sb); sb = NULL; goto out; } #endif if ((ret = check_quotactl_valid(sb, type, cmds, id)) < 0) goto out; ret = do_quotactl(sb, type, cmds, id, addr); out: if (sb) drop_super(sb); unlock_kernel(); return ret; }
/* * do_quotas() * do quotactl commands */ static int do_quotas(const dev_info_t *dev, const char *name) { int tested = 0, failed = 0, enosys = 0; #if defined(Q_GETQUOTA) if (opt_do_run) { struct dqblk dqblk; do_quotactl(name, DO_Q_GETQUOTA, "Q_GETQUOTA", &tested, &failed, &enosys, QCMD(Q_GETQUOTA, USRQUOTA), dev->name, 0, (caddr_t)&dqblk); } #endif #if defined(Q_GETFMT) if (opt_do_run) { uint32_t format; do_quotactl(name, DO_Q_GETFMT, "Q_GETFMT", &tested, &failed, &enosys, QCMD(Q_GETFMT, USRQUOTA), dev->name, 0, (caddr_t)&format); } #endif #if defined(Q_GETINFO) if (opt_do_run) { struct dqinfo dqinfo; do_quotactl(name, DO_Q_GETINFO, "Q_GETINFO", &tested, &failed, &enosys, QCMD(Q_GETINFO, USRQUOTA), dev->name, 0, (caddr_t)&dqinfo); } #endif #if defined(Q_GETSTATS) /* Obsolete in recent kernels */ if (opt_do_run) { struct dqstats dqstats; do_quotactl(name, DO_Q_GETSTATS, "Q_GETSTATS", &tested, &failed, &enosys, QCMD(Q_GETSTATS, USRQUOTA), dev->name, 0, (caddr_t)&dqstats); } #endif #if defined(Q_SYNC) if (opt_do_run) { do_quotactl(name, DO_Q_SYNC, "Q_SYNC", &tested, &failed, &enosys, QCMD(Q_SYNC, USRQUOTA), dev->name, 0, 0); } #endif if (tested == 0) { pr_err(stderr, "%s: quotactl() failed, quota commands not available\n", name); return -1; } if (tested == enosys) { pr_err(stderr, "%s: quotactl() failed, not available on this kernel\n", name); return -1; } if (tested == failed) { pr_err(stderr, "%s: quotactl() failed, all quota commands failed (maybe privilege issues, use -v to see why)\n", name); return -1; } return 0; }