1884d179dSJan Kara /* 2884d179dSJan Kara * Quota code necessary even when VFS quota support is not compiled 3884d179dSJan Kara * into the kernel. The interesting stuff is over in dquot.c, here 4884d179dSJan Kara * we have symbols for initial quotactl(2) handling, the sysctl(2) 5884d179dSJan Kara * variables, etc - things needed even when quota support disabled. 6884d179dSJan Kara */ 7884d179dSJan Kara 8884d179dSJan Kara #include <linux/fs.h> 9884d179dSJan Kara #include <linux/namei.h> 10884d179dSJan Kara #include <linux/slab.h> 11884d179dSJan Kara #include <asm/current.h> 12884d179dSJan Kara #include <asm/uaccess.h> 13884d179dSJan Kara #include <linux/kernel.h> 14884d179dSJan Kara #include <linux/security.h> 15884d179dSJan Kara #include <linux/syscalls.h> 16884d179dSJan Kara #include <linux/buffer_head.h> 17884d179dSJan Kara #include <linux/capability.h> 18884d179dSJan Kara #include <linux/quotaops.h> 19884d179dSJan Kara #include <linux/types.h> 208c4e4acdSChristoph Hellwig #include <linux/writeback.h> 21884d179dSJan Kara 22c988afb5SChristoph Hellwig static int check_quotactl_permission(struct super_block *sb, int type, int cmd, 23268157baSJan Kara qid_t id) 24884d179dSJan Kara { 25c988afb5SChristoph Hellwig switch (cmd) { 26c988afb5SChristoph Hellwig /* these commands do not require any special privilegues */ 27c988afb5SChristoph Hellwig case Q_GETFMT: 28c988afb5SChristoph Hellwig case Q_SYNC: 29c988afb5SChristoph Hellwig case Q_GETINFO: 30c988afb5SChristoph Hellwig case Q_XGETQSTAT: 31c988afb5SChristoph Hellwig case Q_XQUOTASYNC: 32c988afb5SChristoph Hellwig break; 33c988afb5SChristoph Hellwig /* allow to query information for dquots we "own" */ 34c988afb5SChristoph Hellwig case Q_GETQUOTA: 35c988afb5SChristoph Hellwig case Q_XGETQUOTA: 36c988afb5SChristoph Hellwig if ((type == USRQUOTA && current_euid() == id) || 37c988afb5SChristoph Hellwig (type == GRPQUOTA && in_egroup_p(id))) 38c988afb5SChristoph Hellwig break; 39c988afb5SChristoph Hellwig /*FALLTHROUGH*/ 40c988afb5SChristoph Hellwig default: 41884d179dSJan Kara if (!capable(CAP_SYS_ADMIN)) 42884d179dSJan Kara return -EPERM; 43884d179dSJan Kara } 44884d179dSJan Kara 45c988afb5SChristoph Hellwig return security_quotactl(cmd, type, id, sb); 46884d179dSJan Kara } 47884d179dSJan Kara 486ae09575SChristoph Hellwig static int quota_sync_all(int type) 49884d179dSJan Kara { 50850b201bSChristoph Hellwig struct super_block *sb; 516ae09575SChristoph Hellwig int ret; 526ae09575SChristoph Hellwig 536ae09575SChristoph Hellwig if (type >= MAXQUOTAS) 546ae09575SChristoph Hellwig return -EINVAL; 556ae09575SChristoph Hellwig ret = security_quotactl(Q_SYNC, type, 0, NULL); 566ae09575SChristoph Hellwig if (ret) 576ae09575SChristoph Hellwig return ret; 58884d179dSJan Kara 59884d179dSJan Kara spin_lock(&sb_lock); 60884d179dSJan Kara restart: 61884d179dSJan Kara list_for_each_entry(sb, &super_blocks, s_list) { 625fb324adSChristoph Hellwig if (!sb->s_qcop || !sb->s_qcop->quota_sync) 635fb324adSChristoph Hellwig continue; 645fb324adSChristoph Hellwig 65884d179dSJan Kara sb->s_count++; 66884d179dSJan Kara spin_unlock(&sb_lock); 67884d179dSJan Kara down_read(&sb->s_umount); 68850b201bSChristoph Hellwig if (sb->s_root) 695fb324adSChristoph Hellwig sb->s_qcop->quota_sync(sb, type, 1); 70884d179dSJan Kara up_read(&sb->s_umount); 71884d179dSJan Kara spin_lock(&sb_lock); 72884d179dSJan Kara if (__put_super_and_need_restart(sb)) 73884d179dSJan Kara goto restart; 74884d179dSJan Kara } 75884d179dSJan Kara spin_unlock(&sb_lock); 766ae09575SChristoph Hellwig 776ae09575SChristoph Hellwig return 0; 78884d179dSJan Kara } 79884d179dSJan Kara 80c411e5f6SChristoph Hellwig static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id, 81268157baSJan Kara void __user *addr) 82884d179dSJan Kara { 83884d179dSJan Kara char *pathname; 84f450d4feSChristoph Hellwig int ret = -ENOSYS; 85884d179dSJan Kara 86268157baSJan Kara pathname = getname(addr); 87268157baSJan Kara if (IS_ERR(pathname)) 88884d179dSJan Kara return PTR_ERR(pathname); 89f450d4feSChristoph Hellwig if (sb->s_qcop->quota_on) 90884d179dSJan Kara ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0); 91884d179dSJan Kara putname(pathname); 92884d179dSJan Kara return ret; 93884d179dSJan Kara } 94884d179dSJan Kara 95c411e5f6SChristoph Hellwig static int quota_getfmt(struct super_block *sb, int type, void __user *addr) 96c411e5f6SChristoph Hellwig { 97884d179dSJan Kara __u32 fmt; 98884d179dSJan Kara 99884d179dSJan Kara down_read(&sb_dqopt(sb)->dqptr_sem); 100884d179dSJan Kara if (!sb_has_quota_active(sb, type)) { 101884d179dSJan Kara up_read(&sb_dqopt(sb)->dqptr_sem); 102884d179dSJan Kara return -ESRCH; 103884d179dSJan Kara } 104884d179dSJan Kara fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id; 105884d179dSJan Kara up_read(&sb_dqopt(sb)->dqptr_sem); 106884d179dSJan Kara if (copy_to_user(addr, &fmt, sizeof(fmt))) 107884d179dSJan Kara return -EFAULT; 108884d179dSJan Kara return 0; 109884d179dSJan Kara } 110c411e5f6SChristoph Hellwig 111c411e5f6SChristoph Hellwig static int quota_getinfo(struct super_block *sb, int type, void __user *addr) 112c411e5f6SChristoph Hellwig { 113884d179dSJan Kara struct if_dqinfo info; 114c411e5f6SChristoph Hellwig int ret; 115884d179dSJan Kara 116f450d4feSChristoph Hellwig if (!sb_has_quota_active(sb, type)) 117f450d4feSChristoph Hellwig return -ESRCH; 118f450d4feSChristoph Hellwig if (!sb->s_qcop->get_info) 119f450d4feSChristoph Hellwig return -ENOSYS; 120268157baSJan Kara ret = sb->s_qcop->get_info(sb, type, &info); 121c411e5f6SChristoph Hellwig if (!ret && copy_to_user(addr, &info, sizeof(info))) 122884d179dSJan Kara return -EFAULT; 123c411e5f6SChristoph Hellwig return ret; 124884d179dSJan Kara } 125c411e5f6SChristoph Hellwig 126c411e5f6SChristoph Hellwig static int quota_setinfo(struct super_block *sb, int type, void __user *addr) 127c411e5f6SChristoph Hellwig { 128884d179dSJan Kara struct if_dqinfo info; 129884d179dSJan Kara 130884d179dSJan Kara if (copy_from_user(&info, addr, sizeof(info))) 131884d179dSJan Kara return -EFAULT; 132f450d4feSChristoph Hellwig if (!sb_has_quota_active(sb, type)) 133f450d4feSChristoph Hellwig return -ESRCH; 134f450d4feSChristoph Hellwig if (!sb->s_qcop->set_info) 135f450d4feSChristoph Hellwig return -ENOSYS; 136884d179dSJan Kara return sb->s_qcop->set_info(sb, type, &info); 137884d179dSJan Kara } 138c411e5f6SChristoph Hellwig 139b9b2dd36SChristoph Hellwig static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src) 140b9b2dd36SChristoph Hellwig { 141b9b2dd36SChristoph Hellwig dst->dqb_bhardlimit = src->d_blk_hardlimit; 142b9b2dd36SChristoph Hellwig dst->dqb_bsoftlimit = src->d_blk_softlimit; 143b9b2dd36SChristoph Hellwig dst->dqb_curspace = src->d_bcount; 144b9b2dd36SChristoph Hellwig dst->dqb_ihardlimit = src->d_ino_hardlimit; 145b9b2dd36SChristoph Hellwig dst->dqb_isoftlimit = src->d_ino_softlimit; 146b9b2dd36SChristoph Hellwig dst->dqb_curinodes = src->d_icount; 147b9b2dd36SChristoph Hellwig dst->dqb_btime = src->d_btimer; 148b9b2dd36SChristoph Hellwig dst->dqb_itime = src->d_itimer; 149b9b2dd36SChristoph Hellwig dst->dqb_valid = QIF_ALL; 150b9b2dd36SChristoph Hellwig } 151b9b2dd36SChristoph Hellwig 152c411e5f6SChristoph Hellwig static int quota_getquota(struct super_block *sb, int type, qid_t id, 153c411e5f6SChristoph Hellwig void __user *addr) 154c411e5f6SChristoph Hellwig { 155b9b2dd36SChristoph Hellwig struct fs_disk_quota fdq; 156884d179dSJan Kara struct if_dqblk idq; 157c411e5f6SChristoph Hellwig int ret; 158884d179dSJan Kara 159f450d4feSChristoph Hellwig if (!sb->s_qcop->get_dqblk) 160f450d4feSChristoph Hellwig return -ENOSYS; 161b9b2dd36SChristoph Hellwig ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq); 162268157baSJan Kara if (ret) 163884d179dSJan Kara return ret; 164b9b2dd36SChristoph Hellwig copy_to_if_dqblk(&idq, &fdq); 165884d179dSJan Kara if (copy_to_user(addr, &idq, sizeof(idq))) 166884d179dSJan Kara return -EFAULT; 167884d179dSJan Kara return 0; 168884d179dSJan Kara } 169c411e5f6SChristoph Hellwig 170*c472b432SChristoph Hellwig static void copy_from_if_dqblk(struct fs_disk_quota *dst, struct if_dqblk *src) 171*c472b432SChristoph Hellwig { 172*c472b432SChristoph Hellwig dst->d_blk_hardlimit = src->dqb_bhardlimit; 173*c472b432SChristoph Hellwig dst->d_blk_softlimit = src->dqb_bsoftlimit; 174*c472b432SChristoph Hellwig dst->d_bcount = src->dqb_curspace; 175*c472b432SChristoph Hellwig dst->d_ino_hardlimit = src->dqb_ihardlimit; 176*c472b432SChristoph Hellwig dst->d_ino_softlimit = src->dqb_isoftlimit; 177*c472b432SChristoph Hellwig dst->d_icount = src->dqb_curinodes; 178*c472b432SChristoph Hellwig dst->d_btimer = src->dqb_btime; 179*c472b432SChristoph Hellwig dst->d_itimer = src->dqb_itime; 180*c472b432SChristoph Hellwig 181*c472b432SChristoph Hellwig dst->d_fieldmask = 0; 182*c472b432SChristoph Hellwig if (src->dqb_valid & QIF_BLIMITS) 183*c472b432SChristoph Hellwig dst->d_fieldmask |= FS_DQ_BSOFT | FS_DQ_BHARD; 184*c472b432SChristoph Hellwig if (src->dqb_valid & QIF_SPACE) 185*c472b432SChristoph Hellwig dst->d_fieldmask |= FS_DQ_BCOUNT; 186*c472b432SChristoph Hellwig if (src->dqb_valid & QIF_ILIMITS) 187*c472b432SChristoph Hellwig dst->d_fieldmask |= FS_DQ_ISOFT | FS_DQ_IHARD; 188*c472b432SChristoph Hellwig if (src->dqb_valid & QIF_INODES) 189*c472b432SChristoph Hellwig dst->d_fieldmask |= FS_DQ_ICOUNT; 190*c472b432SChristoph Hellwig if (src->dqb_valid & QIF_BTIME) 191*c472b432SChristoph Hellwig dst->d_fieldmask |= FS_DQ_BTIMER; 192*c472b432SChristoph Hellwig if (src->dqb_valid & QIF_ITIME) 193*c472b432SChristoph Hellwig dst->d_fieldmask |= FS_DQ_ITIMER; 194*c472b432SChristoph Hellwig } 195*c472b432SChristoph Hellwig 196c411e5f6SChristoph Hellwig static int quota_setquota(struct super_block *sb, int type, qid_t id, 197c411e5f6SChristoph Hellwig void __user *addr) 198c411e5f6SChristoph Hellwig { 199*c472b432SChristoph Hellwig struct fs_disk_quota fdq; 200884d179dSJan Kara struct if_dqblk idq; 201884d179dSJan Kara 202884d179dSJan Kara if (copy_from_user(&idq, addr, sizeof(idq))) 203884d179dSJan Kara return -EFAULT; 204f450d4feSChristoph Hellwig if (!sb->s_qcop->set_dqblk) 205f450d4feSChristoph Hellwig return -ENOSYS; 206*c472b432SChristoph Hellwig copy_from_if_dqblk(&fdq, &idq); 207*c472b432SChristoph Hellwig return sb->s_qcop->set_dqblk(sb, type, id, &fdq); 208884d179dSJan Kara } 209884d179dSJan Kara 210c411e5f6SChristoph Hellwig static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr) 211c411e5f6SChristoph Hellwig { 212884d179dSJan Kara __u32 flags; 213884d179dSJan Kara 214884d179dSJan Kara if (copy_from_user(&flags, addr, sizeof(flags))) 215884d179dSJan Kara return -EFAULT; 216f450d4feSChristoph Hellwig if (!sb->s_qcop->set_xstate) 217f450d4feSChristoph Hellwig return -ENOSYS; 218884d179dSJan Kara return sb->s_qcop->set_xstate(sb, flags, cmd); 219884d179dSJan Kara } 220884d179dSJan Kara 221c411e5f6SChristoph Hellwig static int quota_getxstate(struct super_block *sb, void __user *addr) 222c411e5f6SChristoph Hellwig { 223c411e5f6SChristoph Hellwig struct fs_quota_stat fqs; 224c411e5f6SChristoph Hellwig int ret; 225c411e5f6SChristoph Hellwig 226f450d4feSChristoph Hellwig if (!sb->s_qcop->get_xstate) 227f450d4feSChristoph Hellwig return -ENOSYS; 228c411e5f6SChristoph Hellwig ret = sb->s_qcop->get_xstate(sb, &fqs); 229c411e5f6SChristoph Hellwig if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) 230884d179dSJan Kara return -EFAULT; 231c411e5f6SChristoph Hellwig return ret; 232884d179dSJan Kara } 233c411e5f6SChristoph Hellwig 234c411e5f6SChristoph Hellwig static int quota_setxquota(struct super_block *sb, int type, qid_t id, 235c411e5f6SChristoph Hellwig void __user *addr) 236c411e5f6SChristoph Hellwig { 237884d179dSJan Kara struct fs_disk_quota fdq; 238884d179dSJan Kara 239884d179dSJan Kara if (copy_from_user(&fdq, addr, sizeof(fdq))) 240884d179dSJan Kara return -EFAULT; 241*c472b432SChristoph Hellwig if (!sb->s_qcop->set_dqblk) 242f450d4feSChristoph Hellwig return -ENOSYS; 243*c472b432SChristoph Hellwig return sb->s_qcop->set_dqblk(sb, type, id, &fdq); 244884d179dSJan Kara } 245c411e5f6SChristoph Hellwig 246c411e5f6SChristoph Hellwig static int quota_getxquota(struct super_block *sb, int type, qid_t id, 247c411e5f6SChristoph Hellwig void __user *addr) 248c411e5f6SChristoph Hellwig { 249884d179dSJan Kara struct fs_disk_quota fdq; 250c411e5f6SChristoph Hellwig int ret; 251884d179dSJan Kara 252b9b2dd36SChristoph Hellwig if (!sb->s_qcop->get_dqblk) 253f450d4feSChristoph Hellwig return -ENOSYS; 254b9b2dd36SChristoph Hellwig ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq); 255c411e5f6SChristoph Hellwig if (!ret && copy_to_user(addr, &fdq, sizeof(fdq))) 256884d179dSJan Kara return -EFAULT; 257c411e5f6SChristoph Hellwig return ret; 258884d179dSJan Kara } 259c411e5f6SChristoph Hellwig 260c411e5f6SChristoph Hellwig /* Copy parameters and call proper function */ 261c411e5f6SChristoph Hellwig static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, 262c411e5f6SChristoph Hellwig void __user *addr) 263c411e5f6SChristoph Hellwig { 264c988afb5SChristoph Hellwig int ret; 265c988afb5SChristoph Hellwig 266c988afb5SChristoph Hellwig if (type >= (XQM_COMMAND(cmd) ? XQM_MAXQUOTAS : MAXQUOTAS)) 267c988afb5SChristoph Hellwig return -EINVAL; 268c988afb5SChristoph Hellwig if (!sb->s_qcop) 269c988afb5SChristoph Hellwig return -ENOSYS; 270c988afb5SChristoph Hellwig 271c988afb5SChristoph Hellwig ret = check_quotactl_permission(sb, type, cmd, id); 272c988afb5SChristoph Hellwig if (ret < 0) 273c988afb5SChristoph Hellwig return ret; 274c988afb5SChristoph Hellwig 275c411e5f6SChristoph Hellwig switch (cmd) { 276c411e5f6SChristoph Hellwig case Q_QUOTAON: 277c411e5f6SChristoph Hellwig return quota_quotaon(sb, type, cmd, id, addr); 278c411e5f6SChristoph Hellwig case Q_QUOTAOFF: 279f450d4feSChristoph Hellwig if (!sb->s_qcop->quota_off) 280f450d4feSChristoph Hellwig return -ENOSYS; 281c411e5f6SChristoph Hellwig return sb->s_qcop->quota_off(sb, type, 0); 282c411e5f6SChristoph Hellwig case Q_GETFMT: 283c411e5f6SChristoph Hellwig return quota_getfmt(sb, type, addr); 284c411e5f6SChristoph Hellwig case Q_GETINFO: 285c411e5f6SChristoph Hellwig return quota_getinfo(sb, type, addr); 286c411e5f6SChristoph Hellwig case Q_SETINFO: 287c411e5f6SChristoph Hellwig return quota_setinfo(sb, type, addr); 288c411e5f6SChristoph Hellwig case Q_GETQUOTA: 289c411e5f6SChristoph Hellwig return quota_getquota(sb, type, id, addr); 290c411e5f6SChristoph Hellwig case Q_SETQUOTA: 291c411e5f6SChristoph Hellwig return quota_setquota(sb, type, id, addr); 292c411e5f6SChristoph Hellwig case Q_SYNC: 293f450d4feSChristoph Hellwig if (!sb->s_qcop->quota_sync) 294f450d4feSChristoph Hellwig return -ENOSYS; 2955fb324adSChristoph Hellwig return sb->s_qcop->quota_sync(sb, type, 1); 296c411e5f6SChristoph Hellwig case Q_XQUOTAON: 297c411e5f6SChristoph Hellwig case Q_XQUOTAOFF: 298c411e5f6SChristoph Hellwig case Q_XQUOTARM: 299c411e5f6SChristoph Hellwig return quota_setxstate(sb, cmd, addr); 300c411e5f6SChristoph Hellwig case Q_XGETQSTAT: 301c411e5f6SChristoph Hellwig return quota_getxstate(sb, addr); 302c411e5f6SChristoph Hellwig case Q_XSETQLIM: 303c411e5f6SChristoph Hellwig return quota_setxquota(sb, type, id, addr); 304c411e5f6SChristoph Hellwig case Q_XGETQUOTA: 305c411e5f6SChristoph Hellwig return quota_getxquota(sb, type, id, addr); 306884d179dSJan Kara case Q_XQUOTASYNC: 3078c4e4acdSChristoph Hellwig /* caller already holds s_umount */ 3088c4e4acdSChristoph Hellwig if (sb->s_flags & MS_RDONLY) 3098c4e4acdSChristoph Hellwig return -EROFS; 3108c4e4acdSChristoph Hellwig writeback_inodes_sb(sb); 3118c4e4acdSChristoph Hellwig return 0; 312884d179dSJan Kara default: 313f450d4feSChristoph Hellwig return -EINVAL; 314884d179dSJan Kara } 315884d179dSJan Kara } 316884d179dSJan Kara 317884d179dSJan Kara /* 318884d179dSJan Kara * look up a superblock on which quota ops will be performed 319884d179dSJan Kara * - use the name of a block device to find the superblock thereon 320884d179dSJan Kara */ 3217a2435d8SJan Kara static struct super_block *quotactl_block(const char __user *special) 322884d179dSJan Kara { 323884d179dSJan Kara #ifdef CONFIG_BLOCK 324884d179dSJan Kara struct block_device *bdev; 325884d179dSJan Kara struct super_block *sb; 326884d179dSJan Kara char *tmp = getname(special); 327884d179dSJan Kara 328884d179dSJan Kara if (IS_ERR(tmp)) 329884d179dSJan Kara return ERR_CAST(tmp); 330884d179dSJan Kara bdev = lookup_bdev(tmp); 331884d179dSJan Kara putname(tmp); 332884d179dSJan Kara if (IS_ERR(bdev)) 333884d179dSJan Kara return ERR_CAST(bdev); 334884d179dSJan Kara sb = get_super(bdev); 335884d179dSJan Kara bdput(bdev); 336884d179dSJan Kara if (!sb) 337884d179dSJan Kara return ERR_PTR(-ENODEV); 338884d179dSJan Kara 339884d179dSJan Kara return sb; 340884d179dSJan Kara #else 341884d179dSJan Kara return ERR_PTR(-ENODEV); 342884d179dSJan Kara #endif 343884d179dSJan Kara } 344884d179dSJan Kara 345884d179dSJan Kara /* 346884d179dSJan Kara * This is the system call interface. This communicates with 347884d179dSJan Kara * the user-level programs. Currently this only supports diskquota 348884d179dSJan Kara * calls. Maybe we need to add the process quotas etc. in the future, 349884d179dSJan Kara * but we probably should use rlimits for that. 350884d179dSJan Kara */ 351884d179dSJan Kara SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special, 352884d179dSJan Kara qid_t, id, void __user *, addr) 353884d179dSJan Kara { 354884d179dSJan Kara uint cmds, type; 355884d179dSJan Kara struct super_block *sb = NULL; 356884d179dSJan Kara int ret; 357884d179dSJan Kara 358884d179dSJan Kara cmds = cmd >> SUBCMDSHIFT; 359884d179dSJan Kara type = cmd & SUBCMDMASK; 360884d179dSJan Kara 3616ae09575SChristoph Hellwig /* 3626ae09575SChristoph Hellwig * As a special case Q_SYNC can be called without a specific device. 3636ae09575SChristoph Hellwig * It will iterate all superblocks that have quota enabled and call 3646ae09575SChristoph Hellwig * the sync action on each of them. 3656ae09575SChristoph Hellwig */ 3666ae09575SChristoph Hellwig if (!special) { 3676ae09575SChristoph Hellwig if (cmds == Q_SYNC) 3686ae09575SChristoph Hellwig return quota_sync_all(type); 3696ae09575SChristoph Hellwig return -ENODEV; 3706ae09575SChristoph Hellwig } 3716ae09575SChristoph Hellwig 372884d179dSJan Kara sb = quotactl_block(special); 373884d179dSJan Kara if (IS_ERR(sb)) 374884d179dSJan Kara return PTR_ERR(sb); 375884d179dSJan Kara 376884d179dSJan Kara ret = do_quotactl(sb, type, cmds, id, addr); 377884d179dSJan Kara 3786ae09575SChristoph Hellwig drop_super(sb); 379884d179dSJan Kara return ret; 380884d179dSJan Kara } 381