[kernel/user/steved/f19-lnfs-v3.8-rc7] Added Label NFS support.

Steve Dickson steved at fedoraproject.org
Mon Feb 18 15:31:45 UTC 2013


commit 289dd09ae0d56f9f5cf7b951acd8ed9b1c224e4a
Author: Steve Dickson <steved at redhat.com>
Date:   Mon Feb 18 08:20:15 2013 -0500

    Added Label NFS support.
    
    Signed-off-by: Steve Dickson <steved at redhat.com>

 config-x86-generic            |    4 +
 kernel.spec                   |    7 +-
 lnfs-3.8.0-0.rc7.git3.1.patch | 3852 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 3862 insertions(+), 1 deletions(-)
---
diff --git a/config-x86-generic b/config-x86-generic
index 67b5be1..29a9097 100644
--- a/config-x86-generic
+++ b/config-x86-generic
@@ -434,3 +434,7 @@ CONFIG_MODULE_SIG_SHA256=y
 # CONFIG_MODULE_SIG_FORCE is not set
 CONFIG_MODULE_SIG_BLACKLIST=y
 CONFIG_MODULE_SIG_UEFI=y
+
+CONFIG_NFS_V4_SECURITY_LABEL=y
+CONFIG_NFSD_V4_SECURITY_LABEL=y
+
diff --git a/kernel.spec b/kernel.spec
index 259ae73..ce589ca 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -31,7 +31,7 @@ Summary: The Linux kernel
 #
 # (Uncomment the '#' and both spaces below to set the buildid.)
 #
-# % define buildid .local
+%define buildid .lnfs
 ###################################################################
 
 # The buildid can also be specified on the rpmbuild command line
@@ -694,6 +694,7 @@ Patch2901: v4l-dvb-experimental.patch
 # fs fixes
 
 # NFSv4
+Patch4000: lnfs-3.8.0-0.rc7.git3.1.patch
 
 # patches headed upstream
 Patch10000: fs-proc-devtree-remove_proc_entry.patch
@@ -1336,6 +1337,7 @@ ApplyPatch arm-imx-fixdrm.patch
 # eCryptfs
 
 # NFSv4
+ApplyPatch lnfs-3.8.0-0.rc7.git3.1.patch
 
 # USB
 
@@ -2322,6 +2324,9 @@ fi
 #                 ||----w |
 #                 ||     ||
 %changelog
+* Sat Feb 16 2013 Steve Dickson <steved at redhat.com> 3.8.0-0.rc7.git3.1-lnfs
+* Added Label NFS support.
+
 * Thu Feb 14 2013 Josh Boyer <jwboyer at redhat.com> - 3.8.0-0.rc7.git3.1
 - Linux v3.8-rc7-73-g323a72d
 
diff --git a/lnfs-3.8.0-0.rc7.git3.1.patch b/lnfs-3.8.0-0.rc7.git3.1.patch
new file mode 100644
index 0000000..dd9832f
--- /dev/null
+++ b/lnfs-3.8.0-0.rc7.git3.1.patch
@@ -0,0 +1,3852 @@
+diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
+index 13ca196..3861a1f 100644
+--- a/fs/nfs/Kconfig
++++ b/fs/nfs/Kconfig
+@@ -131,6 +131,24 @@ config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
+ 	  If the NFS client is unchanged from the upstream kernel, this
+ 	  option should be set to the default "kernel.org".
+ 
++config NFS_V4_SECURITY_LABEL
++	bool "Provide Security Label support for NFSv4 client"
++	depends on NFS_V4 && SECURITY
++	help
++
++	Say Y here if you want enable fine-grained security label attribute
++	support for NFS version 4.  Security labels allow security modules like
++	SELinux and Smack to label files to facilitate enforcement of their policies.
++	Without this an NFSv4 mount will have the same label on each file.
++
++	If you do not wish to enable fine-grained security labels SELinux or
++	Smack policies on NFSv4 files, say N.
++
++	WARNING: there is still a chance of backwards-incompatible protocol changes.  
++	For now we recommend "Y" only for developers and testers."
++
++	If unsure, say N.
++
+ config ROOT_NFS
+ 	bool "Root file system on NFS"
+ 	depends on NFS_FS=y && IP_PNP
+diff --git a/fs/nfs/client.c b/fs/nfs/client.c
+index 9f3c664..9798309 100644
+--- a/fs/nfs/client.c
++++ b/fs/nfs/client.c
+@@ -1075,7 +1075,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
+ 	}
+ 
+ 	if (!(fattr->valid & NFS_ATTR_FATTR)) {
+-		error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr);
++		error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr, NULL);
+ 		if (error < 0) {
+ 			dprintk("nfs_create_server: getattr error = %d\n", -error);
+ 			goto error;
+diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
+index 1b2d7eb..d81b7e3 100644
+--- a/fs/nfs/dir.c
++++ b/fs/nfs/dir.c
+@@ -447,7 +447,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
+ 	dentry = d_lookup(parent, &filename);
+ 	if (dentry != NULL) {
+ 		if (nfs_same_file(dentry, entry)) {
+-			nfs_refresh_inode(dentry->d_inode, entry->fattr);
++			nfs_refresh_inode(dentry->d_inode, entry->fattr, entry->label);
+ 			goto out;
+ 		} else {
+ 			if (d_invalidate(dentry) != 0)
+@@ -460,7 +460,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
+ 	if (dentry == NULL)
+ 		return;
+ 
+-	inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr);
++	inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr, entry->label);
+ 	if (IS_ERR(inode))
+ 		goto out;
+ 
+@@ -585,10 +585,16 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
+ 	if (entry.fh == NULL || entry.fattr == NULL)
+ 		goto out;
+ 
++	entry.label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT);
++	if (IS_ERR(entry.label)) {
++		status = PTR_ERR(entry.label);
++		goto out;
++	}
++
+ 	array = nfs_readdir_get_array(page);
+ 	if (IS_ERR(array)) {
+ 		status = PTR_ERR(array);
+-		goto out;
++		goto out_label_free;
+ 	}
+ 	memset(array, 0, sizeof(struct nfs_cache_array));
+ 	array->eof_index = -1;
+@@ -614,6 +620,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
+ 	nfs_readdir_free_large_page(pages_ptr, pages, array_size);
+ out_release_array:
+ 	nfs_readdir_release_array(page);
++out_label_free:
++	nfs4_label_free(entry.label);
+ out:
+ 	nfs_free_fattr(entry.fattr);
+ 	nfs_free_fhandle(entry.fh);
+@@ -1040,6 +1048,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
+ 	struct dentry *parent;
+ 	struct nfs_fh *fhandle = NULL;
+ 	struct nfs_fattr *fattr = NULL;
++	struct nfs4_label *label = NULL;
+ 	int error;
+ 
+ 	if (flags & LOOKUP_RCU)
+@@ -1082,16 +1091,22 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
+ 	if (fhandle == NULL || fattr == NULL)
+ 		goto out_error;
+ 
+-	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
++	label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT);
++	if (IS_ERR(label))
++		goto out_error;
++
++	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
+ 	if (error)
+ 		goto out_bad;
+ 	if (nfs_compare_fh(NFS_FH(inode), fhandle))
+ 		goto out_bad;
+-	if ((error = nfs_refresh_inode(inode, fattr)) != 0)
++	if ((error = nfs_refresh_inode(inode, fattr, label)) != 0)
+ 		goto out_bad;
+ 
+ 	nfs_free_fattr(fattr);
+ 	nfs_free_fhandle(fhandle);
++	nfs4_label_free(label);
++
+ out_set_verifier:
+ 	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+  out_valid:
+@@ -1108,6 +1123,7 @@ out_zap_parent:
+  out_bad:
+ 	nfs_free_fattr(fattr);
+ 	nfs_free_fhandle(fhandle);
++	nfs4_label_free(label);
+ 	nfs_mark_for_revalidate(dir);
+ 	if (inode && S_ISDIR(inode->i_mode)) {
+ 		/* Purge readdir caches. */
+@@ -1128,6 +1144,7 @@ out_zap_parent:
+ out_error:
+ 	nfs_free_fattr(fattr);
+ 	nfs_free_fhandle(fhandle);
++	nfs4_label_free(label);
+ 	dput(parent);
+ 	dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n",
+ 			__func__, dentry->d_parent->d_name.name,
+@@ -1216,6 +1233,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
+ 	struct inode *inode = NULL;
+ 	struct nfs_fh *fhandle = NULL;
+ 	struct nfs_fattr *fattr = NULL;
++	struct nfs4_label *label = NULL;
+ 	int error;
+ 
+ 	dfprintk(VFS, "NFS: lookup(%s/%s)\n",
+@@ -1242,17 +1260,21 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
+ 	if (fhandle == NULL || fattr == NULL)
+ 		goto out;
+ 
++	label = nfs4_label_alloc(NFS_SERVER(dir), GFP_NOWAIT);
++	if (IS_ERR(label))
++		goto out;
++
+ 	parent = dentry->d_parent;
+ 	/* Protect against concurrent sillydeletes */
+ 	nfs_block_sillyrename(parent);
+-	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
++	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
+ 	if (error == -ENOENT)
+ 		goto no_entry;
+ 	if (error < 0) {
+ 		res = ERR_PTR(error);
+ 		goto out_unblock_sillyrename;
+ 	}
+-	inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
++	inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label);
+ 	res = ERR_CAST(inode);
+ 	if (IS_ERR(res))
+ 		goto out_unblock_sillyrename;
+@@ -1270,6 +1292,7 @@ no_entry:
+ 	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+ out_unblock_sillyrename:
+ 	nfs_unblock_sillyrename(parent);
++	nfs4_label_free(label);
+ out:
+ 	nfs_free_fattr(fattr);
+ 	nfs_free_fhandle(fhandle);
+@@ -1486,7 +1509,8 @@ no_open:
+  * Code common to create, mkdir, and mknod.
+  */
+ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
+-				struct nfs_fattr *fattr)
++				struct nfs_fattr *fattr,
++				struct nfs4_label *label)
+ {
+ 	struct dentry *parent = dget_parent(dentry);
+ 	struct inode *dir = parent->d_inode;
+@@ -1499,18 +1523,18 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
+ 	if (dentry->d_inode)
+ 		goto out;
+ 	if (fhandle->size == 0) {
+-		error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
++		error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, NULL);
+ 		if (error)
+ 			goto out_error;
+ 	}
+ 	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+ 	if (!(fattr->valid & NFS_ATTR_FATTR)) {
+ 		struct nfs_server *server = NFS_SB(dentry->d_sb);
+-		error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr);
++		error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr, NULL);
+ 		if (error < 0)
+ 			goto out_error;
+ 	}
+-	inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
++	inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label);
+ 	error = PTR_ERR(inode);
+ 	if (IS_ERR(inode))
+ 		goto out_error;
+diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
+index 033803c..14bd667 100644
+--- a/fs/nfs/getroot.c
++++ b/fs/nfs/getroot.c
+@@ -95,7 +95,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
+ 		goto out;
+ 	}
+ 
+-	inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
++	inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL);
+ 	if (IS_ERR(inode)) {
+ 		dprintk("nfs_get_root: get root inode failed\n");
+ 		ret = ERR_CAST(inode);
+diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
+index ebeb94c..1bed944 100644
+--- a/fs/nfs/inode.c
++++ b/fs/nfs/inode.c
+@@ -61,7 +61,7 @@
+ static bool enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED;
+ 
+ static void nfs_invalidate_inode(struct inode *);
+-static int nfs_update_inode(struct inode *, struct nfs_fattr *);
++static int nfs_update_inode(struct inode *, struct nfs_fattr *, struct nfs4_label *);
+ 
+ static struct kmem_cache * nfs_inode_cachep;
+ 
+@@ -162,11 +162,19 @@ static void nfs_zap_caches_locked(struct inode *inode)
+ 
+ 	memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf));
+ 	if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) {
+-		nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
+ 		nfs_fscache_invalidate(inode);
+-	} else {
+-		nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
+-	}
++		nfsi->cache_validity |= NFS_INO_INVALID_ATTR
++					| NFS_INO_INVALID_LABEL
++					| NFS_INO_INVALID_DATA
++					| NFS_INO_INVALID_ACCESS
++					| NFS_INO_INVALID_ACL
++					| NFS_INO_REVAL_PAGECACHE;
++	} else
++		nfsi->cache_validity |= NFS_INO_INVALID_ATTR
++					| NFS_INO_INVALID_LABEL
++					| NFS_INO_INVALID_ACCESS
++					| NFS_INO_INVALID_ACL
++					| NFS_INO_REVAL_PAGECACHE;
+ }
+ 
+ void nfs_zap_caches(struct inode *inode)
+@@ -255,12 +263,60 @@ nfs_init_locked(struct inode *inode, void *opaque)
+ 	return 0;
+ }
+ 
++#ifdef CONFIG_NFS_V4_SECURITY_LABEL
++void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
++					struct nfs4_label *label)
++{
++	int error;
++
++	if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL) &&
++			label && inode->i_security) {
++		error = security_inode_notifysecctx(inode, label->label,
++				label->len);
++		if (error)
++			printk(KERN_ERR "%s() %s %d "
++					"security_inode_notifysecctx() %d\n",
++					__func__,
++					(char *)label->label,
++					label->len, error);
++	}
++}
++
++struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
++{
++	struct nfs4_label *label = NULL;
++
++	if (!(server->caps & NFS_CAP_SECURITY_LABEL))
++		return label;
++
++	label = kzalloc(sizeof(struct nfs4_label), flags);
++	if (label == NULL)
++		return ERR_PTR(-ENOMEM);
++
++	label->label = kzalloc(NFS4_MAXLABELLEN, flags);
++	if (label->label == NULL) {
++		kfree(label);
++		return ERR_PTR(-ENOMEM);
++	}
++	label->len = NFS4_MAXLABELLEN;
++
++	return label;
++}
++EXPORT_SYMBOL_GPL(nfs4_label_alloc);
++#else
++void inline nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
++					struct nfs4_label *label)
++{
++}
++#endif
++EXPORT_SYMBOL_GPL(nfs_setsecurity);
++
+ /*
+  * This is our front-end to iget that looks up inodes by file handle
+  * instead of inode number.
+  */
+ struct inode *
+-nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
++nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+ 	struct nfs_find_desc desc = {
+ 		.fh	= fh,
+@@ -382,6 +438,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
+ 			 */
+ 			inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
+ 		}
++
++		nfs_setsecurity(inode, fattr, label);
++
+ 		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
+ 		nfsi->attrtimeo_timestamp = now;
+ 		nfsi->access_cache = RB_ROOT;
+@@ -390,7 +449,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
+ 
+ 		unlock_new_inode(inode);
+ 	} else
+-		nfs_refresh_inode(inode, fattr);
++		nfs_refresh_inode(inode, fattr, label);
+ 	dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
+ 		inode->i_sb->s_id,
+ 		(long long)NFS_FILEID(inode),
+@@ -447,7 +506,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
+ 		NFS_PROTO(inode)->return_delegation(inode);
+ 	error = NFS_PROTO(inode)->setattr(dentry, fattr, attr);
+ 	if (error == 0)
+-		nfs_refresh_inode(inode, fattr);
++		nfs_refresh_inode(inode, fattr, NULL);
+ 	nfs_free_fattr(fattr);
+ out:
+ 	return error;
+@@ -744,6 +803,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c
+ 	spin_unlock(&inode->i_lock);
+ 	return ctx;
+ }
++EXPORT_SYMBOL_GPL(nfs_find_open_context);
+ 
+ static void nfs_file_clear_open_context(struct file *filp)
+ {
+@@ -789,6 +849,7 @@ int
+ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
+ {
+ 	int		 status = -ESTALE;
++	struct nfs4_label *label = NULL;
+ 	struct nfs_fattr *fattr = NULL;
+ 	struct nfs_inode *nfsi = NFS_I(inode);
+ 
+@@ -806,7 +867,14 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
+ 		goto out;
+ 
+ 	nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
+-	status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr);
++
++	label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
++	if (IS_ERR(label)) {
++		status = PTR_ERR(label);
++		goto out;
++	}
++
++	status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, label);
+ 	if (status != 0) {
+ 		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
+ 			 inode->i_sb->s_id,
+@@ -816,15 +884,15 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
+ 			if (!S_ISDIR(inode->i_mode))
+ 				set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
+ 		}
+-		goto out;
++		goto err_out;
+ 	}
+ 
+-	status = nfs_refresh_inode(inode, fattr);
++	status = nfs_refresh_inode(inode, fattr, label);
+ 	if (status) {
+ 		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
+ 			 inode->i_sb->s_id,
+ 			 (long long)NFS_FILEID(inode), status);
+-		goto out;
++		goto err_out;
+ 	}
+ 
+ 	if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
+@@ -834,7 +902,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
+ 		inode->i_sb->s_id,
+ 		(long long)NFS_FILEID(inode));
+ 
+- out:
++err_out:
++	nfs4_label_free(label);
++out:
+ 	nfs_free_fattr(fattr);
+ 	return status;
+ }
+@@ -862,7 +932,8 @@ static int nfs_attribute_cache_expired(struct inode *inode)
+  */
+ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
+ {
+-	if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR)
++	if (!(NFS_I(inode)->cache_validity &
++			(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL))
+ 			&& !nfs_attribute_cache_expired(inode))
+ 		return NFS_STALE(inode) ? -ESTALE : 0;
+ 	return __nfs_revalidate_inode(server, inode);
+@@ -1176,10 +1247,10 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
+ 		((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
+ }
+ 
+-static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
++static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+ 	if (nfs_inode_attrs_need_update(inode, fattr))
+-		return nfs_update_inode(inode, fattr);
++		return nfs_update_inode(inode, fattr, label);
+ 	return nfs_check_inode_attributes(inode, fattr);
+ }
+ 
+@@ -1193,21 +1264,24 @@ static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr
+  * safe to do a full update of the inode attributes, or whether just to
+  * call nfs_check_inode_attributes.
+  */
+-int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
++int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+ 	int status;
+ 
+ 	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+ 		return 0;
+ 	spin_lock(&inode->i_lock);
+-	status = nfs_refresh_inode_locked(inode, fattr);
++	status = nfs_refresh_inode_locked(inode, fattr, label);
+ 	spin_unlock(&inode->i_lock);
+ 
++	if (label && !status)
++		nfs_setsecurity(inode, fattr, label);
++
+ 	return status;
+ }
+ EXPORT_SYMBOL_GPL(nfs_refresh_inode);
+ 
+-static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
++static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+ 	struct nfs_inode *nfsi = NFS_I(inode);
+ 
+@@ -1218,7 +1292,7 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr
+ 	}
+ 	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+ 		return 0;
+-	return nfs_refresh_inode_locked(inode, fattr);
++	return nfs_refresh_inode_locked(inode, fattr, label);
+ }
+ 
+ /**
+@@ -1235,13 +1309,17 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr
+  * are expected to change one or more attributes, to avoid
+  * unnecessary NFS requests and trips through nfs_update_inode().
+  */
+-int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
++int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+ 	int status;
+ 
+ 	spin_lock(&inode->i_lock);
+-	status = nfs_post_op_update_inode_locked(inode, fattr);
++	status = nfs_post_op_update_inode_locked(inode, fattr, label);
+ 	spin_unlock(&inode->i_lock);
++	if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) {
++		if (label && !status)
++			nfs_setsecurity(inode, fattr, label);
++	}
+ 	return status;
+ }
+ EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);
+@@ -1292,7 +1370,7 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
+ 		fattr->valid |= NFS_ATTR_FATTR_PRESIZE;
+ 	}
+ out_noforce:
+-	status = nfs_post_op_update_inode_locked(inode, fattr);
++	status = nfs_post_op_update_inode_locked(inode, fattr, NULL);
+ 	spin_unlock(&inode->i_lock);
+ 	return status;
+ }
+@@ -1310,7 +1388,7 @@ EXPORT_SYMBOL_GPL(nfs_post_op_update_inode_force_wcc);
+  *
+  * A very similar scenario holds for the dir cache.
+  */
+-static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
++static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+ 	struct nfs_server *server;
+ 	struct nfs_inode *nfsi = NFS_I(inode);
+@@ -1482,7 +1560,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
+ 		inode->i_blocks = fattr->du.nfs2.blocks;
+ 
+ 	/* Update attrtimeo value if we're out of the unstable period */
+-	if (invalid & NFS_INO_INVALID_ATTR) {
++	if (invalid & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) {
+ 		nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
+ 		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
+ 		nfsi->attrtimeo_timestamp = now;
+@@ -1495,6 +1573,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
+ 		}
+ 	}
+ 	invalid &= ~NFS_INO_INVALID_ATTR;
++	invalid &= ~NFS_INO_INVALID_LABEL;
+ 	/* Don't invalidate the data if we were to blame */
+ 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
+ 				|| S_ISLNK(inode->i_mode)))
+diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
+index fc8dc20..348b535 100644
+--- a/fs/nfs/namespace.c
++++ b/fs/nfs/namespace.c
+@@ -280,7 +280,7 @@ struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry,
+ 	struct dentry *parent = dget_parent(dentry);
+ 
+ 	/* Look it up again to get its attributes */
+-	err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr);
++	err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr, NULL);
+ 	dput(parent);
+ 	if (err != 0)
+ 		return ERR_PTR(err);
+diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
+index 4a1aafb..1a2f11b 100644
+--- a/fs/nfs/nfs3acl.c
++++ b/fs/nfs/nfs3acl.c
+@@ -240,7 +240,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
+ 
+ 	switch (status) {
+ 		case 0:
+-			status = nfs_refresh_inode(inode, res.fattr);
++			status = nfs_refresh_inode(inode, res.fattr, NULL);
+ 			break;
+ 		case -EPFNOSUPPORT:
+ 		case -EPROTONOSUPPORT:
+@@ -352,7 +352,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
+ 
+ 	switch (status) {
+ 		case 0:
+-			status = nfs_refresh_inode(inode, fattr);
++			status = nfs_refresh_inode(inode, fattr, NULL);
+ 			nfs3_cache_acls(inode, acl, dfacl);
+ 			break;
+ 		case -EPFNOSUPPORT:
+diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
+index 70efb63..69bca2f 100644
+--- a/fs/nfs/nfs3proc.c
++++ b/fs/nfs/nfs3proc.c
+@@ -98,7 +98,7 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+  */
+ static int
+ nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+-		struct nfs_fattr *fattr)
++		struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+ 	struct rpc_message msg = {
+ 		.rpc_proc	= &nfs3_procedures[NFS3PROC_GETATTR],
+@@ -143,7 +143,8 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+ 
+ static int
+ nfs3_proc_lookup(struct inode *dir, struct qstr *name,
+-		 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
++		 struct nfs_fh *fhandle, struct nfs_fattr *fattr,
++		 struct nfs4_label *label)
+ {
+ 	struct nfs3_diropargs	arg = {
+ 		.fh		= NFS_FH(dir),
+@@ -168,7 +169,7 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name,
+ 
+ 	nfs_fattr_init(fattr);
+ 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+-	nfs_refresh_inode(dir, res.dir_attr);
++	nfs_refresh_inode(dir, res.dir_attr, NULL);
+ 	if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) {
+ 		msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
+ 		msg.rpc_argp = fhandle;
+@@ -216,7 +217,7 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
+ 		goto out;
+ 
+ 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
+-	nfs_refresh_inode(inode, res.fattr);
++	nfs_refresh_inode(inode, res.fattr, NULL);
+ 	if (status == 0) {
+ 		entry->mask = 0;
+ 		if (res.access & NFS3_ACCESS_READ)
+@@ -255,7 +256,7 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page,
+ 	msg.rpc_resp = fattr;
+ 
+ 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
+-	nfs_refresh_inode(inode, fattr);
++	nfs_refresh_inode(inode, fattr, NULL);
+ 	nfs_free_fattr(fattr);
+ out:
+ 	dprintk("NFS reply readlink: %d\n", status);
+@@ -298,9 +299,9 @@ static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_
+ 	int status;
+ 
+ 	status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0);
+-	nfs_post_op_update_inode(dir, data->res.dir_attr);
++	nfs_post_op_update_inode(dir, data->res.dir_attr, NULL);
+ 	if (status == 0)
+-		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
++		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
+ 	return status;
+ }
+ 
+@@ -381,7 +382,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
+ 		 * not sure this buys us anything (and I'd have
+ 		 * to revamp the NFSv3 XDR code) */
+ 		status = nfs3_proc_setattr(dentry, data->res.fattr, sattr);
+-		nfs_post_op_update_inode(dentry->d_inode, data->res.fattr);
++		nfs_post_op_update_inode(dentry->d_inode, data->res.fattr, NULL);
+ 		dprintk("NFS reply setattr (post-create): %d\n", status);
+ 		if (status != 0)
+ 			goto out;
+@@ -414,7 +415,7 @@ nfs3_proc_remove(struct inode *dir, struct qstr *name)
+ 		goto out;
+ 
+ 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+-	nfs_post_op_update_inode(dir, res.dir_attr);
++	nfs_post_op_update_inode(dir, res.dir_attr, NULL);
+ 	nfs_free_fattr(res.dir_attr);
+ out:
+ 	dprintk("NFS reply remove: %d\n", status);
+@@ -439,7 +440,7 @@ nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
+ 	if (nfs3_async_handle_jukebox(task, dir))
+ 		return 0;
+ 	res = task->tk_msg.rpc_resp;
+-	nfs_post_op_update_inode(dir, res->dir_attr);
++	nfs_post_op_update_inode(dir, res->dir_attr, NULL);
+ 	return 1;
+ }
+ 
+@@ -464,8 +465,8 @@ nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
+ 		return 0;
+ 	res = task->tk_msg.rpc_resp;
+ 
+-	nfs_post_op_update_inode(old_dir, res->old_fattr);
+-	nfs_post_op_update_inode(new_dir, res->new_fattr);
++	nfs_post_op_update_inode(old_dir, res->old_fattr, NULL);
++	nfs_post_op_update_inode(new_dir, res->new_fattr, NULL);
+ 	return 1;
+ }
+ 
+@@ -495,8 +496,8 @@ nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
+ 		goto out;
+ 
+ 	status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0);
+-	nfs_post_op_update_inode(old_dir, res.old_fattr);
+-	nfs_post_op_update_inode(new_dir, res.new_fattr);
++	nfs_post_op_update_inode(old_dir, res.old_fattr, NULL);
++	nfs_post_op_update_inode(new_dir, res.new_fattr, NULL);
+ out:
+ 	nfs_free_fattr(res.old_fattr);
+ 	nfs_free_fattr(res.new_fattr);
+@@ -528,8 +529,8 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
+ 		goto out;
+ 
+ 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
+-	nfs_post_op_update_inode(dir, res.dir_attr);
+-	nfs_post_op_update_inode(inode, res.fattr);
++	nfs_post_op_update_inode(dir, res.dir_attr, NULL);
++	nfs_post_op_update_inode(inode, res.fattr, NULL);
+ out:
+ 	nfs_free_fattr(res.dir_attr);
+ 	nfs_free_fattr(res.fattr);
+@@ -622,7 +623,7 @@ nfs3_proc_rmdir(struct inode *dir, struct qstr *name)
+ 
+ 	msg.rpc_resp = dir_attr;
+ 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+-	nfs_post_op_update_inode(dir, dir_attr);
++	nfs_post_op_update_inode(dir, dir_attr, NULL);
+ 	nfs_free_fattr(dir_attr);
+ out:
+ 	dprintk("NFS reply rmdir: %d\n", status);
+@@ -677,7 +678,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
+ 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ 
+ 	nfs_invalidate_atime(dir);
+-	nfs_refresh_inode(dir, res.dir_attr);
++	nfs_refresh_inode(dir, res.dir_attr, NULL);
+ 
+ 	nfs_free_fattr(res.dir_attr);
+ out:
+@@ -816,7 +817,7 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
+ 		return -EAGAIN;
+ 
+ 	nfs_invalidate_atime(inode);
+-	nfs_refresh_inode(inode, &data->fattr);
++	nfs_refresh_inode(inode, &data->fattr, NULL);
+ 	return 0;
+ }
+ 
+@@ -860,7 +861,7 @@ static int nfs3_commit_done(struct rpc_task *task, struct nfs_commit_data *data)
+ {
+ 	if (nfs3_async_handle_jukebox(task, data->inode))
+ 		return -EAGAIN;
+-	nfs_refresh_inode(data->inode, data->res.fattr);
++	nfs_refresh_inode(data->inode, data->res.fattr, NULL);
+ 	return 0;
+ }
+ 
+diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
+index a3f488b..5ae39be 100644
+--- a/fs/nfs/nfs4_fs.h
++++ b/fs/nfs/nfs4_fs.h
+@@ -225,7 +225,7 @@ extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh
+ extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *,
+ 				  struct nfs4_fs_locations *, struct page *);
+ extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *,
+-			    struct nfs_fh *, struct nfs_fattr *);
++			    struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *);
+ extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
+ extern int nfs4_release_lockowner(struct nfs4_lock_state *);
+ extern const struct xattr_handler *nfs4_xattr_handlers[];
+@@ -291,10 +291,10 @@ is_ds_client(struct nfs_client *clp)
+ extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
+ 
+ extern const u32 nfs4_fattr_bitmap[3];
+-extern const u32 nfs4_statfs_bitmap[2];
+-extern const u32 nfs4_pathconf_bitmap[2];
++extern const u32 nfs4_statfs_bitmap[3];
++extern const u32 nfs4_pathconf_bitmap[3];
+ extern const u32 nfs4_fsinfo_bitmap[3];
+-extern const u32 nfs4_fs_locations_bitmap[2];
++extern const u32 nfs4_fs_locations_bitmap[3];
+ 
+ void nfs4_free_client(struct nfs_client *);
+ 
+diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
+index 1e09eb7..f5c701e 100644
+--- a/fs/nfs/nfs4namespace.c
++++ b/fs/nfs/nfs4namespace.c
+@@ -368,7 +368,7 @@ struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
+ 	struct vfsmount *mnt;
+ 
+ 	/* Look it up again to get its attributes and sec flavor */
+-	client = nfs4_proc_lookup_mountpoint(parent->d_inode, &dentry->d_name, fh, fattr);
++	client = nfs4_proc_lookup_mountpoint(parent->d_inode, &dentry->d_name, fh, fattr, NULL);
+ 	dput(parent);
+ 	if (IS_ERR(client))
+ 		return ERR_CAST(client);
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index cf747ef..40c1d1f 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -77,15 +77,49 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
+ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
+ static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
+ static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
+-static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *);
+-static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
++static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label);
++static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label);
+ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
+ 			    struct nfs_fattr *fattr, struct iattr *sattr,
+-			    struct nfs4_state *state);
++			    struct nfs4_state *state, struct nfs4_label *ilabel,
++			    struct nfs4_label *olabel);
+ #ifdef CONFIG_NFS_V4_1
+ static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *);
+ static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *);
+ #endif
++
++#ifdef CONFIG_NFS_V4_SECURITY_LABEL
++static inline struct nfs4_label *
++nfs4_label_init_security(struct inode *dir, struct dentry *dentry, 
++	struct iattr *sattr, struct nfs4_label *l)
++{
++	int err;
++
++	if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
++		err = security_dentry_init_security(dentry, sattr->ia_mode,
++					&dentry->d_name, (void **)&l->label, &l->len);
++		if (err == 0)
++			return l;
++	}
++	return NULL;
++}
++static inline void 
++nfs4_label_release_security(struct nfs4_label *label) 
++{
++	if (label)
++		security_release_secctx(label->label, label->len);
++}
++#else
++static inline struct nfs4_label *
++nfs4_label_init_security(struct inode *dir, struct dentry *dentry, 
++	struct iattr *sattr, struct nfs4_label *l)
++{ return NULL; }
++
++static inline void 
++nfs4_label_release_security(struct nfs4_label *label) 
++{ return; }
++#endif
++
+ /* Prevent leaks of NFSv4 errors into userland */
+ static int nfs4_map_errors(int err)
+ {
+@@ -130,7 +164,8 @@ const u32 nfs4_fattr_bitmap[3] = {
+ 	| FATTR4_WORD1_SPACE_USED
+ 	| FATTR4_WORD1_TIME_ACCESS
+ 	| FATTR4_WORD1_TIME_METADATA
+-	| FATTR4_WORD1_TIME_MODIFY
++	| FATTR4_WORD1_TIME_MODIFY,
++	FATTR4_WORD2_SECURITY_LABEL
+ };
+ 
+ static const u32 nfs4_pnfs_open_bitmap[3] = {
+@@ -157,7 +192,7 @@ static const u32 nfs4_open_noattr_bitmap[3] = {
+ 	| FATTR4_WORD0_FILEID,
+ };
+ 
+-const u32 nfs4_statfs_bitmap[2] = {
++const u32 nfs4_statfs_bitmap[3] = {
+ 	FATTR4_WORD0_FILES_AVAIL
+ 	| FATTR4_WORD0_FILES_FREE
+ 	| FATTR4_WORD0_FILES_TOTAL,
+@@ -166,7 +201,7 @@ const u32 nfs4_statfs_bitmap[2] = {
+ 	| FATTR4_WORD1_SPACE_TOTAL
+ };
+ 
+-const u32 nfs4_pathconf_bitmap[2] = {
++const u32 nfs4_pathconf_bitmap[3] = {
+ 	FATTR4_WORD0_MAXLINK
+ 	| FATTR4_WORD0_MAXNAME,
+ 	0
+@@ -181,7 +216,7 @@ const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
+ 			FATTR4_WORD2_LAYOUT_BLKSIZE
+ };
+ 
+-const u32 nfs4_fs_locations_bitmap[2] = {
++const u32 nfs4_fs_locations_bitmap[3] = {
+ 	FATTR4_WORD0_TYPE
+ 	| FATTR4_WORD0_CHANGE
+ 	| FATTR4_WORD0_SIZE
+@@ -197,7 +232,7 @@ const u32 nfs4_fs_locations_bitmap[2] = {
+ 	| FATTR4_WORD1_TIME_ACCESS
+ 	| FATTR4_WORD1_TIME_METADATA
+ 	| FATTR4_WORD1_TIME_MODIFY
+-	| FATTR4_WORD1_MOUNTED_ON_FILEID
++	| FATTR4_WORD1_MOUNTED_ON_FILEID,
+ };
+ 
+ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
+@@ -747,6 +782,7 @@ struct nfs4_opendata {
+ 	struct nfs4_string owner_name;
+ 	struct nfs4_string group_name;
+ 	struct nfs_fattr f_attr;
++	struct nfs4_label *f_label;
+ 	struct dentry *dir;
+ 	struct dentry *dentry;
+ 	struct nfs4_state_owner *owner;
+@@ -762,6 +798,7 @@ struct nfs4_opendata {
+ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
+ {
+ 	p->o_res.f_attr = &p->f_attr;
++	p->o_res.f_label = p->f_label;
+ 	p->o_res.seqid = p->o_arg.seqid;
+ 	p->c_res.seqid = p->c_arg.seqid;
+ 	p->o_res.server = p->o_arg.server;
+@@ -772,7 +809,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
+ 
+ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
+ 		struct nfs4_state_owner *sp, fmode_t fmode, int flags,
+-		const struct iattr *attrs,
++		const struct iattr *attrs, struct nfs4_label *label,
+ 		gfp_t gfp_mask)
+ {
+ 	struct dentry *parent = dget_parent(dentry);
+@@ -783,9 +820,14 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
+ 	p = kzalloc(sizeof(*p), gfp_mask);
+ 	if (p == NULL)
+ 		goto err;
++
++	p->f_label = nfs4_label_alloc(server, gfp_mask);
++	if (IS_ERR(p->f_label))
++		goto err_free_p;
++
+ 	p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask);
+ 	if (p->o_arg.seqid == NULL)
+-		goto err_free;
++		goto err_free_label;
+ 	nfs_sb_active(dentry->d_sb);
+ 	p->dentry = dget(dentry);
+ 	p->dir = parent;
+@@ -810,6 +852,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
+ 	p->o_arg.bitmask = server->attr_bitmask;
+ 	p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
+ 	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
++	p->o_arg.label = label;
+ 	if (attrs != NULL && attrs->ia_valid != 0) {
+ 		__be32 verf[2];
+ 
+@@ -827,7 +870,10 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
+ 	nfs4_init_opendata_res(p);
+ 	kref_init(&p->kref);
+ 	return p;
+-err_free:
++
++err_free_label:
++	nfs4_label_free(p->f_label);
++err_free_p:
+ 	kfree(p);
+ err:
+ 	dput(parent);
+@@ -844,6 +890,9 @@ static void nfs4_opendata_free(struct kref *kref)
+ 	if (p->state != NULL)
+ 		nfs4_put_open_state(p->state);
+ 	nfs4_put_state_owner(p->owner);
++
++	nfs4_label_free(p->f_label);
++
+ 	dput(p->dir);
+ 	dput(p->dentry);
+ 	nfs_sb_deactive(sb);
+@@ -1111,7 +1160,7 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
+ 	if (state == NULL)
+ 		goto err;
+ 
+-	ret = nfs_refresh_inode(inode, &data->f_attr);
++	ret = nfs_refresh_inode(inode, &data->f_attr, data->f_label);
+ 	if (ret)
+ 		goto err;
+ 
+@@ -1141,7 +1190,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
+ 	ret = -EAGAIN;
+ 	if (!(data->f_attr.valid & NFS_ATTR_FATTR))
+ 		goto err;
+-	inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr);
++	inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr, data->f_label);
+ 	ret = PTR_ERR(inode);
+ 	if (IS_ERR(inode))
+ 		goto err;
+@@ -1191,7 +1240,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
+ {
+ 	struct nfs4_opendata *opendata;
+ 
+-	opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, NULL, GFP_NOFS);
++	opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, NULL, NULL, GFP_NOFS);
+ 	if (opendata == NULL)
+ 		return ERR_PTR(-ENOMEM);
+ 	opendata->state = state;
+@@ -1694,7 +1743,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
+ 			return status;
+ 	}
+ 	if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
+-		_nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr);
++		_nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr, o_res->f_label);
+ 	return 0;
+ }
+ 
+@@ -1853,6 +1902,7 @@ static int _nfs4_do_open(struct inode *dir,
+ 			fmode_t fmode,
+ 			int flags,
+ 			struct iattr *sattr,
++			struct nfs4_label *label,
+ 			struct rpc_cred *cred,
+ 			struct nfs4_state **res,
+ 			struct nfs4_threshold **ctx_th)
+@@ -1861,6 +1911,7 @@ static int _nfs4_do_open(struct inode *dir,
+ 	struct nfs4_state     *state = NULL;
+ 	struct nfs_server       *server = NFS_SERVER(dir);
+ 	struct nfs4_opendata *opendata;
++	struct nfs4_label *olabel = NULL;
+ 	int status;
+ 
+ 	/* Protect against reboot recovery conflicts */
+@@ -1876,10 +1927,18 @@ static int _nfs4_do_open(struct inode *dir,
+ 	if (dentry->d_inode != NULL)
+ 		nfs4_return_incompatible_delegation(dentry->d_inode, fmode);
+ 	status = -ENOMEM;
+-	opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, GFP_KERNEL);
++	opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, label, GFP_KERNEL);
+ 	if (opendata == NULL)
+ 		goto err_put_state_owner;
+ 
++	if (label) {
++		olabel = nfs4_label_alloc(server, GFP_KERNEL);
++		if (IS_ERR(olabel)) {
++			status = PTR_ERR(olabel);
++			goto err_opendata_put;
++		}
++	}
++
+ 	if (ctx_th && server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) {
+ 		opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc();
+ 		if (!opendata->f_attr.mdsthreshold)
+@@ -1891,18 +1950,18 @@ static int _nfs4_do_open(struct inode *dir,
+ 
+ 	status = _nfs4_proc_open(opendata);
+ 	if (status != 0)
+-		goto err_opendata_put;
++		goto err_free_label;
+ 
+ 	state = nfs4_opendata_to_nfs4_state(opendata);
+ 	status = PTR_ERR(state);
+ 	if (IS_ERR(state))
+-		goto err_opendata_put;
++		goto err_free_label;
+ 	if (server->caps & NFS_CAP_POSIX_LOCK)
+ 		set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
+ 
+ 	status = nfs4_opendata_access(cred, opendata, state, fmode, flags);
+ 	if (status != 0)
+-		goto err_opendata_put;
++		goto err_free_label;
+ 
+ 	if (opendata->o_arg.open_flags & O_EXCL) {
+ 		nfs4_exclusive_attrset(opendata, sattr);
+@@ -1910,10 +1969,12 @@ static int _nfs4_do_open(struct inode *dir,
+ 		nfs_fattr_init(opendata->o_res.f_attr);
+ 		status = nfs4_do_setattr(state->inode, cred,
+ 				opendata->o_res.f_attr, sattr,
+-				state);
+-		if (status == 0)
++				state, label, olabel);
++		if (status == 0) {
+ 			nfs_setattr_update_inode(state->inode, sattr);
+-		nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr);
++			nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel);
++			nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
++		}
+ 	}
+ 
+ 	if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
+@@ -1922,10 +1983,14 @@ static int _nfs4_do_open(struct inode *dir,
+ 		kfree(opendata->f_attr.mdsthreshold);
+ 	opendata->f_attr.mdsthreshold = NULL;
+ 
++	nfs4_label_free(olabel);
++
+ 	nfs4_opendata_put(opendata);
+ 	nfs4_put_state_owner(sp);
+ 	*res = state;
+ 	return 0;
++err_free_label:
++	nfs4_label_free(olabel);
+ err_opendata_put:
+ 	kfree(opendata->f_attr.mdsthreshold);
+ 	nfs4_opendata_put(opendata);
+@@ -1942,6 +2007,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
+ 					fmode_t fmode,
+ 					int flags,
+ 					struct iattr *sattr,
++					struct nfs4_label *label,
+ 					struct rpc_cred *cred,
+ 					struct nfs4_threshold **ctx_th)
+ {
+@@ -1951,7 +2017,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
+ 
+ 	fmode &= FMODE_READ|FMODE_WRITE|FMODE_EXEC;
+ 	do {
+-		status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred,
++		status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, label, cred,
+ 				       &res, ctx_th);
+ 		if (status == 0)
+ 			break;
+@@ -1996,7 +2062,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
+ 
+ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
+ 			    struct nfs_fattr *fattr, struct iattr *sattr,
+-			    struct nfs4_state *state)
++			    struct nfs4_state *state, struct nfs4_label *ilabel,
++			    struct nfs4_label *olabel)
+ {
+ 	struct nfs_server *server = NFS_SERVER(inode);
+         struct nfs_setattrargs  arg = {
+@@ -2004,9 +2071,11 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
+                 .iap            = sattr,
+ 		.server		= server,
+ 		.bitmask = server->attr_bitmask,
++		.label		= ilabel,
+         };
+         struct nfs_setattrres  res = {
+ 		.fattr		= fattr,
++		.label		= olabel,
+ 		.server		= server,
+         };
+         struct rpc_message msg = {
+@@ -2018,6 +2087,9 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
+ 	unsigned long timestamp = jiffies;
+ 	int status;
+ 
++	if (ilabel == NULL || olabel == NULL)
++		arg.bitmask = server->attr_bitmask_nl;
++
+ 	nfs_fattr_init(fattr);
+ 
+ 	if (state != NULL) {
+@@ -2041,7 +2113,8 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
+ 
+ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
+ 			   struct nfs_fattr *fattr, struct iattr *sattr,
+-			   struct nfs4_state *state)
++			   struct nfs4_state *state, struct nfs4_label *ilabel,
++			   struct nfs4_label *olabel)
+ {
+ 	struct nfs_server *server = NFS_SERVER(inode);
+ 	struct nfs4_exception exception = {
+@@ -2050,7 +2123,7 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
+ 	};
+ 	int err;
+ 	do {
+-		err = _nfs4_do_setattr(inode, cred, fattr, sattr, state);
++		err = _nfs4_do_setattr(inode, cred, fattr, sattr, state, ilabel, olabel);
+ 		switch (err) {
+ 		case -NFS4ERR_OPENMODE:
+ 			if (state && !(state->state & FMODE_WRITE)) {
+@@ -2137,7 +2210,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
+ 				rpc_restart_call_prepare(task);
+ 	}
+ 	nfs_release_seqid(calldata->arg.seqid);
+-	nfs_refresh_inode(calldata->inode, calldata->res.fattr);
++	nfs_refresh_inode(calldata->inode, calldata->res.fattr, NULL);
+ 	dprintk("%s: done, ret = %d!\n", __func__, task->tk_status);
+ }
+ 
+@@ -2244,7 +2317,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
+ 	if (calldata->arg.seqid == NULL)
+ 		goto out_free_calldata;
+ 	calldata->arg.fmode = 0;
+-	calldata->arg.bitmask = server->cache_consistency_bitmask;
++	calldata->arg.bitmask = server->cache_consistency_bitmask_nl;
+ 	calldata->res.fattr = &calldata->fattr;
+ 	calldata->res.seqid = calldata->arg.seqid;
+ 	calldata->res.server = server;
+@@ -2274,10 +2347,16 @@ static struct inode *
+ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
+ {
+ 	struct nfs4_state *state;
++	struct nfs4_label l, *label = NULL;
++
++	label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);
+ 
+ 	/* Protect against concurrent sillydeletes */
+-	state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr,
++	state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr, label,
+ 			     ctx->cred, &ctx->mdsthreshold);
++
++	nfs4_label_release_security(label);
++
+ 	if (IS_ERR(state))
+ 		return ERR_CAST(state);
+ 	ctx->state = state;
+@@ -2337,10 +2416,27 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
+ 			server->caps |= NFS_CAP_CTIME;
+ 		if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY)
+ 			server->caps |= NFS_CAP_MTIME;
++#ifdef CONFIG_NFS_V4_SECURITY_LABEL
++		if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL) {
++			server->caps |= NFS_CAP_SECURITY_LABEL;
++		} else
++#endif
++		server->attr_bitmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
++
++		if (server->caps & NFS_CAP_SECURITY_LABEL) {
++			memcpy(server->attr_bitmask_nl, res.attr_bitmask, 
++				sizeof(server->attr_bitmask));
++			server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
++		}
+ 
+ 		memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
+ 		server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
+-		server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
++		server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA |
++							FATTR4_WORD1_TIME_MODIFY;
++		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
++		memcpy(server->cache_consistency_bitmask_nl, server->cache_consistency_bitmask,
++							sizeof(server->cache_consistency_bitmask_nl));
++		server->cache_consistency_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+ 		server->acl_bitmask = res.acl_bitmask;
+ 		server->fh_expire_type = res.fh_expire_type;
+ 	}
+@@ -2363,8 +2459,9 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
+ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
+ 		struct nfs_fsinfo *info)
+ {
++	u32 bitmask[3];
+ 	struct nfs4_lookup_root_arg args = {
+-		.bitmask = nfs4_fattr_bitmap,
++		.bitmask = bitmask,
+ 	};
+ 	struct nfs4_lookup_res res = {
+ 		.server = server,
+@@ -2377,6 +2474,13 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
+ 		.rpc_resp = &res,
+ 	};
+ 
++	bitmask[0] = nfs4_fattr_bitmap[0];
++	bitmask[1] = nfs4_fattr_bitmap[1];
++	/*
++	 * Process the label in the upcoming getfattr 
++	 */
++	bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL;
++
+ 	nfs_fattr_init(info->fattr);
+ 	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
+ }
+@@ -2475,6 +2579,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
+ {
+ 	int error;
+ 	struct nfs_fattr *fattr = info->fattr;
++	struct nfs4_label *label = NULL;
+ 
+ 	error = nfs4_server_capabilities(server, mntfh);
+ 	if (error < 0) {
+@@ -2482,16 +2587,23 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
+ 		return error;
+ 	}
+ 
+-	error = nfs4_proc_getattr(server, mntfh, fattr);
++	label = nfs4_label_alloc(server, GFP_KERNEL);
++	if (IS_ERR(label))
++		return PTR_ERR(label);
++
++	error = nfs4_proc_getattr(server, mntfh, fattr, label);
+ 	if (error < 0) {
+ 		dprintk("nfs4_get_root: getattr error = %d\n", -error);
+-		return error;
++		goto err_free_label;
+ 	}
+ 
+ 	if (fattr->valid & NFS_ATTR_FATTR_FSID &&
+ 	    !nfs_fsid_equal(&server->fsid, &fattr->fsid))
+ 		memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
+ 
++err_free_label:
++	nfs4_label_free(label);
++
+ 	return error;
+ }
+ 
+@@ -2538,7 +2650,8 @@ out:
+ 	return status;
+ }
+ 
+-static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
++static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
++				struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+ 	struct nfs4_getattr_arg args = {
+ 		.fh = fhandle,
+@@ -2546,6 +2659,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+ 	};
+ 	struct nfs4_getattr_res res = {
+ 		.fattr = fattr,
++		.label = label,
+ 		.server = server,
+ 	};
+ 	struct rpc_message msg = {
+@@ -2553,18 +2667,22 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+ 		.rpc_argp = &args,
+ 		.rpc_resp = &res,
+ 	};
+-	
++
++	if (!label)
++		args.bitmask = server->attr_bitmask_nl;
++
+ 	nfs_fattr_init(fattr);
+ 	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
+ }
+ 
+-static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
++static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
++				struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+ 	struct nfs4_exception exception = { };
+ 	int err;
+ 	do {
+ 		err = nfs4_handle_exception(server,
+-				_nfs4_proc_getattr(server, fhandle, fattr),
++				_nfs4_proc_getattr(server, fhandle, fattr, label),
+ 				&exception);
+ 	} while (exception.retry);
+ 	return err;
+@@ -2594,6 +2712,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+ 	struct inode *inode = dentry->d_inode;
+ 	struct rpc_cred *cred = NULL;
+ 	struct nfs4_state *state = NULL;
++	struct nfs4_label *label = NULL;
+ 	int status;
+ 
+ 	if (pnfs_ld_layoutret_on_setattr(inode))
+@@ -2620,15 +2739,21 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+ 		}
+ 	}
+ 
+-	status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
++	label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
++	if (IS_ERR(label))
++		return PTR_ERR(label);
++
++	status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, label);
+ 	if (status == 0)
+ 		nfs_setattr_update_inode(inode, sattr);
++
++	nfs4_label_free(label);
+ 	return status;
+ }
+ 
+ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
+ 		const struct qstr *name, struct nfs_fh *fhandle,
+-		struct nfs_fattr *fattr)
++		struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+ 	struct nfs_server *server = NFS_SERVER(dir);
+ 	int		       status;
+@@ -2640,6 +2765,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
+ 	struct nfs4_lookup_res res = {
+ 		.server = server,
+ 		.fattr = fattr,
++		.label = label,
+ 		.fh = fhandle,
+ 	};
+ 	struct rpc_message msg = {
+@@ -2648,6 +2774,9 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
+ 		.rpc_resp = &res,
+ 	};
+ 
++	if (label == NULL)
++		args.bitmask = server->attr_bitmask_nl;
++
+ 	nfs_fattr_init(fattr);
+ 
+ 	dprintk("NFS call  lookup %s\n", name->name);
+@@ -2666,13 +2795,13 @@ static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr)
+ 
+ static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
+ 				   struct qstr *name, struct nfs_fh *fhandle,
+-				   struct nfs_fattr *fattr)
++				   struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+ 	struct nfs4_exception exception = { };
+ 	struct rpc_clnt *client = *clnt;
+ 	int err;
+ 	do {
+-		err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr);
++		err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label);
+ 		switch (err) {
+ 		case -NFS4ERR_BADNAME:
+ 			err = -ENOENT;
+@@ -2706,12 +2835,13 @@ out:
+ }
+ 
+ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
+-			    struct nfs_fh *fhandle, struct nfs_fattr *fattr)
++			    struct nfs_fh *fhandle, struct nfs_fattr *fattr,
++			    struct nfs4_label *label)
+ {
+ 	int status;
+ 	struct rpc_clnt *client = NFS_CLIENT(dir);
+ 
+-	status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr);
++	status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, label);
+ 	if (client != NFS_CLIENT(dir)) {
+ 		rpc_shutdown_client(client);
+ 		nfs_fixup_secinfo_attributes(fattr);
+@@ -2721,12 +2851,13 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
+ 
+ struct rpc_clnt *
+ nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name,
+-			    struct nfs_fh *fhandle, struct nfs_fattr *fattr)
++			    struct nfs_fh *fhandle, struct nfs_fattr *fattr,
++			    struct nfs4_label *label)
+ {
+ 	int status;
+ 	struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir));
+ 
+-	status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr);
++	status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, label);
+ 	if (status < 0) {
+ 		rpc_shutdown_client(client);
+ 		return ERR_PTR(status);
+@@ -2743,6 +2874,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
+ 	};
+ 	struct nfs4_accessres res = {
+ 		.server = server,
++		.label = NULL,
+ 	};
+ 	struct rpc_message msg = {
+ 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
+@@ -2751,7 +2883,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
+ 		.rpc_cred = entry->cred,
+ 	};
+ 	int mode = entry->mask;
+-	int status;
++	int status = 0;
+ 
+ 	/*
+ 	 * Determine which access bits we want to ask for...
+@@ -2774,11 +2906,21 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
+ 	if (res.fattr == NULL)
+ 		return -ENOMEM;
+ 
++	res.label = nfs4_label_alloc(server, GFP_KERNEL);
++	if (IS_ERR(res.label)) {
++		status = PTR_ERR(res.label);
++		goto out;
++	}
++
+ 	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
+ 	if (!status) {
+ 		nfs_access_set_mask(entry, res.access);
+-		nfs_refresh_inode(inode, res.fattr);
++		nfs_refresh_inode(inode, res.fattr, res.label);
+ 	}
++
++	nfs4_label_free(res.label);
++
++out:
+ 	nfs_free_fattr(res.fattr);
+ 	return status;
+ }
+@@ -2856,6 +2998,7 @@ static int
+ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
+ 		 int flags)
+ {
++	struct nfs4_label l, *ilabel = NULL;
+ 	struct nfs_open_context *ctx;
+ 	struct nfs4_state *state;
+ 	int status = 0;
+@@ -2864,9 +3007,11 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
+ 	if (IS_ERR(ctx))
+ 		return PTR_ERR(ctx);
+ 
++	ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
++
+ 	sattr->ia_mode &= ~current_umask();
+ 	state = nfs4_do_open(dir, dentry, ctx->mode,
+-			flags, sattr, ctx->cred,
++			flags, sattr, ilabel, ctx->cred,
+ 			&ctx->mdsthreshold);
+ 	d_drop(dentry);
+ 	if (IS_ERR(state)) {
+@@ -2877,6 +3022,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
+ 	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+ 	ctx->state = state;
+ out:
++	nfs4_label_release_security(ilabel);
+ 	put_nfs_open_context(ctx);
+ 	return status;
+ }
+@@ -2925,6 +3071,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
+ 	res->server = server;
+ 	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
+ 	nfs41_init_sequence(&args->seq_args, &res->seq_res, 1);
++
++	nfs_fattr_init(res->dir_attr);
+ }
+ 
+ static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
+@@ -2990,6 +3138,8 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
+ 		.new_dir = NFS_FH(new_dir),
+ 		.old_name = old_name,
+ 		.new_name = new_name,
++		.old_label = NULL,
++		.new_label = NULL,
+ 	};
+ 	struct nfs_renameres res = {
+ 		.server = server,
+@@ -3000,12 +3150,33 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
+ 		.rpc_resp = &res,
+ 	};
+ 	int status = -ENOMEM;
++
++
++	if (server->caps & NFS_CAP_SECURITY_LABEL) {
++		res.old_label = nfs4_label_alloc(server, GFP_NOWAIT);
++		if (IS_ERR(res.old_label)) {
++			status = PTR_ERR(res.old_label);
++			goto out;
++		}
++		res.new_label = nfs4_label_alloc(server, GFP_NOWAIT);
++		if (IS_ERR(res.new_label)) {
++			status = PTR_ERR(res.new_label);
++			nfs4_label_free(res.old_label);
++			goto out;
++		}
++	}
++
+ 	
+ 	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
+ 	if (!status) {
+ 		update_changeattr(old_dir, &res.old_cinfo);
+ 		update_changeattr(new_dir, &res.new_cinfo);
+ 	}
++
++	nfs4_label_free(res.old_label);
++	nfs4_label_free(res.new_label);
++
++out:
+ 	return status;
+ }
+ 
+@@ -3034,6 +3205,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
+ 	};
+ 	struct nfs4_link_res res = {
+ 		.server = server,
++		.label = NULL,
+ 	};
+ 	struct rpc_message msg = {
+ 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
+@@ -3046,11 +3218,21 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
+ 	if (res.fattr == NULL)
+ 		goto out;
+ 
++	res.label = nfs4_label_alloc(server, GFP_KERNEL);
++	if (IS_ERR(res.label)) {
++		status = PTR_ERR(res.label);
++		goto out;
++	}
++
+ 	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
+ 	if (!status) {
+ 		update_changeattr(dir, &res.cinfo);
+-		nfs_post_op_update_inode(inode, res.fattr);
++		nfs_post_op_update_inode(inode, res.fattr, res.label);
+ 	}
++
++
++	nfs4_label_free(res.label);
++
+ out:
+ 	nfs_free_fattr(res.fattr);
+ 	return status;
+@@ -3074,6 +3256,7 @@ struct nfs4_createdata {
+ 	struct nfs4_create_res res;
+ 	struct nfs_fh fh;
+ 	struct nfs_fattr fattr;
++	struct nfs4_label *label;
+ };
+ 
+ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
+@@ -3085,6 +3268,10 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
+ 	if (data != NULL) {
+ 		struct nfs_server *server = NFS_SERVER(dir);
+ 
++		data->label = nfs4_label_alloc(server, GFP_KERNEL);
++		if (IS_ERR(data->label))
++			goto out_free;
++
+ 		data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE];
+ 		data->msg.rpc_argp = &data->arg;
+ 		data->msg.rpc_resp = &data->res;
+@@ -3097,9 +3284,13 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
+ 		data->res.server = server;
+ 		data->res.fh = &data->fh;
+ 		data->res.fattr = &data->fattr;
++		data->res.label = data->label;
+ 		nfs_fattr_init(data->res.fattr);
+ 	}
+ 	return data;
++out_free:
++	kfree(data);
++	return NULL;
+ }
+ 
+ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
+@@ -3108,18 +3299,20 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
+ 				    &data->arg.seq_args, &data->res.seq_res, 1);
+ 	if (status == 0) {
+ 		update_changeattr(dir, &data->res.dir_cinfo);
+-		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
++		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label);
+ 	}
+ 	return status;
+ }
+ 
+ static void nfs4_free_createdata(struct nfs4_createdata *data)
+ {
++	nfs4_label_free(data->label);
+ 	kfree(data);
+ }
+ 
+ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
+-		struct page *page, unsigned int len, struct iattr *sattr)
++		struct page *page, unsigned int len, struct iattr *sattr,
++		struct nfs4_label *label)
+ {
+ 	struct nfs4_createdata *data;
+ 	int status = -ENAMETOOLONG;
+@@ -3135,6 +3328,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
+ 	data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK];
+ 	data->arg.u.symlink.pages = &page;
+ 	data->arg.u.symlink.len = len;
++	data->arg.label = label;
+ 	
+ 	status = nfs4_do_create(dir, dentry, data);
+ 
+@@ -3147,18 +3341,24 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
+ 		struct page *page, unsigned int len, struct iattr *sattr)
+ {
+ 	struct nfs4_exception exception = { };
++	struct nfs4_label l, *label = NULL;
+ 	int err;
++
++	label = nfs4_label_init_security(dir, dentry, sattr, &l);
++
+ 	do {
+ 		err = nfs4_handle_exception(NFS_SERVER(dir),
+ 				_nfs4_proc_symlink(dir, dentry, page,
+-							len, sattr),
++							len, sattr, label),
+ 				&exception);
+ 	} while (exception.retry);
++
++	nfs4_label_release_security(label);
+ 	return err;
+ }
+ 
+ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
+-		struct iattr *sattr)
++		struct iattr *sattr, struct nfs4_label *label)
+ {
+ 	struct nfs4_createdata *data;
+ 	int status = -ENOMEM;
+@@ -3167,6 +3367,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
+ 	if (data == NULL)
+ 		goto out;
+ 
++	data->arg.label = label;
+ 	status = nfs4_do_create(dir, dentry, data);
+ 
+ 	nfs4_free_createdata(data);
+@@ -3178,14 +3379,19 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
+ 		struct iattr *sattr)
+ {
+ 	struct nfs4_exception exception = { };
++	struct nfs4_label l, *label = NULL;
+ 	int err;
+ 
++	label = nfs4_label_init_security(dir, dentry, sattr, &l);
++
+ 	sattr->ia_mode &= ~current_umask();
+ 	do {
+ 		err = nfs4_handle_exception(NFS_SERVER(dir),
+-				_nfs4_proc_mkdir(dir, dentry, sattr),
++				_nfs4_proc_mkdir(dir, dentry, sattr, label),
+ 				&exception);
+ 	} while (exception.retry);
++	nfs4_label_release_security(label);
++
+ 	return err;
+ }
+ 
+@@ -3201,7 +3407,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
+ 		.bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask,
+ 		.plus = plus,
+ 	};
+-	struct nfs4_readdir_res res;
++	struct nfs4_readdir_res res = {
++		.pgbase = 0,
++	};
+ 	struct rpc_message msg = {
+ 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR],
+ 		.rpc_argp = &args,
+@@ -3243,7 +3451,7 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
+ }
+ 
+ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
+-		struct iattr *sattr, dev_t rdev)
++		struct iattr *sattr, struct nfs4_label *label, dev_t rdev)
+ {
+ 	struct nfs4_createdata *data;
+ 	int mode = sattr->ia_mode;
+@@ -3268,7 +3476,8 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
+ 		status = -EINVAL;
+ 		goto out_free;
+ 	}
+-	
++
++	data->arg.label = label;	
+ 	status = nfs4_do_create(dir, dentry, data);
+ out_free:
+ 	nfs4_free_createdata(data);
+@@ -3280,14 +3489,20 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
+ 		struct iattr *sattr, dev_t rdev)
+ {
+ 	struct nfs4_exception exception = { };
++	struct nfs4_label l, *label = NULL;
+ 	int err;
+ 
++	label = nfs4_label_init_security(dir, dentry, sattr, &l);
++
+ 	sattr->ia_mode &= ~current_umask();
+ 	do {
+ 		err = nfs4_handle_exception(NFS_SERVER(dir),
+-				_nfs4_proc_mknod(dir, dentry, sattr, rdev),
++				_nfs4_proc_mknod(dir, dentry, sattr, label, rdev),
+ 				&exception);
+ 	} while (exception.retry);
++
++	nfs4_label_release_security(label);
++
+ 	return err;
+ }
+ 
+@@ -3503,7 +3718,11 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
+ 		data->args.bitmask = NULL;
+ 		data->res.fattr = NULL;
+ 	} else
++#ifdef CONFIG_NFS_V4_SECURITY_LABEL
++		data->args.bitmask = server->cache_consistency_bitmask_nl;
++#else
+ 		data->args.bitmask = server->cache_consistency_bitmask;
++#endif
+ 
+ 	if (!data->write_done_cb)
+ 		data->write_done_cb = nfs4_write_done_cb;
+@@ -3928,6 +4147,178 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
+ 	return err;
+ }
+ 
++#ifdef CONFIG_NFS_V4_SECURITY_LABEL
++static int _nfs4_get_security_label(struct inode *inode, void *buf,
++					size_t buflen)
++{
++	struct nfs_server *server = NFS_SERVER(inode);
++	struct nfs_fattr fattr;
++	struct nfs4_label label = {0, 0, buflen, buf};
++	u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
++	struct nfs4_getattr_arg args = {
++		.fh		= NFS_FH(inode),
++		.bitmask	= bitmask,
++	};
++	struct nfs4_getattr_res res = {
++		.fattr		= &fattr,
++		.label		= &label,
++		.server		= server,
++	};
++	struct rpc_message msg = {
++		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
++		.rpc_argp	= &args,
++		.rpc_resp	= &res,
++	};
++	int ret;
++
++	nfs_fattr_init(&fattr);
++
++	ret = rpc_call_sync(server->client, &msg, 0);
++	if (ret)
++		return ret;
++	if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL))
++		return -ENOENT;
++	if (buflen < label.len)
++		return -ERANGE;
++	return 0;
++}
++
++static int nfs4_get_security_label(struct inode *inode, void *buf,
++					size_t buflen)
++{
++	struct nfs4_exception exception = { };
++	int err;
++
++	if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
++		return -EOPNOTSUPP;
++
++	do {
++		err = nfs4_handle_exception(NFS_SERVER(inode),
++				_nfs4_get_security_label(inode, buf, buflen),
++				&exception);
++	} while (exception.retry);
++	return err;
++}
++
++static int _nfs4_do_set_security_label(struct inode *inode,
++		struct nfs4_label *ilabel,
++		struct nfs_fattr *fattr,
++		struct nfs4_label *olabel,
++		struct nfs4_state *state)
++{
++
++	struct iattr sattr = {0};
++	struct nfs_server *server = NFS_SERVER(inode);
++	const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
++	struct nfs_setattrargs args = {
++		.fh             = NFS_FH(inode),
++		.iap            = &sattr,
++		.server		= server,
++		.bitmask	= bitmask,
++		.label		= ilabel,
++	};
++	struct nfs_setattrres res = {
++		.fattr		= fattr,
++		.label		= olabel,
++		.server		= server,
++	};
++	struct rpc_message msg = {
++		.rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
++		.rpc_argp       = &args,
++		.rpc_resp       = &res,
++	};
++	unsigned long timestamp = jiffies;
++	int status;
++
++	if (state != NULL) {
++		struct nfs_lockowner lockowner = {
++			.l_owner = current->files,
++			.l_pid = current->tgid,
++		};
++
++		msg.rpc_cred = state->owner->so_cred;
++		nfs4_select_rw_stateid(&args.stateid, state, FMODE_WRITE,
++				&lockowner);
++	} else if (nfs4_copy_delegation_stateid(&args.stateid, inode,
++				FMODE_WRITE)) {
++		/* Use that stateid */
++	} else
++		nfs4_stateid_copy(&args.stateid, &zero_stateid);
++
++	status = rpc_call_sync(server->client, &msg, 0);
++	if (status == 0 && state != NULL)
++		renew_lease(server, timestamp);
++	return status;
++}
++
++static int nfs4_do_set_security_label(struct inode *inode,
++		struct nfs4_label *ilabel,
++		struct nfs_fattr *fattr,
++		struct nfs4_label *olabel,
++		struct nfs4_state *state)
++{
++	struct nfs4_exception exception = { };
++	int err;
++
++	do {
++		err = nfs4_handle_exception(NFS_SERVER(inode),
++				_nfs4_do_set_security_label(inode, ilabel,
++				fattr, olabel, state),
++				&exception);
++	} while (exception.retry);
++	return err;
++}
++
++static int
++nfs4_set_security_label(struct dentry *dentry, const void *buf, size_t buflen)
++{
++	struct nfs4_label ilabel, *olabel = NULL;
++	struct nfs_fattr fattr;
++	struct rpc_cred *cred;
++	struct nfs_open_context *ctx;
++	struct nfs4_state *state = NULL;
++	struct inode *inode = dentry->d_inode;
++	int status;
++
++	if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
++		return -EOPNOTSUPP;
++
++	nfs_fattr_init(&fattr);
++
++	ilabel.pi = 0;
++	ilabel.lfs = 0;
++	ilabel.label = (char *)buf;
++	ilabel.len = buflen;
++
++	cred = rpc_lookup_cred();
++	if (IS_ERR(cred))
++		return PTR_ERR(cred);
++
++	olabel = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
++	if (IS_ERR(olabel)) {
++		status = -PTR_ERR(olabel);
++		goto out;
++	}
++
++	/* Search for an existing open(O_WRITE) file */
++	ctx = nfs_find_open_context(inode, cred, FMODE_WRITE);
++	if (ctx != NULL)
++		state = ctx->state;
++
++	status = nfs4_do_set_security_label(inode, &ilabel, &fattr, olabel,
++						state);
++	if (status == 0)
++		nfs_setsecurity(inode, &fattr, olabel);
++	if (ctx != NULL)
++		put_nfs_open_context(ctx);
++	nfs4_label_free(olabel);
++out:
++	put_rpccred(cred);
++	return status;
++}
++#endif	/* CONFIG_NFS_V4_SECURITY_LABEL */
++
++
+ static int
+ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state)
+ {
+@@ -4216,7 +4607,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
+ 	nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+ 	data->args.fhandle = &data->fh;
+ 	data->args.stateid = &data->stateid;
+-	data->args.bitmask = server->cache_consistency_bitmask;
++	data->args.bitmask = server->cache_consistency_bitmask_nl;
+ 	nfs_copy_fh(&data->fh, NFS_FH(inode));
+ 	nfs4_stateid_copy(&data->stateid, stateid);
+ 	data->res.fattr = &data->fattr;
+@@ -4240,7 +4631,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
+ 	if (status == 0)
+ 		nfs_post_op_update_inode_force_wcc(inode, &data->fattr);
+ 	else
+-		nfs_refresh_inode(inode, &data->fattr);
++		nfs_refresh_inode(inode, &data->fattr, NULL);
+ out:
+ 	rpc_put_task(task);
+ 	return status;
+@@ -5059,6 +5450,53 @@ static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list,
+ 	return len;
+ }
+ 
++#ifdef CONFIG_NFS_V4_SECURITY_LABEL
++static inline int nfs4_server_supports_labels(struct nfs_server *server)
++{
++	return server->caps & NFS_CAP_SECURITY_LABEL;
++}
++
++static int nfs4_xattr_set_nfs4_label(struct dentry *dentry, const char *key,
++				   const void *buf, size_t buflen,
++				   int flags, int type)
++{
++	if (security_ismaclabel(key))
++		return nfs4_set_security_label(dentry, buf, buflen);
++
++	return -EOPNOTSUPP;
++}
++
++static int nfs4_xattr_get_nfs4_label(struct dentry *dentry, const char *key,
++				   void *buf, size_t buflen, int type)
++{
++	if (security_ismaclabel(key))
++		return nfs4_get_security_label(dentry->d_inode, buf, buflen);
++	return -EOPNOTSUPP;
++}
++
++static size_t nfs4_xattr_list_nfs4_label(struct dentry *dentry, char *list,
++				       size_t list_len, const char *name,
++				       size_t name_len, int type)
++{
++	size_t len = 0;
++
++	if (nfs_server_capable(dentry->d_inode, NFS_CAP_SECURITY_LABEL)) {
++		len = security_inode_listsecurity(dentry->d_inode, NULL, 0);
++		if (list && len <= list_len)
++			security_inode_listsecurity(dentry->d_inode, list, len);
++	}
++	return len;
++}
++
++static const struct xattr_handler nfs4_xattr_nfs4_label_handler = {
++	.prefix = XATTR_SECURITY_PREFIX,
++	.list	= nfs4_xattr_list_nfs4_label,
++	.get	= nfs4_xattr_get_nfs4_label,
++	.set	= nfs4_xattr_set_nfs4_label,
++};
++#endif
++
++
+ /*
+  * nfs_fhget will use either the mounted_on_fileid or the fileid
+  */
+@@ -5082,7 +5520,7 @@ static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
+ 				   struct page *page)
+ {
+ 	struct nfs_server *server = NFS_SERVER(dir);
+-	u32 bitmask[2] = {
++	u32 bitmask[3] = {
+ 		[0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
+ 	};
+ 	struct nfs4_fs_locations_arg args = {
+@@ -6797,6 +7235,9 @@ static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
+ 
+ const struct xattr_handler *nfs4_xattr_handlers[] = {
+ 	&nfs4_xattr_nfs4_acl_handler,
++#ifdef CONFIG_NFS_V4_SECURITY_LABEL
++	&nfs4_xattr_nfs4_label_handler,
++#endif
+ 	NULL
+ };
+ 
+diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
+index 26b1439..47452a8 100644
+--- a/fs/nfs/nfs4xdr.c
++++ b/fs/nfs/nfs4xdr.c
+@@ -102,12 +102,23 @@ static int nfs4_stat_to_errno(int);
+ #define nfs4_path_maxsz		(1 + ((3 + NFS4_MAXPATHLEN) >> 2))
+ #define nfs4_owner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
+ #define nfs4_group_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
++#ifdef CONFIG_NFS_V4_SECURITY_LABEL
++/* PI(4 bytes) + LFS(4 bytes) + 1(for null terminator?) + MAXLABELLEN */
++#define	nfs4_label_maxsz	(4 + 4 + 1 + XDR_QUADLEN(NFS4_MAXLABELLEN))
++#define encode_readdir_space 24
++#define encode_readdir_bitmask_sz 3
++#else
++#define	nfs4_label_maxsz	0
++#define encode_readdir_space 20
++#define encode_readdir_bitmask_sz 2
++#endif
+ /* We support only one layout type per file system */
+ #define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8)
+ /* This is based on getfattr, which uses the most attributes: */
+ #define nfs4_fattr_value_maxsz	(1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \
+ 				3 + 3 + 3 + nfs4_owner_maxsz + \
+-				nfs4_group_maxsz + decode_mdsthreshold_maxsz))
++				nfs4_group_maxsz + nfs4_label_maxsz + \
++				 decode_mdsthreshold_maxsz))
+ #define nfs4_fattr_maxsz	(nfs4_fattr_bitmap_maxsz + \
+ 				nfs4_fattr_value_maxsz)
+ #define decode_getattr_maxsz    (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
+@@ -115,6 +126,7 @@ static int nfs4_stat_to_errno(int);
+ 				 1 + 2 + 1 + \
+ 				nfs4_owner_maxsz + \
+ 				nfs4_group_maxsz + \
++				nfs4_label_maxsz + \
+ 				4 + 4)
+ #define encode_savefh_maxsz     (op_encode_hdr_maxsz)
+ #define decode_savefh_maxsz     (op_decode_hdr_maxsz)
+@@ -192,9 +204,11 @@ static int nfs4_stat_to_errno(int);
+ 				 encode_stateid_maxsz + 3)
+ #define decode_read_maxsz	(op_decode_hdr_maxsz + 2)
+ #define encode_readdir_maxsz	(op_encode_hdr_maxsz + \
+-				 2 + encode_verifier_maxsz + 5)
++				 2 + encode_verifier_maxsz + 5 + \
++				nfs4_label_maxsz)
+ #define decode_readdir_maxsz	(op_decode_hdr_maxsz + \
+-				 decode_verifier_maxsz)
++				 decode_verifier_maxsz + \
++				nfs4_label_maxsz + nfs4_fattr_maxsz)
+ #define encode_readlink_maxsz	(op_encode_hdr_maxsz)
+ #define decode_readlink_maxsz	(op_decode_hdr_maxsz + 1)
+ #define encode_write_maxsz	(op_encode_hdr_maxsz + \
+@@ -972,7 +986,9 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve
+ 	encode_opaque_fixed(xdr, verf->data, NFS4_VERIFIER_SIZE);
+ }
+ 
+-static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
++static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
++				const struct nfs4_label *label,
++				const struct nfs_server *server)
+ {
+ 	char owner_name[IDMAP_NAMESZ];
+ 	char owner_group[IDMAP_NAMESZ];
+@@ -983,15 +999,16 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
+ 	int len;
+ 	uint32_t bmval0 = 0;
+ 	uint32_t bmval1 = 0;
++	uint32_t bmval2 = 0;
+ 
+ 	/*
+ 	 * We reserve enough space to write the entire attribute buffer at once.
+ 	 * In the worst-case, this would be
+-	 *   12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
+-	 *          = 36 bytes, plus any contribution from variable-length fields
++	 * 16(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
++	 * = 40 bytes, plus any contribution from variable-length fields
+ 	 *            such as owner/group.
+ 	 */
+-	len = 16;
++	len = 20;
+ 
+ 	/* Sigh */
+ 	if (iap->ia_valid & ATTR_SIZE)
+@@ -1021,6 +1038,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
+ 		}
+ 		len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
+ 	}
++	if (label)
++		len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
+ 	if (iap->ia_valid & ATTR_ATIME_SET)
+ 		len += 16;
+ 	else if (iap->ia_valid & ATTR_ATIME)
+@@ -1035,9 +1054,9 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
+ 	 * We write the bitmap length now, but leave the bitmap and the attribute
+ 	 * buffer length to be backfilled at the end of this routine.
+ 	 */
+-	*p++ = cpu_to_be32(2);
++	*p++ = cpu_to_be32(3);
+ 	q = p;
+-	p += 3;
++	p += 4;
+ 
+ 	if (iap->ia_valid & ATTR_SIZE) {
+ 		bmval0 |= FATTR4_WORD0_SIZE;
+@@ -1077,6 +1096,13 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
+ 		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
+ 		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
+ 	}
++	if (label) {
++		bmval2 |= FATTR4_WORD2_SECURITY_LABEL;
++		*p++ = cpu_to_be32(label->lfs);
++		*p++ = cpu_to_be32(label->pi);
++		*p++ = cpu_to_be32(label->len);
++		p = xdr_encode_opaque_fixed(p, label->label, label->len);
++	}
+ 
+ 	/*
+ 	 * Now we backfill the bitmap and the attribute buffer length.
+@@ -1086,9 +1112,10 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
+ 				len, ((char *)p - (char *)q) + 4);
+ 		BUG();
+ 	}
+-	len = (char *)p - (char *)q - 12;
++	len = (char *)p - (char *)q - 16;
+ 	*q++ = htonl(bmval0);
+ 	*q++ = htonl(bmval1);
++	*q++ = htonl(bmval2);
+ 	*q = htonl(len);
+ 
+ /* out: */
+@@ -1142,7 +1169,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
+ 	}
+ 
+ 	encode_string(xdr, create->name->len, create->name->name);
+-	encode_attrs(xdr, create->attrs, create->server);
++	encode_attrs(xdr, create->attrs, create->label, create->server);
+ }
+ 
+ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
+@@ -1194,8 +1221,10 @@ encode_getattr_three(struct xdr_stream *xdr,
+ 
+ static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
+ {
+-	encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
+-			   bitmask[1] & nfs4_fattr_bitmap[1], hdr);
++	encode_getattr_three(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
++			   bitmask[1] & nfs4_fattr_bitmap[1],
++			   bitmask[2] & nfs4_fattr_bitmap[2],
++			   hdr);
+ }
+ 
+ static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask,
+@@ -1373,21 +1402,23 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
+ 	switch(arg->open_flags & O_EXCL) {
+ 	case 0:
+ 		*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
+-		encode_attrs(xdr, arg->u.attrs, arg->server);
++		encode_attrs(xdr, arg->u.attrs, arg->label, arg->server);
+ 		break;
+ 	default:
+ 		clp = arg->server->nfs_client;
+ 		if (clp->cl_mvops->minor_version > 0) {
+ 			if (nfs4_has_persistent_session(clp)) {
+ 				*p = cpu_to_be32(NFS4_CREATE_GUARDED);
+-				encode_attrs(xdr, arg->u.attrs, arg->server);
++				encode_attrs(xdr, arg->u.attrs, arg->label,
++						arg->server);
+ 			} else {
+ 				struct iattr dummy;
+ 
+ 				*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
+ 				encode_nfs4_verifier(xdr, &arg->u.verifier);
+ 				dummy.ia_valid = 0;
+-				encode_attrs(xdr, &dummy, arg->server);
++				encode_attrs(xdr, &dummy, arg->label,
++						arg->server);
+ 			}
+ 		} else {
+ 			*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
+@@ -1566,20 +1597,34 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
+ 	encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr);
+ 	encode_uint64(xdr, readdir->cookie);
+ 	encode_nfs4_verifier(xdr, &readdir->verifier);
+-	p = reserve_space(xdr, 20);
++	p = reserve_space(xdr, encode_readdir_space);
+ 	*p++ = cpu_to_be32(dircount);
+ 	*p++ = cpu_to_be32(readdir->count);
+-	*p++ = cpu_to_be32(2);
+-
++	*p++ = cpu_to_be32(encode_readdir_bitmask_sz);
+ 	*p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
+-	*p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
++	*p   = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
++	if (encode_readdir_bitmask_sz > 2) {
++		p++, *p++ = cpu_to_be32(readdir->bitmask[2]);
++	}
+ 	memcpy(verf, readdir->verifier.data, sizeof(verf));
+-	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
++
++#ifdef CONFIG_NFS_V4_SECURITY_LABEL
++	dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x:%08x\n",
++			__func__,
++			(unsigned long long)readdir->cookie,
++			verf[0], verf[1],
++			attrs[0] & readdir->bitmask[0],
++			attrs[1] & readdir->bitmask[1],
++			readdir->bitmask[2]);
++#else
++	dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
+ 			__func__,
+ 			(unsigned long long)readdir->cookie,
+ 			verf[0], verf[1],
+ 			attrs[0] & readdir->bitmask[0],
+ 			attrs[1] & readdir->bitmask[1]);
++#endif
++
+ }
+ 
+ static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
+@@ -1638,7 +1683,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
+ {
+ 	encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
+ 	encode_nfs4_stateid(xdr, &arg->stateid);
+-	encode_attrs(xdr, arg->iap, server);
++	encode_attrs(xdr, arg->iap, arg->label, server);
+ }
+ 
+ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
+@@ -4056,6 +4101,60 @@ static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
+ 	return status;
+ }
+ 
++static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap,
++					struct nfs4_label *label)
++{
++	uint32_t pi = 0;
++	uint32_t lfs = 0;
++	__u32 len;
++	__be32 *p;
++	int status = 0;
++
++	if (unlikely(bitmap[2] & (FATTR4_WORD2_SECURITY_LABEL - 1U)))
++		return -EIO;
++	if (likely(bitmap[2] & FATTR4_WORD2_SECURITY_LABEL)) {
++		p = xdr_inline_decode(xdr, 4);
++		if (unlikely(!p))
++			goto out_overflow;
++		lfs = be32_to_cpup(p++);
++		p = xdr_inline_decode(xdr, 4);
++		if (unlikely(!p))
++			goto out_overflow;
++		pi = be32_to_cpup(p++);
++		p = xdr_inline_decode(xdr, 4);
++		if (unlikely(!p))
++			goto out_overflow;
++		len = be32_to_cpup(p++);
++		p = xdr_inline_decode(xdr, len);
++		if (unlikely(!p))
++			goto out_overflow;
++		if (len < NFS4_MAXLABELLEN) {
++			if (label) {
++				memcpy(label->label, p, len);
++				label->len = len;
++				label->pi = pi;
++				label->lfs = lfs;
++				status = NFS_ATTR_FATTR_V4_SECURITY_LABEL;
++			} else {
++				printk("%s(): NULL label.\n", __func__);
++				dump_stack();
++				goto out_overflow;
++			}
++			bitmap[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
++		} else
++			printk(KERN_WARNING "%s: label too long (%u)!\n",
++					__func__, len);
++	}
++	if (label && label->label)
++		dprintk("%s: label=%s, len=%d, PI=%d, LFS=%d\n", __func__,
++			(char *)label->label, label->len, label->pi, label->lfs);
++	return status;
++
++out_overflow:
++	print_overflow_msg(__func__, xdr);
++	return -EIO;
++}
++
+ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
+ {
+ 	int status = 0;
+@@ -4398,7 +4497,7 @@ out_overflow:
+ 
+ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
+ 		struct nfs_fattr *fattr, struct nfs_fh *fh,
+-		struct nfs4_fs_locations *fs_loc,
++		struct nfs4_fs_locations *fs_loc, struct nfs4_label *label,
+ 		const struct nfs_server *server)
+ {
+ 	int status;
+@@ -4506,6 +4605,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
+ 	if (status < 0)
+ 		goto xdr_error;
+ 
++	status = decode_attr_security_label(xdr, bitmap, label);
++	if (status < 0)
++		goto xdr_error;
++	fattr->valid |= status;
++
+ xdr_error:
+ 	dprintk("%s: xdr returned %d\n", __func__, -status);
+ 	return status;
+@@ -4513,7 +4617,7 @@ xdr_error:
+ 
+ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
+ 		struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc,
+-		const struct nfs_server *server)
++		struct nfs4_label *label, const struct nfs_server *server)
+ {
+ 	unsigned int savep;
+ 	uint32_t attrlen,
+@@ -4532,7 +4636,8 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
+ 	if (status < 0)
+ 		goto xdr_error;
+ 
+-	status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, server);
++	status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc,
++					label, server);
+ 	if (status < 0)
+ 		goto xdr_error;
+ 
+@@ -4543,9 +4648,9 @@ xdr_error:
+ }
+ 
+ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
+-		const struct nfs_server *server)
++		struct nfs4_label *label, const struct nfs_server *server)
+ {
+-	return decode_getfattr_generic(xdr, fattr, NULL, NULL, server);
++	return decode_getfattr_generic(xdr, fattr, NULL, NULL, label, server);
+ }
+ 
+ /*
+@@ -5879,7 +5984,7 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
+ 	status = decode_open_downgrade(xdr, res);
+ 	if (status != 0)
+ 		goto out;
+-	decode_getfattr(xdr, res->fattr, res->server);
++	decode_getfattr(xdr, res->fattr, res->label, res->server);
+ out:
+ 	return status;
+ }
+@@ -5905,7 +6010,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+ 	status = decode_access(xdr, &res->supported, &res->access);
+ 	if (status != 0)
+ 		goto out;
+-	decode_getfattr(xdr, res->fattr, res->server);
++	decode_getfattr(xdr, res->fattr, res->label, res->server);
+ out:
+ 	return status;
+ }
+@@ -5934,7 +6039,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+ 	status = decode_getfh(xdr, res->fh);
+ 	if (status)
+ 		goto out;
+-	status = decode_getfattr(xdr, res->fattr, res->server);
++	status = decode_getfattr(xdr, res->fattr, res->label, res->server);
+ out:
+ 	return status;
+ }
+@@ -5960,7 +6065,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
+ 		goto out;
+ 	status = decode_getfh(xdr, res->fh);
+ 	if (status == 0)
+-		status = decode_getfattr(xdr, res->fattr, res->server);
++		status = decode_getfattr(xdr, res->fattr,
++						res->label, res->server);
+ out:
+ 	return status;
+ }
+@@ -6051,7 +6157,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+ 	status = decode_restorefh(xdr);
+ 	if (status)
+ 		goto out;
+-	decode_getfattr(xdr, res->fattr, res->server);
++	decode_getfattr(xdr, res->fattr, res->label, res->server);
+ out:
+ 	return status;
+ }
+@@ -6080,7 +6186,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+ 	status = decode_getfh(xdr, res->fh);
+ 	if (status)
+ 		goto out;
+-	decode_getfattr(xdr, res->fattr, res->server);
++	decode_getfattr(xdr, res->fattr, res->label, res->server);
+ out:
+ 	return status;
+ }
+@@ -6112,7 +6218,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+ 	status = decode_putfh(xdr);
+ 	if (status)
+ 		goto out;
+-	status = decode_getfattr(xdr, res->fattr, res->server);
++	status = decode_getfattr(xdr, res->fattr, res->label, res->server);
+ out:
+ 	return status;
+ }
+@@ -6214,7 +6320,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+ 	 * 	an ESTALE error. Shouldn't be a problem,
+ 	 * 	though, since fattr->valid will remain unset.
+ 	 */
+-	decode_getfattr(xdr, res->fattr, res->server);
++	decode_getfattr(xdr, res->fattr, res->label, res->server);
+ out:
+ 	return status;
+ }
+@@ -6245,7 +6351,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+ 		goto out;
+ 	if (res->access_request)
+ 		decode_access(xdr, &res->access_supported, &res->access_result);
+-	decode_getfattr(xdr, res->f_attr, res->server);
++	decode_getfattr(xdr, res->f_attr, res->f_label, res->server);
+ out:
+ 	return status;
+ }
+@@ -6295,7 +6401,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
+ 		goto out;
+ 	if (res->access_request)
+ 		decode_access(xdr, &res->access_supported, &res->access_result);
+-	decode_getfattr(xdr, res->f_attr, res->server);
++	decode_getfattr(xdr, res->f_attr, NULL, res->server);
+ out:
+ 	return status;
+ }
+@@ -6322,7 +6428,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
+ 	status = decode_setattr(xdr);
+ 	if (status)
+ 		goto out;
+-	decode_getfattr(xdr, res->fattr, res->server);
++	decode_getfattr(xdr, res->fattr, res->label, res->server);
+ out:
+ 	return status;
+ }
+@@ -6502,7 +6608,7 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
+ 	if (status)
+ 		goto out;
+ 	if (res->fattr)
+-		decode_getfattr(xdr, res->fattr, res->server);
++		decode_getfattr(xdr, res->fattr, NULL, res->server);
+ 	if (!status)
+ 		status = res->count;
+ out:
+@@ -6683,7 +6789,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
+ 	status = decode_putfh(xdr);
+ 	if (status != 0)
+ 		goto out;
+-	status = decode_getfattr(xdr, res->fattr, res->server);
++	status = decode_getfattr(xdr, res->fattr, res->label, res->server);
+ 	if (status != 0)
+ 		goto out;
+ 	status = decode_delegreturn(xdr);
+@@ -6716,7 +6822,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
+ 	xdr_enter_page(xdr, PAGE_SIZE);
+ 	status = decode_getfattr_generic(xdr, &res->fs_locations->fattr,
+ 					 NULL, res->fs_locations,
+-					 res->fs_locations->server);
++					 NULL, res->fs_locations->server);
+ out:
+ 	return status;
+ }
+@@ -6997,7 +7103,7 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
+ 	status = decode_layoutcommit(xdr, rqstp, res);
+ 	if (status)
+ 		goto out;
+-	decode_getfattr(xdr, res->fattr, res->server);
++	decode_getfattr(xdr, res->fattr, NULL, res->server);
+ out:
+ 	return status;
+ }
+@@ -7129,7 +7235,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
+ 		goto out_overflow;
+ 
+ 	if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
+-				  NULL, entry->server) < 0)
++			NULL, entry->label, entry->server) < 0)
+ 		goto out_overflow;
+ 	if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
+ 		entry->ino = entry->fattr->mounted_on_fileid;
+diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
+index f084dac..0ee882e 100644
+--- a/fs/nfs/proc.c
++++ b/fs/nfs/proc.c
+@@ -98,7 +98,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+  */
+ static int
+ nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+-		struct nfs_fattr *fattr)
++		struct nfs_fattr *fattr, struct nfs4_label *label)
+ {
+ 	struct rpc_message msg = {
+ 		.rpc_proc	= &nfs_procedures[NFSPROC_GETATTR],
+@@ -146,7 +146,8 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+ 
+ static int
+ nfs_proc_lookup(struct inode *dir, struct qstr *name,
+-		struct nfs_fh *fhandle, struct nfs_fattr *fattr)
++		struct nfs_fh *fhandle, struct nfs_fattr *fattr,
++		struct nfs4_label *label)
+ {
+ 	struct nfs_diropargs	arg = {
+ 		.fh		= NFS_FH(dir),
+@@ -243,7 +244,7 @@ nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
+ 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ 	nfs_mark_for_revalidate(dir);
+ 	if (status == 0)
+-		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
++		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
+ 	nfs_free_createdata(data);
+ out:
+ 	dprintk("NFS reply create: %d\n", status);
+@@ -290,7 +291,7 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
+ 		status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ 	}
+ 	if (status == 0)
+-		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
++		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
+ 	nfs_free_createdata(data);
+ out:
+ 	dprintk("NFS reply mknod: %d\n", status);
+@@ -442,7 +443,7 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
+ 	 * should fill in the data with a LOOKUP call on the wire.
+ 	 */
+ 	if (status == 0)
+-		status = nfs_instantiate(dentry, fh, fattr);
++		status = nfs_instantiate(dentry, fh, fattr, NULL);
+ 
+ out_free:
+ 	nfs_free_fattr(fattr);
+@@ -471,7 +472,7 @@ nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
+ 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ 	nfs_mark_for_revalidate(dir);
+ 	if (status == 0)
+-		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
++		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
+ 	nfs_free_createdata(data);
+ out:
+ 	dprintk("NFS reply mkdir: %d\n", status);
+@@ -607,7 +608,7 @@ static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
+ 
+ 	nfs_invalidate_atime(inode);
+ 	if (task->tk_status >= 0) {
+-		nfs_refresh_inode(inode, data->res.fattr);
++		nfs_refresh_inode(inode, data->res.fattr, data->res.label);
+ 		/* Emulate the eof flag, which isn't normally needed in NFSv2
+ 		 * as it is guaranteed to always return the file attributes
+ 		 */
+diff --git a/fs/nfs/super.c b/fs/nfs/super.c
+index b056b16..4e78f93 100644
+--- a/fs/nfs/super.c
++++ b/fs/nfs/super.c
+@@ -877,6 +877,7 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root)
+ 		seq_printf(m, "\n\tnfsv4:\t");
+ 		seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
+ 		seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
++		seq_printf(m, ",bm2=0x%x", nfss->attr_bitmask[2]);
+ 		seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
+ 		show_sessions(m, nfss);
+ 		show_pnfs(m, nfss);
+@@ -2418,7 +2419,21 @@ static int nfs_bdi_register(struct nfs_server *server)
+ int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot,
+ 			struct nfs_mount_info *mount_info)
+ {
+-	return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts);
++	int error;
++	unsigned long kflags = 0, kflags_out = 0;
++	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
++		kflags |= SECURITY_LSM_NATIVE_LABELS;
++
++	error = security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts,
++						kflags, &kflags_out);
++	if (error)
++		goto err;
++
++	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
++		!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
++		NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
++err:
++	return error;
+ }
+ EXPORT_SYMBOL_GPL(nfs_set_sb_security);
+ 
+diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
+index 8df1ea4..a569dc1 100644
+--- a/fs/nfsd/Kconfig
++++ b/fs/nfsd/Kconfig
+@@ -81,6 +81,22 @@ config NFSD_V4
+ 
+ 	  If unsure, say N.
+ 
++config NFSD_V4_SECURITY_LABEL
++	bool "Provide Security Label support for NFSv4 server"
++	depends on NFSD_V4 && SECURITY
++	help
++
++	Say Y here if you want enable fine-grained security label attribute
++	support for NFS version 4.  Security labels allow security modules like
++	SELinux and Smack to label files to facilitate enforcement of their policies.
++	Without this an NFSv4 mount will have the same label on each file.
++
++	If you do not wish to enable fine-grained security labels SELinux or
++	Smack policies on NFSv4 files, say N.
++
++	WARNING: there is still a chance of backwards-incompatible protocol changes.  
++	For now we recommend "Y" only for developers and testers."
++
+ config NFSD_FAULT_INJECTION
+ 	bool "NFS server manual fault injection"
+ 	depends on NFSD_V4 && DEBUG_KERNEL
+diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
+index 9d1c5db..898092d 100644
+--- a/fs/nfsd/nfs4proc.c
++++ b/fs/nfsd/nfs4proc.c
+@@ -42,6 +42,36 @@
+ #include "current_stateid.h"
+ #include "netns.h"
+ 
++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
++#include <linux/security.h>
++
++static inline void
++nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct nfs4_label *label, u32 *bmval)
++{
++	struct inode *inode = resfh->fh_dentry->d_inode;
++	int status;
++
++	mutex_lock(&inode->i_mutex);
++	status = security_inode_setsecctx(resfh->fh_dentry,
++		label->label, label->len);
++	mutex_unlock(&inode->i_mutex);
++
++	if (status)
++		/*
++		 * We should probably fail the whole open at this point,
++		 * but we've already created or opened the file, so it's 
++		 * too late; So this seems the least of evils:
++		 */
++		bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
++		
++	return;
++}
++#else 
++static inline void 
++nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct nfs4_label *label, u32 *bmval)
++{ }
++#endif
++
+ #define NFSDDBG_FACILITY		NFSDDBG_PROC
+ 
+ static u32 nfsd_attrmask[] = {
+@@ -230,6 +260,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
+ 					(u32 *)open->op_verf.data,
+ 					&open->op_truncate, &open->op_created);
+ 
++		if (!status && open->op_label != NULL) 
++			nfsd4_security_inode_setsecctx(resfh, open->op_label, open->op_bmval);
++
+ 		/*
+ 		 * Following rfc 3530 14.2.16, use the returned bitmask
+ 		 * to indicate which attributes we used to store the
+@@ -599,6 +632,9 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ 	if (status)
+ 		goto out;
+ 
++	if (create->cr_label != NULL)
++		nfsd4_security_inode_setsecctx(&resfh, create->cr_label, create->cr_bmval);
++
+ 	if (create->cr_acl != NULL)
+ 		do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
+ 				create->cr_bmval);
+@@ -888,6 +924,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ 					    setattr->sa_acl);
+ 	if (status)
+ 		goto out;
++	if (setattr->sa_label != NULL)
++		status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh,
++				setattr->sa_label);
++	if (status)
++		goto out;
+ 	status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
+ 				0, (time_t)0);
+ out:
+diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
+index 0dc1158..d2ae8db 100644
+--- a/fs/nfsd/nfs4xdr.c
++++ b/fs/nfsd/nfs4xdr.c
+@@ -55,6 +55,11 @@
+ #include "cache.h"
+ #include "netns.h"
+ 
++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
++#include <linux/security.h>
++#endif
++
++
+ #define NFSDDBG_FACILITY		NFSDDBG_XDR
+ 
+ /*
+@@ -79,6 +84,24 @@ check_filename(char *str, int len)
+ 			return nfserr_badname;
+ 	return 0;
+ }
++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
++static struct nfs4_label *nfsd4_label_alloc(u32 len)
++{
++	struct nfs4_label *label = NULL;
++
++	if (len > NFS4_MAXLABELLEN)
++		return ERR_PTR(-ENAMETOOLONG);
++
++	label = kzalloc(len + sizeof(struct nfs4_label), GFP_KERNEL);
++	if (label == NULL)
++		return ERR_PTR(-ENOMEM);
++
++	label->label = (char *)(label + 1);
++	label->len = len;
++
++	return label;
++}
++#endif
+ 
+ #define DECODE_HEAD				\
+ 	__be32 *p;				\
+@@ -242,7 +265,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
+ 
+ static __be32
+ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
+-		   struct iattr *iattr, struct nfs4_acl **acl)
++		   struct iattr *iattr, struct nfs4_acl **acl,
++		   struct nfs4_label **label)
+ {
+ 	int expected_len, len = 0;
+ 	u32 dummy32;
+@@ -386,6 +410,38 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
+ 			goto xdr_error;
+ 		}
+ 	}
++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
++	if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
++		uint32_t pi;
++		uint32_t lfs;
++
++		READ_BUF(4);
++		len += 4;
++		READ32(lfs);
++		READ_BUF(4);
++		len += 4;
++		READ32(pi);
++		READ_BUF(4);
++		len += 4;
++		READ32(dummy32);
++		READ_BUF(dummy32);
++		len += (XDR_QUADLEN(dummy32) << 2);
++		READMEM(buf, dummy32);
++
++		*label = nfsd4_label_alloc(dummy32);
++		if (*label == NULL) {
++			host_err = PTR_ERR(label);
++			goto out_nfserr;
++		}
++
++		memcpy((*label)->label, buf, (*label)->len);
++		((char *)(*label)->label)[(*label)->len] = '\0';
++		(*label)->pi = pi;
++		(*label)->lfs = lfs;
++
++		defer_free(argp, kfree, *label);
++	}
++#endif
+ 	if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
+ 	    || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
+ 	    || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
+@@ -575,7 +631,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
+ 		return status;
+ 
+ 	status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
+-				    &create->cr_acl);
++				    &create->cr_acl, &create->cr_label);
+ 	if (status)
+ 		goto out;
+ 
+@@ -825,7 +881,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
+ 		case NFS4_CREATE_UNCHECKED:
+ 		case NFS4_CREATE_GUARDED:
+ 			status = nfsd4_decode_fattr(argp, open->op_bmval,
+-				&open->op_iattr, &open->op_acl);
++				&open->op_iattr, &open->op_acl, &open->op_label);
+ 			if (status)
+ 				goto out;
+ 			break;
+@@ -839,7 +895,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
+ 			READ_BUF(NFS4_VERIFIER_SIZE);
+ 			COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
+ 			status = nfsd4_decode_fattr(argp, open->op_bmval,
+-				&open->op_iattr, &open->op_acl);
++				&open->op_iattr, &open->op_acl, &open->op_label);
+ 			if (status)
+ 				goto out;
+ 			break;
+@@ -1061,7 +1117,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
+ 	if (status)
+ 		return status;
+ 	return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr,
+-				  &setattr->sa_acl);
++				  &setattr->sa_acl, &setattr->sa_label);
+ }
+ 
+ static __be32
+@@ -1970,6 +2026,50 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
+ 			      FATTR4_WORD0_RDATTR_ERROR)
+ #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
+ 
++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
++static inline __be32
++nfsd4_encode_security_label(struct svc_rqst *rqstp, struct dentry *dentry, __be32 **pp, int *buflen)
++{
++	void *context;
++	int err;
++	int len;
++	uint32_t pi = 0;
++	uint32_t lfs = 0;
++	__be32 *p = *pp;
++
++	err = 0;
++	(void)security_inode_getsecctx(dentry->d_inode, &context, &len);
++	if (len < 0)
++		return nfserrno(len);
++
++	if (*buflen < ((XDR_QUADLEN(len) << 2) + 4 + 4 + 4)) {
++		err = nfserr_resource;
++		goto out;
++	}
++
++	/* XXX: A call to the translation code should be placed here
++	 * for now send 0  until we have that to indicate the null
++	 * translation */ 
++
++	if ((*buflen -= 4) < 0)
++		return nfserr_resource;
++
++	WRITE32(lfs);	
++	WRITE32(pi);
++	p = xdr_encode_opaque(p, context, len);
++	*buflen -= (XDR_QUADLEN(len) << 2) + 4;
++
++	*pp = p;
++out:
++	security_release_secctx(context, len);
++	return err;
++}
++#else
++static inline __be32
++nfsd4_encode_security_label(struct svc_rqst *rqstp, struct dentry *dentry, __be32 **pp, int *buflen)
++{ return 0; }
++#endif
++
+ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
+ {
+ 	/* As per referral draft:  */
+@@ -2423,6 +2523,12 @@ out_acl:
+ 			get_parent_attributes(exp, &stat);
+ 		WRITE64(stat.ino);
+ 	}
++	if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
++		status = nfsd4_encode_security_label(rqstp, dentry,
++				&p, &buflen);
++		if (status)
++			goto out;
++	}
+ 	if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
+ 		WRITE32(3);
+ 		WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0);
+diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
+index de23db2..26a457b 100644
+--- a/fs/nfsd/nfsd.h
++++ b/fs/nfsd/nfsd.h
+@@ -311,7 +311,11 @@ void		nfsd_lockd_shutdown(void);
+  | FATTR4_WORD1_TIME_DELTA   | FATTR4_WORD1_TIME_METADATA    \
+  | FATTR4_WORD1_TIME_MODIFY     | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
+ 
++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
++#define NFSD4_SUPPORTED_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL
++#else
+ #define NFSD4_SUPPORTED_ATTRS_WORD2 0
++#endif
+ 
+ #define NFSD4_1_SUPPORTED_ATTRS_WORD0 \
+ 	NFSD4_SUPPORTED_ATTRS_WORD0
+@@ -350,7 +354,7 @@ static inline u32 nfsd_suppattrs2(u32 minorversion)
+ #define NFSD_WRITEABLE_ATTRS_WORD1 \
+ 	(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
+ 	| FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
+-#define NFSD_WRITEABLE_ATTRS_WORD2 0
++#define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL
+ 
+ #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
+ 	NFSD_WRITEABLE_ATTRS_WORD0
+diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
+index d586117..0d290c5 100644
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -28,6 +28,7 @@
+ #include <asm/uaccess.h>
+ #include <linux/exportfs.h>
+ #include <linux/writeback.h>
++#include <linux/security.h>
+ 
+ #ifdef CONFIG_NFSD_V3
+ #include "xdr3.h"
+@@ -621,6 +622,34 @@ int nfsd4_is_junction(struct dentry *dentry)
+ 		return 0;
+ 	return 1;
+ }
++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
++__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
++		struct nfs4_label *label)
++{
++	__be32 error;
++	int host_error;
++	struct dentry *dentry;
++
++	/* XXX: should we have a MAY_SSECCTX? */
++	error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
++	if (error)
++		return error;
++
++	dentry = fhp->fh_dentry;
++
++	mutex_lock(&dentry->d_inode->i_mutex);
++	host_error = security_inode_setsecctx(dentry, label->label, label->len);
++	mutex_unlock(&dentry->d_inode->i_mutex);
++	return nfserrno(host_error);
++}
++#else
++__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
++		struct nfs4_label *label)
++{
++	return -EOPNOTSUPP;
++}
++#endif
++
+ #endif /* defined(CONFIG_NFSD_V4) */
+ 
+ #ifdef CONFIG_NFSD_V3
+diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
+index 359594c..49c6cc0 100644
+--- a/fs/nfsd/vfs.h
++++ b/fs/nfsd/vfs.h
+@@ -55,6 +55,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *);
+ __be32          nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
+                     struct nfs4_acl *);
+ int             nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
++__be32          nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
++		    struct nfs4_label *);
+ #endif /* CONFIG_NFSD_V4 */
+ __be32		nfsd_create(struct svc_rqst *, struct svc_fh *,
+ 				char *name, int len, struct iattr *attrs,
+diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
+index 0889bfb..9e7e663 100644
+--- a/fs/nfsd/xdr4.h
++++ b/fs/nfsd/xdr4.h
+@@ -118,6 +118,7 @@ struct nfsd4_create {
+ 	struct iattr	cr_iattr;           /* request */
+ 	struct nfsd4_change_info  cr_cinfo; /* response */
+ 	struct nfs4_acl *cr_acl;
++	struct nfs4_label *cr_label;
+ };
+ #define cr_linklen	u.link.namelen
+ #define cr_linkname	u.link.name
+@@ -246,6 +247,7 @@ struct nfsd4_open {
+ 	struct nfs4_file *op_file;          /* used during processing */
+ 	struct nfs4_ol_stateid *op_stp;	    /* used during processing */
+ 	struct nfs4_acl *op_acl;
++	struct nfs4_label *op_label;
+ };
+ #define op_iattr	iattr
+ 
+@@ -330,6 +332,7 @@ struct nfsd4_setattr {
+ 	u32		sa_bmval[3];        /* request */
+ 	struct iattr	sa_iattr;           /* request */
+ 	struct nfs4_acl *sa_acl;
++	struct nfs4_label *sa_label;
+ };
+ 
+ struct nfsd4_setclientid {
+diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
+index e111fa4..aab8bd8 100644
+--- a/include/linux/nfs4.h
++++ b/include/linux/nfs4.h
+@@ -28,6 +28,13 @@ struct nfs4_acl {
+ 	struct nfs4_ace	aces[0];
+ };
+ 
++struct nfs4_label {
++	uint32_t	lfs;
++	uint32_t	pi;
++	u32		len;
++	char	*label;
++};
++
+ typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
+ 
+ struct nfs_stateid4 {
+@@ -373,6 +380,7 @@ enum lock_type4 {
+ #define FATTR4_WORD1_MOUNTED_ON_FILEID  (1UL << 23)
+ #define FATTR4_WORD1_FS_LAYOUT_TYPES    (1UL << 30)
+ #define FATTR4_WORD2_LAYOUT_BLKSIZE     (1UL << 1)
++#define FATTR4_WORD2_SECURITY_LABEL     (1UL << 17)
+ #define FATTR4_WORD2_MDSTHRESHOLD       (1UL << 4)
+ 
+ /* MDS threshold bitmap bits */
+diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
+index 1cc2568..6de5336 100644
+--- a/include/linux/nfs_fs.h
++++ b/include/linux/nfs_fs.h
+@@ -199,6 +199,7 @@ struct nfs_inode {
+ #define NFS_INO_INVALID_ACL	0x0010		/* cached acls are invalid */
+ #define NFS_INO_REVAL_PAGECACHE	0x0020		/* must revalidate pagecache */
+ #define NFS_INO_REVAL_FORCED	0x0040		/* force revalidation ignoring a delegation */
++#define NFS_INO_INVALID_LABEL	0x0080		/* cached label is invalid */
+ 
+ /*
+  * Bit offsets in flags field
+@@ -328,9 +329,9 @@ extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping);
+ extern void nfs_zap_caches(struct inode *);
+ extern void nfs_invalidate_atime(struct inode *);
+ extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
+-				struct nfs_fattr *);
+-extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
+-extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
++				struct nfs_fattr *, struct nfs4_label *);
++extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *, struct nfs4_label *);
++extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *);
+ extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
+ extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+ extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
+@@ -344,6 +345,8 @@ extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
+ extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
+ extern int nfs_setattr(struct dentry *, struct iattr *);
+ extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
++extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
++				struct nfs4_label *label);
+ extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
+ extern void put_nfs_open_context(struct nfs_open_context *ctx);
+ extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode);
+@@ -460,7 +463,8 @@ extern const struct file_operations nfs_dir_operations;
+ extern const struct dentry_operations nfs_dentry_operations;
+ 
+ extern void nfs_force_lookup_revalidate(struct inode *dir);
+-extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr);
++extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh,
++			struct nfs_fattr *fattr, struct nfs4_label *label);
+ extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags);
+ extern void nfs_access_zap_cache(struct inode *inode);
+ 
+@@ -489,6 +493,24 @@ extern int nfs_mountpoint_expiry_timeout;
+ extern void nfs_release_automount_timer(void);
+ 
+ /*
++ * linux/fs/nfs/nfs4proc.c
++ */
++#ifdef CONFIG_NFS_V4_SECURITY_LABEL
++extern struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags);
++static inline void nfs4_label_free(struct nfs4_label *label)
++{
++	if (label) {
++		kfree(label->label);
++		kfree(label);
++	}
++	return;
++}
++#else
++static inline struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) { return NULL; }
++static inline void nfs4_label_free(void *label) {}
++#endif
++
++/*
+  * linux/fs/nfs/unlink.c
+  */
+ extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
+diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
+index 6c6ed15..2a4f1d4 100644
+--- a/include/linux/nfs_fs_sb.h
++++ b/include/linux/nfs_fs_sb.h
+@@ -145,11 +145,18 @@ struct nfs_server {
+ 	u32			attr_bitmask[3];/* V4 bitmask representing the set
+ 						   of attributes supported on this
+ 						   filesystem */
+-	u32			cache_consistency_bitmask[2];
++	u32			attr_bitmask_nl[3];
++						/* V4 bitmask representing the
++						   set of attributes supported
++						   on this filesystem excluding
++						   the label support bit. */
++	u32			cache_consistency_bitmask[3];
+ 						/* V4 bitmask representing the subset
+ 						   of change attribute, size, ctime
+ 						   and mtime attributes supported by
+ 						   the server */
++	u32			cache_consistency_bitmask_nl[3];
++						/* As above, excluding label. */
+ 	u32			acl_bitmask;	/* V4 bitmask representing the ACEs
+ 						   that are supported on this
+ 						   filesystem */
+@@ -197,5 +204,6 @@ struct nfs_server {
+ #define NFS_CAP_MTIME		(1U << 13)
+ #define NFS_CAP_POSIX_LOCK	(1U << 14)
+ #define NFS_CAP_UIDGID_NOMAP	(1U << 15)
++#define NFS_CAP_SECURITY_LABEL	(1U << 16)
+ 
+ #endif
+diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
+index 29adb12..9f5f599 100644
+--- a/include/linux/nfs_xdr.h
++++ b/include/linux/nfs_xdr.h
+@@ -104,6 +104,7 @@ struct nfs_fattr {
+ #define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22)
+ #define NFS_ATTR_FATTR_OWNER_NAME	(1U << 23)
+ #define NFS_ATTR_FATTR_GROUP_NAME	(1U << 24)
++#define NFS_ATTR_FATTR_V4_SECURITY_LABEL (1U << 25)
+ 
+ #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
+ 		| NFS_ATTR_FATTR_MODE \
+@@ -123,7 +124,8 @@ struct nfs_fattr {
+ #define NFS_ATTR_FATTR_V3 (NFS_ATTR_FATTR \
+ 		| NFS_ATTR_FATTR_SPACE_USED)
+ #define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
+-		| NFS_ATTR_FATTR_SPACE_USED)
++		| NFS_ATTR_FATTR_SPACE_USED \
++		| NFS_ATTR_FATTR_V4_SECURITY_LABEL)
+ 
+ /*
+  * Info on the file system
+@@ -348,6 +350,7 @@ struct nfs_openargs {
+ 	const u32 *		bitmask;
+ 	const u32 *		open_bitmap;
+ 	__u32			claim;
++	const struct nfs4_label *label;
+ };
+ 
+ struct nfs_openres {
+@@ -357,6 +360,7 @@ struct nfs_openres {
+ 	struct nfs4_change_info	cinfo;
+ 	__u32                   rflags;
+ 	struct nfs_fattr *      f_attr;
++	struct nfs4_label	*f_label;
+ 	struct nfs_seqid *	seqid;
+ 	const struct nfs_server *server;
+ 	fmode_t			delegation_type;
+@@ -401,6 +405,7 @@ struct nfs_closeres {
+ 	struct nfs4_sequence_res	seq_res;
+ 	nfs4_stateid            stateid;
+ 	struct nfs_fattr *	fattr;
++	struct nfs4_label	*label;
+ 	struct nfs_seqid *	seqid;
+ 	const struct nfs_server *server;
+ };
+@@ -474,6 +479,7 @@ struct nfs4_delegreturnargs {
+ struct nfs4_delegreturnres {
+ 	struct nfs4_sequence_res	seq_res;
+ 	struct nfs_fattr * fattr;
++	struct nfs4_label	*label;
+ 	const struct nfs_server *server;
+ };
+ 
+@@ -494,6 +500,7 @@ struct nfs_readargs {
+ struct nfs_readres {
+ 	struct nfs4_sequence_res	seq_res;
+ 	struct nfs_fattr *	fattr;
++	struct nfs4_label	*label;
+ 	__u32			count;
+ 	int                     eof;
+ };
+@@ -562,6 +569,7 @@ struct nfs_removeres {
+ 	struct nfs4_sequence_res 	seq_res;
+ 	const struct nfs_server *server;
+ 	struct nfs_fattr	*dir_attr;
++	struct nfs4_label	*dir_label;
+ 	struct nfs4_change_info	cinfo;
+ };
+ 
+@@ -574,6 +582,8 @@ struct nfs_renameargs {
+ 	const struct nfs_fh		*new_dir;
+ 	const struct qstr		*old_name;
+ 	const struct qstr		*new_name;
++	const struct nfs4_label		*old_label;
++	const struct nfs4_label		*new_label;
+ };
+ 
+ struct nfs_renameres {
+@@ -581,8 +591,10 @@ struct nfs_renameres {
+ 	const struct nfs_server		*server;
+ 	struct nfs4_change_info		old_cinfo;
+ 	struct nfs_fattr		*old_fattr;
++	struct nfs4_label		*old_label;
+ 	struct nfs4_change_info		new_cinfo;
+ 	struct nfs_fattr		*new_fattr;
++	struct nfs4_label		*new_label;
+ };
+ 
+ /*
+@@ -597,6 +609,7 @@ struct nfs_entry {
+ 	int			eof;
+ 	struct nfs_fh *		fh;
+ 	struct nfs_fattr *	fattr;
++	struct nfs4_label  *label;
+ 	unsigned char		d_type;
+ 	struct nfs_server *	server;
+ };
+@@ -629,6 +642,7 @@ struct nfs_setattrargs {
+ 	struct iattr *                  iap;
+ 	const struct nfs_server *	server; /* Needed for name mapping */
+ 	const u32 *			bitmask;
++	const struct nfs4_label		*label;
+ };
+ 
+ struct nfs_setaclargs {
+@@ -664,6 +678,7 @@ struct nfs_getaclres {
+ struct nfs_setattrres {
+ 	struct nfs4_sequence_res	seq_res;
+ 	struct nfs_fattr *              fattr;
++	struct nfs4_label		*label;
+ 	const struct nfs_server *	server;
+ };
+ 
+@@ -709,6 +724,7 @@ struct nfs3_setaclargs {
+ struct nfs_diropok {
+ 	struct nfs_fh *		fh;
+ 	struct nfs_fattr *	fattr;
++	struct nfs4_label	*label;
+ };
+ 
+ struct nfs_readlinkargs {
+@@ -839,6 +855,7 @@ struct nfs4_accessres {
+ 	struct nfs4_sequence_res	seq_res;
+ 	const struct nfs_server *	server;
+ 	struct nfs_fattr *		fattr;
++	struct nfs4_label		*label;
+ 	u32				supported;
+ 	u32				access;
+ };
+@@ -861,6 +878,7 @@ struct nfs4_create_arg {
+ 	const struct iattr *		attrs;
+ 	const struct nfs_fh *		dir_fh;
+ 	const u32 *			bitmask;
++	const struct nfs4_label		*label;
+ };
+ 
+ struct nfs4_create_res {
+@@ -868,6 +886,7 @@ struct nfs4_create_res {
+ 	const struct nfs_server *	server;
+ 	struct nfs_fh *			fh;
+ 	struct nfs_fattr *		fattr;
++	struct nfs4_label		*label;
+ 	struct nfs4_change_info		dir_cinfo;
+ };
+ 
+@@ -892,6 +911,7 @@ struct nfs4_getattr_res {
+ 	struct nfs4_sequence_res	seq_res;
+ 	const struct nfs_server *	server;
+ 	struct nfs_fattr *		fattr;
++	struct nfs4_label		*label;
+ };
+ 
+ struct nfs4_link_arg {
+@@ -906,8 +926,10 @@ struct nfs4_link_res {
+ 	struct nfs4_sequence_res	seq_res;
+ 	const struct nfs_server *	server;
+ 	struct nfs_fattr *		fattr;
++	struct nfs4_label		*label;
+ 	struct nfs4_change_info		cinfo;
+ 	struct nfs_fattr *		dir_attr;
++	struct nfs4_label		*dir_label;
+ };
+ 
+ 
+@@ -923,6 +945,7 @@ struct nfs4_lookup_res {
+ 	const struct nfs_server *	server;
+ 	struct nfs_fattr *		fattr;
+ 	struct nfs_fh *			fh;
++	struct nfs4_label		*label;
+ };
+ 
+ struct nfs4_lookup_root_arg {
+@@ -1376,11 +1399,12 @@ struct nfs_rpc_ops {
+ 	struct dentry *(*try_mount) (int, const char *, struct nfs_mount_info *,
+ 				     struct nfs_subversion *);
+ 	int	(*getattr) (struct nfs_server *, struct nfs_fh *,
+-			    struct nfs_fattr *);
++			    struct nfs_fattr *, struct nfs4_label *);
+ 	int	(*setattr) (struct dentry *, struct nfs_fattr *,
+ 			    struct iattr *);
+ 	int	(*lookup)  (struct inode *, struct qstr *,
+-			    struct nfs_fh *, struct nfs_fattr *);
++			    struct nfs_fh *, struct nfs_fattr *,
++			    struct nfs4_label *);
+ 	int	(*access)  (struct inode *, struct nfs_access_entry *);
+ 	int	(*readlink)(struct inode *, struct page *, unsigned int,
+ 			    unsigned int);
+diff --git a/include/linux/security.h b/include/linux/security.h
+index eee7478..9dc244e 100644
+--- a/include/linux/security.h
++++ b/include/linux/security.h
+@@ -26,6 +26,7 @@
+ #include <linux/capability.h>
+ #include <linux/slab.h>
+ #include <linux/err.h>
++#include <linux/string.h>
+ 
+ struct linux_binprm;
+ struct cred;
+@@ -60,6 +61,9 @@ struct mm_struct;
+ #define SECURITY_CAP_NOAUDIT 0
+ #define SECURITY_CAP_AUDIT 1
+ 
++/* LSM Agnostic defines for sb_set_mnt_opts */
++#define SECURITY_LSM_NATIVE_LABELS	1
++
+ struct ctl_table;
+ struct audit_krule;
+ struct user_namespace;
+@@ -306,6 +310,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
+  *	Parse a string of security data filling in the opts structure
+  *	@options string containing all mount options known by the LSM
+  *	@opts binary data structure usable by the LSM
++ * @dentry_init_security:
++ *	Compute a context for a dentry as the inode is not yet available
++ *	since NFSv4 has no label backed by an EA anyway.
++ *	@dentry dentry to use in calculating the context.
++ *	@mode mode used to determine resource type.
++ *	@name name of the last path component used to create file
++ *	@ctx pointer to place the pointer to the resulting context in.
++ *	@ctxlen point to place the length of the resulting context.
++ *
+  *
+  * Security hooks for inode operations.
+  *
+@@ -1309,6 +1322,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
+  *	@pages contains the number of pages.
+  *	Return 0 if permission is granted.
+  *
++ * @ismaclabel:
++ *	Check if the extended attribute specified by @name
++ *	represents a MAC label. Returns 0 if name is a MAC
++ *	attribute otherwise returns non-zero.
++ *	@name full extended attribute name to check against
++ *	LSM as a MAC label.
++ *
+  * @secid_to_secctx:
+  *	Convert secid to security context.  If secdata is NULL the length of
+  *	the result will be returned in seclen, but no secdata will be returned.
+@@ -1435,10 +1455,16 @@ struct security_operations {
+ 	int (*sb_pivotroot) (struct path *old_path,
+ 			     struct path *new_path);
+ 	int (*sb_set_mnt_opts) (struct super_block *sb,
+-				struct security_mnt_opts *opts);
++				struct security_mnt_opts *opts,
++				unsigned long kern_flags,
++				unsigned long *set_kern_flags);
+ 	void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
+ 				   struct super_block *newsb);
+ 	int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
++	int (*dentry_init_security) (struct dentry *dentry, int mode,
++					struct qstr *name, void **ctx,
++					u32 *ctxlen);
++
+ 
+ #ifdef CONFIG_SECURITY_PATH
+ 	int (*path_unlink) (struct path *dir, struct dentry *dentry);
+@@ -1586,6 +1612,7 @@ struct security_operations {
+ 
+ 	int (*getprocattr) (struct task_struct *p, char *name, char **value);
+ 	int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size);
++	int (*ismaclabel) (const char *name);
+ 	int (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen);
+ 	int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
+ 	void (*release_secctx) (char *secdata, u32 seclen);
+@@ -1720,10 +1747,16 @@ int security_sb_mount(const char *dev_name, struct path *path,
+ 		      const char *type, unsigned long flags, void *data);
+ int security_sb_umount(struct vfsmount *mnt, int flags);
+ int security_sb_pivotroot(struct path *old_path, struct path *new_path);
+-int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts);
++int security_sb_set_mnt_opts(struct super_block *sb,
++				struct security_mnt_opts *opts,
++				unsigned long kern_flags,
++				unsigned long *set_kern_flags);
+ void security_sb_clone_mnt_opts(const struct super_block *oldsb,
+ 				struct super_block *newsb);
+ int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
++int security_dentry_init_security(struct dentry *dentry, int mode,
++					struct qstr *name, void **ctx,
++					u32 *ctxlen);
+ 
+ int security_inode_alloc(struct inode *inode);
+ void security_inode_free(struct inode *inode);
+@@ -1835,6 +1868,7 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode);
+ int security_getprocattr(struct task_struct *p, char *name, char **value);
+ int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
+ int security_netlink_send(struct sock *sk, struct sk_buff *skb);
++int security_ismaclabel(const char *name);
+ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
+ int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
+ void security_release_secctx(char *secdata, u32 seclen);
+@@ -2006,7 +2040,9 @@ static inline int security_sb_pivotroot(struct path *old_path,
+ }
+ 
+ static inline int security_sb_set_mnt_opts(struct super_block *sb,
+-					   struct security_mnt_opts *opts)
++					   struct security_mnt_opts *opts,
++					   unsigned long kern_flags,
++					   unsigned long *set_kern_flags)
+ {
+ 	return 0;
+ }
+@@ -2028,6 +2064,16 @@ static inline int security_inode_alloc(struct inode *inode)
+ static inline void security_inode_free(struct inode *inode)
+ { }
+ 
++static inline int security_dentry_init_security(struct dentry *dentry,
++						 int mode,
++						 struct qstr *name,
++						 void **ctx,
++						 u32 *ctxlen)
++{
++	return -EOPNOTSUPP;
++}
++
++
+ static inline int security_inode_init_security(struct inode *inode,
+ 						struct inode *dir,
+ 						const struct qstr *qstr,
+@@ -2513,6 +2559,11 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
+ 	return cap_netlink_send(sk, skb);
+ }
+ 
++static inline int security_ismaclabel(const char *name)
++{
++	return 0;
++}
++
+ static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+ {
+ 	return -EOPNOTSUPP;
+diff --git a/include/uapi/linux/nfs4.h b/include/uapi/linux/nfs4.h
+index 788128e..19a7b6d 100644
+--- a/include/uapi/linux/nfs4.h
++++ b/include/uapi/linux/nfs4.h
+@@ -25,7 +25,7 @@
+ #define NFS4_MAXNAMLEN		NAME_MAX
+ #define NFS4_OPAQUE_LIMIT	1024
+ #define NFS4_MAX_SESSIONID_LEN	16
+-
++#define NFS4_MAXLABELLEN	128 
+ #define NFS4_ACCESS_READ        0x0001
+ #define NFS4_ACCESS_LOOKUP      0x0002
+ #define NFS4_ACCESS_MODIFY      0x0004
+diff --git a/security/capability.c b/security/capability.c
+index 5797750..59b82d0 100644
+--- a/security/capability.c
++++ b/security/capability.c
+@@ -91,7 +91,10 @@ static int cap_sb_pivotroot(struct path *old_path, struct path *new_path)
+ }
+ 
+ static int cap_sb_set_mnt_opts(struct super_block *sb,
+-			       struct security_mnt_opts *opts)
++			       struct security_mnt_opts *opts,
++			       unsigned long kern_flags,
++			       unsigned long *set_kern_flags)
++
+ {
+ 	if (unlikely(opts->num_mnt_opts))
+ 		return -EOPNOTSUPP;
+@@ -108,6 +111,13 @@ static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
+ 	return 0;
+ }
+ 
++static int cap_dentry_init_security(struct dentry *dentry, int mode,
++					struct qstr *name, void **ctx,
++					u32 *ctxlen)
++{
++	return 0;
++}
++
+ static int cap_inode_alloc_security(struct inode *inode)
+ {
+ 	return 0;
+@@ -810,6 +820,11 @@ static int cap_setprocattr(struct task_struct *p, char *name, void *value,
+ 	return -EINVAL;
+ }
+ 
++static int cap_ismaclabel(const char *name)
++{
++	return 0;
++}
++
+ static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+ {
+ 	return -EOPNOTSUPP;
+@@ -925,6 +940,7 @@ void __init security_fixup_ops(struct security_operations *ops)
+ 	set_to_cap_if_null(ops, sb_set_mnt_opts);
+ 	set_to_cap_if_null(ops, sb_clone_mnt_opts);
+ 	set_to_cap_if_null(ops, sb_parse_opts_str);
++	set_to_cap_if_null(ops, dentry_init_security);
+ 	set_to_cap_if_null(ops, inode_alloc_security);
+ 	set_to_cap_if_null(ops, inode_free_security);
+ 	set_to_cap_if_null(ops, inode_init_security);
+@@ -1028,6 +1044,7 @@ void __init security_fixup_ops(struct security_operations *ops)
+ 	set_to_cap_if_null(ops, d_instantiate);
+ 	set_to_cap_if_null(ops, getprocattr);
+ 	set_to_cap_if_null(ops, setprocattr);
++	set_to_cap_if_null(ops, ismaclabel);
+ 	set_to_cap_if_null(ops, secid_to_secctx);
+ 	set_to_cap_if_null(ops, secctx_to_secid);
+ 	set_to_cap_if_null(ops, release_secctx);
+diff --git a/security/security.c b/security/security.c
+index 7b88c6a..af835e3 100644
+--- a/security/security.c
++++ b/security/security.c
+@@ -12,6 +12,7 @@
+  */
+ 
+ #include <linux/capability.h>
++#include <linux/dcache.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/kernel.h>
+@@ -293,9 +294,12 @@ int security_sb_pivotroot(struct path *old_path, struct path *new_path)
+ }
+ 
+ int security_sb_set_mnt_opts(struct super_block *sb,
+-				struct security_mnt_opts *opts)
++				struct security_mnt_opts *opts,
++				unsigned long kern_flags,
++				unsigned long *set_kern_flags)
+ {
+-	return security_ops->sb_set_mnt_opts(sb, opts);
++	return security_ops->sb_set_mnt_opts(sb, opts, kern_flags,
++						set_kern_flags);
+ }
+ EXPORT_SYMBOL(security_sb_set_mnt_opts);
+ 
+@@ -324,6 +328,15 @@ void security_inode_free(struct inode *inode)
+ 	security_ops->inode_free_security(inode);
+ }
+ 
++int security_dentry_init_security(struct dentry *dentry, int mode,
++					struct qstr *name, void **ctx,
++					u32 *ctxlen)
++{
++	return security_ops->dentry_init_security(dentry, mode, name,
++							ctx, ctxlen);
++}
++EXPORT_SYMBOL(security_dentry_init_security);
++
+ int security_inode_init_security(struct inode *inode, struct inode *dir,
+ 				 const struct qstr *qstr,
+ 				 const initxattrs initxattrs, void *fs_data)
+@@ -647,6 +660,7 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
+ 		return 0;
+ 	return security_ops->inode_listsecurity(inode, buffer, buffer_size);
+ }
++EXPORT_SYMBOL(security_inode_listsecurity);
+ 
+ void security_inode_getsecid(const struct inode *inode, u32 *secid)
+ {
+@@ -1047,6 +1061,12 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb)
+ 	return security_ops->netlink_send(sk, skb);
+ }
+ 
++int security_ismaclabel(const char *name)
++{
++	return security_ops->ismaclabel(name);
++}
++EXPORT_SYMBOL(security_ismaclabel);
++
+ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+ {
+ 	return security_ops->secid_to_secctx(secid, secdata, seclen);
+diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
+index ef26e96..af947f8 100644
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -80,6 +80,7 @@
+ #include <linux/syslog.h>
+ #include <linux/user_namespace.h>
+ #include <linux/export.h>
++#include <linux/security.h>
+ #include <linux/msg.h>
+ #include <linux/shm.h>
+ 
+@@ -283,13 +284,14 @@ static void superblock_free_security(struct super_block *sb)
+ 
+ /* The file system's label must be initialized prior to use. */
+ 
+-static const char *labeling_behaviors[6] = {
++static const char *labeling_behaviors[7] = {
+ 	"uses xattr",
+ 	"uses transition SIDs",
+ 	"uses task SIDs",
+ 	"uses genfs_contexts",
+ 	"not configured for labeling",
+ 	"uses mountpoint labeling",
++	"uses native labeling",
+ };
+ 
+ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
+@@ -551,7 +553,9 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
+  * labeling information.
+  */
+ static int selinux_set_mnt_opts(struct super_block *sb,
+-				struct security_mnt_opts *opts)
++				struct security_mnt_opts *opts,
++				unsigned long kern_flags,
++				unsigned long *set_kern_flags)
+ {
+ 	const struct cred *cred = current_cred();
+ 	int rc = 0, i;
+@@ -579,6 +583,12 @@ static int selinux_set_mnt_opts(struct super_block *sb,
+ 			"before the security server is initialized\n");
+ 		goto out;
+ 	}
++	if (kern_flags && !set_kern_flags) {
++		/* Specifying internal flags without providing a place to
++		 * place the results is not allowed */
++		rc = -EINVAL;
++		goto out;
++	}
+ 
+ 	/*
+ 	 * Binary mount data FS will come through this function twice.  Once
+@@ -669,14 +679,21 @@ static int selinux_set_mnt_opts(struct super_block *sb,
+ 	if (strcmp(sb->s_type->name, "proc") == 0)
+ 		sbsec->flags |= SE_SBPROC;
+ 
+-	/* Determine the labeling behavior to use for this filesystem type. */
+-	rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
+-	if (rc) {
+-		printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
+-		       __func__, sb->s_type->name, rc);
+-		goto out;
++	if (!sbsec->behavior) {
++		/*
++		 * Determine the labeling behavior to use for this
++		 * filesystem type.
++		 */
++		rc = security_fs_use((sbsec->flags & SE_SBPROC) ?
++					"proc" : sb->s_type->name,
++					&sbsec->behavior, &sbsec->sid);
++		if (rc) {
++			printk(KERN_WARNING
++				"%s: security_fs_use(%s) returned %d\n",
++					__func__, sb->s_type->name, rc);
++			goto out;
++		}
+ 	}
+-
+ 	/* sets the context of the superblock for the fs being mounted. */
+ 	if (fscontext_sid) {
+ 		rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
+@@ -691,6 +708,11 @@ static int selinux_set_mnt_opts(struct super_block *sb,
+ 	 * sets the label used on all file below the mountpoint, and will set
+ 	 * the superblock context if not already set.
+ 	 */
++	if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
++		sbsec->behavior = SECURITY_FS_USE_NATIVE;
++		*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
++	}
++
+ 	if (context_sid) {
+ 		if (!fscontext_sid) {
+ 			rc = may_context_mount_sb_relabel(context_sid, sbsec,
+@@ -722,7 +744,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
+ 	}
+ 
+ 	if (defcontext_sid) {
+-		if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
++		if (sbsec->behavior != SECURITY_FS_USE_XATTR &&
++			sbsec->behavior != SECURITY_FS_USE_NATIVE) {
+ 			rc = -EINVAL;
+ 			printk(KERN_WARNING "SELinux: defcontext option is "
+ 			       "invalid for this filesystem type\n");
+@@ -948,7 +971,7 @@ static int superblock_doinit(struct super_block *sb, void *data)
+ 		goto out_err;
+ 
+ out:
+-	rc = selinux_set_mnt_opts(sb, &opts);
++	rc = selinux_set_mnt_opts(sb, &opts, 0, NULL);
+ 
+ out_err:
+ 	security_free_mnt_opts(&opts);
+@@ -1190,6 +1213,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
+ 	}
+ 
+ 	switch (sbsec->behavior) {
++	case SECURITY_FS_USE_NATIVE:
++		break;
+ 	case SECURITY_FS_USE_XATTR:
+ 		if (!inode->i_op->getxattr) {
+ 			isec->sid = sbsec->def_sid;
+@@ -2483,6 +2508,40 @@ static void selinux_inode_free_security(struct inode *inode)
+ 	inode_free_security(inode);
+ }
+ 
++static int selinux_dentry_init_security(struct dentry *dentry, int mode,
++					struct qstr *name, void **ctx,
++					u32 *ctxlen)
++{
++	const struct cred *cred = current_cred();
++	struct task_security_struct *tsec;
++	struct inode_security_struct *dsec;
++	struct superblock_security_struct *sbsec;
++	struct inode *dir = dentry->d_parent->d_inode;
++	u32 newsid;
++	int rc;
++
++	tsec = cred->security;
++	dsec = dir->i_security;
++	sbsec = dir->i_sb->s_security;
++
++	if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
++		newsid = tsec->create_sid;
++	} else {
++		rc = security_transition_sid(tsec->sid, dsec->sid,
++					     inode_mode_to_security_class(mode),
++					     name,
++					     &newsid);
++		if (rc) {
++			printk(KERN_WARNING
++				"%s: security_transition_sid failed, rc=%d\n",
++			       __func__, -rc);
++			return rc;
++		}
++	}
++
++	return security_sid_to_context(newsid, (char **)ctx, ctxlen);
++}
++
+ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
+ 				       const struct qstr *qstr, char **name,
+ 				       void **value, size_t *len)
+@@ -2817,7 +2876,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
+ 		return;
+ 	}
+ 
++	isec->sclass = inode_mode_to_security_class(inode->i_mode);
+ 	isec->sid = newsid;
++	isec->initialized = 1;
++
+ 	return;
+ }
+ 
+@@ -2905,6 +2967,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
+ 	if (rc)
+ 		return rc;
+ 
++	isec->sclass = inode_mode_to_security_class(inode->i_mode);
+ 	isec->sid = newsid;
+ 	isec->initialized = 1;
+ 	return 0;
+@@ -5392,6 +5455,11 @@ abort_change:
+ 	return error;
+ }
+ 
++static int selinux_ismaclabel(const char *name)
++{
++	return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
++}
++
+ static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+ {
+ 	return security_sid_to_context(secid, secdata, seclen);
+@@ -5534,6 +5602,7 @@ static struct security_operations selinux_ops = {
+ 	.sb_clone_mnt_opts =		selinux_sb_clone_mnt_opts,
+ 	.sb_parse_opts_str = 		selinux_parse_opts_str,
+ 
++	.dentry_init_security =		selinux_dentry_init_security,
+ 
+ 	.inode_alloc_security =		selinux_inode_alloc_security,
+ 	.inode_free_security =		selinux_inode_free_security,
+@@ -5629,6 +5698,7 @@ static struct security_operations selinux_ops = {
+ 	.getprocattr =			selinux_getprocattr,
+ 	.setprocattr =			selinux_setprocattr,
+ 
++	.ismaclabel =			selinux_ismaclabel,
+ 	.secid_to_secctx =		selinux_secid_to_secctx,
+ 	.secctx_to_secid =		selinux_secctx_to_secid,
+ 	.release_secctx =		selinux_release_secctx,
+diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
+index 6d38851..8fd8e18 100644
+--- a/security/selinux/include/security.h
++++ b/security/selinux/include/security.h
+@@ -169,6 +169,8 @@ int security_get_allow_unknown(void);
+ #define SECURITY_FS_USE_GENFS		4 /* use the genfs support */
+ #define SECURITY_FS_USE_NONE		5 /* no labeling support */
+ #define SECURITY_FS_USE_MNTPOINT	6 /* use mountpoint labeling */
++#define SECURITY_FS_USE_NATIVE		7 /* use native label support */
++#define SECURITY_FS_USE_MAX		7 /* Highest SECURITY_FS_USE_XXX */
+ 
+ int security_fs_use(const char *fstype, unsigned int *behavior,
+ 	u32 *sid);
+diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
+index 9cd9b7c..c8adde3 100644
+--- a/security/selinux/ss/policydb.c
++++ b/security/selinux/ss/policydb.c
+@@ -2168,7 +2168,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
+ 
+ 				rc = -EINVAL;
+ 				c->v.behavior = le32_to_cpu(buf[0]);
+-				if (c->v.behavior > SECURITY_FS_USE_NONE)
++				/* Determined at runtime, not in policy DB. */
++				if (c->v.behavior == SECURITY_FS_USE_MNTPOINT)
++					goto out;
++				if (c->v.behavior > SECURITY_FS_USE_MAX)
+ 					goto out;
+ 
+ 				rc = -ENOMEM;
+diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
+index 38be92c..82c3c72 100644
+--- a/security/smack/smack_lsm.c
++++ b/security/smack/smack_lsm.c
+@@ -3335,6 +3335,16 @@ static void smack_audit_rule_free(void *vrule)
+ #endif /* CONFIG_AUDIT */
+ 
+ /**
++ * smack_ismaclabel - check if xattr @name references a smack MAC label
++ * @name: Full xattr name to check.
++ */
++static int smack_ismaclabel(const char *name)
++{
++	return (strcmp(name, XATTR_SMACK_SUFFIX) == 0);
++}
++
++
++/**
+  * smack_secid_to_secctx - return the smack label for a secid
+  * @secid: incoming integer
+  * @secdata: destination
+@@ -3530,6 +3540,7 @@ struct security_operations smack_ops = {
+ 	.audit_rule_free =		smack_audit_rule_free,
+ #endif /* CONFIG_AUDIT */
+ 
++	.ismaclabel =			smack_ismaclabel,
+ 	.secid_to_secctx = 		smack_secid_to_secctx,
+ 	.secctx_to_secid = 		smack_secctx_to_secid,
+ 	.release_secctx = 		smack_release_secctx,


More information about the scm-commits mailing list