aboutsummaryrefslogtreecommitdiffstats
path: root/fs/quota.c
diff options
context:
space:
mode:
authorVasily Tarasov <vtaras@openvz.org>2007-07-16 02:41:12 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 12:05:48 -0400
commitb716395e2b8e450e294537de0c91476ded2f0395 (patch)
tree7f8fd39022c1caca71abb30303a453d77cf4d905 /fs/quota.c
parent4b7775870b69129e640ed583c9b362d5cd66159d (diff)
diskquota: 32bit quota tools on 64bit architectures
OpenVZ Linux kernel team has discovered the problem with 32bit quota tools working on 64bit architectures. In 2.6.10 kernel sys32_quotactl() function was replaced by sys_quotactl() with the comment "sys_quotactl seems to be 32/64bit clean, enable it for 32bit" However this isn't right. Look at if_dqblk structure: struct if_dqblk { __u64 dqb_bhardlimit; __u64 dqb_bsoftlimit; __u64 dqb_curspace; __u64 dqb_ihardlimit; __u64 dqb_isoftlimit; __u64 dqb_curinodes; __u64 dqb_btime; __u64 dqb_itime; __u32 dqb_valid; }; For 32 bit quota tools sizeof(if_dqblk) == 0x44. But for 64 bit kernel its size is 0x48, 'cause of alignment! Thus we got a problem. Attached patch reintroduce sys32_quotactl() function, that handles this and related situations. [michal.k.k.piotrowski@gmail.com: build fix] [akpm@linux-foundation.org: Make it link with CONFIG_QUOTA=n] Signed-off-by: Vasily Tarasov <vtaras@openvz.org> Cc: Andi Kleen <ak@suse.de> Cc: "Luck, Tony" <tony.luck@intel.com> Cc: Jan Kara <jack@ucw.cz> Cc: <linux-arch@vger.kernel.org> Signed-off-by: Michal Piotrowski <michal.k.k.piotrowski@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/quota.c')
-rw-r--r--fs/quota.c118
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 */
21static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) 23static 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 */
395struct 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 */
408struct compat_fs_qfilestat {
409 compat_u64 dqb_bhardlimit;
410 compat_u64 qfs_nblks;
411 compat_uint_t qfs_nextents;
412};
413
414struct 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
428asmlinkage 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