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 */
 371asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t id, void __user *addr)
 372{
 373        uint cmds, type;
 374        struct super_block *sb = NULL;
 375        int ret;
 376
 377        cmds = cmd >> SUBCMDSHIFT;
 378        type = cmd & SUBCMDMASK;
 379
 380        if (cmds != Q_SYNC || special) {
 381                sb = quotactl_block(special);
 382                if (IS_ERR(sb))
 383                        return PTR_ERR(sb);
 384        }
 385
 386        ret = check_quotactl_valid(sb, type, cmds, id);
 387        if (ret >= 0)
 388                ret = do_quotactl(sb, type, cmds, id, addr);
 389        if (sb)
 390                drop_super(sb);
 391
 392        return ret;
 393}
 394
 395#if defined(CONFIG_COMPAT_FOR_U64_ALIGNMENT)
 396/*
 397 * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64)
 398 * and is necessary due to alignment problems.
 399 */
 400struct compat_if_dqblk {
 401        compat_u64 dqb_bhardlimit;
 402        compat_u64 dqb_bsoftlimit;
 403        compat_u64 dqb_curspace;
 404        compat_u64 dqb_ihardlimit;
 405        compat_u64 dqb_isoftlimit;
 406        compat_u64 dqb_curinodes;
 407        compat_u64 dqb_btime;
 408        compat_u64 dqb_itime;
 409        compat_uint_t dqb_valid;
 410};
 411
 412/* XFS structures */
 413struct compat_fs_qfilestat {
 414        compat_u64 dqb_bhardlimit;
 415        compat_u64 qfs_nblks;
 416        compat_uint_t qfs_nextents;
 417};
 418
 419struct compat_fs_quota_stat {
 420        __s8            qs_version;
 421        __u16           qs_flags;
 422        __s8            qs_pad;
 423        struct compat_fs_qfilestat      qs_uquota;
 424        struct compat_fs_qfilestat      qs_gquota;
 425        compat_uint_t   qs_incoredqs;
 426        compat_int_t    qs_btimelimit;
 427        compat_int_t    qs_itimelimit;
 428        compat_int_t    qs_rtbtimelimit;
 429        __u16           qs_bwarnlimit;
 430        __u16           qs_iwarnlimit;
 431};
 432
 433asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special,
 434                                                qid_t id, void __user *addr)
 435{
 436        unsigned int cmds;
 437        struct if_dqblk __user *dqblk;
 438        struct compat_if_dqblk __user *compat_dqblk;
 439        struct fs_quota_stat __user *fsqstat;
 440        struct compat_fs_quota_stat __user *compat_fsqstat;
 441        compat_uint_t data;
 442        u16 xdata;
 443        long ret;
 444
 445        cmds = cmd >> SUBCMDSHIFT;
 446
 447        switch (cmds) {
 448        case Q_GETQUOTA:
 449                dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
 450                compat_dqblk = addr;
 451                ret = sys_quotactl(cmd, special, id, dqblk);
 452                if (ret)
 453                        break;
 454                if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) ||
 455                        get_user(data, &dqblk->dqb_valid) ||
 456                        put_user(data, &compat_dqblk->dqb_valid))
 457                        ret = -EFAULT;
 458                break;
 459        case Q_SETQUOTA:
 460                dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
 461                compat_dqblk = addr;
 462                ret = -EFAULT;
 463                if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) ||
 464                        get_user(data, &compat_dqblk->dqb_valid) ||
 465                        put_user(data, &dqblk->dqb_valid))
 466                        break;
 467                ret = sys_quotactl(cmd, special, id, dqblk);
 468                break;
 469        case Q_XGETQSTAT:
 470                fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat));
 471                compat_fsqstat = addr;
 472                ret = sys_quotactl(cmd, special, id, fsqstat);
 473                if (ret)
 474                        break;
 475                ret = -EFAULT;
 476                /* Copying qs_version, qs_flags, qs_pad */
 477                if (copy_in_user(compat_fsqstat, fsqstat,
 478                        offsetof(struct compat_fs_quota_stat, qs_uquota)))
 479                        break;
 480                /* Copying qs_uquota */
 481                if (copy_in_user(&compat_fsqstat->qs_uquota,
 482                        &fsqstat->qs_uquota,
 483                        sizeof(compat_fsqstat->qs_uquota)) ||
 484                        get_user(data, &fsqstat->qs_uquota.qfs_nextents) ||
 485                        put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents))
 486                        break;
 487                /* Copying qs_gquota */
 488                if (copy_in_user(&compat_fsqstat->qs_gquota,
 489                        &fsqstat->qs_gquota,
 490                        sizeof(compat_fsqstat->qs_gquota)) ||
 491                        get_user(data, &fsqstat->qs_gquota.qfs_nextents) ||
 492                        put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents))
 493                        break;
 494                /* Copying the rest */
 495                if (copy_in_user(&compat_fsqstat->qs_incoredqs,
 496                        &fsqstat->qs_incoredqs,
 497                        sizeof(struct compat_fs_quota_stat) -
 498                        offsetof(struct compat_fs_quota_stat, qs_incoredqs)) ||
 499                        get_user(xdata, &fsqstat->qs_iwarnlimit) ||
 500                        put_user(xdata, &compat_fsqstat->qs_iwarnlimit))
 501                        break;
 502                ret = 0;
 503                break;
 504        default:
 505                ret = sys_quotactl(cmd, special, id, addr);
 506        }
 507        return ret;
 508}
 509#endif
 510
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.