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> 21*8c4e4acdSChristoph Hellwig #include <linux/writeback.h> 2286e931a3SSteven Whitehouse #include <net/netlink.h> 2386e931a3SSteven Whitehouse #include <net/genetlink.h> 24884d179dSJan Kara 25c988afb5SChristoph Hellwig static int check_quotactl_permission(struct super_block *sb, int type, int cmd, 26268157baSJan Kara qid_t id) 27884d179dSJan Kara { 28c988afb5SChristoph Hellwig switch (cmd) { 29c988afb5SChristoph Hellwig /* these commands do not require any special privilegues */ 30c988afb5SChristoph Hellwig case Q_GETFMT: 31c988afb5SChristoph Hellwig case Q_SYNC: 32c988afb5SChristoph Hellwig case Q_GETINFO: 33c988afb5SChristoph Hellwig case Q_XGETQSTAT: 34c988afb5SChristoph Hellwig case Q_XQUOTASYNC: 35c988afb5SChristoph Hellwig break; 36c988afb5SChristoph Hellwig /* allow to query information for dquots we "own" */ 37c988afb5SChristoph Hellwig case Q_GETQUOTA: 38c988afb5SChristoph Hellwig case Q_XGETQUOTA: 39c988afb5SChristoph Hellwig if ((type == USRQUOTA && current_euid() == id) || 40c988afb5SChristoph Hellwig (type == GRPQUOTA && in_egroup_p(id))) 41c988afb5SChristoph Hellwig break; 42c988afb5SChristoph Hellwig /*FALLTHROUGH*/ 43c988afb5SChristoph Hellwig default: 44884d179dSJan Kara if (!capable(CAP_SYS_ADMIN)) 45884d179dSJan Kara return -EPERM; 46884d179dSJan Kara } 47884d179dSJan Kara 48c988afb5SChristoph Hellwig return security_quotactl(cmd, type, id, sb); 49884d179dSJan Kara } 50884d179dSJan Kara 51850b201bSChristoph Hellwig #ifdef CONFIG_QUOTA 52850b201bSChristoph Hellwig void sync_quota_sb(struct super_block *sb, int type) 53884d179dSJan Kara { 54884d179dSJan Kara int cnt; 55884d179dSJan Kara 56*8c4e4acdSChristoph Hellwig if (!sb->s_qcop || !sb->s_qcop->quota_sync) 57850b201bSChristoph Hellwig return; 58850b201bSChristoph Hellwig 59884d179dSJan Kara sb->s_qcop->quota_sync(sb, type); 60884d179dSJan Kara 61884d179dSJan Kara if (sb_dqopt(sb)->flags & DQUOT_QUOTA_SYS_FILE) 62884d179dSJan Kara return; 63884d179dSJan Kara /* This is not very clever (and fast) but currently I don't know about 64884d179dSJan Kara * any other simple way of getting quota data to disk and we must get 65884d179dSJan Kara * them there for userspace to be visible... */ 66884d179dSJan Kara if (sb->s_op->sync_fs) 67884d179dSJan Kara sb->s_op->sync_fs(sb, 1); 68884d179dSJan Kara sync_blockdev(sb->s_bdev); 69884d179dSJan Kara 70884d179dSJan Kara /* 71884d179dSJan Kara * Now when everything is written we can discard the pagecache so 72884d179dSJan Kara * that userspace sees the changes. 73884d179dSJan Kara */ 74884d179dSJan Kara mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); 75884d179dSJan Kara for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 76884d179dSJan Kara if (type != -1 && cnt != type) 77884d179dSJan Kara continue; 78884d179dSJan Kara if (!sb_has_quota_active(sb, cnt)) 79884d179dSJan Kara continue; 80268157baSJan Kara mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex, 81268157baSJan Kara I_MUTEX_QUOTA); 82884d179dSJan Kara truncate_inode_pages(&sb_dqopt(sb)->files[cnt]->i_data, 0); 83884d179dSJan Kara mutex_unlock(&sb_dqopt(sb)->files[cnt]->i_mutex); 84884d179dSJan Kara } 85884d179dSJan Kara mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); 86884d179dSJan Kara } 87850b201bSChristoph Hellwig #endif 88884d179dSJan Kara 896ae09575SChristoph Hellwig static int quota_sync_all(int type) 90884d179dSJan Kara { 91850b201bSChristoph Hellwig struct super_block *sb; 92884d179dSJan Kara int cnt; 936ae09575SChristoph Hellwig int ret; 946ae09575SChristoph Hellwig 956ae09575SChristoph Hellwig if (type >= MAXQUOTAS) 966ae09575SChristoph Hellwig return -EINVAL; 976ae09575SChristoph Hellwig ret = security_quotactl(Q_SYNC, type, 0, NULL); 986ae09575SChristoph Hellwig if (ret) 996ae09575SChristoph Hellwig return ret; 100884d179dSJan Kara 101884d179dSJan Kara spin_lock(&sb_lock); 102884d179dSJan Kara restart: 103884d179dSJan Kara list_for_each_entry(sb, &super_blocks, s_list) { 104268157baSJan Kara /* This test just improves performance so it needn't be 105268157baSJan Kara * reliable... */ 106884d179dSJan Kara for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 107884d179dSJan Kara if (type != -1 && type != cnt) 108884d179dSJan Kara continue; 109884d179dSJan Kara if (!sb_has_quota_active(sb, cnt)) 110884d179dSJan Kara continue; 111884d179dSJan Kara if (!info_dirty(&sb_dqopt(sb)->info[cnt]) && 112884d179dSJan Kara list_empty(&sb_dqopt(sb)->info[cnt].dqi_dirty_list)) 113884d179dSJan Kara continue; 114884d179dSJan Kara break; 115884d179dSJan Kara } 116884d179dSJan Kara if (cnt == MAXQUOTAS) 117884d179dSJan Kara continue; 118884d179dSJan Kara sb->s_count++; 119884d179dSJan Kara spin_unlock(&sb_lock); 120884d179dSJan Kara down_read(&sb->s_umount); 121850b201bSChristoph Hellwig if (sb->s_root) 122850b201bSChristoph Hellwig sync_quota_sb(sb, type); 123884d179dSJan Kara up_read(&sb->s_umount); 124884d179dSJan Kara spin_lock(&sb_lock); 125884d179dSJan Kara if (__put_super_and_need_restart(sb)) 126884d179dSJan Kara goto restart; 127884d179dSJan Kara } 128884d179dSJan Kara spin_unlock(&sb_lock); 1296ae09575SChristoph Hellwig 1306ae09575SChristoph Hellwig return 0; 131884d179dSJan Kara } 132884d179dSJan Kara 133c411e5f6SChristoph Hellwig static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id, 134268157baSJan Kara void __user *addr) 135884d179dSJan Kara { 136884d179dSJan Kara char *pathname; 137f450d4feSChristoph Hellwig int ret = -ENOSYS; 138884d179dSJan Kara 139268157baSJan Kara pathname = getname(addr); 140268157baSJan Kara if (IS_ERR(pathname)) 141884d179dSJan Kara return PTR_ERR(pathname); 142f450d4feSChristoph Hellwig if (sb->s_qcop->quota_on) 143884d179dSJan Kara ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0); 144884d179dSJan Kara putname(pathname); 145884d179dSJan Kara return ret; 146884d179dSJan Kara } 147884d179dSJan Kara 148c411e5f6SChristoph Hellwig static int quota_getfmt(struct super_block *sb, int type, void __user *addr) 149c411e5f6SChristoph Hellwig { 150884d179dSJan Kara __u32 fmt; 151884d179dSJan Kara 152884d179dSJan Kara down_read(&sb_dqopt(sb)->dqptr_sem); 153884d179dSJan Kara if (!sb_has_quota_active(sb, type)) { 154884d179dSJan Kara up_read(&sb_dqopt(sb)->dqptr_sem); 155884d179dSJan Kara return -ESRCH; 156884d179dSJan Kara } 157884d179dSJan Kara fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id; 158884d179dSJan Kara up_read(&sb_dqopt(sb)->dqptr_sem); 159884d179dSJan Kara if (copy_to_user(addr, &fmt, sizeof(fmt))) 160884d179dSJan Kara return -EFAULT; 161884d179dSJan Kara return 0; 162884d179dSJan Kara } 163c411e5f6SChristoph Hellwig 164c411e5f6SChristoph Hellwig static int quota_getinfo(struct super_block *sb, int type, void __user *addr) 165c411e5f6SChristoph Hellwig { 166884d179dSJan Kara struct if_dqinfo info; 167c411e5f6SChristoph Hellwig int ret; 168884d179dSJan Kara 169f450d4feSChristoph Hellwig if (!sb_has_quota_active(sb, type)) 170f450d4feSChristoph Hellwig return -ESRCH; 171f450d4feSChristoph Hellwig if (!sb->s_qcop->get_info) 172f450d4feSChristoph Hellwig return -ENOSYS; 173268157baSJan Kara ret = sb->s_qcop->get_info(sb, type, &info); 174c411e5f6SChristoph Hellwig if (!ret && copy_to_user(addr, &info, sizeof(info))) 175884d179dSJan Kara return -EFAULT; 176c411e5f6SChristoph Hellwig return ret; 177884d179dSJan Kara } 178c411e5f6SChristoph Hellwig 179c411e5f6SChristoph Hellwig static int quota_setinfo(struct super_block *sb, int type, void __user *addr) 180c411e5f6SChristoph Hellwig { 181884d179dSJan Kara struct if_dqinfo info; 182884d179dSJan Kara 183884d179dSJan Kara if (copy_from_user(&info, addr, sizeof(info))) 184884d179dSJan Kara return -EFAULT; 185f450d4feSChristoph Hellwig if (!sb_has_quota_active(sb, type)) 186f450d4feSChristoph Hellwig return -ESRCH; 187f450d4feSChristoph Hellwig if (!sb->s_qcop->set_info) 188f450d4feSChristoph Hellwig return -ENOSYS; 189884d179dSJan Kara return sb->s_qcop->set_info(sb, type, &info); 190884d179dSJan Kara } 191c411e5f6SChristoph Hellwig 192c411e5f6SChristoph Hellwig static int quota_getquota(struct super_block *sb, int type, qid_t id, 193c411e5f6SChristoph Hellwig void __user *addr) 194c411e5f6SChristoph Hellwig { 195884d179dSJan Kara struct if_dqblk idq; 196c411e5f6SChristoph Hellwig int ret; 197884d179dSJan Kara 198f450d4feSChristoph Hellwig if (!sb_has_quota_active(sb, type)) 199f450d4feSChristoph Hellwig return -ESRCH; 200f450d4feSChristoph Hellwig if (!sb->s_qcop->get_dqblk) 201f450d4feSChristoph Hellwig return -ENOSYS; 202268157baSJan Kara ret = sb->s_qcop->get_dqblk(sb, type, id, &idq); 203268157baSJan Kara if (ret) 204884d179dSJan Kara return ret; 205884d179dSJan Kara if (copy_to_user(addr, &idq, sizeof(idq))) 206884d179dSJan Kara return -EFAULT; 207884d179dSJan Kara return 0; 208884d179dSJan Kara } 209c411e5f6SChristoph Hellwig 210c411e5f6SChristoph Hellwig static int quota_setquota(struct super_block *sb, int type, qid_t id, 211c411e5f6SChristoph Hellwig void __user *addr) 212c411e5f6SChristoph Hellwig { 213884d179dSJan Kara struct if_dqblk idq; 214884d179dSJan Kara 215884d179dSJan Kara if (copy_from_user(&idq, addr, sizeof(idq))) 216884d179dSJan Kara return -EFAULT; 217f450d4feSChristoph Hellwig if (!sb_has_quota_active(sb, type)) 218f450d4feSChristoph Hellwig return -ESRCH; 219f450d4feSChristoph Hellwig if (!sb->s_qcop->set_dqblk) 220f450d4feSChristoph Hellwig return -ENOSYS; 221884d179dSJan Kara return sb->s_qcop->set_dqblk(sb, type, id, &idq); 222884d179dSJan Kara } 223884d179dSJan Kara 224c411e5f6SChristoph Hellwig static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr) 225c411e5f6SChristoph Hellwig { 226884d179dSJan Kara __u32 flags; 227884d179dSJan Kara 228884d179dSJan Kara if (copy_from_user(&flags, addr, sizeof(flags))) 229884d179dSJan Kara return -EFAULT; 230f450d4feSChristoph Hellwig if (!sb->s_qcop->set_xstate) 231f450d4feSChristoph Hellwig return -ENOSYS; 232884d179dSJan Kara return sb->s_qcop->set_xstate(sb, flags, cmd); 233884d179dSJan Kara } 234884d179dSJan Kara 235c411e5f6SChristoph Hellwig static int quota_getxstate(struct super_block *sb, void __user *addr) 236c411e5f6SChristoph Hellwig { 237c411e5f6SChristoph Hellwig struct fs_quota_stat fqs; 238c411e5f6SChristoph Hellwig int ret; 239c411e5f6SChristoph Hellwig 240f450d4feSChristoph Hellwig if (!sb->s_qcop->get_xstate) 241f450d4feSChristoph Hellwig return -ENOSYS; 242c411e5f6SChristoph Hellwig ret = sb->s_qcop->get_xstate(sb, &fqs); 243c411e5f6SChristoph Hellwig if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) 244884d179dSJan Kara return -EFAULT; 245c411e5f6SChristoph Hellwig return ret; 246884d179dSJan Kara } 247c411e5f6SChristoph Hellwig 248c411e5f6SChristoph Hellwig static int quota_setxquota(struct super_block *sb, int type, qid_t id, 249c411e5f6SChristoph Hellwig void __user *addr) 250c411e5f6SChristoph Hellwig { 251884d179dSJan Kara struct fs_disk_quota fdq; 252884d179dSJan Kara 253884d179dSJan Kara if (copy_from_user(&fdq, addr, sizeof(fdq))) 254884d179dSJan Kara return -EFAULT; 255f450d4feSChristoph Hellwig if (!sb->s_qcop->set_xquota) 256f450d4feSChristoph Hellwig return -ENOSYS; 257884d179dSJan Kara return sb->s_qcop->set_xquota(sb, type, id, &fdq); 258884d179dSJan Kara } 259c411e5f6SChristoph Hellwig 260c411e5f6SChristoph Hellwig static int quota_getxquota(struct super_block *sb, int type, qid_t id, 261c411e5f6SChristoph Hellwig void __user *addr) 262c411e5f6SChristoph Hellwig { 263884d179dSJan Kara struct fs_disk_quota fdq; 264c411e5f6SChristoph Hellwig int ret; 265884d179dSJan Kara 266f450d4feSChristoph Hellwig if (!sb->s_qcop->get_xquota) 267f450d4feSChristoph Hellwig return -ENOSYS; 268268157baSJan Kara ret = sb->s_qcop->get_xquota(sb, type, id, &fdq); 269c411e5f6SChristoph Hellwig if (!ret && copy_to_user(addr, &fdq, sizeof(fdq))) 270884d179dSJan Kara return -EFAULT; 271c411e5f6SChristoph Hellwig return ret; 272884d179dSJan Kara } 273c411e5f6SChristoph Hellwig 274c411e5f6SChristoph Hellwig /* Copy parameters and call proper function */ 275c411e5f6SChristoph Hellwig static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, 276c411e5f6SChristoph Hellwig void __user *addr) 277c411e5f6SChristoph Hellwig { 278c988afb5SChristoph Hellwig int ret; 279c988afb5SChristoph Hellwig 280c988afb5SChristoph Hellwig if (type >= (XQM_COMMAND(cmd) ? XQM_MAXQUOTAS : MAXQUOTAS)) 281c988afb5SChristoph Hellwig return -EINVAL; 282c988afb5SChristoph Hellwig if (!sb->s_qcop) 283c988afb5SChristoph Hellwig return -ENOSYS; 284c988afb5SChristoph Hellwig 285c988afb5SChristoph Hellwig ret = check_quotactl_permission(sb, type, cmd, id); 286c988afb5SChristoph Hellwig if (ret < 0) 287c988afb5SChristoph Hellwig return ret; 288c988afb5SChristoph Hellwig 289c411e5f6SChristoph Hellwig switch (cmd) { 290c411e5f6SChristoph Hellwig case Q_QUOTAON: 291c411e5f6SChristoph Hellwig return quota_quotaon(sb, type, cmd, id, addr); 292c411e5f6SChristoph Hellwig case Q_QUOTAOFF: 293f450d4feSChristoph Hellwig if (!sb->s_qcop->quota_off) 294f450d4feSChristoph Hellwig return -ENOSYS; 295c411e5f6SChristoph Hellwig return sb->s_qcop->quota_off(sb, type, 0); 296c411e5f6SChristoph Hellwig case Q_GETFMT: 297c411e5f6SChristoph Hellwig return quota_getfmt(sb, type, addr); 298c411e5f6SChristoph Hellwig case Q_GETINFO: 299c411e5f6SChristoph Hellwig return quota_getinfo(sb, type, addr); 300c411e5f6SChristoph Hellwig case Q_SETINFO: 301c411e5f6SChristoph Hellwig return quota_setinfo(sb, type, addr); 302c411e5f6SChristoph Hellwig case Q_GETQUOTA: 303c411e5f6SChristoph Hellwig return quota_getquota(sb, type, id, addr); 304c411e5f6SChristoph Hellwig case Q_SETQUOTA: 305c411e5f6SChristoph Hellwig return quota_setquota(sb, type, id, addr); 306c411e5f6SChristoph Hellwig case Q_SYNC: 307f450d4feSChristoph Hellwig if (!sb->s_qcop->quota_sync) 308f450d4feSChristoph Hellwig return -ENOSYS; 309c411e5f6SChristoph Hellwig sync_quota_sb(sb, type); 310c411e5f6SChristoph Hellwig return 0; 311c411e5f6SChristoph Hellwig case Q_XQUOTAON: 312c411e5f6SChristoph Hellwig case Q_XQUOTAOFF: 313c411e5f6SChristoph Hellwig case Q_XQUOTARM: 314c411e5f6SChristoph Hellwig return quota_setxstate(sb, cmd, addr); 315c411e5f6SChristoph Hellwig case Q_XGETQSTAT: 316c411e5f6SChristoph Hellwig return quota_getxstate(sb, addr); 317c411e5f6SChristoph Hellwig case Q_XSETQLIM: 318c411e5f6SChristoph Hellwig return quota_setxquota(sb, type, id, addr); 319c411e5f6SChristoph Hellwig case Q_XGETQUOTA: 320c411e5f6SChristoph Hellwig return quota_getxquota(sb, type, id, addr); 321884d179dSJan Kara case Q_XQUOTASYNC: 322*8c4e4acdSChristoph Hellwig /* caller already holds s_umount */ 323*8c4e4acdSChristoph Hellwig if (sb->s_flags & MS_RDONLY) 324*8c4e4acdSChristoph Hellwig return -EROFS; 325*8c4e4acdSChristoph Hellwig writeback_inodes_sb(sb); 326*8c4e4acdSChristoph Hellwig return 0; 327884d179dSJan Kara default: 328f450d4feSChristoph Hellwig return -EINVAL; 329884d179dSJan Kara } 330884d179dSJan Kara } 331884d179dSJan Kara 332884d179dSJan Kara /* 333884d179dSJan Kara * look up a superblock on which quota ops will be performed 334884d179dSJan Kara * - use the name of a block device to find the superblock thereon 335884d179dSJan Kara */ 3367a2435d8SJan Kara static struct super_block *quotactl_block(const char __user *special) 337884d179dSJan Kara { 338884d179dSJan Kara #ifdef CONFIG_BLOCK 339884d179dSJan Kara struct block_device *bdev; 340884d179dSJan Kara struct super_block *sb; 341884d179dSJan Kara char *tmp = getname(special); 342884d179dSJan Kara 343884d179dSJan Kara if (IS_ERR(tmp)) 344884d179dSJan Kara return ERR_CAST(tmp); 345884d179dSJan Kara bdev = lookup_bdev(tmp); 346884d179dSJan Kara putname(tmp); 347884d179dSJan Kara if (IS_ERR(bdev)) 348884d179dSJan Kara return ERR_CAST(bdev); 349884d179dSJan Kara sb = get_super(bdev); 350884d179dSJan Kara bdput(bdev); 351884d179dSJan Kara if (!sb) 352884d179dSJan Kara return ERR_PTR(-ENODEV); 353884d179dSJan Kara 354884d179dSJan Kara return sb; 355884d179dSJan Kara #else 356884d179dSJan Kara return ERR_PTR(-ENODEV); 357884d179dSJan Kara #endif 358884d179dSJan Kara } 359884d179dSJan Kara 360884d179dSJan Kara /* 361884d179dSJan Kara * This is the system call interface. This communicates with 362884d179dSJan Kara * the user-level programs. Currently this only supports diskquota 363884d179dSJan Kara * calls. Maybe we need to add the process quotas etc. in the future, 364884d179dSJan Kara * but we probably should use rlimits for that. 365884d179dSJan Kara */ 366884d179dSJan Kara SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special, 367884d179dSJan Kara qid_t, id, void __user *, addr) 368884d179dSJan Kara { 369884d179dSJan Kara uint cmds, type; 370884d179dSJan Kara struct super_block *sb = NULL; 371884d179dSJan Kara int ret; 372884d179dSJan Kara 373884d179dSJan Kara cmds = cmd >> SUBCMDSHIFT; 374884d179dSJan Kara type = cmd & SUBCMDMASK; 375884d179dSJan Kara 3766ae09575SChristoph Hellwig /* 3776ae09575SChristoph Hellwig * As a special case Q_SYNC can be called without a specific device. 3786ae09575SChristoph Hellwig * It will iterate all superblocks that have quota enabled and call 3796ae09575SChristoph Hellwig * the sync action on each of them. 3806ae09575SChristoph Hellwig */ 3816ae09575SChristoph Hellwig if (!special) { 3826ae09575SChristoph Hellwig if (cmds == Q_SYNC) 3836ae09575SChristoph Hellwig return quota_sync_all(type); 3846ae09575SChristoph Hellwig return -ENODEV; 3856ae09575SChristoph Hellwig } 3866ae09575SChristoph Hellwig 387884d179dSJan Kara sb = quotactl_block(special); 388884d179dSJan Kara if (IS_ERR(sb)) 389884d179dSJan Kara return PTR_ERR(sb); 390884d179dSJan Kara 391884d179dSJan Kara ret = do_quotactl(sb, type, cmds, id, addr); 392884d179dSJan Kara 3936ae09575SChristoph Hellwig drop_super(sb); 394884d179dSJan Kara return ret; 395884d179dSJan Kara } 396884d179dSJan Kara 397884d179dSJan Kara #if defined(CONFIG_COMPAT_FOR_U64_ALIGNMENT) 398884d179dSJan Kara /* 399884d179dSJan Kara * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64) 400884d179dSJan Kara * and is necessary due to alignment problems. 401884d179dSJan Kara */ 402884d179dSJan Kara struct compat_if_dqblk { 403884d179dSJan Kara compat_u64 dqb_bhardlimit; 404884d179dSJan Kara compat_u64 dqb_bsoftlimit; 405884d179dSJan Kara compat_u64 dqb_curspace; 406884d179dSJan Kara compat_u64 dqb_ihardlimit; 407884d179dSJan Kara compat_u64 dqb_isoftlimit; 408884d179dSJan Kara compat_u64 dqb_curinodes; 409884d179dSJan Kara compat_u64 dqb_btime; 410884d179dSJan Kara compat_u64 dqb_itime; 411884d179dSJan Kara compat_uint_t dqb_valid; 412884d179dSJan Kara }; 413884d179dSJan Kara 414884d179dSJan Kara /* XFS structures */ 415884d179dSJan Kara struct compat_fs_qfilestat { 416884d179dSJan Kara compat_u64 dqb_bhardlimit; 417884d179dSJan Kara compat_u64 qfs_nblks; 418884d179dSJan Kara compat_uint_t qfs_nextents; 419884d179dSJan Kara }; 420884d179dSJan Kara 421884d179dSJan Kara struct compat_fs_quota_stat { 422884d179dSJan Kara __s8 qs_version; 423884d179dSJan Kara __u16 qs_flags; 424884d179dSJan Kara __s8 qs_pad; 425884d179dSJan Kara struct compat_fs_qfilestat qs_uquota; 426884d179dSJan Kara struct compat_fs_qfilestat qs_gquota; 427884d179dSJan Kara compat_uint_t qs_incoredqs; 428884d179dSJan Kara compat_int_t qs_btimelimit; 429884d179dSJan Kara compat_int_t qs_itimelimit; 430884d179dSJan Kara compat_int_t qs_rtbtimelimit; 431884d179dSJan Kara __u16 qs_bwarnlimit; 432884d179dSJan Kara __u16 qs_iwarnlimit; 433884d179dSJan Kara }; 434884d179dSJan Kara 435884d179dSJan Kara asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special, 436884d179dSJan Kara qid_t id, void __user *addr) 437884d179dSJan Kara { 438884d179dSJan Kara unsigned int cmds; 439884d179dSJan Kara struct if_dqblk __user *dqblk; 440884d179dSJan Kara struct compat_if_dqblk __user *compat_dqblk; 441884d179dSJan Kara struct fs_quota_stat __user *fsqstat; 442884d179dSJan Kara struct compat_fs_quota_stat __user *compat_fsqstat; 443884d179dSJan Kara compat_uint_t data; 444884d179dSJan Kara u16 xdata; 445884d179dSJan Kara long ret; 446884d179dSJan Kara 447884d179dSJan Kara cmds = cmd >> SUBCMDSHIFT; 448884d179dSJan Kara 449884d179dSJan Kara switch (cmds) { 450884d179dSJan Kara case Q_GETQUOTA: 451884d179dSJan Kara dqblk = compat_alloc_user_space(sizeof(struct if_dqblk)); 452884d179dSJan Kara compat_dqblk = addr; 453884d179dSJan Kara ret = sys_quotactl(cmd, special, id, dqblk); 454884d179dSJan Kara if (ret) 455884d179dSJan Kara break; 456884d179dSJan Kara if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) || 457884d179dSJan Kara get_user(data, &dqblk->dqb_valid) || 458884d179dSJan Kara put_user(data, &compat_dqblk->dqb_valid)) 459884d179dSJan Kara ret = -EFAULT; 460884d179dSJan Kara break; 461884d179dSJan Kara case Q_SETQUOTA: 462884d179dSJan Kara dqblk = compat_alloc_user_space(sizeof(struct if_dqblk)); 463884d179dSJan Kara compat_dqblk = addr; 464884d179dSJan Kara ret = -EFAULT; 465884d179dSJan Kara if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) || 466884d179dSJan Kara get_user(data, &compat_dqblk->dqb_valid) || 467884d179dSJan Kara put_user(data, &dqblk->dqb_valid)) 468884d179dSJan Kara break; 469884d179dSJan Kara ret = sys_quotactl(cmd, special, id, dqblk); 470884d179dSJan Kara break; 471884d179dSJan Kara case Q_XGETQSTAT: 472884d179dSJan Kara fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat)); 473884d179dSJan Kara compat_fsqstat = addr; 474884d179dSJan Kara ret = sys_quotactl(cmd, special, id, fsqstat); 475884d179dSJan Kara if (ret) 476884d179dSJan Kara break; 477884d179dSJan Kara ret = -EFAULT; 478884d179dSJan Kara /* Copying qs_version, qs_flags, qs_pad */ 479884d179dSJan Kara if (copy_in_user(compat_fsqstat, fsqstat, 480884d179dSJan Kara offsetof(struct compat_fs_quota_stat, qs_uquota))) 481884d179dSJan Kara break; 482884d179dSJan Kara /* Copying qs_uquota */ 483884d179dSJan Kara if (copy_in_user(&compat_fsqstat->qs_uquota, 484884d179dSJan Kara &fsqstat->qs_uquota, 485884d179dSJan Kara sizeof(compat_fsqstat->qs_uquota)) || 486884d179dSJan Kara get_user(data, &fsqstat->qs_uquota.qfs_nextents) || 487884d179dSJan Kara put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents)) 488884d179dSJan Kara break; 489884d179dSJan Kara /* Copying qs_gquota */ 490884d179dSJan Kara if (copy_in_user(&compat_fsqstat->qs_gquota, 491884d179dSJan Kara &fsqstat->qs_gquota, 492884d179dSJan Kara sizeof(compat_fsqstat->qs_gquota)) || 493884d179dSJan Kara get_user(data, &fsqstat->qs_gquota.qfs_nextents) || 494884d179dSJan Kara put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents)) 495884d179dSJan Kara break; 496884d179dSJan Kara /* Copying the rest */ 497884d179dSJan Kara if (copy_in_user(&compat_fsqstat->qs_incoredqs, 498884d179dSJan Kara &fsqstat->qs_incoredqs, 499884d179dSJan Kara sizeof(struct compat_fs_quota_stat) - 500884d179dSJan Kara offsetof(struct compat_fs_quota_stat, qs_incoredqs)) || 501884d179dSJan Kara get_user(xdata, &fsqstat->qs_iwarnlimit) || 502884d179dSJan Kara put_user(xdata, &compat_fsqstat->qs_iwarnlimit)) 503884d179dSJan Kara break; 504884d179dSJan Kara ret = 0; 505884d179dSJan Kara break; 506884d179dSJan Kara default: 507884d179dSJan Kara ret = sys_quotactl(cmd, special, id, addr); 508884d179dSJan Kara } 509884d179dSJan Kara return ret; 510884d179dSJan Kara } 511884d179dSJan Kara #endif 51286e931a3SSteven Whitehouse 51386e931a3SSteven Whitehouse 51486e931a3SSteven Whitehouse #ifdef CONFIG_QUOTA_NETLINK_INTERFACE 51586e931a3SSteven Whitehouse 51686e931a3SSteven Whitehouse /* Netlink family structure for quota */ 51786e931a3SSteven Whitehouse static struct genl_family quota_genl_family = { 51886e931a3SSteven Whitehouse .id = GENL_ID_GENERATE, 51986e931a3SSteven Whitehouse .hdrsize = 0, 52086e931a3SSteven Whitehouse .name = "VFS_DQUOT", 52186e931a3SSteven Whitehouse .version = 1, 52286e931a3SSteven Whitehouse .maxattr = QUOTA_NL_A_MAX, 52386e931a3SSteven Whitehouse }; 52486e931a3SSteven Whitehouse 52586e931a3SSteven Whitehouse /** 52686e931a3SSteven Whitehouse * quota_send_warning - Send warning to userspace about exceeded quota 52786e931a3SSteven Whitehouse * @type: The quota type: USRQQUOTA, GRPQUOTA,... 52886e931a3SSteven Whitehouse * @id: The user or group id of the quota that was exceeded 52986e931a3SSteven Whitehouse * @dev: The device on which the fs is mounted (sb->s_dev) 53086e931a3SSteven Whitehouse * @warntype: The type of the warning: QUOTA_NL_... 53186e931a3SSteven Whitehouse * 53286e931a3SSteven Whitehouse * This can be used by filesystems (including those which don't use 53386e931a3SSteven Whitehouse * dquot) to send a message to userspace relating to quota limits. 53486e931a3SSteven Whitehouse * 53586e931a3SSteven Whitehouse */ 53686e931a3SSteven Whitehouse 53786e931a3SSteven Whitehouse void quota_send_warning(short type, unsigned int id, dev_t dev, 53886e931a3SSteven Whitehouse const char warntype) 53986e931a3SSteven Whitehouse { 54086e931a3SSteven Whitehouse static atomic_t seq; 54186e931a3SSteven Whitehouse struct sk_buff *skb; 54286e931a3SSteven Whitehouse void *msg_head; 54386e931a3SSteven Whitehouse int ret; 54486e931a3SSteven Whitehouse int msg_size = 4 * nla_total_size(sizeof(u32)) + 54586e931a3SSteven Whitehouse 2 * nla_total_size(sizeof(u64)); 54686e931a3SSteven Whitehouse 54786e931a3SSteven Whitehouse /* We have to allocate using GFP_NOFS as we are called from a 54886e931a3SSteven Whitehouse * filesystem performing write and thus further recursion into 54986e931a3SSteven Whitehouse * the fs to free some data could cause deadlocks. */ 55086e931a3SSteven Whitehouse skb = genlmsg_new(msg_size, GFP_NOFS); 55186e931a3SSteven Whitehouse if (!skb) { 55286e931a3SSteven Whitehouse printk(KERN_ERR 55386e931a3SSteven Whitehouse "VFS: Not enough memory to send quota warning.\n"); 55486e931a3SSteven Whitehouse return; 55586e931a3SSteven Whitehouse } 55686e931a3SSteven Whitehouse msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), 55786e931a3SSteven Whitehouse "a_genl_family, 0, QUOTA_NL_C_WARNING); 55886e931a3SSteven Whitehouse if (!msg_head) { 55986e931a3SSteven Whitehouse printk(KERN_ERR 56086e931a3SSteven Whitehouse "VFS: Cannot store netlink header in quota warning.\n"); 56186e931a3SSteven Whitehouse goto err_out; 56286e931a3SSteven Whitehouse } 56386e931a3SSteven Whitehouse ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type); 56486e931a3SSteven Whitehouse if (ret) 56586e931a3SSteven Whitehouse goto attr_err_out; 56686e931a3SSteven Whitehouse ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id); 56786e931a3SSteven Whitehouse if (ret) 56886e931a3SSteven Whitehouse goto attr_err_out; 56986e931a3SSteven Whitehouse ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype); 57086e931a3SSteven Whitehouse if (ret) 57186e931a3SSteven Whitehouse goto attr_err_out; 57286e931a3SSteven Whitehouse ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, MAJOR(dev)); 57386e931a3SSteven Whitehouse if (ret) 57486e931a3SSteven Whitehouse goto attr_err_out; 57586e931a3SSteven Whitehouse ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev)); 57686e931a3SSteven Whitehouse if (ret) 57786e931a3SSteven Whitehouse goto attr_err_out; 57886e931a3SSteven Whitehouse ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid()); 57986e931a3SSteven Whitehouse if (ret) 58086e931a3SSteven Whitehouse goto attr_err_out; 58186e931a3SSteven Whitehouse genlmsg_end(skb, msg_head); 58286e931a3SSteven Whitehouse 58386e931a3SSteven Whitehouse genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); 58486e931a3SSteven Whitehouse return; 58586e931a3SSteven Whitehouse attr_err_out: 58686e931a3SSteven Whitehouse printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); 58786e931a3SSteven Whitehouse err_out: 58886e931a3SSteven Whitehouse kfree_skb(skb); 58986e931a3SSteven Whitehouse } 59086e931a3SSteven Whitehouse EXPORT_SYMBOL(quota_send_warning); 59186e931a3SSteven Whitehouse 59286e931a3SSteven Whitehouse static int __init quota_init(void) 59386e931a3SSteven Whitehouse { 59486e931a3SSteven Whitehouse if (genl_register_family("a_genl_family) != 0) 59586e931a3SSteven Whitehouse printk(KERN_ERR 59686e931a3SSteven Whitehouse "VFS: Failed to create quota netlink interface.\n"); 59786e931a3SSteven Whitehouse return 0; 59886e931a3SSteven Whitehouse }; 59986e931a3SSteven Whitehouse 60086e931a3SSteven Whitehouse module_init(quota_init); 60186e931a3SSteven Whitehouse #endif 60286e931a3SSteven Whitehouse 603