The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/quota.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Quota code necessary even when VFS quota support is not compiled
    3  * into the kernel.  The interesting stuff is over in dquot.c, here
    4  * we have symbols for initial quotactl(2) handling, the sysctl(2)
    5  * variables, etc - things needed even when quota support disabled.
    6  */
    7 
    8 #include <linux/fs.h>
    9 #include <linux/slab.h>
   10 #include <asm/current.h>
   11 #include <asm/uaccess.h>
   12 #include <linux/kernel.h>
   13 #include <linux/smp_lock.h>
   14 #include <linux/quotaops.h>
   15 #include <linux/quotacompat.h>
   16 
   17 struct dqstats dqstats;
   18 
   19 /* Check validity of quotactl */
   20 static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
   21 {
   22         if (type >= MAXQUOTAS)
   23                 return -EINVAL;
   24         if (!sb && cmd != Q_SYNC)
   25                 return -ENODEV;
   26         /* Is operation supported? */
   27         if (sb && !sb->s_qcop)
   28                 return -ENOSYS;
   29 
   30         switch (cmd) {
   31                 case Q_GETFMT:
   32                         break;
   33                 case Q_QUOTAON:
   34                         if (!sb->s_qcop->quota_on)
   35                                 return -ENOSYS;
   36                         break;
   37                 case Q_QUOTAOFF:
   38                         if (!sb->s_qcop->quota_off)
   39                                 return -ENOSYS;
   40                         break;
   41                 case Q_SETINFO:
   42                         if (!sb->s_qcop->set_info)
   43                                 return -ENOSYS;
   44                         break;
   45                 case Q_GETINFO:
   46                         if (!sb->s_qcop->get_info)
   47                                 return -ENOSYS;
   48                         break;
   49                 case Q_SETQUOTA:
   50                         if (!sb->s_qcop->set_dqblk)
   51                                 return -ENOSYS;
   52                         break;
   53                 case Q_GETQUOTA:
   54                         if (!sb->s_qcop->get_dqblk)
   55                                 return -ENOSYS;
   56                         break;
   57                 case Q_SYNC:
   58                         if (sb && !sb->s_qcop->quota_sync)
   59                                 return -ENOSYS;
   60                         break;
   61                 case Q_XQUOTAON:
   62                 case Q_XQUOTAOFF:
   63                 case Q_XQUOTARM:
   64                         if (!sb->s_qcop->set_xstate)
   65                                 return -ENOSYS;
   66                         break;
   67                 case Q_XGETQSTAT:
   68                         if (!sb->s_qcop->get_xstate)
   69                                 return -ENOSYS;
   70                         break;
   71                 case Q_XSETQLIM:
   72                         if (!sb->s_qcop->set_xquota)
   73                                 return -ENOSYS;
   74                         break;
   75                 case Q_XGETQUOTA:
   76                         if (!sb->s_qcop->get_xquota)
   77                                 return -ENOSYS;
   78                         break;
   79                 default:
   80                         return -EINVAL;
   81         }
   82 
   83         /* Is quota turned on for commands which need it? */
   84         switch (cmd) {
   85                 case Q_GETFMT:
   86                 case Q_GETINFO:
   87                 case Q_QUOTAOFF:
   88                 case Q_SETINFO:
   89                 case Q_SETQUOTA:
   90                 case Q_GETQUOTA:
   91                         if (!sb_has_quota_enabled(sb, type))
   92                                 return -ESRCH;
   93         }
   94         /* Check privileges */
   95         if (cmd == Q_GETQUOTA || cmd == Q_XGETQUOTA) {
   96                 if (((type == USRQUOTA && current->euid != id) ||
   97                      (type == GRPQUOTA && !in_egroup_p(id))) &&
   98                     !capable(CAP_SYS_ADMIN))
   99                         return -EPERM;
  100         }
  101         else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT)
  102                 if (!capable(CAP_SYS_ADMIN))
  103                         return -EPERM;
  104         return 0;
  105 }
  106 
  107 /* Resolve device pathname to superblock */
  108 static struct super_block *resolve_dev(const char *path)
  109 {
  110         int ret;
  111         mode_t mode;
  112         struct nameidata nd;
  113         kdev_t dev;
  114         struct super_block *sb;
  115 
  116         ret = user_path_walk(path, &nd);
  117         if (ret)
  118                 goto out;
  119 
  120         dev = nd.dentry->d_inode->i_rdev;
  121         mode = nd.dentry->d_inode->i_mode;
  122         path_release(&nd);
  123 
  124         ret = -ENOTBLK;
  125         if (!S_ISBLK(mode))
  126                 goto out;
  127         ret = -ENODEV;
  128         sb = get_super(dev);
  129         if (!sb)
  130                 goto out;
  131         return sb;
  132 out:
  133         return ERR_PTR(ret);
  134 }
  135 
  136 /* Copy parameters and call proper function */
  137 static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr)
  138 {
  139         int ret;
  140 
  141         switch (cmd) {
  142                 case Q_QUOTAON: {
  143                         char *pathname;
  144 
  145                         if (IS_ERR(pathname = getname(addr)))
  146                                 return PTR_ERR(pathname);
  147                         ret = sb->s_qcop->quota_on(sb, type, id, pathname);
  148                         putname(pathname);
  149                         return ret;
  150                 }
  151                 case Q_QUOTAOFF:
  152                         return sb->s_qcop->quota_off(sb, type);
  153 
  154                 case Q_GETFMT: {
  155                         __u32 fmt;
  156 
  157                         fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
  158                         if (copy_to_user(addr, &fmt, sizeof(fmt)))
  159                                 return -EFAULT;
  160                         return 0;
  161                 }
  162                 case Q_GETINFO: {
  163                         struct if_dqinfo info;
  164 
  165                         if ((ret = sb->s_qcop->get_info(sb, type, &info)))
  166                                 return ret;
  167                         if (copy_to_user(addr, &info, sizeof(info)))
  168                                 return -EFAULT;
  169                         return 0;
  170                 }
  171                 case Q_SETINFO: {
  172                         struct if_dqinfo info;
  173 
  174                         if (copy_from_user(&info, addr, sizeof(info)))
  175                                 return -EFAULT;
  176                         return sb->s_qcop->set_info(sb, type, &info);
  177                 }
  178                 case Q_GETQUOTA: {
  179                         struct if_dqblk idq;
  180 
  181                         if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)))
  182                                 return ret;
  183                         if (copy_to_user(addr, &idq, sizeof(idq)))
  184                                 return -EFAULT;
  185                         return 0;
  186                 }
  187                 case Q_SETQUOTA: {
  188                         struct if_dqblk idq;
  189 
  190                         if (copy_from_user(&idq, addr, sizeof(idq)))
  191                                 return -EFAULT;
  192                         return sb->s_qcop->set_dqblk(sb, type, id, &idq);
  193                 }
  194                 case Q_SYNC:
  195                         if (sb)
  196                                 return sb->s_qcop->quota_sync(sb, type);
  197                         sync_dquots_dev(NODEV, type);
  198                         return 0;
  199                 case Q_XQUOTAON:
  200                 case Q_XQUOTAOFF:
  201                 case Q_XQUOTARM: {
  202                         __u32 flags;
  203 
  204                         if (copy_from_user(&flags, addr, sizeof(flags)))
  205                                 return -EFAULT;
  206                         return sb->s_qcop->set_xstate(sb, flags, cmd);
  207                 }
  208                 case Q_XGETQSTAT: {
  209                         struct fs_quota_stat fqs;
  210                 
  211                         if ((ret = sb->s_qcop->get_xstate(sb, &fqs)))
  212                                 return ret;
  213                         if (copy_to_user(addr, &fqs, sizeof(fqs)))
  214                                 return -EFAULT;
  215                         return 0;
  216                 }
  217                 case Q_XSETQLIM: {
  218                         struct fs_disk_quota fdq;
  219 
  220                         if (copy_from_user(&fdq, addr, sizeof(fdq)))
  221                                 return -EFAULT;
  222                        return sb->s_qcop->set_xquota(sb, type, id, &fdq);
  223                 }
  224                 case Q_XGETQUOTA: {
  225                         struct fs_disk_quota fdq;
  226 
  227                         if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq)))
  228                                 return ret;
  229                         if (copy_to_user(addr, &fdq, sizeof(fdq)))
  230                                 return -EFAULT;
  231                         return 0;
  232                 }
  233                 /* We never reach here unless validity check is broken */
  234                 default:
  235                         BUG();
  236         }
  237         return 0;
  238 }
  239 
  240 static int check_compat_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
  241 {
  242         if (type >= MAXQUOTAS)
  243                 return -EINVAL;
  244         /* Is operation supported? */
  245         /* sb==NULL for GETSTATS calls */
  246         if (sb && !sb->s_qcop)
  247                 return -ENOSYS;
  248 
  249         switch (cmd) {
  250                 case Q_COMP_QUOTAON:
  251                         if (!sb->s_qcop->quota_on)
  252                                 return -ENOSYS;
  253                         break;
  254                 case Q_COMP_QUOTAOFF:
  255                         if (!sb->s_qcop->quota_off)
  256                                 return -ENOSYS;
  257                         break;
  258                 case Q_COMP_SYNC:
  259                         if (sb && !sb->s_qcop->quota_sync)
  260                                 return -ENOSYS;
  261                         break;
  262                 case Q_V1_SETQLIM:
  263                 case Q_V1_SETUSE:
  264                 case Q_V1_SETQUOTA:
  265                         if (!sb->s_qcop->set_dqblk)
  266                                 return -ENOSYS;
  267                         break;
  268                 case Q_V1_GETQUOTA:
  269                         if (!sb->s_qcop->get_dqblk)
  270                                 return -ENOSYS;
  271                         break;
  272                 case Q_V1_RSQUASH:
  273                         if (!sb->s_qcop->set_info)
  274                                 return -ENOSYS;
  275                         break;
  276                 case Q_V1_GETSTATS:
  277                         return 0;       /* GETSTATS need no other checks */
  278                 default:
  279                         return -EINVAL;
  280         }
  281 
  282         /* Is quota turned on for commands which need it? */
  283         switch (cmd) {
  284                 case Q_V2_SETFLAGS:
  285                 case Q_V2_SETGRACE:
  286                 case Q_V2_SETINFO:
  287                 case Q_V2_GETINFO:
  288                 case Q_COMP_QUOTAOFF:
  289                 case Q_V1_RSQUASH:
  290                 case Q_V1_SETQUOTA:
  291                 case Q_V1_SETQLIM:
  292                 case Q_V1_SETUSE:
  293                 case Q_V2_SETQUOTA:
  294                 /* Q_V2_SETQLIM: collision with Q_V1_SETQLIM */
  295                 case Q_V2_SETUSE:
  296                 case Q_V1_GETQUOTA:
  297                 case Q_V2_GETQUOTA:
  298                         if (!sb_has_quota_enabled(sb, type))
  299                                 return -ESRCH;
  300         }
  301         if (cmd != Q_COMP_QUOTAON &&
  302             cmd != Q_COMP_QUOTAOFF &&
  303             cmd != Q_COMP_SYNC &&
  304             sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id != QFMT_VFS_OLD)
  305                 return -ESRCH;
  306 
  307         /* Check privileges */
  308         if (cmd == Q_V1_GETQUOTA || cmd == Q_V2_GETQUOTA) {
  309                 if (((type == USRQUOTA && current->euid != id) ||
  310                      (type == GRPQUOTA && !in_egroup_p(id))) &&
  311                     !capable(CAP_SYS_ADMIN))
  312                         return -EPERM;
  313         }
  314         else if (cmd != Q_V1_GETSTATS && cmd != Q_V2_GETSTATS && cmd != Q_V2_GETINFO && cmd != Q_COMP_SYNC)
  315                 if (!capable(CAP_SYS_ADMIN))
  316                         return -EPERM;
  317         return 0;
  318 }
  319 
  320 static int v1_set_rsquash(struct super_block *sb, int type, int flag)
  321 {
  322         struct if_dqinfo info;
  323 
  324         info.dqi_valid = IIF_FLAGS;
  325         info.dqi_flags = flag ? V1_DQF_RSQUASH : 0;
  326         return sb->s_qcop->set_info(sb, type, &info);
  327 }
  328 
  329 static int v1_get_dqblk(struct super_block *sb, int type, qid_t id, struct v1c_mem_dqblk *mdq)
  330 {
  331         struct if_dqblk idq;
  332         int ret;
  333 
  334         if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)) < 0)
  335                 return ret;
  336         mdq->dqb_ihardlimit = idq.dqb_ihardlimit;
  337         mdq->dqb_isoftlimit = idq.dqb_isoftlimit;
  338         mdq->dqb_curinodes = idq.dqb_curinodes;
  339         mdq->dqb_bhardlimit = idq.dqb_bhardlimit;
  340         mdq->dqb_bsoftlimit = idq.dqb_bsoftlimit;
  341         mdq->dqb_curblocks = toqb(idq.dqb_curspace);
  342         mdq->dqb_itime = idq.dqb_itime;
  343         mdq->dqb_btime = idq.dqb_btime;
  344         if (id == 0) {  /* Times for id 0 are in fact grace times */
  345                 struct if_dqinfo info;
  346 
  347                 if ((ret = sb->s_qcop->get_info(sb, type, &info)) < 0)
  348                         return ret;
  349                 mdq->dqb_btime = info.dqi_bgrace;
  350                 mdq->dqb_itime = info.dqi_igrace;
  351         }
  352         return 0;
  353 }
  354 
  355 static int v1_set_dqblk(struct super_block *sb, int type, int cmd, qid_t id, struct v1c_mem_dqblk *mdq)
  356 {
  357         struct if_dqblk idq;
  358         int ret;
  359 
  360         idq.dqb_valid = 0;
  361         if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETQLIM) {
  362                 idq.dqb_ihardlimit = mdq->dqb_ihardlimit;
  363                 idq.dqb_isoftlimit = mdq->dqb_isoftlimit;
  364                 idq.dqb_bhardlimit = mdq->dqb_bhardlimit;
  365                 idq.dqb_bsoftlimit = mdq->dqb_bsoftlimit;
  366                 idq.dqb_valid |= QIF_LIMITS;
  367         }
  368         if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETUSE) {
  369                 idq.dqb_curinodes = mdq->dqb_curinodes;
  370                 idq.dqb_curspace = ((qsize_t)mdq->dqb_curblocks) << QUOTABLOCK_BITS;
  371                 idq.dqb_valid |= QIF_USAGE;
  372         }
  373         ret = sb->s_qcop->set_dqblk(sb, type, id, &idq);
  374         if (!ret && id == 0 && cmd == Q_V1_SETQUOTA) {  /* Times for id 0 are in fact grace times */
  375                 struct if_dqinfo info;
  376 
  377                 info.dqi_bgrace = mdq->dqb_btime;
  378                 info.dqi_igrace = mdq->dqb_itime;
  379                 info.dqi_valid = IIF_BGRACE | IIF_IGRACE;
  380                 ret = sb->s_qcop->set_info(sb, type, &info);
  381         }
  382         return ret;
  383 }
  384 
  385 static void v1_get_stats(struct v1c_dqstats *dst)
  386 {
  387         memcpy(dst, &dqstats, sizeof(dqstats));
  388 }
  389 
  390 /* Handle requests to old interface */
  391 static int do_compat_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr)
  392 {
  393         int ret;
  394 
  395         switch (cmd) {
  396                 case Q_COMP_QUOTAON: {
  397                         char *pathname;
  398 
  399                         if (IS_ERR(pathname = getname(addr)))
  400                                 return PTR_ERR(pathname);
  401                         ret = sb->s_qcop->quota_on(sb, type, QFMT_VFS_OLD, pathname);
  402                         putname(pathname);
  403                         return ret;
  404                 }
  405                 case Q_COMP_QUOTAOFF:
  406                         return sb->s_qcop->quota_off(sb, type);
  407                 case Q_COMP_SYNC:
  408                         if (sb)
  409                                 return sb->s_qcop->quota_sync(sb, type);
  410                         sync_dquots_dev(NODEV, type);
  411                         return 0;
  412                 case Q_V1_RSQUASH: {
  413                         int flag;
  414 
  415                         if (copy_from_user(&flag, addr, sizeof(flag)))
  416                                 return -EFAULT;
  417                         return v1_set_rsquash(sb, type, flag);
  418                 }
  419                 case Q_V1_GETQUOTA: {
  420                         struct v1c_mem_dqblk mdq;
  421 
  422                         if ((ret = v1_get_dqblk(sb, type, id, &mdq)))
  423                                 return ret;
  424                         if (copy_to_user(addr, &mdq, sizeof(mdq)))
  425                                 return -EFAULT;
  426                         return 0;
  427                 }
  428                 case Q_V1_SETQLIM:
  429                 case Q_V1_SETUSE:
  430                 case Q_V1_SETQUOTA: {
  431                         struct v1c_mem_dqblk mdq;
  432 
  433                         if (copy_from_user(&mdq, addr, sizeof(mdq)))
  434                                 return -EFAULT;
  435                         return v1_set_dqblk(sb, type, cmd, id, &mdq);
  436                 }
  437                 case Q_V1_GETSTATS: {
  438                         struct v1c_dqstats dst;
  439 
  440                         v1_get_stats(&dst);
  441                         if (copy_to_user(addr, &dst, sizeof(dst)))
  442                                 return -EFAULT;
  443                         return 0;
  444                 }
  445         }
  446         BUG();
  447         return 0;
  448 }
  449 
  450 /* Macros for short-circuiting the compatibility tests */
  451 #define NEW_COMMAND(c) ((c) & (0x80 << 16))
  452 #define XQM_COMMAND(c) (((c) & ('X' << 8)) == ('X' << 8))
  453 
  454 /*
  455  * This is the system call interface. This communicates with
  456  * the user-level programs. Currently this only supports diskquota
  457  * calls. Maybe we need to add the process quotas etc. in the future,
  458  * but we probably should use rlimits for that.
  459  */
  460 asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, caddr_t addr)
  461 {
  462         uint cmds, type;
  463         struct super_block *sb = NULL;
  464         int ret = -EINVAL;
  465 
  466         lock_kernel();
  467         cmds = cmd >> SUBCMDSHIFT;
  468         type = cmd & SUBCMDMASK;
  469 
  470         if (cmds != Q_V1_GETSTATS && cmds != Q_V2_GETSTATS && IS_ERR(sb = resolve_dev(special))) {
  471                 ret = PTR_ERR(sb);
  472                 sb = NULL;
  473                 goto out;
  474         }
  475         if (!NEW_COMMAND(cmds) && !XQM_COMMAND(cmds)) {
  476                 if ((ret = check_compat_quotactl_valid(sb, type, cmds, id)) < 0)
  477                         goto out;
  478                 ret = do_compat_quotactl(sb, type, cmds, id, addr);
  479                 goto out;
  480         }
  481         if ((ret = check_quotactl_valid(sb, type, cmds, id)) < 0)
  482                 goto out;
  483         ret = do_quotactl(sb, type, cmds, id, addr);
  484 out:
  485         if (sb)
  486                 drop_super(sb);
  487         unlock_kernel();
  488         return ret;
  489 }

Cache object: 77f89f0ed6d0fcf3f19d040dd43391e4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.