linux/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/namei.h>
  10#include <linux/slab.h>
  11#include <asm/current.h>
  12#include <asm/uaccess.h>
  13#include <linux/compat.h>
  14#include <linux/kernel.h>
  15#include <linux/security.h>
  16#include <linux/syscalls.h>
  17#include <linux/buffer_head.h>
  18#include <linux/capability.h>
  19#include <linux/quotaops.h>
  20#include <linux/types.h>
  21
  22/* Check validity of generic quotactl commands */
  23static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
  24{
  25        if (type >= MAXQUOTAS)
  26                return -EINVAL;
  27        if (!sb && cmd != Q_SYNC)
  28                return -ENODEV;
  29        /* Is operation supported? */
  30        if (sb && !sb->s_qcop)
  31                return -ENOSYS;
  32
  33        switch (cmd) {
  34                case Q_GETFMT:
  35                        break;
  36                case Q_QUOTAON:
  37                        if (!sb->s_qcop->quota_on)
  38                                return -ENOSYS;
  39                        break;
  40                case Q_QUOTAOFF:
  41                        if (!sb->s_qcop->quota_off)
  42                                return -ENOSYS;
  43                        break;
  44                case Q_SETINFO:
  45                        if (!sb->s_qcop->set_info)
  46                                return -ENOSYS;
  47                        break;
  48                case Q_GETINFO:
  49                        if (!sb->s_qcop->get_info)
  50                                return -ENOSYS;
  51                        break;
  52                case Q_SETQUOTA:
  53                        if (!sb->s_qcop->set_dqblk)
  54                                return -ENOSYS;
  55                        break;
  56                case Q_GETQUOTA:
  57                        if (!sb->s_qcop->get_dqblk)
  58                                return -ENOSYS;
  59                        break;
  60                case Q_SYNC:
  61                        if (sb && !sb->s_qcop->quota_sync)
  62                                return -ENOSYS;
  63                        break;
  64                default:
  65                        return -EINVAL;
  66        }
  67
  68        /* Is quota turned on for commands which need it? */
  69        switch (cmd) {
  70                case Q_GETFMT:
  71                case Q_GETINFO:
  72                case Q_SETINFO:
  73                case Q_SETQUOTA:
  74                case Q_GETQUOTA:
  75                        /* This is just informative test so we are satisfied without a lock */
  76                        if (!sb_has_quota_enabled(sb, type))
  77                                return -ESRCH;
  78        }
  79
  80        /* Check privileges */
  81        if (cmd == Q_GETQUOTA) {
  82                if (((type == USRQUOTA && current->euid != id) ||
  83                     (type == GRPQUOTA && !in_egroup_p(id))) &&
  84                    !capable(CAP_SYS_ADMIN))
  85                        return -EPERM;
  86        }
  87        else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO)
  88                if (!capable(CAP_SYS_ADMIN))
  89                        return -EPERM;
  90
  91        return 0;
  92}
  93
  94/* Check validity of XFS Quota Manager commands */
  95static int xqm_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
  96{
  97        if (type >= XQM_MAXQUOTAS)
  98                return -EINVAL;
  99        if (!sb)
 100                return -ENODEV;
 101        if (!sb->s_qcop)
 102                return -ENOSYS;
 103
 104        switch (cmd) {
 105                case Q_XQUOTAON:
 106                case Q_XQUOTAOFF:
 107                case Q_XQUOTARM:
 108                        if (!sb->s_qcop->set_xstate)
 109                                return -ENOSYS;
 110                        break;
 111                case Q_XGETQSTAT:
 112                        if (!sb->s_qcop->get_xstate)
 113                                return -ENOSYS;
 114                        break;
 115                case Q_XSETQLIM:
 116                        if (!sb->s_qcop->set_xquota)
 117                                return -ENOSYS;
 118                        break;
 119                case Q_XGETQUOTA:
 120                        if (!sb->s_qcop->get_xquota)
 121                                return -ENOSYS;
 122                        break;
 123                case Q_XQUOTASYNC:
 124                        if (!sb->s_qcop->quota_sync)
 125                                return -ENOSYS;
 126                        break;
 127                default:
 128                        return -EINVAL;
 129        }
 130
 131        /* Check privileges */
 132        if (cmd == Q_XGETQUOTA) {
 133                if (((type == XQM_USRQUOTA && current->euid != id) ||
 134                     (type == XQM_GRPQUOTA && !in_egroup_p(id))) &&
 135                     !capable(CAP_SYS_ADMIN))
 136                        return -EPERM;
 137        } else if (cmd != Q_XGETQSTAT && cmd != Q_XQUOTASYNC) {
 138                if (!capable(CAP_SYS_ADMIN))
 139                        return -EPERM;
 140        }
 141
 142        return 0;
 143}
 144
 145static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
 146{
 147        int error;
 148
 149        if (XQM_COMMAND(cmd))
 150                error = xqm_quotactl_valid(sb, type, cmd, id);
 151        else
 152                error = generic_quotactl_valid(sb, type, cmd, id);
 153        if (!error)
 154                error = security_quotactl(cmd, type, id, sb);
 155        return error;
 156}
 157
 158static void quota_sync_sb(struct super_block *sb, int type)
 159{
 160        int cnt;
 161
 162        sb->s_qcop->quota_sync(sb, type);
 163        /* This is not very clever (and fast) but currently I don't know about
 164         * any other simple way of getting quota data to disk and we must get
 165         * them there for userspace to be visible... */
 166        if (sb->s_op->sync_fs)
 167                sb->s_op->sync_fs(sb, 1);
 168        sync_blockdev(sb->s_bdev);
 169
 170        /*
 171         * Now when everything is written we can discard the pagecache so
 172         * that userspace sees the changes.
 173         */
 174        mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
 175        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 176                if (type != -1 && cnt != type)
 177                        continue;
 178                if (!sb_has_quota_enabled(sb, cnt))
 179                        continue;
 180                mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex, I_MUTEX_QUOTA);
 181                truncate_inode_pages(&sb_dqopt(sb)->files[cnt]->i_data, 0);
 182                mutex_unlock(&sb_dqopt(sb)->files[cnt]->i_mutex);
 183        }
 184        mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
 185}
 186
 187void sync_dquots(struct super_block *sb, int type)
 188{
 189        int cnt;
 190
 191        if (sb) {
 192                if (sb->s_qcop->quota_sync)
 193                        quota_sync_sb(sb, type);
 194                return;
 195        }
 196
 197        spin_lock(&sb_lock);
 198restart:
 199        list_for_each_entry(sb, &super_blocks, s_list) {
 200                /* This test just improves performance so it needn't be reliable... */
 201                for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 202                        if (type != -1 && type != cnt)
 203                                continue;
 204                        if (!sb_has_quota_enabled(sb, cnt))
 205                                continue;
 206                        if (!info_dirty(&sb_dqopt(sb)->info[cnt]) &&
 207                            list_empty(&sb_dqopt(sb)->info[cnt].dqi_dirty_list))
 208                                continue;
 209                        break;
 210                }
 211                if (cnt == MAXQUOTAS)
 212                        continue;
 213                sb->s_count++;
 214                spin_unlock(&sb_lock);
 215                down_read(&sb->s_umount);
 216                if (sb->s_root && sb->s_qcop->quota_sync)
 217                        quota_sync_sb(sb, type);
 218                up_read(&sb->s_umount);
 219                spin_lock(&sb_lock);
 220                if (__put_super_and_need_restart(sb))
 221                        goto restart;
 222        }
 223        spin_unlock(&sb_lock);
 224}
 225
 226/* Copy parameters and call proper function */
 227static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void __user *addr)
 228{
 229        int ret;
 230
 231        switch (cmd) {
 232                case Q_QUOTAON: {
 233                        char *pathname;
 234
 235                        if (IS_ERR(pathname = getname(addr)))
 236                                return PTR_ERR(pathname);
 237                        ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0);
 238                        putname(pathname);
 239                        return ret;
 240                }
 241                case Q_QUOTAOFF:
 242                        return sb->s_qcop->quota_off(sb, type, 0);
 243
 244                case Q_GETFMT: {
 245                        __u32 fmt;
 246
 247                        down_read(&sb_dqopt(sb)->dqptr_sem);
 248                        if (!sb_has_quota_enabled(sb, type)) {
 249                                up_read(&sb_dqopt(sb)->dqptr_sem);
 250                                return -ESRCH;
 251                        }
 252                        fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
 253                        up_read(&sb_dqopt(sb)->dqptr_sem);
 254                        if (copy_to_user(addr, &fmt, sizeof(fmt)))
 255                                return -EFAULT;
 256                        return 0;
 257                }
 258                case Q_GETINFO: {
 259                        struct if_dqinfo info;
 260
 261                        if ((ret = sb->s_qcop->get_info(sb, type, &info)))
 262                                return ret;
 263                        if (copy_to_user(addr, &info, sizeof(info)))
 264                                return -EFAULT;
 265                        return 0;
 266                }
 267                case Q_SETINFO: {
 268                        struct if_dqinfo info;
 269
 270                        if (copy_from_user(&info, addr, sizeof(info)))
 271                                return -EFAULT;
 272                        return sb->s_qcop->set_info(sb, type, &info);
 273                }
 274                case Q_GETQUOTA: {
 275                        struct if_dqblk idq;
 276
 277                        if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)))
 278                                return ret;
 279                        if (copy_to_user(addr, &idq, sizeof(idq)))
 280                                return -EFAULT;
 281                        return 0;
 282                }
 283                case Q_SETQUOTA: {
 284                        struct if_dqblk idq;
 285
 286                        if (copy_from_user(&idq, addr, sizeof(idq)))
 287                                return -EFAULT;
 288                        return sb->s_qcop->set_dqblk(sb, type, id, &idq);
 289                }
 290                case Q_SYNC:
 291                        sync_dquots(sb, type);
 292                        return 0;
 293
 294                case Q_XQUOTAON:
 295                case Q_XQUOTAOFF:
 296                case Q_XQUOTARM: {
 297                        __u32 flags;
 298
 299                        if (copy_from_user(&flags, addr, sizeof(flags)))
 300                                return -EFAULT;
 301                        return sb->s_qcop->set_xstate(sb, flags, cmd);
 302                }
 303                case Q_XGETQSTAT: {
 304                        struct fs_quota_stat fqs;
 305                
 306                        if ((ret = sb->s_qcop->get_xstate(sb, &fqs)))
 307                                return ret;
 308                        if (copy_to_user(addr, &fqs, sizeof(fqs)))
 309                                return -EFAULT;
 310                        return 0;
 311                }
 312                case Q_XSETQLIM: {
 313                        struct fs_disk_quota fdq;
 314
 315                        if (copy_from_user(&fdq, addr, sizeof(fdq)))
 316                                return -EFAULT;
 317                       return sb->s_qcop->set_xquota(sb, type, id, &fdq);
 318                }
 319                case Q_XGETQUOTA: {
 320                        struct fs_disk_quota fdq;
 321
 322                        if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq)))
 323                                return ret;
 324                        if (copy_to_user(addr, &fdq, sizeof(fdq)))
 325                                return -EFAULT;
 326                        return 0;
 327                }
 328                case Q_XQUOTASYNC:
 329                        return sb->s_qcop->quota_sync(sb, type);
 330                /* We never reach here unless validity check is broken */
 331                default:
 332                        BUG();
 333        }
 334        return 0;
 335}
 336
 337/*
 338 * look up a superblock on which quota ops will be performed
 339 * - use the name of a block device to find the superblock thereon
 340 */
 341static inline struct super_block *quotactl_block(const char __user *special)
 342{
 343#ifdef CONFIG_BLOCK
 344        struct block_device *bdev;
 345        struct super_block *sb;
 346        char *tmp = getname(special);
 347
 348        if (IS_ERR(tmp))
 349                return ERR_CAST(tmp);
 350        bdev = lookup_bdev(tmp);
 351        putname(tmp);
 352        if (IS_ERR(bdev))
 353                return ERR_CAST(bdev);
 354        sb = get_super(bdev);
 355        bdput(bdev);
 356        if (!sb)
 357                return ERR_PTR(-ENODEV);
 358
 359        return sb;
 360#else
 361        return ERR_PTR(-ENODEV);
 362#endif
 363}
 364
 365/*
 366 * This is the system call interface. This communicates with
 367 * the user-level programs. Currently this only supports diskquota
 368 * calls. Maybe we need to add the process quotas etc. in the future,
 369 * but we probably should use rlimits for that.
 370 */
 371SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
 372                qid_t, id, void __user *, addr)
 373{
 374        uint cmds, type;
 375        struct super_block *sb = NULL;
 376        int ret;
 377
 378        cmds = cmd >> SUBCMDSHIFT;
 379        type = cmd & SUBCMDMASK;
 380
 381        if (cmds != Q_SYNC || special) {
 382                sb = quotactl_block(special);
 383                if (IS_ERR(sb))
 384                        return PTR_ERR(sb);
 385        }
 386
 387        ret = check_quotactl_valid(sb, type, cmds, id);
 388        if (ret >= 0)
 389                ret = do_quotactl(sb, type, cmds, id, addr);
 390        if (sb)
 391                drop_super(sb);
 392
 393        return ret;
 394}
 395
 396#if defined(CONFIG_COMPAT_FOR_U64_ALIGNMENT)
 397/*
 398 * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64)
 399 * and is necessary due to alignment problems.
 400 */
 401struct compat_if_dqblk {
 402        compat_u64 dqb_bhardlimit;
 403        compat_u64 dqb_bsoftlimit;
 404        compat_u64 dqb_curspace;
 405        compat_u64 dqb_ihardlimit;
 406        compat_u64 dqb_isoftlimit;
 407        compat_u64 dqb_curinodes;
 408        compat_u64 dqb_btime;
 409        compat_u64 dqb_itime;
 410        compat_uint_t dqb_valid;
 411};
 412
 413/* XFS structures */
 414struct compat_fs_qfilestat {
 415        compat_u64 dqb_bhardlimit;
 416        compat_u64 qfs_nblks;
 417        compat_uint_t qfs_nextents;
 418};
 419
 420struct compat_fs_quota_stat {
 421        __s8            qs_version;
 422        __u16           qs_flags;
 423        __s8            qs_pad;
 424        struct compat_fs_qfilestat      qs_uquota;
 425        struct compat_fs_qfilestat      qs_gquota;
 426        compat_uint_t   qs_incoredqs;
 427        compat_int_t    qs_btimelimit;
 428        compat_int_t    qs_itimelimit;
 429        compat_int_t    qs_rtbtimelimit;
 430        __u16           qs_bwarnlimit;
 431        __u16           qs_iwarnlimit;
 432};
 433
 434asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special,
 435                                                qid_t id, void __user *addr)
 436{
 437        unsigned int cmds;
 438        struct if_dqblk __user *dqblk;
 439        struct compat_if_dqblk __user *compat_dqblk;
 440        struct fs_quota_stat __user *fsqstat;
 441        struct compat_fs_quota_stat __user *compat_fsqstat;
 442        compat_uint_t data;
 443        u16 xdata;
 444        long ret;
 445
 446        cmds = cmd >> SUBCMDSHIFT;
 447
 448        switch (cmds) {
 449        case Q_GETQUOTA:
 450                dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
 451                compat_dqblk = addr;
 452                ret = sys_quotactl(cmd, special, id, dqblk);
 453                if (ret)
 454                        break;
 455                if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) ||
 456                        get_user(data, &dqblk->dqb_valid) ||
 457                        put_user(data, &compat_dqblk->dqb_valid))
 458                        ret = -EFAULT;
 459                break;
 460        case Q_SETQUOTA:
 461                dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
 462                compat_dqblk = addr;
 463                ret = -EFAULT;
 464                if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) ||
 465                        get_user(data, &compat_dqblk->dqb_valid) ||
 466                        put_user(data, &dqblk->dqb_valid))
 467                        break;
 468                ret = sys_quotactl(cmd, special, id, dqblk);
 469                break;
 470        case Q_XGETQSTAT:
 471                fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat));
 472                compat_fsqstat = addr;
 473                ret = sys_quotactl(cmd, special, id, fsqstat);
 474                if (ret)
 475                        break;
 476                ret = -EFAULT;
 477                /* Copying qs_version, qs_flags, qs_pad */
 478                if (copy_in_user(compat_fsqstat, fsqstat,
 479                        offsetof(struct compat_fs_quota_stat, qs_uquota)))
 480                        break;
 481                /* Copying qs_uquota */
 482                if (copy_in_user(&compat_fsqstat->qs_uquota,
 483                        &fsqstat->qs_uquota,
 484                        sizeof(compat_fsqstat->qs_uquota)) ||
 485                        get_user(data, &fsqstat->qs_uquota.qfs_nextents) ||
 486                        put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents))
 487                        break;
 488                /* Copying qs_gquota */
 489                if (copy_in_user(&compat_fsqstat->qs_gquota,
 490                        &fsqstat->qs_gquota,
 491                        sizeof(compat_fsqstat->qs_gquota)) ||
 492                        get_user(data, &fsqstat->qs_gquota.qfs_nextents) ||
 493                        put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents))
 494                        break;
 495                /* Copying the rest */
 496                if (copy_in_user(&compat_fsqstat->qs_incoredqs,
 497                        &fsqstat->qs_incoredqs,
 498                        sizeof(struct compat_fs_quota_stat) -
 499                        offsetof(struct compat_fs_quota_stat, qs_incoredqs)) ||
 500                        get_user(xdata, &fsqstat->qs_iwarnlimit) ||
 501                        put_user(xdata, &compat_fsqstat->qs_iwarnlimit))
 502                        break;
 503                ret = 0;
 504                break;
 505        default:
 506                ret = sys_quotactl(cmd, special, id, addr);
 507        }
 508        return ret;
 509}
 510#endif
 511
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.