linux-bk/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/kernel.h>
  14#include <linux/smp_lock.h>
  15#include <linux/security.h>
  16
  17/* Check validity of quotactl */
  18static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
  19{
  20        if (type >= MAXQUOTAS)
  21                return -EINVAL;
  22        /* Is operation supported? */
  23        if (!sb->s_qcop)
  24                return -ENOSYS;
  25
  26        switch (cmd) {
  27                case Q_GETFMT:
  28                        break;
  29                case Q_QUOTAON:
  30                        if (!sb->s_qcop->quota_on)
  31                                return -ENOSYS;
  32                        break;
  33                case Q_QUOTAOFF:
  34                        if (!sb->s_qcop->quota_off)
  35                                return -ENOSYS;
  36                        break;
  37                case Q_SETINFO:
  38                        if (!sb->s_qcop->set_info)
  39                                return -ENOSYS;
  40                        break;
  41                case Q_GETINFO:
  42                        if (!sb->s_qcop->get_info)
  43                                return -ENOSYS;
  44                        break;
  45                case Q_SETQUOTA:
  46                        if (!sb->s_qcop->set_dqblk)
  47                                return -ENOSYS;
  48                        break;
  49                case Q_GETQUOTA:
  50                        if (!sb->s_qcop->get_dqblk)
  51                                return -ENOSYS;
  52                        break;
  53                case Q_SYNC:
  54                        if (!sb->s_qcop->quota_sync)
  55                                return -ENOSYS;
  56                        break;
  57                case Q_XQUOTAON:
  58                case Q_XQUOTAOFF:
  59                case Q_XQUOTARM:
  60                        if (!sb->s_qcop->set_xstate)
  61                                return -ENOSYS;
  62                        break;
  63                case Q_XGETQSTAT:
  64                        if (!sb->s_qcop->get_xstate)
  65                                return -ENOSYS;
  66                        break;
  67                case Q_XSETQLIM:
  68                        if (!sb->s_qcop->set_xquota)
  69                                return -ENOSYS;
  70                        break;
  71                case Q_XGETQUOTA:
  72                        if (!sb->s_qcop->get_xquota)
  73                                return -ENOSYS;
  74                        break;
  75                default:
  76                        return -EINVAL;
  77        }
  78
  79        /* Is quota turned on for commands which need it? */
  80        switch (cmd) {
  81                case Q_GETFMT:
  82                case Q_GETINFO:
  83                case Q_QUOTAOFF:
  84                case Q_SETINFO:
  85                case Q_SETQUOTA:
  86                case Q_GETQUOTA:
  87                        if (!sb_has_quota_enabled(sb, type))
  88                                return -ESRCH;
  89        }
  90        /* Check privileges */
  91        if (cmd == Q_GETQUOTA || cmd == Q_XGETQUOTA) {
  92                if (((type == USRQUOTA && current->euid != id) ||
  93                     (type == GRPQUOTA && !in_egroup_p(id))) &&
  94                    !capable(CAP_SYS_ADMIN))
  95                        return -EPERM;
  96        }
  97        else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT)
  98                if (!capable(CAP_SYS_ADMIN))
  99                        return -EPERM;
 100
 101        return security_ops->quotactl (cmd, type, id, sb);
 102}
 103
 104/* Resolve device pathname to superblock */
 105static struct super_block *resolve_dev(const char *path)
 106{
 107        int ret;
 108        mode_t mode;
 109        struct nameidata nd;
 110        struct block_device *bdev;
 111        struct super_block *sb;
 112
 113        ret = user_path_walk(path, &nd);
 114        if (ret)
 115                goto out;
 116
 117        bdev = nd.dentry->d_inode->i_bdev;
 118        mode = nd.dentry->d_inode->i_mode;
 119        path_release(&nd);
 120
 121        ret = -ENOTBLK;
 122        if (!S_ISBLK(mode))
 123                goto out;
 124        ret = -ENODEV;
 125        sb = get_super(bdev);
 126        if (!sb)
 127                goto out;
 128        return sb;
 129out:
 130        return ERR_PTR(ret);
 131}
 132
 133/* Copy parameters and call proper function */
 134static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr)
 135{
 136        int ret;
 137
 138        switch (cmd) {
 139                case Q_QUOTAON: {
 140                        char *pathname;
 141
 142                        if (IS_ERR(pathname = getname(addr)))
 143                                return PTR_ERR(pathname);
 144                        ret = sb->s_qcop->quota_on(sb, type, id, pathname);
 145                        putname(pathname);
 146                        return ret;
 147                }
 148                case Q_QUOTAOFF:
 149                        return sb->s_qcop->quota_off(sb, type);
 150
 151                case Q_GETFMT: {
 152                        __u32 fmt;
 153
 154                        fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
 155                        if (copy_to_user(addr, &fmt, sizeof(fmt)))
 156                                return -EFAULT;
 157                        return 0;
 158                }
 159                case Q_GETINFO: {
 160                        struct if_dqinfo info;
 161
 162                        if ((ret = sb->s_qcop->get_info(sb, type, &info)))
 163                                return ret;
 164                        if (copy_to_user(addr, &info, sizeof(info)))
 165                                return -EFAULT;
 166                        return 0;
 167                }
 168                case Q_SETINFO: {
 169                        struct if_dqinfo info;
 170
 171                        if (copy_from_user(&info, addr, sizeof(info)))
 172                                return -EFAULT;
 173                        return sb->s_qcop->set_info(sb, type, &info);
 174                }
 175                case Q_GETQUOTA: {
 176                        struct if_dqblk idq;
 177
 178                        if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)))
 179                                return ret;
 180                        if (copy_to_user(addr, &idq, sizeof(idq)))
 181                                return -EFAULT;
 182                        return 0;
 183                }
 184                case Q_SETQUOTA: {
 185                        struct if_dqblk idq;
 186
 187                        if (copy_from_user(&idq, addr, sizeof(idq)))
 188                                return -EFAULT;
 189                        return sb->s_qcop->set_dqblk(sb, type, id, &idq);
 190                }
 191                case Q_SYNC:
 192                        return sb->s_qcop->quota_sync(sb, type);
 193
 194                case Q_XQUOTAON:
 195                case Q_XQUOTAOFF:
 196                case Q_XQUOTARM: {
 197                        __u32 flags;
 198
 199                        if (copy_from_user(&flags, addr, sizeof(flags)))
 200                                return -EFAULT;
 201                        return sb->s_qcop->set_xstate(sb, flags, cmd);
 202                }
 203                case Q_XGETQSTAT: {
 204                        struct fs_quota_stat fqs;
 205                
 206                        if ((ret = sb->s_qcop->get_xstate(sb, &fqs)))
 207                                return ret;
 208                        if (copy_to_user(addr, &fqs, sizeof(fqs)))
 209                                return -EFAULT;
 210                        return 0;
 211                }
 212                case Q_XSETQLIM: {
 213                        struct fs_disk_quota fdq;
 214
 215                        if (copy_from_user(&fdq, addr, sizeof(fdq)))
 216                                return -EFAULT;
 217                       return sb->s_qcop->set_xquota(sb, type, id, &fdq);
 218                }
 219                case Q_XGETQUOTA: {
 220                        struct fs_disk_quota fdq;
 221
 222                        if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq)))
 223                                return ret;
 224                        if (copy_to_user(addr, &fdq, sizeof(fdq)))
 225                                return -EFAULT;
 226                        return 0;
 227                }
 228                /* We never reach here unless validity check is broken */
 229                default:
 230                        BUG();
 231        }
 232        return 0;
 233}
 234
 235/*
 236 * This is the system call interface. This communicates with
 237 * the user-level programs. Currently this only supports diskquota
 238 * calls. Maybe we need to add the process quotas etc. in the future,
 239 * but we probably should use rlimits for that.
 240 */
 241asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, caddr_t addr)
 242{
 243        uint cmds, type;
 244        struct super_block *sb = NULL;
 245        int ret = -EINVAL;
 246
 247        lock_kernel();
 248        cmds = cmd >> SUBCMDSHIFT;
 249        type = cmd & SUBCMDMASK;
 250
 251        if (IS_ERR(sb = resolve_dev(special))) {
 252                ret = PTR_ERR(sb);
 253                sb = NULL;
 254                goto out;
 255        }
 256        if ((ret = check_quotactl_valid(sb, type, cmds, id)) < 0)
 257                goto out;
 258        ret = do_quotactl(sb, type, cmds, id, addr);
 259out:
 260        if (sb)
 261                drop_super(sb);
 262        unlock_kernel();
 263        return ret;
 264}
 265
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.