Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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