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