ocfs2: Implementation of local and global quota file handling
[deliverable/linux.git] / fs / ocfs2 / super.c
index 304b63ac78cfcceeef4759c66c5f72952477909d..7bb83e41581e2bffab6fde9940a4a33ed9e5035b 100644 (file)
 #include "uptodate.h"
 #include "ver.h"
 #include "xattr.h"
+#include "quota.h"
 
 #include "buffer_head_io.h"
 
 static struct kmem_cache *ocfs2_inode_cachep = NULL;
+struct kmem_cache *ocfs2_dquot_cachep;
+struct kmem_cache *ocfs2_qf_chunk_cachep;
 
 /* OCFS2 needs to schedule several differnt types of work which
  * require cluster locking, disk I/O, recovery waits, etc. Since these
@@ -137,6 +140,8 @@ static const struct super_operations ocfs2_sops = {
        .put_super      = ocfs2_put_super,
        .remount_fs     = ocfs2_remount,
        .show_options   = ocfs2_show_options,
+       .quota_read     = ocfs2_quota_read,
+       .quota_write    = ocfs2_quota_write,
 };
 
 enum {
@@ -158,6 +163,8 @@ enum {
        Opt_user_xattr,
        Opt_nouser_xattr,
        Opt_inode64,
+       Opt_acl,
+       Opt_noacl,
        Opt_err,
 };
 
@@ -180,6 +187,8 @@ static const match_table_t tokens = {
        {Opt_user_xattr, "user_xattr"},
        {Opt_nouser_xattr, "nouser_xattr"},
        {Opt_inode64, "inode64"},
+       {Opt_acl, "acl"},
+       {Opt_noacl, "noacl"},
        {Opt_err, NULL}
 };
 
@@ -221,6 +230,19 @@ static int ocfs2_sync_fs(struct super_block *sb, int wait)
        return 0;
 }
 
+static int ocfs2_need_system_inode(struct ocfs2_super *osb, int ino)
+{
+       if (!OCFS2_HAS_RO_COMPAT_FEATURE(osb->sb, OCFS2_FEATURE_RO_COMPAT_USRQUOTA)
+           && (ino == USER_QUOTA_SYSTEM_INODE
+               || ino == LOCAL_USER_QUOTA_SYSTEM_INODE))
+               return 0;
+       if (!OCFS2_HAS_RO_COMPAT_FEATURE(osb->sb, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)
+           && (ino == GROUP_QUOTA_SYSTEM_INODE
+               || ino == LOCAL_GROUP_QUOTA_SYSTEM_INODE))
+               return 0;
+       return 1;
+}
+
 static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb)
 {
        struct inode *new = NULL;
@@ -247,6 +269,8 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb)
 
        for (i = OCFS2_FIRST_ONLINE_SYSTEM_INODE;
             i <= OCFS2_LAST_GLOBAL_SYSTEM_INODE; i++) {
+               if (!ocfs2_need_system_inode(osb, i))
+                       continue;
                new = ocfs2_get_system_file_inode(osb, i, osb->slot_num);
                if (!new) {
                        ocfs2_release_system_inodes(osb);
@@ -277,6 +301,8 @@ static int ocfs2_init_local_system_inodes(struct ocfs2_super *osb)
        for (i = OCFS2_LAST_GLOBAL_SYSTEM_INODE + 1;
             i < NUM_SYSTEM_INODES;
             i++) {
+               if (!ocfs2_need_system_inode(osb, i))
+                       continue;
                new = ocfs2_get_system_file_inode(osb, i, osb->slot_num);
                if (!new) {
                        ocfs2_release_system_inodes(osb);
@@ -466,6 +492,8 @@ unlock_osb:
        if (!ret) {
                /* Only save off the new mount options in case of a successful
                 * remount. */
+               if (!(osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR))
+                       parsed_options.mount_opt &= ~OCFS2_MOUNT_POSIX_ACL;
                osb->s_mount_opt = parsed_options.mount_opt;
                osb->s_atime_quantum = parsed_options.atime_quantum;
                osb->preferred_slot = parsed_options.slot;
@@ -651,6 +679,10 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        }
        brelse(bh);
        bh = NULL;
+
+       if (!(osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR))
+               parsed_options.mount_opt &= ~OCFS2_MOUNT_POSIX_ACL;
+
        osb->s_mount_opt = parsed_options.mount_opt;
        osb->s_atime_quantum = parsed_options.atime_quantum;
        osb->preferred_slot = parsed_options.slot;
@@ -664,6 +696,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 
        sb->s_magic = OCFS2_SUPER_MAGIC;
 
+       sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
+               ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
+
        /* Hard readonly mode only if: bdev_read_only, MS_RDONLY,
         * heartbeat=none */
        if (bdev_read_only(sb->s_bdev)) {
@@ -945,6 +980,19 @@ static int ocfs2_parse_options(struct super_block *sb,
                case Opt_inode64:
                        mopt->mount_opt |= OCFS2_MOUNT_INODE64;
                        break;
+#ifdef CONFIG_OCFS2_FS_POSIX_ACL
+               case Opt_acl:
+                       mopt->mount_opt |= OCFS2_MOUNT_POSIX_ACL;
+                       break;
+               case Opt_noacl:
+                       mopt->mount_opt &= ~OCFS2_MOUNT_POSIX_ACL;
+                       break;
+#else
+               case Opt_acl:
+               case Opt_noacl:
+                       printk(KERN_INFO "ocfs2 (no)acl options not supported\n");
+                       break;
+#endif
                default:
                        mlog(ML_ERROR,
                             "Unrecognized mount option \"%s\" "
@@ -1017,6 +1065,13 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
        if (opts & OCFS2_MOUNT_INODE64)
                seq_printf(s, ",inode64");
 
+#ifdef CONFIG_OCFS2_FS_POSIX_ACL
+       if (opts & OCFS2_MOUNT_POSIX_ACL)
+               seq_printf(s, ",acl");
+       else
+               seq_printf(s, ",noacl");
+#endif
+
        return 0;
 }
 
@@ -1054,6 +1109,7 @@ static int __init ocfs2_init(void)
 
        ocfs2_set_locking_protocol();
 
+       status = register_quota_format(&ocfs2_quota_format);
 leave:
        if (status < 0) {
                ocfs2_free_mem_caches();
@@ -1077,6 +1133,8 @@ static void __exit ocfs2_exit(void)
                destroy_workqueue(ocfs2_wq);
        }
 
+       unregister_quota_format(&ocfs2_quota_format);
+
        debugfs_remove(ocfs2_debugfs_root);
 
        ocfs2_free_mem_caches();
@@ -1192,8 +1250,27 @@ static int ocfs2_initialize_mem_caches(void)
                                       (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
                                       ocfs2_inode_init_once);
-       if (!ocfs2_inode_cachep)
+       ocfs2_dquot_cachep = kmem_cache_create("ocfs2_dquot_cache",
+                                       sizeof(struct ocfs2_dquot),
+                                       0,
+                                       (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
+                                               SLAB_MEM_SPREAD),
+                                       NULL);
+       ocfs2_qf_chunk_cachep = kmem_cache_create("ocfs2_qf_chunk_cache",
+                                       sizeof(struct ocfs2_quota_chunk),
+                                       0,
+                                       (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD),
+                                       NULL);
+       if (!ocfs2_inode_cachep || !ocfs2_dquot_cachep ||
+           !ocfs2_qf_chunk_cachep) {
+               if (ocfs2_inode_cachep)
+                       kmem_cache_destroy(ocfs2_inode_cachep);
+               if (ocfs2_dquot_cachep)
+                       kmem_cache_destroy(ocfs2_dquot_cachep);
+               if (ocfs2_qf_chunk_cachep)
+                       kmem_cache_destroy(ocfs2_qf_chunk_cachep);
                return -ENOMEM;
+       }
 
        return 0;
 }
@@ -1202,8 +1279,15 @@ static void ocfs2_free_mem_caches(void)
 {
        if (ocfs2_inode_cachep)
                kmem_cache_destroy(ocfs2_inode_cachep);
-
        ocfs2_inode_cachep = NULL;
+
+       if (ocfs2_dquot_cachep)
+               kmem_cache_destroy(ocfs2_dquot_cachep);
+       ocfs2_dquot_cachep = NULL;
+
+       if (ocfs2_qf_chunk_cachep)
+               kmem_cache_destroy(ocfs2_qf_chunk_cachep);
+       ocfs2_qf_chunk_cachep = NULL;
 }
 
 static int ocfs2_get_sector(struct super_block *sb,
This page took 0.028083 seconds and 5 git commands to generate.