linux-old/fs/quota.c
<<
>>
Prefs
   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
  17struct dqstats dqstats;
  18
  19/* Check validity of quotactl */
  20static 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 */
 108static 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;
 132out:
 133        return ERR_PTR(ret);
 134}
 135
 136/* Copy parameters and call proper function */
 137static 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
 240static 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
 320static 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
 329static 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
 355static 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
 385static void v1_get_stats(struct v1c_dqstats *dst)
 386{
 387        memcpy(dst, &dqstats, sizeof(dqstats));
 388}
 389
 390/* Handle requests to old interface */
 391static 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 */
 460asmlinkage 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);
 484out:
 485        if (sb)
 486                drop_super(sb);
 487        unlock_kernel();
 488        return ret;
 489}
 490
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.