#include <linux/xattr.h>
 #include <linux/iversion.h>
 #include <linux/posix_acl.h>
+#include <linux/security.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
 
 static void fuse_advise_use_readdirplus(struct inode *dir)
 {
        return ERR_PTR(err);
 }
 
+static int get_security_context(struct dentry *entry, umode_t mode,
+                               void **security_ctx, u32 *security_ctxlen)
+{
+       struct fuse_secctx *fctx;
+       struct fuse_secctx_header *header;
+       void *ctx = NULL, *ptr;
+       u32 ctxlen, total_len = sizeof(*header);
+       int err, nr_ctx = 0;
+       const char *name;
+       size_t namelen;
+
+       err = security_dentry_init_security(entry, mode, &entry->d_name,
+                                           &name, &ctx, &ctxlen);
+       if (err) {
+               if (err != -EOPNOTSUPP)
+                       goto out_err;
+               /* No LSM is supporting this security hook. Ignore error */
+               ctxlen = 0;
+               ctx = NULL;
+       }
+
+       if (ctxlen) {
+               nr_ctx = 1;
+               namelen = strlen(name) + 1;
+               err = -EIO;
+               if (WARN_ON(namelen > XATTR_NAME_MAX + 1 || ctxlen > S32_MAX))
+                       goto out_err;
+               total_len += FUSE_REC_ALIGN(sizeof(*fctx) + namelen + ctxlen);
+       }
+
+       err = -ENOMEM;
+       header = ptr = kzalloc(total_len, GFP_KERNEL);
+       if (!ptr)
+               goto out_err;
+
+       header->nr_secctx = nr_ctx;
+       header->size = total_len;
+       ptr += sizeof(*header);
+       if (nr_ctx) {
+               fctx = ptr;
+               fctx->size = ctxlen;
+               ptr += sizeof(*fctx);
+
+               strcpy(ptr, name);
+               ptr += namelen;
+
+               memcpy(ptr, ctx, ctxlen);
+       }
+       *security_ctxlen = total_len;
+       *security_ctx = header;
+       err = 0;
+out_err:
+       kfree(ctx);
+       return err;
+}
+
 /*
  * Atomic create+open operation
  *
        struct fuse_entry_out outentry;
        struct fuse_inode *fi;
        struct fuse_file *ff;
+       void *security_ctx = NULL;
+       u32 security_ctxlen;
 
        /* Userspace expects S_IFREG in create mode */
        BUG_ON((mode & S_IFMT) != S_IFREG);
        args.out_args[0].value = &outentry;
        args.out_args[1].size = sizeof(outopen);
        args.out_args[1].value = &outopen;
+
+       if (fm->fc->init_security) {
+               err = get_security_context(entry, mode, &security_ctx,
+                                          &security_ctxlen);
+               if (err)
+                       goto out_put_forget_req;
+
+               args.in_numargs = 3;
+               args.in_args[2].size = security_ctxlen;
+               args.in_args[2].value = security_ctx;
+       }
+
        err = fuse_simple_request(fm, &args);
+       kfree(security_ctx);
        if (err)
                goto out_free_ff;
 
        struct dentry *d;
        int err;
        struct fuse_forget_link *forget;
+       void *security_ctx = NULL;
+       u32 security_ctxlen;
 
        if (fuse_is_bad(dir))
                return -EIO;
        args->out_numargs = 1;
        args->out_args[0].size = sizeof(outarg);
        args->out_args[0].value = &outarg;
+
+       if (fm->fc->init_security && args->opcode != FUSE_LINK) {
+               err = get_security_context(entry, mode, &security_ctx,
+                                          &security_ctxlen);
+               if (err)
+                       goto out_put_forget_req;
+
+               BUG_ON(args->in_numargs != 2);
+
+               args->in_numargs = 3;
+               args->in_args[2].size = security_ctxlen;
+               args->in_args[2].value = security_ctx;
+       }
+
        err = fuse_simple_request(fm, args);
+       kfree(security_ctx);
        if (err)
                goto out_put_forget_req;
 
 
  *  7.36
  *  - extend fuse_init_in with reserved fields, add FUSE_INIT_EXT init flag
  *  - add flags2 to fuse_init_in and fuse_init_out
+ *  - add FUSE_SECURITY_CTX init flag
+ *  - add security context to create, mkdir, symlink, and mknod requests
  */
 
 #ifndef _LINUX_FUSE_H
  * FUSE_SETXATTR_EXT:  Server supports extended struct fuse_setxattr_in
  * FUSE_INIT_EXT: extended fuse_init_in request
  * FUSE_INIT_RESERVED: reserved, do not use
+ * FUSE_SECURITY_CTX:  add security context to create, mkdir, symlink, and
+ *                     mknod
  */
 #define FUSE_ASYNC_READ                (1 << 0)
 #define FUSE_POSIX_LOCKS       (1 << 1)
 #define FUSE_INIT_EXT          (1 << 30)
 #define FUSE_INIT_RESERVED     (1 << 31)
 /* bits 32..63 get shifted down 32 bits into the flags2 field */
+#define FUSE_SECURITY_CTX      (1ULL << 32)
 
 /**
  * CUSE INIT request/reply flags
        char name[];
 };
 
-#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
-#define FUSE_DIRENT_ALIGN(x) \
+/* Align variable length records to 64bit boundary */
+#define FUSE_REC_ALIGN(x) \
        (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
+
+#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
+#define FUSE_DIRENT_ALIGN(x) FUSE_REC_ALIGN(x)
 #define FUSE_DIRENT_SIZE(d) \
        FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
 
        uint64_t        padding;
 };
 
+/*
+ * For each security context, send fuse_secctx with size of security context
+ * fuse_secctx will be followed by security context name and this in turn
+ * will be followed by actual context label.
+ * fuse_secctx, name, context
+ */
+struct fuse_secctx {
+       uint32_t        size;
+       uint32_t        padding;
+};
+
+/*
+ * Contains the information about how many fuse_secctx structures are being
+ * sent and what's the total size of all security contexts (including
+ * size of fuse_secctx_header).
+ *
+ */
+struct fuse_secctx_header {
+       uint32_t        size;
+       uint32_t        nr_secctx;
+};
+
 #endif /* _LINUX_FUSE_H */