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

[PATCH] disk quotas fail when /etc/mtab is symlinked to /proc/mounts

If /etc/mtab is a regular file all of the mount options (of a file system)
are written to /etc/mtab by the mount command. The quota tools look there
for the quota strings for their operation. If, however, /etc/mtab is a
symlink to /proc/mounts (a "good thing" in some environments) the tools
don't write anything - they assume the kernel will take care of things.

While the quota options are sent down to the kernel via the mount system
call and the file system codes handle them properly unfortunately there is
no code to echo the quota strings into /proc/mounts and the quota tools
fail in the symlink case.

The attached patchs modify the EXT[2|3] and JFS codes to add the necessary
hooks. The show_options function of each file system in these patches
currently deal with only those things that seemed related to quotas;
especially in the EXT3 case more can be done (later?).

Jan Kara also noted the difficulty in moving these changes above the FS
codes responding similarly to myself to Andrew's comment about possible
VFS migration. Issue summary:

- FS codes have to process the entire string of options anyway.

- Only FS codes that use quotas must have a show_options function (for
quotas to work properly) however quotas are only used in a small number
of FS.

- Since most of the quota using FS support other options these FS codes
should have the a show_options function to show those options - and the
quota echoing becomes virtually negligible.

Based on feedback I have modified my patches from the original:

JFS a missing patch has been restored to the posting
EXT[2|3] and JFS always use the show_options function
- Each FS has at least one FS specific option displayed
- QUOTA output is under a CONFIG_QUOTA ifdef
- a follow-on patch will add a multitude of options for each FS
EXT[2|3] and JFS "quota" is treated as "usrquota"
EXT3 journalled data check for journalled quota removed
EXT[2|3] mount when quota specified but not compiled in

- no changes from my original patch. I tested the patch and the codes
warn but

- still mount. With all due respection I believe the comments
otherwise were a

- misread of the patch. Please reread/test and comment. XFS patch
removed - the XFS team already made the necessary changes EXT3 mixing
old and new quotas are handled differently (not purely exclusive)

- if old and new quotas for the same type are used together the old
type is silently depricated for compatability (e.g. usrquota and
usrjquota)

- mixing of old and new quotas is an error (e.g. usrjquota and
grpquota)

Signed-off-by: Mark Bellon <mbellon@mvista.com>
Acked-by: Dave Kleikamp <shaggy@austin.ibm.com>
Cc: Jan Kara <jack@ucw.cz>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Mark Bellon and committed by
Linus Torvalds
8fc2751b c9237156

+186 -21
+52 -7
fs/ext2/super.c
··· 19 19 #include <linux/config.h> 20 20 #include <linux/module.h> 21 21 #include <linux/string.h> 22 + #include <linux/fs.h> 22 23 #include <linux/slab.h> 23 24 #include <linux/init.h> 24 25 #include <linux/blkdev.h> ··· 28 27 #include <linux/buffer_head.h> 29 28 #include <linux/smp_lock.h> 30 29 #include <linux/vfs.h> 30 + #include <linux/seq_file.h> 31 + #include <linux/mount.h> 31 32 #include <asm/uaccess.h> 32 33 #include "ext2.h" 33 34 #include "xattr.h" ··· 204 201 #endif 205 202 } 206 203 204 + static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs) 205 + { 206 + struct ext2_sb_info *sbi = EXT2_SB(vfs->mnt_sb); 207 + 208 + if (sbi->s_mount_opt & EXT2_MOUNT_GRPID) 209 + seq_puts(seq, ",grpid"); 210 + else 211 + seq_puts(seq, ",nogrpid"); 212 + 213 + #if defined(CONFIG_QUOTA) 214 + if (sbi->s_mount_opt & EXT2_MOUNT_USRQUOTA) 215 + seq_puts(seq, ",usrquota"); 216 + 217 + if (sbi->s_mount_opt & EXT2_MOUNT_GRPQUOTA) 218 + seq_puts(seq, ",grpquota"); 219 + #endif 220 + 221 + return 0; 222 + } 223 + 207 224 #ifdef CONFIG_QUOTA 208 225 static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off); 209 226 static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off); ··· 241 218 .statfs = ext2_statfs, 242 219 .remount_fs = ext2_remount, 243 220 .clear_inode = ext2_clear_inode, 221 + .show_options = ext2_show_options, 244 222 #ifdef CONFIG_QUOTA 245 223 .quota_read = ext2_quota_read, 246 224 .quota_write = ext2_quota_write, ··· 280 256 281 257 enum { 282 258 Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, 283 - Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, 284 - Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, 285 - Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip, 286 - Opt_ignore, Opt_err, 259 + Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, 260 + Opt_err_ro, Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, 261 + Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr, 262 + Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota, 263 + Opt_usrquota, Opt_grpquota 287 264 }; 288 265 289 266 static match_table_t tokens = { ··· 313 288 {Opt_acl, "acl"}, 314 289 {Opt_noacl, "noacl"}, 315 290 {Opt_xip, "xip"}, 316 - {Opt_ignore, "grpquota"}, 291 + {Opt_grpquota, "grpquota"}, 317 292 {Opt_ignore, "noquota"}, 318 - {Opt_ignore, "quota"}, 319 - {Opt_ignore, "usrquota"}, 293 + {Opt_quota, "quota"}, 294 + {Opt_usrquota, "usrquota"}, 320 295 {Opt_err, NULL} 321 296 }; 322 297 ··· 431 406 printk("EXT2 xip option not supported\n"); 432 407 #endif 433 408 break; 409 + 410 + #if defined(CONFIG_QUOTA) 411 + case Opt_quota: 412 + case Opt_usrquota: 413 + set_opt(sbi->s_mount_opt, USRQUOTA); 414 + break; 415 + 416 + case Opt_grpquota: 417 + set_opt(sbi->s_mount_opt, GRPQUOTA); 418 + break; 419 + #else 420 + case Opt_quota: 421 + case Opt_usrquota: 422 + case Opt_grpquota: 423 + printk(KERN_ERR 424 + "EXT2-fs: quota operations not supported.\n"); 425 + 426 + break; 427 + #endif 428 + 434 429 case Opt_ignore: 435 430 break; 436 431 default:
+81 -11
fs/ext3/super.c
··· 35 35 #include <linux/mount.h> 36 36 #include <linux/namei.h> 37 37 #include <linux/quotaops.h> 38 + #include <linux/seq_file.h> 38 39 #include <asm/uaccess.h> 39 40 #include "xattr.h" 40 41 #include "acl.h" ··· 510 509 kfree(rsv); 511 510 } 512 511 513 - #ifdef CONFIG_QUOTA 512 + static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) 513 + { 514 + struct ext3_sb_info *sbi = EXT3_SB(vfs->mnt_sb); 514 515 516 + if (sbi->s_mount_opt & EXT3_MOUNT_JOURNAL_DATA) 517 + seq_puts(seq, ",data=journal"); 518 + 519 + if (sbi->s_mount_opt & EXT3_MOUNT_ORDERED_DATA) 520 + seq_puts(seq, ",data=ordered"); 521 + 522 + if (sbi->s_mount_opt & EXT3_MOUNT_WRITEBACK_DATA) 523 + seq_puts(seq, ",data=writeback"); 524 + 525 + #if defined(CONFIG_QUOTA) 526 + if (sbi->s_jquota_fmt) 527 + seq_printf(seq, ",jqfmt=%s", 528 + (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold": "vfsv0"); 529 + 530 + if (sbi->s_qf_names[USRQUOTA]) 531 + seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]); 532 + 533 + if (sbi->s_qf_names[GRPQUOTA]) 534 + seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]); 535 + 536 + if (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA) 537 + seq_puts(seq, ",usrquota"); 538 + 539 + if (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA) 540 + seq_puts(seq, ",grpquota"); 541 + #endif 542 + 543 + return 0; 544 + } 545 + 546 + #ifdef CONFIG_QUOTA 515 547 #define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group") 516 548 #define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA)) 517 549 ··· 603 569 .statfs = ext3_statfs, 604 570 .remount_fs = ext3_remount, 605 571 .clear_inode = ext3_clear_inode, 572 + .show_options = ext3_show_options, 606 573 #ifdef CONFIG_QUOTA 607 574 .quota_read = ext3_quota_read, 608 575 .quota_write = ext3_quota_write, ··· 625 590 Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, 626 591 Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, 627 592 Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, 628 - Opt_ignore, Opt_barrier, Opt_err, Opt_resize, 593 + Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota, 594 + Opt_grpquota 629 595 }; 630 596 631 597 static match_table_t tokens = { ··· 670 634 {Opt_grpjquota, "grpjquota=%s"}, 671 635 {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, 672 636 {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, 673 - {Opt_quota, "grpquota"}, 637 + {Opt_grpquota, "grpquota"}, 674 638 {Opt_noquota, "noquota"}, 675 639 {Opt_quota, "quota"}, 676 - {Opt_quota, "usrquota"}, 640 + {Opt_usrquota, "usrquota"}, 677 641 {Opt_barrier, "barrier=%u"}, 678 642 {Opt_err, NULL}, 679 643 {Opt_resize, "resize"}, ··· 939 903 sbi->s_jquota_fmt = QFMT_VFS_V0; 940 904 break; 941 905 case Opt_quota: 906 + case Opt_usrquota: 942 907 set_opt(sbi->s_mount_opt, QUOTA); 908 + set_opt(sbi->s_mount_opt, USRQUOTA); 909 + break; 910 + case Opt_grpquota: 911 + set_opt(sbi->s_mount_opt, QUOTA); 912 + set_opt(sbi->s_mount_opt, GRPQUOTA); 943 913 break; 944 914 case Opt_noquota: 945 915 if (sb_any_quota_enabled(sb)) { ··· 954 912 return 0; 955 913 } 956 914 clear_opt(sbi->s_mount_opt, QUOTA); 915 + clear_opt(sbi->s_mount_opt, USRQUOTA); 916 + clear_opt(sbi->s_mount_opt, GRPQUOTA); 957 917 break; 958 918 #else 919 + case Opt_quota: 920 + case Opt_usrquota: 921 + case Opt_grpquota: 959 922 case Opt_usrjquota: 960 923 case Opt_grpjquota: 961 924 case Opt_offusrjquota: ··· 971 924 "EXT3-fs: journalled quota options not " 972 925 "supported.\n"); 973 926 break; 974 - case Opt_quota: 975 927 case Opt_noquota: 976 928 break; 977 929 #endif ··· 1008 962 } 1009 963 } 1010 964 #ifdef CONFIG_QUOTA 1011 - if (!sbi->s_jquota_fmt && (sbi->s_qf_names[USRQUOTA] || 1012 - sbi->s_qf_names[GRPQUOTA])) { 1013 - printk(KERN_ERR 1014 - "EXT3-fs: journalled quota format not specified.\n"); 1015 - return 0; 965 + if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) { 966 + if ((sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA) && 967 + sbi->s_qf_names[USRQUOTA]) 968 + clear_opt(sbi->s_mount_opt, USRQUOTA); 969 + 970 + if ((sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA) && 971 + sbi->s_qf_names[GRPQUOTA]) 972 + clear_opt(sbi->s_mount_opt, GRPQUOTA); 973 + 974 + if ((sbi->s_qf_names[USRQUOTA] && 975 + (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA)) || 976 + (sbi->s_qf_names[GRPQUOTA] && 977 + (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA))) { 978 + printk(KERN_ERR "EXT3-fs: old and new quota " 979 + "format mixing.\n"); 980 + return 0; 981 + } 982 + 983 + if (!sbi->s_jquota_fmt) { 984 + printk(KERN_ERR "EXT3-fs: journalled quota format " 985 + "not specified.\n"); 986 + return 0; 987 + } 988 + } else { 989 + if (sbi->s_jquota_fmt) { 990 + printk(KERN_ERR "EXT3-fs: journalled quota format " 991 + "specified with no journalling " 992 + "enabled.\n"); 993 + return 0; 994 + } 1016 995 } 1017 996 #endif 1018 - 1019 997 return 1; 1020 998 } 1021 999
+3
fs/jfs/jfs_filsys.h
··· 37 37 #define JFS_ERR_CONTINUE 0x00000004 /* continue */ 38 38 #define JFS_ERR_PANIC 0x00000008 /* panic */ 39 39 40 + #define JFS_USRQUOTA 0x00000010 41 + #define JFS_GRPQUOTA 0x00000020 42 + 40 43 /* platform option (conditional compilation) */ 41 44 #define JFS_AIX 0x80000000 /* AIX support */ 42 45 /* POSIX name/directory support */
+45 -3
fs/jfs/super.c
··· 23 23 #include <linux/parser.h> 24 24 #include <linux/completion.h> 25 25 #include <linux/vfs.h> 26 + #include <linux/mount.h> 26 27 #include <linux/moduleparam.h> 27 28 #include <linux/posix_acl.h> 28 29 #include <asm/uaccess.h> 30 + #include <linux/seq_file.h> 29 31 30 32 #include "jfs_incore.h" 31 33 #include "jfs_filsys.h" ··· 194 192 195 193 enum { 196 194 Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, 197 - Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, 195 + Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota, 196 + Opt_usrquota, Opt_grpquota 198 197 }; 199 198 200 199 static match_table_t tokens = { ··· 207 204 {Opt_errors, "errors=%s"}, 208 205 {Opt_ignore, "noquota"}, 209 206 {Opt_ignore, "quota"}, 210 - {Opt_ignore, "usrquota"}, 211 - {Opt_ignore, "grpquota"}, 207 + {Opt_usrquota, "usrquota"}, 208 + {Opt_grpquota, "grpquota"}, 212 209 {Opt_err, NULL} 213 210 }; 214 211 ··· 296 293 } 297 294 break; 298 295 } 296 + 297 + #if defined(CONFIG_QUOTA) 298 + case Opt_quota: 299 + case Opt_usrquota: 300 + *flag |= JFS_USRQUOTA; 301 + break; 302 + case Opt_grpquota: 303 + *flag |= JFS_GRPQUOTA; 304 + break; 305 + #else 306 + case Opt_usrquota: 307 + case Opt_grpquota: 308 + case Opt_quota: 309 + printk(KERN_ERR 310 + "JFS: quota operations not supported\n"); 311 + break; 312 + #endif 313 + 299 314 default: 300 315 printk("jfs: Unrecognized mount option \"%s\" " 301 316 " or missing value\n", p); ··· 560 539 return 0; 561 540 } 562 541 542 + static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs) 543 + { 544 + struct jfs_sb_info *sbi = JFS_SBI(vfs->mnt_sb); 545 + 546 + if (sbi->flag & JFS_NOINTEGRITY) 547 + seq_puts(seq, ",nointegrity"); 548 + else 549 + seq_puts(seq, ",integrity"); 550 + 551 + #if defined(CONFIG_QUOTA) 552 + if (sbi->flag & JFS_USRQUOTA) 553 + seq_puts(seq, ",usrquota"); 554 + 555 + if (sbi->flag & JFS_GRPQUOTA) 556 + seq_puts(seq, ",grpquota"); 557 + #endif 558 + 559 + return 0; 560 + } 561 + 563 562 static struct super_operations jfs_super_operations = { 564 563 .alloc_inode = jfs_alloc_inode, 565 564 .destroy_inode = jfs_destroy_inode, ··· 593 552 .unlockfs = jfs_unlockfs, 594 553 .statfs = jfs_statfs, 595 554 .remount_fs = jfs_remount, 555 + .show_options = jfs_show_options 596 556 }; 597 557 598 558 static struct export_operations jfs_export_operations = {
+3
include/linux/ext2_fs.h
··· 313 313 #define EXT2_MOUNT_XATTR_USER 0x004000 /* Extended user attributes */ 314 314 #define EXT2_MOUNT_POSIX_ACL 0x008000 /* POSIX Access Control Lists */ 315 315 #define EXT2_MOUNT_XIP 0x010000 /* Execute in place */ 316 + #define EXT2_MOUNT_USRQUOTA 0x020000 /* user quota */ 317 + #define EXT2_MOUNT_GRPQUOTA 0x040000 /* group quota */ 318 + 316 319 317 320 #define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt 318 321 #define set_opt(o, opt) o |= EXT2_MOUNT_##opt
+2
include/linux/ext3_fs.h
··· 373 373 #define EXT3_MOUNT_BARRIER 0x20000 /* Use block barriers */ 374 374 #define EXT3_MOUNT_NOBH 0x40000 /* No bufferheads */ 375 375 #define EXT3_MOUNT_QUOTA 0x80000 /* Some quota option set */ 376 + #define EXT3_MOUNT_USRQUOTA 0x100000 /* "old" user quota */ 377 + #define EXT3_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */ 376 378 377 379 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ 378 380 #ifndef _LINUX_EXT2_FS_H