1884d179dSJan Kara /* 2884d179dSJan Kara * Quota code necessary even when VFS quota support is not compiled 3884d179dSJan Kara * into the kernel. The interesting stuff is over in dquot.c, here 4884d179dSJan Kara * we have symbols for initial quotactl(2) handling, the sysctl(2) 5884d179dSJan Kara * variables, etc - things needed even when quota support disabled. 6884d179dSJan Kara */ 7884d179dSJan Kara 8884d179dSJan Kara #include <linux/fs.h> 9884d179dSJan Kara #include <linux/namei.h> 10884d179dSJan Kara #include <linux/slab.h> 11884d179dSJan Kara #include <asm/current.h> 12884d179dSJan Kara #include <asm/uaccess.h> 13884d179dSJan Kara #include <linux/compat.h> 14884d179dSJan Kara #include <linux/kernel.h> 15884d179dSJan Kara #include <linux/security.h> 16884d179dSJan Kara #include <linux/syscalls.h> 17884d179dSJan Kara #include <linux/buffer_head.h> 18884d179dSJan Kara #include <linux/capability.h> 19884d179dSJan Kara #include <linux/quotaops.h> 20884d179dSJan Kara #include <linux/types.h> 2186e931a3SSteven Whitehouse #include <net/netlink.h> 2286e931a3SSteven Whitehouse #include <net/genetlink.h> 23884d179dSJan Kara 24884d179dSJan Kara /* Check validity of generic quotactl commands */ 25268157baSJan Kara static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, 26268157baSJan Kara qid_t id) 27884d179dSJan Kara { 28884d179dSJan Kara if (type >= MAXQUOTAS) 29884d179dSJan Kara return -EINVAL; 30884d179dSJan Kara if (!sb && cmd != Q_SYNC) 31884d179dSJan Kara return -ENODEV; 32884d179dSJan Kara /* Is operation supported? */ 33884d179dSJan Kara if (sb && !sb->s_qcop) 34884d179dSJan Kara return -ENOSYS; 35884d179dSJan Kara 36884d179dSJan Kara /* Check privileges */ 37884d179dSJan Kara if (cmd == Q_GETQUOTA) { 38884d179dSJan Kara if (((type == USRQUOTA && current_euid() != id) || 39884d179dSJan Kara (type == GRPQUOTA && !in_egroup_p(id))) && 40884d179dSJan Kara !capable(CAP_SYS_ADMIN)) 41884d179dSJan Kara return -EPERM; 42884d179dSJan Kara } 43884d179dSJan Kara else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO) 44884d179dSJan Kara if (!capable(CAP_SYS_ADMIN)) 45884d179dSJan Kara return -EPERM; 46884d179dSJan Kara 47884d179dSJan Kara return 0; 48884d179dSJan Kara } 49884d179dSJan Kara 50884d179dSJan Kara /* Check validity of XFS Quota Manager commands */ 51268157baSJan Kara static int xqm_quotactl_valid(struct super_block *sb, int type, int cmd, 52268157baSJan Kara qid_t id) 53884d179dSJan Kara { 54884d179dSJan Kara if (type >= XQM_MAXQUOTAS) 55884d179dSJan Kara return -EINVAL; 56884d179dSJan Kara if (!sb) 57884d179dSJan Kara return -ENODEV; 58884d179dSJan Kara if (!sb->s_qcop) 59884d179dSJan Kara return -ENOSYS; 60884d179dSJan Kara 61884d179dSJan Kara /* Check privileges */ 62884d179dSJan Kara if (cmd == Q_XGETQUOTA) { 63884d179dSJan Kara if (((type == XQM_USRQUOTA && current_euid() != id) || 64884d179dSJan Kara (type == XQM_GRPQUOTA && !in_egroup_p(id))) && 65884d179dSJan Kara !capable(CAP_SYS_ADMIN)) 66884d179dSJan Kara return -EPERM; 67884d179dSJan Kara } else if (cmd != Q_XGETQSTAT && cmd != Q_XQUOTASYNC) { 68884d179dSJan Kara if (!capable(CAP_SYS_ADMIN)) 69884d179dSJan Kara return -EPERM; 70884d179dSJan Kara } 71884d179dSJan Kara 72884d179dSJan Kara return 0; 73884d179dSJan Kara } 74884d179dSJan Kara 75268157baSJan Kara static int check_quotactl_valid(struct super_block *sb, int type, int cmd, 76268157baSJan Kara qid_t id) 77884d179dSJan Kara { 78884d179dSJan Kara int error; 79884d179dSJan Kara 80884d179dSJan Kara if (XQM_COMMAND(cmd)) 81884d179dSJan Kara error = xqm_quotactl_valid(sb, type, cmd, id); 82884d179dSJan Kara else 83884d179dSJan Kara error = generic_quotactl_valid(sb, type, cmd, id); 84884d179dSJan Kara if (!error) 85884d179dSJan Kara error = security_quotactl(cmd, type, id, sb); 86884d179dSJan Kara return error; 87884d179dSJan Kara } 88884d179dSJan Kara 89850b201bSChristoph Hellwig #ifdef CONFIG_QUOTA 90850b201bSChristoph Hellwig void sync_quota_sb(struct super_block *sb, int type) 91884d179dSJan Kara { 92884d179dSJan Kara int cnt; 93884d179dSJan Kara 94850b201bSChristoph Hellwig if (!sb->s_qcop->quota_sync) 95850b201bSChristoph Hellwig return; 96850b201bSChristoph Hellwig 97884d179dSJan Kara sb->s_qcop->quota_sync(sb, type); 98884d179dSJan Kara 99884d179dSJan Kara if (sb_dqopt(sb)->flags & DQUOT_QUOTA_SYS_FILE) 100884d179dSJan Kara return; 101884d179dSJan Kara /* This is not very clever (and fast) but currently I don't know about 102884d179dSJan Kara * any other simple way of getting quota data to disk and we must get 103884d179dSJan Kara * them there for userspace to be visible... */ 104884d179dSJan Kara if (sb->s_op->sync_fs) 105884d179dSJan Kara sb->s_op->sync_fs(sb, 1); 106884d179dSJan Kara sync_blockdev(sb->s_bdev); 107884d179dSJan Kara 108884d179dSJan Kara /* 109884d179dSJan Kara * Now when everything is written we can discard the pagecache so 110884d179dSJan Kara * that userspace sees the changes. 111884d179dSJan Kara */ 112884d179dSJan Kara mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); 113884d179dSJan Kara for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 114884d179dSJan Kara if (type != -1 && cnt != type) 115884d179dSJan Kara continue; 116884d179dSJan Kara if (!sb_has_quota_active(sb, cnt)) 117884d179dSJan Kara continue; 118268157baSJan Kara mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex, 119268157baSJan Kara I_MUTEX_QUOTA); 120884d179dSJan Kara truncate_inode_pages(&sb_dqopt(sb)->files[cnt]->i_data, 0); 121884d179dSJan Kara mutex_unlock(&sb_dqopt(sb)->files[cnt]->i_mutex); 122884d179dSJan Kara } 123884d179dSJan Kara mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); 124884d179dSJan Kara } 125850b201bSChristoph Hellwig #endif 126884d179dSJan Kara 127*6ae09575SChristoph Hellwig static int quota_sync_all(int type) 128884d179dSJan Kara { 129850b201bSChristoph Hellwig struct super_block *sb; 130884d179dSJan Kara int cnt; 131*6ae09575SChristoph Hellwig int ret; 132*6ae09575SChristoph Hellwig 133*6ae09575SChristoph Hellwig if (type >= MAXQUOTAS) 134*6ae09575SChristoph Hellwig return -EINVAL; 135*6ae09575SChristoph Hellwig ret = security_quotactl(Q_SYNC, type, 0, NULL); 136*6ae09575SChristoph Hellwig if (ret) 137*6ae09575SChristoph Hellwig return ret; 138884d179dSJan Kara 139884d179dSJan Kara spin_lock(&sb_lock); 140884d179dSJan Kara restart: 141884d179dSJan Kara list_for_each_entry(sb, &super_blocks, s_list) { 142268157baSJan Kara /* This test just improves performance so it needn't be 143268157baSJan Kara * reliable... */ 144884d179dSJan Kara for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 145884d179dSJan Kara if (type != -1 && type != cnt) 146884d179dSJan Kara continue; 147884d179dSJan Kara if (!sb_has_quota_active(sb, cnt)) 148884d179dSJan Kara continue; 149884d179dSJan Kara if (!info_dirty(&sb_dqopt(sb)->info[cnt]) && 150884d179dSJan Kara list_empty(&sb_dqopt(sb)->info[cnt].dqi_dirty_list)) 151884d179dSJan Kara continue; 152884d179dSJan Kara break; 153884d179dSJan Kara } 154884d179dSJan Kara if (cnt == MAXQUOTAS) 155884d179dSJan Kara continue; 156884d179dSJan Kara sb->s_count++; 157884d179dSJan Kara spin_unlock(&sb_lock); 158884d179dSJan Kara down_read(&sb->s_umount); 159850b201bSChristoph Hellwig if (sb->s_root) 160850b201bSChristoph Hellwig sync_quota_sb(sb, type); 161884d179dSJan Kara up_read(&sb->s_umount); 162884d179dSJan Kara spin_lock(&sb_lock); 163884d179dSJan Kara if (__put_super_and_need_restart(sb)) 164884d179dSJan Kara goto restart; 165884d179dSJan Kara } 166884d179dSJan Kara spin_unlock(&sb_lock); 167*6ae09575SChristoph Hellwig 168*6ae09575SChristoph Hellwig return 0; 169884d179dSJan Kara } 170884d179dSJan Kara 171c411e5f6SChristoph Hellwig static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id, 172268157baSJan Kara void __user *addr) 173884d179dSJan Kara { 174884d179dSJan Kara char *pathname; 175f450d4feSChristoph Hellwig int ret = -ENOSYS; 176884d179dSJan Kara 177268157baSJan Kara pathname = getname(addr); 178268157baSJan Kara if (IS_ERR(pathname)) 179884d179dSJan Kara return PTR_ERR(pathname); 180f450d4feSChristoph Hellwig if (sb->s_qcop->quota_on) 181884d179dSJan Kara ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0); 182884d179dSJan Kara putname(pathname); 183884d179dSJan Kara return ret; 184884d179dSJan Kara } 185884d179dSJan Kara 186c411e5f6SChristoph Hellwig static int quota_getfmt(struct super_block *sb, int type, void __user *addr) 187c411e5f6SChristoph Hellwig { 188884d179dSJan Kara __u32 fmt; 189884d179dSJan Kara 190884d179dSJan Kara down_read(&sb_dqopt(sb)->dqptr_sem); 191884d179dSJan Kara if (!sb_has_quota_active(sb, type)) { 192884d179dSJan Kara up_read(&sb_dqopt(sb)->dqptr_sem); 193884d179dSJan Kara return -ESRCH; 194884d179dSJan Kara } 195884d179dSJan Kara fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id; 196884d179dSJan Kara up_read(&sb_dqopt(sb)->dqptr_sem); 197884d179dSJan Kara if (copy_to_user(addr, &fmt, sizeof(fmt))) 198884d179dSJan Kara return -EFAULT; 199884d179dSJan Kara return 0; 200884d179dSJan Kara } 201c411e5f6SChristoph Hellwig 202c411e5f6SChristoph Hellwig static int quota_getinfo(struct super_block *sb, int type, void __user *addr) 203c411e5f6SChristoph Hellwig { 204884d179dSJan Kara struct if_dqinfo info; 205c411e5f6SChristoph Hellwig int ret; 206884d179dSJan Kara 207f450d4feSChristoph Hellwig if (!sb_has_quota_active(sb, type)) 208f450d4feSChristoph Hellwig return -ESRCH; 209f450d4feSChristoph Hellwig if (!sb->s_qcop->get_info) 210f450d4feSChristoph Hellwig return -ENOSYS; 211268157baSJan Kara ret = sb->s_qcop->get_info(sb, type, &info); 212c411e5f6SChristoph Hellwig if (!ret && copy_to_user(addr, &info, sizeof(info))) 213884d179dSJan Kara return -EFAULT; 214c411e5f6SChristoph Hellwig return ret; 215884d179dSJan Kara } 216c411e5f6SChristoph Hellwig 217c411e5f6SChristoph Hellwig static int quota_setinfo(struct super_block *sb, int type, void __user *addr) 218c411e5f6SChristoph Hellwig { 219884d179dSJan Kara struct if_dqinfo info; 220884d179dSJan Kara 221884d179dSJan Kara if (copy_from_user(&info, addr, sizeof(info))) 222884d179dSJan Kara return -EFAULT; 223f450d4feSChristoph Hellwig if (!sb_has_quota_active(sb, type)) 224f450d4feSChristoph Hellwig return -ESRCH; 225f450d4feSChristoph Hellwig if (!sb->s_qcop->set_info) 226f450d4feSChristoph Hellwig return -ENOSYS; 227884d179dSJan Kara return sb->s_qcop->set_info(sb, type, &info); 228884d179dSJan Kara } 229c411e5f6SChristoph Hellwig 230c411e5f6SChristoph Hellwig static int quota_getquota(struct super_block *sb, int type, qid_t id, 231c411e5f6SChristoph Hellwig void __user *addr) 232c411e5f6SChristoph Hellwig { 233884d179dSJan Kara struct if_dqblk idq; 234c411e5f6SChristoph Hellwig int ret; 235884d179dSJan Kara 236f450d4feSChristoph Hellwig if (!sb_has_quota_active(sb, type)) 237f450d4feSChristoph Hellwig return -ESRCH; 238f450d4feSChristoph Hellwig if (!sb->s_qcop->get_dqblk) 239f450d4feSChristoph Hellwig return -ENOSYS; 240268157baSJan Kara ret = sb->s_qcop->get_dqblk(sb, type, id, &idq); 241268157baSJan Kara if (ret) 242884d179dSJan Kara return ret; 243884d179dSJan Kara if (copy_to_user(addr, &idq, sizeof(idq))) 244884d179dSJan Kara return -EFAULT; 245884d179dSJan Kara return 0; 246884d179dSJan Kara } 247c411e5f6SChristoph Hellwig 248c411e5f6SChristoph Hellwig static int quota_setquota(struct super_block *sb, int type, qid_t id, 249c411e5f6SChristoph Hellwig void __user *addr) 250c411e5f6SChristoph Hellwig { 251884d179dSJan Kara struct if_dqblk idq; 252884d179dSJan Kara 253884d179dSJan Kara if (copy_from_user(&idq, addr, sizeof(idq))) 254884d179dSJan Kara return -EFAULT; 255f450d4feSChristoph Hellwig if (!sb_has_quota_active(sb, type)) 256f450d4feSChristoph Hellwig return -ESRCH; 257f450d4feSChristoph Hellwig if (!sb->s_qcop->set_dqblk) 258f450d4feSChristoph Hellwig return -ENOSYS; 259884d179dSJan Kara return sb->s_qcop->set_dqblk(sb, type, id, &idq); 260884d179dSJan Kara } 261884d179dSJan Kara 262c411e5f6SChristoph Hellwig static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr) 263c411e5f6SChristoph Hellwig { 264884d179dSJan Kara __u32 flags; 265884d179dSJan Kara 266884d179dSJan Kara if (copy_from_user(&flags, addr, sizeof(flags))) 267884d179dSJan Kara return -EFAULT; 268f450d4feSChristoph Hellwig if (!sb->s_qcop->set_xstate) 269f450d4feSChristoph Hellwig return -ENOSYS; 270884d179dSJan Kara return sb->s_qcop->set_xstate(sb, flags, cmd); 271884d179dSJan Kara } 272884d179dSJan Kara 273c411e5f6SChristoph Hellwig static int quota_getxstate(struct super_block *sb, void __user *addr) 274c411e5f6SChristoph Hellwig { 275c411e5f6SChristoph Hellwig struct fs_quota_stat fqs; 276c411e5f6SChristoph Hellwig int ret; 277c411e5f6SChristoph Hellwig 278f450d4feSChristoph Hellwig if (!sb->s_qcop->get_xstate) 279f450d4feSChristoph Hellwig return -ENOSYS; 280c411e5f6SChristoph Hellwig ret = sb->s_qcop->get_xstate(sb, &fqs); 281c411e5f6SChristoph Hellwig if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) 282884d179dSJan Kara return -EFAULT; 283c411e5f6SChristoph Hellwig return ret; 284884d179dSJan Kara } 285c411e5f6SChristoph Hellwig 286c411e5f6SChristoph Hellwig static int quota_setxquota(struct super_block *sb, int type, qid_t id, 287c411e5f6SChristoph Hellwig void __user *addr) 288c411e5f6SChristoph Hellwig { 289884d179dSJan Kara struct fs_disk_quota fdq; 290884d179dSJan Kara 291884d179dSJan Kara if (copy_from_user(&fdq, addr, sizeof(fdq))) 292884d179dSJan Kara return -EFAULT; 293f450d4feSChristoph Hellwig if (!sb->s_qcop->set_xquota) 294f450d4feSChristoph Hellwig return -ENOSYS; 295884d179dSJan Kara return sb->s_qcop->set_xquota(sb, type, id, &fdq); 296884d179dSJan Kara } 297c411e5f6SChristoph Hellwig 298c411e5f6SChristoph Hellwig static int quota_getxquota(struct super_block *sb, int type, qid_t id, 299c411e5f6SChristoph Hellwig void __user *addr) 300c411e5f6SChristoph Hellwig { 301884d179dSJan Kara struct fs_disk_quota fdq; 302c411e5f6SChristoph Hellwig int ret; 303884d179dSJan Kara 304f450d4feSChristoph Hellwig if (!sb->s_qcop->get_xquota) 305f450d4feSChristoph Hellwig return -ENOSYS; 306268157baSJan Kara ret = sb->s_qcop->get_xquota(sb, type, id, &fdq); 307c411e5f6SChristoph Hellwig if (!ret && copy_to_user(addr, &fdq, sizeof(fdq))) 308884d179dSJan Kara return -EFAULT; 309c411e5f6SChristoph Hellwig return ret; 310884d179dSJan Kara } 311c411e5f6SChristoph Hellwig 312c411e5f6SChristoph Hellwig /* Copy parameters and call proper function */ 313c411e5f6SChristoph Hellwig static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, 314c411e5f6SChristoph Hellwig void __user *addr) 315c411e5f6SChristoph Hellwig { 316c411e5f6SChristoph Hellwig switch (cmd) { 317c411e5f6SChristoph Hellwig case Q_QUOTAON: 318c411e5f6SChristoph Hellwig return quota_quotaon(sb, type, cmd, id, addr); 319c411e5f6SChristoph Hellwig case Q_QUOTAOFF: 320f450d4feSChristoph Hellwig if (!sb->s_qcop->quota_off) 321f450d4feSChristoph Hellwig return -ENOSYS; 322c411e5f6SChristoph Hellwig return sb->s_qcop->quota_off(sb, type, 0); 323c411e5f6SChristoph Hellwig case Q_GETFMT: 324c411e5f6SChristoph Hellwig return quota_getfmt(sb, type, addr); 325c411e5f6SChristoph Hellwig case Q_GETINFO: 326c411e5f6SChristoph Hellwig return quota_getinfo(sb, type, addr); 327c411e5f6SChristoph Hellwig case Q_SETINFO: 328c411e5f6SChristoph Hellwig return quota_setinfo(sb, type, addr); 329c411e5f6SChristoph Hellwig case Q_GETQUOTA: 330c411e5f6SChristoph Hellwig return quota_getquota(sb, type, id, addr); 331c411e5f6SChristoph Hellwig case Q_SETQUOTA: 332c411e5f6SChristoph Hellwig return quota_setquota(sb, type, id, addr); 333c411e5f6SChristoph Hellwig case Q_SYNC: 334f450d4feSChristoph Hellwig if (!sb->s_qcop->quota_sync) 335f450d4feSChristoph Hellwig return -ENOSYS; 336c411e5f6SChristoph Hellwig sync_quota_sb(sb, type); 337c411e5f6SChristoph Hellwig return 0; 338c411e5f6SChristoph Hellwig case Q_XQUOTAON: 339c411e5f6SChristoph Hellwig case Q_XQUOTAOFF: 340c411e5f6SChristoph Hellwig case Q_XQUOTARM: 341c411e5f6SChristoph Hellwig return quota_setxstate(sb, cmd, addr); 342c411e5f6SChristoph Hellwig case Q_XGETQSTAT: 343c411e5f6SChristoph Hellwig return quota_getxstate(sb, addr); 344c411e5f6SChristoph Hellwig case Q_XSETQLIM: 345c411e5f6SChristoph Hellwig return quota_setxquota(sb, type, id, addr); 346c411e5f6SChristoph Hellwig case Q_XGETQUOTA: 347c411e5f6SChristoph Hellwig return quota_getxquota(sb, type, id, addr); 348884d179dSJan Kara case Q_XQUOTASYNC: 349f450d4feSChristoph Hellwig if (!sb->s_qcop->quota_sync) 350f450d4feSChristoph Hellwig return -ENOSYS; 351884d179dSJan Kara return sb->s_qcop->quota_sync(sb, type); 352884d179dSJan Kara default: 353f450d4feSChristoph Hellwig return -EINVAL; 354884d179dSJan Kara } 355884d179dSJan Kara } 356884d179dSJan Kara 357884d179dSJan Kara /* 358884d179dSJan Kara * look up a superblock on which quota ops will be performed 359884d179dSJan Kara * - use the name of a block device to find the superblock thereon 360884d179dSJan Kara */ 3617a2435d8SJan Kara static struct super_block *quotactl_block(const char __user *special) 362884d179dSJan Kara { 363884d179dSJan Kara #ifdef CONFIG_BLOCK 364884d179dSJan Kara struct block_device *bdev; 365884d179dSJan Kara struct super_block *sb; 366884d179dSJan Kara char *tmp = getname(special); 367884d179dSJan Kara 368884d179dSJan Kara if (IS_ERR(tmp)) 369884d179dSJan Kara return ERR_CAST(tmp); 370884d179dSJan Kara bdev = lookup_bdev(tmp); 371884d179dSJan Kara putname(tmp); 372884d179dSJan Kara if (IS_ERR(bdev)) 373884d179dSJan Kara return ERR_CAST(bdev); 374884d179dSJan Kara sb = get_super(bdev); 375884d179dSJan Kara bdput(bdev); 376884d179dSJan Kara if (!sb) 377884d179dSJan Kara return ERR_PTR(-ENODEV); 378884d179dSJan Kara 379884d179dSJan Kara return sb; 380884d179dSJan Kara #else 381884d179dSJan Kara return ERR_PTR(-ENODEV); 382884d179dSJan Kara #endif 383884d179dSJan Kara } 384884d179dSJan Kara 385884d179dSJan Kara /* 386884d179dSJan Kara * This is the system call interface. This communicates with 387884d179dSJan Kara * the user-level programs. Currently this only supports diskquota 388884d179dSJan Kara * calls. Maybe we need to add the process quotas etc. in the future, 389884d179dSJan Kara * but we probably should use rlimits for that. 390884d179dSJan Kara */ 391884d179dSJan Kara SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special, 392884d179dSJan Kara qid_t, id, void __user *, addr) 393884d179dSJan Kara { 394884d179dSJan Kara uint cmds, type; 395884d179dSJan Kara struct super_block *sb = NULL; 396884d179dSJan Kara int ret; 397884d179dSJan Kara 398884d179dSJan Kara cmds = cmd >> SUBCMDSHIFT; 399884d179dSJan Kara type = cmd & SUBCMDMASK; 400884d179dSJan Kara 401*6ae09575SChristoph Hellwig /* 402*6ae09575SChristoph Hellwig * As a special case Q_SYNC can be called without a specific device. 403*6ae09575SChristoph Hellwig * It will iterate all superblocks that have quota enabled and call 404*6ae09575SChristoph Hellwig * the sync action on each of them. 405*6ae09575SChristoph Hellwig */ 406*6ae09575SChristoph Hellwig if (!special) { 407*6ae09575SChristoph Hellwig if (cmds == Q_SYNC) 408*6ae09575SChristoph Hellwig return quota_sync_all(type); 409*6ae09575SChristoph Hellwig return -ENODEV; 410*6ae09575SChristoph Hellwig } 411*6ae09575SChristoph Hellwig 412884d179dSJan Kara sb = quotactl_block(special); 413884d179dSJan Kara if (IS_ERR(sb)) 414884d179dSJan Kara return PTR_ERR(sb); 415884d179dSJan Kara 416884d179dSJan Kara ret = check_quotactl_valid(sb, type, cmds, id); 417884d179dSJan Kara if (ret >= 0) 418884d179dSJan Kara ret = do_quotactl(sb, type, cmds, id, addr); 419884d179dSJan Kara 420*6ae09575SChristoph Hellwig drop_super(sb); 421884d179dSJan Kara return ret; 422884d179dSJan Kara } 423884d179dSJan Kara 424884d179dSJan Kara #if defined(CONFIG_COMPAT_FOR_U64_ALIGNMENT) 425884d179dSJan Kara /* 426884d179dSJan Kara * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64) 427884d179dSJan Kara * and is necessary due to alignment problems. 428884d179dSJan Kara */ 429884d179dSJan Kara struct compat_if_dqblk { 430884d179dSJan Kara compat_u64 dqb_bhardlimit; 431884d179dSJan Kara compat_u64 dqb_bsoftlimit; 432884d179dSJan Kara compat_u64 dqb_curspace; 433884d179dSJan Kara compat_u64 dqb_ihardlimit; 434884d179dSJan Kara compat_u64 dqb_isoftlimit; 435884d179dSJan Kara compat_u64 dqb_curinodes; 436884d179dSJan Kara compat_u64 dqb_btime; 437884d179dSJan Kara compat_u64 dqb_itime; 438884d179dSJan Kara compat_uint_t dqb_valid; 439884d179dSJan Kara }; 440884d179dSJan Kara 441884d179dSJan Kara /* XFS structures */ 442884d179dSJan Kara struct compat_fs_qfilestat { 443884d179dSJan Kara compat_u64 dqb_bhardlimit; 444884d179dSJan Kara compat_u64 qfs_nblks; 445884d179dSJan Kara compat_uint_t qfs_nextents; 446884d179dSJan Kara }; 447884d179dSJan Kara 448884d179dSJan Kara struct compat_fs_quota_stat { 449884d179dSJan Kara __s8 qs_version; 450884d179dSJan Kara __u16 qs_flags; 451884d179dSJan Kara __s8 qs_pad; 452884d179dSJan Kara struct compat_fs_qfilestat qs_uquota; 453884d179dSJan Kara struct compat_fs_qfilestat qs_gquota; 454884d179dSJan Kara compat_uint_t qs_incoredqs; 455884d179dSJan Kara compat_int_t qs_btimelimit; 456884d179dSJan Kara compat_int_t qs_itimelimit; 457884d179dSJan Kara compat_int_t qs_rtbtimelimit; 458884d179dSJan Kara __u16 qs_bwarnlimit; 459884d179dSJan Kara __u16 qs_iwarnlimit; 460884d179dSJan Kara }; 461884d179dSJan Kara 462884d179dSJan Kara asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special, 463884d179dSJan Kara qid_t id, void __user *addr) 464884d179dSJan Kara { 465884d179dSJan Kara unsigned int cmds; 466884d179dSJan Kara struct if_dqblk __user *dqblk; 467884d179dSJan Kara struct compat_if_dqblk __user *compat_dqblk; 468884d179dSJan Kara struct fs_quota_stat __user *fsqstat; 469884d179dSJan Kara struct compat_fs_quota_stat __user *compat_fsqstat; 470884d179dSJan Kara compat_uint_t data; 471884d179dSJan Kara u16 xdata; 472884d179dSJan Kara long ret; 473884d179dSJan Kara 474884d179dSJan Kara cmds = cmd >> SUBCMDSHIFT; 475884d179dSJan Kara 476884d179dSJan Kara switch (cmds) { 477884d179dSJan Kara case Q_GETQUOTA: 478884d179dSJan Kara dqblk = compat_alloc_user_space(sizeof(struct if_dqblk)); 479884d179dSJan Kara compat_dqblk = addr; 480884d179dSJan Kara ret = sys_quotactl(cmd, special, id, dqblk); 481884d179dSJan Kara if (ret) 482884d179dSJan Kara break; 483884d179dSJan Kara if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) || 484884d179dSJan Kara get_user(data, &dqblk->dqb_valid) || 485884d179dSJan Kara put_user(data, &compat_dqblk->dqb_valid)) 486884d179dSJan Kara ret = -EFAULT; 487884d179dSJan Kara break; 488884d179dSJan Kara case Q_SETQUOTA: 489884d179dSJan Kara dqblk = compat_alloc_user_space(sizeof(struct if_dqblk)); 490884d179dSJan Kara compat_dqblk = addr; 491884d179dSJan Kara ret = -EFAULT; 492884d179dSJan Kara if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) || 493884d179dSJan Kara get_user(data, &compat_dqblk->dqb_valid) || 494884d179dSJan Kara put_user(data, &dqblk->dqb_valid)) 495884d179dSJan Kara break; 496884d179dSJan Kara ret = sys_quotactl(cmd, special, id, dqblk); 497884d179dSJan Kara break; 498884d179dSJan Kara case Q_XGETQSTAT: 499884d179dSJan Kara fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat)); 500884d179dSJan Kara compat_fsqstat = addr; 501884d179dSJan Kara ret = sys_quotactl(cmd, special, id, fsqstat); 502884d179dSJan Kara if (ret) 503884d179dSJan Kara break; 504884d179dSJan Kara ret = -EFAULT; 505884d179dSJan Kara /* Copying qs_version, qs_flags, qs_pad */ 506884d179dSJan Kara if (copy_in_user(compat_fsqstat, fsqstat, 507884d179dSJan Kara offsetof(struct compat_fs_quota_stat, qs_uquota))) 508884d179dSJan Kara break; 509884d179dSJan Kara /* Copying qs_uquota */ 510884d179dSJan Kara if (copy_in_user(&compat_fsqstat->qs_uquota, 511884d179dSJan Kara &fsqstat->qs_uquota, 512884d179dSJan Kara sizeof(compat_fsqstat->qs_uquota)) || 513884d179dSJan Kara get_user(data, &fsqstat->qs_uquota.qfs_nextents) || 514884d179dSJan Kara put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents)) 515884d179dSJan Kara break; 516884d179dSJan Kara /* Copying qs_gquota */ 517884d179dSJan Kara if (copy_in_user(&compat_fsqstat->qs_gquota, 518884d179dSJan Kara &fsqstat->qs_gquota, 519884d179dSJan Kara sizeof(compat_fsqstat->qs_gquota)) || 520884d179dSJan Kara get_user(data, &fsqstat->qs_gquota.qfs_nextents) || 521884d179dSJan Kara put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents)) 522884d179dSJan Kara break; 523884d179dSJan Kara /* Copying the rest */ 524884d179dSJan Kara if (copy_in_user(&compat_fsqstat->qs_incoredqs, 525884d179dSJan Kara &fsqstat->qs_incoredqs, 526884d179dSJan Kara sizeof(struct compat_fs_quota_stat) - 527884d179dSJan Kara offsetof(struct compat_fs_quota_stat, qs_incoredqs)) || 528884d179dSJan Kara get_user(xdata, &fsqstat->qs_iwarnlimit) || 529884d179dSJan Kara put_user(xdata, &compat_fsqstat->qs_iwarnlimit)) 530884d179dSJan Kara break; 531884d179dSJan Kara ret = 0; 532884d179dSJan Kara break; 533884d179dSJan Kara default: 534884d179dSJan Kara ret = sys_quotactl(cmd, special, id, addr); 535884d179dSJan Kara } 536884d179dSJan Kara return ret; 537884d179dSJan Kara } 538884d179dSJan Kara #endif 53986e931a3SSteven Whitehouse 54086e931a3SSteven Whitehouse 54186e931a3SSteven Whitehouse #ifdef CONFIG_QUOTA_NETLINK_INTERFACE 54286e931a3SSteven Whitehouse 54386e931a3SSteven Whitehouse /* Netlink family structure for quota */ 54486e931a3SSteven Whitehouse static struct genl_family quota_genl_family = { 54586e931a3SSteven Whitehouse .id = GENL_ID_GENERATE, 54686e931a3SSteven Whitehouse .hdrsize = 0, 54786e931a3SSteven Whitehouse .name = "VFS_DQUOT", 54886e931a3SSteven Whitehouse .version = 1, 54986e931a3SSteven Whitehouse .maxattr = QUOTA_NL_A_MAX, 55086e931a3SSteven Whitehouse }; 55186e931a3SSteven Whitehouse 55286e931a3SSteven Whitehouse /** 55386e931a3SSteven Whitehouse * quota_send_warning - Send warning to userspace about exceeded quota 55486e931a3SSteven Whitehouse * @type: The quota type: USRQQUOTA, GRPQUOTA,... 55586e931a3SSteven Whitehouse * @id: The user or group id of the quota that was exceeded 55686e931a3SSteven Whitehouse * @dev: The device on which the fs is mounted (sb->s_dev) 55786e931a3SSteven Whitehouse * @warntype: The type of the warning: QUOTA_NL_... 55886e931a3SSteven Whitehouse * 55986e931a3SSteven Whitehouse * This can be used by filesystems (including those which don't use 56086e931a3SSteven Whitehouse * dquot) to send a message to userspace relating to quota limits. 56186e931a3SSteven Whitehouse * 56286e931a3SSteven Whitehouse */ 56386e931a3SSteven Whitehouse 56486e931a3SSteven Whitehouse void quota_send_warning(short type, unsigned int id, dev_t dev, 56586e931a3SSteven Whitehouse const char warntype) 56686e931a3SSteven Whitehouse { 56786e931a3SSteven Whitehouse static atomic_t seq; 56886e931a3SSteven Whitehouse struct sk_buff *skb; 56986e931a3SSteven Whitehouse void *msg_head; 57086e931a3SSteven Whitehouse int ret; 57186e931a3SSteven Whitehouse int msg_size = 4 * nla_total_size(sizeof(u32)) + 57286e931a3SSteven Whitehouse 2 * nla_total_size(sizeof(u64)); 57386e931a3SSteven Whitehouse 57486e931a3SSteven Whitehouse /* We have to allocate using GFP_NOFS as we are called from a 57586e931a3SSteven Whitehouse * filesystem performing write and thus further recursion into 57686e931a3SSteven Whitehouse * the fs to free some data could cause deadlocks. */ 57786e931a3SSteven Whitehouse skb = genlmsg_new(msg_size, GFP_NOFS); 57886e931a3SSteven Whitehouse if (!skb) { 57986e931a3SSteven Whitehouse printk(KERN_ERR 58086e931a3SSteven Whitehouse "VFS: Not enough memory to send quota warning.\n"); 58186e931a3SSteven Whitehouse return; 58286e931a3SSteven Whitehouse } 58386e931a3SSteven Whitehouse msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), 58486e931a3SSteven Whitehouse "a_genl_family, 0, QUOTA_NL_C_WARNING); 58586e931a3SSteven Whitehouse if (!msg_head) { 58686e931a3SSteven Whitehouse printk(KERN_ERR 58786e931a3SSteven Whitehouse "VFS: Cannot store netlink header in quota warning.\n"); 58886e931a3SSteven Whitehouse goto err_out; 58986e931a3SSteven Whitehouse } 59086e931a3SSteven Whitehouse ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type); 59186e931a3SSteven Whitehouse if (ret) 59286e931a3SSteven Whitehouse goto attr_err_out; 59386e931a3SSteven Whitehouse ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id); 59486e931a3SSteven Whitehouse if (ret) 59586e931a3SSteven Whitehouse goto attr_err_out; 59686e931a3SSteven Whitehouse ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype); 59786e931a3SSteven Whitehouse if (ret) 59886e931a3SSteven Whitehouse goto attr_err_out; 59986e931a3SSteven Whitehouse ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, MAJOR(dev)); 60086e931a3SSteven Whitehouse if (ret) 60186e931a3SSteven Whitehouse goto attr_err_out; 60286e931a3SSteven Whitehouse ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev)); 60386e931a3SSteven Whitehouse if (ret) 60486e931a3SSteven Whitehouse goto attr_err_out; 60586e931a3SSteven Whitehouse ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid()); 60686e931a3SSteven Whitehouse if (ret) 60786e931a3SSteven Whitehouse goto attr_err_out; 60886e931a3SSteven Whitehouse genlmsg_end(skb, msg_head); 60986e931a3SSteven Whitehouse 61086e931a3SSteven Whitehouse genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); 61186e931a3SSteven Whitehouse return; 61286e931a3SSteven Whitehouse attr_err_out: 61386e931a3SSteven Whitehouse printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); 61486e931a3SSteven Whitehouse err_out: 61586e931a3SSteven Whitehouse kfree_skb(skb); 61686e931a3SSteven Whitehouse } 61786e931a3SSteven Whitehouse EXPORT_SYMBOL(quota_send_warning); 61886e931a3SSteven Whitehouse 61986e931a3SSteven Whitehouse static int __init quota_init(void) 62086e931a3SSteven Whitehouse { 62186e931a3SSteven Whitehouse if (genl_register_family("a_genl_family) != 0) 62286e931a3SSteven Whitehouse printk(KERN_ERR 62386e931a3SSteven Whitehouse "VFS: Failed to create quota netlink interface.\n"); 62486e931a3SSteven Whitehouse return 0; 62586e931a3SSteven Whitehouse }; 62686e931a3SSteven Whitehouse 62786e931a3SSteven Whitehouse module_init(quota_init); 62886e931a3SSteven Whitehouse #endif 62986e931a3SSteven Whitehouse 630