diff options
Diffstat (limited to 'fs/quota.c')
| -rw-r--r-- | fs/quota.c | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/fs/quota.c b/fs/quota.c index 9f237d6182c9..e6577ac15a6c 100644 --- a/fs/quota.c +++ b/fs/quota.c | |||
| @@ -10,12 +10,14 @@ | |||
| 10 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
| 11 | #include <asm/current.h> | 11 | #include <asm/current.h> |
| 12 | #include <asm/uaccess.h> | 12 | #include <asm/uaccess.h> |
| 13 | #include <linux/compat.h> | ||
| 13 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
| 14 | #include <linux/security.h> | 15 | #include <linux/security.h> |
| 15 | #include <linux/syscalls.h> | 16 | #include <linux/syscalls.h> |
| 16 | #include <linux/buffer_head.h> | 17 | #include <linux/buffer_head.h> |
| 17 | #include <linux/capability.h> | 18 | #include <linux/capability.h> |
| 18 | #include <linux/quotaops.h> | 19 | #include <linux/quotaops.h> |
| 20 | #include <linux/types.h> | ||
| 19 | 21 | ||
| 20 | /* Check validity of generic quotactl commands */ | 22 | /* Check validity of generic quotactl commands */ |
| 21 | static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) | 23 | static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) |
| @@ -384,3 +386,119 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t | |||
| 384 | 386 | ||
| 385 | return ret; | 387 | return ret; |
| 386 | } | 388 | } |
| 389 | |||
| 390 | #if defined(CONFIG_X86_64) || defined(CONFIG_IA64) | ||
| 391 | /* | ||
| 392 | * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64) | ||
| 393 | * and is necessary due to alignment problems. | ||
| 394 | */ | ||
| 395 | struct compat_if_dqblk { | ||
| 396 | compat_u64 dqb_bhardlimit; | ||
| 397 | compat_u64 dqb_bsoftlimit; | ||
| 398 | compat_u64 dqb_curspace; | ||
| 399 | compat_u64 dqb_ihardlimit; | ||
| 400 | compat_u64 dqb_isoftlimit; | ||
| 401 | compat_u64 dqb_curinodes; | ||
| 402 | compat_u64 dqb_btime; | ||
| 403 | compat_u64 dqb_itime; | ||
| 404 | compat_uint_t dqb_valid; | ||
| 405 | }; | ||
| 406 | |||
| 407 | /* XFS structures */ | ||
| 408 | struct compat_fs_qfilestat { | ||
| 409 | compat_u64 dqb_bhardlimit; | ||
| 410 | compat_u64 qfs_nblks; | ||
| 411 | compat_uint_t qfs_nextents; | ||
| 412 | }; | ||
| 413 | |||
| 414 | struct compat_fs_quota_stat { | ||
| 415 | __s8 qs_version; | ||
| 416 | __u16 qs_flags; | ||
| 417 | __s8 qs_pad; | ||
| 418 | struct compat_fs_qfilestat qs_uquota; | ||
| 419 | struct compat_fs_qfilestat qs_gquota; | ||
| 420 | compat_uint_t qs_incoredqs; | ||
| 421 | compat_int_t qs_btimelimit; | ||
| 422 | compat_int_t qs_itimelimit; | ||
| 423 | compat_int_t qs_rtbtimelimit; | ||
| 424 | __u16 qs_bwarnlimit; | ||
| 425 | __u16 qs_iwarnlimit; | ||
| 426 | }; | ||
| 427 | |||
| 428 | asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special, | ||
| 429 | qid_t id, void __user *addr) | ||
| 430 | { | ||
| 431 | unsigned int cmds; | ||
| 432 | struct if_dqblk __user *dqblk; | ||
| 433 | struct compat_if_dqblk __user *compat_dqblk; | ||
| 434 | struct fs_quota_stat __user *fsqstat; | ||
| 435 | struct compat_fs_quota_stat __user *compat_fsqstat; | ||
| 436 | compat_uint_t data; | ||
| 437 | u16 xdata; | ||
| 438 | long ret; | ||
| 439 | |||
| 440 | cmds = cmd >> SUBCMDSHIFT; | ||
| 441 | |||
| 442 | switch (cmds) { | ||
| 443 | case Q_GETQUOTA: | ||
| 444 | dqblk = compat_alloc_user_space(sizeof(struct if_dqblk)); | ||
| 445 | compat_dqblk = addr; | ||
| 446 | ret = sys_quotactl(cmd, special, id, dqblk); | ||
| 447 | if (ret) | ||
| 448 | break; | ||
| 449 | if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) || | ||
| 450 | get_user(data, &dqblk->dqb_valid) || | ||
| 451 | put_user(data, &compat_dqblk->dqb_valid)) | ||
| 452 | ret = -EFAULT; | ||
| 453 | break; | ||
| 454 | case Q_SETQUOTA: | ||
| 455 | dqblk = compat_alloc_user_space(sizeof(struct if_dqblk)); | ||
| 456 | compat_dqblk = addr; | ||
| 457 | ret = -EFAULT; | ||
| 458 | if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) || | ||
| 459 | get_user(data, &compat_dqblk->dqb_valid) || | ||
| 460 | put_user(data, &dqblk->dqb_valid)) | ||
| 461 | break; | ||
| 462 | ret = sys_quotactl(cmd, special, id, dqblk); | ||
| 463 | break; | ||
| 464 | case Q_XGETQSTAT: | ||
| 465 | fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat)); | ||
| 466 | compat_fsqstat = addr; | ||
| 467 | ret = sys_quotactl(cmd, special, id, fsqstat); | ||
| 468 | if (ret) | ||
| 469 | break; | ||
| 470 | ret = -EFAULT; | ||
| 471 | /* Copying qs_version, qs_flags, qs_pad */ | ||
| 472 | if (copy_in_user(compat_fsqstat, fsqstat, | ||
| 473 | offsetof(struct compat_fs_quota_stat, qs_uquota))) | ||
| 474 | break; | ||
| 475 | /* Copying qs_uquota */ | ||
| 476 | if (copy_in_user(&compat_fsqstat->qs_uquota, | ||
| 477 | &fsqstat->qs_uquota, | ||
| 478 | sizeof(compat_fsqstat->qs_uquota)) || | ||
| 479 | get_user(data, &fsqstat->qs_uquota.qfs_nextents) || | ||
| 480 | put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents)) | ||
| 481 | break; | ||
| 482 | /* Copying qs_gquota */ | ||
| 483 | if (copy_in_user(&compat_fsqstat->qs_gquota, | ||
| 484 | &fsqstat->qs_gquota, | ||
| 485 | sizeof(compat_fsqstat->qs_gquota)) || | ||
| 486 | get_user(data, &fsqstat->qs_gquota.qfs_nextents) || | ||
| 487 | put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents)) | ||
| 488 | break; | ||
| 489 | /* Copying the rest */ | ||
| 490 | if (copy_in_user(&compat_fsqstat->qs_incoredqs, | ||
| 491 | &fsqstat->qs_incoredqs, | ||
| 492 | sizeof(struct compat_fs_quota_stat) - | ||
| 493 | offsetof(struct compat_fs_quota_stat, qs_incoredqs)) || | ||
| 494 | get_user(xdata, &fsqstat->qs_iwarnlimit) || | ||
| 495 | put_user(xdata, &compat_fsqstat->qs_iwarnlimit)) | ||
| 496 | break; | ||
| 497 | ret = 0; | ||
| 498 | break; | ||
| 499 | default: | ||
| 500 | ret = sys_quotactl(cmd, special, id, addr); | ||
| 501 | } | ||
| 502 | return ret; | ||
| 503 | } | ||
| 504 | #endif | ||
