diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index 69cb796f6270..03f773b7c423 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -37,6 +37,7 @@
  * is on, and remove the appropriate bits from attr->ia_mode (attr is a
  * "struct iattr *"). -BlaisorBlade
  */
+extern int use_xattr;
 struct hostfs_timespec {
 	long long tv_sec;
 	long long tv_nsec;
@@ -67,7 +68,8 @@ struct hostfs_stat {
 	unsigned int min;
 };
 
-extern int stat_file(const char *path, struct hostfs_stat *p, int fd);
+extern int stat_file(const char *path, struct hostfs_stat *p, int fd,
+							int mnt_use_xattr);
 extern int access_file(char *path, int r, int w, int x);
 extern int open_file(char *path, int r, int w, int append);
 extern void *open_dir(char *path, int *err_out);
@@ -83,11 +85,14 @@ extern int write_file(int fd, unsigned long long *offset, const char *buf,
 		      int len);
 extern int lseek_file(int fd, long long offset, int whence);
 extern int fsync_file(int fd, int datasync);
-extern int file_create(char *name, int mode);
-extern int set_attr(const char *file, struct hostfs_iattr *attrs, int fd);
+extern int file_create(char *name, int mode, uid_t uid, gid_t gid,
+							int mnt_use_xattr);
+extern int set_attr(const char *file, struct hostfs_iattr *attrs, int fd,
+							    int mnt_use_xattr);
 extern int make_symlink(const char *from, const char *to);
 extern int unlink_file(const char *file);
-extern int do_mkdir(const char *file, int mode);
+extern int do_mkdir(const char *file, int mode, uid_t uid, gid_t gid,
+							int mnt_use_xattr);
 extern int hostfs_do_rmdir(const char *file);
 extern int do_mknod(const char *file, int mode, unsigned int major,
 		    unsigned int minor);
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 28b4f15c19eb..a2afe70abf14 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -17,6 +17,7 @@
 #include <linux/writeback.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
+#include <linux/uidgid.h>
 #include "hostfs.h"
 #include <init.h>
 #include <kern.h>
@@ -28,6 +29,11 @@ struct hostfs_inode_info {
 	struct mutex open_mutex;
 };
 
+struct hostfs_fs_info {
+	char host_root_path[PATH_MAX+1];
+	int use_xattr;
+};
+
 static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
 {
 	return list_entry(inode, struct hostfs_inode_info, vfs_inode);
@@ -64,6 +70,8 @@ static int __init hostfs_args(char *options, int *add)
 		if (*options != '\0') {
 			if (!strcmp(options, "append"))
 				append = 1;
+			else if (!strcmp(options, "xattrperm"))
+				use_xattr = 1;
 			else printf("hostfs_args - unsupported option - %s\n",
 				    options);
 		}
@@ -79,18 +87,22 @@ __uml_setup("hostfs=", hostfs_args,
 "    tree on the host.  If this isn't specified, then a user inside UML can\n"
 "    mount anything on the host that's accessible to the user that's running\n"
 "    it.\n"
-"    The only flag currently supported is 'append', which specifies that all\n"
-"    files opened by hostfs will be opened in append mode.\n\n"
+"    The only flags currently supported are 'append', which specifies that\n"
+"    all files opened by hostfs will be opened in append mode and 'xattrperm'\n"
+"    which specifies that permissions of files will be stored in extended\n"
+"    attributes.\n\n"
 );
 #endif
 
 static char *__dentry_name(struct dentry *dentry, char *name)
 {
 	char *p = dentry_path_raw(dentry, name, PATH_MAX);
+	struct hostfs_fs_info *sb_data;
 	char *root;
 	size_t len;
 
-	root = dentry->d_sb->s_fs_info;
+	sb_data = dentry->d_sb->s_fs_info;
+	root = sb_data->host_root_path;
 	len = strlen(root);
 	if (IS_ERR(p)) {
 		__putname(name);
@@ -203,8 +215,10 @@ static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
 	long long f_bavail;
 	long long f_files;
 	long long f_ffree;
+	struct hostfs_fs_info *sb_data;
 
-	err = do_statfs(dentry->d_sb->s_fs_info,
+	sb_data = dentry->d_sb->s_fs_info;
+	err = do_statfs(sb_data->host_root_path,
 			&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
 			&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
 			&sf->f_namelen);
@@ -250,15 +264,21 @@ static void hostfs_free_inode(struct inode *inode)
 
 static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
 {
-	const char *root_path = root->d_sb->s_fs_info;
+	struct hostfs_fs_info *sb_data = root->d_sb->s_fs_info;
 	size_t offset = strlen(root_ino) + 1;
 
-	if (strlen(root_path) > offset)
-		seq_show_option(seq, root_path + offset, NULL);
+	if (strlen(sb_data->host_root_path) > offset)
+		seq_show_option(seq, sb_data->host_root_path + offset, NULL);
 
 	if (append)
 		seq_puts(seq, ",append");
 
+	if (sb_data->use_xattr == 0)
+		seq_puts(seq, ",noxattrperm");
+
+	if (sb_data->use_xattr == 1)
+		seq_puts(seq, ",xattrperm");
+
 	return 0;
 }
 
@@ -516,7 +536,8 @@ static int read_name(struct inode *ino, char *name)
 {
 	dev_t rdev;
 	struct hostfs_stat st;
-	int err = stat_file(name, &st, -1);
+	struct hostfs_fs_info *sb_data = ino->i_sb->s_fs_info;
+	int err = stat_file(name, &st, -1, sb_data->use_xattr);
 	if (err)
 		return err;
 
@@ -564,9 +585,13 @@ static int hostfs_create(struct mnt_idmap *idmap, struct inode *dir,
 			 struct dentry *dentry, umode_t mode, bool excl)
 {
 	struct inode *inode;
+	struct hostfs_fs_info *sb_data;
 	char *name;
 	int error, fd;
+	unsigned int currentuid;
+	unsigned int currentgid;
 
+	sb_data = dentry->d_sb->s_fs_info;
 	inode = hostfs_iget(dir->i_sb);
 	if (IS_ERR(inode)) {
 		error = PTR_ERR(inode);
@@ -578,7 +603,10 @@ static int hostfs_create(struct mnt_idmap *idmap, struct inode *dir,
 	if (name == NULL)
 		goto out_put;
 
-	fd = file_create(name, mode & 0777);
+	currentuid = from_kuid(current->cred->user_ns, current->cred->euid);
+	currentgid = from_kgid(current->cred->user_ns, current->cred->egid);
+	fd = file_create(name, mode & 0777, currentuid, currentgid,
+							   sb_data->use_xattr);
 	if (fd < 0)
 		error = fd;
 	else
@@ -675,12 +703,18 @@ static int hostfs_symlink(struct mnt_idmap *idmap, struct inode *ino,
 static int hostfs_mkdir(struct mnt_idmap *idmap, struct inode *ino,
 			struct dentry *dentry, umode_t mode)
 {
+	struct hostfs_fs_info *sb_data;
 	char *file;
 	int err;
+	unsigned int currentuid;
+	unsigned int currentgid;
 
+	sb_data = dentry->d_sb->s_fs_info;
 	if ((file = dentry_name(dentry)) == NULL)
 		return -ENOMEM;
-	err = do_mkdir(file, mode);
+	currentuid = from_kuid(current->cred->user_ns, current->cred->euid);
+	currentgid = from_kgid(current->cred->user_ns, current->cred->egid);
+	err = do_mkdir(file, mode, currentuid, currentgid, sb_data->use_xattr);
 	__putname(file);
 	return err;
 }
@@ -796,10 +830,12 @@ static int hostfs_setattr(struct mnt_idmap *idmap,
 {
 	struct inode *inode = d_inode(dentry);
 	struct hostfs_iattr attrs;
+	struct hostfs_fs_info *sb_data;
 	char *name;
 	int err;
 
 	int fd = HOSTFS_I(inode)->fd;
+	sb_data = dentry->d_sb->s_fs_info;
 
 	err = setattr_prepare(&nop_mnt_idmap, dentry, attr);
 	if (err)
@@ -849,7 +885,7 @@ static int hostfs_setattr(struct mnt_idmap *idmap,
 	name = dentry_name(dentry);
 	if (name == NULL)
 		return -ENOMEM;
-	err = set_attr(name, &attrs, fd);
+	err = set_attr(name, &attrs, fd, sb_data->use_xattr);
 	__putname(name);
 	if (err)
 		return err;
@@ -915,10 +951,58 @@ static const struct inode_operations hostfs_link_iops = {
 	.get_link	= hostfs_get_link,
 };
 
+static int hostfs_parse_options(struct hostfs_fs_info *sb_data, const char *d)
+{
+	int err = 0, unknown = 0;
+	char *ptr, *options, *string;
+
+	snprintf(sb_data->host_root_path, PATH_MAX, "%s/", root_ino);
+	sb_data->use_xattr = -1;
+	if (d == NULL)
+		return 0;
+
+	string = kmalloc(strlen(d) + 1, GFP_KERNEL);
+	if (string == NULL) {
+		err = -ENOMEM;
+		goto out;
+	}
+	options = string;
+	strcpy(options, d);
+
+	while (options) {
+		ptr = strchr(options, ',');
+		if (ptr != NULL)
+			*ptr++ = '\0';
+		if (*options != '\0') {
+			if (!strcmp(options, "noxattrperm")) {
+				sb_data->use_xattr = 0;
+				goto _break;
+			}
+			if (!strcmp(options, "xattrperm")) {
+				sb_data->use_xattr = 1;
+				goto _break;
+			}
+			if (!unknown) {
+				unknown = 1;
+				strcat(sb_data->host_root_path, options);
+				goto _break;
+			}
+			pr_warn("hostfs: unsupported mount option\n");
+			err = -EINVAL;
+			goto out;
+		}
+_break:
+		options = ptr;
+	}
+
+out:
+	kfree(string);
+	return err;
+}
 static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
 {
 	struct inode *root_inode;
-	char *host_root_path, *req_root = d;
+	struct hostfs_fs_info *sb_data;
 	int err;
 
 	sb->s_blocksize = 1024;
@@ -931,26 +1015,26 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
 	if (err)
 		goto out;
 
-	/* NULL is printed as '(null)' by printf(): avoid that. */
-	if (req_root == NULL)
-		req_root = "";
-
 	err = -ENOMEM;
-	sb->s_fs_info = host_root_path =
-		kasprintf(GFP_KERNEL, "%s/%s", root_ino, req_root);
-	if (host_root_path == NULL)
+	sb_data = kmalloc(sizeof(struct hostfs_fs_info), GFP_KERNEL);
+	if (sb_data == NULL)
+		goto out;
+
+	err = hostfs_parse_options(sb_data, d);
+	if (err != 0)
 		goto out;
+	sb->s_fs_info = sb_data;
 
 	root_inode = new_inode(sb);
 	if (!root_inode)
 		goto out;
 
-	err = read_name(root_inode, host_root_path);
+	err = read_name(root_inode, sb_data->host_root_path);
 	if (err)
 		goto out_put;
 
 	if (S_ISLNK(root_inode->i_mode)) {
-		char *name = follow_link(host_root_path);
+		char *name = follow_link(sb_data->host_root_path);
 		if (IS_ERR(name)) {
 			err = PTR_ERR(name);
 			goto out_put;
@@ -1001,6 +1085,9 @@ static int __init init_hostfs(void)
 	hostfs_inode_cache = KMEM_CACHE(hostfs_inode_info, 0);
 	if (!hostfs_inode_cache)
 		return -ENOMEM;
+	#ifdef MODULE
+	use_xattr = 0;
+	#endif
 	return register_filesystem(&hostfs_type);
 }
 
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index 5ecc4706172b..f5dd524cd153 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -10,14 +10,19 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <string.h>
+#include <stdlib.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/vfs.h>
 #include <sys/syscall.h>
+#include <sys/xattr.h>
+#include <um_malloc.h>
 #include "hostfs.h"
 #include <utime.h>
 
+int use_xattr;
+
 static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p)
 {
 	p->ino = buf->st_ino;
@@ -38,7 +43,184 @@ static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p)
 	p->min = os_minor(buf->st_rdev);
 }
 
-int stat_file(const char *path, struct hostfs_stat *p, int fd)
+static int uml_chown(const char *pathname, uid_t owner, gid_t group,
+							int mnt_use_xattr)
+{
+	int xattr = (mnt_use_xattr == -1) ? use_xattr : mnt_use_xattr;
+	/* 10 digits uid, 10 digits gid, null byte and ',' */
+	char umlcred[22];
+	/* max_gid=4294967295 - 10 digits + null byte */
+	char gid[11];
+	int i = 0;
+
+	if (xattr) {
+		memset(umlcred, 0, sizeof(umlcred));
+		getxattr(pathname, "user.umlcred", umlcred, sizeof(umlcred));
+
+		while (umlcred[i] != ',' && umlcred[i] != '\0')
+			i++;
+		umlcred[i] = '\0';
+
+		if (group == -1)
+			strncpy(gid, &umlcred[i+1], sizeof(gid));
+		else
+			snprintf(gid, sizeof(gid), "%u", group);
+		if (owner != -1)
+			snprintf(umlcred, sizeof(gid), "%u", owner);
+
+		strcat(umlcred, ",");
+		strncat(umlcred, gid, sizeof(gid-1));
+		if (setxattr(pathname, "user.umlcred", umlcred,
+						strlen(umlcred)+1, 0))
+			return -errno;
+
+		return 0;
+	}
+	if (chown(pathname, owner, group))
+		return -errno;
+	return 0;
+}
+
+static int uml_fchown(int fd, uid_t owner, gid_t group, int mnt_use_xattr)
+{
+	int xattr = (mnt_use_xattr == -1) ? use_xattr : mnt_use_xattr;
+	/* 10 digits uid, 10 digits gid, null byte and ',' */
+	char umlcred[22];
+	/* max_gid=4294967295 - 10 digits + null byte */
+	char gid[11];
+	int i = 0;
+
+	if (xattr) {
+		memset(umlcred, 0, sizeof(umlcred));
+		fgetxattr(fd, "user.umlcred", umlcred, sizeof(umlcred));
+
+		while (umlcred[i] != ',' && umlcred[i] != '\0')
+			i++;
+		umlcred[i] = '\0';
+
+		if (group == -1)
+			strncpy(gid, &umlcred[i+1], sizeof(gid));
+		else
+			snprintf(gid, sizeof(gid), "%u", group);
+		if (owner != -1)
+			snprintf(umlcred, sizeof(gid), "%u", owner);
+
+		strcat(umlcred, ",");
+		strncat(umlcred, gid, sizeof(gid-1));
+		if (fsetxattr(fd, "user.umlcred", umlcred, strlen(umlcred)+1, 0))
+			return -errno;
+
+		return 0;
+	}
+	if (fchown(fd, owner, group))
+		return -errno;
+	return 0;
+}
+
+static int uml_chmod(const char *pathname, unsigned int mode, int mnt_use_xattr)
+{
+	int xattr = (mnt_use_xattr == -1) ? use_xattr : mnt_use_xattr;
+	int i;
+	char mode_string[7];	/* mode is 16-bit -> max 6 digits in octal */
+
+	if (xattr) {
+		strcpy(mode_string, "000000");
+		i = sizeof(mode_string) - 1;
+		while (mode > 0) {
+			mode_string[i] = (mode % 8) + '0';
+			mode = mode / 8;
+			i--;
+		}
+		if (setxattr(pathname, "user.umlmode", mode_string,
+						       sizeof(mode_string), 0))
+			return -errno;
+		return 0;
+	}
+	if (chmod(pathname, mode))
+		return -errno;
+	return 0;
+}
+
+static int uml_fchmod(int fd, unsigned int mode, int mnt_use_xattr)
+{
+	int xattr = (mnt_use_xattr == -1) ? use_xattr : mnt_use_xattr;
+	int i;
+	char mode_string[7];	/* mode is 16-bit -> max 6 digits in octal */
+
+	if (xattr) {
+		strcpy(mode_string, "000000");
+		i = sizeof(mode_string) - 1;
+		while (mode > 0) {
+			mode_string[i] = (mode % 8) + '0';
+			mode = mode / 8;
+			i--;
+		}
+		if (fsetxattr(fd, "user.umlmode", mode_string,
+						  sizeof(mode_string), 0))
+			return -errno;
+		return 0;
+	}
+	if (fchmod(fd, mode))
+		return -errno;
+	return 0;
+}
+
+static void read_permissions(const char *path, struct stat64 *p,
+							int mnt_use_xattr)
+{
+	unsigned int mode = 0, i;
+	char mode_string[7], umlcred[22];
+	int xattr = (mnt_use_xattr == -1) ? use_xattr : mnt_use_xattr;
+
+	if (!xattr)
+		return;
+
+	if (getxattr(path, "user.umlmode", mode_string, sizeof(mode_string)) != -1) {
+		i = 0;
+		while (mode_string[i] != '\0') {
+			mode *= 8;
+			mode += mode_string[i] - '0';
+			i++;
+		}
+		p->st_mode = mode;
+	}
+
+	if (getxattr(path, "user.umlcred", umlcred, sizeof(umlcred)) != -1) {
+		i = 0;
+		while (umlcred[i] != ',')
+			i++;
+		umlcred[i] = '\0';
+
+		if (strlen(umlcred) > 0)
+			p->st_uid = atoi(umlcred);
+		if (strlen(&umlcred[i+1]) > 0)
+			p->st_gid = atoi(&umlcred[i+1]);
+	}
+}
+
+static long is_set_gid(const char *path, int mnt_use_xattr)
+{
+	int i = strlen(path) + 1;
+	char *parent = uml_kmalloc(i, UM_GFP_KERNEL);
+	struct stat64 buf = { 0 };
+
+	if (parent == NULL)
+		return -1;
+	strcpy(parent, path);
+	i = i - 3;
+	while (parent[i] != '/')
+		i--;
+	parent[i] = '\0';
+
+	stat64(parent, &buf);
+	read_permissions(parent, &buf, mnt_use_xattr);
+	kfree(parent);
+	if (buf.st_mode & S_ISGID)
+		return buf.st_gid;
+	return -1;
+}
+
+int stat_file(const char *path, struct hostfs_stat *p, int fd, int mnt_use_xattr)
 {
 	struct stat64 buf;
 
@@ -48,6 +230,7 @@ int stat_file(const char *path, struct hostfs_stat *p, int fd)
 	} else if (lstat64(path, &buf) < 0) {
 		return -errno;
 	}
+	read_permissions(path, &buf, mnt_use_xattr);
 	stat64_to_hostfs(&buf, p);
 	return 0;
 }
@@ -181,44 +364,60 @@ void close_dir(void *stream)
 	closedir(stream);
 }
 
-int file_create(char *name, int mode)
+int file_create(char *name, int mode, uid_t uid, gid_t gid, int mnt_use_xattr)
 {
 	int fd;
+	long ret;
 
 	fd = open64(name, O_CREAT | O_RDWR, mode);
 	if (fd < 0)
 		return -errno;
+
+	ret = is_set_gid(name, mnt_use_xattr);
+	if (ret != -1)
+		gid = ret;
+	uml_chown(name, uid, gid, mnt_use_xattr);
 	return fd;
 }
 
-int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
+int set_attr(const char *file, struct hostfs_iattr *attrs, int fd,
+							     int mnt_use_xattr)
 {
 	struct hostfs_stat st;
 	struct timeval times[2];
-	int err, ma;
+	int err, ma, ret;
 
 	if (attrs->ia_valid & HOSTFS_ATTR_MODE) {
 		if (fd >= 0) {
-			if (fchmod(fd, attrs->ia_mode) != 0)
-				return -errno;
-		} else if (chmod(file, attrs->ia_mode) != 0) {
-			return -errno;
+			ret = uml_fchmod(fd, attrs->ia_mode, mnt_use_xattr);
+			if (ret != 0)
+				return ret;
+		} else {
+			ret = uml_chmod(file, attrs->ia_mode, mnt_use_xattr);
+			if (ret != 0)
+				return ret;
 		}
 	}
 	if (attrs->ia_valid & HOSTFS_ATTR_UID) {
 		if (fd >= 0) {
-			if (fchown(fd, attrs->ia_uid, -1))
-				return -errno;
-		} else if (chown(file, attrs->ia_uid, -1)) {
-			return -errno;
+			ret = uml_fchown(fd, attrs->ia_uid, -1, mnt_use_xattr);
+			if (ret != 0)
+				return ret;
+		} else {
+			ret = uml_chown(file, attrs->ia_uid, -1, mnt_use_xattr);
+			if (ret != 0)
+				return ret;
 		}
 	}
 	if (attrs->ia_valid & HOSTFS_ATTR_GID) {
 		if (fd >= 0) {
-			if (fchown(fd, -1, attrs->ia_gid))
-				return -errno;
-		} else if (chown(file, -1, attrs->ia_gid)) {
-			return -errno;
+			ret = uml_fchown(fd, -1, attrs->ia_gid, mnt_use_xattr);
+			if (ret != 0)
+				return ret;
+		} else {
+			ret = uml_chown(file, -1, attrs->ia_gid, mnt_use_xattr);
+			if (ret != 0)
+				return ret;
 		}
 	}
 	if (attrs->ia_valid & HOSTFS_ATTR_SIZE) {
@@ -237,7 +436,7 @@ int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
 	 */
 	ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET);
 	if (attrs->ia_valid & ma) {
-		err = stat_file(file, &st, fd);
+		err = stat_file(file, &st, fd, mnt_use_xattr);
 		if (err != 0)
 			return err;
 
@@ -265,7 +464,7 @@ int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
 
 	/* Note: ctime is not handled */
 	if (attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)) {
-		err = stat_file(file, &st, fd);
+		err = stat_file(file, &st, fd, mnt_use_xattr);
 		attrs->ia_atime = st.atime;
 		attrs->ia_mtime = st.mtime;
 		if (err != 0)
@@ -294,13 +493,18 @@ int unlink_file(const char *file)
 	return 0;
 }
 
-int do_mkdir(const char *file, int mode)
+int do_mkdir(const char *file, int mode, uid_t uid, gid_t gid, int mnt_use_xattr)
 {
 	int err;
+	long ret;
 
 	err = mkdir(file, mode);
 	if (err)
 		return -errno;
+	ret = is_set_gid(file, mnt_use_xattr);
+	if (ret != -1)
+		gid = ret;
+	uml_chown(file, uid, gid, mnt_use_xattr);
 	return 0;
 }
 
