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