*/
 struct lsm_blob_sizes {
        int     lbs_cred;
+       int     lbs_file;
 };
 
 /*
 
                                 AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
                                 AA_EXEC_MMAP | AA_MAY_LINK)
 
-#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
+static inline struct aa_file_ctx *file_ctx(struct file *file)
+{
+       return file->f_security + apparmor_blob_sizes.lbs_file;
+}
 
 /* struct aa_file_ctx - the AppArmor context the file was opened in
  * @lock: lock to update the ctx
 
 
 static int apparmor_file_alloc_security(struct file *file)
 {
-       int error = 0;
-
-       /* freed by apparmor_file_free_security */
+       struct aa_file_ctx *ctx = file_ctx(file);
        struct aa_label *label = begin_current_label_crit_section();
-       file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
-       if (!file_ctx(file))
-               error = -ENOMEM;
-       end_current_label_crit_section(label);
 
-       return error;
+       spin_lock_init(&ctx->lock);
+       rcu_assign_pointer(ctx->label, aa_get_label(label));
+       end_current_label_crit_section(label);
+       return 0;
 }
 
 static void apparmor_file_free_security(struct file *file)
 {
-       aa_free_file_ctx(file_ctx(file));
+       struct aa_file_ctx *ctx = file_ctx(file);
+
+       if (ctx)
+               aa_put_label(rcu_access_pointer(ctx->label));
 }
 
 static int common_file_perm(const char *op, struct file *file, u32 mask)
  */
 struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = {
        .lbs_cred = sizeof(struct aa_task_ctx *),
+       .lbs_file = sizeof(struct aa_file_ctx),
 };
 
 static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
 
 struct security_hook_heads security_hook_heads __lsm_ro_after_init;
 static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
 
+static struct kmem_cache *lsm_file_cache;
+
 char *lsm_names;
 static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init;
 
                return;
 
        lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+       lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
 }
 
 /* Prepare LSM for initialization. */
                prepare_lsm(*lsm);
 
        init_debug("cred blob size     = %d\n", blob_sizes.lbs_cred);
+       init_debug("file blob size     = %d\n", blob_sizes.lbs_file);
+
+       /*
+        * Create any kmem_caches needed for blobs
+        */
+       if (blob_sizes.lbs_file)
+               lsm_file_cache = kmem_cache_create("lsm_file_cache",
+                                                  blob_sizes.lbs_file, 0,
+                                                  SLAB_PANIC, NULL);
 
        for (lsm = ordered_lsms; *lsm; lsm++)
                initialize_lsm(*lsm);
                panic("%s: Early cred alloc failed.\n", __func__);
 }
 
+/**
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
+ *
+ * Allocate the file blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_file_alloc(struct file *file)
+{
+       if (!lsm_file_cache) {
+               file->f_security = NULL;
+               return 0;
+       }
+
+       file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
+       if (file->f_security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
 /*
  * Hook list operation macros.
  *
 
 int security_file_alloc(struct file *file)
 {
-       return call_int_hook(file_alloc_security, 0, file);
+       int rc = lsm_file_alloc(file);
+
+       if (rc)
+               return rc;
+       rc = call_int_hook(file_alloc_security, 0, file);
+       if (unlikely(rc))
+               security_file_free(file);
+       return rc;
 }
 
 void security_file_free(struct file *file)
 {
+       void *blob;
+
        call_void_hook(file_free_security, file);
+
+       blob = file->f_security;
+       if (blob) {
+               file->f_security = NULL;
+               kmem_cache_free(lsm_file_cache, blob);
+       }
 }
 
 int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return rc;
 
        rc = call_int_hook(cred_alloc_blank, 0, cred, gfp);
-       if (rc)
+       if (unlikely(rc))
                security_cred_free(cred);
        return rc;
 }
                return rc;
 
        rc = call_int_hook(cred_prepare, 0, new, old, gfp);
-       if (rc)
+       if (unlikely(rc))
                security_cred_free(new);
        return rc;
 }
 
 __setup("checkreqprot=", checkreqprot_setup);
 
 static struct kmem_cache *sel_inode_cache;
-static struct kmem_cache *file_security_cache;
 
 /**
  * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
 
 static int file_alloc_security(struct file *file)
 {
-       struct file_security_struct *fsec;
+       struct file_security_struct *fsec = selinux_file(file);
        u32 sid = current_sid();
 
-       fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
-       if (!fsec)
-               return -ENOMEM;
-
        fsec->sid = sid;
        fsec->fown_sid = sid;
-       file->f_security = fsec;
 
        return 0;
 }
 
-static void file_free_security(struct file *file)
-{
-       struct file_security_struct *fsec = selinux_file(file);
-       file->f_security = NULL;
-       kmem_cache_free(file_security_cache, fsec);
-}
-
 static int superblock_alloc_security(struct super_block *sb)
 {
        struct superblock_security_struct *sbsec;
        return file_alloc_security(file);
 }
 
-static void selinux_file_free_security(struct file *file)
-{
-       file_free_security(file);
-}
-
 /*
  * Check whether a task has the ioctl permission and cmd
  * operation to an inode.
 
 struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
        .lbs_cred = sizeof(struct task_security_struct),
+       .lbs_file = sizeof(struct file_security_struct),
 };
 
 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 
        LSM_HOOK_INIT(file_permission, selinux_file_permission),
        LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
-       LSM_HOOK_INIT(file_free_security, selinux_file_free_security),
        LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
        LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
        LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
        sel_inode_cache = kmem_cache_create("selinux_inode_security",
                                            sizeof(struct inode_security_struct),
                                            0, SLAB_PANIC, NULL);
-       file_security_cache = kmem_cache_create("selinux_file_security",
-                                           sizeof(struct file_security_struct),
-                                           0, SLAB_PANIC, NULL);
        avc_init();
 
        avtab_cache_init();
 
 
 static inline struct file_security_struct *selinux_file(const struct file *file)
 {
-       return file->f_security;
+       return file->f_security + selinux_blob_sizes.lbs_file;
 }
 
 #endif /* _SELINUX_OBJSEC_H_ */
 
 
 static inline struct smack_known **smack_file(const struct file *file)
 {
-       return (struct smack_known **)&file->f_security;
+       return (struct smack_known **)(file->f_security +
+                                      smack_blob_sizes.lbs_file);
 }
 
 /*
 
        return 0;
 }
 
-/**
- * smack_file_free_security - clear a file security blob
- * @file: the object
- *
- * The security blob for a file is a pointer to the master
- * label list, so no memory is freed.
- */
-static void smack_file_free_security(struct file *file)
-{
-       file->f_security = NULL;
-}
-
 /**
  * smack_file_ioctl - Smack check on ioctls
  * @file: the object
 
 struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = {
        .lbs_cred = sizeof(struct task_smack),
+       .lbs_file = sizeof(struct smack_known *),
 };
 
 static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid),
 
        LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security),
-       LSM_HOOK_INIT(file_free_security, smack_file_free_security),
        LSM_HOOK_INIT(file_ioctl, smack_file_ioctl),
        LSM_HOOK_INIT(file_lock, smack_file_lock),
        LSM_HOOK_INIT(file_fcntl, smack_file_fcntl),