linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [REVIEW][PATCH 0/15] userns subsystem conversions
@ 2012-08-25 23:54 Eric W. Biederman
  2012-08-25 23:58 ` [REVIEW][PATCH 01/15] userns: Enable building of pf_key sockets when user namespace support is enabled Eric W. Biederman
                   ` (13 more replies)
  0 siblings, 14 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-25 23:54 UTC (permalink / raw)
  To: linux-kernel; +Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller


This patchset updates all of the major linux subsystems that use uids
and gids to store them in kuid_t and kgid_t types.

This update allows some of the subsystems to work in all user namespaces
while other subsystems were updated to only work in the initial user
namespace.

kuid_t and kgid_t values have been pushed as deeply into the code as
possible to allow type checking to find as many problems as possible.
In a couple of cases this involved taking an implicit union stored in
an unsigned int and making it an explicit union.

This patchset is based on 3.6-rc1 and strictly against:
git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git for-next

My intention after these patches have been reviewed is to add them to my
non-rebasing for-next branch of my user namespace tree and to merge
these changes into 3.7.

I had hoped when I converted the core kernel that I would have removed
the interactions between subsystems and would be able to merge these
changes independently through maintainer trees in a timely fashion, but
there are just enough dependencies and interactions that the changes
really all need to be in one tree to make these changes testable/usable.

Once these changes hit my for-next branch I won't be rebasing them so
if a maintainer wants to merge them to avoid conflicts feel free.

The biggest cross subystem change this round is probably the change
to have audit_get_loginuid return a kuid_t, but it certainly isn't
the only cross subsystem change.

Eric W. Biederman (15):
      userns: Enable building of pf_key sockets when user namespace support is enabled.
      userns: Make credential debugging user namespace safe.
      userns: Convert security/keys to the new userns infrastructure
      userns: net: Call key_alloc with GLOBAL_ROOT_UID, GLOBAL_ROOT_GID instead of 0, 0
      userns: Convert ipc to use kuid and kgid where appropriate
      userns: Convert audit to use kuid and kgid where appropriate
      userns: Convert taskstats to handle the user and pid namespaces.
      userns: Convert bsd process accounting to use kuid and kgid where appropriate
      userns: Convert process event connector to handle kuids and kgids
      userns: Convert debugfs to use kuid/kgid where appropriate.
      userns: Teach trace to use from_kuid
      userns: Convert drm to use kuid and kgid and struct pid where appropriate
      userns: Add basic quota support
      userns: Convert vfs posix_acl support to use kuid and kgid where appripriate.
      userns: Convert configfs to use kuid and kgid where appropriate

 drivers/connector/cn_proc.c       |   18 +++-
 drivers/gpu/drm/drm_fops.c        |    3 +-
 drivers/gpu/drm/drm_info.c        |    5 +-
 drivers/gpu/drm/drm_ioctl.c       |    4 +-
 drivers/tty/tty_audit.c           |   16 ++--
 fs/9p/acl.c                       |    8 +-
 fs/btrfs/acl.c                    |    8 +-
 fs/configfs/inode.c               |    4 +-
 fs/debugfs/inode.c                |   26 +++--
 fs/ext2/acl.c                     |   32 ++++--
 fs/ext3/acl.c                     |   32 ++++--
 fs/ext4/acl.c                     |   31 ++++--
 fs/generic_acl.c                  |    4 +-
 fs/gfs2/acl.c                     |   14 ++--
 fs/gfs2/quota.c                   |   44 +++++---
 fs/jffs2/acl.c                    |    4 +-
 fs/jfs/acl.c                      |    4 +-
 fs/jfs/xattr.c                    |    4 +-
 fs/nfs/nfs3acl.c                  |    4 +-
 fs/nfsd/vfs.c                     |    8 +-
 fs/ocfs2/acl.c                    |    4 +-
 fs/ocfs2/file.c                   |    6 +-
 fs/ocfs2/quota_global.c           |   34 +++++--
 fs/ocfs2/quota_local.c            |   12 ++-
 fs/posix_acl.c                    |   30 +++---
 fs/proc/base.c                    |   12 ++-
 fs/quota/dquot.c                  |   43 ++++----
 fs/quota/netlink.c                |   11 ++-
 fs/quota/quota.c                  |   44 +++++---
 fs/quota/quota_tree.c             |   20 +++-
 fs/quota/quota_v1.c               |    8 +-
 fs/quota/quota_v2.c               |   14 ++-
 drivers/connector/cn_proc.c       |   18 +++-
 drivers/gpu/drm/drm_fops.c        |    3 +-
 drivers/gpu/drm/drm_info.c        |    5 +-
 drivers/gpu/drm/drm_ioctl.c       |    4 +-
 drivers/tty/tty_audit.c           |   16 ++--
 fs/9p/acl.c                       |    8 +-
 fs/btrfs/acl.c                    |    8 +-
 fs/configfs/inode.c               |    4 +-
 fs/debugfs/inode.c                |   26 +++--
 fs/ext2/acl.c                     |   32 ++++--
 fs/ext3/acl.c                     |   32 ++++--
 fs/ext4/acl.c                     |   31 ++++--
 fs/generic_acl.c                  |    4 +-
 fs/gfs2/acl.c                     |   14 ++--
 fs/gfs2/quota.c                   |   44 +++++---
 fs/jffs2/acl.c                    |    4 +-
 fs/jfs/acl.c                      |    4 +-
 fs/jfs/xattr.c                    |    4 +-
 fs/nfs/nfs3acl.c                  |    4 +-
 fs/nfsd/vfs.c                     |    8 +-
 fs/ocfs2/acl.c                    |    4 +-
 fs/ocfs2/file.c                   |    6 +-
 fs/ocfs2/quota_global.c           |   34 +++++--
 fs/ocfs2/quota_local.c            |   12 ++-
 fs/posix_acl.c                    |   30 +++---
 fs/proc/base.c                    |   12 ++-
 fs/quota/dquot.c                  |   43 ++++----
 fs/quota/netlink.c                |   11 ++-
 fs/quota/quota.c                  |   44 +++++---
 fs/quota/quota_tree.c             |   20 +++-
 fs/quota/quota_v1.c               |    8 +-
 fs/quota/quota_v2.c               |   14 ++-
 fs/reiserfs/xattr_acl.c           |    4 +-
 fs/xattr.c                        |    7 ++
 fs/xattr_acl.c                    |   96 +++++++++++++++--
 fs/xfs/xfs_acl.c                  |    4 +-
 fs/xfs/xfs_quotaops.c             |   18 ++--
 fs/xfs/xfs_trans_dquot.c          |    8 +-
 include/drm/drmP.h                |    4 +-
 include/linux/audit.h             |   12 ++-
 include/linux/init_task.h         |    2 +-
 include/linux/ipc.h               |    9 +-
 include/linux/key.h               |    9 +-
 include/linux/posix_acl.h         |    8 ++-
 include/linux/posix_acl_xattr.h   |   18 +++-
 include/linux/quota.h             |   91 +++++++++++++++-
 include/linux/quotaops.h          |   18 +++-
 include/linux/sched.h             |    2 +-
 include/linux/tsacct_kern.h       |    8 +-
 include/linux/tty.h               |    4 +-
 include/net/netlabel.h            |    2 +-
 include/net/xfrm.h                |   23 ++--
 init/Kconfig                      |   18 ---
 ipc/msg.c                         |   14 ++-
 ipc/sem.c                         |   13 ++-
 ipc/shm.c                         |   19 ++--
 ipc/util.c                        |   35 ++++---
 ipc/util.h                        |    2 +-
 kernel/acct.c                     |    4 +-
 kernel/audit.c                    |   42 +++++---
 kernel/audit.h                    |    4 +-
 kernel/audit_watch.c              |    2 +-
 kernel/auditfilter.c              |  142 +++++++++++++++++++++----
 kernel/auditsc.c                  |  214 +++++++++++++++++++------------------
 kernel/cred.c                     |   10 ++-
 kernel/taskstats.c                |   23 +++-
 kernel/trace/trace.c              |    3 +-
 kernel/trace/trace.h              |    2 +-
 kernel/tsacct.c                   |   12 ++-
 net/core/dev.c                    |    2 +-
 net/dns_resolver/dns_key.c        |    3 +-
 net/netlabel/netlabel_unlabeled.c |    2 +-
 net/netlabel/netlabel_user.c      |    2 +-
 net/rxrpc/ar-key.c                |    6 +-
 net/xfrm/xfrm_policy.c            |    8 +-
 net/xfrm/xfrm_state.c             |    6 +-
 net/xfrm/xfrm_user.c              |   12 +-
 security/keys/internal.h          |    6 +-
 security/keys/key.c               |   23 ++---
 security/keys/keyctl.c            |   50 +++++----
 security/keys/keyring.c           |    4 +-
 security/keys/permission.c        |   14 +--
 security/keys/proc.c              |   44 ++++----
 security/keys/process_keys.c      |   15 ++--
 security/keys/request_key.c       |    6 +-
 85 files changed, 1056 insertions(+), 564 deletions(-)

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [REVIEW][PATCH 01/15] userns: Enable building of pf_key sockets when user namespace support is enabled.
  2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
@ 2012-08-25 23:58 ` Eric W. Biederman
  2012-08-25 23:59 ` [REVIEW][PATCH 02/15] userns: Make credential debugging user namespace safe Eric W. Biederman
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-25 23:58 UTC (permalink / raw)
  To: linux-kernel; +Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller


Enable building of pf_key sockets and user namespace support at the
same time.  This combination builds successfully so there is no reason
to forbid it.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
---
 init/Kconfig |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/init/Kconfig b/init/Kconfig
index b445d6f..448b701 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -944,7 +944,6 @@ config UIDGID_CONVERTED
 	# Networking
 	depends on NET_9P = n
 	depends on AF_RXRPC = n
-	depends on NET_KEY = n
 	depends on DNS_RESOLVER = n
 
 	# Filesystems
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [REVIEW][PATCH 02/15] userns: Make credential debugging user namespace safe.
  2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
  2012-08-25 23:58 ` [REVIEW][PATCH 01/15] userns: Enable building of pf_key sockets when user namespace support is enabled Eric W. Biederman
@ 2012-08-25 23:59 ` Eric W. Biederman
  2012-08-25 23:59 ` [REVIEW][PATCH 03/15] userns: Convert security/keys to the new userns infrastructure Eric W. Biederman
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-25 23:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller, David Howells


Cc: David Howells <dhowells@redhat.com>
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 init/Kconfig  |    1 -
 kernel/cred.c |   10 ++++++++--
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/init/Kconfig b/init/Kconfig
index 448b701..fdabc51 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -936,7 +936,6 @@ config UIDGID_CONVERTED
 	depends on FS_POSIX_ACL = n
 	depends on QUOTA = n
 	depends on QUOTACTL = n
-	depends on DEBUG_CREDENTIALS = n
 	depends on BSD_PROCESS_ACCT = n
 	depends on DRM = n
 	depends on PROC_EVENTS = n
diff --git a/kernel/cred.c b/kernel/cred.c
index de728ac..48cea3d 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -799,9 +799,15 @@ static void dump_invalid_creds(const struct cred *cred, const char *label,
 	       atomic_read(&cred->usage),
 	       read_cred_subscribers(cred));
 	printk(KERN_ERR "CRED: ->*uid = { %d,%d,%d,%d }\n",
-	       cred->uid, cred->euid, cred->suid, cred->fsuid);
+		from_kuid_munged(&init_user_ns, cred->uid),
+		from_kuid_munged(&init_user_ns, cred->euid),
+		from_kuid_munged(&init_user_ns, cred->suid),
+		from_kuid_munged(&init_user_ns, cred->fsuid));
 	printk(KERN_ERR "CRED: ->*gid = { %d,%d,%d,%d }\n",
-	       cred->gid, cred->egid, cred->sgid, cred->fsgid);
+		from_kgid_munged(&init_user_ns, cred->gid),
+		from_kgid_munged(&init_user_ns, cred->egid),
+		from_kgid_munged(&init_user_ns, cred->sgid),
+		from_kgid_munged(&init_user_ns, cred->fsgid));
 #ifdef CONFIG_SECURITY
 	printk(KERN_ERR "CRED: ->security is %p\n", cred->security);
 	if ((unsigned long) cred->security >= PAGE_SIZE &&
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [REVIEW][PATCH 03/15] userns: Convert security/keys to the new userns infrastructure
  2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
  2012-08-25 23:58 ` [REVIEW][PATCH 01/15] userns: Enable building of pf_key sockets when user namespace support is enabled Eric W. Biederman
  2012-08-25 23:59 ` [REVIEW][PATCH 02/15] userns: Make credential debugging user namespace safe Eric W. Biederman
@ 2012-08-25 23:59 ` Eric W. Biederman
  2012-08-26  0:00 ` [REVIEW][PATCH 04/15] userns: net: Call key_alloc with GLOBAL_ROOT_UID, GLOBAL_ROOT_GID instead of 0, 0 Eric W. Biederman
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-25 23:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller,
	linux-security-module, keyrings, David Howells


- Replace key_user ->user_ns equality checks with kuid_has_mapping checks.
- Use from_kuid to generate key descriptions
- Use kuid_t and kgid_t and the associated helpers instead of uid_t and gid_t
- Avoid potential problems with file descriptor passing by displaying
  keys in the user namespace of the opener of key status proc files.

Cc: linux-security-module@vger.kernel.org
Cc: keyrings@linux-nfs.org
Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 include/linux/key.h          |    9 ++++---
 init/Kconfig                 |    1 -
 security/keys/internal.h     |    6 +---
 security/keys/key.c          |   23 ++++++------------
 security/keys/keyctl.c       |   50 +++++++++++++++++++++++++----------------
 security/keys/keyring.c      |    4 +-
 security/keys/permission.c   |   14 +++--------
 security/keys/proc.c         |   44 ++++++++++++++++++------------------
 security/keys/process_keys.c |   15 ++++++------
 security/keys/request_key.c  |    6 ++--
 10 files changed, 84 insertions(+), 88 deletions(-)

diff --git a/include/linux/key.h b/include/linux/key.h
index cef3b31..2393b1c 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -24,6 +24,7 @@
 #include <linux/atomic.h>
 
 #ifdef __KERNEL__
+#include <linux/uidgid.h>
 
 /* key handle serial number */
 typedef int32_t key_serial_t;
@@ -137,8 +138,8 @@ struct key {
 		time_t		revoked_at;	/* time at which key was revoked */
 	};
 	time_t			last_used_at;	/* last time used for LRU keyring discard */
-	uid_t			uid;
-	gid_t			gid;
+	kuid_t			uid;
+	kgid_t			gid;
 	key_perm_t		perm;		/* access permissions */
 	unsigned short		quotalen;	/* length added to quota */
 	unsigned short		datalen;	/* payload data length
@@ -193,7 +194,7 @@ struct key {
 
 extern struct key *key_alloc(struct key_type *type,
 			     const char *desc,
-			     uid_t uid, gid_t gid,
+			     kuid_t uid, kgid_t gid,
 			     const struct cred *cred,
 			     key_perm_t perm,
 			     unsigned long flags);
@@ -262,7 +263,7 @@ extern int key_link(struct key *keyring,
 extern int key_unlink(struct key *keyring,
 		      struct key *key);
 
-extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
+extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
 				 const struct cred *cred,
 				 unsigned long flags,
 				 struct key *dest);
diff --git a/init/Kconfig b/init/Kconfig
index fdabc51..d7f73bb 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -928,7 +928,6 @@ config UIDGID_CONVERTED
 	depends on SYSVIPC = n
 	depends on IMA = n
 	depends on EVM = n
-	depends on KEYS = n
 	depends on AUDIT = n
 	depends on AUDITSYSCALL = n
 	depends on TASKSTATS = n
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 22ff052..8bbefc3 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -52,8 +52,7 @@ struct key_user {
 	atomic_t		usage;		/* for accessing qnkeys & qnbytes */
 	atomic_t		nkeys;		/* number of keys */
 	atomic_t		nikeys;		/* number of instantiated keys */
-	uid_t			uid;
-	struct user_namespace	*user_ns;
+	kuid_t			uid;
 	int			qnkeys;		/* number of keys allocated to this user */
 	int			qnbytes;	/* number of bytes allocated to this user */
 };
@@ -62,8 +61,7 @@ extern struct rb_root	key_user_tree;
 extern spinlock_t	key_user_lock;
 extern struct key_user	root_key_user;
 
-extern struct key_user *key_user_lookup(uid_t uid,
-					struct user_namespace *user_ns);
+extern struct key_user *key_user_lookup(kuid_t uid);
 extern void key_user_put(struct key_user *user);
 
 /*
diff --git a/security/keys/key.c b/security/keys/key.c
index 50d96d4..4289c5b 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -18,7 +18,6 @@
 #include <linux/workqueue.h>
 #include <linux/random.h>
 #include <linux/err.h>
-#include <linux/user_namespace.h>
 #include "internal.h"
 
 struct kmem_cache *key_jar;
@@ -52,7 +51,7 @@ void __key_check(const struct key *key)
  * Get the key quota record for a user, allocating a new record if one doesn't
  * already exist.
  */
-struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
+struct key_user *key_user_lookup(kuid_t uid)
 {
 	struct key_user *candidate = NULL, *user;
 	struct rb_node *parent = NULL;
@@ -67,13 +66,9 @@ try_again:
 		parent = *p;
 		user = rb_entry(parent, struct key_user, node);
 
-		if (uid < user->uid)
+		if (uid_lt(uid, user->uid))
 			p = &(*p)->rb_left;
-		else if (uid > user->uid)
-			p = &(*p)->rb_right;
-		else if (user_ns < user->user_ns)
-			p = &(*p)->rb_left;
-		else if (user_ns > user->user_ns)
+		else if (uid_gt(uid, user->uid))
 			p = &(*p)->rb_right;
 		else
 			goto found;
@@ -102,7 +97,6 @@ try_again:
 	atomic_set(&candidate->nkeys, 0);
 	atomic_set(&candidate->nikeys, 0);
 	candidate->uid = uid;
-	candidate->user_ns = get_user_ns(user_ns);
 	candidate->qnkeys = 0;
 	candidate->qnbytes = 0;
 	spin_lock_init(&candidate->lock);
@@ -131,7 +125,6 @@ void key_user_put(struct key_user *user)
 	if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
 		rb_erase(&user->node, &key_user_tree);
 		spin_unlock(&key_user_lock);
-		put_user_ns(user->user_ns);
 
 		kfree(user);
 	}
@@ -229,7 +222,7 @@ serial_exists:
  * key_alloc() calls don't race with module unloading.
  */
 struct key *key_alloc(struct key_type *type, const char *desc,
-		      uid_t uid, gid_t gid, const struct cred *cred,
+		      kuid_t uid, kgid_t gid, const struct cred *cred,
 		      key_perm_t perm, unsigned long flags)
 {
 	struct key_user *user = NULL;
@@ -253,16 +246,16 @@ struct key *key_alloc(struct key_type *type, const char *desc,
 	quotalen = desclen + type->def_datalen;
 
 	/* get hold of the key tracking for this user */
-	user = key_user_lookup(uid, cred->user_ns);
+	user = key_user_lookup(uid);
 	if (!user)
 		goto no_memory_1;
 
 	/* check that the user's quota permits allocation of another key and
 	 * its description */
 	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
-		unsigned maxkeys = (uid == 0) ?
+		unsigned maxkeys = uid_eq(uid, GLOBAL_ROOT_UID) ?
 			key_quota_root_maxkeys : key_quota_maxkeys;
-		unsigned maxbytes = (uid == 0) ?
+		unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ?
 			key_quota_root_maxbytes : key_quota_maxbytes;
 
 		spin_lock(&user->lock);
@@ -380,7 +373,7 @@ int key_payload_reserve(struct key *key, size_t datalen)
 
 	/* contemplate the quota adjustment */
 	if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
-		unsigned maxbytes = (key->user->uid == 0) ?
+		unsigned maxbytes = uid_eq(key->user->uid, GLOBAL_ROOT_UID) ?
 			key_quota_root_maxbytes : key_quota_maxbytes;
 
 		spin_lock(&key->user->lock);
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 3364fbf..1ecc0f7 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -569,8 +569,8 @@ okay:
 	ret = snprintf(tmpbuf, PAGE_SIZE - 1,
 		       "%s;%d;%d;%08x;%s",
 		       key->type->name,
-		       key->uid,
-		       key->gid,
+		       from_kuid_munged(current_user_ns(), key->uid),
+		       from_kgid_munged(current_user_ns(), key->gid),
 		       key->perm,
 		       key->description ?: "");
 
@@ -766,15 +766,25 @@ error:
  *
  * If successful, 0 will be returned.
  */
-long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
+long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
 {
 	struct key_user *newowner, *zapowner = NULL;
 	struct key *key;
 	key_ref_t key_ref;
 	long ret;
+	kuid_t uid;
+	kgid_t gid;
+
+	uid = make_kuid(current_user_ns(), user);
+	gid = make_kgid(current_user_ns(), group);
+	ret = -EINVAL;
+	if ((user != (uid_t) -1) && !uid_valid(uid))
+		goto error;
+	if ((group != (gid_t) -1) && !gid_valid(gid))
+		goto error;
 
 	ret = 0;
-	if (uid == (uid_t) -1 && gid == (gid_t) -1)
+	if (user == (uid_t) -1 && group == (gid_t) -1)
 		goto error;
 
 	key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
@@ -792,27 +802,27 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
 
 	if (!capable(CAP_SYS_ADMIN)) {
 		/* only the sysadmin can chown a key to some other UID */
-		if (uid != (uid_t) -1 && key->uid != uid)
+		if (user != (uid_t) -1 && !uid_eq(key->uid, uid))
 			goto error_put;
 
 		/* only the sysadmin can set the key's GID to a group other
 		 * than one of those that the current process subscribes to */
-		if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
+		if (group != (gid_t) -1 && !gid_eq(gid, key->gid) && !in_group_p(gid))
 			goto error_put;
 	}
 
 	/* change the UID */
-	if (uid != (uid_t) -1 && uid != key->uid) {
+	if (user != (uid_t) -1 && !uid_eq(uid, key->uid)) {
 		ret = -ENOMEM;
-		newowner = key_user_lookup(uid, current_user_ns());
+		newowner = key_user_lookup(uid);
 		if (!newowner)
 			goto error_put;
 
 		/* transfer the quota burden to the new user */
 		if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
-			unsigned maxkeys = (uid == 0) ?
+			unsigned maxkeys = uid_eq(uid, GLOBAL_ROOT_UID) ?
 				key_quota_root_maxkeys : key_quota_maxkeys;
-			unsigned maxbytes = (uid == 0) ?
+			unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ?
 				key_quota_root_maxbytes : key_quota_maxbytes;
 
 			spin_lock(&newowner->lock);
@@ -846,7 +856,7 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
 	}
 
 	/* change the GID */
-	if (gid != (gid_t) -1)
+	if (group != (gid_t) -1)
 		key->gid = gid;
 
 	ret = 0;
@@ -897,7 +907,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
 	down_write(&key->sem);
 
 	/* if we're not the sysadmin, we can only change a key that we own */
-	if (capable(CAP_SYS_ADMIN) || key->uid == current_fsuid()) {
+	if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) {
 		key->perm = perm;
 		ret = 0;
 	}
@@ -1507,18 +1517,18 @@ long keyctl_session_to_parent(void)
 
 	/* the parent must have the same effective ownership and mustn't be
 	 * SUID/SGID */
-	if (pcred->uid	!= mycred->euid	||
-	    pcred->euid	!= mycred->euid	||
-	    pcred->suid	!= mycred->euid	||
-	    pcred->gid	!= mycred->egid	||
-	    pcred->egid	!= mycred->egid	||
-	    pcred->sgid	!= mycred->egid)
+	if (!uid_eq(pcred->uid,	 mycred->euid) ||
+	    !uid_eq(pcred->euid, mycred->euid) ||
+	    !uid_eq(pcred->suid, mycred->euid) ||
+	    !gid_eq(pcred->gid,	 mycred->egid) ||
+	    !gid_eq(pcred->egid, mycred->egid) ||
+	    !gid_eq(pcred->sgid, mycred->egid))
 		goto unlock;
 
 	/* the keyrings must have the same UID */
 	if ((pcred->tgcred->session_keyring &&
-	     pcred->tgcred->session_keyring->uid != mycred->euid) ||
-	    mycred->tgcred->session_keyring->uid != mycred->euid)
+	     !uid_eq(pcred->tgcred->session_keyring->uid, mycred->euid)) ||
+	    !uid_eq(mycred->tgcred->session_keyring->uid, mycred->euid))
 		goto unlock;
 
 	/* cancel an already pending keyring replacement */
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 81e7852..a5f5c4b 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -256,7 +256,7 @@ error:
 /*
  * Allocate a keyring and link into the destination keyring.
  */
-struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
+struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
 			  const struct cred *cred, unsigned long flags,
 			  struct key *dest)
 {
@@ -612,7 +612,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
 				    &keyring_name_hash[bucket],
 				    type_data.link
 				    ) {
-			if (keyring->user->user_ns != current_user_ns())
+			if (!kuid_has_mapping(current_user_ns(), keyring->user->uid))
 				continue;
 
 			if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
diff --git a/security/keys/permission.c b/security/keys/permission.c
index 0b4d019..efcc0c8 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -36,33 +36,27 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
 
 	key = key_ref_to_ptr(key_ref);
 
-	if (key->user->user_ns != cred->user_ns)
-		goto use_other_perms;
-
 	/* use the second 8-bits of permissions for keys the caller owns */
-	if (key->uid == cred->fsuid) {
+	if (uid_eq(key->uid, cred->fsuid)) {
 		kperm = key->perm >> 16;
 		goto use_these_perms;
 	}
 
 	/* use the third 8-bits of permissions for keys the caller has a group
 	 * membership in common with */
-	if (key->gid != -1 && key->perm & KEY_GRP_ALL) {
-		if (key->gid == cred->fsgid) {
+	if (gid_valid(key->gid) && key->perm & KEY_GRP_ALL) {
+		if (gid_eq(key->gid, cred->fsgid)) {
 			kperm = key->perm >> 8;
 			goto use_these_perms;
 		}
 
-		ret = groups_search(cred->group_info,
-				    make_kgid(current_user_ns(), key->gid));
+		ret = groups_search(cred->group_info, key->gid);
 		if (ret) {
 			kperm = key->perm >> 8;
 			goto use_these_perms;
 		}
 	}
 
-use_other_perms:
-
 	/* otherwise use the least-significant 8-bits */
 	kperm = key->perm;
 
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 30d1ddf..217b685 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -88,14 +88,14 @@ __initcall(key_proc_init);
  */
 #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
 
-static struct rb_node *key_serial_next(struct rb_node *n)
+static struct rb_node *key_serial_next(struct seq_file *p, struct rb_node *n)
 {
-	struct user_namespace *user_ns = current_user_ns();
+	struct user_namespace *user_ns = seq_user_ns(p);
 
 	n = rb_next(n);
 	while (n) {
 		struct key *key = rb_entry(n, struct key, serial_node);
-		if (key->user->user_ns == user_ns)
+		if (kuid_has_mapping(user_ns, key->user->uid))
 			break;
 		n = rb_next(n);
 	}
@@ -107,9 +107,9 @@ static int proc_keys_open(struct inode *inode, struct file *file)
 	return seq_open(file, &proc_keys_ops);
 }
 
-static struct key *find_ge_key(key_serial_t id)
+static struct key *find_ge_key(struct seq_file *p, key_serial_t id)
 {
-	struct user_namespace *user_ns = current_user_ns();
+	struct user_namespace *user_ns = seq_user_ns(p);
 	struct rb_node *n = key_serial_tree.rb_node;
 	struct key *minkey = NULL;
 
@@ -132,7 +132,7 @@ static struct key *find_ge_key(key_serial_t id)
 		return NULL;
 
 	for (;;) {
-		if (minkey->user->user_ns == user_ns)
+		if (kuid_has_mapping(user_ns, minkey->user->uid))
 			return minkey;
 		n = rb_next(&minkey->serial_node);
 		if (!n)
@@ -151,7 +151,7 @@ static void *proc_keys_start(struct seq_file *p, loff_t *_pos)
 
 	if (*_pos > INT_MAX)
 		return NULL;
-	key = find_ge_key(pos);
+	key = find_ge_key(p, pos);
 	if (!key)
 		return NULL;
 	*_pos = key->serial;
@@ -168,7 +168,7 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos)
 {
 	struct rb_node *n;
 
-	n = key_serial_next(v);
+	n = key_serial_next(p, v);
 	if (n)
 		*_pos = key_node_serial(n);
 	return n;
@@ -254,8 +254,8 @@ static int proc_keys_show(struct seq_file *m, void *v)
 		   atomic_read(&key->usage),
 		   xbuf,
 		   key->perm,
-		   key->uid,
-		   key->gid,
+		   from_kuid_munged(seq_user_ns(m), key->uid),
+		   from_kgid_munged(seq_user_ns(m), key->gid),
 		   key->type->name);
 
 #undef showflag
@@ -270,26 +270,26 @@ static int proc_keys_show(struct seq_file *m, void *v)
 
 #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */
 
-static struct rb_node *__key_user_next(struct rb_node *n)
+static struct rb_node *__key_user_next(struct user_namespace *user_ns, struct rb_node *n)
 {
 	while (n) {
 		struct key_user *user = rb_entry(n, struct key_user, node);
-		if (user->user_ns == current_user_ns())
+		if (kuid_has_mapping(user_ns, user->uid))
 			break;
 		n = rb_next(n);
 	}
 	return n;
 }
 
-static struct rb_node *key_user_next(struct rb_node *n)
+static struct rb_node *key_user_next(struct user_namespace *user_ns, struct rb_node *n)
 {
-	return __key_user_next(rb_next(n));
+	return __key_user_next(user_ns, rb_next(n));
 }
 
-static struct rb_node *key_user_first(struct rb_root *r)
+static struct rb_node *key_user_first(struct user_namespace *user_ns, struct rb_root *r)
 {
 	struct rb_node *n = rb_first(r);
-	return __key_user_next(n);
+	return __key_user_next(user_ns, n);
 }
 
 /*
@@ -309,10 +309,10 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
 
 	spin_lock(&key_user_lock);
 
-	_p = key_user_first(&key_user_tree);
+	_p = key_user_first(seq_user_ns(p), &key_user_tree);
 	while (pos > 0 && _p) {
 		pos--;
-		_p = key_user_next(_p);
+		_p = key_user_next(seq_user_ns(p), _p);
 	}
 
 	return _p;
@@ -321,7 +321,7 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
 static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
 {
 	(*_pos)++;
-	return key_user_next((struct rb_node *)v);
+	return key_user_next(seq_user_ns(p), (struct rb_node *)v);
 }
 
 static void proc_key_users_stop(struct seq_file *p, void *v)
@@ -334,13 +334,13 @@ static int proc_key_users_show(struct seq_file *m, void *v)
 {
 	struct rb_node *_p = v;
 	struct key_user *user = rb_entry(_p, struct key_user, node);
-	unsigned maxkeys = (user->uid == 0) ?
+	unsigned maxkeys = uid_eq(user->uid, GLOBAL_ROOT_UID) ?
 		key_quota_root_maxkeys : key_quota_maxkeys;
-	unsigned maxbytes = (user->uid == 0) ?
+	unsigned maxbytes = uid_eq(user->uid, GLOBAL_ROOT_UID) ?
 		key_quota_root_maxbytes : key_quota_maxbytes;
 
 	seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n",
-		   user->uid,
+		   from_kuid_munged(seq_user_ns(m), user->uid),
 		   atomic_read(&user->usage),
 		   atomic_read(&user->nkeys),
 		   atomic_read(&user->nikeys),
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 54339cf..a58f712 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -34,8 +34,7 @@ struct key_user root_key_user = {
 	.lock		= __SPIN_LOCK_UNLOCKED(root_key_user.lock),
 	.nkeys		= ATOMIC_INIT(2),
 	.nikeys		= ATOMIC_INIT(2),
-	.uid		= 0,
-	.user_ns	= &init_user_ns,
+	.uid		= GLOBAL_ROOT_UID,
 };
 
 /*
@@ -48,11 +47,13 @@ int install_user_keyrings(void)
 	struct key *uid_keyring, *session_keyring;
 	char buf[20];
 	int ret;
+	uid_t uid;
 
 	cred = current_cred();
 	user = cred->user;
+	uid = from_kuid(cred->user_ns, user->uid);
 
-	kenter("%p{%u}", user, user->uid);
+	kenter("%p{%u}", user, uid);
 
 	if (user->uid_keyring) {
 		kleave(" = 0 [exist]");
@@ -67,11 +68,11 @@ int install_user_keyrings(void)
 		 * - there may be one in existence already as it may have been
 		 *   pinned by a session, but the user_struct pointing to it
 		 *   may have been destroyed by setuid */
-		sprintf(buf, "_uid.%u", user->uid);
+		sprintf(buf, "_uid.%u", uid);
 
 		uid_keyring = find_keyring_by_name(buf, true);
 		if (IS_ERR(uid_keyring)) {
-			uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
+			uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID,
 						    cred, KEY_ALLOC_IN_QUOTA,
 						    NULL);
 			if (IS_ERR(uid_keyring)) {
@@ -82,12 +83,12 @@ int install_user_keyrings(void)
 
 		/* get a default session keyring (which might also exist
 		 * already) */
-		sprintf(buf, "_uid_ses.%u", user->uid);
+		sprintf(buf, "_uid_ses.%u", uid);
 
 		session_keyring = find_keyring_by_name(buf, true);
 		if (IS_ERR(session_keyring)) {
 			session_keyring =
-				keyring_alloc(buf, user->uid, (gid_t) -1,
+				keyring_alloc(buf, user->uid, INVALID_GID,
 					      cred, KEY_ALLOC_IN_QUOTA, NULL);
 			if (IS_ERR(session_keyring)) {
 				ret = PTR_ERR(session_keyring);
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 000e750..66e2118 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -139,8 +139,8 @@ static int call_sbin_request_key(struct key_construction *cons,
 		goto error_link;
 
 	/* record the UID and GID */
-	sprintf(uid_str, "%d", cred->fsuid);
-	sprintf(gid_str, "%d", cred->fsgid);
+	sprintf(uid_str, "%d", from_kuid(&init_user_ns, cred->fsuid));
+	sprintf(gid_str, "%d", from_kgid(&init_user_ns, cred->fsgid));
 
 	/* we say which key is under construction */
 	sprintf(key_str, "%d", key->serial);
@@ -442,7 +442,7 @@ static struct key *construct_key_and_link(struct key_type *type,
 
 	kenter("");
 
-	user = key_user_lookup(current_fsuid(), current_user_ns());
+	user = key_user_lookup(current_fsuid());
 	if (!user)
 		return ERR_PTR(-ENOMEM);
 
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [REVIEW][PATCH 04/15] userns: net: Call key_alloc with GLOBAL_ROOT_UID, GLOBAL_ROOT_GID instead of 0, 0
  2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
                   ` (2 preceding siblings ...)
  2012-08-25 23:59 ` [REVIEW][PATCH 03/15] userns: Convert security/keys to the new userns infrastructure Eric W. Biederman
@ 2012-08-26  0:00 ` Eric W. Biederman
  2012-08-26  0:00 ` [REVIEW][PATCH 05/15] userns: Convert ipc to use kuid and kgid where appropriate Eric W. Biederman
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-26  0:00 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller, Sage Weil,
	ceph-devel, David Howells, David Miller, linux-afs

>From 088e7f2778bd228a4ce05f8dfaa4eb999e2207d2 Mon Sep 17 00:00:00 2001
From: "Eric W. Biederman" <ebiederm@xmission.com>
Date: Fri, 25 May 2012 16:37:54 -0600
Subject: 

In net/dns_resolver/dns_key.c and net/rxrpc/ar-key.c make them
work with user namespaces enabled where key_alloc takes kuids and kgids.
Pass GLOBAL_ROOT_UID and GLOBAL_ROOT_GID instead of bare 0's.

Cc: Sage Weil <sage@inktank.com>
Cc: ceph-devel@vger.kernel.org
Cc: David Howells <dhowells@redhat.com>
Cc: David Miller <davem@davemloft.net>
Cc: linux-afs@lists.infradead.org
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 init/Kconfig               |    2 --
 net/dns_resolver/dns_key.c |    3 ++-
 net/rxrpc/ar-key.c         |    6 ++++--
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/init/Kconfig b/init/Kconfig
index d7f73bb..28715ec 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -941,8 +941,6 @@ config UIDGID_CONVERTED
 
 	# Networking
 	depends on NET_9P = n
-	depends on AF_RXRPC = n
-	depends on DNS_RESOLVER = n
 
 	# Filesystems
 	depends on USB_GADGETFS = n
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
index d9507dd..9807945 100644
--- a/net/dns_resolver/dns_key.c
+++ b/net/dns_resolver/dns_key.c
@@ -259,7 +259,8 @@ static int __init init_dns_resolver(void)
 	if (!cred)
 		return -ENOMEM;
 
-	keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred,
+	keyring = key_alloc(&key_type_keyring, ".dns_resolver",
+			    GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
 			    (KEY_POS_ALL & ~KEY_POS_SETATTR) |
 			    KEY_USR_VIEW | KEY_USR_READ,
 			    KEY_ALLOC_NOT_IN_QUOTA);
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
index 8b1f9f4..011d238 100644
--- a/net/rxrpc/ar-key.c
+++ b/net/rxrpc/ar-key.c
@@ -948,7 +948,8 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
 
 	_enter("");
 
-	key = key_alloc(&key_type_rxrpc, "x", 0, 0, cred, 0,
+	key = key_alloc(&key_type_rxrpc, "x",
+			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0,
 			KEY_ALLOC_NOT_IN_QUOTA);
 	if (IS_ERR(key)) {
 		_leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
@@ -994,7 +995,8 @@ struct key *rxrpc_get_null_key(const char *keyname)
 	struct key *key;
 	int ret;
 
-	key = key_alloc(&key_type_rxrpc, keyname, 0, 0, cred,
+	key = key_alloc(&key_type_rxrpc, keyname,
+			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
 			KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
 	if (IS_ERR(key))
 		return key;
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [REVIEW][PATCH 05/15] userns: Convert ipc to use kuid and kgid where appropriate
  2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
                   ` (3 preceding siblings ...)
  2012-08-26  0:00 ` [REVIEW][PATCH 04/15] userns: net: Call key_alloc with GLOBAL_ROOT_UID, GLOBAL_ROOT_GID instead of 0, 0 Eric W. Biederman
@ 2012-08-26  0:00 ` Eric W. Biederman
  2012-08-26  0:01 ` [REVIEW][PATCH 07/15] userns: Convert taskstats to handle the user and pid namespaces Eric W. Biederman
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-26  0:00 UTC (permalink / raw)
  To: linux-kernel; +Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller


- Store the ipc owner and creator with a kuid
- Store the ipc group and the crators group with a kgid.
- Add error handling to ipc_update_perms, allowing it to
  fail if the uids and gids can not be converted to kuids
  or kgids.
- Modify the proc files to display the ipc creator and
  owner in the user namespace of the opener of the proc file.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 include/linux/ipc.h |    9 +++++----
 init/Kconfig        |    1 -
 ipc/msg.c           |   14 +++++++++-----
 ipc/sem.c           |   13 ++++++++-----
 ipc/shm.c           |   19 +++++++++++--------
 ipc/util.c          |   35 +++++++++++++++++++++--------------
 ipc/util.h          |    2 +-
 7 files changed, 55 insertions(+), 38 deletions(-)

diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index 30e8161..ca833fd 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -79,6 +79,7 @@ struct ipc_kludge {
 
 #ifdef __KERNEL__
 #include <linux/spinlock.h>
+#include <linux/uidgid.h>
 
 #define IPCMNI 32768  /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
 
@@ -89,10 +90,10 @@ struct kern_ipc_perm
 	int		deleted;
 	int		id;
 	key_t		key;
-	uid_t		uid;
-	gid_t		gid;
-	uid_t		cuid;
-	gid_t		cgid;
+	kuid_t		uid;
+	kgid_t		gid;
+	kuid_t		cuid;
+	kgid_t		cgid;
 	umode_t		mode; 
 	unsigned long	seq;
 	void		*security;
diff --git a/init/Kconfig b/init/Kconfig
index 28715ec..4daf449 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -925,7 +925,6 @@ config UIDGID_CONVERTED
 
 	# List of kernel pieces that need user namespace work
 	# Features
-	depends on SYSVIPC = n
 	depends on IMA = n
 	depends on EVM = n
 	depends on AUDIT = n
diff --git a/ipc/msg.c b/ipc/msg.c
index 7385de2..a71af5a 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -443,9 +443,12 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
 			goto out_unlock;
 		}
 
+		err = ipc_update_perm(&msqid64.msg_perm, ipcp);
+		if (err)
+			goto out_unlock;
+
 		msq->q_qbytes = msqid64.msg_qbytes;
 
-		ipc_update_perm(&msqid64.msg_perm, ipcp);
 		msq->q_ctime = get_seconds();
 		/* sleeping receivers might be excluded by
 		 * stricter permissions.
@@ -922,6 +925,7 @@ out:
 #ifdef CONFIG_PROC_FS
 static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
 {
+	struct user_namespace *user_ns = seq_user_ns(s);
 	struct msg_queue *msq = it;
 
 	return seq_printf(s,
@@ -933,10 +937,10 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
 			msq->q_qnum,
 			msq->q_lspid,
 			msq->q_lrpid,
-			msq->q_perm.uid,
-			msq->q_perm.gid,
-			msq->q_perm.cuid,
-			msq->q_perm.cgid,
+			from_kuid_munged(user_ns, msq->q_perm.uid),
+			from_kgid_munged(user_ns, msq->q_perm.gid),
+			from_kuid_munged(user_ns, msq->q_perm.cuid),
+			from_kgid_munged(user_ns, msq->q_perm.cgid),
 			msq->q_stime,
 			msq->q_rtime,
 			msq->q_ctime);
diff --git a/ipc/sem.c b/ipc/sem.c
index 5215a81..58d31f1 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1104,7 +1104,9 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
 		freeary(ns, ipcp);
 		goto out_up;
 	case IPC_SET:
-		ipc_update_perm(&semid64.sem_perm, ipcp);
+		err = ipc_update_perm(&semid64.sem_perm, ipcp);
+		if (err)
+			goto out_unlock;
 		sma->sem_ctime = get_seconds();
 		break;
 	default:
@@ -1677,6 +1679,7 @@ void exit_sem(struct task_struct *tsk)
 #ifdef CONFIG_PROC_FS
 static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
 {
+	struct user_namespace *user_ns = seq_user_ns(s);
 	struct sem_array *sma = it;
 
 	return seq_printf(s,
@@ -1685,10 +1688,10 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
 			  sma->sem_perm.id,
 			  sma->sem_perm.mode,
 			  sma->sem_nsems,
-			  sma->sem_perm.uid,
-			  sma->sem_perm.gid,
-			  sma->sem_perm.cuid,
-			  sma->sem_perm.cgid,
+			  from_kuid_munged(user_ns, sma->sem_perm.uid),
+			  from_kgid_munged(user_ns, sma->sem_perm.gid),
+			  from_kuid_munged(user_ns, sma->sem_perm.cuid),
+			  from_kgid_munged(user_ns, sma->sem_perm.cgid),
 			  sma->sem_otime,
 			  sma->sem_ctime);
 }
diff --git a/ipc/shm.c b/ipc/shm.c
index 00faa05..dff40c9 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -758,7 +758,9 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
 		do_shm_rmid(ns, ipcp);
 		goto out_up;
 	case IPC_SET:
-		ipc_update_perm(&shmid64.shm_perm, ipcp);
+		err = ipc_update_perm(&shmid64.shm_perm, ipcp);
+		if (err)
+			goto out_unlock;
 		shp->shm_ctim = get_seconds();
 		break;
 	default:
@@ -893,10 +895,10 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
 		audit_ipc_obj(&(shp->shm_perm));
 
 		if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
-			uid_t euid = current_euid();
+			kuid_t euid = current_euid();
 			err = -EPERM;
-			if (euid != shp->shm_perm.uid &&
-			    euid != shp->shm_perm.cuid)
+			if (!uid_eq(euid, shp->shm_perm.uid) &&
+			    !uid_eq(euid, shp->shm_perm.cuid))
 				goto out_unlock;
 			if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
 				goto out_unlock;
@@ -1220,6 +1222,7 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
 #ifdef CONFIG_PROC_FS
 static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
 {
+	struct user_namespace *user_ns = seq_user_ns(s);
 	struct shmid_kernel *shp = it;
 	unsigned long rss = 0, swp = 0;
 
@@ -1242,10 +1245,10 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
 			  shp->shm_cprid,
 			  shp->shm_lprid,
 			  shp->shm_nattch,
-			  shp->shm_perm.uid,
-			  shp->shm_perm.gid,
-			  shp->shm_perm.cuid,
-			  shp->shm_perm.cgid,
+			  from_kuid_munged(user_ns, shp->shm_perm.uid),
+			  from_kgid_munged(user_ns, shp->shm_perm.gid),
+			  from_kuid_munged(user_ns, shp->shm_perm.cuid),
+			  from_kgid_munged(user_ns, shp->shm_perm.cgid),
 			  shp->shm_atim,
 			  shp->shm_dtim,
 			  shp->shm_ctim,
diff --git a/ipc/util.c b/ipc/util.c
index eb07fd3..72fd078 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -249,8 +249,8 @@ int ipc_get_maxid(struct ipc_ids *ids)
  
 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
 {
-	uid_t euid;
-	gid_t egid;
+	kuid_t euid;
+	kgid_t egid;
 	int id, err;
 
 	if (size > IPCMNI)
@@ -606,14 +606,14 @@ void ipc_rcu_putref(void *ptr)
  
 int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
 {
-	uid_t euid = current_euid();
+	kuid_t euid = current_euid();
 	int requested_mode, granted_mode;
 
 	audit_ipc_obj(ipcp);
 	requested_mode = (flag >> 6) | (flag >> 3) | flag;
 	granted_mode = ipcp->mode;
-	if (euid == ipcp->cuid ||
-	    euid == ipcp->uid)
+	if (uid_eq(euid, ipcp->cuid) ||
+	    uid_eq(euid, ipcp->uid))
 		granted_mode >>= 6;
 	else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
 		granted_mode >>= 3;
@@ -643,10 +643,10 @@ int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
 void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
 {
 	out->key	= in->key;
-	out->uid	= in->uid;
-	out->gid	= in->gid;
-	out->cuid	= in->cuid;
-	out->cgid	= in->cgid;
+	out->uid	= from_kuid_munged(current_user_ns(), in->uid);
+	out->gid	= from_kgid_munged(current_user_ns(), in->gid);
+	out->cuid	= from_kuid_munged(current_user_ns(), in->cuid);
+	out->cgid	= from_kgid_munged(current_user_ns(), in->cgid);
 	out->mode	= in->mode;
 	out->seq	= in->seq;
 }
@@ -747,12 +747,19 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
  * @in:  the permission given as input.
  * @out: the permission of the ipc to set.
  */
-void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
+int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
 {
-	out->uid = in->uid;
-	out->gid = in->gid;
+	kuid_t uid = make_kuid(current_user_ns(), in->uid);
+	kgid_t gid = make_kgid(current_user_ns(), in->gid);
+	if (!uid_valid(uid) || !gid_valid(gid))
+		return -EINVAL;
+
+	out->uid = uid;
+	out->gid = gid;
 	out->mode = (out->mode & ~S_IRWXUGO)
 		| (in->mode & S_IRWXUGO);
+
+	return 0;
 }
 
 /**
@@ -777,7 +784,7 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
 				      struct ipc64_perm *perm, int extra_perm)
 {
 	struct kern_ipc_perm *ipcp;
-	uid_t euid;
+	kuid_t euid;
 	int err;
 
 	down_write(&ids->rw_mutex);
@@ -793,7 +800,7 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
 					 perm->gid, perm->mode);
 
 	euid = current_euid();
-	if (euid == ipcp->cuid || euid == ipcp->uid  ||
+	if (uid_eq(euid, ipcp->cuid) || uid_eq(euid, ipcp->uid)  ||
 	    ns_capable(ns->user_ns, CAP_SYS_ADMIN))
 		return ipcp;
 
diff --git a/ipc/util.h b/ipc/util.h
index 850ef3e..c8fe2f7 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -125,7 +125,7 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
 
 void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
 void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
-void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
+int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
 struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
 				      struct ipc_ids *ids, int id, int cmd,
 				      struct ipc64_perm *perm, int extra_perm);
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [REVIEW][PATCH 07/15] userns: Convert taskstats to handle the user and pid namespaces.
  2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
                   ` (4 preceding siblings ...)
  2012-08-26  0:00 ` [REVIEW][PATCH 05/15] userns: Convert ipc to use kuid and kgid where appropriate Eric W. Biederman
@ 2012-08-26  0:01 ` Eric W. Biederman
  2012-08-26  0:02 ` [REVIEW][PATCH 09/15] userns: Convert process event connector to handle kuids and kgids Eric W. Biederman
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-26  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller, Balbir Singh


- Explicitly limit exit task stat broadcast to the initial user and
  pid namespaces, as it is already limited to the initial network
  namespace.

- For broadcast task stats explicitly generate all of the idenitiers
  in terms of the initial user namespace and the initial pid
  namespace.

- For request stats report them in terms of the current user namespace
  and the current pid namespace.  Netlink messages are delivered
  syncrhonously to the kernel allowing us to get the user namespace
  and the pid namespace from the current task.

- Pass the namespaces for representing pids and uids and gids
  into bacct_add_task.

Cc: Balbir Singh <bsingharora@gmail.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 include/linux/tsacct_kern.h |    8 ++++++--
 init/Kconfig                |    1 -
 kernel/taskstats.c          |   23 +++++++++++++++++------
 kernel/tsacct.c             |   12 +++++++-----
 4 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/include/linux/tsacct_kern.h b/include/linux/tsacct_kern.h
index 7e50ac7..44893e5 100644
--- a/include/linux/tsacct_kern.h
+++ b/include/linux/tsacct_kern.h
@@ -10,9 +10,13 @@
 #include <linux/taskstats.h>
 
 #ifdef CONFIG_TASKSTATS
-extern void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk);
+extern void bacct_add_tsk(struct user_namespace *user_ns,
+			  struct pid_namespace *pid_ns,
+			  struct taskstats *stats, struct task_struct *tsk);
 #else
-static inline void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
+static inline void bacct_add_tsk(struct user_namespace *user_ns,
+				 struct pid_namespace *pid_ns,
+				 struct taskstats *stats, struct task_struct *tsk)
 {}
 #endif /* CONFIG_TASKSTATS */
 
diff --git a/init/Kconfig b/init/Kconfig
index 525f4e8..965a700 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -927,7 +927,6 @@ config UIDGID_CONVERTED
 	# Features
 	depends on IMA = n
 	depends on EVM = n
-	depends on TASKSTATS = n
 	depends on TRACING = n
 	depends on FS_POSIX_ACL = n
 	depends on QUOTA = n
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index d0a3279..3880df2 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -27,6 +27,7 @@
 #include <linux/cgroup.h>
 #include <linux/fs.h>
 #include <linux/file.h>
+#include <linux/pid_namespace.h>
 #include <net/genetlink.h>
 #include <linux/atomic.h>
 
@@ -174,7 +175,9 @@ static void send_cpu_listeners(struct sk_buff *skb,
 	up_write(&listeners->sem);
 }
 
-static void fill_stats(struct task_struct *tsk, struct taskstats *stats)
+static void fill_stats(struct user_namespace *user_ns,
+		       struct pid_namespace *pid_ns,
+		       struct task_struct *tsk, struct taskstats *stats)
 {
 	memset(stats, 0, sizeof(*stats));
 	/*
@@ -190,7 +193,7 @@ static void fill_stats(struct task_struct *tsk, struct taskstats *stats)
 	stats->version = TASKSTATS_VERSION;
 	stats->nvcsw = tsk->nvcsw;
 	stats->nivcsw = tsk->nivcsw;
-	bacct_add_tsk(stats, tsk);
+	bacct_add_tsk(user_ns, pid_ns, stats, tsk);
 
 	/* fill in extended acct fields */
 	xacct_add_tsk(stats, tsk);
@@ -207,7 +210,7 @@ static int fill_stats_for_pid(pid_t pid, struct taskstats *stats)
 	rcu_read_unlock();
 	if (!tsk)
 		return -ESRCH;
-	fill_stats(tsk, stats);
+	fill_stats(current_user_ns(), task_active_pid_ns(current), tsk, stats);
 	put_task_struct(tsk);
 	return 0;
 }
@@ -291,6 +294,12 @@ static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
 	if (!cpumask_subset(mask, cpu_possible_mask))
 		return -EINVAL;
 
+	if (current_user_ns() != &init_user_ns)
+		return -EINVAL;
+
+	if (task_active_pid_ns(current) != &init_pid_ns)
+		return -EINVAL;
+
 	if (isadd == REGISTER) {
 		for_each_cpu(cpu, mask) {
 			s = kmalloc_node(sizeof(struct listener),
@@ -631,11 +640,12 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
 	if (rc < 0)
 		return;
 
-	stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID, tsk->pid);
+	stats = mk_reply(rep_skb, TASKSTATS_TYPE_PID,
+			 task_pid_nr_ns(tsk, &init_pid_ns));
 	if (!stats)
 		goto err;
 
-	fill_stats(tsk, stats);
+	fill_stats(&init_user_ns, &init_pid_ns, tsk, stats);
 
 	/*
 	 * Doesn't matter if tsk is the leader or the last group member leaving
@@ -643,7 +653,8 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
 	if (!is_thread_group || !group_dead)
 		goto send;
 
-	stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID, tsk->tgid);
+	stats = mk_reply(rep_skb, TASKSTATS_TYPE_TGID,
+			 task_tgid_nr_ns(tsk, &init_pid_ns));
 	if (!stats)
 		goto err;
 
diff --git a/kernel/tsacct.c b/kernel/tsacct.c
index 23b4d78..625df0b 100644
--- a/kernel/tsacct.c
+++ b/kernel/tsacct.c
@@ -26,7 +26,9 @@
 /*
  * fill in basic accounting fields
  */
-void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
+void bacct_add_tsk(struct user_namespace *user_ns,
+		   struct pid_namespace *pid_ns,
+		   struct taskstats *stats, struct task_struct *tsk)
 {
 	const struct cred *tcred;
 	struct timespec uptime, ts;
@@ -55,13 +57,13 @@ void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
 		stats->ac_flag |= AXSIG;
 	stats->ac_nice	 = task_nice(tsk);
 	stats->ac_sched	 = tsk->policy;
-	stats->ac_pid	 = tsk->pid;
+	stats->ac_pid	 = task_pid_nr_ns(tsk, pid_ns);
 	rcu_read_lock();
 	tcred = __task_cred(tsk);
-	stats->ac_uid	 = tcred->uid;
-	stats->ac_gid	 = tcred->gid;
+	stats->ac_uid	 = from_kuid_munged(user_ns, tcred->uid);
+	stats->ac_gid	 = from_kgid_munged(user_ns, tcred->gid);
 	stats->ac_ppid	 = pid_alive(tsk) ?
-				rcu_dereference(tsk->real_parent)->tgid : 0;
+		task_tgid_nr_ns(rcu_dereference(tsk->real_parent), pid_ns) : 0;
 	rcu_read_unlock();
 	stats->ac_utime = cputime_to_usecs(tsk->utime);
 	stats->ac_stime = cputime_to_usecs(tsk->stime);
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [REVIEW][PATCH 09/15] userns: Convert process event connector to handle kuids and kgids
  2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
                   ` (5 preceding siblings ...)
  2012-08-26  0:01 ` [REVIEW][PATCH 07/15] userns: Convert taskstats to handle the user and pid namespaces Eric W. Biederman
@ 2012-08-26  0:02 ` Eric W. Biederman
  2012-08-26 12:33   ` Evgeniy Polyakov
  2012-08-26  0:03 ` [REVIEW][PATCH 10/15] userns: Convert debugfs to use kuid/kgid where appropriate Eric W. Biederman
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-26  0:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller,
	Evgeniy Polyakov, David Miller


- Only allow asking for events from the initial user and pid namespace,
  where we generate the events in.

- Convert kuids and kgids into the initial user namespace to report
  them via the process event connector.

Cc: Evgeniy Polyakov <zbr@ioremap.net>
Cc: David Miller <davem@davemloft.net>
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 drivers/connector/cn_proc.c |   18 ++++++++++++++----
 init/Kconfig                |    1 -
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 3e92b7d..fce2000 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -30,6 +30,7 @@
 #include <linux/gfp.h>
 #include <linux/ptrace.h>
 #include <linux/atomic.h>
+#include <linux/pid_namespace.h>
 
 #include <asm/unaligned.h>
 
@@ -127,11 +128,11 @@ void proc_id_connector(struct task_struct *task, int which_id)
 	rcu_read_lock();
 	cred = __task_cred(task);
 	if (which_id == PROC_EVENT_UID) {
-		ev->event_data.id.r.ruid = cred->uid;
-		ev->event_data.id.e.euid = cred->euid;
+		ev->event_data.id.r.ruid = from_kuid_munged(&init_user_ns, cred->uid);
+		ev->event_data.id.e.euid = from_kuid_munged(&init_user_ns, cred->euid);
 	} else if (which_id == PROC_EVENT_GID) {
-		ev->event_data.id.r.rgid = cred->gid;
-		ev->event_data.id.e.egid = cred->egid;
+		ev->event_data.id.r.rgid = from_kgid_munged(&init_user_ns, cred->gid);
+		ev->event_data.id.e.egid = from_kgid_munged(&init_user_ns, cred->egid);
 	} else {
 		rcu_read_unlock();
 		return;
@@ -303,6 +304,15 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,
 	if (msg->len != sizeof(*mc_op))
 		return;
 
+	/* 
+	 * Events are reported with respect to the initial pid
+	 * and user namespaces so ignore requestors from
+	 * other namespaces.
+	 */
+	if ((current_user_ns() != &init_user_ns) ||
+	    (task_active_pid_ns(current) != &init_pid_ns))
+		return;
+
 	mc_op = (enum proc_cn_mcast_op *)msg->data;
 	switch (*mc_op) {
 	case PROC_CN_MCAST_LISTEN:
diff --git a/init/Kconfig b/init/Kconfig
index 6c9d004..7327869 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -932,7 +932,6 @@ config UIDGID_CONVERTED
 	depends on QUOTA = n
 	depends on QUOTACTL = n
 	depends on DRM = n
-	depends on PROC_EVENTS = n
 
 	# Networking
 	depends on NET_9P = n
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [REVIEW][PATCH 10/15] userns: Convert debugfs to use kuid/kgid where appropriate.
  2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
                   ` (6 preceding siblings ...)
  2012-08-26  0:02 ` [REVIEW][PATCH 09/15] userns: Convert process event connector to handle kuids and kgids Eric W. Biederman
@ 2012-08-26  0:03 ` Eric W. Biederman
  2012-09-05 21:09   ` Greg Kroah-Hartman
  2012-08-26  0:04 ` [REVIEW][PATCH 11/15] userns: Teach trace to use from_kuid Eric W. Biederman
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-26  0:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller, Greg Kroah-Hartman


Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 fs/debugfs/inode.c |   26 ++++++++++++++++++--------
 init/Kconfig       |    1 -
 2 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 4733eab..36e2b66 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -128,8 +128,8 @@ static inline int debugfs_positive(struct dentry *dentry)
 }
 
 struct debugfs_mount_opts {
-	uid_t uid;
-	gid_t gid;
+	kuid_t uid;
+	kgid_t gid;
 	umode_t mode;
 };
 
@@ -156,6 +156,8 @@ static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts)
 	substring_t args[MAX_OPT_ARGS];
 	int option;
 	int token;
+	kuid_t uid;
+	kgid_t gid;
 	char *p;
 
 	opts->mode = DEBUGFS_DEFAULT_MODE;
@@ -169,12 +171,18 @@ static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts)
 		case Opt_uid:
 			if (match_int(&args[0], &option))
 				return -EINVAL;
-			opts->uid = option;
+			uid = make_kuid(current_user_ns(), option);
+			if (!uid_valid(uid))
+				return -EINVAL;
+			opts->uid = uid;
 			break;
 		case Opt_gid:
 			if (match_octal(&args[0], &option))
 				return -EINVAL;
-			opts->gid = option;
+			gid = make_kgid(current_user_ns(), option);
+			if (!gid_valid(gid))
+				return -EINVAL;
+			opts->gid = gid;
 			break;
 		case Opt_mode:
 			if (match_octal(&args[0], &option))
@@ -226,10 +234,12 @@ static int debugfs_show_options(struct seq_file *m, struct dentry *root)
 	struct debugfs_fs_info *fsi = root->d_sb->s_fs_info;
 	struct debugfs_mount_opts *opts = &fsi->mount_opts;
 
-	if (opts->uid != 0)
-		seq_printf(m, ",uid=%u", opts->uid);
-	if (opts->gid != 0)
-		seq_printf(m, ",gid=%u", opts->gid);
+	if (!uid_eq(opts->uid, GLOBAL_ROOT_UID))
+		seq_printf(m, ",uid=%u",
+			   from_kuid_munged(&init_user_ns, opts->uid));
+	if (!gid_eq(opts->gid, GLOBAL_ROOT_GID))
+		seq_printf(m, ",gid=%u",
+			   from_kgid_munged(&init_user_ns, opts->gid));
 	if (opts->mode != DEBUGFS_DEFAULT_MODE)
 		seq_printf(m, ",mode=%o", opts->mode);
 
diff --git a/init/Kconfig b/init/Kconfig
index 7327869..af41fa7 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -955,7 +955,6 @@ config UIDGID_CONVERTED
 	depends on CODA_FS = n
 	depends on CONFIGFS_FS = n
 	depends on CRAMFS = n
-	depends on DEBUG_FS = n
 	depends on ECRYPT_FS = n
 	depends on EFS_FS = n
 	depends on EXOFS_FS = n
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [REVIEW][PATCH 11/15] userns: Teach trace to use from_kuid
  2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
                   ` (7 preceding siblings ...)
  2012-08-26  0:03 ` [REVIEW][PATCH 10/15] userns: Convert debugfs to use kuid/kgid where appropriate Eric W. Biederman
@ 2012-08-26  0:04 ` Eric W. Biederman
  2012-08-26  0:18   ` Steven Rostedt
  2012-08-26  0:05 ` [REVIEW][PATCH 12/15] userns: Convert drm to use kuid and kgid and struct pid where appropriate Eric W. Biederman
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-26  0:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller,
	Steven Rostedt, Frederic Weisbecker, Ingo Molnar


- When tracing capture the kuid.
- When displaying the data to user space convert the kuid into the
  user namespace of the process that opened the report file.

Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 init/Kconfig         |    1 -
 kernel/trace/trace.c |    3 ++-
 kernel/trace/trace.h |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/init/Kconfig b/init/Kconfig
index af41fa7..d849ba2 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -927,7 +927,6 @@ config UIDGID_CONVERTED
 	# Features
 	depends on IMA = n
 	depends on EVM = n
-	depends on TRACING = n
 	depends on FS_POSIX_ACL = n
 	depends on QUOTA = n
 	depends on QUOTACTL = n
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 5c38c81..c9ace83 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -2060,7 +2060,8 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter)
 	seq_puts(m, "#    -----------------\n");
 	seq_printf(m, "#    | task: %.16s-%d "
 		   "(uid:%d nice:%ld policy:%ld rt_prio:%ld)\n",
-		   data->comm, data->pid, data->uid, data->nice,
+		   data->comm, data->pid,
+		   from_kuid_munged(seq_user_ns(m), data->uid), data->nice,
 		   data->policy, data->rt_priority);
 	seq_puts(m, "#    -----------------\n");
 
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 55e1f7f..40a6f30 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -147,7 +147,7 @@ struct trace_array_cpu {
 	unsigned long		skipped_entries;
 	cycle_t			preempt_timestamp;
 	pid_t			pid;
-	uid_t			uid;
+	kuid_t			uid;
 	char			comm[TASK_COMM_LEN];
 };
 
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [REVIEW][PATCH 12/15] userns: Convert drm to use kuid and kgid and struct pid where appropriate
  2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
                   ` (8 preceding siblings ...)
  2012-08-26  0:04 ` [REVIEW][PATCH 11/15] userns: Teach trace to use from_kuid Eric W. Biederman
@ 2012-08-26  0:05 ` Eric W. Biederman
  2012-09-13  1:31   ` Dave Airlie
  2012-08-26  0:07 ` [REVIEW][PATCH 15/15] userns: Convert configfs to use kuid and kgid " Eric W. Biederman
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-26  0:05 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller,
	David Airlie, dri-devel


Blink Blink this had not been converted to use struct pid ages ago?

- On drm open capture the openers kuid and struct pid.
- On drm close release the kuid and struct pid
- When reporting the uid and pid convert the kuid and struct pid
  into values in the appropriate namespace.

Cc: David Airlie <airlied@linux.ie>
Cc: dri-devel@lists.freedesktop.org
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 drivers/gpu/drm/drm_fops.c  |    3 ++-
 drivers/gpu/drm/drm_info.c  |    5 +++--
 drivers/gpu/drm/drm_ioctl.c |    4 ++--
 include/drm/drmP.h          |    4 ++--
 init/Kconfig                |    1 -
 5 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 5062eec..433d2fa 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -251,7 +251,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
 	filp->private_data = priv;
 	priv->filp = filp;
 	priv->uid = current_euid();
-	priv->pid = task_pid_nr(current);
+	priv->pid = get_pid(task_pid(current));
 	priv->minor = idr_find(&drm_minors_idr, minor_id);
 	priv->ioctl_count = 0;
 	/* for compatibility root is always authenticated */
@@ -524,6 +524,7 @@ int drm_release(struct inode *inode, struct file *filp)
 	if (drm_core_check_feature(dev, DRIVER_PRIME))
 		drm_prime_destroy_file_private(&file_priv->prime);
 
+	put_pid(file_priv->pid);
 	kfree(file_priv);
 
 	/* ========================================================
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
index 8928edb..eb0af39 100644
--- a/drivers/gpu/drm/drm_info.c
+++ b/drivers/gpu/drm/drm_info.c
@@ -191,8 +191,9 @@ int drm_clients_info(struct seq_file *m, void *data)
 		seq_printf(m, "%c %3d %5d %5d %10u %10lu\n",
 			   priv->authenticated ? 'y' : 'n',
 			   priv->minor->index,
-			   priv->pid,
-			   priv->uid, priv->magic, priv->ioctl_count);
+			   pid_vnr(priv->pid),
+			   from_kuid_munged(seq_user_ns(m), priv->uid),
+			   priv->magic, priv->ioctl_count);
 	}
 	mutex_unlock(&dev->struct_mutex);
 	return 0;
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 64a62c6..39a4383 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -215,8 +215,8 @@ int drm_getclient(struct drm_device *dev, void *data,
 	list_for_each_entry(pt, &dev->filelist, lhead) {
 		if (i++ >= idx) {
 			client->auth = pt->authenticated;
-			client->pid = pt->pid;
-			client->uid = pt->uid;
+			client->pid = pid_vnr(pt->pid);
+			client->uid = from_kuid_munged(current_user_ns(), pt->uid);
 			client->magic = pt->magic;
 			client->iocs = pt->ioctl_count;
 			mutex_unlock(&dev->struct_mutex);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index d6b67bb..9bc5c6a 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -426,8 +426,8 @@ struct drm_prime_file_private {
 /** File private data */
 struct drm_file {
 	int authenticated;
-	pid_t pid;
-	uid_t uid;
+	struct pid *pid;
+	kuid_t uid;
 	drm_magic_t magic;
 	unsigned long ioctl_count;
 	struct list_head lhead;
diff --git a/init/Kconfig b/init/Kconfig
index d849ba2..2a388e5 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -930,7 +930,6 @@ config UIDGID_CONVERTED
 	depends on FS_POSIX_ACL = n
 	depends on QUOTA = n
 	depends on QUOTACTL = n
-	depends on DRM = n
 
 	# Networking
 	depends on NET_9P = n
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [REVIEW][PATCH 15/15] userns: Convert configfs to use kuid and kgid where appropriate
  2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
                   ` (9 preceding siblings ...)
  2012-08-26  0:05 ` [REVIEW][PATCH 12/15] userns: Convert drm to use kuid and kgid and struct pid where appropriate Eric W. Biederman
@ 2012-08-26  0:07 ` Eric W. Biederman
  2012-08-26 13:00 ` [PATCH 06/15] userns: Convert audit " Eric W. Biederman
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-26  0:07 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller, Joel Becker


Cc: Joel Becker <jlbec@evilplan.org>
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 fs/configfs/inode.c |    4 ++--
 init/Kconfig        |    1 -
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index 0074362..a9d35b0 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -79,8 +79,8 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
 			return -ENOMEM;
 		/* assign default attributes */
 		sd_iattr->ia_mode = sd->s_mode;
-		sd_iattr->ia_uid = 0;
-		sd_iattr->ia_gid = 0;
+		sd_iattr->ia_uid = GLOBAL_ROOT_UID;
+		sd_iattr->ia_gid = GLOBAL_ROOT_GID;
 		sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME;
 		sd->s_iattr = sd_iattr;
 	}
diff --git a/init/Kconfig b/init/Kconfig
index e8612fb..296d48b 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -948,7 +948,6 @@ config UIDGID_CONVERTED
 	depends on CEPH_FS = n
 	depends on CIFS = n
 	depends on CODA_FS = n
-	depends on CONFIGFS_FS = n
 	depends on CRAMFS = n
 	depends on ECRYPT_FS = n
 	depends on EFS_FS = n
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [REVIEW][PATCH 11/15] userns: Teach trace to use from_kuid
  2012-08-26  0:04 ` [REVIEW][PATCH 11/15] userns: Teach trace to use from_kuid Eric W. Biederman
@ 2012-08-26  0:18   ` Steven Rostedt
  2012-08-26  0:28     ` Eric W. Biederman
  0 siblings, 1 reply; 37+ messages in thread
From: Steven Rostedt @ 2012-08-26  0:18 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Frederic Weisbecker, Ingo Molnar

On Sat, 2012-08-25 at 17:04 -0700, Eric W. Biederman wrote:
> - When tracing capture the kuid.
> - When displaying the data to user space convert the kuid into the
>   user namespace of the process that opened the report file.
> 

> index 5c38c81..c9ace83 100644
> --- a/kernel/trace/trace.c
> +++ b/kernel/trace/trace.c
> @@ -2060,7 +2060,8 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter)
>  	seq_puts(m, "#    -----------------\n");
>  	seq_printf(m, "#    | task: %.16s-%d "
>  		   "(uid:%d nice:%ld policy:%ld rt_prio:%ld)\n",
> -		   data->comm, data->pid, data->uid, data->nice,
> +		   data->comm, data->pid,
> +		   from_kuid_munged(seq_user_ns(m), data->uid), data->nice,

This is a global id. That is, it stored whatever process triggered the
report, not the one reading it. Thus, two different readers could get a
different uid for the same task that triggered the latency?

-- Steve

>  		   data->policy, data->rt_priority);
>  	seq_puts(m, "#    -----------------\n");
>  
> diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
> index 55e1f7f..40a6f30 100644
> --- a/kernel/trace/trace.h
> +++ b/kernel/trace/trace.h
> @@ -147,7 +147,7 @@ struct trace_array_cpu {
>  	unsigned long		skipped_entries;
>  	cycle_t			preempt_timestamp;
>  	pid_t			pid;
> -	uid_t			uid;
> +	kuid_t			uid;
>  	char			comm[TASK_COMM_LEN];
>  };
>  



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [REVIEW][PATCH 11/15] userns: Teach trace to use from_kuid
  2012-08-26  0:18   ` Steven Rostedt
@ 2012-08-26  0:28     ` Eric W. Biederman
  0 siblings, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-26  0:28 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Frederic Weisbecker, Ingo Molnar

Steven Rostedt <rostedt@goodmis.org> writes:

> On Sat, 2012-08-25 at 17:04 -0700, Eric W. Biederman wrote:
>> - When tracing capture the kuid.
>> - When displaying the data to user space convert the kuid into the
>>   user namespace of the process that opened the report file.
>> 
>
>> index 5c38c81..c9ace83 100644
>> --- a/kernel/trace/trace.c
>> +++ b/kernel/trace/trace.c
>> @@ -2060,7 +2060,8 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter)
>>  	seq_puts(m, "#    -----------------\n");
>>  	seq_printf(m, "#    | task: %.16s-%d "
>>  		   "(uid:%d nice:%ld policy:%ld rt_prio:%ld)\n",
>> -		   data->comm, data->pid, data->uid, data->nice,
>> +		   data->comm, data->pid,
>> +		   from_kuid_munged(seq_user_ns(m), data->uid), data->nice,
>
> This is a global id. That is, it stored whatever process triggered the
> report, not the one reading it. Thus, two different readers could get a
> different uid for the same task that triggered the latency?

Yes the stored value is a kuid_t the global kernel internal form.

We report the value as a uid_t in the user namespace of the reader.  So
if two different processes in different user namespaces read the file
they can see different values.

Now I don't expect in practice we will allow anyone who isn't
the global root user to even think of looking at debugfs, but in
case we do we might as well handle this as best as we can.

Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [REVIEW][PATCH 09/15] userns: Convert process event connector to handle kuids and kgids
  2012-08-26  0:02 ` [REVIEW][PATCH 09/15] userns: Convert process event connector to handle kuids and kgids Eric W. Biederman
@ 2012-08-26 12:33   ` Evgeniy Polyakov
  2012-08-26 13:43     ` Eric W. Biederman
  0 siblings, 1 reply; 37+ messages in thread
From: Evgeniy Polyakov @ 2012-08-26 12:33 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn, David Miller

On Sat, Aug 25, 2012 at 05:02:59PM -0700, Eric W. Biederman (ebiederm@xmission.com) wrote:
> 
> - Only allow asking for events from the initial user and pid namespace,
>   where we generate the events in.
> 
> - Convert kuids and kgids into the initial user namespace to report
>   them via the process event connector.


Looks good, if IDs are really supposed to be sent only from root
namespace. And you dropped PROC_EVENTS from init/Kconfig, but since it
was no, it should be ok by default.

Feel free to add my acked-by: Evgeniy Polyakov <zbr@ioremap.net>
Although I thoughs it could be more interesting to generate events
including namespace id

-- 
	Evgeniy Polyakov

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 06/15] userns: Convert audit to use kuid and kgid where appropriate
  2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
                   ` (10 preceding siblings ...)
  2012-08-26  0:07 ` [REVIEW][PATCH 15/15] userns: Convert configfs to use kuid and kgid " Eric W. Biederman
@ 2012-08-26 13:00 ` Eric W. Biederman
       [not found] ` <9E0E8AAC-9548-4009-AE29-D368244D8EEA@dubeyko.com>
       [not found] ` <87harqecvk.fsf@xmission.com>
  13 siblings, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-26 13:00 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller, Al Viro,
	Eric Paris, Paul Moore, Greg Kroah-Hartman


- Explicitly deny permission for audit messages sent from processes
  outside of the initial pid or user namespace.  This removes the need
  to format audit messages in other the initial user and pid namespaces.

- Explicitly format uids gids in audit messges in the initial user
  namespace. This is safe because auditd is restrected to be in
  the initial user namespace.

- Expliclty format pids in audit messages in the initial pid namespace.
  This is safe because auditd is restricted to be in the initial pid
  namespace.

- Modify audit_get_loginuid to return a kuid
- Modify /proc/<pid>/loginuid on read to convert the loginuid
  into the user namespace of the opener of the file.
- Modify /proc/<pid>/loginud on write to convert the loginuid
  from the user namespace of the opener of the file.

- In audit_krule store kuid_t values in a new uid field.  Allowing
  type safety when filtering on uids.
- In audit_krule store kgidt_t values in a new gid field.  Allowing
  type safety when filtering on gids.

- Get caller process uid and gid from the current task instead of the
  NETLINK_CB.  This results in simpler code yielding kuid_t and kgid_t
  values.  This is safe because netlink requests are now all processed
  in the task of the sender.

- Convert audit_sig_uid into a kuid_t.

- Deny bitmask comparisons of uids and gids

- Introduce audit_uid_comparitor and audit_gid_compartor typesafe
  variants of audit_compartor without the bitmask operations.

- Replace audit_compare_id with audit_compare_uid and audit_compare_gid.
  This is one of those odd cases where being type safe and duplicating
  code leads to simpler short and more concise code.

- For uid comparisons replace audit_comparator with audit_uid comparator.
- For gid comparisons replace audit_comparator with audit_gid_comparator.

The net result is that the audit subsystem now uses kuid_t and kgid_t whenever
possible making it almost impossible to confuse a raw uid_t with a kuid_t
preventing bugs.

Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Eric Paris <eparis@redhat.com>
Cc: Paul Moore <paul@paul-moore.com>
Cc: David Miller <davem@davemloft.net>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---

Apologies if you are receiving this twice.  I am resending because
it looks like this message failed to be delivered to most of it's
recepients.

 drivers/tty/tty_audit.c           |   16 ++--
 fs/proc/base.c                    |   12 ++-
 include/linux/audit.h             |   12 ++-
 include/linux/init_task.h         |    2 +-
 include/linux/sched.h             |    2 +-
 include/linux/tty.h               |    4 +-
 include/net/netlabel.h            |    2 +-
 include/net/xfrm.h                |   23 ++--
 init/Kconfig                      |    2 -
 kernel/audit.c                    |   42 +++++---
 kernel/audit.h                    |    4 +-
 kernel/audit_watch.c              |    2 +-
 kernel/auditfilter.c              |  142 +++++++++++++++++++++----
 kernel/auditsc.c                  |  214 +++++++++++++++++++------------------
 net/core/dev.c                    |    2 +-
 net/netlabel/netlabel_unlabeled.c |    2 +-
 net/netlabel/netlabel_user.c      |    2 +-
 net/xfrm/xfrm_policy.c            |    8 +-
 net/xfrm/xfrm_state.c             |    6 +-
 net/xfrm/xfrm_user.c              |   12 +-
 20 files changed, 320 insertions(+), 191 deletions(-)

diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c
index 7c58669..e6b2422 100644
--- a/drivers/tty/tty_audit.c
+++ b/drivers/tty/tty_audit.c
@@ -61,7 +61,7 @@ static void tty_audit_buf_put(struct tty_audit_buf *buf)
 }
 
 static void tty_audit_log(const char *description, struct task_struct *tsk,
-			  uid_t loginuid, unsigned sessionid, int major,
+			  kuid_t loginuid, unsigned sessionid, int major,
 			  int minor, unsigned char *data, size_t size)
 {
 	struct audit_buffer *ab;
@@ -69,11 +69,13 @@ static void tty_audit_log(const char *description, struct task_struct *tsk,
 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
 	if (ab) {
 		char name[sizeof(tsk->comm)];
-		uid_t uid = task_uid(tsk);
+		uid_t uid = from_kuid_munged(&init_user_ns, task_uid(tsk));
 
 		audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
 				 "major=%d minor=%d comm=", description,
-				 tsk->pid, uid, loginuid, sessionid,
+				 tsk->pid, uid,
+				 from_kuid(&init_user_ns, loginuid),
+				 sessionid,
 				 major, minor);
 		get_task_comm(name, tsk);
 		audit_log_untrustedstring(ab, name);
@@ -89,7 +91,7 @@ static void tty_audit_log(const char *description, struct task_struct *tsk,
  *	Generate an audit message from the contents of @buf, which is owned by
  *	@tsk with @loginuid.  @buf->mutex must be locked.
  */
-static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
+static void tty_audit_buf_push(struct task_struct *tsk, kuid_t loginuid,
 			       unsigned int sessionid,
 			       struct tty_audit_buf *buf)
 {
@@ -112,7 +114,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
  */
 static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
 {
-	uid_t auid = audit_get_loginuid(current);
+	kuid_t auid = audit_get_loginuid(current);
 	unsigned int sessionid = audit_get_sessionid(current);
 	tty_audit_buf_push(current, auid, sessionid, buf);
 }
@@ -179,7 +181,7 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch)
 	}
 
 	if (should_audit && audit_enabled) {
-		uid_t auid;
+		kuid_t auid;
 		unsigned int sessionid;
 
 		auid = audit_get_loginuid(current);
@@ -199,7 +201,7 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch)
  * reference to the tty audit buffer if available.
  * Flush the buffer or return an appropriate error code.
  */
-int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
+int tty_audit_push_task(struct task_struct *tsk, kuid_t loginuid, u32 sessionid)
 {
 	struct tty_audit_buf *buf = ERR_PTR(-EPERM);
 	unsigned long flags;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1b6c84c..138cff4 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1089,7 +1089,8 @@ static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
 	if (!task)
 		return -ESRCH;
 	length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
-				audit_get_loginuid(task));
+			   from_kuid(file->f_cred->user_ns,
+				     audit_get_loginuid(task)));
 	put_task_struct(task);
 	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
 }
@@ -1101,6 +1102,7 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
 	char *page, *tmp;
 	ssize_t length;
 	uid_t loginuid;
+	kuid_t kloginuid;
 
 	rcu_read_lock();
 	if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) {
@@ -1130,7 +1132,13 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
 		goto out_free_page;
 
 	}
-	length = audit_set_loginuid(loginuid);
+	kloginuid = make_kuid(file->f_cred->user_ns, loginuid);
+	if (!uid_valid(kloginuid)) {
+		length = -EINVAL;
+		goto out_free_page;
+	}
+
+	length = audit_set_loginuid(kloginuid);
 	if (likely(length == 0))
 		length = count;
 
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 36abf2a..4af8ba7 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -442,6 +442,8 @@ struct audit_krule {
 struct audit_field {
 	u32				type;
 	u32				val;
+	kuid_t				uid;
+	kgid_t				gid;
 	u32				op;
 	char				*lsm_str;
 	void				*lsm_rule;
@@ -525,7 +527,7 @@ static inline void audit_ptrace(struct task_struct *t)
 extern unsigned int audit_serial(void);
 extern int auditsc_get_stamp(struct audit_context *ctx,
 			      struct timespec *t, unsigned int *serial);
-extern int  audit_set_loginuid(uid_t loginuid);
+extern int  audit_set_loginuid(kuid_t loginuid);
 #define audit_get_loginuid(t) ((t)->loginuid)
 #define audit_get_sessionid(t) ((t)->sessionid)
 extern void audit_log_task_context(struct audit_buffer *ab);
@@ -637,7 +639,7 @@ extern int audit_signals;
 #define audit_core_dumps(i) do { ; } while (0)
 #define audit_seccomp(i,s,c) do { ; } while (0)
 #define auditsc_get_stamp(c,t,s) (0)
-#define audit_get_loginuid(t) (-1)
+#define audit_get_loginuid(t) (INVALID_UID)
 #define audit_get_sessionid(t) (-1)
 #define audit_log_task_context(b) do { ; } while (0)
 #define audit_ipc_obj(i) ((void)0)
@@ -700,10 +702,10 @@ extern void 		    audit_log_secctx(struct audit_buffer *ab, u32 secid);
 extern int		    audit_update_lsm_rules(void);
 
 				/* Private API (for audit.c only) */
-extern int audit_filter_user(struct netlink_skb_parms *cb);
+extern int audit_filter_user(void);
 extern int audit_filter_type(int type);
-extern int  audit_receive_filter(int type, int pid, int uid, int seq,
-				void *data, size_t datasz, uid_t loginuid,
+extern int  audit_receive_filter(int type, int pid, kuid_t uid, int seq,
+				void *data, size_t datasz, kuid_t loginuid,
 				u32 sessionid, u32 sid);
 extern int audit_enabled;
 #else
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 89f1cb1..6d087c5 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -92,7 +92,7 @@ extern struct group_info init_groups;
 
 #ifdef CONFIG_AUDITSYSCALL
 #define INIT_IDS \
-	.loginuid = -1, \
+	.loginuid = INVALID_UID, \
 	.sessionid = -1,
 #else
 #define INIT_IDS
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c147e70..f64d092 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1426,7 +1426,7 @@ struct task_struct {
 
 	struct audit_context *audit_context;
 #ifdef CONFIG_AUDITSYSCALL
-	uid_t loginuid;
+	kuid_t loginuid;
 	unsigned int sessionid;
 #endif
 	struct seccomp seccomp;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 9f47ab5..7298385 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -553,7 +553,7 @@ extern void tty_audit_fork(struct signal_struct *sig);
 extern void tty_audit_tiocsti(struct tty_struct *tty, char ch);
 extern void tty_audit_push(struct tty_struct *tty);
 extern int tty_audit_push_task(struct task_struct *tsk,
-			       uid_t loginuid, u32 sessionid);
+			       kuid_t loginuid, u32 sessionid);
 #else
 static inline void tty_audit_add_data(struct tty_struct *tty,
 				      unsigned char *data, size_t size)
@@ -572,7 +572,7 @@ static inline void tty_audit_push(struct tty_struct *tty)
 {
 }
 static inline int tty_audit_push_task(struct task_struct *tsk,
-				      uid_t loginuid, u32 sessionid)
+				      kuid_t loginuid, u32 sessionid)
 {
 	return 0;
 }
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index f674409..2c95d55 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -110,7 +110,7 @@ struct cipso_v4_doi;
 /* NetLabel audit information */
 struct netlbl_audit {
 	u32 secid;
-	uid_t loginuid;
+	kuid_t loginuid;
 	u32 sessionid;
 };
 
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index d9509eb..1f217e2 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -662,7 +662,7 @@ struct xfrm_spi_skb_cb {
 /* Audit Information */
 struct xfrm_audit {
 	u32	secid;
-	uid_t	loginuid;
+	kuid_t	loginuid;
 	u32	sessionid;
 };
 
@@ -681,13 +681,14 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op)
 	return audit_buf;
 }
 
-static inline void xfrm_audit_helper_usrinfo(uid_t auid, u32 ses, u32 secid,
+static inline void xfrm_audit_helper_usrinfo(kuid_t auid, u32 ses, u32 secid,
 					     struct audit_buffer *audit_buf)
 {
 	char *secctx;
 	u32 secctx_len;
 
-	audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses);
+	audit_log_format(audit_buf, " auid=%u ses=%u",
+			 from_kuid(&init_user_ns, auid), ses);
 	if (secid != 0 &&
 	    security_secid_to_secctx(secid, &secctx, &secctx_len) == 0) {
 		audit_log_format(audit_buf, " subj=%s", secctx);
@@ -697,13 +698,13 @@ static inline void xfrm_audit_helper_usrinfo(uid_t auid, u32 ses, u32 secid,
 }
 
 extern void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
-				  u32 auid, u32 ses, u32 secid);
+				  kuid_t auid, u32 ses, u32 secid);
 extern void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
-				  u32 auid, u32 ses, u32 secid);
+				  kuid_t auid, u32 ses, u32 secid);
 extern void xfrm_audit_state_add(struct xfrm_state *x, int result,
-				 u32 auid, u32 ses, u32 secid);
+				 kuid_t auid, u32 ses, u32 secid);
 extern void xfrm_audit_state_delete(struct xfrm_state *x, int result,
-				    u32 auid, u32 ses, u32 secid);
+				    kuid_t auid, u32 ses, u32 secid);
 extern void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
 					     struct sk_buff *skb);
 extern void xfrm_audit_state_replay(struct xfrm_state *x,
@@ -716,22 +717,22 @@ extern void xfrm_audit_state_icvfail(struct xfrm_state *x,
 #else
 
 static inline void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
-				  u32 auid, u32 ses, u32 secid)
+				  kuid_t auid, u32 ses, u32 secid)
 {
 }
 
 static inline void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
-				  u32 auid, u32 ses, u32 secid)
+				  kuid_t auid, u32 ses, u32 secid)
 {
 }
 
 static inline void xfrm_audit_state_add(struct xfrm_state *x, int result,
-				 u32 auid, u32 ses, u32 secid)
+				 kuid_t auid, u32 ses, u32 secid)
 {
 }
 
 static inline void xfrm_audit_state_delete(struct xfrm_state *x, int result,
-				    u32 auid, u32 ses, u32 secid)
+				    kuid_t auid, u32 ses, u32 secid)
 {
 }
 
diff --git a/init/Kconfig b/init/Kconfig
index 4daf449..525f4e8 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -927,8 +927,6 @@ config UIDGID_CONVERTED
 	# Features
 	depends on IMA = n
 	depends on EVM = n
-	depends on AUDIT = n
-	depends on AUDITSYSCALL = n
 	depends on TASKSTATS = n
 	depends on TRACING = n
 	depends on FS_POSIX_ACL = n
diff --git a/kernel/audit.c b/kernel/audit.c
index ea3b7b6..b25afb7 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -61,6 +61,7 @@
 #include <linux/netlink.h>
 #include <linux/freezer.h>
 #include <linux/tty.h>
+#include <linux/pid_namespace.h>
 
 #include "audit.h"
 
@@ -104,7 +105,7 @@ static int	audit_backlog_wait_time = 60 * HZ;
 static int	audit_backlog_wait_overflow = 0;
 
 /* The identity of the user shutting down the audit system. */
-uid_t		audit_sig_uid = -1;
+kuid_t		audit_sig_uid = INVALID_UID;
 pid_t		audit_sig_pid = -1;
 u32		audit_sig_sid = 0;
 
@@ -264,7 +265,7 @@ void audit_log_lost(const char *message)
 }
 
 static int audit_log_config_change(char *function_name, int new, int old,
-				   uid_t loginuid, u32 sessionid, u32 sid,
+				   kuid_t loginuid, u32 sessionid, u32 sid,
 				   int allow_changes)
 {
 	struct audit_buffer *ab;
@@ -272,7 +273,7 @@ static int audit_log_config_change(char *function_name, int new, int old,
 
 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
 	audit_log_format(ab, "%s=%d old=%d auid=%u ses=%u", function_name, new,
-			 old, loginuid, sessionid);
+			 old, from_kuid(&init_user_ns, loginuid), sessionid);
 	if (sid) {
 		char *ctx = NULL;
 		u32 len;
@@ -292,7 +293,7 @@ static int audit_log_config_change(char *function_name, int new, int old,
 }
 
 static int audit_do_config_change(char *function_name, int *to_change,
-				  int new, uid_t loginuid, u32 sessionid,
+				  int new, kuid_t loginuid, u32 sessionid,
 				  u32 sid)
 {
 	int allow_changes, rc = 0, old = *to_change;
@@ -319,21 +320,21 @@ static int audit_do_config_change(char *function_name, int *to_change,
 	return rc;
 }
 
-static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sessionid,
+static int audit_set_rate_limit(int limit, kuid_t loginuid, u32 sessionid,
 				u32 sid)
 {
 	return audit_do_config_change("audit_rate_limit", &audit_rate_limit,
 				      limit, loginuid, sessionid, sid);
 }
 
-static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sessionid,
+static int audit_set_backlog_limit(int limit, kuid_t loginuid, u32 sessionid,
 				   u32 sid)
 {
 	return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit,
 				      limit, loginuid, sessionid, sid);
 }
 
-static int audit_set_enabled(int state, uid_t loginuid, u32 sessionid, u32 sid)
+static int audit_set_enabled(int state, kuid_t loginuid, u32 sessionid, u32 sid)
 {
 	int rc;
 	if (state < AUDIT_OFF || state > AUDIT_LOCKED)
@@ -348,7 +349,7 @@ static int audit_set_enabled(int state, uid_t loginuid, u32 sessionid, u32 sid)
 	return rc;
 }
 
-static int audit_set_failure(int state, uid_t loginuid, u32 sessionid, u32 sid)
+static int audit_set_failure(int state, kuid_t loginuid, u32 sessionid, u32 sid)
 {
 	if (state != AUDIT_FAIL_SILENT
 	    && state != AUDIT_FAIL_PRINTK
@@ -467,7 +468,7 @@ static int kauditd_thread(void *dummy)
 	return 0;
 }
 
-static int audit_prepare_user_tty(pid_t pid, uid_t loginuid, u32 sessionid)
+static int audit_prepare_user_tty(pid_t pid, kuid_t loginuid, u32 sessionid)
 {
 	struct task_struct *tsk;
 	int err;
@@ -588,6 +589,11 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
 {
 	int err = 0;
 
+	/* Only support the initial namespaces for now. */
+	if ((current_user_ns() != &init_user_ns) ||
+	    (task_active_pid_ns(current) != &init_pid_ns))
+		return -EPERM;
+
 	switch (msg_type) {
 	case AUDIT_GET:
 	case AUDIT_LIST:
@@ -619,7 +625,7 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
 }
 
 static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
-				     u32 pid, u32 uid, uid_t auid, u32 ses,
+				     u32 pid, kuid_t uid, kuid_t auid, u32 ses,
 				     u32 sid)
 {
 	int rc = 0;
@@ -633,7 +639,10 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
 
 	*ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
 	audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u",
-			 pid, uid, auid, ses);
+			 pid,
+			 from_kuid(&init_user_ns, uid),
+			 from_kuid(&init_user_ns, auid),
+			 ses);
 	if (sid) {
 		rc = security_secid_to_secctx(sid, &ctx, &len);
 		if (rc)
@@ -649,13 +658,14 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
 
 static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-	u32			uid, pid, seq, sid;
+	u32			pid, seq, sid;
+	kuid_t			uid;
 	void			*data;
 	struct audit_status	*status_get, status_set;
 	int			err;
 	struct audit_buffer	*ab;
 	u16			msg_type = nlh->nlmsg_type;
-	uid_t			loginuid; /* loginuid of sender */
+	kuid_t			loginuid; /* loginuid of sender */
 	u32			sessionid;
 	struct audit_sig_info   *sig_data;
 	char			*ctx = NULL;
@@ -676,7 +686,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 	}
 
 	pid  = NETLINK_CREDS(skb)->pid;
-	uid  = NETLINK_CREDS(skb)->uid;
+	uid = current_uid();
 	loginuid = audit_get_loginuid(current);
 	sessionid = audit_get_sessionid(current);
 	security_task_getsecid(current, &sid);
@@ -738,7 +748,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 		if (!audit_enabled && msg_type != AUDIT_USER_AVC)
 			return 0;
 
-		err = audit_filter_user(&NETLINK_CB(skb));
+		err = audit_filter_user();
 		if (err == 1) {
 			err = 0;
 			if (msg_type == AUDIT_USER_TTY) {
@@ -866,7 +876,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 				security_release_secctx(ctx, len);
 			return -ENOMEM;
 		}
-		sig_data->uid = audit_sig_uid;
+		sig_data->uid = from_kuid(&init_user_ns, audit_sig_uid);
 		sig_data->pid = audit_sig_pid;
 		if (audit_sig_sid) {
 			memcpy(sig_data->ctx, ctx, len);
diff --git a/kernel/audit.h b/kernel/audit.h
index 8167668..fd30cc7 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -76,6 +76,8 @@ static inline int audit_hash_ino(u32 ino)
 
 extern int audit_match_class(int class, unsigned syscall);
 extern int audit_comparator(const u32 left, const u32 op, const u32 right);
+extern int audit_uid_comparator(kuid_t left, const u32 op, kuid_t right);
+extern int audit_gid_comparator(kgid_t left, const u32 op, kgid_t right);
 extern int audit_compare_dname_path(const char *dname, const char *path,
 				    int *dirlen);
 extern struct sk_buff *	    audit_make_reply(int pid, int seq, int type,
@@ -144,7 +146,7 @@ extern void audit_kill_trees(struct list_head *);
 extern char *audit_unpack_string(void **, size_t *, size_t);
 
 extern pid_t audit_sig_pid;
-extern uid_t audit_sig_uid;
+extern kuid_t audit_sig_uid;
 extern u32 audit_sig_sid;
 
 #ifdef CONFIG_AUDITSYSCALL
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 3823281..1c22ec3 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -241,7 +241,7 @@ static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watc
 		struct audit_buffer *ab;
 		ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
 		audit_log_format(ab, "auid=%u ses=%u op=",
-				 audit_get_loginuid(current),
+				 from_kuid(&init_user_ns, audit_get_loginuid(current)),
 				 audit_get_sessionid(current));
 		audit_log_string(ab, op);
 		audit_log_format(ab, " path=");
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index a6c3f1a..1a8a648 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -342,6 +342,8 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
 
 		f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS);
 		f->val = rule->values[i];
+		f->uid = INVALID_UID;
+		f->gid = INVALID_GID;
 
 		err = -EINVAL;
 		if (f->op == Audit_bad)
@@ -350,16 +352,34 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
 		switch(f->type) {
 		default:
 			goto exit_free;
-		case AUDIT_PID:
 		case AUDIT_UID:
 		case AUDIT_EUID:
 		case AUDIT_SUID:
 		case AUDIT_FSUID:
+		case AUDIT_LOGINUID:
+			/* bit ops not implemented for uid comparisons */
+			if (f->op == Audit_bitmask || f->op == Audit_bittest)
+				goto exit_free;
+
+			f->uid = make_kuid(current_user_ns(), f->val);
+			if (!uid_valid(f->uid))
+				goto exit_free;
+			break;
+
 		case AUDIT_GID:
 		case AUDIT_EGID:
 		case AUDIT_SGID:
 		case AUDIT_FSGID:
-		case AUDIT_LOGINUID:
+			/* bit ops not implemented for gid comparisons */
+			if (f->op == Audit_bitmask || f->op == Audit_bittest)
+				goto exit_free;
+
+			f->gid = make_kgid(current_user_ns(), f->val);
+			if (!gid_valid(f->gid))
+				goto exit_free;
+			break;
+
+		case AUDIT_PID:
 		case AUDIT_PERS:
 		case AUDIT_MSGTYPE:
 		case AUDIT_PPID:
@@ -437,19 +457,41 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 
 		f->type = data->fields[i];
 		f->val = data->values[i];
+		f->uid = INVALID_UID;
+		f->gid = INVALID_GID;
 		f->lsm_str = NULL;
 		f->lsm_rule = NULL;
 		switch(f->type) {
-		case AUDIT_PID:
 		case AUDIT_UID:
 		case AUDIT_EUID:
 		case AUDIT_SUID:
 		case AUDIT_FSUID:
+		case AUDIT_LOGINUID:
+		case AUDIT_OBJ_UID:
+			/* bit ops not implemented for uid comparisons */
+			if (f->op == Audit_bitmask || f->op == Audit_bittest)
+				goto exit_free;
+
+			f->uid = make_kuid(current_user_ns(), f->val);
+			if (!uid_valid(f->uid))
+				goto exit_free;
+			break;
+
 		case AUDIT_GID:
 		case AUDIT_EGID:
 		case AUDIT_SGID:
 		case AUDIT_FSGID:
-		case AUDIT_LOGINUID:
+		case AUDIT_OBJ_GID:
+			/* bit ops not implemented for gid comparisons */
+			if (f->op == Audit_bitmask || f->op == Audit_bittest)
+				goto exit_free;
+
+			f->gid = make_kgid(current_user_ns(), f->val);
+			if (!gid_valid(f->gid))
+				goto exit_free;
+			break;
+
+		case AUDIT_PID:
 		case AUDIT_PERS:
 		case AUDIT_MSGTYPE:
 		case AUDIT_PPID:
@@ -461,9 +503,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 		case AUDIT_ARG1:
 		case AUDIT_ARG2:
 		case AUDIT_ARG3:
-		case AUDIT_OBJ_UID:
-		case AUDIT_OBJ_GID:
 			break;
+		/* arch is only allowed to be = or != */
 		case AUDIT_ARCH:
 			entry->rule.arch_f = f;
 			break;
@@ -707,6 +748,23 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
 			if (strcmp(a->filterkey, b->filterkey))
 				return 1;
 			break;
+		case AUDIT_UID:
+		case AUDIT_EUID:
+		case AUDIT_SUID:
+		case AUDIT_FSUID:
+		case AUDIT_LOGINUID:
+		case AUDIT_OBJ_UID:
+			if (!uid_eq(a->fields[i].uid, b->fields[i].uid))
+				return 1;
+			break;
+		case AUDIT_GID:
+		case AUDIT_EGID:
+		case AUDIT_SGID:
+		case AUDIT_FSGID:
+		case AUDIT_OBJ_GID:
+			if (!gid_eq(a->fields[i].gid, b->fields[i].gid))
+				return 1;
+			break;
 		default:
 			if (a->fields[i].val != b->fields[i].val)
 				return 1;
@@ -1056,7 +1114,7 @@ static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
 }
 
 /* Log rule additions and removals */
-static void audit_log_rule_change(uid_t loginuid, u32 sessionid, u32 sid,
+static void audit_log_rule_change(kuid_t loginuid, u32 sessionid, u32 sid,
 				  char *action, struct audit_krule *rule,
 				  int res)
 {
@@ -1068,7 +1126,8 @@ static void audit_log_rule_change(uid_t loginuid, u32 sessionid, u32 sid,
 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
 	if (!ab)
 		return;
-	audit_log_format(ab, "auid=%u ses=%u", loginuid, sessionid);
+	audit_log_format(ab, "auid=%u ses=%u",
+			 from_kuid(&init_user_ns, loginuid), sessionid);
 	if (sid) {
 		char *ctx = NULL;
 		u32 len;
@@ -1098,8 +1157,8 @@ static void audit_log_rule_change(uid_t loginuid, u32 sessionid, u32 sid,
  * @sessionid: sessionid for netlink audit message
  * @sid: SE Linux Security ID of sender
  */
-int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
-			 size_t datasz, uid_t loginuid, u32 sessionid, u32 sid)
+int audit_receive_filter(int type, int pid, kuid_t uid, int seq, void *data,
+			 size_t datasz, kuid_t loginuid, u32 sessionid, u32 sid)
 {
 	struct task_struct *tsk;
 	struct audit_netlink_list *dest;
@@ -1198,6 +1257,52 @@ int audit_comparator(u32 left, u32 op, u32 right)
 	}
 }
 
+int audit_uid_comparator(kuid_t left, u32 op, kuid_t right)
+{
+	switch (op) {
+	case Audit_equal:
+		return uid_eq(left, right);
+	case Audit_not_equal:
+		return !uid_eq(left, right);
+	case Audit_lt:
+		return uid_lt(left, right);
+	case Audit_le:
+		return uid_lte(left, right);
+	case Audit_gt:
+		return uid_gt(left, right);
+	case Audit_ge:
+		return uid_gte(left, right);
+	case Audit_bitmask:
+	case Audit_bittest:
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+int audit_gid_comparator(kgid_t left, u32 op, kgid_t right)
+{
+	switch (op) {
+	case Audit_equal:
+		return gid_eq(left, right);
+	case Audit_not_equal:
+		return !gid_eq(left, right);
+	case Audit_lt:
+		return gid_lt(left, right);
+	case Audit_le:
+		return gid_lte(left, right);
+	case Audit_gt:
+		return gid_gt(left, right);
+	case Audit_ge:
+		return gid_gte(left, right);
+	case Audit_bitmask:
+	case Audit_bittest:
+	default:
+		BUG();
+		return 0;
+	}
+}
+
 /* Compare given dentry name with last component in given path,
  * return of 0 indicates a match. */
 int audit_compare_dname_path(const char *dname, const char *path,
@@ -1236,8 +1341,7 @@ int audit_compare_dname_path(const char *dname, const char *path,
 	return strncmp(p, dname, dlen);
 }
 
-static int audit_filter_user_rules(struct netlink_skb_parms *cb,
-				   struct audit_krule *rule,
+static int audit_filter_user_rules(struct audit_krule *rule,
 				   enum audit_state *state)
 {
 	int i;
@@ -1249,17 +1353,17 @@ static int audit_filter_user_rules(struct netlink_skb_parms *cb,
 
 		switch (f->type) {
 		case AUDIT_PID:
-			result = audit_comparator(cb->creds.pid, f->op, f->val);
+			result = audit_comparator(task_pid_nr(current), f->op, f->val);
 			break;
 		case AUDIT_UID:
-			result = audit_comparator(cb->creds.uid, f->op, f->val);
+			result = audit_uid_comparator(current_uid(), f->op, f->uid);
 			break;
 		case AUDIT_GID:
-			result = audit_comparator(cb->creds.gid, f->op, f->val);
+			result = audit_gid_comparator(current_gid(), f->op, f->gid);
 			break;
 		case AUDIT_LOGINUID:
-			result = audit_comparator(audit_get_loginuid(current),
-						  f->op, f->val);
+			result = audit_uid_comparator(audit_get_loginuid(current),
+						  f->op, f->uid);
 			break;
 		case AUDIT_SUBJ_USER:
 		case AUDIT_SUBJ_ROLE:
@@ -1287,7 +1391,7 @@ static int audit_filter_user_rules(struct netlink_skb_parms *cb,
 	return 1;
 }
 
-int audit_filter_user(struct netlink_skb_parms *cb)
+int audit_filter_user(void)
 {
 	enum audit_state state = AUDIT_DISABLED;
 	struct audit_entry *e;
@@ -1295,7 +1399,7 @@ int audit_filter_user(struct netlink_skb_parms *cb)
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {
-		if (audit_filter_user_rules(cb, &e->rule, &state)) {
+		if (audit_filter_user_rules(&e->rule, &state)) {
 			if (state == AUDIT_DISABLED)
 				ret = 0;
 			break;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 4b96415..0795f58 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -113,8 +113,8 @@ struct audit_names {
 	unsigned long	ino;
 	dev_t		dev;
 	umode_t		mode;
-	uid_t		uid;
-	gid_t		gid;
+	kuid_t		uid;
+	kgid_t		gid;
 	dev_t		rdev;
 	u32		osid;
 	struct audit_cap_data fcap;
@@ -149,8 +149,8 @@ struct audit_aux_data_execve {
 struct audit_aux_data_pids {
 	struct audit_aux_data	d;
 	pid_t			target_pid[AUDIT_AUX_PIDS];
-	uid_t			target_auid[AUDIT_AUX_PIDS];
-	uid_t			target_uid[AUDIT_AUX_PIDS];
+	kuid_t			target_auid[AUDIT_AUX_PIDS];
+	kuid_t			target_uid[AUDIT_AUX_PIDS];
 	unsigned int		target_sessionid[AUDIT_AUX_PIDS];
 	u32			target_sid[AUDIT_AUX_PIDS];
 	char 			target_comm[AUDIT_AUX_PIDS][TASK_COMM_LEN];
@@ -208,14 +208,14 @@ struct audit_context {
 	size_t sockaddr_len;
 				/* Save things to print about task_struct */
 	pid_t		    pid, ppid;
-	uid_t		    uid, euid, suid, fsuid;
-	gid_t		    gid, egid, sgid, fsgid;
+	kuid_t		    uid, euid, suid, fsuid;
+	kgid_t		    gid, egid, sgid, fsgid;
 	unsigned long	    personality;
 	int		    arch;
 
 	pid_t		    target_pid;
-	uid_t		    target_auid;
-	uid_t		    target_uid;
+	kuid_t		    target_auid;
+	kuid_t		    target_uid;
 	unsigned int	    target_sessionid;
 	u32		    target_sid;
 	char		    target_comm[TASK_COMM_LEN];
@@ -231,8 +231,8 @@ struct audit_context {
 			long args[6];
 		} socketcall;
 		struct {
-			uid_t			uid;
-			gid_t			gid;
+			kuid_t			uid;
+			kgid_t			gid;
 			umode_t			mode;
 			u32			osid;
 			int			has_perm;
@@ -464,37 +464,47 @@ static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)
 	return 0;
 }
 
-static int audit_compare_id(uid_t uid1,
-			    struct audit_names *name,
-			    unsigned long name_offset,
-			    struct audit_field *f,
-			    struct audit_context *ctx)
+static int audit_compare_uid(kuid_t uid,
+			     struct audit_names *name,
+			     struct audit_field *f,
+			     struct audit_context *ctx)
 {
 	struct audit_names *n;
-	unsigned long addr;
-	uid_t uid2;
 	int rc;
 
-	BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
-
 	if (name) {
-		addr = (unsigned long)name;
-		addr += name_offset;
-
-		uid2 = *(uid_t *)addr;
-		rc = audit_comparator(uid1, f->op, uid2);
+		rc = audit_uid_comparator(uid, f->op, name->uid);
 		if (rc)
 			return rc;
 	}
 
 	if (ctx) {
 		list_for_each_entry(n, &ctx->names_list, list) {
-			addr = (unsigned long)n;
-			addr += name_offset;
+			rc = audit_uid_comparator(uid, f->op, n->uid);
+			if (rc)
+				return rc;
+		}
+	}
+	return 0;
+}
+
+static int audit_compare_gid(kgid_t gid,
+			     struct audit_names *name,
+			     struct audit_field *f,
+			     struct audit_context *ctx)
+{
+	struct audit_names *n;
+	int rc;
 
-			uid2 = *(uid_t *)addr;
+	if (name) {
+		rc = audit_gid_comparator(gid, f->op, name->gid);
+		if (rc)
+			return rc;
+	}
 
-			rc = audit_comparator(uid1, f->op, uid2);
+	if (ctx) {
+		list_for_each_entry(n, &ctx->names_list, list) {
+			rc = audit_gid_comparator(gid, f->op, n->gid);
 			if (rc)
 				return rc;
 		}
@@ -511,80 +521,62 @@ static int audit_field_compare(struct task_struct *tsk,
 	switch (f->val) {
 	/* process to file object comparisons */
 	case AUDIT_COMPARE_UID_TO_OBJ_UID:
-		return audit_compare_id(cred->uid,
-					name, offsetof(struct audit_names, uid),
-					f, ctx);
+		return audit_compare_uid(cred->uid, name, f, ctx);
 	case AUDIT_COMPARE_GID_TO_OBJ_GID:
-		return audit_compare_id(cred->gid,
-					name, offsetof(struct audit_names, gid),
-					f, ctx);
+		return audit_compare_gid(cred->gid, name, f, ctx);
 	case AUDIT_COMPARE_EUID_TO_OBJ_UID:
-		return audit_compare_id(cred->euid,
-					name, offsetof(struct audit_names, uid),
-					f, ctx);
+		return audit_compare_uid(cred->euid, name, f, ctx);
 	case AUDIT_COMPARE_EGID_TO_OBJ_GID:
-		return audit_compare_id(cred->egid,
-					name, offsetof(struct audit_names, gid),
-					f, ctx);
+		return audit_compare_gid(cred->egid, name, f, ctx);
 	case AUDIT_COMPARE_AUID_TO_OBJ_UID:
-		return audit_compare_id(tsk->loginuid,
-					name, offsetof(struct audit_names, uid),
-					f, ctx);
+		return audit_compare_uid(tsk->loginuid, name, f, ctx);
 	case AUDIT_COMPARE_SUID_TO_OBJ_UID:
-		return audit_compare_id(cred->suid,
-					name, offsetof(struct audit_names, uid),
-					f, ctx);
+		return audit_compare_uid(cred->suid, name, f, ctx);
 	case AUDIT_COMPARE_SGID_TO_OBJ_GID:
-		return audit_compare_id(cred->sgid,
-					name, offsetof(struct audit_names, gid),
-					f, ctx);
+		return audit_compare_gid(cred->sgid, name, f, ctx);
 	case AUDIT_COMPARE_FSUID_TO_OBJ_UID:
-		return audit_compare_id(cred->fsuid,
-					name, offsetof(struct audit_names, uid),
-					f, ctx);
+		return audit_compare_uid(cred->fsuid, name, f, ctx);
 	case AUDIT_COMPARE_FSGID_TO_OBJ_GID:
-		return audit_compare_id(cred->fsgid,
-					name, offsetof(struct audit_names, gid),
-					f, ctx);
+		return audit_compare_gid(cred->fsgid, name, f, ctx);
 	/* uid comparisons */
 	case AUDIT_COMPARE_UID_TO_AUID:
-		return audit_comparator(cred->uid, f->op, tsk->loginuid);
+		return audit_uid_comparator(cred->uid, f->op, tsk->loginuid);
 	case AUDIT_COMPARE_UID_TO_EUID:
-		return audit_comparator(cred->uid, f->op, cred->euid);
+		return audit_uid_comparator(cred->uid, f->op, cred->euid);
 	case AUDIT_COMPARE_UID_TO_SUID:
-		return audit_comparator(cred->uid, f->op, cred->suid);
+		return audit_uid_comparator(cred->uid, f->op, cred->suid);
 	case AUDIT_COMPARE_UID_TO_FSUID:
-		return audit_comparator(cred->uid, f->op, cred->fsuid);
+		return audit_uid_comparator(cred->uid, f->op, cred->fsuid);
 	/* auid comparisons */
 	case AUDIT_COMPARE_AUID_TO_EUID:
-		return audit_comparator(tsk->loginuid, f->op, cred->euid);
+		return audit_uid_comparator(tsk->loginuid, f->op, cred->euid);
 	case AUDIT_COMPARE_AUID_TO_SUID:
-		return audit_comparator(tsk->loginuid, f->op, cred->suid);
+		return audit_uid_comparator(tsk->loginuid, f->op, cred->suid);
 	case AUDIT_COMPARE_AUID_TO_FSUID:
-		return audit_comparator(tsk->loginuid, f->op, cred->fsuid);
+		return audit_uid_comparator(tsk->loginuid, f->op, cred->fsuid);
 	/* euid comparisons */
 	case AUDIT_COMPARE_EUID_TO_SUID:
-		return audit_comparator(cred->euid, f->op, cred->suid);
+		return audit_uid_comparator(cred->euid,	f->op, cred->suid);
 	case AUDIT_COMPARE_EUID_TO_FSUID:
-		return audit_comparator(cred->euid, f->op, cred->fsuid);
+		return audit_uid_comparator(cred->euid, f->op, cred->fsuid);
 	/* suid comparisons */
 	case AUDIT_COMPARE_SUID_TO_FSUID:
-		return audit_comparator(cred->suid, f->op, cred->fsuid);
+		return audit_uid_comparator(cred->suid,	f->op, cred->fsuid);
 	/* gid comparisons */
 	case AUDIT_COMPARE_GID_TO_EGID:
-		return audit_comparator(cred->gid, f->op, cred->egid);
+		return audit_gid_comparator(cred->gid, f->op, cred->egid);
 	case AUDIT_COMPARE_GID_TO_SGID:
-		return audit_comparator(cred->gid, f->op, cred->sgid);
+		return audit_gid_comparator(cred->gid, f->op, cred->sgid);
 	case AUDIT_COMPARE_GID_TO_FSGID:
-		return audit_comparator(cred->gid, f->op, cred->fsgid);
+		return audit_gid_comparator(cred->gid, f->op, cred->fsgid);
 	/* egid comparisons */
 	case AUDIT_COMPARE_EGID_TO_SGID:
-		return audit_comparator(cred->egid, f->op, cred->sgid);
+		return audit_gid_comparator(cred->egid,	f->op, cred->sgid);
 	case AUDIT_COMPARE_EGID_TO_FSGID:
-		return audit_comparator(cred->egid, f->op, cred->fsgid);
+		return audit_gid_comparator(cred->egid,	f->op, cred->fsgid);
 	/* sgid comparison */
 	case AUDIT_COMPARE_SGID_TO_FSGID:
-		return audit_comparator(cred->sgid, f->op, cred->fsgid);
+		return audit_gid_comparator(cred->sgid,	f->op, cred->fsgid);
 	default:
 		WARN(1, "Missing AUDIT_COMPARE define.  Report as a bug\n");
 		return 0;
@@ -630,28 +622,28 @@ static int audit_filter_rules(struct task_struct *tsk,
 			}
 			break;
 		case AUDIT_UID:
-			result = audit_comparator(cred->uid, f->op, f->val);
+			result = audit_uid_comparator(cred->uid, f->op, f->uid);
 			break;
 		case AUDIT_EUID:
-			result = audit_comparator(cred->euid, f->op, f->val);
+			result = audit_uid_comparator(cred->euid, f->op, f->uid);
 			break;
 		case AUDIT_SUID:
-			result = audit_comparator(cred->suid, f->op, f->val);
+			result = audit_uid_comparator(cred->suid, f->op, f->uid);
 			break;
 		case AUDIT_FSUID:
-			result = audit_comparator(cred->fsuid, f->op, f->val);
+			result = audit_uid_comparator(cred->fsuid, f->op, f->uid);
 			break;
 		case AUDIT_GID:
-			result = audit_comparator(cred->gid, f->op, f->val);
+			result = audit_gid_comparator(cred->gid, f->op, f->gid);
 			break;
 		case AUDIT_EGID:
-			result = audit_comparator(cred->egid, f->op, f->val);
+			result = audit_gid_comparator(cred->egid, f->op, f->gid);
 			break;
 		case AUDIT_SGID:
-			result = audit_comparator(cred->sgid, f->op, f->val);
+			result = audit_gid_comparator(cred->sgid, f->op, f->gid);
 			break;
 		case AUDIT_FSGID:
-			result = audit_comparator(cred->fsgid, f->op, f->val);
+			result = audit_gid_comparator(cred->fsgid, f->op, f->gid);
 			break;
 		case AUDIT_PERS:
 			result = audit_comparator(tsk->personality, f->op, f->val);
@@ -717,10 +709,10 @@ static int audit_filter_rules(struct task_struct *tsk,
 			break;
 		case AUDIT_OBJ_UID:
 			if (name) {
-				result = audit_comparator(name->uid, f->op, f->val);
+				result = audit_uid_comparator(name->uid, f->op, f->uid);
 			} else if (ctx) {
 				list_for_each_entry(n, &ctx->names_list, list) {
-					if (audit_comparator(n->uid, f->op, f->val)) {
+					if (audit_uid_comparator(n->uid, f->op, f->uid)) {
 						++result;
 						break;
 					}
@@ -729,10 +721,10 @@ static int audit_filter_rules(struct task_struct *tsk,
 			break;
 		case AUDIT_OBJ_GID:
 			if (name) {
-				result = audit_comparator(name->gid, f->op, f->val);
+				result = audit_gid_comparator(name->gid, f->op, f->gid);
 			} else if (ctx) {
 				list_for_each_entry(n, &ctx->names_list, list) {
-					if (audit_comparator(n->gid, f->op, f->val)) {
+					if (audit_gid_comparator(n->gid, f->op, f->gid)) {
 						++result;
 						break;
 					}
@@ -750,7 +742,7 @@ static int audit_filter_rules(struct task_struct *tsk,
 		case AUDIT_LOGINUID:
 			result = 0;
 			if (ctx)
-				result = audit_comparator(tsk->loginuid, f->op, f->val);
+				result = audit_uid_comparator(tsk->loginuid, f->op, f->uid);
 			break;
 		case AUDIT_SUBJ_USER:
 		case AUDIT_SUBJ_ROLE:
@@ -1184,7 +1176,7 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk
 }
 
 static int audit_log_pid_context(struct audit_context *context, pid_t pid,
-				 uid_t auid, uid_t uid, unsigned int sessionid,
+				 kuid_t auid, kuid_t uid, unsigned int sessionid,
 				 u32 sid, char *comm)
 {
 	struct audit_buffer *ab;
@@ -1196,8 +1188,9 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
 	if (!ab)
 		return rc;
 
-	audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid, auid,
-			 uid, sessionid);
+	audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,
+			 from_kuid(&init_user_ns, auid),
+			 from_kuid(&init_user_ns, uid), sessionid);
 	if (security_secid_to_secctx(sid, &ctx, &len)) {
 		audit_log_format(ab, " obj=(none)");
 		rc = 1;
@@ -1447,7 +1440,9 @@ static void show_special(struct audit_context *context, int *call_panic)
 		u32 osid = context->ipc.osid;
 
 		audit_log_format(ab, "ouid=%u ogid=%u mode=%#ho",
-			 context->ipc.uid, context->ipc.gid, context->ipc.mode);
+				 from_kuid(&init_user_ns, context->ipc.uid),
+				 from_kgid(&init_user_ns, context->ipc.gid),
+				 context->ipc.mode);
 		if (osid) {
 			char *ctx = NULL;
 			u32 len;
@@ -1560,8 +1555,8 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
 				 MAJOR(n->dev),
 				 MINOR(n->dev),
 				 n->mode,
-				 n->uid,
-				 n->gid,
+				 from_kuid(&init_user_ns, n->uid),
+				 from_kgid(&init_user_ns, n->gid),
 				 MAJOR(n->rdev),
 				 MINOR(n->rdev));
 	}
@@ -1638,11 +1633,16 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 		  context->name_count,
 		  context->ppid,
 		  context->pid,
-		  tsk->loginuid,
-		  context->uid,
-		  context->gid,
-		  context->euid, context->suid, context->fsuid,
-		  context->egid, context->sgid, context->fsgid, tty,
+		  from_kuid(&init_user_ns, tsk->loginuid),
+		  from_kuid(&init_user_ns, context->uid),
+		  from_kgid(&init_user_ns, context->gid),
+		  from_kuid(&init_user_ns, context->euid),
+		  from_kuid(&init_user_ns, context->suid),
+		  from_kuid(&init_user_ns, context->fsuid),
+		  from_kgid(&init_user_ns, context->egid),
+		  from_kgid(&init_user_ns, context->sgid),
+		  from_kgid(&init_user_ns, context->fsgid),
+		  tty,
 		  tsk->sessionid);
 
 
@@ -2299,14 +2299,14 @@ static atomic_t session_id = ATOMIC_INIT(0);
  *
  * Called (set) from fs/proc/base.c::proc_loginuid_write().
  */
-int audit_set_loginuid(uid_t loginuid)
+int audit_set_loginuid(kuid_t loginuid)
 {
 	struct task_struct *task = current;
 	struct audit_context *context = task->audit_context;
 	unsigned int sessionid;
 
 #ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE
-	if (task->loginuid != -1)
+	if (uid_valid(task->loginuid))
 		return -EPERM;
 #else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
 	if (!capable(CAP_AUDIT_CONTROL))
@@ -2322,8 +2322,10 @@ int audit_set_loginuid(uid_t loginuid)
 			audit_log_format(ab, "login pid=%d uid=%u "
 				"old auid=%u new auid=%u"
 				" old ses=%u new ses=%u",
-				task->pid, task_uid(task),
-				task->loginuid, loginuid,
+				task->pid,
+				from_kuid(&init_user_ns, task_uid(task)),
+				from_kuid(&init_user_ns, task->loginuid),
+				from_kuid(&init_user_ns, loginuid),
 				task->sessionid, sessionid);
 			audit_log_end(ab);
 		}
@@ -2546,15 +2548,14 @@ int __audit_signal_info(int sig, struct task_struct *t)
 	struct audit_aux_data_pids *axp;
 	struct task_struct *tsk = current;
 	struct audit_context *ctx = tsk->audit_context;
-	uid_t uid = current_uid(), t_uid = task_uid(t);
 
 	if (audit_pid && t->tgid == audit_pid) {
 		if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1 || sig == SIGUSR2) {
 			audit_sig_pid = tsk->pid;
-			if (tsk->loginuid != -1)
+			if (uid_valid(tsk->loginuid))
 				audit_sig_uid = tsk->loginuid;
 			else
-				audit_sig_uid = uid;
+				audit_sig_uid = current_uid();
 			security_task_getsecid(tsk, &audit_sig_sid);
 		}
 		if (!audit_signals || audit_dummy_context())
@@ -2566,7 +2567,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
 	if (!ctx->target_pid) {
 		ctx->target_pid = t->tgid;
 		ctx->target_auid = audit_get_loginuid(t);
-		ctx->target_uid = t_uid;
+		ctx->target_uid = task_uid(t);
 		ctx->target_sessionid = audit_get_sessionid(t);
 		security_task_getsecid(t, &ctx->target_sid);
 		memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
@@ -2587,7 +2588,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
 
 	axp->target_pid[axp->pid_count] = t->tgid;
 	axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
-	axp->target_uid[axp->pid_count] = t_uid;
+	axp->target_uid[axp->pid_count] = task_uid(t);
 	axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
 	security_task_getsecid(t, &axp->target_sid[axp->pid_count]);
 	memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
@@ -2676,9 +2677,10 @@ static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr)
 	gid_t gid;
 	unsigned int sessionid;
 
-	auid = audit_get_loginuid(current);
+	auid = from_kuid(&init_user_ns, audit_get_loginuid(current));
 	sessionid = audit_get_sessionid(current);
-	current_uid_gid(&uid, &gid);
+	uid = from_kuid(&init_user_ns, current_uid());
+	gid = from_kgid(&init_user_ns, current_gid());
 
 	audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
 			 auid, uid, gid, sessionid);
diff --git a/net/core/dev.c b/net/core/dev.c
index 026bb4a..1c0d082 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4524,7 +4524,7 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc)
 				"dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u",
 				dev->name, (dev->flags & IFF_PROMISC),
 				(old_flags & IFF_PROMISC),
-				audit_get_loginuid(current),
+				from_kuid(&init_user_ns, audit_get_loginuid(current)),
 				from_kuid(&init_user_ns, uid),
 				from_kgid(&init_user_ns, gid),
 				audit_get_sessionid(current));
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index e7ff694..729a345 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -1541,7 +1541,7 @@ int __init netlbl_unlabel_defconf(void)
 	 * it is called is at bootup before the audit subsystem is reporting
 	 * messages so don't worry to much about these values. */
 	security_task_getsecid(current, &audit_info.secid);
-	audit_info.loginuid = 0;
+	audit_info.loginuid = GLOBAL_ROOT_UID;
 	audit_info.sessionid = 0;
 
 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 9fae63f..9650c4a 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -109,7 +109,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
 		return NULL;
 
 	audit_log_format(audit_buf, "netlabel: auid=%u ses=%u",
-			 audit_info->loginuid,
+			 from_kuid(&init_user_ns, audit_info->loginuid),
 			 audit_info->sessionid);
 
 	if (audit_info->secid != 0 &&
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index c5a5165..2f47515 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2630,12 +2630,12 @@ static void xfrm_policy_fini(struct net *net)
 
 	flush_work(&net->xfrm.policy_hash_work);
 #ifdef CONFIG_XFRM_SUB_POLICY
-	audit_info.loginuid = -1;
+	audit_info.loginuid = INVALID_UID;
 	audit_info.sessionid = -1;
 	audit_info.secid = 0;
 	xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, &audit_info);
 #endif
-	audit_info.loginuid = -1;
+	audit_info.loginuid = INVALID_UID;
 	audit_info.sessionid = -1;
 	audit_info.secid = 0;
 	xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info);
@@ -2742,7 +2742,7 @@ static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp,
 }
 
 void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
-			   uid_t auid, u32 sessionid, u32 secid)
+			   kuid_t auid, u32 sessionid, u32 secid)
 {
 	struct audit_buffer *audit_buf;
 
@@ -2757,7 +2757,7 @@ void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
 EXPORT_SYMBOL_GPL(xfrm_audit_policy_add);
 
 void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
-			      uid_t auid, u32 sessionid, u32 secid)
+			      kuid_t auid, u32 sessionid, u32 secid)
 {
 	struct audit_buffer *audit_buf;
 
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 5b228f9..fce6a49 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -2045,7 +2045,7 @@ void xfrm_state_fini(struct net *net)
 	unsigned int sz;
 
 	flush_work(&net->xfrm.state_hash_work);
-	audit_info.loginuid = -1;
+	audit_info.loginuid = INVALID_UID;
 	audit_info.sessionid = -1;
 	audit_info.secid = 0;
 	xfrm_state_flush(net, IPSEC_PROTO_ANY, &audit_info);
@@ -2112,7 +2112,7 @@ static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
 }
 
 void xfrm_audit_state_add(struct xfrm_state *x, int result,
-			  uid_t auid, u32 sessionid, u32 secid)
+			  kuid_t auid, u32 sessionid, u32 secid)
 {
 	struct audit_buffer *audit_buf;
 
@@ -2127,7 +2127,7 @@ void xfrm_audit_state_add(struct xfrm_state *x, int result,
 EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
 
 void xfrm_audit_state_delete(struct xfrm_state *x, int result,
-			     uid_t auid, u32 sessionid, u32 secid)
+			     kuid_t auid, u32 sessionid, u32 secid)
 {
 	struct audit_buffer *audit_buf;
 
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index e75d8e4..9ea55db 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -575,7 +575,7 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
 	struct xfrm_state *x;
 	int err;
 	struct km_event c;
-	uid_t loginuid = audit_get_loginuid(current);
+	kuid_t loginuid = audit_get_loginuid(current);
 	u32 sessionid = audit_get_sessionid(current);
 	u32 sid;
 
@@ -654,7 +654,7 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
 	int err = -ESRCH;
 	struct km_event c;
 	struct xfrm_usersa_id *p = nlmsg_data(nlh);
-	uid_t loginuid = audit_get_loginuid(current);
+	kuid_t loginuid = audit_get_loginuid(current);
 	u32 sessionid = audit_get_sessionid(current);
 	u32 sid;
 
@@ -1369,7 +1369,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
 	struct km_event c;
 	int err;
 	int excl;
-	uid_t loginuid = audit_get_loginuid(current);
+	kuid_t loginuid = audit_get_loginuid(current);
 	u32 sessionid = audit_get_sessionid(current);
 	u32 sid;
 
@@ -1624,7 +1624,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
 					    NETLINK_CB(skb).pid);
 		}
 	} else {
-		uid_t loginuid = audit_get_loginuid(current);
+		kuid_t loginuid = audit_get_loginuid(current);
 		u32 sessionid = audit_get_sessionid(current);
 		u32 sid;
 
@@ -1918,7 +1918,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	err = 0;
 	if (up->hard) {
-		uid_t loginuid = audit_get_loginuid(current);
+		kuid_t loginuid = audit_get_loginuid(current);
 		u32 sessionid = audit_get_sessionid(current);
 		u32 sid;
 
@@ -1961,7 +1961,7 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
 	km_state_expired(x, ue->hard, current->pid);
 
 	if (ue->hard) {
-		uid_t loginuid = audit_get_loginuid(current);
+		kuid_t loginuid = audit_get_loginuid(current);
 		u32 sessionid = audit_get_sessionid(current);
 		u32 sid;
 
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [REVIEW][PATCH 09/15] userns: Convert process event connector to handle kuids and kgids
  2012-08-26 12:33   ` Evgeniy Polyakov
@ 2012-08-26 13:43     ` Eric W. Biederman
  0 siblings, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-26 13:43 UTC (permalink / raw)
  To: Evgeniy Polyakov
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn, David Miller

Evgeniy Polyakov <zbr@ioremap.net> writes:

> On Sat, Aug 25, 2012 at 05:02:59PM -0700, Eric W. Biederman (ebiederm@xmission.com) wrote:
>> 
>> - Only allow asking for events from the initial user and pid namespace,
>>   where we generate the events in.
>> 
>> - Convert kuids and kgids into the initial user namespace to report
>>   them via the process event connector.
>
>
> Looks good, if IDs are really supposed to be sent only from root
> namespace.

It is more about where events are recevied rather than where events are
sent from.

With this change events continue to be sent from all processes but can
only be received by processes in the initial user and initial pid
namespace.

To processes in other namespaces the uids and pids that the proc
connector code puts into it's messages are just non-sense, so I
cause the registration of connector clients in other namespaces to fail.

All of that I can do easily without a complete reworking of the current
connector code.  Which is enough for my current goal of building able
to build a kernel with all features enabled and only loosing features
if you are in somethin other than the initial namespaces.


> And you dropped PROC_EVENTS from init/Kconfig, but since it
> was no, it should be ok by default.

The removal of PROC_EVENTS from init/Kconfig was removing of the compile
guard that kept PROC_EVENTS and USER_NS from being selected at the same
time.  The curent user namespace code simply disables code that fails
to build when user namespace support is enabled.

> Feel free to add my acked-by: Evgeniy Polyakov <zbr@ioremap.net>
> Although I thoughs it could be more interesting to generate events
> including namespace id

There isn't a namespace id.  It is perfectly possible to generate events
that can be received by processes in multiple pid and user nameapces
just by calling pid_nr_ns() and from_kuid() with the right parameters.
The challenge is figuring out what namespaces have listening netlink
sockets we should send messages to.

Adding support for recepetion of connector proc events by listeners in
other namespaces looks like it would require near complete rewrite of
the connector code:
- Adding support for connector netlink sockets in other than the initial
  network namespace.
- Tracking which sockets were opened in which pid and which user
  namespaces.
- Filtering messages based on which namespaces the clients are listening
  in.
- Generating the different messages for the different sets of clients.

When someone cares enough I am certain the code will get written.
Having a clear unambigous that configuration does not work is
the first step in getting there.

I presume that whatever listens to connector based proc events listens
for the appropriate ack when registering and the daemon will fail to
start up.

Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [REVIEW][PATCH 0/15] userns subsystem conversions
       [not found] ` <9E0E8AAC-9548-4009-AE29-D368244D8EEA@dubeyko.com>
@ 2012-08-26 14:25   ` Eric W. Biederman
  0 siblings, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-26 14:25 UTC (permalink / raw)
  To: Vyacheslav Dubeyko
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn, David Miller

Vyacheslav Dubeyko <slava@dubeyko.com> writes:

> HI,
>
> On Aug 26, 2012, at 3:54 AM, Eric W. Biederman wrote:
>> 
>> fs/9p/acl.c                       |    8 +-
>> fs/btrfs/acl.c                    |    8 +-
>> fs/configfs/inode.c               |    4 +-
>> fs/debugfs/inode.c                |   26 +++--
>> fs/ext2/acl.c                     |   32 ++++--
>> fs/ext3/acl.c                     |   32 ++++--
>> fs/ext4/acl.c                     |   31 ++++--
>> fs/generic_acl.c                  |    4 +-
>> fs/gfs2/acl.c                     |   14 ++--
>> fs/gfs2/quota.c                   |   44 +++++---
>> fs/jffs2/acl.c                    |    4 +-
>> fs/jfs/acl.c                      |    4 +-
>> fs/jfs/xattr.c                    |    4 +-
>> fs/nfs/nfs3acl.c                  |    4 +-
>> fs/nfsd/vfs.c                     |    8 +-
>> fs/ocfs2/acl.c                    |    4 +-
>> fs/ocfs2/file.c                   |    6 +-
>> fs/ocfs2/quota_global.c           |   34 +++++--
>> fs/ocfs2/quota_local.c            |   12 ++-
>> fs/posix_acl.c                    |   30 +++---
>> fs/proc/base.c                    |   12 ++-
>> fs/quota/dquot.c                  |   43 ++++----
>> fs/quota/netlink.c                |   11 ++-
>> fs/quota/quota.c                  |   44 +++++---
>> fs/quota/quota_tree.c             |   20 +++-
>> fs/quota/quota_v1.c               |    8 +-
>> fs/quota/quota_v2.c               |   14 ++-
>> drivers/connector/cn_proc.c       |   18 +++-
>> drivers/gpu/drm/drm_fops.c        |    3 +-
>> drivers/gpu/drm/drm_info.c        |    5 +-
>> drivers/gpu/drm/drm_ioctl.c       |    4 +-
>> drivers/tty/tty_audit.c           |   16 ++--
>> fs/9p/acl.c                       |    8 +-
>> fs/btrfs/acl.c                    |    8 +-
>> fs/configfs/inode.c               |    4 +-
>> fs/debugfs/inode.c                |   26 +++--
>> fs/ext2/acl.c                     |   32 ++++--
>> fs/ext3/acl.c                     |   32 ++++--
>> fs/ext4/acl.c                     |   31 ++++--
>> fs/generic_acl.c                  |    4 +-
>> fs/gfs2/acl.c                     |   14 ++--
>> fs/gfs2/quota.c                   |   44 +++++---
>> fs/jffs2/acl.c                    |    4 +-
>> fs/jfs/acl.c                      |    4 +-
>> fs/jfs/xattr.c                    |    4 +-
>> fs/nfs/nfs3acl.c                  |    4 +-
>> fs/nfsd/vfs.c                     |    8 +-
>> fs/ocfs2/acl.c                    |    4 +-
>> fs/ocfs2/file.c                   |    6 +-
>> fs/ocfs2/quota_global.c           |   34 +++++--
>> fs/ocfs2/quota_local.c            |   12 ++-
>> fs/posix_acl.c                    |   30 +++---
>> fs/proc/base.c                    |   12 ++-
>> fs/quota/dquot.c                  |   43 ++++----
>> fs/quota/netlink.c                |   11 ++-
>> fs/quota/quota.c                  |   44 +++++---
>> fs/quota/quota_tree.c             |   20 +++-
>> fs/quota/quota_v1.c               |    8 +-
>> fs/quota/quota_v2.c               |   14 ++-
>> fs/reiserfs/xattr_acl.c           |    4 +-
>> fs/xattr.c                        |    7 ++
>> fs/xattr_acl.c                    |   96 +++++++++++++++--
>> fs/xfs/xfs_acl.c                  |    4 +-
>> fs/xfs/xfs_quotaops.c             |   18 ++--
>> fs/xfs/xfs_trans_dquot.c          |    8 +-
>
>
> Sorry, maybe I misunderstand something. But I can't find in the patch
> set changes in concrete filesystems' code.

I assume the problem is patches 6 8 13 and 14 didn't make it through to
the mailling for some reason.

Just to see what is going on I you can look at my development branch
git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git userns-always-map-user-v48

Meanwhile I am going to scratch my head and try and resolve my technical
patch sending difficulties.

Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [REVIEW][PATCH 13/15] userns: Add basic quota support
       [not found] ` <87harqecvk.fsf@xmission.com>
@ 2012-08-27  8:50   ` Jan Kara
  2012-08-27 15:54     ` Eric W. Biederman
  2012-08-28  0:12     ` [PATCH] userns: Add basic quota support v2 Eric W. Biederman
  2012-08-27  8:58   ` [REVIEW][PATCH 13/15] userns: Add basic quota support Steven Whitehouse
  1 sibling, 2 replies; 37+ messages in thread
From: Jan Kara @ 2012-08-27  8:50 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, cluster-devel, Mark Fasheh,
	Joel Becker, ocfs2-devel, Ben Myers, Alex Elder, xfs, Jan Kara,
	Dmitry Monakhov

  Hello,

On Sat 25-08-12 17:05:35, Eric W. Biederman wrote:
> Two helper are added dqgetusr and dqgetgrp to allow the quota
> infrastructure to be called with a kuid and a kgid respectively.  This
> creates type safe variants of dqget and leads to shorter more
> comprehensible code.
  It would look more comprehensible to me to have functions like:
kuid2qown() and kgid2qown() and then call dqget(sb, kuid2qown(attr->uid))
(see below for qown_t change proposal). The code then at the first look
explains what is going on... Hmm?

> Place the USRQUOTA and GRPQUOTA defines into enum quota_type.  This
> brings with it the ability for the compiler to check that switch
> statements handle every quota type, and the ability to mark which
> values store the type of a quota entry.
  OK, makes sense.

> Add the data type qown_t a union of kuid_t and kgid_t. qown_t is a
> replacement for the implicit union of uid and gid stored in an
> unsigned int that is was used in the quota data structures.  Making
> the data type explicit allows the kuid_t and kgid_t type safety to
> propogate more thoroughly through the code, revealing more places
> where uid/gid conversions need be made.
  Hum, when we already do this, wouldn't it make more sense to embed quota
type in qown_t? Because with the union thing you have no meaningful way of
accessing that type without having quota type anyway. So having that in a
single structure makes a lot of sense, plus it makes prototypes shorter...
And you have to call make_qown() anyway...

> Allong with the data type qown_t comes the helper functions
> qown_eq, from_qown, from_qown_munged, qown_valid, and make_qown.
> 
> Update struct dquot dq_id to be a qown_t.
> 
> Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
> and dquot_set_dqblk to use enum quota_type and qown_t.
> 
> Make minimal changes to gfs2, ocfs2, and xfs to deal with the change
> in quota structures and signatures.  The ocfs2 changes are larger than
> most because of the extensive tracing throughout the ocfs2 quota code
> that prints out dq_id.
  Otherwise the changes look OK to me, although I didn't check them in
detail yet (as above suggestions will change the code anyway).

								Honza
> 
> Cc: Steven Whitehouse <swhiteho@redhat.com>
> Cc: cluster-devel@redhat.com
> Cc: Mark Fasheh <mfasheh@suse.com>
> Cc: Joel Becker <jlbec@evilplan.org>
> Cc: ocfs2-devel@oss.oracle.com
> Cc: Ben Myers <bpm@sgi.com>
> Cc: Alex Elder <elder@kernel.org>
> Cc: xfs@oss.sgi.com
> Cc: Jan Kara <jack@suse.cz>
> Cc: Dmitry Monakhov <dmonakhov@openvz.org>
> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
> ---
>  fs/gfs2/quota.c          |   44 ++++++++++++++---------
>  fs/ocfs2/file.c          |    6 +--
>  fs/ocfs2/quota_global.c  |   34 +++++++++++++-----
>  fs/ocfs2/quota_local.c   |   12 +++++--
>  fs/quota/dquot.c         |   43 ++++++++++++----------
>  fs/quota/netlink.c       |   11 ++++--
>  fs/quota/quota.c         |   44 +++++++++++++++-------
>  fs/quota/quota_tree.c    |   20 +++++++---
>  fs/quota/quota_v1.c      |    8 +++--
>  fs/quota/quota_v2.c      |   14 +++++--
>  fs/xfs/xfs_quotaops.c    |   18 ++++++----
>  fs/xfs/xfs_trans_dquot.c |    8 +++--
>  include/linux/quota.h    |   91 +++++++++++++++++++++++++++++++++++++++++++---
>  include/linux/quotaops.h |   18 +++++++--
>  init/Kconfig             |    2 -
>  15 files changed, 270 insertions(+), 103 deletions(-)
> 
> diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
> index a3bde91..858f052 100644
> --- a/fs/gfs2/quota.c
> +++ b/fs/gfs2/quota.c
> @@ -1057,6 +1057,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
>                  return 0;
>  
>  	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
> +		enum quota_type qtype;
> +		qown_t qown;
>  		qd = ip->i_res->rs_qa_qd[x];
>  
>  		if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
> @@ -1068,10 +1070,11 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
>  		value += qd->qd_change;
>  		spin_unlock(&qd_lru_lock);
>  
> +		qtype = test_bit(QDF_USER, &qd->qd_flags) ? USRQUOTA : GRPQUOTA;
> +		qown = make_qown(&init_user_ns, qtype, qd->qd_id);
>  		if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
>  			print_message(qd, "exceeded");
> -			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
> -					   USRQUOTA : GRPQUOTA, qd->qd_id,
> +			quota_send_warning(qtype, qown,
>  					   sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);
>  
>  			error = -EDQUOT;
> @@ -1081,8 +1084,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
>  			   time_after_eq(jiffies, qd->qd_last_warn +
>  					 gfs2_tune_get(sdp,
>  						gt_quota_warn_period) * HZ)) {
> -			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
> -					   USRQUOTA : GRPQUOTA, qd->qd_id,
> +			quota_send_warning(qtype, qown,
>  					   sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN);
>  			error = print_message(qd, "warning");
>  			qd->qd_last_warn = jiffies;
> @@ -1469,28 +1471,32 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
>  	return 0;
>  }
>  
> -static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
> -			  struct fs_disk_quota *fdq)
> +static int gfs2_get_dqblk(struct super_block *sb, enum quota_type type,
> +			  qown_t id, struct fs_disk_quota *fdq)
>  {
>  	struct gfs2_sbd *sdp = sb->s_fs_info;
>  	struct gfs2_quota_lvb *qlvb;
>  	struct gfs2_quota_data *qd;
>  	struct gfs2_holder q_gh;
>  	int error;
> +	int user;
> +	u32 gfs_id;
>  
>  	memset(fdq, 0, sizeof(struct fs_disk_quota));
>  
>  	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
>  		return -ESRCH; /* Crazy XFS error code */
>  
> +	gfs_id = from_qown(&init_user_ns, type, id);
> +
>  	if (type == USRQUOTA)
> -		type = QUOTA_USER;
> +		user = QUOTA_USER;
>  	else if (type == GRPQUOTA)
> -		type = QUOTA_GROUP;
> +		user = QUOTA_GROUP;
>  	else
>  		return -EINVAL;
>  
> -	error = qd_get(sdp, type, id, &qd);
> +	error = qd_get(sdp, user, gfs_id, &qd);
>  	if (error)
>  		return error;
>  	error = do_glock(qd, FORCE, &q_gh);
> @@ -1499,8 +1505,8 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
>  
>  	qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
>  	fdq->d_version = FS_DQUOT_VERSION;
> -	fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
> -	fdq->d_id = id;
> +	fdq->d_flags = (user == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
> +	fdq->d_id = gfs_id;
>  	fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;
>  	fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;
>  	fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift;
> @@ -1514,8 +1520,8 @@ out:
>  /* GFS2 only supports a subset of the XFS fields */
>  #define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT)
>  
> -static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
> -			  struct fs_disk_quota *fdq)
> +static int gfs2_set_dqblk(struct super_block *sb, enum quota_type type,
> +			  qown_t id, struct fs_disk_quota *fdq)
>  {
>  	struct gfs2_sbd *sdp = sb->s_fs_info;
>  	struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
> @@ -1526,18 +1532,22 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
>  	int alloc_required;
>  	loff_t offset;
>  	int error;
> +	int user;
> +	u32 gfs_id;
>  
>  	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
>  		return -ESRCH; /* Crazy XFS error code */
>  
> +	gfs_id = from_qown(&init_user_ns, type, id);
> +
>  	switch(type) {
>  	case USRQUOTA:
> -		type = QUOTA_USER;
> +		user = QUOTA_USER;
>  		if (fdq->d_flags != FS_USER_QUOTA)
>  			return -EINVAL;
>  		break;
>  	case GRPQUOTA:
> -		type = QUOTA_GROUP;
> +		user = QUOTA_GROUP;
>  		if (fdq->d_flags != FS_GROUP_QUOTA)
>  			return -EINVAL;
>  		break;
> @@ -1547,10 +1557,10 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
>  
>  	if (fdq->d_fieldmask & ~GFS2_FIELDMASK)
>  		return -EINVAL;
> -	if (fdq->d_id != id)
> +	if (fdq->d_id != gfs_id)
>  		return -EINVAL;
>  
> -	error = qd_get(sdp, type, id, &qd);
> +	error = qd_get(sdp, user, gfs_id, &qd);
>  	if (error)
>  		return error;
>  
> diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> index 46a1f6d..063e889 100644
> --- a/fs/ocfs2/file.c
> +++ b/fs/ocfs2/file.c
> @@ -1184,8 +1184,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
>  		if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
>  		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
>  		    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
> -			transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
> -						      USRQUOTA);
> +			transfer_to[USRQUOTA] = dqgetusr(sb, attr->ia_uid);
>  			if (!transfer_to[USRQUOTA]) {
>  				status = -ESRCH;
>  				goto bail_unlock;
> @@ -1194,8 +1193,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
>  		if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid
>  		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
>  		    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
> -			transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
> -						      GRPQUOTA);
> +			transfer_to[GRPQUOTA] = dqgetgrp(sb, attr->ia_gid);
>  			if (!transfer_to[GRPQUOTA]) {
>  				status = -ESRCH;
>  				goto bail_unlock;
> diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
> index 0a86e30..88360f1 100644
> --- a/fs/ocfs2/quota_global.c
> +++ b/fs/ocfs2/quota_global.c
> @@ -95,7 +95,8 @@ static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
>  	struct ocfs2_global_disk_dqblk *d = dp;
>  	struct mem_dqblk *m = &dquot->dq_dqb;
>  
> -	d->dqb_id = cpu_to_le32(dquot->dq_id);
> +	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_type,
> +					  dquot->dq_id));
>  	d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
>  	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
>  	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
> @@ -113,10 +114,13 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
>  	struct ocfs2_global_disk_dqblk *d = dp;
>  	struct ocfs2_mem_dqinfo *oinfo =
>  			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
> +	qown_t qown;
>  
>  	if (qtree_entry_unused(&oinfo->dqi_gi, dp))
>  		return 0;
> -	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
> +
> +	qown = make_qown(&init_user_ns, dquot->dq_type, le32_to_cpu(d->dqb_id));
> +	return qown_eq(qown, dquot->dq_id, dquot->dq_type);
>  }
>  
>  struct qtree_fmt_operations ocfs2_global_ops = {
> @@ -504,7 +508,9 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
>  	olditime = dquot->dq_dqb.dqb_itime;
>  	oldbtime = dquot->dq_dqb.dqb_btime;
>  	ocfs2_global_disk2memdqb(dquot, &dqblk);
> -	trace_ocfs2_sync_dquot(dquot->dq_id, dquot->dq_dqb.dqb_curspace,
> +	trace_ocfs2_sync_dquot(from_qown(&init_user_ns, dquot->dq_type,
> +					 dquot->dq_id),
> +			       dquot->dq_dqb.dqb_curspace,
>  			       (long long)spacechange,
>  			       dquot->dq_dqb.dqb_curinodes,
>  			       (long long)inodechange);
> @@ -556,7 +562,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
>  	if (err < 0) {
>  		mlog(ML_ERROR, "Failed to lock quota info, losing quota write"
>  			       " (type=%d, id=%u)\n", dquot->dq_type,
> -			       (unsigned)dquot->dq_id);
> +			       (unsigned)from_qown(&init_user_ns, dquot->dq_type,
> +						   dquot->dq_id));
>  		goto out;
>  	}
>  	if (freeing)
> @@ -591,7 +598,9 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
>  	struct ocfs2_super *osb = OCFS2_SB(sb);
>  	int status = 0;
>  
> -	trace_ocfs2_sync_dquot_helper(dquot->dq_id, dquot->dq_type,
> +	trace_ocfs2_sync_dquot_helper(from_qown(&init_user_ns, dquot->dq_type,
> +						dquot->dq_id),
> +				      dquot->dq_type,
>  				      type, sb->s_id);
>  	if (type != dquot->dq_type)
>  		goto out;
> @@ -643,7 +652,9 @@ static int ocfs2_write_dquot(struct dquot *dquot)
>  	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
>  	int status = 0;
>  
> -	trace_ocfs2_write_dquot(dquot->dq_id, dquot->dq_type);
> +	trace_ocfs2_write_dquot(from_qown(&init_user_ns, dquot->dq_type,
> +					   dquot->dq_id),
> +				dquot->dq_type);
>  
>  	handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
>  	if (IS_ERR(handle)) {
> @@ -681,7 +692,9 @@ static int ocfs2_release_dquot(struct dquot *dquot)
>  	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
>  	int status = 0;
>  
> -	trace_ocfs2_release_dquot(dquot->dq_id, dquot->dq_type);
> +	trace_ocfs2_release_dquot(from_qown(&init_user_ns, dquot->dq_type,
> +					    dquot->dq_id),
> +				  dquot->dq_type);
>  
>  	mutex_lock(&dquot->dq_lock);
>  	/* Check whether we are not racing with some other dqget() */
> @@ -739,7 +752,8 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
>  	int need_alloc = ocfs2_global_qinit_alloc(sb, type);
>  	handle_t *handle;
>  
> -	trace_ocfs2_acquire_dquot(dquot->dq_id, type);
> +	trace_ocfs2_acquire_dquot(from_qown(&init_user_ns, type, dquot->dq_id),
> +				  type);
>  	mutex_lock(&dquot->dq_lock);
>  	/*
>  	 * We need an exclusive lock, because we're going to update use count
> @@ -826,7 +840,9 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
>  	handle_t *handle;
>  	struct ocfs2_super *osb = OCFS2_SB(sb);
>  
> -	trace_ocfs2_mark_dquot_dirty(dquot->dq_id, type);
> +	trace_ocfs2_mark_dquot_dirty(from_qown(&init_user_ns, type,
> +					       dquot->dq_id),
> +				     type);
>  
>  	/* In case user set some limits, sync dquot immediately to global
>  	 * quota file so that information propagates quicker */
> diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
> index f100bf7..a80936e 100644
> --- a/fs/ocfs2/quota_local.c
> +++ b/fs/ocfs2/quota_local.c
> @@ -501,7 +501,10 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
>  			}
>  			dqblk = (struct ocfs2_local_disk_dqblk *)(qbh->b_data +
>  				ol_dqblk_block_off(sb, chunk, bit));
> -			dquot = dqget(sb, le64_to_cpu(dqblk->dqb_id), type);
> +			dquot = dqget(sb,
> +				      make_qown(&init_user_ns, type,
> +						le64_to_cpu(dqblk->dqb_id)),
> +				      type);
>  			if (!dquot) {
>  				status = -EIO;
>  				mlog(ML_ERROR, "Failed to get quota structure "
> @@ -881,7 +884,9 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
>  	dqblk = (struct ocfs2_local_disk_dqblk *)(bh->b_data
>  		+ ol_dqblk_block_offset(sb, od->dq_local_off));
>  
> -	dqblk->dqb_id = cpu_to_le64(od->dq_dquot.dq_id);
> +	dqblk->dqb_id = cpu_to_le64(from_qown(&init_user_ns,
> +					      od->dq_dquot.dq_type,
> +					      od->dq_dquot.dq_id));
>  	spin_lock(&dq_data_lock);
>  	dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace -
>  					  od->dq_origspace);
> @@ -891,7 +896,8 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
>  	trace_olq_set_dquot(
>  		(unsigned long long)le64_to_cpu(dqblk->dqb_spacemod),
>  		(unsigned long long)le64_to_cpu(dqblk->dqb_inodemod),
> -		od->dq_dquot.dq_id);
> +		from_qown(&init_user_ns, od->dq_dquot.dq_type,
> +			  od->dq_dquot.dq_id));
>  }
>  
>  /* Write dquot to local quota file */
> diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
> index 36a29b7..5fbd1d9a 100644
> --- a/fs/quota/dquot.c
> +++ b/fs/quota/dquot.c
> @@ -253,10 +253,12 @@ static qsize_t inode_get_rsv_space(struct inode *inode);
>  static void __dquot_initialize(struct inode *inode, int type);
>  
>  static inline unsigned int
> -hashfn(const struct super_block *sb, unsigned int id, int type)
> +hashfn(const struct super_block *sb, qown_t qown, enum quota_type type)
>  {
> +	unsigned int id;
>  	unsigned long tmp;
>  
> +	id = from_qown(&init_user_ns, type, qown);
>  	tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type);
>  	return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask;
>  }
> @@ -277,15 +279,15 @@ static inline void remove_dquot_hash(struct dquot *dquot)
>  }
>  
>  static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb,
> -				unsigned int id, int type)
> +				qown_t id, enum quota_type type)
>  {
>  	struct hlist_node *node;
>  	struct dquot *dquot;
>  
>  	hlist_for_each (node, dquot_hash+hashent) {
>  		dquot = hlist_entry(node, struct dquot, dq_hash);
> -		if (dquot->dq_sb == sb && dquot->dq_id == id &&
> -		    dquot->dq_type == type)
> +		if (dquot->dq_sb == sb && dquot->dq_type == type &&
> +		    qown_eq(dquot->dq_id, id, type))
>  			return dquot;
>  	}
>  	return NULL;
> @@ -741,7 +743,9 @@ void dqput(struct dquot *dquot)
>  #ifdef CONFIG_QUOTA_DEBUG
>  	if (!atomic_read(&dquot->dq_count)) {
>  		quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
> -			    quotatypes[dquot->dq_type], dquot->dq_id);
> +			    quotatypes[dquot->dq_type],
> +			    from_qown(&init_user_ns, dquot->dq_type,
> +				      dquot->dq_id));
>  		BUG();
>  	}
>  #endif
> @@ -829,7 +833,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
>   *   a) checking for quota flags under dq_list_lock and
>   *   b) getting a reference to dquot before we release dq_list_lock
>   */
> -struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
> +struct dquot *dqget(struct super_block *sb, qown_t id, enum quota_type type)
>  {
>  	unsigned int hashent = hashfn(sb, id, type);
>  	struct dquot *dquot = NULL, *empty = NULL;
> @@ -1129,7 +1133,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
>  
>  struct dquot_warn {
>  	struct super_block *w_sb;
> -	qid_t w_dq_id;
> +	qown_t w_dq_id;
>  	short w_dq_type;
>  	short w_type;
>  };
> @@ -1156,9 +1160,9 @@ static int need_print_warning(struct dquot_warn *warn)
>  
>  	switch (warn->w_dq_type) {
>  		case USRQUOTA:
> -			return current_fsuid() == warn->w_dq_id;
> +			return uid_eq(current_fsuid(), warn->w_dq_id.uid);
>  		case GRPQUOTA:
> -			return in_group_p(warn->w_dq_id);
> +			return in_group_p(warn->w_dq_id.gid);
>  	}
>  	return 0;
>  }
> @@ -1390,7 +1394,6 @@ static int dquot_active(const struct inode *inode)
>   */
>  static void __dquot_initialize(struct inode *inode, int type)
>  {
> -	unsigned int id = 0;
>  	int cnt;
>  	struct dquot *got[MAXQUOTAS];
>  	struct super_block *sb = inode->i_sb;
> @@ -1403,15 +1406,16 @@ static void __dquot_initialize(struct inode *inode, int type)
>  
>  	/* First get references to structures we might need. */
>  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> +		qown_t id;
>  		got[cnt] = NULL;
>  		if (type != -1 && cnt != type)
>  			continue;
>  		switch (cnt) {
>  		case USRQUOTA:
> -			id = inode->i_uid;
> +			id.uid = inode->i_uid;
>  			break;
>  		case GRPQUOTA:
> -			id = inode->i_gid;
> +			id.gid = inode->i_gid;
>  			break;
>  		}
>  		got[cnt] = dqget(sb, id, cnt);
> @@ -1897,10 +1901,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
>  	if (!dquot_active(inode))
>  		return 0;
>  
> -	if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
> -		transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA);
> -	if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)
> -		transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA);
> +	if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
> +		transfer_to[USRQUOTA] = dqgetusr(sb, iattr->ia_uid);
> +	if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
> +		transfer_to[GRPQUOTA] = dqgetgrp(sb, iattr->ia_gid);
>  
>  	ret = __dquot_transfer(inode, transfer_to);
>  	dqput_all(transfer_to);
> @@ -2362,7 +2366,8 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  	di->d_version = FS_DQUOT_VERSION;
>  	di->d_flags = dquot->dq_type == USRQUOTA ?
>  			FS_USER_QUOTA : FS_GROUP_QUOTA;
> -	di->d_id = dquot->dq_id;
> +	di->d_id = from_qown_munged(current_user_ns(), dquot->dq_type,
> +				    dquot->dq_id);
>  
>  	spin_lock(&dq_data_lock);
>  	di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
> @@ -2376,7 +2381,7 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  	spin_unlock(&dq_data_lock);
>  }
>  
> -int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_get_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		    struct fs_disk_quota *di)
>  {
>  	struct dquot *dquot;
> @@ -2488,7 +2493,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  	return 0;
>  }
>  
> -int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_set_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		  struct fs_disk_quota *di)
>  {
>  	struct dquot *dquot;
> diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
> index d67908b..b2678da 100644
> --- a/fs/quota/netlink.c
> +++ b/fs/quota/netlink.c
> @@ -30,7 +30,7 @@ static struct genl_family quota_genl_family = {
>   *
>   */
>  
> -void quota_send_warning(short type, unsigned int id, dev_t dev,
> +void quota_send_warning(enum quota_type type, qown_t id, dev_t dev,
>  			const char warntype)
>  {
>  	static atomic_t seq;
> @@ -59,7 +59,8 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
>  	ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type);
>  	if (ret)
>  		goto attr_err_out;
> -	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id);
> +	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID,
> +			  from_qown_munged(&init_user_ns, type, id));
>  	if (ret)
>  		goto attr_err_out;
>  	ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
> @@ -71,7 +72,11 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
>  	ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev));
>  	if (ret)
>  		goto attr_err_out;
> -	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
> +	/* Report the current user as seen by the filesystem that issues
> +	 * quota warning.
> +	 */
> +	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID,
> +			  from_kuid_munged(&init_user_ns, current_uid()));
>  	if (ret)
>  		goto attr_err_out;
>  	genlmsg_end(skb, msg_head);
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index 6f15578..b9f44b7 100644
> --- a/fs/quota/quota.c
> +++ b/fs/quota/quota.c
> @@ -32,8 +32,8 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
>  	/* allow to query information for dquots we "own" */
>  	case Q_GETQUOTA:
>  	case Q_XGETQUOTA:
> -		if ((type == USRQUOTA && current_euid() == id) ||
> -		    (type == GRPQUOTA && in_egroup_p(id)))
> +		if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
> +		    (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
>  			break;
>  		/*FALLTHROUGH*/
>  	default:
> @@ -62,7 +62,7 @@ static int quota_sync_all(int type)
>  	return ret;
>  }
>  
> -static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
> +static int quota_quotaon(struct super_block *sb, enum quota_type type, int cmd, qid_t id,
>  		         struct path *path)
>  {
>  	if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta)
> @@ -127,16 +127,20 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
>  	dst->dqb_valid = QIF_ALL;
>  }
>  
> -static int quota_getquota(struct super_block *sb, int type, qid_t id,
> -			  void __user *addr)
> +static int quota_getquota(struct super_block *sb, enum quota_type type,
> +			  qid_t id, void __user *addr)
>  {
> +	qown_t qown;
>  	struct fs_disk_quota fdq;
>  	struct if_dqblk idq;
>  	int ret;
>  
>  	if (!sb->s_qcop->get_dqblk)
>  		return -ENOSYS;
> -	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (qown_valid(type, qown))
> +		return -EINVAL;
> +	ret = sb->s_qcop->get_dqblk(sb, type, qown, &fdq);
>  	if (ret)
>  		return ret;
>  	copy_to_if_dqblk(&idq, &fdq);
> @@ -171,18 +175,22 @@ static void copy_from_if_dqblk(struct fs_disk_quota *dst, struct if_dqblk *src)
>  		dst->d_fieldmask |= FS_DQ_ITIMER;
>  }
>  
> -static int quota_setquota(struct super_block *sb, int type, qid_t id,
> -			  void __user *addr)
> +static int quota_setquota(struct super_block *sb, enum quota_type type,
> +			  qid_t id,  void __user *addr)
>  {
>  	struct fs_disk_quota fdq;
>  	struct if_dqblk idq;
> +	qown_t qown;
>  
>  	if (copy_from_user(&idq, addr, sizeof(idq)))
>  		return -EFAULT;
>  	if (!sb->s_qcop->set_dqblk)
>  		return -ENOSYS;
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (!qown_valid(type, qown))
> +		return -EINVAL;
>  	copy_from_if_dqblk(&fdq, &idq);
> -	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
> +	return sb->s_qcop->set_dqblk(sb, type, qown, &fdq);
>  }
>  
>  static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
> @@ -209,27 +217,35 @@ static int quota_getxstate(struct super_block *sb, void __user *addr)
>  	return ret;
>  }
>  
> -static int quota_setxquota(struct super_block *sb, int type, qid_t id,
> +static int quota_setxquota(struct super_block *sb, enum quota_type type, qid_t id,
>  			   void __user *addr)
>  {
>  	struct fs_disk_quota fdq;
> +	qown_t qown;
>  
>  	if (copy_from_user(&fdq, addr, sizeof(fdq)))
>  		return -EFAULT;
>  	if (!sb->s_qcop->set_dqblk)
>  		return -ENOSYS;
> -	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (!qown_valid(type, qown))
> +		return -EINVAL;
> +	return sb->s_qcop->set_dqblk(sb, type, qown, &fdq);
>  }
>  
> -static int quota_getxquota(struct super_block *sb, int type, qid_t id,
> -			   void __user *addr)
> +static int quota_getxquota(struct super_block *sb, enum quota_type type,
> +			   qid_t id, void __user *addr)
>  {
>  	struct fs_disk_quota fdq;
> +	qown_t qown;
>  	int ret;
>  
>  	if (!sb->s_qcop->get_dqblk)
>  		return -ENOSYS;
> -	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (!qown_valid(type, qown))
> +		return -EINVAL;
> +	ret = sb->s_qcop->get_dqblk(sb, type, qown, &fdq);
>  	if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
>  		return -EFAULT;
>  	return ret;
> diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
> index e41c1becf..4704619 100644
> --- a/fs/quota/quota_tree.c
> +++ b/fs/quota/quota_tree.c
> @@ -22,10 +22,12 @@ MODULE_LICENSE("GPL");
>  
>  #define __QUOTA_QT_PARANOIA
>  
> -static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
> +static int get_index(struct qtree_mem_dqinfo *info, qown_t qown, int depth)
>  {
>  	unsigned int epb = info->dqi_usable_bs >> 2;
> +	qid_t id;
>  
> +	id = from_qown(&init_user_ns, info->dqi_type, qown);
>  	depth = info->dqi_qtree_depth - depth - 1;
>  	while (depth--)
>  		id /= epb;
> @@ -538,8 +540,10 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
>  		ddquot += info->dqi_entry_size;
>  	}
>  	if (i == qtree_dqstr_in_blk(info)) {
> -		quota_error(dquot->dq_sb, "Quota for id %u referenced "
> -			    "but not present", dquot->dq_id);
> +		quota_error(dquot->dq_sb,
> +			    "Quota for id %u referenced but not present",
> +			    from_qown(&init_user_ns, dquot->dq_type,
> +				      dquot->dq_id));
>  		ret = -EIO;
>  		goto out_buf;
>  	} else {
> @@ -607,8 +611,11 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
>  		offset = find_dqentry(info, dquot);
>  		if (offset <= 0) {	/* Entry not present? */
>  			if (offset < 0)
> -				quota_error(sb, "Can't read quota structure "
> -					    "for id %u", dquot->dq_id);
> +				quota_error(sb,"Can't read quota structure "
> +					    "for id %u",
> +					    from_qown(&init_user_ns,
> +						      dquot->dq_type,
> +						      dquot->dq_id));
>  			dquot->dq_off = 0;
>  			set_bit(DQ_FAKE_B, &dquot->dq_flags);
>  			memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
> @@ -626,7 +633,8 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
>  		if (ret >= 0)
>  			ret = -EIO;
>  		quota_error(sb, "Error while reading quota structure for id %u",
> -			    dquot->dq_id);
> +			    from_qown(&init_user_ns, dquot->dq_type,
> +				      dquot->dq_id));
>  		set_bit(DQ_FAKE_B, &dquot->dq_flags);
>  		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
>  		kfree(ddquot);
> diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c
> index 34b37a6..7c028f9 100644
> --- a/fs/quota/quota_v1.c
> +++ b/fs/quota/quota_v1.c
> @@ -63,7 +63,8 @@ static int v1_read_dqblk(struct dquot *dquot)
>  	/* Set structure to 0s in case read fails/is after end of file */
>  	memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
>  	dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk,
> -			sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
> +			sizeof(struct v1_disk_dqblk),
> +			v1_dqoff(from_qown(&init_user_ns, type, dquot->dq_id)));
>  
>  	v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
>  	if (dquot->dq_dqb.dqb_bhardlimit == 0 &&
> @@ -83,7 +84,8 @@ static int v1_commit_dqblk(struct dquot *dquot)
>  	struct v1_disk_dqblk dqblk;
>  
>  	v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
> -	if (dquot->dq_id == 0) {
> +	if (((type == USRQUOTA) && uid_eq(dquot->dq_id.uid, GLOBAL_ROOT_UID)) ||
> +	    ((type == GRPQUOTA) && gid_eq(dquot->dq_id.gid, GLOBAL_ROOT_GID))) {
>  		dqblk.dqb_btime =
>  			sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
>  		dqblk.dqb_itime =
> @@ -93,7 +95,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
>  	if (sb_dqopt(dquot->dq_sb)->files[type])
>  		ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
>  			(char *)&dqblk, sizeof(struct v1_disk_dqblk),
> -			v1_dqoff(dquot->dq_id));
> +			v1_dqoff(from_qown(&init_user_ns, type, dquot->dq_id)));
>  	if (ret != sizeof(struct v1_disk_dqblk)) {
>  		quota_error(dquot->dq_sb, "dquota write failed");
>  		if (ret >= 0)
> diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
> index f1ab360..b9068b7 100644
> --- a/fs/quota/quota_v2.c
> +++ b/fs/quota/quota_v2.c
> @@ -206,7 +206,8 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
>  	d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
>  	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
>  	d->dqb_btime = cpu_to_le64(m->dqb_btime);
> -	d->dqb_id = cpu_to_le32(dquot->dq_id);
> +	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns,
> +					  dquot->dq_type, dquot->dq_id));
>  	if (qtree_entry_unused(info, dp))
>  		d->dqb_itime = cpu_to_le64(1);
>  }
> @@ -216,10 +217,12 @@ static int v2r0_is_id(void *dp, struct dquot *dquot)
>  	struct v2r0_disk_dqblk *d = dp;
>  	struct qtree_mem_dqinfo *info =
>  			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
> +	qown_t qown;
>  
>  	if (qtree_entry_unused(info, dp))
>  		return 0;
> -	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
> +	qown = make_qown(&init_user_ns, dquot->dq_type, le32_to_cpu(d->dqb_id));
> +	return qown_eq(qown, dquot->dq_id, dquot->dq_type);
>  }
>  
>  static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
> @@ -257,7 +260,8 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
>  	d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
>  	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
>  	d->dqb_btime = cpu_to_le64(m->dqb_btime);
> -	d->dqb_id = cpu_to_le32(dquot->dq_id);
> +	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns,
> +					  dquot->dq_type, dquot->dq_id));
>  	if (qtree_entry_unused(info, dp))
>  		d->dqb_itime = cpu_to_le64(1);
>  }
> @@ -267,10 +271,12 @@ static int v2r1_is_id(void *dp, struct dquot *dquot)
>  	struct v2r1_disk_dqblk *d = dp;
>  	struct qtree_mem_dqinfo *info =
>  			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
> +	qown_t qown;
>  
>  	if (qtree_entry_unused(info, dp))
>  		return 0;
> -	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
> +	qown = make_qown(&init_user_ns, dquot->dq_type, le32_to_cpu(d->dqb_id));
> +	return qown_eq(qown, dquot->dq_id, dquot->dq_type);
>  }
>  
>  static int v2_read_dquot(struct dquot *dquot)
> diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
> index fed504f..9ee2d6d 100644
> --- a/fs/xfs/xfs_quotaops.c
> +++ b/fs/xfs/xfs_quotaops.c
> @@ -29,7 +29,7 @@
>  
>  
>  STATIC int
> -xfs_quota_type(int type)
> +xfs_quota_type(enum quota_type type)
>  {
>  	switch (type) {
>  	case USRQUOTA:
> @@ -97,28 +97,31 @@ xfs_fs_set_xstate(
>  STATIC int
>  xfs_fs_get_dqblk(
>  	struct super_block	*sb,
> -	int			type,
> -	qid_t			id,
> +	enum quota_type		type,
> +	qown_t			id,
>  	struct fs_disk_quota	*fdq)
>  {
>  	struct xfs_mount	*mp = XFS_M(sb);
> +	xfs_dqid_t		xfs_id;
>  
>  	if (!XFS_IS_QUOTA_RUNNING(mp))
>  		return -ENOSYS;
>  	if (!XFS_IS_QUOTA_ON(mp))
>  		return -ESRCH;
>  
> -	return -xfs_qm_scall_getquota(mp, id, xfs_quota_type(type), fdq);
> +	xfs_id = from_qown(&init_user_ns, type, id);
> +	return -xfs_qm_scall_getquota(mp, xfs_id, xfs_quota_type(type), fdq);
>  }
>  
>  STATIC int
>  xfs_fs_set_dqblk(
>  	struct super_block	*sb,
> -	int			type,
> -	qid_t			id,
> +	enum quota_type		type,
> +	qown_t			id,
>  	struct fs_disk_quota	*fdq)
>  {
>  	struct xfs_mount	*mp = XFS_M(sb);
> +	xfs_dqid_t		xfs_id;
>  
>  	if (sb->s_flags & MS_RDONLY)
>  		return -EROFS;
> @@ -127,7 +130,8 @@ xfs_fs_set_dqblk(
>  	if (!XFS_IS_QUOTA_ON(mp))
>  		return -ESRCH;
>  
> -	return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq);
> +	xfs_id = from_qown(&init_user_ns, type, id);
> +	return -xfs_qm_scall_setqlim(mp, xfs_id, xfs_quota_type(type), fdq);
>  }
>  
>  const struct quotactl_ops xfs_quotactl_operations = {
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index bcb6054..0c7ab32 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -575,12 +575,14 @@ xfs_quota_warn(
>  	struct xfs_dquot	*dqp,
>  	int			type)
>  {
> +	enum quota_type qtype;
> +	qown_t qown;
>  	/* no warnings for project quotas - we just return ENOSPC later */
>  	if (dqp->dq_flags & XFS_DQ_PROJ)
>  		return;
> -	quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA,
> -			   be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev,
> -			   type);
> +	qtype = (dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA;
> +	qown = make_qown(&init_user_ns, qtype, be32_to_cpu(dqp->q_core.d_id));
> +	quota_send_warning(qtype, qown, mp->m_super->s_dev, type);
>  }
>  
>  /*
> diff --git a/include/linux/quota.h b/include/linux/quota.h
> index 524ede8..67921d5 100644
> --- a/include/linux/quota.h
> +++ b/include/linux/quota.h
> @@ -181,10 +181,91 @@ enum {
>  #include <linux/dqblk_v2.h>
>  
>  #include <linux/atomic.h>
> +#include <linux/uidgid.h>
>  
>  typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
>  typedef long long qsize_t;	/* Type in which we store sizes */
>  
> +#undef USRQUOTA
> +#undef GRPQUOTA
> +enum quota_type {
> +	USRQUOTA = 0,
> +	GRPQUOTA = 1,
> +};
> +
> +typedef union quota_id {
> +	kuid_t uid;
> +	kgid_t gid;
> +} qown_t;			/* Type in which we store the quota owner */
> +
> +static inline bool qown_eq(qown_t left, qown_t right, enum quota_type type)
> +{
> +	switch(type) {
> +	case USRQUOTA:
> +		return uid_eq(left.uid, right.uid);
> +	case GRPQUOTA:
> +		return gid_eq(left.gid, right.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +static inline u32 from_qown(struct user_namespace *user_ns,
> +			    enum quota_type type, qown_t qown)
> +{
> +	switch (type) {
> +	case USRQUOTA:
> +		return from_kuid(user_ns, qown.uid);
> +	case GRPQUOTA:
> +		return from_kgid(user_ns, qown.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +static inline u32 from_qown_munged(struct user_namespace *user_ns,
> +				   enum quota_type type, qown_t qown)
> +{
> +	switch (type) {
> +	case USRQUOTA:
> +		return from_kuid_munged(user_ns, qown.uid);
> +	case GRPQUOTA:
> +		return from_kgid_munged(user_ns, qown.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +static inline qown_t make_qown(struct user_namespace *user_ns,
> +			      enum quota_type type, qid_t id)
> +{
> +	qown_t qown;
> +
> +	switch (type) {
> +	case USRQUOTA:
> +		qown.uid = make_kuid(user_ns, id);
> +		break;
> +	case GRPQUOTA:
> +		qown.gid = make_kgid(user_ns, id);
> +		break;
> +	default:
> +		BUG();
> +	}
> +	return qown;
> +}
> +
> +static inline bool qown_valid(enum quota_type type, qown_t qown)
> +{
> +	switch (type) {
> +	case USRQUOTA:
> +		return uid_valid(qown.uid);
> +	case GRPQUOTA:
> +		return gid_valid(qown.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
>  extern spinlock_t dq_data_lock;
>  
>  /* Maximal numbers of writes for quota operation (insert/delete/update)
> @@ -294,7 +375,7 @@ struct dquot {
>  	atomic_t dq_count;		/* Use count */
>  	wait_queue_head_t dq_wait_unused;	/* Wait queue for dquot to become unused */
>  	struct super_block *dq_sb;	/* superblock this applies to */
> -	unsigned int dq_id;		/* ID this applies to (uid, gid) */
> +	qown_t dq_id;			/* ID this applies to (uid, gid) */
>  	loff_t dq_off;			/* Offset of dquot on disk */
>  	unsigned long dq_flags;		/* See DQ_* */
>  	short dq_type;			/* Type of quota */
> @@ -336,8 +417,8 @@ struct quotactl_ops {
>  	int (*quota_sync)(struct super_block *, int);
>  	int (*get_info)(struct super_block *, int, struct if_dqinfo *);
>  	int (*set_info)(struct super_block *, int, struct if_dqinfo *);
> -	int (*get_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
> -	int (*set_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
> +	int (*get_dqblk)(struct super_block *, enum quota_type, qown_t, struct fs_disk_quota *);
> +	int (*set_dqblk)(struct super_block *, enum quota_type, qown_t, struct fs_disk_quota *);
>  	int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
>  	int (*set_xstate)(struct super_block *, unsigned int, int);
>  };
> @@ -386,10 +467,10 @@ static inline unsigned int dquot_generic_flag(unsigned int flags, int type)
>  }
>  
>  #ifdef CONFIG_QUOTA_NETLINK_INTERFACE
> -extern void quota_send_warning(short type, unsigned int id, dev_t dev,
> +extern void quota_send_warning(enum quota_type type, qown_t id, dev_t dev,
>  			       const char warntype);
>  #else
> -static inline void quota_send_warning(short type, unsigned int id, dev_t dev,
> +static inline void quota_send_warning(enum quota_type type, qown_t id, dev_t dev,
>  				      const char warntype)
>  {
>  	return;
> diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
> index ec6b65f..d988b11 100644
> --- a/include/linux/quotaops.h
> +++ b/include/linux/quotaops.h
> @@ -44,13 +44,23 @@ void inode_sub_rsv_space(struct inode *inode, qsize_t number);
>  
>  void dquot_initialize(struct inode *inode);
>  void dquot_drop(struct inode *inode);
> -struct dquot *dqget(struct super_block *sb, unsigned int id, int type);
> +struct dquot *dqget(struct super_block *sb, qown_t id, enum quota_type type);
>  void dqput(struct dquot *dquot);
>  int dquot_scan_active(struct super_block *sb,
>  		      int (*fn)(struct dquot *dquot, unsigned long priv),
>  		      unsigned long priv);
>  struct dquot *dquot_alloc(struct super_block *sb, int type);
>  void dquot_destroy(struct dquot *dquot);
> +static inline struct dquot *dqgetusr(struct super_block *sb, kuid_t uid)
> +{
> +	qown_t id = { .uid = uid };
> +	return dqget(sb, id, USRQUOTA);
> +}
> +static inline struct dquot *dqgetgrp(struct super_block *sb, kgid_t gid)
> +{
> +	qown_t id = { .gid = gid };
> +	return dqget(sb, id, GRPQUOTA);
> +}
>  
>  int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags);
>  void __dquot_free_space(struct inode *inode, qsize_t number, int flags);
> @@ -87,15 +97,15 @@ int dquot_writeback_dquots(struct super_block *sb, int type);
>  int dquot_quota_sync(struct super_block *sb, int type);
>  int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
>  int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
> -int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_get_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		struct fs_disk_quota *di);
> -int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_set_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		struct fs_disk_quota *di);
>  
>  int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
>  int dquot_transfer(struct inode *inode, struct iattr *iattr);
>  
> -static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type)
> +static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, enum quota_type type)
>  {
>  	return sb_dqopt(sb)->info + type;
>  }
> diff --git a/init/Kconfig b/init/Kconfig
> index 2a388e5..a0bccce 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -928,8 +928,6 @@ config UIDGID_CONVERTED
>  	depends on IMA = n
>  	depends on EVM = n
>  	depends on FS_POSIX_ACL = n
> -	depends on QUOTA = n
> -	depends on QUOTACTL = n
>  
>  	# Networking
>  	depends on NET_9P = n
> -- 
> 1.7.5.4
> 
-- 
Jan Kara <jack@suse.cz>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [REVIEW][PATCH 13/15] userns: Add basic quota support
       [not found] ` <87harqecvk.fsf@xmission.com>
  2012-08-27  8:50   ` [REVIEW][PATCH 13/15] userns: Add basic quota support Jan Kara
@ 2012-08-27  8:58   ` Steven Whitehouse
  1 sibling, 0 replies; 37+ messages in thread
From: Steven Whitehouse @ 2012-08-27  8:58 UTC (permalink / raw)
  To: Eric W. Biederman, Abhijith Das
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, cluster-devel, Mark Fasheh, Joel Becker,
	ocfs2-devel, Ben Myers, Alex Elder, xfs, Jan Kara,
	Dmitry Monakhov

Hi,

On Sat, 2012-08-25 at 17:05 -0700, Eric W. Biederman wrote:
> Two helper are added dqgetusr and dqgetgrp to allow the quota
> infrastructure to be called with a kuid and a kgid respectively.  This
> creates type safe variants of dqget and leads to shorter more
> comprehensible code.
> 
> Place the USRQUOTA and GRPQUOTA defines into enum quota_type.  This
> brings with it the ability for the compiler to check that switch
> statements handle every quota type, and the ability to mark which
> values store the type of a quota entry.
> 
> Add the data type qown_t a union of kuid_t and kgid_t. qown_t is a
> replacement for the implicit union of uid and gid stored in an
> unsigned int that is was used in the quota data structures.  Making
> the data type explicit allows the kuid_t and kgid_t type safety to
> propogate more thoroughly through the code, revealing more places
> where uid/gid conversions need be made.
> 
> Allong with the data type qown_t comes the helper functions
> qown_eq, from_qown, from_qown_munged, qown_valid, and make_qown.
> 
> Update struct dquot dq_id to be a qown_t.
> 
> Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
> and dquot_set_dqblk to use enum quota_type and qown_t.
> 
> Make minimal changes to gfs2, ocfs2, and xfs to deal with the change
> in quota structures and signatures.  The ocfs2 changes are larger than
> most because of the extensive tracing throughout the ocfs2 quota code
> that prints out dq_id.
> 

I think this is ok from the GFS2 perspective. Abhi, does it look ok to
you?

Steve.




> Cc: Steven Whitehouse <swhiteho@redhat.com>
> Cc: cluster-devel@redhat.com
> Cc: Mark Fasheh <mfasheh@suse.com>
> Cc: Joel Becker <jlbec@evilplan.org>
> Cc: ocfs2-devel@oss.oracle.com
> Cc: Ben Myers <bpm@sgi.com>
> Cc: Alex Elder <elder@kernel.org>
> Cc: xfs@oss.sgi.com
> Cc: Jan Kara <jack@suse.cz>
> Cc: Dmitry Monakhov <dmonakhov@openvz.org>
> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
> ---
>  fs/gfs2/quota.c          |   44 ++++++++++++++---------
>  fs/ocfs2/file.c          |    6 +--
>  fs/ocfs2/quota_global.c  |   34 +++++++++++++-----
>  fs/ocfs2/quota_local.c   |   12 +++++--
>  fs/quota/dquot.c         |   43 ++++++++++++----------
>  fs/quota/netlink.c       |   11 ++++--
>  fs/quota/quota.c         |   44 +++++++++++++++-------
>  fs/quota/quota_tree.c    |   20 +++++++---
>  fs/quota/quota_v1.c      |    8 +++--
>  fs/quota/quota_v2.c      |   14 +++++--
>  fs/xfs/xfs_quotaops.c    |   18 ++++++----
>  fs/xfs/xfs_trans_dquot.c |    8 +++--
>  include/linux/quota.h    |   91 +++++++++++++++++++++++++++++++++++++++++++---
>  include/linux/quotaops.h |   18 +++++++--
>  init/Kconfig             |    2 -
>  15 files changed, 270 insertions(+), 103 deletions(-)
> 
> diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
> index a3bde91..858f052 100644
> --- a/fs/gfs2/quota.c
> +++ b/fs/gfs2/quota.c
> @@ -1057,6 +1057,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
>                  return 0;
>  
>  	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
> +		enum quota_type qtype;
> +		qown_t qown;
>  		qd = ip->i_res->rs_qa_qd[x];
>  
>  		if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
> @@ -1068,10 +1070,11 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
>  		value += qd->qd_change;
>  		spin_unlock(&qd_lru_lock);
>  
> +		qtype = test_bit(QDF_USER, &qd->qd_flags) ? USRQUOTA : GRPQUOTA;
> +		qown = make_qown(&init_user_ns, qtype, qd->qd_id);
>  		if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
>  			print_message(qd, "exceeded");
> -			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
> -					   USRQUOTA : GRPQUOTA, qd->qd_id,
> +			quota_send_warning(qtype, qown,
>  					   sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);
>  
>  			error = -EDQUOT;
> @@ -1081,8 +1084,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
>  			   time_after_eq(jiffies, qd->qd_last_warn +
>  					 gfs2_tune_get(sdp,
>  						gt_quota_warn_period) * HZ)) {
> -			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
> -					   USRQUOTA : GRPQUOTA, qd->qd_id,
> +			quota_send_warning(qtype, qown,
>  					   sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN);
>  			error = print_message(qd, "warning");
>  			qd->qd_last_warn = jiffies;
> @@ -1469,28 +1471,32 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
>  	return 0;
>  }
>  
> -static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
> -			  struct fs_disk_quota *fdq)
> +static int gfs2_get_dqblk(struct super_block *sb, enum quota_type type,
> +			  qown_t id, struct fs_disk_quota *fdq)
>  {
>  	struct gfs2_sbd *sdp = sb->s_fs_info;
>  	struct gfs2_quota_lvb *qlvb;
>  	struct gfs2_quota_data *qd;
>  	struct gfs2_holder q_gh;
>  	int error;
> +	int user;
> +	u32 gfs_id;
>  
>  	memset(fdq, 0, sizeof(struct fs_disk_quota));
>  
>  	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
>  		return -ESRCH; /* Crazy XFS error code */
>  
> +	gfs_id = from_qown(&init_user_ns, type, id);
> +
>  	if (type == USRQUOTA)
> -		type = QUOTA_USER;
> +		user = QUOTA_USER;
>  	else if (type == GRPQUOTA)
> -		type = QUOTA_GROUP;
> +		user = QUOTA_GROUP;
>  	else
>  		return -EINVAL;
>  
> -	error = qd_get(sdp, type, id, &qd);
> +	error = qd_get(sdp, user, gfs_id, &qd);
>  	if (error)
>  		return error;
>  	error = do_glock(qd, FORCE, &q_gh);
> @@ -1499,8 +1505,8 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
>  
>  	qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
>  	fdq->d_version = FS_DQUOT_VERSION;
> -	fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
> -	fdq->d_id = id;
> +	fdq->d_flags = (user == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
> +	fdq->d_id = gfs_id;
>  	fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;
>  	fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;
>  	fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift;
> @@ -1514,8 +1520,8 @@ out:
>  /* GFS2 only supports a subset of the XFS fields */
>  #define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT)
>  
> -static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
> -			  struct fs_disk_quota *fdq)
> +static int gfs2_set_dqblk(struct super_block *sb, enum quota_type type,
> +			  qown_t id, struct fs_disk_quota *fdq)
>  {
>  	struct gfs2_sbd *sdp = sb->s_fs_info;
>  	struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
> @@ -1526,18 +1532,22 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
>  	int alloc_required;
>  	loff_t offset;
>  	int error;
> +	int user;
> +	u32 gfs_id;
>  
>  	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
>  		return -ESRCH; /* Crazy XFS error code */
>  
> +	gfs_id = from_qown(&init_user_ns, type, id);
> +
>  	switch(type) {
>  	case USRQUOTA:
> -		type = QUOTA_USER;
> +		user = QUOTA_USER;
>  		if (fdq->d_flags != FS_USER_QUOTA)
>  			return -EINVAL;
>  		break;
>  	case GRPQUOTA:
> -		type = QUOTA_GROUP;
> +		user = QUOTA_GROUP;
>  		if (fdq->d_flags != FS_GROUP_QUOTA)
>  			return -EINVAL;
>  		break;
> @@ -1547,10 +1557,10 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
>  
>  	if (fdq->d_fieldmask & ~GFS2_FIELDMASK)
>  		return -EINVAL;
> -	if (fdq->d_id != id)
> +	if (fdq->d_id != gfs_id)
>  		return -EINVAL;
>  
> -	error = qd_get(sdp, type, id, &qd);
> +	error = qd_get(sdp, user, gfs_id, &qd);
>  	if (error)
>  		return error;
>  
> diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> index 46a1f6d..063e889 100644
> --- a/fs/ocfs2/file.c
> +++ b/fs/ocfs2/file.c
> @@ -1184,8 +1184,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
>  		if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
>  		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
>  		    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
> -			transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
> -						      USRQUOTA);
> +			transfer_to[USRQUOTA] = dqgetusr(sb, attr->ia_uid);
>  			if (!transfer_to[USRQUOTA]) {
>  				status = -ESRCH;
>  				goto bail_unlock;
> @@ -1194,8 +1193,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
>  		if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid
>  		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
>  		    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
> -			transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
> -						      GRPQUOTA);
> +			transfer_to[GRPQUOTA] = dqgetgrp(sb, attr->ia_gid);
>  			if (!transfer_to[GRPQUOTA]) {
>  				status = -ESRCH;
>  				goto bail_unlock;
> diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
> index 0a86e30..88360f1 100644
> --- a/fs/ocfs2/quota_global.c
> +++ b/fs/ocfs2/quota_global.c
> @@ -95,7 +95,8 @@ static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
>  	struct ocfs2_global_disk_dqblk *d = dp;
>  	struct mem_dqblk *m = &dquot->dq_dqb;
>  
> -	d->dqb_id = cpu_to_le32(dquot->dq_id);
> +	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_type,
> +					  dquot->dq_id));
>  	d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
>  	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
>  	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
> @@ -113,10 +114,13 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
>  	struct ocfs2_global_disk_dqblk *d = dp;
>  	struct ocfs2_mem_dqinfo *oinfo =
>  			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
> +	qown_t qown;
>  
>  	if (qtree_entry_unused(&oinfo->dqi_gi, dp))
>  		return 0;
> -	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
> +
> +	qown = make_qown(&init_user_ns, dquot->dq_type, le32_to_cpu(d->dqb_id));
> +	return qown_eq(qown, dquot->dq_id, dquot->dq_type);
>  }
>  
>  struct qtree_fmt_operations ocfs2_global_ops = {
> @@ -504,7 +508,9 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
>  	olditime = dquot->dq_dqb.dqb_itime;
>  	oldbtime = dquot->dq_dqb.dqb_btime;
>  	ocfs2_global_disk2memdqb(dquot, &dqblk);
> -	trace_ocfs2_sync_dquot(dquot->dq_id, dquot->dq_dqb.dqb_curspace,
> +	trace_ocfs2_sync_dquot(from_qown(&init_user_ns, dquot->dq_type,
> +					 dquot->dq_id),
> +			       dquot->dq_dqb.dqb_curspace,
>  			       (long long)spacechange,
>  			       dquot->dq_dqb.dqb_curinodes,
>  			       (long long)inodechange);
> @@ -556,7 +562,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
>  	if (err < 0) {
>  		mlog(ML_ERROR, "Failed to lock quota info, losing quota write"
>  			       " (type=%d, id=%u)\n", dquot->dq_type,
> -			       (unsigned)dquot->dq_id);
> +			       (unsigned)from_qown(&init_user_ns, dquot->dq_type,
> +						   dquot->dq_id));
>  		goto out;
>  	}
>  	if (freeing)
> @@ -591,7 +598,9 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
>  	struct ocfs2_super *osb = OCFS2_SB(sb);
>  	int status = 0;
>  
> -	trace_ocfs2_sync_dquot_helper(dquot->dq_id, dquot->dq_type,
> +	trace_ocfs2_sync_dquot_helper(from_qown(&init_user_ns, dquot->dq_type,
> +						dquot->dq_id),
> +				      dquot->dq_type,
>  				      type, sb->s_id);
>  	if (type != dquot->dq_type)
>  		goto out;
> @@ -643,7 +652,9 @@ static int ocfs2_write_dquot(struct dquot *dquot)
>  	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
>  	int status = 0;
>  
> -	trace_ocfs2_write_dquot(dquot->dq_id, dquot->dq_type);
> +	trace_ocfs2_write_dquot(from_qown(&init_user_ns, dquot->dq_type,
> +					   dquot->dq_id),
> +				dquot->dq_type);
>  
>  	handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
>  	if (IS_ERR(handle)) {
> @@ -681,7 +692,9 @@ static int ocfs2_release_dquot(struct dquot *dquot)
>  	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
>  	int status = 0;
>  
> -	trace_ocfs2_release_dquot(dquot->dq_id, dquot->dq_type);
> +	trace_ocfs2_release_dquot(from_qown(&init_user_ns, dquot->dq_type,
> +					    dquot->dq_id),
> +				  dquot->dq_type);
>  
>  	mutex_lock(&dquot->dq_lock);
>  	/* Check whether we are not racing with some other dqget() */
> @@ -739,7 +752,8 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
>  	int need_alloc = ocfs2_global_qinit_alloc(sb, type);
>  	handle_t *handle;
>  
> -	trace_ocfs2_acquire_dquot(dquot->dq_id, type);
> +	trace_ocfs2_acquire_dquot(from_qown(&init_user_ns, type, dquot->dq_id),
> +				  type);
>  	mutex_lock(&dquot->dq_lock);
>  	/*
>  	 * We need an exclusive lock, because we're going to update use count
> @@ -826,7 +840,9 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
>  	handle_t *handle;
>  	struct ocfs2_super *osb = OCFS2_SB(sb);
>  
> -	trace_ocfs2_mark_dquot_dirty(dquot->dq_id, type);
> +	trace_ocfs2_mark_dquot_dirty(from_qown(&init_user_ns, type,
> +					       dquot->dq_id),
> +				     type);
>  
>  	/* In case user set some limits, sync dquot immediately to global
>  	 * quota file so that information propagates quicker */
> diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
> index f100bf7..a80936e 100644
> --- a/fs/ocfs2/quota_local.c
> +++ b/fs/ocfs2/quota_local.c
> @@ -501,7 +501,10 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
>  			}
>  			dqblk = (struct ocfs2_local_disk_dqblk *)(qbh->b_data +
>  				ol_dqblk_block_off(sb, chunk, bit));
> -			dquot = dqget(sb, le64_to_cpu(dqblk->dqb_id), type);
> +			dquot = dqget(sb,
> +				      make_qown(&init_user_ns, type,
> +						le64_to_cpu(dqblk->dqb_id)),
> +				      type);
>  			if (!dquot) {
>  				status = -EIO;
>  				mlog(ML_ERROR, "Failed to get quota structure "
> @@ -881,7 +884,9 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
>  	dqblk = (struct ocfs2_local_disk_dqblk *)(bh->b_data
>  		+ ol_dqblk_block_offset(sb, od->dq_local_off));
>  
> -	dqblk->dqb_id = cpu_to_le64(od->dq_dquot.dq_id);
> +	dqblk->dqb_id = cpu_to_le64(from_qown(&init_user_ns,
> +					      od->dq_dquot.dq_type,
> +					      od->dq_dquot.dq_id));
>  	spin_lock(&dq_data_lock);
>  	dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace -
>  					  od->dq_origspace);
> @@ -891,7 +896,8 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
>  	trace_olq_set_dquot(
>  		(unsigned long long)le64_to_cpu(dqblk->dqb_spacemod),
>  		(unsigned long long)le64_to_cpu(dqblk->dqb_inodemod),
> -		od->dq_dquot.dq_id);
> +		from_qown(&init_user_ns, od->dq_dquot.dq_type,
> +			  od->dq_dquot.dq_id));
>  }
>  
>  /* Write dquot to local quota file */
> diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
> index 36a29b7..5fbd1d9a 100644
> --- a/fs/quota/dquot.c
> +++ b/fs/quota/dquot.c
> @@ -253,10 +253,12 @@ static qsize_t inode_get_rsv_space(struct inode *inode);
>  static void __dquot_initialize(struct inode *inode, int type);
>  
>  static inline unsigned int
> -hashfn(const struct super_block *sb, unsigned int id, int type)
> +hashfn(const struct super_block *sb, qown_t qown, enum quota_type type)
>  {
> +	unsigned int id;
>  	unsigned long tmp;
>  
> +	id = from_qown(&init_user_ns, type, qown);
>  	tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type);
>  	return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask;
>  }
> @@ -277,15 +279,15 @@ static inline void remove_dquot_hash(struct dquot *dquot)
>  }
>  
>  static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb,
> -				unsigned int id, int type)
> +				qown_t id, enum quota_type type)
>  {
>  	struct hlist_node *node;
>  	struct dquot *dquot;
>  
>  	hlist_for_each (node, dquot_hash+hashent) {
>  		dquot = hlist_entry(node, struct dquot, dq_hash);
> -		if (dquot->dq_sb == sb && dquot->dq_id == id &&
> -		    dquot->dq_type == type)
> +		if (dquot->dq_sb == sb && dquot->dq_type == type &&
> +		    qown_eq(dquot->dq_id, id, type))
>  			return dquot;
>  	}
>  	return NULL;
> @@ -741,7 +743,9 @@ void dqput(struct dquot *dquot)
>  #ifdef CONFIG_QUOTA_DEBUG
>  	if (!atomic_read(&dquot->dq_count)) {
>  		quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
> -			    quotatypes[dquot->dq_type], dquot->dq_id);
> +			    quotatypes[dquot->dq_type],
> +			    from_qown(&init_user_ns, dquot->dq_type,
> +				      dquot->dq_id));
>  		BUG();
>  	}
>  #endif
> @@ -829,7 +833,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
>   *   a) checking for quota flags under dq_list_lock and
>   *   b) getting a reference to dquot before we release dq_list_lock
>   */
> -struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
> +struct dquot *dqget(struct super_block *sb, qown_t id, enum quota_type type)
>  {
>  	unsigned int hashent = hashfn(sb, id, type);
>  	struct dquot *dquot = NULL, *empty = NULL;
> @@ -1129,7 +1133,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
>  
>  struct dquot_warn {
>  	struct super_block *w_sb;
> -	qid_t w_dq_id;
> +	qown_t w_dq_id;
>  	short w_dq_type;
>  	short w_type;
>  };
> @@ -1156,9 +1160,9 @@ static int need_print_warning(struct dquot_warn *warn)
>  
>  	switch (warn->w_dq_type) {
>  		case USRQUOTA:
> -			return current_fsuid() == warn->w_dq_id;
> +			return uid_eq(current_fsuid(), warn->w_dq_id.uid);
>  		case GRPQUOTA:
> -			return in_group_p(warn->w_dq_id);
> +			return in_group_p(warn->w_dq_id.gid);
>  	}
>  	return 0;
>  }
> @@ -1390,7 +1394,6 @@ static int dquot_active(const struct inode *inode)
>   */
>  static void __dquot_initialize(struct inode *inode, int type)
>  {
> -	unsigned int id = 0;
>  	int cnt;
>  	struct dquot *got[MAXQUOTAS];
>  	struct super_block *sb = inode->i_sb;
> @@ -1403,15 +1406,16 @@ static void __dquot_initialize(struct inode *inode, int type)
>  
>  	/* First get references to structures we might need. */
>  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> +		qown_t id;
>  		got[cnt] = NULL;
>  		if (type != -1 && cnt != type)
>  			continue;
>  		switch (cnt) {
>  		case USRQUOTA:
> -			id = inode->i_uid;
> +			id.uid = inode->i_uid;
>  			break;
>  		case GRPQUOTA:
> -			id = inode->i_gid;
> +			id.gid = inode->i_gid;
>  			break;
>  		}
>  		got[cnt] = dqget(sb, id, cnt);
> @@ -1897,10 +1901,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
>  	if (!dquot_active(inode))
>  		return 0;
>  
> -	if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
> -		transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA);
> -	if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)
> -		transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA);
> +	if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
> +		transfer_to[USRQUOTA] = dqgetusr(sb, iattr->ia_uid);
> +	if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
> +		transfer_to[GRPQUOTA] = dqgetgrp(sb, iattr->ia_gid);
>  
>  	ret = __dquot_transfer(inode, transfer_to);
>  	dqput_all(transfer_to);
> @@ -2362,7 +2366,8 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  	di->d_version = FS_DQUOT_VERSION;
>  	di->d_flags = dquot->dq_type == USRQUOTA ?
>  			FS_USER_QUOTA : FS_GROUP_QUOTA;
> -	di->d_id = dquot->dq_id;
> +	di->d_id = from_qown_munged(current_user_ns(), dquot->dq_type,
> +				    dquot->dq_id);
>  
>  	spin_lock(&dq_data_lock);
>  	di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
> @@ -2376,7 +2381,7 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  	spin_unlock(&dq_data_lock);
>  }
>  
> -int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_get_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		    struct fs_disk_quota *di)
>  {
>  	struct dquot *dquot;
> @@ -2488,7 +2493,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  	return 0;
>  }
>  
> -int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_set_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		  struct fs_disk_quota *di)
>  {
>  	struct dquot *dquot;
> diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
> index d67908b..b2678da 100644
> --- a/fs/quota/netlink.c
> +++ b/fs/quota/netlink.c
> @@ -30,7 +30,7 @@ static struct genl_family quota_genl_family = {
>   *
>   */
>  
> -void quota_send_warning(short type, unsigned int id, dev_t dev,
> +void quota_send_warning(enum quota_type type, qown_t id, dev_t dev,
>  			const char warntype)
>  {
>  	static atomic_t seq;
> @@ -59,7 +59,8 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
>  	ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type);
>  	if (ret)
>  		goto attr_err_out;
> -	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id);
> +	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID,
> +			  from_qown_munged(&init_user_ns, type, id));
>  	if (ret)
>  		goto attr_err_out;
>  	ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
> @@ -71,7 +72,11 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
>  	ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev));
>  	if (ret)
>  		goto attr_err_out;
> -	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
> +	/* Report the current user as seen by the filesystem that issues
> +	 * quota warning.
> +	 */
> +	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID,
> +			  from_kuid_munged(&init_user_ns, current_uid()));
>  	if (ret)
>  		goto attr_err_out;
>  	genlmsg_end(skb, msg_head);
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index 6f15578..b9f44b7 100644
> --- a/fs/quota/quota.c
> +++ b/fs/quota/quota.c
> @@ -32,8 +32,8 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
>  	/* allow to query information for dquots we "own" */
>  	case Q_GETQUOTA:
>  	case Q_XGETQUOTA:
> -		if ((type == USRQUOTA && current_euid() == id) ||
> -		    (type == GRPQUOTA && in_egroup_p(id)))
> +		if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
> +		    (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
>  			break;
>  		/*FALLTHROUGH*/
>  	default:
> @@ -62,7 +62,7 @@ static int quota_sync_all(int type)
>  	return ret;
>  }
>  
> -static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
> +static int quota_quotaon(struct super_block *sb, enum quota_type type, int cmd, qid_t id,
>  		         struct path *path)
>  {
>  	if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta)
> @@ -127,16 +127,20 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
>  	dst->dqb_valid = QIF_ALL;
>  }
>  
> -static int quota_getquota(struct super_block *sb, int type, qid_t id,
> -			  void __user *addr)
> +static int quota_getquota(struct super_block *sb, enum quota_type type,
> +			  qid_t id, void __user *addr)
>  {
> +	qown_t qown;
>  	struct fs_disk_quota fdq;
>  	struct if_dqblk idq;
>  	int ret;
>  
>  	if (!sb->s_qcop->get_dqblk)
>  		return -ENOSYS;
> -	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (qown_valid(type, qown))
> +		return -EINVAL;
> +	ret = sb->s_qcop->get_dqblk(sb, type, qown, &fdq);
>  	if (ret)
>  		return ret;
>  	copy_to_if_dqblk(&idq, &fdq);
> @@ -171,18 +175,22 @@ static void copy_from_if_dqblk(struct fs_disk_quota *dst, struct if_dqblk *src)
>  		dst->d_fieldmask |= FS_DQ_ITIMER;
>  }
>  
> -static int quota_setquota(struct super_block *sb, int type, qid_t id,
> -			  void __user *addr)
> +static int quota_setquota(struct super_block *sb, enum quota_type type,
> +			  qid_t id,  void __user *addr)
>  {
>  	struct fs_disk_quota fdq;
>  	struct if_dqblk idq;
> +	qown_t qown;
>  
>  	if (copy_from_user(&idq, addr, sizeof(idq)))
>  		return -EFAULT;
>  	if (!sb->s_qcop->set_dqblk)
>  		return -ENOSYS;
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (!qown_valid(type, qown))
> +		return -EINVAL;
>  	copy_from_if_dqblk(&fdq, &idq);
> -	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
> +	return sb->s_qcop->set_dqblk(sb, type, qown, &fdq);
>  }
>  
>  static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
> @@ -209,27 +217,35 @@ static int quota_getxstate(struct super_block *sb, void __user *addr)
>  	return ret;
>  }
>  
> -static int quota_setxquota(struct super_block *sb, int type, qid_t id,
> +static int quota_setxquota(struct super_block *sb, enum quota_type type, qid_t id,
>  			   void __user *addr)
>  {
>  	struct fs_disk_quota fdq;
> +	qown_t qown;
>  
>  	if (copy_from_user(&fdq, addr, sizeof(fdq)))
>  		return -EFAULT;
>  	if (!sb->s_qcop->set_dqblk)
>  		return -ENOSYS;
> -	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (!qown_valid(type, qown))
> +		return -EINVAL;
> +	return sb->s_qcop->set_dqblk(sb, type, qown, &fdq);
>  }
>  
> -static int quota_getxquota(struct super_block *sb, int type, qid_t id,
> -			   void __user *addr)
> +static int quota_getxquota(struct super_block *sb, enum quota_type type,
> +			   qid_t id, void __user *addr)
>  {
>  	struct fs_disk_quota fdq;
> +	qown_t qown;
>  	int ret;
>  
>  	if (!sb->s_qcop->get_dqblk)
>  		return -ENOSYS;
> -	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (!qown_valid(type, qown))
> +		return -EINVAL;
> +	ret = sb->s_qcop->get_dqblk(sb, type, qown, &fdq);
>  	if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
>  		return -EFAULT;
>  	return ret;
> diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
> index e41c1becf..4704619 100644
> --- a/fs/quota/quota_tree.c
> +++ b/fs/quota/quota_tree.c
> @@ -22,10 +22,12 @@ MODULE_LICENSE("GPL");
>  
>  #define __QUOTA_QT_PARANOIA
>  
> -static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
> +static int get_index(struct qtree_mem_dqinfo *info, qown_t qown, int depth)
>  {
>  	unsigned int epb = info->dqi_usable_bs >> 2;
> +	qid_t id;
>  
> +	id = from_qown(&init_user_ns, info->dqi_type, qown);
>  	depth = info->dqi_qtree_depth - depth - 1;
>  	while (depth--)
>  		id /= epb;
> @@ -538,8 +540,10 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
>  		ddquot += info->dqi_entry_size;
>  	}
>  	if (i == qtree_dqstr_in_blk(info)) {
> -		quota_error(dquot->dq_sb, "Quota for id %u referenced "
> -			    "but not present", dquot->dq_id);
> +		quota_error(dquot->dq_sb,
> +			    "Quota for id %u referenced but not present",
> +			    from_qown(&init_user_ns, dquot->dq_type,
> +				      dquot->dq_id));
>  		ret = -EIO;
>  		goto out_buf;
>  	} else {
> @@ -607,8 +611,11 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
>  		offset = find_dqentry(info, dquot);
>  		if (offset <= 0) {	/* Entry not present? */
>  			if (offset < 0)
> -				quota_error(sb, "Can't read quota structure "
> -					    "for id %u", dquot->dq_id);
> +				quota_error(sb,"Can't read quota structure "
> +					    "for id %u",
> +					    from_qown(&init_user_ns,
> +						      dquot->dq_type,
> +						      dquot->dq_id));
>  			dquot->dq_off = 0;
>  			set_bit(DQ_FAKE_B, &dquot->dq_flags);
>  			memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
> @@ -626,7 +633,8 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
>  		if (ret >= 0)
>  			ret = -EIO;
>  		quota_error(sb, "Error while reading quota structure for id %u",
> -			    dquot->dq_id);
> +			    from_qown(&init_user_ns, dquot->dq_type,
> +				      dquot->dq_id));
>  		set_bit(DQ_FAKE_B, &dquot->dq_flags);
>  		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
>  		kfree(ddquot);
> diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c
> index 34b37a6..7c028f9 100644
> --- a/fs/quota/quota_v1.c
> +++ b/fs/quota/quota_v1.c
> @@ -63,7 +63,8 @@ static int v1_read_dqblk(struct dquot *dquot)
>  	/* Set structure to 0s in case read fails/is after end of file */
>  	memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
>  	dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk,
> -			sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
> +			sizeof(struct v1_disk_dqblk),
> +			v1_dqoff(from_qown(&init_user_ns, type, dquot->dq_id)));
>  
>  	v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
>  	if (dquot->dq_dqb.dqb_bhardlimit == 0 &&
> @@ -83,7 +84,8 @@ static int v1_commit_dqblk(struct dquot *dquot)
>  	struct v1_disk_dqblk dqblk;
>  
>  	v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
> -	if (dquot->dq_id == 0) {
> +	if (((type == USRQUOTA) && uid_eq(dquot->dq_id.uid, GLOBAL_ROOT_UID)) ||
> +	    ((type == GRPQUOTA) && gid_eq(dquot->dq_id.gid, GLOBAL_ROOT_GID))) {
>  		dqblk.dqb_btime =
>  			sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
>  		dqblk.dqb_itime =
> @@ -93,7 +95,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
>  	if (sb_dqopt(dquot->dq_sb)->files[type])
>  		ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
>  			(char *)&dqblk, sizeof(struct v1_disk_dqblk),
> -			v1_dqoff(dquot->dq_id));
> +			v1_dqoff(from_qown(&init_user_ns, type, dquot->dq_id)));
>  	if (ret != sizeof(struct v1_disk_dqblk)) {
>  		quota_error(dquot->dq_sb, "dquota write failed");
>  		if (ret >= 0)
> diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
> index f1ab360..b9068b7 100644
> --- a/fs/quota/quota_v2.c
> +++ b/fs/quota/quota_v2.c
> @@ -206,7 +206,8 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
>  	d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
>  	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
>  	d->dqb_btime = cpu_to_le64(m->dqb_btime);
> -	d->dqb_id = cpu_to_le32(dquot->dq_id);
> +	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns,
> +					  dquot->dq_type, dquot->dq_id));
>  	if (qtree_entry_unused(info, dp))
>  		d->dqb_itime = cpu_to_le64(1);
>  }
> @@ -216,10 +217,12 @@ static int v2r0_is_id(void *dp, struct dquot *dquot)
>  	struct v2r0_disk_dqblk *d = dp;
>  	struct qtree_mem_dqinfo *info =
>  			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
> +	qown_t qown;
>  
>  	if (qtree_entry_unused(info, dp))
>  		return 0;
> -	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
> +	qown = make_qown(&init_user_ns, dquot->dq_type, le32_to_cpu(d->dqb_id));
> +	return qown_eq(qown, dquot->dq_id, dquot->dq_type);
>  }
>  
>  static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
> @@ -257,7 +260,8 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
>  	d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
>  	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
>  	d->dqb_btime = cpu_to_le64(m->dqb_btime);
> -	d->dqb_id = cpu_to_le32(dquot->dq_id);
> +	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns,
> +					  dquot->dq_type, dquot->dq_id));
>  	if (qtree_entry_unused(info, dp))
>  		d->dqb_itime = cpu_to_le64(1);
>  }
> @@ -267,10 +271,12 @@ static int v2r1_is_id(void *dp, struct dquot *dquot)
>  	struct v2r1_disk_dqblk *d = dp;
>  	struct qtree_mem_dqinfo *info =
>  			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
> +	qown_t qown;
>  
>  	if (qtree_entry_unused(info, dp))
>  		return 0;
> -	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
> +	qown = make_qown(&init_user_ns, dquot->dq_type, le32_to_cpu(d->dqb_id));
> +	return qown_eq(qown, dquot->dq_id, dquot->dq_type);
>  }
>  
>  static int v2_read_dquot(struct dquot *dquot)
> diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
> index fed504f..9ee2d6d 100644
> --- a/fs/xfs/xfs_quotaops.c
> +++ b/fs/xfs/xfs_quotaops.c
> @@ -29,7 +29,7 @@
>  
> 
>  STATIC int
> -xfs_quota_type(int type)
> +xfs_quota_type(enum quota_type type)
>  {
>  	switch (type) {
>  	case USRQUOTA:
> @@ -97,28 +97,31 @@ xfs_fs_set_xstate(
>  STATIC int
>  xfs_fs_get_dqblk(
>  	struct super_block	*sb,
> -	int			type,
> -	qid_t			id,
> +	enum quota_type		type,
> +	qown_t			id,
>  	struct fs_disk_quota	*fdq)
>  {
>  	struct xfs_mount	*mp = XFS_M(sb);
> +	xfs_dqid_t		xfs_id;
>  
>  	if (!XFS_IS_QUOTA_RUNNING(mp))
>  		return -ENOSYS;
>  	if (!XFS_IS_QUOTA_ON(mp))
>  		return -ESRCH;
>  
> -	return -xfs_qm_scall_getquota(mp, id, xfs_quota_type(type), fdq);
> +	xfs_id = from_qown(&init_user_ns, type, id);
> +	return -xfs_qm_scall_getquota(mp, xfs_id, xfs_quota_type(type), fdq);
>  }
>  
>  STATIC int
>  xfs_fs_set_dqblk(
>  	struct super_block	*sb,
> -	int			type,
> -	qid_t			id,
> +	enum quota_type		type,
> +	qown_t			id,
>  	struct fs_disk_quota	*fdq)
>  {
>  	struct xfs_mount	*mp = XFS_M(sb);
> +	xfs_dqid_t		xfs_id;
>  
>  	if (sb->s_flags & MS_RDONLY)
>  		return -EROFS;
> @@ -127,7 +130,8 @@ xfs_fs_set_dqblk(
>  	if (!XFS_IS_QUOTA_ON(mp))
>  		return -ESRCH;
>  
> -	return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq);
> +	xfs_id = from_qown(&init_user_ns, type, id);
> +	return -xfs_qm_scall_setqlim(mp, xfs_id, xfs_quota_type(type), fdq);
>  }
>  
>  const struct quotactl_ops xfs_quotactl_operations = {
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index bcb6054..0c7ab32 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -575,12 +575,14 @@ xfs_quota_warn(
>  	struct xfs_dquot	*dqp,
>  	int			type)
>  {
> +	enum quota_type qtype;
> +	qown_t qown;
>  	/* no warnings for project quotas - we just return ENOSPC later */
>  	if (dqp->dq_flags & XFS_DQ_PROJ)
>  		return;
> -	quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA,
> -			   be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev,
> -			   type);
> +	qtype = (dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA;
> +	qown = make_qown(&init_user_ns, qtype, be32_to_cpu(dqp->q_core.d_id));
> +	quota_send_warning(qtype, qown, mp->m_super->s_dev, type);
>  }
>  
>  /*
> diff --git a/include/linux/quota.h b/include/linux/quota.h
> index 524ede8..67921d5 100644
> --- a/include/linux/quota.h
> +++ b/include/linux/quota.h
> @@ -181,10 +181,91 @@ enum {
>  #include <linux/dqblk_v2.h>
>  
>  #include <linux/atomic.h>
> +#include <linux/uidgid.h>
>  
>  typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
>  typedef long long qsize_t;	/* Type in which we store sizes */
>  
> +#undef USRQUOTA
> +#undef GRPQUOTA
> +enum quota_type {
> +	USRQUOTA = 0,
> +	GRPQUOTA = 1,
> +};
> +
> +typedef union quota_id {
> +	kuid_t uid;
> +	kgid_t gid;
> +} qown_t;			/* Type in which we store the quota owner */
> +
> +static inline bool qown_eq(qown_t left, qown_t right, enum quota_type type)
> +{
> +	switch(type) {
> +	case USRQUOTA:
> +		return uid_eq(left.uid, right.uid);
> +	case GRPQUOTA:
> +		return gid_eq(left.gid, right.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +static inline u32 from_qown(struct user_namespace *user_ns,
> +			    enum quota_type type, qown_t qown)
> +{
> +	switch (type) {
> +	case USRQUOTA:
> +		return from_kuid(user_ns, qown.uid);
> +	case GRPQUOTA:
> +		return from_kgid(user_ns, qown.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +static inline u32 from_qown_munged(struct user_namespace *user_ns,
> +				   enum quota_type type, qown_t qown)
> +{
> +	switch (type) {
> +	case USRQUOTA:
> +		return from_kuid_munged(user_ns, qown.uid);
> +	case GRPQUOTA:
> +		return from_kgid_munged(user_ns, qown.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +static inline qown_t make_qown(struct user_namespace *user_ns,
> +			      enum quota_type type, qid_t id)
> +{
> +	qown_t qown;
> +
> +	switch (type) {
> +	case USRQUOTA:
> +		qown.uid = make_kuid(user_ns, id);
> +		break;
> +	case GRPQUOTA:
> +		qown.gid = make_kgid(user_ns, id);
> +		break;
> +	default:
> +		BUG();
> +	}
> +	return qown;
> +}
> +
> +static inline bool qown_valid(enum quota_type type, qown_t qown)
> +{
> +	switch (type) {
> +	case USRQUOTA:
> +		return uid_valid(qown.uid);
> +	case GRPQUOTA:
> +		return gid_valid(qown.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
>  extern spinlock_t dq_data_lock;
>  
>  /* Maximal numbers of writes for quota operation (insert/delete/update)
> @@ -294,7 +375,7 @@ struct dquot {
>  	atomic_t dq_count;		/* Use count */
>  	wait_queue_head_t dq_wait_unused;	/* Wait queue for dquot to become unused */
>  	struct super_block *dq_sb;	/* superblock this applies to */
> -	unsigned int dq_id;		/* ID this applies to (uid, gid) */
> +	qown_t dq_id;			/* ID this applies to (uid, gid) */
>  	loff_t dq_off;			/* Offset of dquot on disk */
>  	unsigned long dq_flags;		/* See DQ_* */
>  	short dq_type;			/* Type of quota */
> @@ -336,8 +417,8 @@ struct quotactl_ops {
>  	int (*quota_sync)(struct super_block *, int);
>  	int (*get_info)(struct super_block *, int, struct if_dqinfo *);
>  	int (*set_info)(struct super_block *, int, struct if_dqinfo *);
> -	int (*get_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
> -	int (*set_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
> +	int (*get_dqblk)(struct super_block *, enum quota_type, qown_t, struct fs_disk_quota *);
> +	int (*set_dqblk)(struct super_block *, enum quota_type, qown_t, struct fs_disk_quota *);
>  	int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
>  	int (*set_xstate)(struct super_block *, unsigned int, int);
>  };
> @@ -386,10 +467,10 @@ static inline unsigned int dquot_generic_flag(unsigned int flags, int type)
>  }
>  
>  #ifdef CONFIG_QUOTA_NETLINK_INTERFACE
> -extern void quota_send_warning(short type, unsigned int id, dev_t dev,
> +extern void quota_send_warning(enum quota_type type, qown_t id, dev_t dev,
>  			       const char warntype);
>  #else
> -static inline void quota_send_warning(short type, unsigned int id, dev_t dev,
> +static inline void quota_send_warning(enum quota_type type, qown_t id, dev_t dev,
>  				      const char warntype)
>  {
>  	return;
> diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
> index ec6b65f..d988b11 100644
> --- a/include/linux/quotaops.h
> +++ b/include/linux/quotaops.h
> @@ -44,13 +44,23 @@ void inode_sub_rsv_space(struct inode *inode, qsize_t number);
>  
>  void dquot_initialize(struct inode *inode);
>  void dquot_drop(struct inode *inode);
> -struct dquot *dqget(struct super_block *sb, unsigned int id, int type);
> +struct dquot *dqget(struct super_block *sb, qown_t id, enum quota_type type);
>  void dqput(struct dquot *dquot);
>  int dquot_scan_active(struct super_block *sb,
>  		      int (*fn)(struct dquot *dquot, unsigned long priv),
>  		      unsigned long priv);
>  struct dquot *dquot_alloc(struct super_block *sb, int type);
>  void dquot_destroy(struct dquot *dquot);
> +static inline struct dquot *dqgetusr(struct super_block *sb, kuid_t uid)
> +{
> +	qown_t id = { .uid = uid };
> +	return dqget(sb, id, USRQUOTA);
> +}
> +static inline struct dquot *dqgetgrp(struct super_block *sb, kgid_t gid)
> +{
> +	qown_t id = { .gid = gid };
> +	return dqget(sb, id, GRPQUOTA);
> +}
>  
>  int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags);
>  void __dquot_free_space(struct inode *inode, qsize_t number, int flags);
> @@ -87,15 +97,15 @@ int dquot_writeback_dquots(struct super_block *sb, int type);
>  int dquot_quota_sync(struct super_block *sb, int type);
>  int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
>  int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
> -int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_get_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		struct fs_disk_quota *di);
> -int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_set_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		struct fs_disk_quota *di);
>  
>  int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
>  int dquot_transfer(struct inode *inode, struct iattr *iattr);
>  
> -static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type)
> +static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, enum quota_type type)
>  {
>  	return sb_dqopt(sb)->info + type;
>  }
> diff --git a/init/Kconfig b/init/Kconfig
> index 2a388e5..a0bccce 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -928,8 +928,6 @@ config UIDGID_CONVERTED
>  	depends on IMA = n
>  	depends on EVM = n
>  	depends on FS_POSIX_ACL = n
> -	depends on QUOTA = n
> -	depends on QUOTACTL = n
>  
>  	# Networking
>  	depends on NET_9P = n



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [REVIEW][PATCH 13/15] userns: Add basic quota support
  2012-08-27  8:50   ` [REVIEW][PATCH 13/15] userns: Add basic quota support Jan Kara
@ 2012-08-27 15:54     ` Eric W. Biederman
  2012-08-28  0:12     ` [PATCH] userns: Add basic quota support v2 Eric W. Biederman
  1 sibling, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-27 15:54 UTC (permalink / raw)
  To: Jan Kara
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, cluster-devel, Mark Fasheh,
	Joel Becker, ocfs2-devel, Ben Myers, Alex Elder, xfs,
	Dmitry Monakhov

Jan Kara <jack@suse.cz> writes:

>   Hello,
>
> On Sat 25-08-12 17:05:35, Eric W. Biederman wrote:
>> Two helper are added dqgetusr and dqgetgrp to allow the quota
>> infrastructure to be called with a kuid and a kgid respectively.  This
>> creates type safe variants of dqget and leads to shorter more
>> comprehensible code.
>   It would look more comprehensible to me to have functions like:
> kuid2qown() and kgid2qown() and then call dqget(sb, kuid2qown(attr->uid))
> (see below for qown_t change proposal). The code then at the first look
> explains what is going on... Hmm?
>
>> Place the USRQUOTA and GRPQUOTA defines into enum quota_type.  This
>> brings with it the ability for the compiler to check that switch
>> statements handle every quota type, and the ability to mark which
>> values store the type of a quota entry.
>   OK, makes sense.
>
>> Add the data type qown_t a union of kuid_t and kgid_t. qown_t is a
>> replacement for the implicit union of uid and gid stored in an
>> unsigned int that is was used in the quota data structures.  Making
>> the data type explicit allows the kuid_t and kgid_t type safety to
>> propogate more thoroughly through the code, revealing more places
>> where uid/gid conversions need be made.
>   Hum, when we already do this, wouldn't it make more sense to embed quota
> type in qown_t? Because with the union thing you have no meaningful way of
> accessing that type without having quota type anyway. So having that in a
> single structure makes a lot of sense, plus it makes prototypes shorter...
> And you have to call make_qown() anyway...

So I think there was a reason for having the type separate but I'm not
seeing that reason off the top of my head.

I think it was filesystems like gfs2 doing weird things.  But I tell
you want I will play with this and if I can't reproduce find a reason
for putting them in one structure I will because there are definitely
good reasons for doing that.


>> Allong with the data type qown_t comes the helper functions
>> qown_eq, from_qown, from_qown_munged, qown_valid, and make_qown.
>> 
>> Update struct dquot dq_id to be a qown_t.
>> 
>> Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
>> and dquot_set_dqblk to use enum quota_type and qown_t.
>> 
>> Make minimal changes to gfs2, ocfs2, and xfs to deal with the change
>> in quota structures and signatures.  The ocfs2 changes are larger than
>> most because of the extensive tracing throughout the ocfs2 quota code
>> that prints out dq_id.
>   Otherwise the changes look OK to me, although I didn't check them in
> detail yet (as above suggestions will change the code anyway).
>
> 								Honza

Thanks, 

Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH] userns: Add basic quota support v2
  2012-08-27  8:50   ` [REVIEW][PATCH 13/15] userns: Add basic quota support Jan Kara
  2012-08-27 15:54     ` Eric W. Biederman
@ 2012-08-28  0:12     ` Eric W. Biederman
  2012-08-28  9:05       ` Jan Kara
  1 sibling, 1 reply; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-28  0:12 UTC (permalink / raw)
  To: Jan Kara
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
	Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das


Add the data type struct qown which holds the owning identifier of a
quota.  struct qown is a replacement for the implicit union of uid,
gid and project stored in an unsigned int and the quota type field
that is was used in the quota data structures.  Making the data type
explicit allows the kuid_t and kgid_t type safety to propogate more
thoroughly through the code, revealing more places where uid/gid
conversions need be made.

Allong with the data type struct qown comes the helper functions
qown_eq, qown_lt, from_qown, from_qown_munged, qown_valid, make_qown,
make_qown_invalid, make_qown_uid, make_qown_gid.

Replace struct dquot dq_id and dq_type with dq_own a struct qown.

Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
and dquot_set_dqblk to use struct qown.

Make minimal changes to ext3, ext4, gfs2, ocfs2, and xfs to deal with
the change in quota structures and signatures.  The ocfs2 changes are
larger than most because of the extensive tracing throughout the ocfs2
quota code that prints out dq_id.

v2:
 - Renamed qown_t struct qown
 - Added the quota type to struct qown.
 - Removed enum quota_type (In this patch it was just noise)
 - Added qown_lt, make_qown_invalid, make_qown_uid, make_qown_gid
 - Taught qown to handle xfs project ids (but only in init_user_ns). 
   Q_XGETQUOTA calls .get_quotblk with project ids.

Cc: Steven Whitehouse <swhiteho@redhat.com>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Ben Myers <bpm@sgi.com>
Cc: Alex Elder <elder@kernel.org>
Cc: Jan Kara <jack@suse.cz>
Cc: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---

 fs/ext3/super.c          |    2 +-
 fs/ext4/super.c          |    2 +-
 fs/gfs2/quota.c          |   52 +++++++++------
 fs/ocfs2/file.c          |    6 +-
 fs/ocfs2/quota_global.c  |   43 +++++++-----
 fs/ocfs2/quota_local.c   |   15 +++--
 fs/quota/dquot.c         |  118 +++++++++++++++++-----------------
 fs/quota/netlink.c       |   10 ++-
 fs/quota/quota.c         |   28 ++++++--
 fs/quota/quota_tree.c    |   35 ++++++----
 fs/quota/quota_v1.c      |   12 ++--
 fs/quota/quota_v2.c      |   26 ++++---
 fs/xfs/xfs_quotaops.c    |   14 ++--
 fs/xfs/xfs_trans_dquot.c |    8 ++-
 include/linux/quota.h    |  162 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/quotaops.h |    6 +-
 init/Kconfig             |    2 -
 17 files changed, 371 insertions(+), 170 deletions(-)

diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index ff9bcdc..c5879f1 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -2814,7 +2814,7 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
 
 static inline struct inode *dquot_to_inode(struct dquot *dquot)
 {
-	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_own.type];
 }
 
 static int ext3_write_dquot(struct dquot *dquot)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index d76ec82..f60b48f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -4796,7 +4796,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
 
 static inline struct inode *dquot_to_inode(struct dquot *dquot)
 {
-	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_own.type];
 }
 
 static int ext4_write_dquot(struct dquot *dquot)
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index a3bde91..f0310f9 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -1057,6 +1057,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
                 return 0;
 
 	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
+		int qtype;
+		struct qown qown;
 		qd = ip->i_res->rs_qa_qd[x];
 
 		if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
@@ -1068,11 +1070,12 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
 		value += qd->qd_change;
 		spin_unlock(&qd_lru_lock);
 
+		qtype = test_bit(QDF_USER, &qd->qd_flags) ? USRQUOTA : GRPQUOTA;
+		qown = make_qown(&init_user_ns, qtype, qd->qd_id);
 		if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
 			print_message(qd, "exceeded");
-			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
-					   USRQUOTA : GRPQUOTA, qd->qd_id,
-					   sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);
+			quota_send_warning(qown, sdp->sd_vfs->s_dev,
+					   QUOTA_NL_BHARDWARN);
 
 			error = -EDQUOT;
 			break;
@@ -1081,9 +1084,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
 			   time_after_eq(jiffies, qd->qd_last_warn +
 					 gfs2_tune_get(sdp,
 						gt_quota_warn_period) * HZ)) {
-			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
-					   USRQUOTA : GRPQUOTA, qd->qd_id,
-					   sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN);
+			quota_send_warning(qown, sdp->sd_vfs->s_dev,
+					   QUOTA_NL_BSOFTWARN);
 			error = print_message(qd, "warning");
 			qd->qd_last_warn = jiffies;
 		}
@@ -1469,7 +1471,7 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
 	return 0;
 }
 
-static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
+static int gfs2_get_dqblk(struct super_block *sb, struct qown qown,
 			  struct fs_disk_quota *fdq)
 {
 	struct gfs2_sbd *sdp = sb->s_fs_info;
@@ -1477,20 +1479,24 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
 	struct gfs2_quota_data *qd;
 	struct gfs2_holder q_gh;
 	int error;
+	int user;
+	u32 gfs_id;
 
 	memset(fdq, 0, sizeof(struct fs_disk_quota));
 
 	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
 		return -ESRCH; /* Crazy XFS error code */
 
-	if (type == USRQUOTA)
-		type = QUOTA_USER;
-	else if (type == GRPQUOTA)
-		type = QUOTA_GROUP;
+	gfs_id = from_qown(&init_user_ns, qown);
+
+	if (qown.type == USRQUOTA)
+		user = QUOTA_USER;
+	else if (qown.type == GRPQUOTA)
+		user = QUOTA_GROUP;
 	else
 		return -EINVAL;
 
-	error = qd_get(sdp, type, id, &qd);
+	error = qd_get(sdp, user, gfs_id, &qd);
 	if (error)
 		return error;
 	error = do_glock(qd, FORCE, &q_gh);
@@ -1499,8 +1505,8 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
 
 	qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
 	fdq->d_version = FS_DQUOT_VERSION;
-	fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
-	fdq->d_id = id;
+	fdq->d_flags = (user == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
+	fdq->d_id = gfs_id;
 	fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;
 	fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;
 	fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift;
@@ -1514,8 +1520,8 @@ out:
 /* GFS2 only supports a subset of the XFS fields */
 #define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT)
 
-static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
-			  struct fs_disk_quota *fdq)
+static int gfs2_set_dqblk(struct super_block *sb,
+			  struct qown qown, struct fs_disk_quota *fdq)
 {
 	struct gfs2_sbd *sdp = sb->s_fs_info;
 	struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
@@ -1526,18 +1532,22 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
 	int alloc_required;
 	loff_t offset;
 	int error;
+	int user;
+	u32 gfs_id;
 
 	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
 		return -ESRCH; /* Crazy XFS error code */
 
-	switch(type) {
+	gfs_id = from_qown(&init_user_ns, qown);
+
+	switch(qown.type) {
 	case USRQUOTA:
-		type = QUOTA_USER;
+		user = QUOTA_USER;
 		if (fdq->d_flags != FS_USER_QUOTA)
 			return -EINVAL;
 		break;
 	case GRPQUOTA:
-		type = QUOTA_GROUP;
+		user = QUOTA_GROUP;
 		if (fdq->d_flags != FS_GROUP_QUOTA)
 			return -EINVAL;
 		break;
@@ -1547,10 +1557,10 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
 
 	if (fdq->d_fieldmask & ~GFS2_FIELDMASK)
 		return -EINVAL;
-	if (fdq->d_id != id)
+	if (fdq->d_id != gfs_id)
 		return -EINVAL;
 
-	error = qd_get(sdp, type, id, &qd);
+	error = qd_get(sdp, user, gfs_id, &qd);
 	if (error)
 		return error;
 
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 46a1f6d..3879186 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1184,8 +1184,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 		if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
 		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
 		    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
-			transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
-						      USRQUOTA);
+			transfer_to[USRQUOTA] = dqget(sb, make_qown_uid(attr->ia_uid));
 			if (!transfer_to[USRQUOTA]) {
 				status = -ESRCH;
 				goto bail_unlock;
@@ -1194,8 +1193,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 		if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid
 		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
 		    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
-			transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
-						      GRPQUOTA);
+			transfer_to[GRPQUOTA] = dqget(sb, make_qown_gid(attr->ia_gid));
 			if (!transfer_to[GRPQUOTA]) {
 				status = -ESRCH;
 				goto bail_unlock;
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
index 0a86e30..dcee469 100644
--- a/fs/ocfs2/quota_global.c
+++ b/fs/ocfs2/quota_global.c
@@ -95,7 +95,7 @@ static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
 	struct ocfs2_global_disk_dqblk *d = dp;
 	struct mem_dqblk *m = &dquot->dq_dqb;
 
-	d->dqb_id = cpu_to_le32(dquot->dq_id);
+	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_own));
 	d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
 	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
 	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
@@ -112,11 +112,14 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
 {
 	struct ocfs2_global_disk_dqblk *d = dp;
 	struct ocfs2_mem_dqinfo *oinfo =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
+	struct qown qown;
 
 	if (qtree_entry_unused(&oinfo->dqi_gi, dp))
 		return 0;
-	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+
+	qown = make_qown(&init_user_ns, dquot->dq_own.type, le32_to_cpu(d->dqb_id));
+	return qown_eq(qown, dquot->dq_own);
 }
 
 struct qtree_fmt_operations ocfs2_global_ops = {
@@ -475,7 +478,7 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
 {
 	int err, err2;
 	struct super_block *sb = dquot->dq_sb;
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
 	struct ocfs2_global_disk_dqblk dqblk;
 	s64 spacechange, inodechange;
@@ -504,7 +507,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
 	olditime = dquot->dq_dqb.dqb_itime;
 	oldbtime = dquot->dq_dqb.dqb_btime;
 	ocfs2_global_disk2memdqb(dquot, &dqblk);
-	trace_ocfs2_sync_dquot(dquot->dq_id, dquot->dq_dqb.dqb_curspace,
+	trace_ocfs2_sync_dquot(from_qown(&init_user_ns, dquot->dq_own),
+			       dquot->dq_dqb.dqb_curspace,
 			       (long long)spacechange,
 			       dquot->dq_dqb.dqb_curinodes,
 			       (long long)inodechange);
@@ -555,8 +559,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
 	err = ocfs2_qinfo_lock(info, freeing);
 	if (err < 0) {
 		mlog(ML_ERROR, "Failed to lock quota info, losing quota write"
-			       " (type=%d, id=%u)\n", dquot->dq_type,
-			       (unsigned)dquot->dq_id);
+			       " (type=%d, id=%u)\n", dquot->dq_own.type,
+			       (unsigned)from_qown(&init_user_ns, dquot->dq_own));
 		goto out;
 	}
 	if (freeing)
@@ -591,9 +595,10 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
 	struct ocfs2_super *osb = OCFS2_SB(sb);
 	int status = 0;
 
-	trace_ocfs2_sync_dquot_helper(dquot->dq_id, dquot->dq_type,
+	trace_ocfs2_sync_dquot_helper(from_qown(&init_user_ns, dquot->dq_own),
+				      dquot->dq_own.type,
 				      type, sb->s_id);
-	if (type != dquot->dq_type)
+	if (type != dquot->dq_own.type)
 		goto out;
 	status = ocfs2_lock_global_qf(oinfo, 1);
 	if (status < 0)
@@ -643,7 +648,8 @@ static int ocfs2_write_dquot(struct dquot *dquot)
 	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
 	int status = 0;
 
-	trace_ocfs2_write_dquot(dquot->dq_id, dquot->dq_type);
+	trace_ocfs2_write_dquot(from_qown(&init_user_ns, dquot->dq_own),
+				dquot->dq_own.type);
 
 	handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
 	if (IS_ERR(handle)) {
@@ -677,11 +683,12 @@ static int ocfs2_release_dquot(struct dquot *dquot)
 {
 	handle_t *handle;
 	struct ocfs2_mem_dqinfo *oinfo =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
 	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
 	int status = 0;
 
-	trace_ocfs2_release_dquot(dquot->dq_id, dquot->dq_type);
+	trace_ocfs2_release_dquot(from_qown(&init_user_ns, dquot->dq_own),
+				  dquot->dq_own.type);
 
 	mutex_lock(&dquot->dq_lock);
 	/* Check whether we are not racing with some other dqget() */
@@ -691,7 +698,7 @@ static int ocfs2_release_dquot(struct dquot *dquot)
 	if (status < 0)
 		goto out;
 	handle = ocfs2_start_trans(osb,
-		ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_type));
+		ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_own.type));
 	if (IS_ERR(handle)) {
 		status = PTR_ERR(handle);
 		mlog_errno(status);
@@ -733,13 +740,14 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
 	int ex = 0;
 	struct super_block *sb = dquot->dq_sb;
 	struct ocfs2_super *osb = OCFS2_SB(sb);
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
 	struct inode *gqinode = info->dqi_gqinode;
 	int need_alloc = ocfs2_global_qinit_alloc(sb, type);
 	handle_t *handle;
 
-	trace_ocfs2_acquire_dquot(dquot->dq_id, type);
+	trace_ocfs2_acquire_dquot(from_qown(&init_user_ns, dquot->dq_own),
+				  type);
 	mutex_lock(&dquot->dq_lock);
 	/*
 	 * We need an exclusive lock, because we're going to update use count
@@ -821,12 +829,13 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
 	int sync = 0;
 	int status;
 	struct super_block *sb = dquot->dq_sb;
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
 	handle_t *handle;
 	struct ocfs2_super *osb = OCFS2_SB(sb);
 
-	trace_ocfs2_mark_dquot_dirty(dquot->dq_id, type);
+	trace_ocfs2_mark_dquot_dirty(from_qown(&init_user_ns, dquot->dq_own),
+				     type);
 
 	/* In case user set some limits, sync dquot immediately to global
 	 * quota file so that information propagates quicker */
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
index f100bf7..3aec405 100644
--- a/fs/ocfs2/quota_local.c
+++ b/fs/ocfs2/quota_local.c
@@ -501,7 +501,9 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
 			}
 			dqblk = (struct ocfs2_local_disk_dqblk *)(qbh->b_data +
 				ol_dqblk_block_off(sb, chunk, bit));
-			dquot = dqget(sb, le64_to_cpu(dqblk->dqb_id), type);
+			dquot = dqget(sb,
+				      make_qown(&init_user_ns, type,
+						le64_to_cpu(dqblk->dqb_id)));
 			if (!dquot) {
 				status = -EIO;
 				mlog(ML_ERROR, "Failed to get quota structure "
@@ -881,7 +883,8 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
 	dqblk = (struct ocfs2_local_disk_dqblk *)(bh->b_data
 		+ ol_dqblk_block_offset(sb, od->dq_local_off));
 
-	dqblk->dqb_id = cpu_to_le64(od->dq_dquot.dq_id);
+	dqblk->dqb_id = cpu_to_le64(from_qown(&init_user_ns,
+					      od->dq_dquot.dq_own));
 	spin_lock(&dq_data_lock);
 	dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace -
 					  od->dq_origspace);
@@ -891,7 +894,7 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
 	trace_olq_set_dquot(
 		(unsigned long long)le64_to_cpu(dqblk->dqb_spacemod),
 		(unsigned long long)le64_to_cpu(dqblk->dqb_inodemod),
-		od->dq_dquot.dq_id);
+		from_qown(&init_user_ns, od->dq_dquot.dq_own));
 }
 
 /* Write dquot to local quota file */
@@ -900,7 +903,7 @@ int ocfs2_local_write_dquot(struct dquot *dquot)
 	struct super_block *sb = dquot->dq_sb;
 	struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
 	struct buffer_head *bh;
-	struct inode *lqinode = sb_dqopt(sb)->files[dquot->dq_type];
+	struct inode *lqinode = sb_dqopt(sb)->files[dquot->dq_own.type];
 	int status;
 
 	status = ocfs2_read_quota_phys_block(lqinode, od->dq_local_phys_blk,
@@ -1221,7 +1224,7 @@ static void olq_alloc_dquot(struct buffer_head *bh, void *private)
 int ocfs2_create_local_dquot(struct dquot *dquot)
 {
 	struct super_block *sb = dquot->dq_sb;
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct inode *lqinode = sb_dqopt(sb)->files[type];
 	struct ocfs2_quota_chunk *chunk;
 	struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
@@ -1275,7 +1278,7 @@ out:
 int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
 {
 	int status;
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
 	struct super_block *sb = dquot->dq_sb;
 	struct ocfs2_local_disk_chunk *dchunk;
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 36a29b7..766ab61 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -253,11 +253,13 @@ static qsize_t inode_get_rsv_space(struct inode *inode);
 static void __dquot_initialize(struct inode *inode, int type);
 
 static inline unsigned int
-hashfn(const struct super_block *sb, unsigned int id, int type)
+hashfn(const struct super_block *sb, struct qown qown)
 {
+	unsigned int id;
 	unsigned long tmp;
 
-	tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type);
+	id = from_qown(&init_user_ns, qown);
+	tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - qown.type);
 	return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask;
 }
 
@@ -267,7 +269,7 @@ hashfn(const struct super_block *sb, unsigned int id, int type)
 static inline void insert_dquot_hash(struct dquot *dquot)
 {
 	struct hlist_head *head;
-	head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type);
+	head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_own);
 	hlist_add_head(&dquot->dq_hash, head);
 }
 
@@ -277,15 +279,14 @@ static inline void remove_dquot_hash(struct dquot *dquot)
 }
 
 static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb,
-				unsigned int id, int type)
+				struct qown own)
 {
 	struct hlist_node *node;
 	struct dquot *dquot;
 
 	hlist_for_each (node, dquot_hash+hashent) {
 		dquot = hlist_entry(node, struct dquot, dq_hash);
-		if (dquot->dq_sb == sb && dquot->dq_id == id &&
-		    dquot->dq_type == type)
+		if (dquot->dq_sb == sb && qown_eq(dquot->dq_own, own))
 			return dquot;
 	}
 	return NULL;
@@ -351,7 +352,7 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)
 	spin_lock(&dq_list_lock);
 	if (!test_and_set_bit(DQ_MOD_B, &dquot->dq_flags)) {
 		list_add(&dquot->dq_dirty, &sb_dqopt(dquot->dq_sb)->
-				info[dquot->dq_type].dqi_dirty_list);
+				info[dquot->dq_own.type].dqi_dirty_list);
 		ret = 0;
 	}
 	spin_unlock(&dq_list_lock);
@@ -410,17 +411,17 @@ int dquot_acquire(struct dquot *dquot)
 	mutex_lock(&dquot->dq_lock);
 	mutex_lock(&dqopt->dqio_mutex);
 	if (!test_bit(DQ_READ_B, &dquot->dq_flags))
-		ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot);
+		ret = dqopt->ops[dquot->dq_own.type]->read_dqblk(dquot);
 	if (ret < 0)
 		goto out_iolock;
 	set_bit(DQ_READ_B, &dquot->dq_flags);
 	/* Instantiate dquot if needed */
 	if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) {
-		ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+		ret = dqopt->ops[dquot->dq_own.type]->commit_dqblk(dquot);
 		/* Write the info if needed */
-		if (info_dirty(&dqopt->info[dquot->dq_type])) {
-			ret2 = dqopt->ops[dquot->dq_type]->write_file_info(
-						dquot->dq_sb, dquot->dq_type);
+		if (info_dirty(&dqopt->info[dquot->dq_own.type])) {
+			ret2 = dqopt->ops[dquot->dq_own.type]->write_file_info(
+					dquot->dq_sb, dquot->dq_own.type);
 		}
 		if (ret < 0)
 			goto out_iolock;
@@ -455,7 +456,7 @@ int dquot_commit(struct dquot *dquot)
 	/* Inactive dquot can be only if there was error during read/init
 	 * => we have better not writing it */
 	if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
-		ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+		ret = dqopt->ops[dquot->dq_own.type]->commit_dqblk(dquot);
 	else
 		ret = -EIO;
 out_sem:
@@ -477,12 +478,12 @@ int dquot_release(struct dquot *dquot)
 	if (atomic_read(&dquot->dq_count) > 1)
 		goto out_dqlock;
 	mutex_lock(&dqopt->dqio_mutex);
-	if (dqopt->ops[dquot->dq_type]->release_dqblk) {
-		ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot);
+	if (dqopt->ops[dquot->dq_own.type]->release_dqblk) {
+		ret = dqopt->ops[dquot->dq_own.type]->release_dqblk(dquot);
 		/* Write the info */
-		if (info_dirty(&dqopt->info[dquot->dq_type])) {
-			ret2 = dqopt->ops[dquot->dq_type]->write_file_info(
-						dquot->dq_sb, dquot->dq_type);
+		if (info_dirty(&dqopt->info[dquot->dq_own.type])) {
+			ret2 = dqopt->ops[dquot->dq_own.type]->write_file_info(
+						dquot->dq_sb, dquot->dq_own.type);
 		}
 		if (ret >= 0)
 			ret = ret2;
@@ -521,7 +522,7 @@ restart:
 	list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
 		if (dquot->dq_sb != sb)
 			continue;
-		if (dquot->dq_type != type)
+		if (dquot->dq_own.type != type)
 			continue;
 		/* Wait for dquot users */
 		if (atomic_read(&dquot->dq_count)) {
@@ -741,7 +742,8 @@ void dqput(struct dquot *dquot)
 #ifdef CONFIG_QUOTA_DEBUG
 	if (!atomic_read(&dquot->dq_count)) {
 		quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
-			    quotatypes[dquot->dq_type], dquot->dq_id);
+			    quotatypes[dquot->dq_own.type],
+			    from_qown(&init_user_ns, dquot->dq_own));
 		BUG();
 	}
 #endif
@@ -752,7 +754,7 @@ we_slept:
 		/* We have more than one user... nothing to do */
 		atomic_dec(&dquot->dq_count);
 		/* Releasing dquot during quotaoff phase? */
-		if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_type) &&
+		if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_own.type) &&
 		    atomic_read(&dquot->dq_count) == 1)
 			wake_up(&dquot->dq_wait_unused);
 		spin_unlock(&dq_list_lock);
@@ -815,7 +817,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
 	INIT_LIST_HEAD(&dquot->dq_dirty);
 	init_waitqueue_head(&dquot->dq_wait_unused);
 	dquot->dq_sb = sb;
-	dquot->dq_type = type;
+	dquot->dq_own = make_qown_invalid(type);
 	atomic_set(&dquot->dq_count, 1);
 
 	return dquot;
@@ -829,35 +831,35 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
  *   a) checking for quota flags under dq_list_lock and
  *   b) getting a reference to dquot before we release dq_list_lock
  */
-struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
+struct dquot *dqget(struct super_block *sb, struct qown qown)
 {
-	unsigned int hashent = hashfn(sb, id, type);
+	unsigned int hashent = hashfn(sb, qown);
 	struct dquot *dquot = NULL, *empty = NULL;
 
-        if (!sb_has_quota_active(sb, type))
+        if (!sb_has_quota_active(sb, qown.type))
 		return NULL;
 we_slept:
 	spin_lock(&dq_list_lock);
 	spin_lock(&dq_state_lock);
-	if (!sb_has_quota_active(sb, type)) {
+	if (!sb_has_quota_active(sb, qown.type)) {
 		spin_unlock(&dq_state_lock);
 		spin_unlock(&dq_list_lock);
 		goto out;
 	}
 	spin_unlock(&dq_state_lock);
 
-	dquot = find_dquot(hashent, sb, id, type);
+	dquot = find_dquot(hashent, sb, qown);
 	if (!dquot) {
 		if (!empty) {
 			spin_unlock(&dq_list_lock);
-			empty = get_empty_dquot(sb, type);
+			empty = get_empty_dquot(sb, qown.type);
 			if (!empty)
 				schedule();	/* Try to wait for a moment... */
 			goto we_slept;
 		}
 		dquot = empty;
 		empty = NULL;
-		dquot->dq_id = id;
+		dquot->dq_own = qown;
 		/* all dquots go on the inuse_list */
 		put_inuse(dquot);
 		/* hash it first so it can be found */
@@ -1129,8 +1131,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
 
 struct dquot_warn {
 	struct super_block *w_sb;
-	qid_t w_dq_id;
-	short w_dq_type;
+	struct qown w_dq_own;
 	short w_type;
 };
 
@@ -1154,11 +1155,11 @@ static int need_print_warning(struct dquot_warn *warn)
 	if (!flag_print_warnings)
 		return 0;
 
-	switch (warn->w_dq_type) {
+	switch (warn->w_dq_own.type) {
 		case USRQUOTA:
-			return current_fsuid() == warn->w_dq_id;
+			return uid_eq(current_fsuid(), warn->w_dq_own.uid);
 		case GRPQUOTA:
-			return in_group_p(warn->w_dq_id);
+			return in_group_p(warn->w_dq_own.gid);
 	}
 	return 0;
 }
@@ -1184,7 +1185,7 @@ static void print_warning(struct dquot_warn *warn)
 		tty_write_message(tty, ": warning, ");
 	else
 		tty_write_message(tty, ": write failed, ");
-	tty_write_message(tty, quotatypes[warn->w_dq_type]);
+	tty_write_message(tty, quotatypes[warn->w_dq_own.type]);
 	switch (warntype) {
 		case QUOTA_NL_IHARDWARN:
 			msg = " file limit reached.\r\n";
@@ -1217,8 +1218,7 @@ static void prepare_warning(struct dquot_warn *warn, struct dquot *dquot,
 		return;
 	warn->w_type = warntype;
 	warn->w_sb = dquot->dq_sb;
-	warn->w_dq_id = dquot->dq_id;
-	warn->w_dq_type = dquot->dq_type;
+	warn->w_dq_own = dquot->dq_own;
 }
 
 /*
@@ -1236,14 +1236,14 @@ static void flush_warnings(struct dquot_warn *warn)
 #ifdef CONFIG_PRINT_QUOTA_WARNING
 		print_warning(&warn[i]);
 #endif
-		quota_send_warning(warn[i].w_dq_type, warn[i].w_dq_id,
+		quota_send_warning(warn[i].w_dq_own,
 				   warn[i].w_sb->s_dev, warn[i].w_type);
 	}
 }
 
 static int ignore_hardlimit(struct dquot *dquot)
 {
-	struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+	struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_own.type];
 
 	return capable(CAP_SYS_RESOURCE) &&
 	       (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD ||
@@ -1256,7 +1256,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
 {
 	qsize_t newinodes = dquot->dq_dqb.dqb_curinodes + inodes;
 
-	if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
+	if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_own.type) ||
 	    test_bit(DQ_FAKE_B, &dquot->dq_flags))
 		return 0;
 
@@ -1281,7 +1281,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
 	    dquot->dq_dqb.dqb_itime == 0) {
 		prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN);
 		dquot->dq_dqb.dqb_itime = get_seconds() +
-		    sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+		    sb_dqopt(dquot->dq_sb)->info[dquot->dq_own.type].dqi_igrace;
 	}
 
 	return 0;
@@ -1294,7 +1294,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
 	qsize_t tspace;
 	struct super_block *sb = dquot->dq_sb;
 
-	if (!sb_has_quota_limits_enabled(sb, dquot->dq_type) ||
+	if (!sb_has_quota_limits_enabled(sb, dquot->dq_own.type) ||
 	    test_bit(DQ_FAKE_B, &dquot->dq_flags))
 		return 0;
 
@@ -1325,7 +1325,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
 		if (!prealloc) {
 			prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN);
 			dquot->dq_dqb.dqb_btime = get_seconds() +
-			    sb_dqopt(sb)->info[dquot->dq_type].dqi_bgrace;
+			    sb_dqopt(sb)->info[dquot->dq_own.type].dqi_bgrace;
 		}
 		else
 			/*
@@ -1344,7 +1344,7 @@ static int info_idq_free(struct dquot *dquot, qsize_t inodes)
 
 	if (test_bit(DQ_FAKE_B, &dquot->dq_flags) ||
 	    dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit ||
-	    !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type))
+	    !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_own.type))
 		return QUOTA_NL_NOWARN;
 
 	newinodes = dquot->dq_dqb.dqb_curinodes - inodes;
@@ -1390,7 +1390,6 @@ static int dquot_active(const struct inode *inode)
  */
 static void __dquot_initialize(struct inode *inode, int type)
 {
-	unsigned int id = 0;
 	int cnt;
 	struct dquot *got[MAXQUOTAS];
 	struct super_block *sb = inode->i_sb;
@@ -1403,18 +1402,19 @@ static void __dquot_initialize(struct inode *inode, int type)
 
 	/* First get references to structures we might need. */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		struct qown qown;
 		got[cnt] = NULL;
 		if (type != -1 && cnt != type)
 			continue;
 		switch (cnt) {
 		case USRQUOTA:
-			id = inode->i_uid;
+			qown = make_qown_uid(inode->i_uid);
 			break;
 		case GRPQUOTA:
-			id = inode->i_gid;
+			qown = make_qown_gid(inode->i_gid);
 			break;
 		}
-		got[cnt] = dqget(sb, id, cnt);
+		got[cnt] = dqget(sb, qown);
 	}
 
 	down_write(&sb_dqopt(sb)->dqptr_sem);
@@ -1897,10 +1897,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
 	if (!dquot_active(inode))
 		return 0;
 
-	if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
-		transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA);
-	if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)
-		transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA);
+	if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
+		transfer_to[USRQUOTA] = dqget(sb, make_qown_uid(iattr->ia_uid));
+	if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
+		transfer_to[GRPQUOTA] = dqget(sb, make_qown_gid(iattr->ia_gid));
 
 	ret = __dquot_transfer(inode, transfer_to);
 	dqput_all(transfer_to);
@@ -2360,9 +2360,9 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 
 	memset(di, 0, sizeof(*di));
 	di->d_version = FS_DQUOT_VERSION;
-	di->d_flags = dquot->dq_type == USRQUOTA ?
+	di->d_flags = dquot->dq_own.type == USRQUOTA ?
 			FS_USER_QUOTA : FS_GROUP_QUOTA;
-	di->d_id = dquot->dq_id;
+	di->d_id = from_qown_munged(current_user_ns(), dquot->dq_own);
 
 	spin_lock(&dq_data_lock);
 	di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
@@ -2376,12 +2376,12 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 	spin_unlock(&dq_data_lock);
 }
 
-int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_get_dqblk(struct super_block *sb, struct qown qown,
 		    struct fs_disk_quota *di)
 {
 	struct dquot *dquot;
 
-	dquot = dqget(sb, id, type);
+	dquot = dqget(sb, qown);
 	if (!dquot)
 		return -ESRCH;
 	do_get_dqblk(dquot, di);
@@ -2401,7 +2401,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 {
 	struct mem_dqblk *dm = &dquot->dq_dqb;
 	int check_blim = 0, check_ilim = 0;
-	struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+	struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_own.type];
 
 	if (di->d_fieldmask & ~VFS_FS_DQ_MASK)
 		return -EINVAL;
@@ -2488,13 +2488,13 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 	return 0;
 }
 
-int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, struct qown qown,
 		  struct fs_disk_quota *di)
 {
 	struct dquot *dquot;
 	int rc;
 
-	dquot = dqget(sb, id, type);
+	dquot = dqget(sb, qown);
 	if (!dquot) {
 		rc = -ESRCH;
 		goto out;
diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
index d67908b..82e99d7 100644
--- a/fs/quota/netlink.c
+++ b/fs/quota/netlink.c
@@ -30,7 +30,7 @@ static struct genl_family quota_genl_family = {
  *
  */
 
-void quota_send_warning(short type, unsigned int id, dev_t dev,
+void quota_send_warning(struct qown qown, dev_t dev,
 			const char warntype)
 {
 	static atomic_t seq;
@@ -56,10 +56,11 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
 		  "VFS: Cannot store netlink header in quota warning.\n");
 		goto err_out;
 	}
-	ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type);
+	ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, qown.type);
 	if (ret)
 		goto attr_err_out;
-	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id);
+	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID,
+			  from_qown_munged(&init_user_ns, qown));
 	if (ret)
 		goto attr_err_out;
 	ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
@@ -71,7 +72,8 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
 	ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev));
 	if (ret)
 		goto attr_err_out;
-	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
+	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID,
+			  from_kuid_munged(&init_user_ns, current_uid()));
 	if (ret)
 		goto attr_err_out;
 	genlmsg_end(skb, msg_head);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 6f15578..6c0e376 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -32,8 +32,8 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
 	/* allow to query information for dquots we "own" */
 	case Q_GETQUOTA:
 	case Q_XGETQUOTA:
-		if ((type == USRQUOTA && current_euid() == id) ||
-		    (type == GRPQUOTA && in_egroup_p(id)))
+		if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
+		    (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
 			break;
 		/*FALLTHROUGH*/
 	default:
@@ -130,13 +130,17 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
 static int quota_getquota(struct super_block *sb, int type, qid_t id,
 			  void __user *addr)
 {
+	struct qown qown;
 	struct fs_disk_quota fdq;
 	struct if_dqblk idq;
 	int ret;
 
 	if (!sb->s_qcop->get_dqblk)
 		return -ENOSYS;
-	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
+	qown = make_qown(current_user_ns(), type, id);
+	if (qown_valid(qown))
+		return -EINVAL;
+	ret = sb->s_qcop->get_dqblk(sb, qown, &fdq);
 	if (ret)
 		return ret;
 	copy_to_if_dqblk(&idq, &fdq);
@@ -176,13 +180,17 @@ static int quota_setquota(struct super_block *sb, int type, qid_t id,
 {
 	struct fs_disk_quota fdq;
 	struct if_dqblk idq;
+	struct qown qown;
 
 	if (copy_from_user(&idq, addr, sizeof(idq)))
 		return -EFAULT;
 	if (!sb->s_qcop->set_dqblk)
 		return -ENOSYS;
+	qown = make_qown(current_user_ns(), type, id);
+	if (!qown_valid(qown))
+		return -EINVAL;
 	copy_from_if_dqblk(&fdq, &idq);
-	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
+	return sb->s_qcop->set_dqblk(sb, qown, &fdq);
 }
 
 static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
@@ -213,23 +221,31 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id,
 			   void __user *addr)
 {
 	struct fs_disk_quota fdq;
+	struct qown qown;
 
 	if (copy_from_user(&fdq, addr, sizeof(fdq)))
 		return -EFAULT;
 	if (!sb->s_qcop->set_dqblk)
 		return -ENOSYS;
-	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
+	qown = make_qown(current_user_ns(), type, id);
+	if (!qown_valid(qown))
+		return -EINVAL;
+	return sb->s_qcop->set_dqblk(sb, qown, &fdq);
 }
 
 static int quota_getxquota(struct super_block *sb, int type, qid_t id,
 			   void __user *addr)
 {
 	struct fs_disk_quota fdq;
+	struct qown qown;
 	int ret;
 
 	if (!sb->s_qcop->get_dqblk)
 		return -ENOSYS;
-	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
+	qown = make_qown(current_user_ns(), type, id);
+	if (!qown_valid(qown))
+		return -EINVAL;
+	ret = sb->s_qcop->get_dqblk(sb, qown, &fdq);
 	if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
 		return -EFAULT;
 	return ret;
diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
index e41c1becf..fa48156 100644
--- a/fs/quota/quota_tree.c
+++ b/fs/quota/quota_tree.c
@@ -22,10 +22,12 @@ MODULE_LICENSE("GPL");
 
 #define __QUOTA_QT_PARANOIA
 
-static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
+static int get_index(struct qtree_mem_dqinfo *info, struct qown qown, int depth)
 {
 	unsigned int epb = info->dqi_usable_bs >> 2;
+	qid_t id;
 
+	id = from_qown(&init_user_ns, qown);
 	depth = info->dqi_qtree_depth - depth - 1;
 	while (depth--)
 		id /= epb;
@@ -244,7 +246,7 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
 		/* This is enough as the block is already zeroed and the entry
 		 * list is empty... */
 		info->dqi_free_entry = blk;
-		mark_info_dirty(dquot->dq_sb, dquot->dq_type);
+		mark_info_dirty(dquot->dq_sb, dquot->dq_own.type);
 	}
 	/* Block will be full? */
 	if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) {
@@ -313,7 +315,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 		}
 	}
 	ref = (__le32 *)buf;
-	newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+	newblk = le32_to_cpu(ref[get_index(info, dquot->dq_own, depth)]);
 	if (!newblk)
 		newson = 1;
 	if (depth == info->dqi_qtree_depth - 1) {
@@ -322,7 +324,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 			quota_error(dquot->dq_sb, "Inserting already present "
 				    "quota entry (block %u)",
 				    le32_to_cpu(ref[get_index(info,
-						dquot->dq_id, depth)]));
+						dquot->dq_own, depth)]));
 			ret = -EIO;
 			goto out_buf;
 		}
@@ -332,7 +334,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 		ret = do_insert_tree(info, dquot, &newblk, depth+1);
 	}
 	if (newson && ret >= 0) {
-		ref[get_index(info, dquot->dq_id, depth)] =
+		ref[get_index(info, dquot->dq_own, depth)] =
 							cpu_to_le32(newblk);
 		ret = write_blk(info, *treeblk, buf);
 	} else if (newact && ret < 0) {
@@ -357,7 +359,7 @@ static inline int dq_insert_tree(struct qtree_mem_dqinfo *info,
  */
 int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 {
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct super_block *sb = dquot->dq_sb;
 	ssize_t ret;
 	char *ddquot = getdqbuf(info->dqi_entry_size);
@@ -472,7 +474,7 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 			    *blk);
 		goto out_buf;
 	}
-	newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+	newblk = le32_to_cpu(ref[get_index(info, dquot->dq_own, depth)]);
 	if (depth == info->dqi_qtree_depth - 1) {
 		ret = free_dqentry(info, dquot, newblk);
 		newblk = 0;
@@ -481,7 +483,7 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 	}
 	if (ret >= 0 && !newblk) {
 		int i;
-		ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0);
+		ref[get_index(info, dquot->dq_own, depth)] = cpu_to_le32(0);
 		/* Block got empty? */
 		for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++)
 			;
@@ -538,8 +540,9 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
 		ddquot += info->dqi_entry_size;
 	}
 	if (i == qtree_dqstr_in_blk(info)) {
-		quota_error(dquot->dq_sb, "Quota for id %u referenced "
-			    "but not present", dquot->dq_id);
+		quota_error(dquot->dq_sb,
+			    "Quota for id %u referenced but not present",
+			    from_qown(&init_user_ns, dquot->dq_own));
 		ret = -EIO;
 		goto out_buf;
 	} else {
@@ -568,7 +571,7 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
 		goto out_buf;
 	}
 	ret = 0;
-	blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+	blk = le32_to_cpu(ref[get_index(info, dquot->dq_own, depth)]);
 	if (!blk)	/* No reference? */
 		goto out_buf;
 	if (depth < info->dqi_qtree_depth - 1)
@@ -589,7 +592,7 @@ static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info,
 
 int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 {
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct super_block *sb = dquot->dq_sb;
 	loff_t offset;
 	char *ddquot;
@@ -607,8 +610,10 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 		offset = find_dqentry(info, dquot);
 		if (offset <= 0) {	/* Entry not present? */
 			if (offset < 0)
-				quota_error(sb, "Can't read quota structure "
-					    "for id %u", dquot->dq_id);
+				quota_error(sb,"Can't read quota structure "
+					    "for id %u",
+					    from_qown(&init_user_ns,
+						      dquot->dq_own));
 			dquot->dq_off = 0;
 			set_bit(DQ_FAKE_B, &dquot->dq_flags);
 			memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
@@ -626,7 +631,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 		if (ret >= 0)
 			ret = -EIO;
 		quota_error(sb, "Error while reading quota structure for id %u",
-			    dquot->dq_id);
+			    from_qown(&init_user_ns, dquot->dq_own));
 		set_bit(DQ_FAKE_B, &dquot->dq_flags);
 		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
 		kfree(ddquot);
diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c
index 34b37a6..ec37d70 100644
--- a/fs/quota/quota_v1.c
+++ b/fs/quota/quota_v1.c
@@ -54,7 +54,7 @@ static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m)
 
 static int v1_read_dqblk(struct dquot *dquot)
 {
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct v1_disk_dqblk dqblk;
 
 	if (!sb_dqopt(dquot->dq_sb)->files[type])
@@ -63,7 +63,8 @@ static int v1_read_dqblk(struct dquot *dquot)
 	/* Set structure to 0s in case read fails/is after end of file */
 	memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
 	dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk,
-			sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
+			sizeof(struct v1_disk_dqblk),
+			v1_dqoff(from_qown(&init_user_ns, dquot->dq_own)));
 
 	v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
 	if (dquot->dq_dqb.dqb_bhardlimit == 0 &&
@@ -78,12 +79,13 @@ static int v1_read_dqblk(struct dquot *dquot)
 
 static int v1_commit_dqblk(struct dquot *dquot)
 {
-	short type = dquot->dq_type;
+	short type = dquot->dq_own.type;
 	ssize_t ret;
 	struct v1_disk_dqblk dqblk;
 
 	v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
-	if (dquot->dq_id == 0) {
+	if (((type == USRQUOTA) && uid_eq(dquot->dq_own.uid, GLOBAL_ROOT_UID)) ||
+	    ((type == GRPQUOTA) && gid_eq(dquot->dq_own.gid, GLOBAL_ROOT_GID))) {
 		dqblk.dqb_btime =
 			sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
 		dqblk.dqb_itime =
@@ -93,7 +95,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
 	if (sb_dqopt(dquot->dq_sb)->files[type])
 		ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
 			(char *)&dqblk, sizeof(struct v1_disk_dqblk),
-			v1_dqoff(dquot->dq_id));
+			v1_dqoff(from_qown(&init_user_ns, dquot->dq_own)));
 	if (ret != sizeof(struct v1_disk_dqblk)) {
 		quota_error(dquot->dq_sb, "dquota write failed");
 		if (ret >= 0)
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
index f1ab360..1c26279 100644
--- a/fs/quota/quota_v2.c
+++ b/fs/quota/quota_v2.c
@@ -196,7 +196,7 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
 	struct v2r0_disk_dqblk *d = dp;
 	struct mem_dqblk *m = &dquot->dq_dqb;
 	struct qtree_mem_dqinfo *info =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
 
 	d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
 	d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
@@ -206,7 +206,7 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
 	d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
 	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
 	d->dqb_btime = cpu_to_le64(m->dqb_btime);
-	d->dqb_id = cpu_to_le32(dquot->dq_id);
+	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_own));
 	if (qtree_entry_unused(info, dp))
 		d->dqb_itime = cpu_to_le64(1);
 }
@@ -215,11 +215,13 @@ static int v2r0_is_id(void *dp, struct dquot *dquot)
 {
 	struct v2r0_disk_dqblk *d = dp;
 	struct qtree_mem_dqinfo *info =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
+	struct qown qown;
 
 	if (qtree_entry_unused(info, dp))
 		return 0;
-	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+	qown = make_qown(&init_user_ns, dquot->dq_own.type, le32_to_cpu(d->dqb_id));
+	return qown_eq(qown, dquot->dq_own);
 }
 
 static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
@@ -247,7 +249,7 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
 	struct v2r1_disk_dqblk *d = dp;
 	struct mem_dqblk *m = &dquot->dq_dqb;
 	struct qtree_mem_dqinfo *info =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
 
 	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
 	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
@@ -257,7 +259,7 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
 	d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
 	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
 	d->dqb_btime = cpu_to_le64(m->dqb_btime);
-	d->dqb_id = cpu_to_le32(dquot->dq_id);
+	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_own));
 	if (qtree_entry_unused(info, dp))
 		d->dqb_itime = cpu_to_le64(1);
 }
@@ -266,26 +268,28 @@ static int v2r1_is_id(void *dp, struct dquot *dquot)
 {
 	struct v2r1_disk_dqblk *d = dp;
 	struct qtree_mem_dqinfo *info =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
+	struct qown qown;
 
 	if (qtree_entry_unused(info, dp))
 		return 0;
-	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+	qown = make_qown(&init_user_ns, dquot->dq_own.type, le32_to_cpu(d->dqb_id));
+	return qown_eq(qown, dquot->dq_own);
 }
 
 static int v2_read_dquot(struct dquot *dquot)
 {
-	return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+	return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv, dquot);
 }
 
 static int v2_write_dquot(struct dquot *dquot)
 {
-	return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+	return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv, dquot);
 }
 
 static int v2_release_dquot(struct dquot *dquot)
 {
-	return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+	return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv, dquot);
 }
 
 static int v2_free_file_info(struct super_block *sb, int type)
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index fed504f..589e9c7 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -97,28 +97,29 @@ xfs_fs_set_xstate(
 STATIC int
 xfs_fs_get_dqblk(
 	struct super_block	*sb,
-	int			type,
-	qid_t			id,
+	struct qown		qown,
 	struct fs_disk_quota	*fdq)
 {
 	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		xfs_id;
 
 	if (!XFS_IS_QUOTA_RUNNING(mp))
 		return -ENOSYS;
 	if (!XFS_IS_QUOTA_ON(mp))
 		return -ESRCH;
 
-	return -xfs_qm_scall_getquota(mp, id, xfs_quota_type(type), fdq);
+	xfs_id = from_qown(&init_user_ns, qown);
+	return -xfs_qm_scall_getquota(mp, xfs_id, xfs_quota_type(qown.type), fdq);
 }
 
 STATIC int
 xfs_fs_set_dqblk(
 	struct super_block	*sb,
-	int			type,
-	qid_t			id,
+	struct qown		qown,
 	struct fs_disk_quota	*fdq)
 {
 	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		xfs_id;
 
 	if (sb->s_flags & MS_RDONLY)
 		return -EROFS;
@@ -127,7 +128,8 @@ xfs_fs_set_dqblk(
 	if (!XFS_IS_QUOTA_ON(mp))
 		return -ESRCH;
 
-	return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq);
+	xfs_id = from_qown(&init_user_ns, qown);
+	return -xfs_qm_scall_setqlim(mp, xfs_id, xfs_quota_type(qown.type), fdq);
 }
 
 const struct quotactl_ops xfs_quotactl_operations = {
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index bcb6054..3e9fbb8 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -575,12 +575,14 @@ xfs_quota_warn(
 	struct xfs_dquot	*dqp,
 	int			type)
 {
+	int qtype;
+	struct qown qown;
 	/* no warnings for project quotas - we just return ENOSPC later */
 	if (dqp->dq_flags & XFS_DQ_PROJ)
 		return;
-	quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA,
-			   be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev,
-			   type);
+	qtype = (dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA;
+	qown = make_qown(&init_user_ns, qtype, be32_to_cpu(dqp->q_core.d_id));
+	quota_send_warning(qown, mp->m_super->s_dev, type);
 }
 
 /*
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 524ede8..6ebb782 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -181,10 +181,161 @@ enum {
 #include <linux/dqblk_v2.h>
 
 #include <linux/atomic.h>
+#include <linux/uidgid.h>
 
 typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
 typedef long long qsize_t;	/* Type in which we store sizes */
 
+struct qown {			/* Type in which we store the quota owner */
+	union {
+		kuid_t uid;
+		kgid_t gid;
+		unsigned int prj;
+	};
+	int type; /* USRQUOTA (uid) or GRPQUOTA (gid) or XQM_PRJQUOTA (prj) */
+};
+
+static inline bool qown_eq(struct qown left, struct qown right)
+{
+	if (left.type != right.type)
+		return false;
+	switch(left.type) {
+	case USRQUOTA:
+		return uid_eq(left.uid, right.uid);
+	case GRPQUOTA:
+		return gid_eq(left.gid, right.gid);
+	case XQM_PRJQUOTA:
+		return left.prj == right.prj;
+	default:
+		BUG();
+	}
+}
+
+static inline bool qown_lt(struct qown left, struct qown right)
+{
+	if (left.type < right.type)
+		return true;
+	if (left.type > right.type)
+		return false;
+	switch (left.type) {
+	case USRQUOTA:
+		return uid_lt(left.uid, right.uid);
+	case GRPQUOTA:
+		return gid_lt(left.gid, right.gid);
+	case XQM_PRJQUOTA:
+		return left.prj < right.prj;
+	default:
+		BUG();
+	}
+}
+
+static inline u32 from_qown(struct user_namespace *user_ns, struct qown qown)
+{
+	switch (qown.type) {
+	case USRQUOTA:
+		return from_kuid(user_ns, qown.uid);
+	case GRPQUOTA:
+		return from_kgid(user_ns, qown.gid);
+	case XQM_PRJQUOTA:
+		return (user_ns == &init_user_ns) ? qown.prj : -1;
+	default:
+		BUG();
+	}
+}
+
+static inline u32 from_qown_munged(struct user_namespace *user_ns,
+				   struct qown qown)
+{
+	switch (qown.type) {
+	case USRQUOTA:
+		return from_kuid_munged(user_ns, qown.uid);
+	case GRPQUOTA:
+		return from_kgid_munged(user_ns, qown.gid);
+	case XQM_PRJQUOTA:
+		return (user_ns == &init_user_ns) ? qown.prj : -1;
+	default:
+		BUG();
+	}
+}
+
+static inline struct qown make_qown(struct user_namespace *user_ns,
+				    int type, qid_t id)
+{
+	struct qown qown;
+
+	qown.type = type;
+	switch (type) {
+	case USRQUOTA:
+		qown.uid = make_kuid(user_ns, id);
+		break;
+	case GRPQUOTA:
+		qown.gid = make_kgid(user_ns, id);
+		break;
+	case XQM_PRJQUOTA:
+		if (user_ns == &init_user_ns)
+			qown.prj = id;
+		else
+			qown.prj = -1;
+		break;
+	default:
+		BUG();
+	}
+	return qown;
+}
+
+static inline struct qown make_qown_invalid(int type)
+{
+	struct qown qown;
+
+	qown.type = type;
+	switch (type) {
+	case USRQUOTA:
+		qown.uid = INVALID_UID;
+		break;
+	case GRPQUOTA:
+		qown.gid = INVALID_GID;
+		break;
+	case XQM_PRJQUOTA:
+		qown.prj = -1;
+		break;
+	default:
+		BUG();
+	}
+	return qown;
+}
+
+static inline struct qown make_qown_uid(kuid_t uid)
+{
+	struct qown qown = {
+		.type = USRQUOTA,
+		.uid  = uid,
+	};
+	return qown;
+}
+
+static inline struct qown make_qown_gid(kgid_t gid)
+{
+	struct qown qown = {
+		.type = GRPQUOTA,
+		.gid  = gid,
+	};
+	return qown;
+}
+
+static inline bool qown_valid(struct qown qown)
+{
+	switch (qown.type) {
+	case USRQUOTA:
+		return uid_valid(qown.uid);
+	case GRPQUOTA:
+		return gid_valid(qown.gid);
+	case XQM_PRJQUOTA:
+		return qown.prj != (unsigned int)-1;
+	default:
+		BUG();
+	}
+}
+
 extern spinlock_t dq_data_lock;
 
 /* Maximal numbers of writes for quota operation (insert/delete/update)
@@ -294,10 +445,9 @@ struct dquot {
 	atomic_t dq_count;		/* Use count */
 	wait_queue_head_t dq_wait_unused;	/* Wait queue for dquot to become unused */
 	struct super_block *dq_sb;	/* superblock this applies to */
-	unsigned int dq_id;		/* ID this applies to (uid, gid) */
+	struct qown dq_own;		/* ID this applies to (uid, gid) */
 	loff_t dq_off;			/* Offset of dquot on disk */
 	unsigned long dq_flags;		/* See DQ_* */
-	short dq_type;			/* Type of quota */
 	struct mem_dqblk dq_dqb;	/* Diskquota usage */
 };
 
@@ -336,8 +486,8 @@ struct quotactl_ops {
 	int (*quota_sync)(struct super_block *, int);
 	int (*get_info)(struct super_block *, int, struct if_dqinfo *);
 	int (*set_info)(struct super_block *, int, struct if_dqinfo *);
-	int (*get_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
-	int (*set_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
+	int (*get_dqblk)(struct super_block *, struct qown, struct fs_disk_quota *);
+	int (*set_dqblk)(struct super_block *, struct qown, struct fs_disk_quota *);
 	int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
 	int (*set_xstate)(struct super_block *, unsigned int, int);
 };
@@ -386,10 +536,10 @@ static inline unsigned int dquot_generic_flag(unsigned int flags, int type)
 }
 
 #ifdef CONFIG_QUOTA_NETLINK_INTERFACE
-extern void quota_send_warning(short type, unsigned int id, dev_t dev,
+extern void quota_send_warning(struct qown qown, dev_t dev,
 			       const char warntype);
 #else
-static inline void quota_send_warning(short type, unsigned int id, dev_t dev,
+static inline void quota_send_warning(struct qown qown, dev_t dev,
 				      const char warntype)
 {
 	return;
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index ec6b65f..ed9a5e4 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -44,7 +44,7 @@ void inode_sub_rsv_space(struct inode *inode, qsize_t number);
 
 void dquot_initialize(struct inode *inode);
 void dquot_drop(struct inode *inode);
-struct dquot *dqget(struct super_block *sb, unsigned int id, int type);
+struct dquot *dqget(struct super_block *sb, struct qown qown);
 void dqput(struct dquot *dquot);
 int dquot_scan_active(struct super_block *sb,
 		      int (*fn)(struct dquot *dquot, unsigned long priv),
@@ -87,9 +87,9 @@ int dquot_writeback_dquots(struct super_block *sb, int type);
 int dquot_quota_sync(struct super_block *sb, int type);
 int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
 int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
-int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_get_dqblk(struct super_block *sb, struct qown id,
 		struct fs_disk_quota *di);
-int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, struct qown id,
 		struct fs_disk_quota *di);
 
 int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
diff --git a/init/Kconfig b/init/Kconfig
index 2a388e5..a0bccce 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -928,8 +928,6 @@ config UIDGID_CONVERTED
 	depends on IMA = n
 	depends on EVM = n
 	depends on FS_POSIX_ACL = n
-	depends on QUOTA = n
-	depends on QUOTACTL = n
 
 	# Networking
 	depends on NET_9P = n
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH] userns: Add basic quota support v2
  2012-08-28  0:12     ` [PATCH] userns: Add basic quota support v2 Eric W. Biederman
@ 2012-08-28  9:05       ` Jan Kara
  2012-08-28  9:44         ` Boaz Harrosh
  2012-08-28 17:34         ` Eric W. Biederman
  0 siblings, 2 replies; 37+ messages in thread
From: Jan Kara @ 2012-08-28  9:05 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Jan Kara, linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
	Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das

On Mon 27-08-12 17:12:16, Eric W. Biederman wrote: 
> Add the data type struct qown which holds the owning identifier of a
> quota.  struct qown is a replacement for the implicit union of uid,
> gid and project stored in an unsigned int and the quota type field
> that is was used in the quota data structures.  Making the data type
> explicit allows the kuid_t and kgid_t type safety to propogate more
> thoroughly through the code, revealing more places where uid/gid
> conversions need be made.
> 
> Allong with the data type struct qown comes the helper functions
  ^^^^ Along

> qown_eq, qown_lt, from_qown, from_qown_munged, qown_valid, make_qown,
> make_qown_invalid, make_qown_uid, make_qown_gid.
> 
> Replace struct dquot dq_id and dq_type with dq_own a struct qown.
> 
> Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
> and dquot_set_dqblk to use struct qown.
> 
> Make minimal changes to ext3, ext4, gfs2, ocfs2, and xfs to deal with
> the change in quota structures and signatures.  The ocfs2 changes are
> larger than most because of the extensive tracing throughout the ocfs2
> quota code that prints out dq_id.
> 
> v2:
>  - Renamed qown_t struct qown
>  - Added the quota type to struct qown.
>  - Removed enum quota_type (In this patch it was just noise)
>  - Added qown_lt, make_qown_invalid, make_qown_uid, make_qown_gid
>  - Taught qown to handle xfs project ids (but only in init_user_ns). 
>    Q_XGETQUOTA calls .get_quotblk with project ids.
  Just a couple one minor comments below...

> @@ -130,13 +130,17 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
>  static int quota_getquota(struct super_block *sb, int type, qid_t id,
>  			  void __user *addr)
>  {
> +	struct qown qown;
>  	struct fs_disk_quota fdq;
>  	struct if_dqblk idq;
>  	int ret;
>  
>  	if (!sb->s_qcop->get_dqblk)
>  		return -ENOSYS;
> -	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (qown_valid(qown))
            ^ missing '!'

> +		return -EINVAL;
> +	ret = sb->s_qcop->get_dqblk(sb, qown, &fdq);
>  	if (ret)
>  		return ret;
>  	copy_to_if_dqblk(&idq, &fdq);
...
> +static inline u32 from_qown(struct user_namespace *user_ns, struct qown qown)
> +{
> +	switch (qown.type) {
> +	case USRQUOTA:
> +		return from_kuid(user_ns, qown.uid);
> +	case GRPQUOTA:
> +		return from_kgid(user_ns, qown.gid);
> +	case XQM_PRJQUOTA:
> +		return (user_ns == &init_user_ns) ? qown.prj : -1;
> +	default:
> +		BUG();
> +	}
> +}
  I would like a bit more if the function somehow expressed in its name
that it returns id. id_from_qown() might be a bit too long given how often
it is used. qown2id() would be OK but it would be inconsistent with how
names of other functions you've added are formed. So I'm somewhat
undecided...

								Honza
-- 
Jan Kara <jack@suse.cz>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] userns: Add basic quota support v2
  2012-08-28  9:05       ` Jan Kara
@ 2012-08-28  9:44         ` Boaz Harrosh
  2012-08-28 17:34         ` Eric W. Biederman
  1 sibling, 0 replies; 37+ messages in thread
From: Boaz Harrosh @ 2012-08-28  9:44 UTC (permalink / raw)
  To: Jan Kara
  Cc: Eric W. Biederman, linux-kernel, netdev, linux-fsdevel,
	Serge E. Hallyn, David Miller, Steven Whitehouse, Mark Fasheh,
	Joel Becker, Ben Myers, Alex Elder, Dmitry Monakhov,
	Abhijith Das

On 08/28/2012 12:05 PM, Jan Kara wrote:

>> +static inline u32 from_qown(struct user_namespace *user_ns, struct qown qown)
>> +{
>> +	switch (qown.type) {
>> +	case USRQUOTA:
>> +		return from_kuid(user_ns, qown.uid);
>> +	case GRPQUOTA:
>> +		return from_kgid(user_ns, qown.gid);
>> +	case XQM_PRJQUOTA:
>> +		return (user_ns == &init_user_ns) ? qown.prj : -1;
>> +	default:
>> +		BUG();
>> +	}
>> +}
>   I would like a bit more if the function somehow expressed in its name
> that it returns id. id_from_qown() might be a bit too long given how often
> it is used. qown2id() would be OK but it would be inconsistent with how
> names of other functions you've added are formed. So I'm somewhat
> undecided...
> 


qown_id()

> 								Honza



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] userns: Add basic quota support v2
  2012-08-28  9:05       ` Jan Kara
  2012-08-28  9:44         ` Boaz Harrosh
@ 2012-08-28 17:34         ` Eric W. Biederman
  2012-08-28 17:36           ` [PATCH] userns: Add basic quota support v3 Eric W. Biederman
  2012-08-28 17:51           ` [PATCH] userns: Add basic quota support v2 Jan Kara
  1 sibling, 2 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-28 17:34 UTC (permalink / raw)
  To: Jan Kara
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
	Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das

Jan Kara <jack@suse.cz> writes:

> On Mon 27-08-12 17:12:16, Eric W. Biederman wrote: 
>> Add the data type struct qown which holds the owning identifier of a
>> quota.  struct qown is a replacement for the implicit union of uid,
>> gid and project stored in an unsigned int and the quota type field
>> that is was used in the quota data structures.  Making the data type
>> explicit allows the kuid_t and kgid_t type safety to propogate more
>> thoroughly through the code, revealing more places where uid/gid
>> conversions need be made.
>> 
>> Allong with the data type struct qown comes the helper functions
>   ^^^^ Along
>
>> qown_eq, qown_lt, from_qown, from_qown_munged, qown_valid, make_qown,
>> make_qown_invalid, make_qown_uid, make_qown_gid.
>> 
>> Replace struct dquot dq_id and dq_type with dq_own a struct qown.
>> 
>> Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
>> and dquot_set_dqblk to use struct qown.
>> 
>> Make minimal changes to ext3, ext4, gfs2, ocfs2, and xfs to deal with
>> the change in quota structures and signatures.  The ocfs2 changes are
>> larger than most because of the extensive tracing throughout the ocfs2
>> quota code that prints out dq_id.
>> 
>> v2:
>>  - Renamed qown_t struct qown
>>  - Added the quota type to struct qown.
>>  - Removed enum quota_type (In this patch it was just noise)
>>  - Added qown_lt, make_qown_invalid, make_qown_uid, make_qown_gid
>>  - Taught qown to handle xfs project ids (but only in init_user_ns). 
>>    Q_XGETQUOTA calls .get_quotblk with project ids.
>   Just a couple one minor comments below...
>
>> @@ -130,13 +130,17 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
>>  static int quota_getquota(struct super_block *sb, int type, qid_t id,
>>  			  void __user *addr)
>>  {
>> +	struct qown qown;
>>  	struct fs_disk_quota fdq;
>>  	struct if_dqblk idq;
>>  	int ret;
>>  
>>  	if (!sb->s_qcop->get_dqblk)
>>  		return -ENOSYS;
>> -	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
>> +	qown = make_qown(current_user_ns(), type, id);
>> +	if (qown_valid(qown))
>             ^ missing '!'

Good catch thank you.  

>> +		return -EINVAL;
>> +	ret = sb->s_qcop->get_dqblk(sb, qown, &fdq);
>>  	if (ret)
>>  		return ret;
>>  	copy_to_if_dqblk(&idq, &fdq);
> ...
>> +static inline u32 from_qown(struct user_namespace *user_ns, struct qown qown)
>> +{
>> +	switch (qown.type) {
>> +	case USRQUOTA:
>> +		return from_kuid(user_ns, qown.uid);
>> +	case GRPQUOTA:
>> +		return from_kgid(user_ns, qown.gid);
>> +	case XQM_PRJQUOTA:
>> +		return (user_ns == &init_user_ns) ? qown.prj : -1;
>> +	default:
>> +		BUG();
>> +	}
>> +}
>   I would like a bit more if the function somehow expressed in its name
> that it returns id. id_from_qown() might be a bit too long given how often
> it is used. qown2id() would be OK but it would be inconsistent with how
> names of other functions you've added are formed. So I'm somewhat
> undecided...

The qown vs id distinction bothers me a little bit.

I almost want to name it struct kid, and the functions make_kid,
from_kid etc.  Where the emphasis is that we are transforming in and out
of the kernel internal form.  I don't really like make_kid because id as
a base name seems to generic and it barely tells you it is.  Perhaps
make_kqid.  Where we call the quota ids and qid for short?

I am a little uncomfortable calling them kqids because the userspace
code also places format_ids in a plain qid_t.  But make_kqid and
from_kqid seems the best alternate set of names I can come up with.

Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH] userns: Add basic quota support v3
  2012-08-28 17:34         ` Eric W. Biederman
@ 2012-08-28 17:36           ` Eric W. Biederman
  2012-08-28 17:51           ` [PATCH] userns: Add basic quota support v2 Jan Kara
  1 sibling, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-28 17:36 UTC (permalink / raw)
  To: Jan Kara
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
	Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das


Add the data type struct qown which holds the owning identifier of a
quota.  struct qown is a replacement for the implicit union of uid,
gid and project stored in an unsigned int and the quota type field
that is was used in the quota data structures.  Making the data type
explicit allows the kuid_t and kgid_t type safety to propogate more
thoroughly through the code, revealing more places where uid/gid
conversions need be made.

Along with the data type struct qown comes the helper functions
qown_eq, qown_lt, from_qown, from_qown_munged, qown_valid, make_qown,
make_qown_invalid, make_qown_uid, make_qown_gid.

Replace struct dquot dq_id and dq_type with dq_own a struct qown.

Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
and dquot_set_dqblk to use struct qown.

Make minimal changes to ext3, ext4, gfs2, ocfs2, and xfs to deal with
the change in quota structures and signatures.  The ocfs2 changes are
larger than most because of the extensive tracing throughout the ocfs2
quota code that prints out dq_id.

v3:
  - Add missing negation on qown_valid
v2:
  - Renamed qown_t struct qown
  - Added the quota type to struct qown.
  - Removed enum quota_type (In this patch it was just noise)
  - Added qown_lt, make_qown_invalid, make_qown_uid, make_qown_gid
  - Taught qown to handle xfs project ids (but only in init_user_ns).
    Q_XGETQUOTA calls .get_quotblk with project ids.

Cc: Steven Whitehouse <swhiteho@redhat.com>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Ben Myers <bpm@sgi.com>
Cc: Alex Elder <elder@kernel.org>
Cc: Jan Kara <jack@suse.cz>
Cc: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 fs/ext3/super.c          |    2 +-
 fs/ext4/super.c          |    2 +-
 fs/gfs2/quota.c          |   52 +++++++++------
 fs/ocfs2/file.c          |    6 +-
 fs/ocfs2/quota_global.c  |   43 +++++++-----
 fs/ocfs2/quota_local.c   |   15 +++--
 fs/quota/dquot.c         |  118 +++++++++++++++++-----------------
 fs/quota/netlink.c       |   10 ++-
 fs/quota/quota.c         |   28 ++++++--
 fs/quota/quota_tree.c    |   35 ++++++----
 fs/quota/quota_v1.c      |   12 ++--
 fs/quota/quota_v2.c      |   26 ++++---
 fs/xfs/xfs_quotaops.c    |   14 ++--
 fs/xfs/xfs_trans_dquot.c |    8 ++-
 include/linux/quota.h    |  162 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/quotaops.h |    6 +-
 init/Kconfig             |    2 -
 17 files changed, 371 insertions(+), 170 deletions(-)

diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index ff9bcdc..c5879f1 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -2814,7 +2814,7 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
 
 static inline struct inode *dquot_to_inode(struct dquot *dquot)
 {
-	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_own.type];
 }
 
 static int ext3_write_dquot(struct dquot *dquot)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index d76ec82..f60b48f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -4796,7 +4796,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
 
 static inline struct inode *dquot_to_inode(struct dquot *dquot)
 {
-	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_own.type];
 }
 
 static int ext4_write_dquot(struct dquot *dquot)
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index a3bde91..f0310f9 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -1057,6 +1057,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
                 return 0;
 
 	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
+		int qtype;
+		struct qown qown;
 		qd = ip->i_res->rs_qa_qd[x];
 
 		if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
@@ -1068,11 +1070,12 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
 		value += qd->qd_change;
 		spin_unlock(&qd_lru_lock);
 
+		qtype = test_bit(QDF_USER, &qd->qd_flags) ? USRQUOTA : GRPQUOTA;
+		qown = make_qown(&init_user_ns, qtype, qd->qd_id);
 		if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
 			print_message(qd, "exceeded");
-			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
-					   USRQUOTA : GRPQUOTA, qd->qd_id,
-					   sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);
+			quota_send_warning(qown, sdp->sd_vfs->s_dev,
+					   QUOTA_NL_BHARDWARN);
 
 			error = -EDQUOT;
 			break;
@@ -1081,9 +1084,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
 			   time_after_eq(jiffies, qd->qd_last_warn +
 					 gfs2_tune_get(sdp,
 						gt_quota_warn_period) * HZ)) {
-			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
-					   USRQUOTA : GRPQUOTA, qd->qd_id,
-					   sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN);
+			quota_send_warning(qown, sdp->sd_vfs->s_dev,
+					   QUOTA_NL_BSOFTWARN);
 			error = print_message(qd, "warning");
 			qd->qd_last_warn = jiffies;
 		}
@@ -1469,7 +1471,7 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
 	return 0;
 }
 
-static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
+static int gfs2_get_dqblk(struct super_block *sb, struct qown qown,
 			  struct fs_disk_quota *fdq)
 {
 	struct gfs2_sbd *sdp = sb->s_fs_info;
@@ -1477,20 +1479,24 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
 	struct gfs2_quota_data *qd;
 	struct gfs2_holder q_gh;
 	int error;
+	int user;
+	u32 gfs_id;
 
 	memset(fdq, 0, sizeof(struct fs_disk_quota));
 
 	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
 		return -ESRCH; /* Crazy XFS error code */
 
-	if (type == USRQUOTA)
-		type = QUOTA_USER;
-	else if (type == GRPQUOTA)
-		type = QUOTA_GROUP;
+	gfs_id = from_qown(&init_user_ns, qown);
+
+	if (qown.type == USRQUOTA)
+		user = QUOTA_USER;
+	else if (qown.type == GRPQUOTA)
+		user = QUOTA_GROUP;
 	else
 		return -EINVAL;
 
-	error = qd_get(sdp, type, id, &qd);
+	error = qd_get(sdp, user, gfs_id, &qd);
 	if (error)
 		return error;
 	error = do_glock(qd, FORCE, &q_gh);
@@ -1499,8 +1505,8 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
 
 	qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
 	fdq->d_version = FS_DQUOT_VERSION;
-	fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
-	fdq->d_id = id;
+	fdq->d_flags = (user == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
+	fdq->d_id = gfs_id;
 	fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;
 	fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;
 	fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift;
@@ -1514,8 +1520,8 @@ out:
 /* GFS2 only supports a subset of the XFS fields */
 #define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT)
 
-static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
-			  struct fs_disk_quota *fdq)
+static int gfs2_set_dqblk(struct super_block *sb,
+			  struct qown qown, struct fs_disk_quota *fdq)
 {
 	struct gfs2_sbd *sdp = sb->s_fs_info;
 	struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
@@ -1526,18 +1532,22 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
 	int alloc_required;
 	loff_t offset;
 	int error;
+	int user;
+	u32 gfs_id;
 
 	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
 		return -ESRCH; /* Crazy XFS error code */
 
-	switch(type) {
+	gfs_id = from_qown(&init_user_ns, qown);
+
+	switch(qown.type) {
 	case USRQUOTA:
-		type = QUOTA_USER;
+		user = QUOTA_USER;
 		if (fdq->d_flags != FS_USER_QUOTA)
 			return -EINVAL;
 		break;
 	case GRPQUOTA:
-		type = QUOTA_GROUP;
+		user = QUOTA_GROUP;
 		if (fdq->d_flags != FS_GROUP_QUOTA)
 			return -EINVAL;
 		break;
@@ -1547,10 +1557,10 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
 
 	if (fdq->d_fieldmask & ~GFS2_FIELDMASK)
 		return -EINVAL;
-	if (fdq->d_id != id)
+	if (fdq->d_id != gfs_id)
 		return -EINVAL;
 
-	error = qd_get(sdp, type, id, &qd);
+	error = qd_get(sdp, user, gfs_id, &qd);
 	if (error)
 		return error;
 
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 46a1f6d..3879186 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1184,8 +1184,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 		if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
 		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
 		    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
-			transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
-						      USRQUOTA);
+			transfer_to[USRQUOTA] = dqget(sb, make_qown_uid(attr->ia_uid));
 			if (!transfer_to[USRQUOTA]) {
 				status = -ESRCH;
 				goto bail_unlock;
@@ -1194,8 +1193,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 		if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid
 		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
 		    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
-			transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
-						      GRPQUOTA);
+			transfer_to[GRPQUOTA] = dqget(sb, make_qown_gid(attr->ia_gid));
 			if (!transfer_to[GRPQUOTA]) {
 				status = -ESRCH;
 				goto bail_unlock;
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
index 0a86e30..dcee469 100644
--- a/fs/ocfs2/quota_global.c
+++ b/fs/ocfs2/quota_global.c
@@ -95,7 +95,7 @@ static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
 	struct ocfs2_global_disk_dqblk *d = dp;
 	struct mem_dqblk *m = &dquot->dq_dqb;
 
-	d->dqb_id = cpu_to_le32(dquot->dq_id);
+	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_own));
 	d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
 	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
 	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
@@ -112,11 +112,14 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
 {
 	struct ocfs2_global_disk_dqblk *d = dp;
 	struct ocfs2_mem_dqinfo *oinfo =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
+	struct qown qown;
 
 	if (qtree_entry_unused(&oinfo->dqi_gi, dp))
 		return 0;
-	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+
+	qown = make_qown(&init_user_ns, dquot->dq_own.type, le32_to_cpu(d->dqb_id));
+	return qown_eq(qown, dquot->dq_own);
 }
 
 struct qtree_fmt_operations ocfs2_global_ops = {
@@ -475,7 +478,7 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
 {
 	int err, err2;
 	struct super_block *sb = dquot->dq_sb;
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
 	struct ocfs2_global_disk_dqblk dqblk;
 	s64 spacechange, inodechange;
@@ -504,7 +507,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
 	olditime = dquot->dq_dqb.dqb_itime;
 	oldbtime = dquot->dq_dqb.dqb_btime;
 	ocfs2_global_disk2memdqb(dquot, &dqblk);
-	trace_ocfs2_sync_dquot(dquot->dq_id, dquot->dq_dqb.dqb_curspace,
+	trace_ocfs2_sync_dquot(from_qown(&init_user_ns, dquot->dq_own),
+			       dquot->dq_dqb.dqb_curspace,
 			       (long long)spacechange,
 			       dquot->dq_dqb.dqb_curinodes,
 			       (long long)inodechange);
@@ -555,8 +559,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
 	err = ocfs2_qinfo_lock(info, freeing);
 	if (err < 0) {
 		mlog(ML_ERROR, "Failed to lock quota info, losing quota write"
-			       " (type=%d, id=%u)\n", dquot->dq_type,
-			       (unsigned)dquot->dq_id);
+			       " (type=%d, id=%u)\n", dquot->dq_own.type,
+			       (unsigned)from_qown(&init_user_ns, dquot->dq_own));
 		goto out;
 	}
 	if (freeing)
@@ -591,9 +595,10 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
 	struct ocfs2_super *osb = OCFS2_SB(sb);
 	int status = 0;
 
-	trace_ocfs2_sync_dquot_helper(dquot->dq_id, dquot->dq_type,
+	trace_ocfs2_sync_dquot_helper(from_qown(&init_user_ns, dquot->dq_own),
+				      dquot->dq_own.type,
 				      type, sb->s_id);
-	if (type != dquot->dq_type)
+	if (type != dquot->dq_own.type)
 		goto out;
 	status = ocfs2_lock_global_qf(oinfo, 1);
 	if (status < 0)
@@ -643,7 +648,8 @@ static int ocfs2_write_dquot(struct dquot *dquot)
 	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
 	int status = 0;
 
-	trace_ocfs2_write_dquot(dquot->dq_id, dquot->dq_type);
+	trace_ocfs2_write_dquot(from_qown(&init_user_ns, dquot->dq_own),
+				dquot->dq_own.type);
 
 	handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
 	if (IS_ERR(handle)) {
@@ -677,11 +683,12 @@ static int ocfs2_release_dquot(struct dquot *dquot)
 {
 	handle_t *handle;
 	struct ocfs2_mem_dqinfo *oinfo =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
 	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
 	int status = 0;
 
-	trace_ocfs2_release_dquot(dquot->dq_id, dquot->dq_type);
+	trace_ocfs2_release_dquot(from_qown(&init_user_ns, dquot->dq_own),
+				  dquot->dq_own.type);
 
 	mutex_lock(&dquot->dq_lock);
 	/* Check whether we are not racing with some other dqget() */
@@ -691,7 +698,7 @@ static int ocfs2_release_dquot(struct dquot *dquot)
 	if (status < 0)
 		goto out;
 	handle = ocfs2_start_trans(osb,
-		ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_type));
+		ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_own.type));
 	if (IS_ERR(handle)) {
 		status = PTR_ERR(handle);
 		mlog_errno(status);
@@ -733,13 +740,14 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
 	int ex = 0;
 	struct super_block *sb = dquot->dq_sb;
 	struct ocfs2_super *osb = OCFS2_SB(sb);
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
 	struct inode *gqinode = info->dqi_gqinode;
 	int need_alloc = ocfs2_global_qinit_alloc(sb, type);
 	handle_t *handle;
 
-	trace_ocfs2_acquire_dquot(dquot->dq_id, type);
+	trace_ocfs2_acquire_dquot(from_qown(&init_user_ns, dquot->dq_own),
+				  type);
 	mutex_lock(&dquot->dq_lock);
 	/*
 	 * We need an exclusive lock, because we're going to update use count
@@ -821,12 +829,13 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
 	int sync = 0;
 	int status;
 	struct super_block *sb = dquot->dq_sb;
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
 	handle_t *handle;
 	struct ocfs2_super *osb = OCFS2_SB(sb);
 
-	trace_ocfs2_mark_dquot_dirty(dquot->dq_id, type);
+	trace_ocfs2_mark_dquot_dirty(from_qown(&init_user_ns, dquot->dq_own),
+				     type);
 
 	/* In case user set some limits, sync dquot immediately to global
 	 * quota file so that information propagates quicker */
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
index f100bf7..3aec405 100644
--- a/fs/ocfs2/quota_local.c
+++ b/fs/ocfs2/quota_local.c
@@ -501,7 +501,9 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
 			}
 			dqblk = (struct ocfs2_local_disk_dqblk *)(qbh->b_data +
 				ol_dqblk_block_off(sb, chunk, bit));
-			dquot = dqget(sb, le64_to_cpu(dqblk->dqb_id), type);
+			dquot = dqget(sb,
+				      make_qown(&init_user_ns, type,
+						le64_to_cpu(dqblk->dqb_id)));
 			if (!dquot) {
 				status = -EIO;
 				mlog(ML_ERROR, "Failed to get quota structure "
@@ -881,7 +883,8 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
 	dqblk = (struct ocfs2_local_disk_dqblk *)(bh->b_data
 		+ ol_dqblk_block_offset(sb, od->dq_local_off));
 
-	dqblk->dqb_id = cpu_to_le64(od->dq_dquot.dq_id);
+	dqblk->dqb_id = cpu_to_le64(from_qown(&init_user_ns,
+					      od->dq_dquot.dq_own));
 	spin_lock(&dq_data_lock);
 	dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace -
 					  od->dq_origspace);
@@ -891,7 +894,7 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
 	trace_olq_set_dquot(
 		(unsigned long long)le64_to_cpu(dqblk->dqb_spacemod),
 		(unsigned long long)le64_to_cpu(dqblk->dqb_inodemod),
-		od->dq_dquot.dq_id);
+		from_qown(&init_user_ns, od->dq_dquot.dq_own));
 }
 
 /* Write dquot to local quota file */
@@ -900,7 +903,7 @@ int ocfs2_local_write_dquot(struct dquot *dquot)
 	struct super_block *sb = dquot->dq_sb;
 	struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
 	struct buffer_head *bh;
-	struct inode *lqinode = sb_dqopt(sb)->files[dquot->dq_type];
+	struct inode *lqinode = sb_dqopt(sb)->files[dquot->dq_own.type];
 	int status;
 
 	status = ocfs2_read_quota_phys_block(lqinode, od->dq_local_phys_blk,
@@ -1221,7 +1224,7 @@ static void olq_alloc_dquot(struct buffer_head *bh, void *private)
 int ocfs2_create_local_dquot(struct dquot *dquot)
 {
 	struct super_block *sb = dquot->dq_sb;
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct inode *lqinode = sb_dqopt(sb)->files[type];
 	struct ocfs2_quota_chunk *chunk;
 	struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
@@ -1275,7 +1278,7 @@ out:
 int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
 {
 	int status;
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
 	struct super_block *sb = dquot->dq_sb;
 	struct ocfs2_local_disk_chunk *dchunk;
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 36a29b7..766ab61 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -253,11 +253,13 @@ static qsize_t inode_get_rsv_space(struct inode *inode);
 static void __dquot_initialize(struct inode *inode, int type);
 
 static inline unsigned int
-hashfn(const struct super_block *sb, unsigned int id, int type)
+hashfn(const struct super_block *sb, struct qown qown)
 {
+	unsigned int id;
 	unsigned long tmp;
 
-	tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type);
+	id = from_qown(&init_user_ns, qown);
+	tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - qown.type);
 	return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask;
 }
 
@@ -267,7 +269,7 @@ hashfn(const struct super_block *sb, unsigned int id, int type)
 static inline void insert_dquot_hash(struct dquot *dquot)
 {
 	struct hlist_head *head;
-	head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type);
+	head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_own);
 	hlist_add_head(&dquot->dq_hash, head);
 }
 
@@ -277,15 +279,14 @@ static inline void remove_dquot_hash(struct dquot *dquot)
 }
 
 static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb,
-				unsigned int id, int type)
+				struct qown own)
 {
 	struct hlist_node *node;
 	struct dquot *dquot;
 
 	hlist_for_each (node, dquot_hash+hashent) {
 		dquot = hlist_entry(node, struct dquot, dq_hash);
-		if (dquot->dq_sb == sb && dquot->dq_id == id &&
-		    dquot->dq_type == type)
+		if (dquot->dq_sb == sb && qown_eq(dquot->dq_own, own))
 			return dquot;
 	}
 	return NULL;
@@ -351,7 +352,7 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)
 	spin_lock(&dq_list_lock);
 	if (!test_and_set_bit(DQ_MOD_B, &dquot->dq_flags)) {
 		list_add(&dquot->dq_dirty, &sb_dqopt(dquot->dq_sb)->
-				info[dquot->dq_type].dqi_dirty_list);
+				info[dquot->dq_own.type].dqi_dirty_list);
 		ret = 0;
 	}
 	spin_unlock(&dq_list_lock);
@@ -410,17 +411,17 @@ int dquot_acquire(struct dquot *dquot)
 	mutex_lock(&dquot->dq_lock);
 	mutex_lock(&dqopt->dqio_mutex);
 	if (!test_bit(DQ_READ_B, &dquot->dq_flags))
-		ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot);
+		ret = dqopt->ops[dquot->dq_own.type]->read_dqblk(dquot);
 	if (ret < 0)
 		goto out_iolock;
 	set_bit(DQ_READ_B, &dquot->dq_flags);
 	/* Instantiate dquot if needed */
 	if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) {
-		ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+		ret = dqopt->ops[dquot->dq_own.type]->commit_dqblk(dquot);
 		/* Write the info if needed */
-		if (info_dirty(&dqopt->info[dquot->dq_type])) {
-			ret2 = dqopt->ops[dquot->dq_type]->write_file_info(
-						dquot->dq_sb, dquot->dq_type);
+		if (info_dirty(&dqopt->info[dquot->dq_own.type])) {
+			ret2 = dqopt->ops[dquot->dq_own.type]->write_file_info(
+					dquot->dq_sb, dquot->dq_own.type);
 		}
 		if (ret < 0)
 			goto out_iolock;
@@ -455,7 +456,7 @@ int dquot_commit(struct dquot *dquot)
 	/* Inactive dquot can be only if there was error during read/init
 	 * => we have better not writing it */
 	if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
-		ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+		ret = dqopt->ops[dquot->dq_own.type]->commit_dqblk(dquot);
 	else
 		ret = -EIO;
 out_sem:
@@ -477,12 +478,12 @@ int dquot_release(struct dquot *dquot)
 	if (atomic_read(&dquot->dq_count) > 1)
 		goto out_dqlock;
 	mutex_lock(&dqopt->dqio_mutex);
-	if (dqopt->ops[dquot->dq_type]->release_dqblk) {
-		ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot);
+	if (dqopt->ops[dquot->dq_own.type]->release_dqblk) {
+		ret = dqopt->ops[dquot->dq_own.type]->release_dqblk(dquot);
 		/* Write the info */
-		if (info_dirty(&dqopt->info[dquot->dq_type])) {
-			ret2 = dqopt->ops[dquot->dq_type]->write_file_info(
-						dquot->dq_sb, dquot->dq_type);
+		if (info_dirty(&dqopt->info[dquot->dq_own.type])) {
+			ret2 = dqopt->ops[dquot->dq_own.type]->write_file_info(
+						dquot->dq_sb, dquot->dq_own.type);
 		}
 		if (ret >= 0)
 			ret = ret2;
@@ -521,7 +522,7 @@ restart:
 	list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
 		if (dquot->dq_sb != sb)
 			continue;
-		if (dquot->dq_type != type)
+		if (dquot->dq_own.type != type)
 			continue;
 		/* Wait for dquot users */
 		if (atomic_read(&dquot->dq_count)) {
@@ -741,7 +742,8 @@ void dqput(struct dquot *dquot)
 #ifdef CONFIG_QUOTA_DEBUG
 	if (!atomic_read(&dquot->dq_count)) {
 		quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
-			    quotatypes[dquot->dq_type], dquot->dq_id);
+			    quotatypes[dquot->dq_own.type],
+			    from_qown(&init_user_ns, dquot->dq_own));
 		BUG();
 	}
 #endif
@@ -752,7 +754,7 @@ we_slept:
 		/* We have more than one user... nothing to do */
 		atomic_dec(&dquot->dq_count);
 		/* Releasing dquot during quotaoff phase? */
-		if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_type) &&
+		if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_own.type) &&
 		    atomic_read(&dquot->dq_count) == 1)
 			wake_up(&dquot->dq_wait_unused);
 		spin_unlock(&dq_list_lock);
@@ -815,7 +817,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
 	INIT_LIST_HEAD(&dquot->dq_dirty);
 	init_waitqueue_head(&dquot->dq_wait_unused);
 	dquot->dq_sb = sb;
-	dquot->dq_type = type;
+	dquot->dq_own = make_qown_invalid(type);
 	atomic_set(&dquot->dq_count, 1);
 
 	return dquot;
@@ -829,35 +831,35 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
  *   a) checking for quota flags under dq_list_lock and
  *   b) getting a reference to dquot before we release dq_list_lock
  */
-struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
+struct dquot *dqget(struct super_block *sb, struct qown qown)
 {
-	unsigned int hashent = hashfn(sb, id, type);
+	unsigned int hashent = hashfn(sb, qown);
 	struct dquot *dquot = NULL, *empty = NULL;
 
-        if (!sb_has_quota_active(sb, type))
+        if (!sb_has_quota_active(sb, qown.type))
 		return NULL;
 we_slept:
 	spin_lock(&dq_list_lock);
 	spin_lock(&dq_state_lock);
-	if (!sb_has_quota_active(sb, type)) {
+	if (!sb_has_quota_active(sb, qown.type)) {
 		spin_unlock(&dq_state_lock);
 		spin_unlock(&dq_list_lock);
 		goto out;
 	}
 	spin_unlock(&dq_state_lock);
 
-	dquot = find_dquot(hashent, sb, id, type);
+	dquot = find_dquot(hashent, sb, qown);
 	if (!dquot) {
 		if (!empty) {
 			spin_unlock(&dq_list_lock);
-			empty = get_empty_dquot(sb, type);
+			empty = get_empty_dquot(sb, qown.type);
 			if (!empty)
 				schedule();	/* Try to wait for a moment... */
 			goto we_slept;
 		}
 		dquot = empty;
 		empty = NULL;
-		dquot->dq_id = id;
+		dquot->dq_own = qown;
 		/* all dquots go on the inuse_list */
 		put_inuse(dquot);
 		/* hash it first so it can be found */
@@ -1129,8 +1131,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
 
 struct dquot_warn {
 	struct super_block *w_sb;
-	qid_t w_dq_id;
-	short w_dq_type;
+	struct qown w_dq_own;
 	short w_type;
 };
 
@@ -1154,11 +1155,11 @@ static int need_print_warning(struct dquot_warn *warn)
 	if (!flag_print_warnings)
 		return 0;
 
-	switch (warn->w_dq_type) {
+	switch (warn->w_dq_own.type) {
 		case USRQUOTA:
-			return current_fsuid() == warn->w_dq_id;
+			return uid_eq(current_fsuid(), warn->w_dq_own.uid);
 		case GRPQUOTA:
-			return in_group_p(warn->w_dq_id);
+			return in_group_p(warn->w_dq_own.gid);
 	}
 	return 0;
 }
@@ -1184,7 +1185,7 @@ static void print_warning(struct dquot_warn *warn)
 		tty_write_message(tty, ": warning, ");
 	else
 		tty_write_message(tty, ": write failed, ");
-	tty_write_message(tty, quotatypes[warn->w_dq_type]);
+	tty_write_message(tty, quotatypes[warn->w_dq_own.type]);
 	switch (warntype) {
 		case QUOTA_NL_IHARDWARN:
 			msg = " file limit reached.\r\n";
@@ -1217,8 +1218,7 @@ static void prepare_warning(struct dquot_warn *warn, struct dquot *dquot,
 		return;
 	warn->w_type = warntype;
 	warn->w_sb = dquot->dq_sb;
-	warn->w_dq_id = dquot->dq_id;
-	warn->w_dq_type = dquot->dq_type;
+	warn->w_dq_own = dquot->dq_own;
 }
 
 /*
@@ -1236,14 +1236,14 @@ static void flush_warnings(struct dquot_warn *warn)
 #ifdef CONFIG_PRINT_QUOTA_WARNING
 		print_warning(&warn[i]);
 #endif
-		quota_send_warning(warn[i].w_dq_type, warn[i].w_dq_id,
+		quota_send_warning(warn[i].w_dq_own,
 				   warn[i].w_sb->s_dev, warn[i].w_type);
 	}
 }
 
 static int ignore_hardlimit(struct dquot *dquot)
 {
-	struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+	struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_own.type];
 
 	return capable(CAP_SYS_RESOURCE) &&
 	       (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD ||
@@ -1256,7 +1256,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
 {
 	qsize_t newinodes = dquot->dq_dqb.dqb_curinodes + inodes;
 
-	if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
+	if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_own.type) ||
 	    test_bit(DQ_FAKE_B, &dquot->dq_flags))
 		return 0;
 
@@ -1281,7 +1281,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
 	    dquot->dq_dqb.dqb_itime == 0) {
 		prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN);
 		dquot->dq_dqb.dqb_itime = get_seconds() +
-		    sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+		    sb_dqopt(dquot->dq_sb)->info[dquot->dq_own.type].dqi_igrace;
 	}
 
 	return 0;
@@ -1294,7 +1294,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
 	qsize_t tspace;
 	struct super_block *sb = dquot->dq_sb;
 
-	if (!sb_has_quota_limits_enabled(sb, dquot->dq_type) ||
+	if (!sb_has_quota_limits_enabled(sb, dquot->dq_own.type) ||
 	    test_bit(DQ_FAKE_B, &dquot->dq_flags))
 		return 0;
 
@@ -1325,7 +1325,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
 		if (!prealloc) {
 			prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN);
 			dquot->dq_dqb.dqb_btime = get_seconds() +
-			    sb_dqopt(sb)->info[dquot->dq_type].dqi_bgrace;
+			    sb_dqopt(sb)->info[dquot->dq_own.type].dqi_bgrace;
 		}
 		else
 			/*
@@ -1344,7 +1344,7 @@ static int info_idq_free(struct dquot *dquot, qsize_t inodes)
 
 	if (test_bit(DQ_FAKE_B, &dquot->dq_flags) ||
 	    dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit ||
-	    !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type))
+	    !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_own.type))
 		return QUOTA_NL_NOWARN;
 
 	newinodes = dquot->dq_dqb.dqb_curinodes - inodes;
@@ -1390,7 +1390,6 @@ static int dquot_active(const struct inode *inode)
  */
 static void __dquot_initialize(struct inode *inode, int type)
 {
-	unsigned int id = 0;
 	int cnt;
 	struct dquot *got[MAXQUOTAS];
 	struct super_block *sb = inode->i_sb;
@@ -1403,18 +1402,19 @@ static void __dquot_initialize(struct inode *inode, int type)
 
 	/* First get references to structures we might need. */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		struct qown qown;
 		got[cnt] = NULL;
 		if (type != -1 && cnt != type)
 			continue;
 		switch (cnt) {
 		case USRQUOTA:
-			id = inode->i_uid;
+			qown = make_qown_uid(inode->i_uid);
 			break;
 		case GRPQUOTA:
-			id = inode->i_gid;
+			qown = make_qown_gid(inode->i_gid);
 			break;
 		}
-		got[cnt] = dqget(sb, id, cnt);
+		got[cnt] = dqget(sb, qown);
 	}
 
 	down_write(&sb_dqopt(sb)->dqptr_sem);
@@ -1897,10 +1897,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
 	if (!dquot_active(inode))
 		return 0;
 
-	if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
-		transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA);
-	if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)
-		transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA);
+	if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
+		transfer_to[USRQUOTA] = dqget(sb, make_qown_uid(iattr->ia_uid));
+	if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
+		transfer_to[GRPQUOTA] = dqget(sb, make_qown_gid(iattr->ia_gid));
 
 	ret = __dquot_transfer(inode, transfer_to);
 	dqput_all(transfer_to);
@@ -2360,9 +2360,9 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 
 	memset(di, 0, sizeof(*di));
 	di->d_version = FS_DQUOT_VERSION;
-	di->d_flags = dquot->dq_type == USRQUOTA ?
+	di->d_flags = dquot->dq_own.type == USRQUOTA ?
 			FS_USER_QUOTA : FS_GROUP_QUOTA;
-	di->d_id = dquot->dq_id;
+	di->d_id = from_qown_munged(current_user_ns(), dquot->dq_own);
 
 	spin_lock(&dq_data_lock);
 	di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
@@ -2376,12 +2376,12 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 	spin_unlock(&dq_data_lock);
 }
 
-int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_get_dqblk(struct super_block *sb, struct qown qown,
 		    struct fs_disk_quota *di)
 {
 	struct dquot *dquot;
 
-	dquot = dqget(sb, id, type);
+	dquot = dqget(sb, qown);
 	if (!dquot)
 		return -ESRCH;
 	do_get_dqblk(dquot, di);
@@ -2401,7 +2401,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 {
 	struct mem_dqblk *dm = &dquot->dq_dqb;
 	int check_blim = 0, check_ilim = 0;
-	struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+	struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_own.type];
 
 	if (di->d_fieldmask & ~VFS_FS_DQ_MASK)
 		return -EINVAL;
@@ -2488,13 +2488,13 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 	return 0;
 }
 
-int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, struct qown qown,
 		  struct fs_disk_quota *di)
 {
 	struct dquot *dquot;
 	int rc;
 
-	dquot = dqget(sb, id, type);
+	dquot = dqget(sb, qown);
 	if (!dquot) {
 		rc = -ESRCH;
 		goto out;
diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
index d67908b..82e99d7 100644
--- a/fs/quota/netlink.c
+++ b/fs/quota/netlink.c
@@ -30,7 +30,7 @@ static struct genl_family quota_genl_family = {
  *
  */
 
-void quota_send_warning(short type, unsigned int id, dev_t dev,
+void quota_send_warning(struct qown qown, dev_t dev,
 			const char warntype)
 {
 	static atomic_t seq;
@@ -56,10 +56,11 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
 		  "VFS: Cannot store netlink header in quota warning.\n");
 		goto err_out;
 	}
-	ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type);
+	ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, qown.type);
 	if (ret)
 		goto attr_err_out;
-	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id);
+	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID,
+			  from_qown_munged(&init_user_ns, qown));
 	if (ret)
 		goto attr_err_out;
 	ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
@@ -71,7 +72,8 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
 	ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev));
 	if (ret)
 		goto attr_err_out;
-	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
+	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID,
+			  from_kuid_munged(&init_user_ns, current_uid()));
 	if (ret)
 		goto attr_err_out;
 	genlmsg_end(skb, msg_head);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 6f15578..a31dc42 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -32,8 +32,8 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
 	/* allow to query information for dquots we "own" */
 	case Q_GETQUOTA:
 	case Q_XGETQUOTA:
-		if ((type == USRQUOTA && current_euid() == id) ||
-		    (type == GRPQUOTA && in_egroup_p(id)))
+		if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
+		    (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
 			break;
 		/*FALLTHROUGH*/
 	default:
@@ -130,13 +130,17 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
 static int quota_getquota(struct super_block *sb, int type, qid_t id,
 			  void __user *addr)
 {
+	struct qown qown;
 	struct fs_disk_quota fdq;
 	struct if_dqblk idq;
 	int ret;
 
 	if (!sb->s_qcop->get_dqblk)
 		return -ENOSYS;
-	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
+	qown = make_qown(current_user_ns(), type, id);
+	if (!qown_valid(qown))
+		return -EINVAL;
+	ret = sb->s_qcop->get_dqblk(sb, qown, &fdq);
 	if (ret)
 		return ret;
 	copy_to_if_dqblk(&idq, &fdq);
@@ -176,13 +180,17 @@ static int quota_setquota(struct super_block *sb, int type, qid_t id,
 {
 	struct fs_disk_quota fdq;
 	struct if_dqblk idq;
+	struct qown qown;
 
 	if (copy_from_user(&idq, addr, sizeof(idq)))
 		return -EFAULT;
 	if (!sb->s_qcop->set_dqblk)
 		return -ENOSYS;
+	qown = make_qown(current_user_ns(), type, id);
+	if (!qown_valid(qown))
+		return -EINVAL;
 	copy_from_if_dqblk(&fdq, &idq);
-	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
+	return sb->s_qcop->set_dqblk(sb, qown, &fdq);
 }
 
 static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
@@ -213,23 +221,31 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id,
 			   void __user *addr)
 {
 	struct fs_disk_quota fdq;
+	struct qown qown;
 
 	if (copy_from_user(&fdq, addr, sizeof(fdq)))
 		return -EFAULT;
 	if (!sb->s_qcop->set_dqblk)
 		return -ENOSYS;
-	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
+	qown = make_qown(current_user_ns(), type, id);
+	if (!qown_valid(qown))
+		return -EINVAL;
+	return sb->s_qcop->set_dqblk(sb, qown, &fdq);
 }
 
 static int quota_getxquota(struct super_block *sb, int type, qid_t id,
 			   void __user *addr)
 {
 	struct fs_disk_quota fdq;
+	struct qown qown;
 	int ret;
 
 	if (!sb->s_qcop->get_dqblk)
 		return -ENOSYS;
-	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
+	qown = make_qown(current_user_ns(), type, id);
+	if (!qown_valid(qown))
+		return -EINVAL;
+	ret = sb->s_qcop->get_dqblk(sb, qown, &fdq);
 	if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
 		return -EFAULT;
 	return ret;
diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
index e41c1becf..fa48156 100644
--- a/fs/quota/quota_tree.c
+++ b/fs/quota/quota_tree.c
@@ -22,10 +22,12 @@ MODULE_LICENSE("GPL");
 
 #define __QUOTA_QT_PARANOIA
 
-static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
+static int get_index(struct qtree_mem_dqinfo *info, struct qown qown, int depth)
 {
 	unsigned int epb = info->dqi_usable_bs >> 2;
+	qid_t id;
 
+	id = from_qown(&init_user_ns, qown);
 	depth = info->dqi_qtree_depth - depth - 1;
 	while (depth--)
 		id /= epb;
@@ -244,7 +246,7 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
 		/* This is enough as the block is already zeroed and the entry
 		 * list is empty... */
 		info->dqi_free_entry = blk;
-		mark_info_dirty(dquot->dq_sb, dquot->dq_type);
+		mark_info_dirty(dquot->dq_sb, dquot->dq_own.type);
 	}
 	/* Block will be full? */
 	if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) {
@@ -313,7 +315,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 		}
 	}
 	ref = (__le32 *)buf;
-	newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+	newblk = le32_to_cpu(ref[get_index(info, dquot->dq_own, depth)]);
 	if (!newblk)
 		newson = 1;
 	if (depth == info->dqi_qtree_depth - 1) {
@@ -322,7 +324,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 			quota_error(dquot->dq_sb, "Inserting already present "
 				    "quota entry (block %u)",
 				    le32_to_cpu(ref[get_index(info,
-						dquot->dq_id, depth)]));
+						dquot->dq_own, depth)]));
 			ret = -EIO;
 			goto out_buf;
 		}
@@ -332,7 +334,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 		ret = do_insert_tree(info, dquot, &newblk, depth+1);
 	}
 	if (newson && ret >= 0) {
-		ref[get_index(info, dquot->dq_id, depth)] =
+		ref[get_index(info, dquot->dq_own, depth)] =
 							cpu_to_le32(newblk);
 		ret = write_blk(info, *treeblk, buf);
 	} else if (newact && ret < 0) {
@@ -357,7 +359,7 @@ static inline int dq_insert_tree(struct qtree_mem_dqinfo *info,
  */
 int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 {
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct super_block *sb = dquot->dq_sb;
 	ssize_t ret;
 	char *ddquot = getdqbuf(info->dqi_entry_size);
@@ -472,7 +474,7 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 			    *blk);
 		goto out_buf;
 	}
-	newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+	newblk = le32_to_cpu(ref[get_index(info, dquot->dq_own, depth)]);
 	if (depth == info->dqi_qtree_depth - 1) {
 		ret = free_dqentry(info, dquot, newblk);
 		newblk = 0;
@@ -481,7 +483,7 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
 	}
 	if (ret >= 0 && !newblk) {
 		int i;
-		ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0);
+		ref[get_index(info, dquot->dq_own, depth)] = cpu_to_le32(0);
 		/* Block got empty? */
 		for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++)
 			;
@@ -538,8 +540,9 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
 		ddquot += info->dqi_entry_size;
 	}
 	if (i == qtree_dqstr_in_blk(info)) {
-		quota_error(dquot->dq_sb, "Quota for id %u referenced "
-			    "but not present", dquot->dq_id);
+		quota_error(dquot->dq_sb,
+			    "Quota for id %u referenced but not present",
+			    from_qown(&init_user_ns, dquot->dq_own));
 		ret = -EIO;
 		goto out_buf;
 	} else {
@@ -568,7 +571,7 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
 		goto out_buf;
 	}
 	ret = 0;
-	blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+	blk = le32_to_cpu(ref[get_index(info, dquot->dq_own, depth)]);
 	if (!blk)	/* No reference? */
 		goto out_buf;
 	if (depth < info->dqi_qtree_depth - 1)
@@ -589,7 +592,7 @@ static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info,
 
 int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 {
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct super_block *sb = dquot->dq_sb;
 	loff_t offset;
 	char *ddquot;
@@ -607,8 +610,10 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 		offset = find_dqentry(info, dquot);
 		if (offset <= 0) {	/* Entry not present? */
 			if (offset < 0)
-				quota_error(sb, "Can't read quota structure "
-					    "for id %u", dquot->dq_id);
+				quota_error(sb,"Can't read quota structure "
+					    "for id %u",
+					    from_qown(&init_user_ns,
+						      dquot->dq_own));
 			dquot->dq_off = 0;
 			set_bit(DQ_FAKE_B, &dquot->dq_flags);
 			memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
@@ -626,7 +631,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 		if (ret >= 0)
 			ret = -EIO;
 		quota_error(sb, "Error while reading quota structure for id %u",
-			    dquot->dq_id);
+			    from_qown(&init_user_ns, dquot->dq_own));
 		set_bit(DQ_FAKE_B, &dquot->dq_flags);
 		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
 		kfree(ddquot);
diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c
index 34b37a6..ec37d70 100644
--- a/fs/quota/quota_v1.c
+++ b/fs/quota/quota_v1.c
@@ -54,7 +54,7 @@ static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m)
 
 static int v1_read_dqblk(struct dquot *dquot)
 {
-	int type = dquot->dq_type;
+	int type = dquot->dq_own.type;
 	struct v1_disk_dqblk dqblk;
 
 	if (!sb_dqopt(dquot->dq_sb)->files[type])
@@ -63,7 +63,8 @@ static int v1_read_dqblk(struct dquot *dquot)
 	/* Set structure to 0s in case read fails/is after end of file */
 	memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
 	dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk,
-			sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
+			sizeof(struct v1_disk_dqblk),
+			v1_dqoff(from_qown(&init_user_ns, dquot->dq_own)));
 
 	v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
 	if (dquot->dq_dqb.dqb_bhardlimit == 0 &&
@@ -78,12 +79,13 @@ static int v1_read_dqblk(struct dquot *dquot)
 
 static int v1_commit_dqblk(struct dquot *dquot)
 {
-	short type = dquot->dq_type;
+	short type = dquot->dq_own.type;
 	ssize_t ret;
 	struct v1_disk_dqblk dqblk;
 
 	v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
-	if (dquot->dq_id == 0) {
+	if (((type == USRQUOTA) && uid_eq(dquot->dq_own.uid, GLOBAL_ROOT_UID)) ||
+	    ((type == GRPQUOTA) && gid_eq(dquot->dq_own.gid, GLOBAL_ROOT_GID))) {
 		dqblk.dqb_btime =
 			sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
 		dqblk.dqb_itime =
@@ -93,7 +95,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
 	if (sb_dqopt(dquot->dq_sb)->files[type])
 		ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
 			(char *)&dqblk, sizeof(struct v1_disk_dqblk),
-			v1_dqoff(dquot->dq_id));
+			v1_dqoff(from_qown(&init_user_ns, dquot->dq_own)));
 	if (ret != sizeof(struct v1_disk_dqblk)) {
 		quota_error(dquot->dq_sb, "dquota write failed");
 		if (ret >= 0)
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
index f1ab360..1c26279 100644
--- a/fs/quota/quota_v2.c
+++ b/fs/quota/quota_v2.c
@@ -196,7 +196,7 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
 	struct v2r0_disk_dqblk *d = dp;
 	struct mem_dqblk *m = &dquot->dq_dqb;
 	struct qtree_mem_dqinfo *info =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
 
 	d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
 	d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
@@ -206,7 +206,7 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
 	d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
 	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
 	d->dqb_btime = cpu_to_le64(m->dqb_btime);
-	d->dqb_id = cpu_to_le32(dquot->dq_id);
+	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_own));
 	if (qtree_entry_unused(info, dp))
 		d->dqb_itime = cpu_to_le64(1);
 }
@@ -215,11 +215,13 @@ static int v2r0_is_id(void *dp, struct dquot *dquot)
 {
 	struct v2r0_disk_dqblk *d = dp;
 	struct qtree_mem_dqinfo *info =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
+	struct qown qown;
 
 	if (qtree_entry_unused(info, dp))
 		return 0;
-	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+	qown = make_qown(&init_user_ns, dquot->dq_own.type, le32_to_cpu(d->dqb_id));
+	return qown_eq(qown, dquot->dq_own);
 }
 
 static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
@@ -247,7 +249,7 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
 	struct v2r1_disk_dqblk *d = dp;
 	struct mem_dqblk *m = &dquot->dq_dqb;
 	struct qtree_mem_dqinfo *info =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
 
 	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
 	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
@@ -257,7 +259,7 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
 	d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
 	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
 	d->dqb_btime = cpu_to_le64(m->dqb_btime);
-	d->dqb_id = cpu_to_le32(dquot->dq_id);
+	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_own));
 	if (qtree_entry_unused(info, dp))
 		d->dqb_itime = cpu_to_le64(1);
 }
@@ -266,26 +268,28 @@ static int v2r1_is_id(void *dp, struct dquot *dquot)
 {
 	struct v2r1_disk_dqblk *d = dp;
 	struct qtree_mem_dqinfo *info =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv;
+	struct qown qown;
 
 	if (qtree_entry_unused(info, dp))
 		return 0;
-	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+	qown = make_qown(&init_user_ns, dquot->dq_own.type, le32_to_cpu(d->dqb_id));
+	return qown_eq(qown, dquot->dq_own);
 }
 
 static int v2_read_dquot(struct dquot *dquot)
 {
-	return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+	return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv, dquot);
 }
 
 static int v2_write_dquot(struct dquot *dquot)
 {
-	return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+	return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv, dquot);
 }
 
 static int v2_release_dquot(struct dquot *dquot)
 {
-	return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+	return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_own.type)->dqi_priv, dquot);
 }
 
 static int v2_free_file_info(struct super_block *sb, int type)
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index fed504f..589e9c7 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -97,28 +97,29 @@ xfs_fs_set_xstate(
 STATIC int
 xfs_fs_get_dqblk(
 	struct super_block	*sb,
-	int			type,
-	qid_t			id,
+	struct qown		qown,
 	struct fs_disk_quota	*fdq)
 {
 	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		xfs_id;
 
 	if (!XFS_IS_QUOTA_RUNNING(mp))
 		return -ENOSYS;
 	if (!XFS_IS_QUOTA_ON(mp))
 		return -ESRCH;
 
-	return -xfs_qm_scall_getquota(mp, id, xfs_quota_type(type), fdq);
+	xfs_id = from_qown(&init_user_ns, qown);
+	return -xfs_qm_scall_getquota(mp, xfs_id, xfs_quota_type(qown.type), fdq);
 }
 
 STATIC int
 xfs_fs_set_dqblk(
 	struct super_block	*sb,
-	int			type,
-	qid_t			id,
+	struct qown		qown,
 	struct fs_disk_quota	*fdq)
 {
 	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		xfs_id;
 
 	if (sb->s_flags & MS_RDONLY)
 		return -EROFS;
@@ -127,7 +128,8 @@ xfs_fs_set_dqblk(
 	if (!XFS_IS_QUOTA_ON(mp))
 		return -ESRCH;
 
-	return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq);
+	xfs_id = from_qown(&init_user_ns, qown);
+	return -xfs_qm_scall_setqlim(mp, xfs_id, xfs_quota_type(qown.type), fdq);
 }
 
 const struct quotactl_ops xfs_quotactl_operations = {
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index bcb6054..3e9fbb8 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -575,12 +575,14 @@ xfs_quota_warn(
 	struct xfs_dquot	*dqp,
 	int			type)
 {
+	int qtype;
+	struct qown qown;
 	/* no warnings for project quotas - we just return ENOSPC later */
 	if (dqp->dq_flags & XFS_DQ_PROJ)
 		return;
-	quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA,
-			   be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev,
-			   type);
+	qtype = (dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA;
+	qown = make_qown(&init_user_ns, qtype, be32_to_cpu(dqp->q_core.d_id));
+	quota_send_warning(qown, mp->m_super->s_dev, type);
 }
 
 /*
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 524ede8..6ebb782 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -181,10 +181,161 @@ enum {
 #include <linux/dqblk_v2.h>
 
 #include <linux/atomic.h>
+#include <linux/uidgid.h>
 
 typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
 typedef long long qsize_t;	/* Type in which we store sizes */
 
+struct qown {			/* Type in which we store the quota owner */
+	union {
+		kuid_t uid;
+		kgid_t gid;
+		unsigned int prj;
+	};
+	int type; /* USRQUOTA (uid) or GRPQUOTA (gid) or XQM_PRJQUOTA (prj) */
+};
+
+static inline bool qown_eq(struct qown left, struct qown right)
+{
+	if (left.type != right.type)
+		return false;
+	switch(left.type) {
+	case USRQUOTA:
+		return uid_eq(left.uid, right.uid);
+	case GRPQUOTA:
+		return gid_eq(left.gid, right.gid);
+	case XQM_PRJQUOTA:
+		return left.prj == right.prj;
+	default:
+		BUG();
+	}
+}
+
+static inline bool qown_lt(struct qown left, struct qown right)
+{
+	if (left.type < right.type)
+		return true;
+	if (left.type > right.type)
+		return false;
+	switch (left.type) {
+	case USRQUOTA:
+		return uid_lt(left.uid, right.uid);
+	case GRPQUOTA:
+		return gid_lt(left.gid, right.gid);
+	case XQM_PRJQUOTA:
+		return left.prj < right.prj;
+	default:
+		BUG();
+	}
+}
+
+static inline u32 from_qown(struct user_namespace *user_ns, struct qown qown)
+{
+	switch (qown.type) {
+	case USRQUOTA:
+		return from_kuid(user_ns, qown.uid);
+	case GRPQUOTA:
+		return from_kgid(user_ns, qown.gid);
+	case XQM_PRJQUOTA:
+		return (user_ns == &init_user_ns) ? qown.prj : -1;
+	default:
+		BUG();
+	}
+}
+
+static inline u32 from_qown_munged(struct user_namespace *user_ns,
+				   struct qown qown)
+{
+	switch (qown.type) {
+	case USRQUOTA:
+		return from_kuid_munged(user_ns, qown.uid);
+	case GRPQUOTA:
+		return from_kgid_munged(user_ns, qown.gid);
+	case XQM_PRJQUOTA:
+		return (user_ns == &init_user_ns) ? qown.prj : -1;
+	default:
+		BUG();
+	}
+}
+
+static inline struct qown make_qown(struct user_namespace *user_ns,
+				    int type, qid_t id)
+{
+	struct qown qown;
+
+	qown.type = type;
+	switch (type) {
+	case USRQUOTA:
+		qown.uid = make_kuid(user_ns, id);
+		break;
+	case GRPQUOTA:
+		qown.gid = make_kgid(user_ns, id);
+		break;
+	case XQM_PRJQUOTA:
+		if (user_ns == &init_user_ns)
+			qown.prj = id;
+		else
+			qown.prj = -1;
+		break;
+	default:
+		BUG();
+	}
+	return qown;
+}
+
+static inline struct qown make_qown_invalid(int type)
+{
+	struct qown qown;
+
+	qown.type = type;
+	switch (type) {
+	case USRQUOTA:
+		qown.uid = INVALID_UID;
+		break;
+	case GRPQUOTA:
+		qown.gid = INVALID_GID;
+		break;
+	case XQM_PRJQUOTA:
+		qown.prj = -1;
+		break;
+	default:
+		BUG();
+	}
+	return qown;
+}
+
+static inline struct qown make_qown_uid(kuid_t uid)
+{
+	struct qown qown = {
+		.type = USRQUOTA,
+		.uid  = uid,
+	};
+	return qown;
+}
+
+static inline struct qown make_qown_gid(kgid_t gid)
+{
+	struct qown qown = {
+		.type = GRPQUOTA,
+		.gid  = gid,
+	};
+	return qown;
+}
+
+static inline bool qown_valid(struct qown qown)
+{
+	switch (qown.type) {
+	case USRQUOTA:
+		return uid_valid(qown.uid);
+	case GRPQUOTA:
+		return gid_valid(qown.gid);
+	case XQM_PRJQUOTA:
+		return qown.prj != (unsigned int)-1;
+	default:
+		BUG();
+	}
+}
+
 extern spinlock_t dq_data_lock;
 
 /* Maximal numbers of writes for quota operation (insert/delete/update)
@@ -294,10 +445,9 @@ struct dquot {
 	atomic_t dq_count;		/* Use count */
 	wait_queue_head_t dq_wait_unused;	/* Wait queue for dquot to become unused */
 	struct super_block *dq_sb;	/* superblock this applies to */
-	unsigned int dq_id;		/* ID this applies to (uid, gid) */
+	struct qown dq_own;		/* ID this applies to (uid, gid) */
 	loff_t dq_off;			/* Offset of dquot on disk */
 	unsigned long dq_flags;		/* See DQ_* */
-	short dq_type;			/* Type of quota */
 	struct mem_dqblk dq_dqb;	/* Diskquota usage */
 };
 
@@ -336,8 +486,8 @@ struct quotactl_ops {
 	int (*quota_sync)(struct super_block *, int);
 	int (*get_info)(struct super_block *, int, struct if_dqinfo *);
 	int (*set_info)(struct super_block *, int, struct if_dqinfo *);
-	int (*get_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
-	int (*set_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
+	int (*get_dqblk)(struct super_block *, struct qown, struct fs_disk_quota *);
+	int (*set_dqblk)(struct super_block *, struct qown, struct fs_disk_quota *);
 	int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
 	int (*set_xstate)(struct super_block *, unsigned int, int);
 };
@@ -386,10 +536,10 @@ static inline unsigned int dquot_generic_flag(unsigned int flags, int type)
 }
 
 #ifdef CONFIG_QUOTA_NETLINK_INTERFACE
-extern void quota_send_warning(short type, unsigned int id, dev_t dev,
+extern void quota_send_warning(struct qown qown, dev_t dev,
 			       const char warntype);
 #else
-static inline void quota_send_warning(short type, unsigned int id, dev_t dev,
+static inline void quota_send_warning(struct qown qown, dev_t dev,
 				      const char warntype)
 {
 	return;
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index ec6b65f..ed9a5e4 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -44,7 +44,7 @@ void inode_sub_rsv_space(struct inode *inode, qsize_t number);
 
 void dquot_initialize(struct inode *inode);
 void dquot_drop(struct inode *inode);
-struct dquot *dqget(struct super_block *sb, unsigned int id, int type);
+struct dquot *dqget(struct super_block *sb, struct qown qown);
 void dqput(struct dquot *dquot);
 int dquot_scan_active(struct super_block *sb,
 		      int (*fn)(struct dquot *dquot, unsigned long priv),
@@ -87,9 +87,9 @@ int dquot_writeback_dquots(struct super_block *sb, int type);
 int dquot_quota_sync(struct super_block *sb, int type);
 int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
 int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
-int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_get_dqblk(struct super_block *sb, struct qown id,
 		struct fs_disk_quota *di);
-int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, struct qown id,
 		struct fs_disk_quota *di);
 
 int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
diff --git a/init/Kconfig b/init/Kconfig
index 2a388e5..a0bccce 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -928,8 +928,6 @@ config UIDGID_CONVERTED
 	depends on IMA = n
 	depends on EVM = n
 	depends on FS_POSIX_ACL = n
-	depends on QUOTA = n
-	depends on QUOTACTL = n
 
 	# Networking
 	depends on NET_9P = n
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH] userns: Add basic quota support v2
  2012-08-28 17:34         ` Eric W. Biederman
  2012-08-28 17:36           ` [PATCH] userns: Add basic quota support v3 Eric W. Biederman
@ 2012-08-28 17:51           ` Jan Kara
  2012-08-28 19:09             ` [PATCH] userns: Add basic quota support v4 Eric W. Biederman
  1 sibling, 1 reply; 37+ messages in thread
From: Jan Kara @ 2012-08-28 17:51 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Jan Kara, linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
	Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das

On Tue 28-08-12 10:34:04, Eric W. Biederman wrote:
> Jan Kara <jack@suse.cz> writes:
> >> +		return -EINVAL;
> >> +	ret = sb->s_qcop->get_dqblk(sb, qown, &fdq);
> >>  	if (ret)
> >>  		return ret;
> >>  	copy_to_if_dqblk(&idq, &fdq);
> > ...
> >> +static inline u32 from_qown(struct user_namespace *user_ns, struct qown qown)
> >> +{
> >> +	switch (qown.type) {
> >> +	case USRQUOTA:
> >> +		return from_kuid(user_ns, qown.uid);
> >> +	case GRPQUOTA:
> >> +		return from_kgid(user_ns, qown.gid);
> >> +	case XQM_PRJQUOTA:
> >> +		return (user_ns == &init_user_ns) ? qown.prj : -1;
> >> +	default:
> >> +		BUG();
> >> +	}
> >> +}
> >   I would like a bit more if the function somehow expressed in its name
> > that it returns id. id_from_qown() might be a bit too long given how often
> > it is used. qown2id() would be OK but it would be inconsistent with how
> > names of other functions you've added are formed. So I'm somewhat
> > undecided...
> 
> The qown vs id distinction bothers me a little bit.
> 
> I almost want to name it struct kid, and the functions make_kid,
> from_kid etc.  Where the emphasis is that we are transforming in and out
> of the kernel internal form.  I don't really like make_kid because id as
> a base name seems to generic and it barely tells you it is.  Perhaps
> make_kqid.  Where we call the quota ids and qid for short?
> 
> I am a little uncomfortable calling them kqids because the userspace
> code also places format_ids in a plain qid_t.  But make_kqid and
> from_kqid seems the best alternate set of names I can come up with.
  OK, these would seem reasonable to me.

								Honza
-- 
Jan Kara <jack@suse.cz>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH] userns: Add basic quota support v4
  2012-08-28 17:51           ` [PATCH] userns: Add basic quota support v2 Jan Kara
@ 2012-08-28 19:09             ` Eric W. Biederman
  2012-08-29  2:10               ` Dave Chinner
  0 siblings, 1 reply; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-28 19:09 UTC (permalink / raw)
  To: Jan Kara
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
	Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das


Add the data type struct kqid which holds the kernel internal form of
the owning identifier of a quota.  struct kqid is a replacement for
the implicit union of uid, gid and project stored in an unsigned int
and the quota type field that is was used in the quota data
structures.  Making the data type explicit allows the kuid_t and
kgid_t type safety to propogate more thoroughly through the code,
revealing more places where uid/gid conversions need be made.

Along with the data type struct kqid comes the helper functions
qid_eq, qid_lt, from_kqid, from_kqid_munged, qid_valid, make_kqid,
make_kqid_invalid, make_kqid_uid, make_kqid_gid.

Change struct dquot dq_id to a struct kqid and remove the now
unecessary dq_type.

Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
and dquot_set_dqblk to use struct kqid.

Make minimal changes to ext3, ext4, gfs2, ocfs2, and xfs to deal with
the change in quota structures and signatures.  The ocfs2 changes are
larger than most because of the extensive tracing throughout the ocfs2
quota code that prints out dq_id.

v4:
  - Rename struct qown struct kqid and associated changes
    to the naming of the helper functions.
  - Use qid_t to hold the userspace identifier representation
    of quota identifiers in all new code.
v3:
  - Add missing negation on qown_valid
v2:
  - Renamed qown_t struct qown
  - Added the quota type to struct qown.
  - Removed enum quota_type (In this patch it was just noise)
  - Added qown_lt, make_qown_invalid, make_qown_uid, make_qown_gid
  - Taught qown to handle xfs project ids (but only in init_user_ns).
    Q_XGETQUOTA calls .get_quotblk with project ids.

Cc: Steven Whitehouse <swhiteho@redhat.com>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Ben Myers <bpm@sgi.com>
Cc: Alex Elder <elder@kernel.org>
Cc: Jan Kara <jack@suse.cz>
Cc: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 fs/ext3/super.c          |    2 +-
 fs/ext4/super.c          |    2 +-
 fs/gfs2/quota.c          |   52 +++++++++------
 fs/ocfs2/file.c          |    6 +-
 fs/ocfs2/quota_global.c  |   43 +++++++-----
 fs/ocfs2/quota_local.c   |   15 +++--
 fs/quota/dquot.c         |  116 ++++++++++++++++----------------
 fs/quota/netlink.c       |   10 ++-
 fs/quota/quota.c         |   28 ++++++--
 fs/quota/quota_tree.c    |   23 ++++---
 fs/quota/quota_v1.c      |   12 ++--
 fs/quota/quota_v2.c      |   26 ++++---
 fs/xfs/xfs_quotaops.c    |   14 ++--
 fs/xfs/xfs_trans_dquot.c |    8 ++-
 include/linux/quota.h    |  162 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/quotaops.h |    6 +-
 init/Kconfig             |    2 -
 17 files changed, 364 insertions(+), 163 deletions(-)

diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index ff9bcdc..73e42f5 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -2814,7 +2814,7 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
 
 static inline struct inode *dquot_to_inode(struct dquot *dquot)
 {
-	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type];
 }
 
 static int ext3_write_dquot(struct dquot *dquot)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index d76ec82..78e6036 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -4796,7 +4796,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
 
 static inline struct inode *dquot_to_inode(struct dquot *dquot)
 {
-	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type];
 }
 
 static int ext4_write_dquot(struct dquot *dquot)
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index a3bde91..e27f8d6 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -1057,6 +1057,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
                 return 0;
 
 	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
+		int qtype;
+		struct kqid qid;
 		qd = ip->i_res->rs_qa_qd[x];
 
 		if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
@@ -1068,11 +1070,12 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
 		value += qd->qd_change;
 		spin_unlock(&qd_lru_lock);
 
+		qtype = test_bit(QDF_USER, &qd->qd_flags) ? USRQUOTA : GRPQUOTA;
+		qid = make_kqid(&init_user_ns, qtype, qd->qd_id);
 		if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
 			print_message(qd, "exceeded");
-			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
-					   USRQUOTA : GRPQUOTA, qd->qd_id,
-					   sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);
+			quota_send_warning(qid, sdp->sd_vfs->s_dev,
+					   QUOTA_NL_BHARDWARN);
 
 			error = -EDQUOT;
 			break;
@@ -1081,9 +1084,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
 			   time_after_eq(jiffies, qd->qd_last_warn +
 					 gfs2_tune_get(sdp,
 						gt_quota_warn_period) * HZ)) {
-			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
-					   USRQUOTA : GRPQUOTA, qd->qd_id,
-					   sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN);
+			quota_send_warning(qid, sdp->sd_vfs->s_dev,
+					   QUOTA_NL_BSOFTWARN);
 			error = print_message(qd, "warning");
 			qd->qd_last_warn = jiffies;
 		}
@@ -1469,7 +1471,7 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
 	return 0;
 }
 
-static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
+static int gfs2_get_dqblk(struct super_block *sb, struct kqid qid,
 			  struct fs_disk_quota *fdq)
 {
 	struct gfs2_sbd *sdp = sb->s_fs_info;
@@ -1477,20 +1479,24 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
 	struct gfs2_quota_data *qd;
 	struct gfs2_holder q_gh;
 	int error;
+	int user;
+	u32 gfs_id;
 
 	memset(fdq, 0, sizeof(struct fs_disk_quota));
 
 	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
 		return -ESRCH; /* Crazy XFS error code */
 
-	if (type == USRQUOTA)
-		type = QUOTA_USER;
-	else if (type == GRPQUOTA)
-		type = QUOTA_GROUP;
+	gfs_id = from_kqid(&init_user_ns, qid);
+
+	if (qid.type == USRQUOTA)
+		user = QUOTA_USER;
+	else if (qid.type == GRPQUOTA)
+		user = QUOTA_GROUP;
 	else
 		return -EINVAL;
 
-	error = qd_get(sdp, type, id, &qd);
+	error = qd_get(sdp, user, gfs_id, &qd);
 	if (error)
 		return error;
 	error = do_glock(qd, FORCE, &q_gh);
@@ -1499,8 +1505,8 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
 
 	qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
 	fdq->d_version = FS_DQUOT_VERSION;
-	fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
-	fdq->d_id = id;
+	fdq->d_flags = (user == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
+	fdq->d_id = gfs_id;
 	fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;
 	fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;
 	fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift;
@@ -1514,8 +1520,8 @@ out:
 /* GFS2 only supports a subset of the XFS fields */
 #define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT)
 
-static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
-			  struct fs_disk_quota *fdq)
+static int gfs2_set_dqblk(struct super_block *sb,
+			  struct kqid qid, struct fs_disk_quota *fdq)
 {
 	struct gfs2_sbd *sdp = sb->s_fs_info;
 	struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
@@ -1526,18 +1532,22 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
 	int alloc_required;
 	loff_t offset;
 	int error;
+	int user;
+	u32 gfs_id;
 
 	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
 		return -ESRCH; /* Crazy XFS error code */
 
-	switch(type) {
+	gfs_id = from_kqid(&init_user_ns, qid);
+
+	switch(qid.type) {
 	case USRQUOTA:
-		type = QUOTA_USER;
+		user = QUOTA_USER;
 		if (fdq->d_flags != FS_USER_QUOTA)
 			return -EINVAL;
 		break;
 	case GRPQUOTA:
-		type = QUOTA_GROUP;
+		user = QUOTA_GROUP;
 		if (fdq->d_flags != FS_GROUP_QUOTA)
 			return -EINVAL;
 		break;
@@ -1547,10 +1557,10 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
 
 	if (fdq->d_fieldmask & ~GFS2_FIELDMASK)
 		return -EINVAL;
-	if (fdq->d_id != id)
+	if (fdq->d_id != gfs_id)
 		return -EINVAL;
 
-	error = qd_get(sdp, type, id, &qd);
+	error = qd_get(sdp, user, gfs_id, &qd);
 	if (error)
 		return error;
 
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 46a1f6d..5a4ee77 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1184,8 +1184,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 		if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
 		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
 		    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
-			transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
-						      USRQUOTA);
+			transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(attr->ia_uid));
 			if (!transfer_to[USRQUOTA]) {
 				status = -ESRCH;
 				goto bail_unlock;
@@ -1194,8 +1193,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 		if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid
 		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
 		    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
-			transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
-						      GRPQUOTA);
+			transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(attr->ia_gid));
 			if (!transfer_to[GRPQUOTA]) {
 				status = -ESRCH;
 				goto bail_unlock;
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
index 0a86e30..dd4deaa 100644
--- a/fs/ocfs2/quota_global.c
+++ b/fs/ocfs2/quota_global.c
@@ -95,7 +95,7 @@ static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
 	struct ocfs2_global_disk_dqblk *d = dp;
 	struct mem_dqblk *m = &dquot->dq_dqb;
 
-	d->dqb_id = cpu_to_le32(dquot->dq_id);
+	d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
 	d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
 	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
 	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
@@ -112,11 +112,14 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
 {
 	struct ocfs2_global_disk_dqblk *d = dp;
 	struct ocfs2_mem_dqinfo *oinfo =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
+	struct kqid qid;
 
 	if (qtree_entry_unused(&oinfo->dqi_gi, dp))
 		return 0;
-	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+
+	qid = make_kqid(&init_user_ns, dquot->dq_id.type, le32_to_cpu(d->dqb_id));
+	return qid_eq(qid, dquot->dq_id);
 }
 
 struct qtree_fmt_operations ocfs2_global_ops = {
@@ -475,7 +478,7 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
 {
 	int err, err2;
 	struct super_block *sb = dquot->dq_sb;
-	int type = dquot->dq_type;
+	int type = dquot->dq_id.type;
 	struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
 	struct ocfs2_global_disk_dqblk dqblk;
 	s64 spacechange, inodechange;
@@ -504,7 +507,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
 	olditime = dquot->dq_dqb.dqb_itime;
 	oldbtime = dquot->dq_dqb.dqb_btime;
 	ocfs2_global_disk2memdqb(dquot, &dqblk);
-	trace_ocfs2_sync_dquot(dquot->dq_id, dquot->dq_dqb.dqb_curspace,
+	trace_ocfs2_sync_dquot(from_kqid(&init_user_ns, dquot->dq_id),
+			       dquot->dq_dqb.dqb_curspace,
 			       (long long)spacechange,
 			       dquot->dq_dqb.dqb_curinodes,
 			       (long long)inodechange);
@@ -555,8 +559,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
 	err = ocfs2_qinfo_lock(info, freeing);
 	if (err < 0) {
 		mlog(ML_ERROR, "Failed to lock quota info, losing quota write"
-			       " (type=%d, id=%u)\n", dquot->dq_type,
-			       (unsigned)dquot->dq_id);
+			       " (type=%d, id=%u)\n", dquot->dq_id.type,
+			       (unsigned)from_kqid(&init_user_ns, dquot->dq_id));
 		goto out;
 	}
 	if (freeing)
@@ -591,9 +595,10 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
 	struct ocfs2_super *osb = OCFS2_SB(sb);
 	int status = 0;
 
-	trace_ocfs2_sync_dquot_helper(dquot->dq_id, dquot->dq_type,
+	trace_ocfs2_sync_dquot_helper(from_kqid(&init_user_ns, dquot->dq_id),
+				      dquot->dq_id.type,
 				      type, sb->s_id);
-	if (type != dquot->dq_type)
+	if (type != dquot->dq_id.type)
 		goto out;
 	status = ocfs2_lock_global_qf(oinfo, 1);
 	if (status < 0)
@@ -643,7 +648,8 @@ static int ocfs2_write_dquot(struct dquot *dquot)
 	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
 	int status = 0;
 
-	trace_ocfs2_write_dquot(dquot->dq_id, dquot->dq_type);
+	trace_ocfs2_write_dquot(from_kqid(&init_user_ns, dquot->dq_id),
+				dquot->dq_id.type);
 
 	handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
 	if (IS_ERR(handle)) {
@@ -677,11 +683,12 @@ static int ocfs2_release_dquot(struct dquot *dquot)
 {
 	handle_t *handle;
 	struct ocfs2_mem_dqinfo *oinfo =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
 	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
 	int status = 0;
 
-	trace_ocfs2_release_dquot(dquot->dq_id, dquot->dq_type);
+	trace_ocfs2_release_dquot(from_kqid(&init_user_ns, dquot->dq_id),
+				  dquot->dq_id.type);
 
 	mutex_lock(&dquot->dq_lock);
 	/* Check whether we are not racing with some other dqget() */
@@ -691,7 +698,7 @@ static int ocfs2_release_dquot(struct dquot *dquot)
 	if (status < 0)
 		goto out;
 	handle = ocfs2_start_trans(osb,
-		ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_type));
+		ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_id.type));
 	if (IS_ERR(handle)) {
 		status = PTR_ERR(handle);
 		mlog_errno(status);
@@ -733,13 +740,14 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
 	int ex = 0;
 	struct super_block *sb = dquot->dq_sb;
 	struct ocfs2_super *osb = OCFS2_SB(sb);
-	int type = dquot->dq_type;
+	int type = dquot->dq_id.type;
 	struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
 	struct inode *gqinode = info->dqi_gqinode;
 	int need_alloc = ocfs2_global_qinit_alloc(sb, type);
 	handle_t *handle;
 
-	trace_ocfs2_acquire_dquot(dquot->dq_id, type);
+	trace_ocfs2_acquire_dquot(from_kqid(&init_user_ns, dquot->dq_id),
+				  type);
 	mutex_lock(&dquot->dq_lock);
 	/*
 	 * We need an exclusive lock, because we're going to update use count
@@ -821,12 +829,13 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
 	int sync = 0;
 	int status;
 	struct super_block *sb = dquot->dq_sb;
-	int type = dquot->dq_type;
+	int type = dquot->dq_id.type;
 	struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
 	handle_t *handle;
 	struct ocfs2_super *osb = OCFS2_SB(sb);
 
-	trace_ocfs2_mark_dquot_dirty(dquot->dq_id, type);
+	trace_ocfs2_mark_dquot_dirty(from_kqid(&init_user_ns, dquot->dq_id),
+				     type);
 
 	/* In case user set some limits, sync dquot immediately to global
 	 * quota file so that information propagates quicker */
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
index f100bf7..27fe7ee 100644
--- a/fs/ocfs2/quota_local.c
+++ b/fs/ocfs2/quota_local.c
@@ -501,7 +501,9 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
 			}
 			dqblk = (struct ocfs2_local_disk_dqblk *)(qbh->b_data +
 				ol_dqblk_block_off(sb, chunk, bit));
-			dquot = dqget(sb, le64_to_cpu(dqblk->dqb_id), type);
+			dquot = dqget(sb,
+				      make_kqid(&init_user_ns, type,
+						le64_to_cpu(dqblk->dqb_id)));
 			if (!dquot) {
 				status = -EIO;
 				mlog(ML_ERROR, "Failed to get quota structure "
@@ -881,7 +883,8 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
 	dqblk = (struct ocfs2_local_disk_dqblk *)(bh->b_data
 		+ ol_dqblk_block_offset(sb, od->dq_local_off));
 
-	dqblk->dqb_id = cpu_to_le64(od->dq_dquot.dq_id);
+	dqblk->dqb_id = cpu_to_le64(from_kqid(&init_user_ns,
+					      od->dq_dquot.dq_id));
 	spin_lock(&dq_data_lock);
 	dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace -
 					  od->dq_origspace);
@@ -891,7 +894,7 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
 	trace_olq_set_dquot(
 		(unsigned long long)le64_to_cpu(dqblk->dqb_spacemod),
 		(unsigned long long)le64_to_cpu(dqblk->dqb_inodemod),
-		od->dq_dquot.dq_id);
+		from_kqid(&init_user_ns, od->dq_dquot.dq_id));
 }
 
 /* Write dquot to local quota file */
@@ -900,7 +903,7 @@ int ocfs2_local_write_dquot(struct dquot *dquot)
 	struct super_block *sb = dquot->dq_sb;
 	struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
 	struct buffer_head *bh;
-	struct inode *lqinode = sb_dqopt(sb)->files[dquot->dq_type];
+	struct inode *lqinode = sb_dqopt(sb)->files[dquot->dq_id.type];
 	int status;
 
 	status = ocfs2_read_quota_phys_block(lqinode, od->dq_local_phys_blk,
@@ -1221,7 +1224,7 @@ static void olq_alloc_dquot(struct buffer_head *bh, void *private)
 int ocfs2_create_local_dquot(struct dquot *dquot)
 {
 	struct super_block *sb = dquot->dq_sb;
-	int type = dquot->dq_type;
+	int type = dquot->dq_id.type;
 	struct inode *lqinode = sb_dqopt(sb)->files[type];
 	struct ocfs2_quota_chunk *chunk;
 	struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
@@ -1275,7 +1278,7 @@ out:
 int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
 {
 	int status;
-	int type = dquot->dq_type;
+	int type = dquot->dq_id.type;
 	struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
 	struct super_block *sb = dquot->dq_sb;
 	struct ocfs2_local_disk_chunk *dchunk;
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 36a29b7..f52625c 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -253,11 +253,13 @@ static qsize_t inode_get_rsv_space(struct inode *inode);
 static void __dquot_initialize(struct inode *inode, int type);
 
 static inline unsigned int
-hashfn(const struct super_block *sb, unsigned int id, int type)
+hashfn(const struct super_block *sb, struct kqid qid)
 {
+	unsigned int id;
 	unsigned long tmp;
 
-	tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type);
+	id = from_kqid(&init_user_ns, qid);
+	tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - qid.type);
 	return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask;
 }
 
@@ -267,7 +269,7 @@ hashfn(const struct super_block *sb, unsigned int id, int type)
 static inline void insert_dquot_hash(struct dquot *dquot)
 {
 	struct hlist_head *head;
-	head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type);
+	head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id);
 	hlist_add_head(&dquot->dq_hash, head);
 }
 
@@ -277,15 +279,14 @@ static inline void remove_dquot_hash(struct dquot *dquot)
 }
 
 static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb,
-				unsigned int id, int type)
+				struct kqid qid)
 {
 	struct hlist_node *node;
 	struct dquot *dquot;
 
 	hlist_for_each (node, dquot_hash+hashent) {
 		dquot = hlist_entry(node, struct dquot, dq_hash);
-		if (dquot->dq_sb == sb && dquot->dq_id == id &&
-		    dquot->dq_type == type)
+		if (dquot->dq_sb == sb && qid_eq(dquot->dq_id, qid))
 			return dquot;
 	}
 	return NULL;
@@ -351,7 +352,7 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)
 	spin_lock(&dq_list_lock);
 	if (!test_and_set_bit(DQ_MOD_B, &dquot->dq_flags)) {
 		list_add(&dquot->dq_dirty, &sb_dqopt(dquot->dq_sb)->
-				info[dquot->dq_type].dqi_dirty_list);
+				info[dquot->dq_id.type].dqi_dirty_list);
 		ret = 0;
 	}
 	spin_unlock(&dq_list_lock);
@@ -410,17 +411,17 @@ int dquot_acquire(struct dquot *dquot)
 	mutex_lock(&dquot->dq_lock);
 	mutex_lock(&dqopt->dqio_mutex);
 	if (!test_bit(DQ_READ_B, &dquot->dq_flags))
-		ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot);
+		ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot);
 	if (ret < 0)
 		goto out_iolock;
 	set_bit(DQ_READ_B, &dquot->dq_flags);
 	/* Instantiate dquot if needed */
 	if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) {
-		ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+		ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot);
 		/* Write the info if needed */
-		if (info_dirty(&dqopt->info[dquot->dq_type])) {
-			ret2 = dqopt->ops[dquot->dq_type]->write_file_info(
-						dquot->dq_sb, dquot->dq_type);
+		if (info_dirty(&dqopt->info[dquot->dq_id.type])) {
+			ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info(
+					dquot->dq_sb, dquot->dq_id.type);
 		}
 		if (ret < 0)
 			goto out_iolock;
@@ -455,7 +456,7 @@ int dquot_commit(struct dquot *dquot)
 	/* Inactive dquot can be only if there was error during read/init
 	 * => we have better not writing it */
 	if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
-		ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+		ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot);
 	else
 		ret = -EIO;
 out_sem:
@@ -477,12 +478,12 @@ int dquot_release(struct dquot *dquot)
 	if (atomic_read(&dquot->dq_count) > 1)
 		goto out_dqlock;
 	mutex_lock(&dqopt->dqio_mutex);
-	if (dqopt->ops[dquot->dq_type]->release_dqblk) {
-		ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot);
+	if (dqopt->ops[dquot->dq_id.type]->release_dqblk) {
+		ret = dqopt->ops[dquot->dq_id.type]->release_dqblk(dquot);
 		/* Write the info */
-		if (info_dirty(&dqopt->info[dquot->dq_type])) {
-			ret2 = dqopt->ops[dquot->dq_type]->write_file_info(
-						dquot->dq_sb, dquot->dq_type);
+		if (info_dirty(&dqopt->info[dquot->dq_id.type])) {
+			ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info(
+						dquot->dq_sb, dquot->dq_id.type);
 		}
 		if (ret >= 0)
 			ret = ret2;
@@ -521,7 +522,7 @@ restart:
 	list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
 		if (dquot->dq_sb != sb)
 			continue;
-		if (dquot->dq_type != type)
+		if (dquot->dq_id.type != type)
 			continue;
 		/* Wait for dquot users */
 		if (atomic_read(&dquot->dq_count)) {
@@ -741,7 +742,8 @@ void dqput(struct dquot *dquot)
 #ifdef CONFIG_QUOTA_DEBUG
 	if (!atomic_read(&dquot->dq_count)) {
 		quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
-			    quotatypes[dquot->dq_type], dquot->dq_id);
+			    quotatypes[dquot->dq_id.type],
+			    from_kqid(&init_user_ns, dquot->dq_id));
 		BUG();
 	}
 #endif
@@ -752,7 +754,7 @@ we_slept:
 		/* We have more than one user... nothing to do */
 		atomic_dec(&dquot->dq_count);
 		/* Releasing dquot during quotaoff phase? */
-		if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_type) &&
+		if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_id.type) &&
 		    atomic_read(&dquot->dq_count) == 1)
 			wake_up(&dquot->dq_wait_unused);
 		spin_unlock(&dq_list_lock);
@@ -815,7 +817,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
 	INIT_LIST_HEAD(&dquot->dq_dirty);
 	init_waitqueue_head(&dquot->dq_wait_unused);
 	dquot->dq_sb = sb;
-	dquot->dq_type = type;
+	dquot->dq_id = make_kqid_invalid(type);
 	atomic_set(&dquot->dq_count, 1);
 
 	return dquot;
@@ -829,35 +831,35 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
  *   a) checking for quota flags under dq_list_lock and
  *   b) getting a reference to dquot before we release dq_list_lock
  */
-struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
+struct dquot *dqget(struct super_block *sb, struct kqid qid)
 {
-	unsigned int hashent = hashfn(sb, id, type);
+	unsigned int hashent = hashfn(sb, qid);
 	struct dquot *dquot = NULL, *empty = NULL;
 
-        if (!sb_has_quota_active(sb, type))
+        if (!sb_has_quota_active(sb, qid.type))
 		return NULL;
 we_slept:
 	spin_lock(&dq_list_lock);
 	spin_lock(&dq_state_lock);
-	if (!sb_has_quota_active(sb, type)) {
+	if (!sb_has_quota_active(sb, qid.type)) {
 		spin_unlock(&dq_state_lock);
 		spin_unlock(&dq_list_lock);
 		goto out;
 	}
 	spin_unlock(&dq_state_lock);
 
-	dquot = find_dquot(hashent, sb, id, type);
+	dquot = find_dquot(hashent, sb, qid);
 	if (!dquot) {
 		if (!empty) {
 			spin_unlock(&dq_list_lock);
-			empty = get_empty_dquot(sb, type);
+			empty = get_empty_dquot(sb, qid.type);
 			if (!empty)
 				schedule();	/* Try to wait for a moment... */
 			goto we_slept;
 		}
 		dquot = empty;
 		empty = NULL;
-		dquot->dq_id = id;
+		dquot->dq_id = qid;
 		/* all dquots go on the inuse_list */
 		put_inuse(dquot);
 		/* hash it first so it can be found */
@@ -1129,8 +1131,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
 
 struct dquot_warn {
 	struct super_block *w_sb;
-	qid_t w_dq_id;
-	short w_dq_type;
+	struct kqid w_dq_id;
 	short w_type;
 };
 
@@ -1154,11 +1155,11 @@ static int need_print_warning(struct dquot_warn *warn)
 	if (!flag_print_warnings)
 		return 0;
 
-	switch (warn->w_dq_type) {
+	switch (warn->w_dq_id.type) {
 		case USRQUOTA:
-			return current_fsuid() == warn->w_dq_id;
+			return uid_eq(current_fsuid(), warn->w_dq_id.uid);
 		case GRPQUOTA:
-			return in_group_p(warn->w_dq_id);
+			return in_group_p(warn->w_dq_id.gid);
 	}
 	return 0;
 }
@@ -1184,7 +1185,7 @@ static void print_warning(struct dquot_warn *warn)
 		tty_write_message(tty, ": warning, ");
 	else
 		tty_write_message(tty, ": write failed, ");
-	tty_write_message(tty, quotatypes[warn->w_dq_type]);
+	tty_write_message(tty, quotatypes[warn->w_dq_id.type]);
 	switch (warntype) {
 		case QUOTA_NL_IHARDWARN:
 			msg = " file limit reached.\r\n";
@@ -1218,7 +1219,6 @@ static void prepare_warning(struct dquot_warn *warn, struct dquot *dquot,
 	warn->w_type = warntype;
 	warn->w_sb = dquot->dq_sb;
 	warn->w_dq_id = dquot->dq_id;
-	warn->w_dq_type = dquot->dq_type;
 }
 
 /*
@@ -1236,14 +1236,14 @@ static void flush_warnings(struct dquot_warn *warn)
 #ifdef CONFIG_PRINT_QUOTA_WARNING
 		print_warning(&warn[i]);
 #endif
-		quota_send_warning(warn[i].w_dq_type, warn[i].w_dq_id,
+		quota_send_warning(warn[i].w_dq_id,
 				   warn[i].w_sb->s_dev, warn[i].w_type);
 	}
 }
 
 static int ignore_hardlimit(struct dquot *dquot)
 {
-	struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+	struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type];
 
 	return capable(CAP_SYS_RESOURCE) &&
 	       (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD ||
@@ -1256,7 +1256,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
 {
 	qsize_t newinodes = dquot->dq_dqb.dqb_curinodes + inodes;
 
-	if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
+	if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_id.type) ||
 	    test_bit(DQ_FAKE_B, &dquot->dq_flags))
 		return 0;
 
@@ -1281,7 +1281,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes,
 	    dquot->dq_dqb.dqb_itime == 0) {
 		prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN);
 		dquot->dq_dqb.dqb_itime = get_seconds() +
-		    sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+		    sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type].dqi_igrace;
 	}
 
 	return 0;
@@ -1294,7 +1294,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
 	qsize_t tspace;
 	struct super_block *sb = dquot->dq_sb;
 
-	if (!sb_has_quota_limits_enabled(sb, dquot->dq_type) ||
+	if (!sb_has_quota_limits_enabled(sb, dquot->dq_id.type) ||
 	    test_bit(DQ_FAKE_B, &dquot->dq_flags))
 		return 0;
 
@@ -1325,7 +1325,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
 		if (!prealloc) {
 			prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN);
 			dquot->dq_dqb.dqb_btime = get_seconds() +
-			    sb_dqopt(sb)->info[dquot->dq_type].dqi_bgrace;
+			    sb_dqopt(sb)->info[dquot->dq_id.type].dqi_bgrace;
 		}
 		else
 			/*
@@ -1344,7 +1344,7 @@ static int info_idq_free(struct dquot *dquot, qsize_t inodes)
 
 	if (test_bit(DQ_FAKE_B, &dquot->dq_flags) ||
 	    dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit ||
-	    !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type))
+	    !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_id.type))
 		return QUOTA_NL_NOWARN;
 
 	newinodes = dquot->dq_dqb.dqb_curinodes - inodes;
@@ -1390,7 +1390,6 @@ static int dquot_active(const struct inode *inode)
  */
 static void __dquot_initialize(struct inode *inode, int type)
 {
-	unsigned int id = 0;
 	int cnt;
 	struct dquot *got[MAXQUOTAS];
 	struct super_block *sb = inode->i_sb;
@@ -1403,18 +1402,19 @@ static void __dquot_initialize(struct inode *inode, int type)
 
 	/* First get references to structures we might need. */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		struct kqid qid;
 		got[cnt] = NULL;
 		if (type != -1 && cnt != type)
 			continue;
 		switch (cnt) {
 		case USRQUOTA:
-			id = inode->i_uid;
+			qid = make_kqid_uid(inode->i_uid);
 			break;
 		case GRPQUOTA:
-			id = inode->i_gid;
+			qid = make_kqid_gid(inode->i_gid);
 			break;
 		}
-		got[cnt] = dqget(sb, id, cnt);
+		got[cnt] = dqget(sb, qid);
 	}
 
 	down_write(&sb_dqopt(sb)->dqptr_sem);
@@ -1897,10 +1897,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
 	if (!dquot_active(inode))
 		return 0;
 
-	if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
-		transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA);
-	if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)
-		transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA);
+	if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
+		transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(iattr->ia_uid));
+	if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
+		transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(iattr->ia_gid));
 
 	ret = __dquot_transfer(inode, transfer_to);
 	dqput_all(transfer_to);
@@ -2360,9 +2360,9 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 
 	memset(di, 0, sizeof(*di));
 	di->d_version = FS_DQUOT_VERSION;
-	di->d_flags = dquot->dq_type == USRQUOTA ?
+	di->d_flags = dquot->dq_id.type == USRQUOTA ?
 			FS_USER_QUOTA : FS_GROUP_QUOTA;
-	di->d_id = dquot->dq_id;
+	di->d_id = from_kqid_munged(current_user_ns(), dquot->dq_id);
 
 	spin_lock(&dq_data_lock);
 	di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
@@ -2376,12 +2376,12 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 	spin_unlock(&dq_data_lock);
 }
 
-int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
 		    struct fs_disk_quota *di)
 {
 	struct dquot *dquot;
 
-	dquot = dqget(sb, id, type);
+	dquot = dqget(sb, qid);
 	if (!dquot)
 		return -ESRCH;
 	do_get_dqblk(dquot, di);
@@ -2401,7 +2401,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 {
 	struct mem_dqblk *dm = &dquot->dq_dqb;
 	int check_blim = 0, check_ilim = 0;
-	struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+	struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type];
 
 	if (di->d_fieldmask & ~VFS_FS_DQ_MASK)
 		return -EINVAL;
@@ -2488,13 +2488,13 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 	return 0;
 }
 
-int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, struct kqid qid,
 		  struct fs_disk_quota *di)
 {
 	struct dquot *dquot;
 	int rc;
 
-	dquot = dqget(sb, id, type);
+	dquot = dqget(sb, qid);
 	if (!dquot) {
 		rc = -ESRCH;
 		goto out;
diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
index d67908b..16e8abb 100644
--- a/fs/quota/netlink.c
+++ b/fs/quota/netlink.c
@@ -30,7 +30,7 @@ static struct genl_family quota_genl_family = {
  *
  */
 
-void quota_send_warning(short type, unsigned int id, dev_t dev,
+void quota_send_warning(struct kqid qid, dev_t dev,
 			const char warntype)
 {
 	static atomic_t seq;
@@ -56,10 +56,11 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
 		  "VFS: Cannot store netlink header in quota warning.\n");
 		goto err_out;
 	}
-	ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type);
+	ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, qid.type);
 	if (ret)
 		goto attr_err_out;
-	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id);
+	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID,
+			  from_kqid_munged(&init_user_ns, qid));
 	if (ret)
 		goto attr_err_out;
 	ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
@@ -71,7 +72,8 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
 	ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev));
 	if (ret)
 		goto attr_err_out;
-	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
+	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID,
+			  from_kuid_munged(&init_user_ns, current_uid()));
 	if (ret)
 		goto attr_err_out;
 	genlmsg_end(skb, msg_head);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 6f15578..ff0135d 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -32,8 +32,8 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
 	/* allow to query information for dquots we "own" */
 	case Q_GETQUOTA:
 	case Q_XGETQUOTA:
-		if ((type == USRQUOTA && current_euid() == id) ||
-		    (type == GRPQUOTA && in_egroup_p(id)))
+		if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
+		    (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
 			break;
 		/*FALLTHROUGH*/
 	default:
@@ -130,13 +130,17 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
 static int quota_getquota(struct super_block *sb, int type, qid_t id,
 			  void __user *addr)
 {
+	struct kqid qid;
 	struct fs_disk_quota fdq;
 	struct if_dqblk idq;
 	int ret;
 
 	if (!sb->s_qcop->get_dqblk)
 		return -ENOSYS;
-	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
+	qid = make_kqid(current_user_ns(), type, id);
+	if (!qid_valid(qid))
+		return -EINVAL;
+	ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
 	if (ret)
 		return ret;
 	copy_to_if_dqblk(&idq, &fdq);
@@ -176,13 +180,17 @@ static int quota_setquota(struct super_block *sb, int type, qid_t id,
 {
 	struct fs_disk_quota fdq;
 	struct if_dqblk idq;
+	struct kqid qid;
 
 	if (copy_from_user(&idq, addr, sizeof(idq)))
 		return -EFAULT;
 	if (!sb->s_qcop->set_dqblk)
 		return -ENOSYS;
+	qid = make_kqid(current_user_ns(), type, id);
+	if (!qid_valid(qid))
+		return -EINVAL;
 	copy_from_if_dqblk(&fdq, &idq);
-	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
+	return sb->s_qcop->set_dqblk(sb, qid, &fdq);
 }
 
 static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
@@ -213,23 +221,31 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id,
 			   void __user *addr)
 {
 	struct fs_disk_quota fdq;
+	struct kqid qid;
 
 	if (copy_from_user(&fdq, addr, sizeof(fdq)))
 		return -EFAULT;
 	if (!sb->s_qcop->set_dqblk)
 		return -ENOSYS;
-	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
+	qid = make_kqid(current_user_ns(), type, id);
+	if (!qid_valid(qid))
+		return -EINVAL;
+	return sb->s_qcop->set_dqblk(sb, qid, &fdq);
 }
 
 static int quota_getxquota(struct super_block *sb, int type, qid_t id,
 			   void __user *addr)
 {
 	struct fs_disk_quota fdq;
+	struct kqid qid;
 	int ret;
 
 	if (!sb->s_qcop->get_dqblk)
 		return -ENOSYS;
-	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
+	qid = make_kqid(current_user_ns(), type, id);
+	if (!qid_valid(qid))
+		return -EINVAL;
+	ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
 	if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
 		return -EFAULT;
 	return ret;
diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
index e41c1becf..3534c22 100644
--- a/fs/quota/quota_tree.c
+++ b/fs/quota/quota_tree.c
@@ -22,10 +22,12 @@ MODULE_LICENSE("GPL");
 
 #define __QUOTA_QT_PARANOIA
 
-static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
+static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth)
 {
 	unsigned int epb = info->dqi_usable_bs >> 2;
+	qid_t id;
 
+	id = from_kqid(&init_user_ns, qid);
 	depth = info->dqi_qtree_depth - depth - 1;
 	while (depth--)
 		id /= epb;
@@ -244,7 +246,7 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
 		/* This is enough as the block is already zeroed and the entry
 		 * list is empty... */
 		info->dqi_free_entry = blk;
-		mark_info_dirty(dquot->dq_sb, dquot->dq_type);
+		mark_info_dirty(dquot->dq_sb, dquot->dq_id.type);
 	}
 	/* Block will be full? */
 	if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) {
@@ -357,7 +359,7 @@ static inline int dq_insert_tree(struct qtree_mem_dqinfo *info,
  */
 int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 {
-	int type = dquot->dq_type;
+	int type = dquot->dq_id.type;
 	struct super_block *sb = dquot->dq_sb;
 	ssize_t ret;
 	char *ddquot = getdqbuf(info->dqi_entry_size);
@@ -538,8 +540,9 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
 		ddquot += info->dqi_entry_size;
 	}
 	if (i == qtree_dqstr_in_blk(info)) {
-		quota_error(dquot->dq_sb, "Quota for id %u referenced "
-			    "but not present", dquot->dq_id);
+		quota_error(dquot->dq_sb,
+			    "Quota for id %u referenced but not present",
+			    from_kqid(&init_user_ns, dquot->dq_id));
 		ret = -EIO;
 		goto out_buf;
 	} else {
@@ -589,7 +592,7 @@ static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info,
 
 int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 {
-	int type = dquot->dq_type;
+	int type = dquot->dq_id.type;
 	struct super_block *sb = dquot->dq_sb;
 	loff_t offset;
 	char *ddquot;
@@ -607,8 +610,10 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 		offset = find_dqentry(info, dquot);
 		if (offset <= 0) {	/* Entry not present? */
 			if (offset < 0)
-				quota_error(sb, "Can't read quota structure "
-					    "for id %u", dquot->dq_id);
+				quota_error(sb,"Can't read quota structure "
+					    "for id %u",
+					    from_kqid(&init_user_ns,
+						      dquot->dq_id));
 			dquot->dq_off = 0;
 			set_bit(DQ_FAKE_B, &dquot->dq_flags);
 			memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
@@ -626,7 +631,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
 		if (ret >= 0)
 			ret = -EIO;
 		quota_error(sb, "Error while reading quota structure for id %u",
-			    dquot->dq_id);
+			    from_kqid(&init_user_ns, dquot->dq_id));
 		set_bit(DQ_FAKE_B, &dquot->dq_flags);
 		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
 		kfree(ddquot);
diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c
index 34b37a6..469c684 100644
--- a/fs/quota/quota_v1.c
+++ b/fs/quota/quota_v1.c
@@ -54,7 +54,7 @@ static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m)
 
 static int v1_read_dqblk(struct dquot *dquot)
 {
-	int type = dquot->dq_type;
+	int type = dquot->dq_id.type;
 	struct v1_disk_dqblk dqblk;
 
 	if (!sb_dqopt(dquot->dq_sb)->files[type])
@@ -63,7 +63,8 @@ static int v1_read_dqblk(struct dquot *dquot)
 	/* Set structure to 0s in case read fails/is after end of file */
 	memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
 	dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk,
-			sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
+			sizeof(struct v1_disk_dqblk),
+			v1_dqoff(from_kqid(&init_user_ns, dquot->dq_id)));
 
 	v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
 	if (dquot->dq_dqb.dqb_bhardlimit == 0 &&
@@ -78,12 +79,13 @@ static int v1_read_dqblk(struct dquot *dquot)
 
 static int v1_commit_dqblk(struct dquot *dquot)
 {
-	short type = dquot->dq_type;
+	short type = dquot->dq_id.type;
 	ssize_t ret;
 	struct v1_disk_dqblk dqblk;
 
 	v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
-	if (dquot->dq_id == 0) {
+	if (((type == USRQUOTA) && uid_eq(dquot->dq_id.uid, GLOBAL_ROOT_UID)) ||
+	    ((type == GRPQUOTA) && gid_eq(dquot->dq_id.gid, GLOBAL_ROOT_GID))) {
 		dqblk.dqb_btime =
 			sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
 		dqblk.dqb_itime =
@@ -93,7 +95,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
 	if (sb_dqopt(dquot->dq_sb)->files[type])
 		ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
 			(char *)&dqblk, sizeof(struct v1_disk_dqblk),
-			v1_dqoff(dquot->dq_id));
+			v1_dqoff(from_kqid(&init_user_ns, dquot->dq_id)));
 	if (ret != sizeof(struct v1_disk_dqblk)) {
 		quota_error(dquot->dq_sb, "dquota write failed");
 		if (ret >= 0)
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
index f1ab360..928cb22 100644
--- a/fs/quota/quota_v2.c
+++ b/fs/quota/quota_v2.c
@@ -196,7 +196,7 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
 	struct v2r0_disk_dqblk *d = dp;
 	struct mem_dqblk *m = &dquot->dq_dqb;
 	struct qtree_mem_dqinfo *info =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
 
 	d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
 	d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
@@ -206,7 +206,7 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
 	d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
 	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
 	d->dqb_btime = cpu_to_le64(m->dqb_btime);
-	d->dqb_id = cpu_to_le32(dquot->dq_id);
+	d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
 	if (qtree_entry_unused(info, dp))
 		d->dqb_itime = cpu_to_le64(1);
 }
@@ -215,11 +215,13 @@ static int v2r0_is_id(void *dp, struct dquot *dquot)
 {
 	struct v2r0_disk_dqblk *d = dp;
 	struct qtree_mem_dqinfo *info =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
+	struct kqid qid;
 
 	if (qtree_entry_unused(info, dp))
 		return 0;
-	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+	qid = make_kqid(&init_user_ns, dquot->dq_id.type, le32_to_cpu(d->dqb_id));
+	return qid_eq(qid, dquot->dq_id);
 }
 
 static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
@@ -247,7 +249,7 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
 	struct v2r1_disk_dqblk *d = dp;
 	struct mem_dqblk *m = &dquot->dq_dqb;
 	struct qtree_mem_dqinfo *info =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
 
 	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
 	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
@@ -257,7 +259,7 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
 	d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
 	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
 	d->dqb_btime = cpu_to_le64(m->dqb_btime);
-	d->dqb_id = cpu_to_le32(dquot->dq_id);
+	d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
 	if (qtree_entry_unused(info, dp))
 		d->dqb_itime = cpu_to_le64(1);
 }
@@ -266,26 +268,28 @@ static int v2r1_is_id(void *dp, struct dquot *dquot)
 {
 	struct v2r1_disk_dqblk *d = dp;
 	struct qtree_mem_dqinfo *info =
-			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
+			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
+	struct kqid qid;
 
 	if (qtree_entry_unused(info, dp))
 		return 0;
-	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
+	qid = make_kqid(&init_user_ns, dquot->dq_id.type, le32_to_cpu(d->dqb_id));
+	return qid_eq(qid, dquot->dq_id);
 }
 
 static int v2_read_dquot(struct dquot *dquot)
 {
-	return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+	return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
 }
 
 static int v2_write_dquot(struct dquot *dquot)
 {
-	return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+	return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
 }
 
 static int v2_release_dquot(struct dquot *dquot)
 {
-	return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot);
+	return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
 }
 
 static int v2_free_file_info(struct super_block *sb, int type)
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index fed504f..96944c0 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -97,28 +97,29 @@ xfs_fs_set_xstate(
 STATIC int
 xfs_fs_get_dqblk(
 	struct super_block	*sb,
-	int			type,
-	qid_t			id,
+	struct kqid		qid,
 	struct fs_disk_quota	*fdq)
 {
 	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		xfs_id;
 
 	if (!XFS_IS_QUOTA_RUNNING(mp))
 		return -ENOSYS;
 	if (!XFS_IS_QUOTA_ON(mp))
 		return -ESRCH;
 
-	return -xfs_qm_scall_getquota(mp, id, xfs_quota_type(type), fdq);
+	xfs_id = from_kqid(&init_user_ns, qid);
+	return -xfs_qm_scall_getquota(mp, xfs_id, xfs_quota_type(qid.type), fdq);
 }
 
 STATIC int
 xfs_fs_set_dqblk(
 	struct super_block	*sb,
-	int			type,
-	qid_t			id,
+	struct kqid		qid,
 	struct fs_disk_quota	*fdq)
 {
 	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		xfs_id;
 
 	if (sb->s_flags & MS_RDONLY)
 		return -EROFS;
@@ -127,7 +128,8 @@ xfs_fs_set_dqblk(
 	if (!XFS_IS_QUOTA_ON(mp))
 		return -ESRCH;
 
-	return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq);
+	xfs_id = from_kqid(&init_user_ns, qid);
+	return -xfs_qm_scall_setqlim(mp, xfs_id, xfs_quota_type(qid.type), fdq);
 }
 
 const struct quotactl_ops xfs_quotactl_operations = {
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index bcb6054..46de393 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -575,12 +575,14 @@ xfs_quota_warn(
 	struct xfs_dquot	*dqp,
 	int			type)
 {
+	int qtype;
+	struct kqid qid;
 	/* no warnings for project quotas - we just return ENOSPC later */
 	if (dqp->dq_flags & XFS_DQ_PROJ)
 		return;
-	quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA,
-			   be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev,
-			   type);
+	qtype = (dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA;
+	qid = make_kqid(&init_user_ns, qtype, be32_to_cpu(dqp->q_core.d_id));
+	quota_send_warning(qid, mp->m_super->s_dev, type);
 }
 
 /*
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 524ede8..0e73250 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -181,10 +181,161 @@ enum {
 #include <linux/dqblk_v2.h>
 
 #include <linux/atomic.h>
+#include <linux/uidgid.h>
 
 typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
 typedef long long qsize_t;	/* Type in which we store sizes */
 
+struct kqid {			/* Type in which we store the quota identifier */
+	union {
+		kuid_t uid;
+		kgid_t gid;
+		qid_t prj;
+	};
+	int type; /* USRQUOTA (uid) or GRPQUOTA (gid) or XQM_PRJQUOTA (prj) */
+};
+
+static inline bool qid_eq(struct kqid left, struct kqid right)
+{
+	if (left.type != right.type)
+		return false;
+	switch(left.type) {
+	case USRQUOTA:
+		return uid_eq(left.uid, right.uid);
+	case GRPQUOTA:
+		return gid_eq(left.gid, right.gid);
+	case XQM_PRJQUOTA:
+		return left.prj == right.prj;
+	default:
+		BUG();
+	}
+}
+
+static inline bool qid_lt(struct kqid left, struct kqid right)
+{
+	if (left.type < right.type)
+		return true;
+	if (left.type > right.type)
+		return false;
+	switch (left.type) {
+	case USRQUOTA:
+		return uid_lt(left.uid, right.uid);
+	case GRPQUOTA:
+		return gid_lt(left.gid, right.gid);
+	case XQM_PRJQUOTA:
+		return left.prj < right.prj;
+	default:
+		BUG();
+	}
+}
+
+static inline qid_t from_kqid(struct user_namespace *user_ns, struct kqid qid)
+{
+	switch (qid.type) {
+	case USRQUOTA:
+		return from_kuid(user_ns, qid.uid);
+	case GRPQUOTA:
+		return from_kgid(user_ns, qid.gid);
+	case XQM_PRJQUOTA:
+		return (user_ns == &init_user_ns) ? qid.prj : -1;
+	default:
+		BUG();
+	}
+}
+
+static inline qid_t from_kqid_munged(struct user_namespace *user_ns,
+				   struct kqid qid)
+{
+	switch (qid.type) {
+	case USRQUOTA:
+		return from_kuid_munged(user_ns, qid.uid);
+	case GRPQUOTA:
+		return from_kgid_munged(user_ns, qid.gid);
+	case XQM_PRJQUOTA:
+		return (user_ns == &init_user_ns) ? qid.prj : -1;
+	default:
+		BUG();
+	}
+}
+
+static inline struct kqid make_kqid(struct user_namespace *user_ns,
+				    int type, qid_t qid)
+{
+	struct kqid kqid;
+
+	kqid.type = type;
+	switch (type) {
+	case USRQUOTA:
+		kqid.uid = make_kuid(user_ns, qid);
+		break;
+	case GRPQUOTA:
+		kqid.gid = make_kgid(user_ns, qid);
+		break;
+	case XQM_PRJQUOTA:
+		if (user_ns == &init_user_ns)
+			kqid.prj = qid;
+		else
+			kqid.prj = -1;
+		break;
+	default:
+		BUG();
+	}
+	return kqid;
+}
+
+static inline struct kqid make_kqid_invalid(int type)
+{
+	struct kqid kqid;
+
+	kqid.type = type;
+	switch (type) {
+	case USRQUOTA:
+		kqid.uid = INVALID_UID;
+		break;
+	case GRPQUOTA:
+		kqid.gid = INVALID_GID;
+		break;
+	case XQM_PRJQUOTA:
+		kqid.prj = -1;
+		break;
+	default:
+		BUG();
+	}
+	return kqid;
+}
+
+static inline struct kqid make_kqid_uid(kuid_t uid)
+{
+	struct kqid kqid = {
+		.type = USRQUOTA,
+		.uid  = uid,
+	};
+	return kqid;
+}
+
+static inline struct kqid make_kqid_gid(kgid_t gid)
+{
+	struct kqid kqid = {
+		.type = GRPQUOTA,
+		.gid  = gid,
+	};
+	return kqid;
+}
+
+static inline bool qid_valid(struct kqid qid)
+{
+	switch (qid.type) {
+	case USRQUOTA:
+		return uid_valid(qid.uid);
+	case GRPQUOTA:
+		return gid_valid(qid.gid);
+	case XQM_PRJQUOTA:
+		return qid.prj != (qid_t)-1;
+	default:
+		BUG();
+	}
+}
+
 extern spinlock_t dq_data_lock;
 
 /* Maximal numbers of writes for quota operation (insert/delete/update)
@@ -294,10 +445,9 @@ struct dquot {
 	atomic_t dq_count;		/* Use count */
 	wait_queue_head_t dq_wait_unused;	/* Wait queue for dquot to become unused */
 	struct super_block *dq_sb;	/* superblock this applies to */
-	unsigned int dq_id;		/* ID this applies to (uid, gid) */
+	struct kqid dq_id;		/* ID this applies to (uid, gid, prj) */
 	loff_t dq_off;			/* Offset of dquot on disk */
 	unsigned long dq_flags;		/* See DQ_* */
-	short dq_type;			/* Type of quota */
 	struct mem_dqblk dq_dqb;	/* Diskquota usage */
 };
 
@@ -336,8 +486,8 @@ struct quotactl_ops {
 	int (*quota_sync)(struct super_block *, int);
 	int (*get_info)(struct super_block *, int, struct if_dqinfo *);
 	int (*set_info)(struct super_block *, int, struct if_dqinfo *);
-	int (*get_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
-	int (*set_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
+	int (*get_dqblk)(struct super_block *, struct kqid, struct fs_disk_quota *);
+	int (*set_dqblk)(struct super_block *, struct kqid, struct fs_disk_quota *);
 	int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
 	int (*set_xstate)(struct super_block *, unsigned int, int);
 };
@@ -386,10 +536,10 @@ static inline unsigned int dquot_generic_flag(unsigned int flags, int type)
 }
 
 #ifdef CONFIG_QUOTA_NETLINK_INTERFACE
-extern void quota_send_warning(short type, unsigned int id, dev_t dev,
+extern void quota_send_warning(struct kqid qid, dev_t dev,
 			       const char warntype);
 #else
-static inline void quota_send_warning(short type, unsigned int id, dev_t dev,
+static inline void quota_send_warning(struct kqid qid, dev_t dev,
 				      const char warntype)
 {
 	return;
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index ec6b65f..1c50093 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -44,7 +44,7 @@ void inode_sub_rsv_space(struct inode *inode, qsize_t number);
 
 void dquot_initialize(struct inode *inode);
 void dquot_drop(struct inode *inode);
-struct dquot *dqget(struct super_block *sb, unsigned int id, int type);
+struct dquot *dqget(struct super_block *sb, struct kqid qid);
 void dqput(struct dquot *dquot);
 int dquot_scan_active(struct super_block *sb,
 		      int (*fn)(struct dquot *dquot, unsigned long priv),
@@ -87,9 +87,9 @@ int dquot_writeback_dquots(struct super_block *sb, int type);
 int dquot_quota_sync(struct super_block *sb, int type);
 int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
 int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
-int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_get_dqblk(struct super_block *sb, struct kqid id,
 		struct fs_disk_quota *di);
-int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
+int dquot_set_dqblk(struct super_block *sb, struct kqid id,
 		struct fs_disk_quota *di);
 
 int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
diff --git a/init/Kconfig b/init/Kconfig
index 2a388e5..a0bccce 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -928,8 +928,6 @@ config UIDGID_CONVERTED
 	depends on IMA = n
 	depends on EVM = n
 	depends on FS_POSIX_ACL = n
-	depends on QUOTA = n
-	depends on QUOTACTL = n
 
 	# Networking
 	depends on NET_9P = n
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH] userns: Add basic quota support v4
  2012-08-28 19:09             ` [PATCH] userns: Add basic quota support v4 Eric W. Biederman
@ 2012-08-29  2:10               ` Dave Chinner
  2012-08-29  9:31                 ` Eric W. Biederman
  0 siblings, 1 reply; 37+ messages in thread
From: Dave Chinner @ 2012-08-29  2:10 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Jan Kara, linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
	Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das

On Tue, Aug 28, 2012 at 12:09:56PM -0700, Eric W. Biederman wrote:
> 
> Add the data type struct kqid which holds the kernel internal form of
> the owning identifier of a quota.  struct kqid is a replacement for
> the implicit union of uid, gid and project stored in an unsigned int
> and the quota type field that is was used in the quota data
> structures.  Making the data type explicit allows the kuid_t and
> kgid_t type safety to propogate more thoroughly through the code,
> revealing more places where uid/gid conversions need be made.
> 
> Along with the data type struct kqid comes the helper functions
> qid_eq, qid_lt, from_kqid, from_kqid_munged, qid_valid, make_kqid,

I think Jan's comment about from_kqid being named id_from_kgid is
better, though I also think it would read better as kqid_to_id().
ie:

	id = kqid_to_id(ns, qid);

> make_kqid_invalid, make_kqid_uid, make_kqid_gid.

and these named something like uid_to_kqid()

> Change struct dquot dq_id to a struct kqid and remove the now
> unecessary dq_type.
> 
> Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
> and dquot_set_dqblk to use struct kqid.
> 
> Make minimal changes to ext3, ext4, gfs2, ocfs2, and xfs to deal with
> the change in quota structures and signatures.  The ocfs2 changes are
> larger than most because of the extensive tracing throughout the ocfs2
> quota code that prints out dq_id.

How did you test that this all works? e.g. run xfstests -g quota on
each of those filesystems and check for no regressions? And if you
wrote any tests, can you convert them to be part of xfstests so that
namespace aware quotas get tested regularly?

> 
> v4:
>   - Rename struct qown struct kqid and associated changes
>     to the naming of the helper functions.
>   - Use qid_t to hold the userspace identifier representation
>     of quota identifiers in all new code.
> v3:
>   - Add missing negation on qown_valid
> v2:
>   - Renamed qown_t struct qown
>   - Added the quota type to struct qown.
>   - Removed enum quota_type (In this patch it was just noise)
>   - Added qown_lt, make_qown_invalid, make_qown_uid, make_qown_gid
>   - Taught qown to handle xfs project ids (but only in init_user_ns).
>     Q_XGETQUOTA calls .get_quotblk with project ids.

Q_XSETQLIM was modified to handle project quotas as well, I assume?

> index fed504f..96944c0 100644
> --- a/fs/xfs/xfs_quotaops.c
> +++ b/fs/xfs/xfs_quotaops.c
> @@ -97,28 +97,29 @@ xfs_fs_set_xstate(
>  STATIC int
>  xfs_fs_get_dqblk(
>  	struct super_block	*sb,
> -	int			type,
> -	qid_t			id,
> +	struct kqid		qid,
>  	struct fs_disk_quota	*fdq)
>  {
>  	struct xfs_mount	*mp = XFS_M(sb);
> +	xfs_dqid_t		xfs_id;
>  
>  	if (!XFS_IS_QUOTA_RUNNING(mp))
>  		return -ENOSYS;
>  	if (!XFS_IS_QUOTA_ON(mp))
>  		return -ESRCH;
>  
> -	return -xfs_qm_scall_getquota(mp, id, xfs_quota_type(type), fdq);
> +	xfs_id = from_kqid(&init_user_ns, qid);
> +	return -xfs_qm_scall_getquota(mp, xfs_id, xfs_quota_type(qid.type), fdq);
>  }

Why a temporary variable? Why not just:

	return -xfs_qm_scall_getquota(mp, from_kqid(&init_user_ns, qid),
				      xfs_quota_type(qid.type), fdq);

Indeed, why not drive the struct kqid down another level into
xfs_qm_scall_getquota() where all they are used for is parameters to
the xfs_qm_dqget() function?

>  
>  STATIC int
>  xfs_fs_set_dqblk(
>  	struct super_block	*sb,
> -	int			type,
> -	qid_t			id,
> +	struct kqid		qid,
>  	struct fs_disk_quota	*fdq)
>  {
>  	struct xfs_mount	*mp = XFS_M(sb);
> +	xfs_dqid_t		xfs_id;
>  
>  	if (sb->s_flags & MS_RDONLY)
>  		return -EROFS;
> @@ -127,7 +128,8 @@ xfs_fs_set_dqblk(
>  	if (!XFS_IS_QUOTA_ON(mp))
>  		return -ESRCH;
>  
> -	return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq);
> +	xfs_id = from_kqid(&init_user_ns, qid);
> +	return -xfs_qm_scall_setqlim(mp, xfs_id, xfs_quota_type(qid.type), fdq);
>  }

Same is true here....

>  
>  const struct quotactl_ops xfs_quotactl_operations = {
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index bcb6054..46de393 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -575,12 +575,14 @@ xfs_quota_warn(
>  	struct xfs_dquot	*dqp,
>  	int			type)
>  {
> +	int qtype;
> +	struct kqid qid;
>  	/* no warnings for project quotas - we just return ENOSPC later */
>  	if (dqp->dq_flags & XFS_DQ_PROJ)
>  		return;
> -	quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA,
> -			   be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev,
> -			   type);
> +	qtype = (dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA;
> +	qid = make_kqid(&init_user_ns, qtype, be32_to_cpu(dqp->q_core.d_id));
> +	quota_send_warning(qid, mp->m_super->s_dev, type);
>  }
>  
>  /*
> diff --git a/include/linux/quota.h b/include/linux/quota.h
> index 524ede8..0e73250 100644
> --- a/include/linux/quota.h
> +++ b/include/linux/quota.h
> @@ -181,10 +181,161 @@ enum {
>  #include <linux/dqblk_v2.h>
>  
>  #include <linux/atomic.h>
> +#include <linux/uidgid.h>
>  
>  typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
>  typedef long long qsize_t;	/* Type in which we store sizes */

>From fs/xfs/xfs_types.h:

typedef __uint32_t              prid_t;         /* project ID */

Perhaps it would be better to have an official kprid_t definition
here, i.e:

>  
> +struct kqid {			/* Type in which we store the quota identifier */
> +	union {
> +		kuid_t uid;
> +		kgid_t gid;
> +		qid_t prj;

		kprid_t prid;

> +	};
> +	int type; /* USRQUOTA (uid) or GRPQUOTA (gid) or XQM_PRJQUOTA (prj) */
> +};
> +
> +static inline bool qid_eq(struct kqid left, struct kqid right)
> +{
> +	if (left.type != right.type)
> +		return false;
> +	switch(left.type) {
> +	case USRQUOTA:
> +		return uid_eq(left.uid, right.uid);
> +	case GRPQUOTA:
> +		return gid_eq(left.gid, right.gid);
> +	case XQM_PRJQUOTA:
> +		return left.prj == right.prj;
> +	default:
> +		BUG();

BUG()? Seriously? The most this justifies is a WARN_ON_ONCE() to
indicate a potential programming error, not bringing down the entire
machine.

> +	}
> +}
> +
> +static inline bool qid_lt(struct kqid left, struct kqid right)
> +{
> +	if (left.type < right.type)
> +		return true;
> +	if (left.type > right.type)
> +		return false;
> +	switch (left.type) {
> +	case USRQUOTA:
> +		return uid_lt(left.uid, right.uid);
> +	case GRPQUOTA:
> +		return gid_lt(left.gid, right.gid);
> +	case XQM_PRJQUOTA:
> +		return left.prj < right.prj;
> +	default:
> +		BUG();
> +	}
> +}

What is this function used for? it's not referenced at all by the
patch, and there's no documentation/comments explaining why it
exists or how it is intended to be used....

> +static inline qid_t from_kqid(struct user_namespace *user_ns, struct kqid qid)
> +{
> +	switch (qid.type) {
> +	case USRQUOTA:
> +		return from_kuid(user_ns, qid.uid);
> +	case GRPQUOTA:
> +		return from_kgid(user_ns, qid.gid);
> +	case XQM_PRJQUOTA:
> +		return (user_ns == &init_user_ns) ? qid.prj : -1;
> +	default:
> +		BUG();
> +	}
> +}

Oh, this can return an error. That's only checked in a coupl eof
places this function is called. it needs tobe checked everywhere,
otherwise we now have the possibility of quota usage being accounted
to uid/gid/prid 0xffffffff when namespace matches are not found.

> +static inline qid_t from_kqid_munged(struct user_namespace *user_ns,
> +				   struct kqid qid)

What does munging do to the return value? how is it different to
from_kqid()? Document your API....


> +static inline struct kqid make_kqid(struct user_namespace *user_ns,
> +				    int type, qid_t qid)
> +{
> +	struct kqid kqid;
> +
> +	kqid.type = type;
> +	switch (type) {
> +	case USRQUOTA:
> +		kqid.uid = make_kuid(user_ns, qid);
> +		break;
> +	case GRPQUOTA:
> +		kqid.gid = make_kgid(user_ns, qid);
> +		break;
> +	case XQM_PRJQUOTA:
> +		if (user_ns == &init_user_ns)
> +			kqid.prj = qid;
> +		else
> +			kqid.prj = -1;
> +		break;

		kqid.prj = (user_ns == &init_user_ns) ? qid : -1;

> +	default:
> +		BUG();
> +	}
> +	return kqid;
> +}
> +
> +static inline struct kqid make_kqid_invalid(int type)
> +{
> +	struct kqid kqid;
> +
> +	kqid.type = type;
> +	switch (type) {
> +	case USRQUOTA:
> +		kqid.uid = INVALID_UID;
> +		break;
> +	case GRPQUOTA:
> +		kqid.gid = INVALID_GID;
> +		break;
> +	case XQM_PRJQUOTA:
> +		kqid.prj = -1;
> +		break;
> +	default:
> +		BUG();
> +	}
> +	return kqid;
> +}
> +
> +static inline struct kqid make_kqid_uid(kuid_t uid)
> +{
> +	struct kqid kqid = {
> +		.type = USRQUOTA,
> +		.uid  = uid,
> +	};
> +	return kqid;
> +}

Isn't this sort of construct frowned upon? i.e. returning a
structure out of scope? It may be inline code and hence work, but
this strikes me as a landmine waiting for someone to tread on....

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] userns: Add basic quota support v4
  2012-08-29  2:10               ` Dave Chinner
@ 2012-08-29  9:31                 ` Eric W. Biederman
  2012-08-31  1:17                   ` Dave Chinner
  0 siblings, 1 reply; 37+ messages in thread
From: Eric W. Biederman @ 2012-08-29  9:31 UTC (permalink / raw)
  To: Dave Chinner
  Cc: Jan Kara, linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
	Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das


Dave thanks for taking the time to take a detailed look at this code.

Dave Chinner <david@fromorbit.com> writes:

> On Tue, Aug 28, 2012 at 12:09:56PM -0700, Eric W. Biederman wrote:
>> 
>> Add the data type struct kqid which holds the kernel internal form of
>> the owning identifier of a quota.  struct kqid is a replacement for
>> the implicit union of uid, gid and project stored in an unsigned int
>> and the quota type field that is was used in the quota data
>> structures.  Making the data type explicit allows the kuid_t and
>> kgid_t type safety to propogate more thoroughly through the code,
>> revealing more places where uid/gid conversions need be made.
>> 
>> Along with the data type struct kqid comes the helper functions
>> qid_eq, qid_lt, from_kqid, from_kqid_munged, qid_valid, make_kqid,
>
> I think Jan's comment about from_kqid being named id_from_kgid is
> better, though I also think it would read better as kqid_to_id().
> ie:
>
> 	id = kqid_to_id(ns, qid);

kqid and qid are the same thing just in a different encoding.
Emphasizing the quota identifier instead of the kernel vs user encoding
change is paying attention to the wrong thing.

Using make_kqid and from_kqid follows the exact same conventions as I have
established for kuids and kgids.  So if you learn one you have learned
them all.

>> make_kqid_invalid, make_kqid_uid, make_kqid_gid.
>
> and these named something like uid_to_kqid()

The last two are indeed weird, and definitely not the common case,
since there is no precedent I can almost see doing something different
but I don't see a good case for a different name.

>> Change struct dquot dq_id to a struct kqid and remove the now
>> unecessary dq_type.
>> 
>> Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
>> and dquot_set_dqblk to use struct kqid.
>> 
>> Make minimal changes to ext3, ext4, gfs2, ocfs2, and xfs to deal with
>> the change in quota structures and signatures.  The ocfs2 changes are
>> larger than most because of the extensive tracing throughout the ocfs2
>> quota code that prints out dq_id.
>
> How did you test that this all works?

By making it a compile error if you get a conversion wrong and making it
a rule not to make any logic changes.  That combined with code review
and running the code a bit to make certain I did not horribly mess up.

> e.g. run xfstests -g quota on
> each of those filesystems and check for no regressions? And if you
> wrote any tests, can you convert them to be part of xfstests so that
> namespace aware quotas get tested regularly?

I have not written any tests, and running the xfstests in a namespace
should roughly be a matter of "unshare -U xfstest -g quota"  It isn't
quite that easy because  /proc/self/uid_map and /proc/self/gid_map need
to be written first.

Right now only ext2 ext3 and ext4 compile with user namespace support
enabled.  xfs and gfs2 and ocfs2 still only compile with user namespace
support disabled because my patches to convert them are waiting in the
wings until I get the core subsystems primarily quota and posix acls
reviewed.

>> v4:
>>   - Rename struct qown struct kqid and associated changes
>>     to the naming of the helper functions.
>>   - Use qid_t to hold the userspace identifier representation
>>     of quota identifiers in all new code.
>> v3:
>>   - Add missing negation on qown_valid
>> v2:
>>   - Renamed qown_t struct qown
>>   - Added the quota type to struct qown.
>>   - Removed enum quota_type (In this patch it was just noise)
>>   - Added qown_lt, make_qown_invalid, make_qown_uid, make_qown_gid
>>   - Taught qown to handle xfs project ids (but only in init_user_ns).
>>     Q_XGETQUOTA calls .get_quotblk with project ids.
>
> Q_XSETQLIM was modified to handle project quotas as well, I assume?

I didn't break the project quota support for Q_XSETQLIM.


>> index fed504f..96944c0 100644
>> --- a/fs/xfs/xfs_quotaops.c
>> +++ b/fs/xfs/xfs_quotaops.c
>> @@ -97,28 +97,29 @@ xfs_fs_set_xstate(
>>  STATIC int
>>  xfs_fs_get_dqblk(
>>  	struct super_block	*sb,
>> -	int			type,
>> -	qid_t			id,
>> +	struct kqid		qid,
>>  	struct fs_disk_quota	*fdq)
>>  {
>>  	struct xfs_mount	*mp = XFS_M(sb);
>> +	xfs_dqid_t		xfs_id;
>>  
>>  	if (!XFS_IS_QUOTA_RUNNING(mp))
>>  		return -ENOSYS;
>>  	if (!XFS_IS_QUOTA_ON(mp))
>>  		return -ESRCH;
>>  
>> -	return -xfs_qm_scall_getquota(mp, id, xfs_quota_type(type), fdq);
>> +	xfs_id = from_kqid(&init_user_ns, qid);
>> +	return -xfs_qm_scall_getquota(mp, xfs_id, xfs_quota_type(qid.type), fdq);
>>  }
>
> Why a temporary variable? Why not just:
>
> 	return -xfs_qm_scall_getquota(mp, from_kqid(&init_user_ns, qid),
> 				      xfs_quota_type(qid.type), fdq);
>

Because I am not fond of very long lines and because I did the basic
conversion of gfs2 first where using a separate variable a larger
difference.

>From a code review perspective I am still more comfortable with
introducing a temporary variable as the fundamental change is
easier to see.

> Indeed, why not drive the struct kqid down another level into
> xfs_qm_scall_getquota() where all they are used for is parameters to
> the xfs_qm_dqget() function?

I have not driven struct kqid down another level because change
needs to wait until I add user namespace support to xfs.

I only touch xfs in this case because making the implicit union explicit
is needed for type safety and sanity, and unfortunately that requires
the prototype of the quota operations to change.

>>  STATIC int
>>  xfs_fs_set_dqblk(
>>  	struct super_block	*sb,
>> -	int			type,
>> -	qid_t			id,
>> +	struct kqid		qid,
>>  	struct fs_disk_quota	*fdq)
>>  {
>>  	struct xfs_mount	*mp = XFS_M(sb);
>> +	xfs_dqid_t		xfs_id;
>>  
>>  	if (sb->s_flags & MS_RDONLY)
>>  		return -EROFS;
>> @@ -127,7 +128,8 @@ xfs_fs_set_dqblk(
>>  	if (!XFS_IS_QUOTA_ON(mp))
>>  		return -ESRCH;
>>  
>> -	return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq);
>> +	xfs_id = from_kqid(&init_user_ns, qid);
>> +	return -xfs_qm_scall_setqlim(mp, xfs_id, xfs_quota_type(qid.type), fdq);
>>  }
>
> Same is true here....
>
>>  
>>  const struct quotactl_ops xfs_quotactl_operations = {
>> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
>> index bcb6054..46de393 100644
>> --- a/fs/xfs/xfs_trans_dquot.c
>> +++ b/fs/xfs/xfs_trans_dquot.c
>> @@ -575,12 +575,14 @@ xfs_quota_warn(
>>  	struct xfs_dquot	*dqp,
>>  	int			type)
>>  {
>> +	int qtype;
>> +	struct kqid qid;
>>  	/* no warnings for project quotas - we just return ENOSPC later */
>>  	if (dqp->dq_flags & XFS_DQ_PROJ)
>>  		return;
>> -	quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA,
>> -			   be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev,
>> -			   type);
>> +	qtype = (dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA;
>> +	qid = make_kqid(&init_user_ns, qtype, be32_to_cpu(dqp->q_core.d_id));
>> +	quota_send_warning(qid, mp->m_super->s_dev, type);
>>  }
>>  
>>  /*
>> diff --git a/include/linux/quota.h b/include/linux/quota.h
>> index 524ede8..0e73250 100644
>> --- a/include/linux/quota.h
>> +++ b/include/linux/quota.h
>> @@ -181,10 +181,161 @@ enum {
>>  #include <linux/dqblk_v2.h>
>>  
>>  #include <linux/atomic.h>
>> +#include <linux/uidgid.h>
>>  
>>  typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
>>  typedef long long qsize_t;	/* Type in which we store sizes */
>
> From fs/xfs/xfs_types.h:
>
> typedef __uint32_t              prid_t;         /* project ID */
>
> Perhaps it would be better to have an official kprid_t definition
> here, i.e:

We can always improve.  For this patch I don't see it making a
useful difference.

prid_t isn't exported to non xfs code.  The project id is already
stored in an unsigned int or a qid_t.

>> +struct kqid {			/* Type in which we store the quota identifier */
>> +	union {
>> +		kuid_t uid;
>> +		kgid_t gid;
>> +		qid_t prj;
>
> 		kprid_t prid;
>

Hmm.  The naming here is interesting.  No one calls the project id prj.
So I have an avoidable inconsistency here.  xfs most commonly uses
projid and occassionally calls it prid.

So I am inclined to rename this field projid, but I don't know if it is
worth respinning the patch for something so trivial.

>> +	};
>> +	int type; /* USRQUOTA (uid) or GRPQUOTA (gid) or XQM_PRJQUOTA (prj) */
>> +};
>> +
>> +static inline bool qid_eq(struct kqid left, struct kqid right)
>> +{
>> +	if (left.type != right.type)
>> +		return false;
>> +	switch(left.type) {
>> +	case USRQUOTA:
>> +		return uid_eq(left.uid, right.uid);
>> +	case GRPQUOTA:
>> +		return gid_eq(left.gid, right.gid);
>> +	case XQM_PRJQUOTA:
>> +		return left.prj == right.prj;
>> +	default:
>> +		BUG();
>
> BUG()? Seriously? The most this justifies is a WARN_ON_ONCE() to
> indicate a potential programming error, not bringing down the entire
> machine.

Dead serious.  Any other type value is impossible and unsupported.

BUG is not panic.  BUG is an oops. BUG won't bring down the machine
unless the sysadmin wants it too.

Beyond that I am not interesting in supporting exploitable abuse
of this type.

>> +static inline bool qid_lt(struct kqid left, struct kqid right)
>> +{
>> +	if (left.type < right.type)
>> +		return true;
>> +	if (left.type > right.type)
>> +		return false;
>> +	switch (left.type) {
>> +	case USRQUOTA:
>> +		return uid_lt(left.uid, right.uid);
>> +	case GRPQUOTA:
>> +		return gid_lt(left.gid, right.gid);
>> +	case XQM_PRJQUOTA:
>> +		return left.prj < right.prj;
>> +	default:
>> +		BUG();
>> +	}
>> +}
>
> What is this function used for? it's not referenced at all by the
> patch, and there's no documentation/comments explaining why it
> exists or how it is intended to be used....

This function is introduced early, but it is needed for gfs2 as
performs a sort of quota identifiers.

>> +static inline qid_t from_kqid(struct user_namespace *user_ns, struct kqid qid)
>> +{
>> +	switch (qid.type) {
>> +	case USRQUOTA:
>> +		return from_kuid(user_ns, qid.uid);
>> +	case GRPQUOTA:
>> +		return from_kgid(user_ns, qid.gid);
>> +	case XQM_PRJQUOTA:
>> +		return (user_ns == &init_user_ns) ? qid.prj : -1;
>> +	default:
>> +		BUG();
>> +	}
>> +}
>
> Oh, this can return an error. That's only checked in a coupl eof
> places this function is called. it needs tobe checked everywhere,
> otherwise we now have the possibility of quota usage being accounted
> to uid/gid/prid 0xffffffff when namespace matches are not found.

No this is not an error condition.  Returning -1 is the mapping that is
used when there is not a mapping entry.

Depending on the circumstances not having a mapping can be an error,
but it can also be a don't care condition.

All in kernel values are defined as having a mapping into the initial
user namespace.

Looking at my tree the only calls of from_kqid not mapping the id
into the initial user namespace are from_kqid_munged and they report
to userspace.  from_kqid_munged returns fs_overflowuid or fs_overflowgid
in case of a mapping failure.

projects ids can only be accessed if capable(CAP_SYS_ADMIN) which
you can only have in the initial user namespace so for now there will
alwasy be a mapping for project ids.

>> +static inline qid_t from_kqid_munged(struct user_namespace *user_ns,
>> +				   struct kqid qid)
>
> What does munging do to the return value? how is it different to
> from_kqid()? Document your API....

This bit certainly certainly could use a bit more explanation.

Mapping of uids and gids from one domain to another is not new in linux.
It originates with the transition from 16bit identifiers to 32bit
identifiers.  In most places when there is a 32bit identifier that can
not be represented we return a fs_overflowid aka (u16)-2 aka nobody.

So in general when we want to pass a value to userspace from_kqid_munged
is called, and if there is a mapping failure we report the value that
userspace set fs_overflowuid or fs_overflowgid to.  For project ids it
which are restricted to the initial user namespace no mapping failures
can occur.

>> +static inline struct kqid make_kqid(struct user_namespace *user_ns,
>> +				    int type, qid_t qid)
>> +{
>> +	struct kqid kqid;
>> +
>> +	kqid.type = type;
>> +	switch (type) {
>> +	case USRQUOTA:
>> +		kqid.uid = make_kuid(user_ns, qid);
>> +		break;
>> +	case GRPQUOTA:
>> +		kqid.gid = make_kgid(user_ns, qid);
>> +		break;
>> +	case XQM_PRJQUOTA:
>> +		if (user_ns == &init_user_ns)
>> +			kqid.prj = qid;
>> +		else
>> +			kqid.prj = -1;
>> +		break;
>
> 		kqid.prj = (user_ns == &init_user_ns) ? qid : -1;

That is an interesting inconsitency. Given that implemented the others
on one line.

>> +	default:
>> +		BUG();
>> +	}
>> +	return kqid;
>> +}
>> +
>> +static inline struct kqid make_kqid_invalid(int type)
>> +{
>> +	struct kqid kqid;
>> +
>> +	kqid.type = type;
>> +	switch (type) {
>> +	case USRQUOTA:
>> +		kqid.uid = INVALID_UID;
>> +		break;
>> +	case GRPQUOTA:
>> +		kqid.gid = INVALID_GID;
>> +		break;
>> +	case XQM_PRJQUOTA:
>> +		kqid.prj = -1;
>> +		break;
>> +	default:
>> +		BUG();
>> +	}
>> +	return kqid;
>> +}
>> +
>> +static inline struct kqid make_kqid_uid(kuid_t uid)
>> +{
>> +	struct kqid kqid = {
>> +		.type = USRQUOTA,
>> +		.uid  = uid,
>> +	};
>> +	return kqid;
>> +}
>
> Isn't this sort of construct frowned upon? i.e. returning a
> structure out of scope? It may be inline code and hence work, but
> this strikes me as a landmine waiting for someone to tread on....

Not at all because I am returning the structure by value.

Return a structure by reference is the case that doesn't work.

Eric


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] userns: Add basic quota support v4
  2012-08-29  9:31                 ` Eric W. Biederman
@ 2012-08-31  1:17                   ` Dave Chinner
  2012-09-05  5:20                     ` Eric W. Biederman
  2012-09-20  1:28                     ` Eric W. Biederman
  0 siblings, 2 replies; 37+ messages in thread
From: Dave Chinner @ 2012-08-31  1:17 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Jan Kara, linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
	Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das

On Wed, Aug 29, 2012 at 02:31:26AM -0700, Eric W. Biederman wrote:
> 
> Dave thanks for taking the time to take a detailed look at this code.
> 
> Dave Chinner <david@fromorbit.com> writes:
> 
> > On Tue, Aug 28, 2012 at 12:09:56PM -0700, Eric W. Biederman wrote:
> >> 
> >> Add the data type struct kqid which holds the kernel internal form of
> >> the owning identifier of a quota.  struct kqid is a replacement for
> >> the implicit union of uid, gid and project stored in an unsigned int
> >> and the quota type field that is was used in the quota data
> >> structures.  Making the data type explicit allows the kuid_t and
> >> kgid_t type safety to propogate more thoroughly through the code,
> >> revealing more places where uid/gid conversions need be made.
> >> 
> >> Along with the data type struct kqid comes the helper functions
> >> qid_eq, qid_lt, from_kqid, from_kqid_munged, qid_valid, make_kqid,
> >
> > I think Jan's comment about from_kqid being named id_from_kgid is
> > better, though I also think it would read better as kqid_to_id().
> > ie:
> >
> > 	id = kqid_to_id(ns, qid);
> 
> kqid and qid are the same thing just in a different encoding.
> Emphasizing the quota identifier instead of the kernel vs user encoding
> change is paying attention to the wrong thing.

Not from a quota perspective. The only thing the quota code really
cares about is the quota identifier, not the encoding.

Fundamentally, from_kqid() doen't tell me anything about what I'm
getting from the kqid. There's code all over the place that used the
"<format>_to_<other format>" convention because it's obvious what is
being converted from/to. e.g. cpu_to_beXX, compat_to_ptr,
dma_to_phys, pfn_to_page, etc.  Best practises say "follow existing
conventions".

> Using make_kqid and from_kqid follows the exact same conventions as I have
> established for kuids and kgids.  So if you learn one you have learned
> them all.

For those of us that have to look at it once every few months,
following the same conventions as all the other code in the kernel
(i.e. kqid_to_id()) tells me everything I need to know without
having to go through the process of looking up the unusual
from_kqid() function and then from_kuid() to find out what it is
actually doing....

> >> make_kqid_invalid, make_kqid_uid, make_kqid_gid.
> >
> > and these named something like uid_to_kqid()
> 
> The last two are indeed weird, and definitely not the common case,
> since there is no precedent I can almost see doing something different
> but I don't see a good case for a different name.

There's plenty of precendence in other code that converts format.
A very common convention that is used everywhere is DEFINE_...().
That would be make the code easier to grasp than "make...".

> >> Change struct dquot dq_id to a struct kqid and remove the now
> >> unecessary dq_type.
> >> 
> >> Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
> >> and dquot_set_dqblk to use struct kqid.
> >> 
> >> Make minimal changes to ext3, ext4, gfs2, ocfs2, and xfs to deal with
> >> the change in quota structures and signatures.  The ocfs2 changes are
> >> larger than most because of the extensive tracing throughout the ocfs2
> >> quota code that prints out dq_id.
> >
> > How did you test that this all works?
> 
> By making it a compile error if you get a conversion wrong and making it
> a rule not to make any logic changes.
>
> That combined with code review
> and running the code a bit to make certain I did not horribly mess up.

But no actual regression testing. You're messing with code that I
will have to triage when it goes wrong for a user, so IMO your code
has to pass the same bar as the code I write has to pass for review
- please regression test your code and write new regression tests
for new functionality.

> > e.g. run xfstests -g quota on
> > each of those filesystems and check for no regressions? And if you
> > wrote any tests, can you convert them to be part of xfstests so that
> > namespace aware quotas get tested regularly?
> 
> I have not written any tests, and running the xfstests in a namespace
> should roughly be a matter of "unshare -U xfstest -g quota"  It isn't
> quite that easy because  /proc/self/uid_map and /proc/self/gid_map need

Asking people to run the entire regression test suite differently
and with special setup magic won't get the code tested regularly.
Writing a new, self contained test that exercises quota in multiple
namespaces simultaneously is what is needed - that way people who
don't even know that namespaces exist will be regression testing
it...

> >> --- a/include/linux/quota.h
> >> +++ b/include/linux/quota.h
> >> @@ -181,10 +181,161 @@ enum {
> >>  #include <linux/dqblk_v2.h>
> >>  
> >>  #include <linux/atomic.h>
> >> +#include <linux/uidgid.h>
> >>  
> >>  typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
> >>  typedef long long qsize_t;	/* Type in which we store sizes */
> >
> > From fs/xfs/xfs_types.h:
> >
> > typedef __uint32_t              prid_t;         /* project ID */
> >
> > Perhaps it would be better to have an official kprid_t definition
> > here, i.e:
> 
> We can always improve.  For this patch I don't see it making a
> useful difference.

If you are touching the code and introducing new types and concepts
at a global level, then this is precisely when you should be getting
the definitions of those new types correct.

> prid_t isn't exported to non xfs code.  The project id is already
> stored in an unsigned int or a qid_t.

You missed my point - that you are now making a distinction
outside XFS about project quotas. i.e. effectively making it
a first-class quota citizen. That means it needs an equivalent
global type definition and not rely implictly on some subsystem
getting the type conversion correct.

Indeed, isn't that the entire point of your patch set - using the
correct global types throughout the stack to avoid type conversion
errors?

> >> +struct kqid {			/* Type in which we store the quota identifier */
> >> +	union {
> >> +		kuid_t uid;
> >> +		kgid_t gid;
> >> +		qid_t prj;
> >
> > 		kprid_t prid;
> >
> 
> Hmm.  The naming here is interesting.  No one calls the project id prj.
> So I have an avoidable inconsistency here.  xfs most commonly uses
> projid and occassionally calls it prid.

Wrong way around. XFS uses projid in one place - xfs_set_projid() -
and prid in 30 others. The type is xfs_prid_t as well. prid is much
prefered to projid...

> So I am inclined to rename this field projid, but I don't know if it is
> worth respinning the patch for something so trivial.

I'd like to think you are joking, given that the patch series is all
about using consistent, verifiable identifiers... :/

> >> +	};
> >> +	int type; /* USRQUOTA (uid) or GRPQUOTA (gid) or XQM_PRJQUOTA (prj) */
> >> +};
> >> +
> >> +static inline bool qid_eq(struct kqid left, struct kqid right)
> >> +{
> >> +	if (left.type != right.type)
> >> +		return false;
> >> +	switch(left.type) {
> >> +	case USRQUOTA:
> >> +		return uid_eq(left.uid, right.uid);
> >> +	case GRPQUOTA:
> >> +		return gid_eq(left.gid, right.gid);
> >> +	case XQM_PRJQUOTA:
> >> +		return left.prj == right.prj;
> >> +	default:
> >> +		BUG();
> >
> > BUG()? Seriously? The most this justifies is a WARN_ON_ONCE() to
> > indicate a potential programming error, not bringing down the entire
> > machine.
> 
> Dead serious.  Any other type value is impossible and unsupported.

So make the compiler check it (use an enum, or perhaps
BUILD_BUG_ON()).  Don't bring the machine down because you haven't
thought about error handling properly.

> BUG is not panic.  BUG is an oops. BUG won't bring down the machine
> unless the sysadmin wants it too.

panic, oops, it's the same thing to most enterprise distros as they
are configured to dump the kernel or reboot when an oops occurs.

Even if they are not configured this way, any oops that occurs with
a filesystem lock held (like these will) will eventually result in a
filesystem deadlock and subsequent fatal application and/or system
hang. This most definitely is not a condition that should be
triggering a fatal error.

> Beyond that I am not interesting in supporting exploitable abuse
> of this type.

/me jumps up and down on his seat excitedly

Oh, Oh, it's Security Theatre time! Can I have a go!? Please?

If someone can cause an unsupported quota type to appear
in this field, using BUG() creates a wonderful DOS exploit...

:)

> >> +static inline bool qid_lt(struct kqid left, struct kqid right)
> >> +{
> >> +	if (left.type < right.type)
> >> +		return true;
> >> +	if (left.type > right.type)
> >> +		return false;
> >> +	switch (left.type) {
> >> +	case USRQUOTA:
> >> +		return uid_lt(left.uid, right.uid);
> >> +	case GRPQUOTA:
> >> +		return gid_lt(left.gid, right.gid);
> >> +	case XQM_PRJQUOTA:
> >> +		return left.prj < right.prj;
> >> +	default:
> >> +		BUG();
> >> +	}
> >> +}
> >
> > What is this function used for? it's not referenced at all by the
> > patch, and there's no documentation/comments explaining why it
> > exists or how it is intended to be used....
> 
> This function is introduced early, but it is needed for gfs2 as
> performs a sort of quota identifiers.

Introduce it when it is used so the correctness can be determined in
the context that uses it.

> >> +static inline qid_t from_kqid(struct user_namespace *user_ns, struct kqid qid)
> >> +{
> >> +	switch (qid.type) {
> >> +	case USRQUOTA:
> >> +		return from_kuid(user_ns, qid.uid);
> >> +	case GRPQUOTA:
> >> +		return from_kgid(user_ns, qid.gid);
> >> +	case XQM_PRJQUOTA:
> >> +		return (user_ns == &init_user_ns) ? qid.prj : -1;
> >> +	default:
> >> +		BUG();
> >> +	}
> >> +}
> >
> > Oh, this can return an error. That's only checked in a coupl eof
> > places this function is called. it needs tobe checked everywhere,
> > otherwise we now have the possibility of quota usage being accounted
> > to uid/gid/prid 0xffffffff when namespace matches are not found.
> 
> No this is not an error condition.  Returning -1 is the mapping that is
> used when there is not a mapping entry.
>
> Depending on the circumstances not having a mapping can be an error,
> but it can also be a don't care condition.

Which the XFS code would then use as the quota ID for accounting.
That's wrong. So, not having a mapping in this case is an error than
needs to be handled. You didn't add any error handling.

> All in kernel values are defined as having a mapping into the initial
> user namespace.
> 
> Looking at my tree the only calls of from_kqid not mapping the id
> into the initial user namespace are from_kqid_munged and they report
> to userspace.  from_kqid_munged returns fs_overflowuid or fs_overflowgid
> in case of a mapping failure.
>
> projects ids can only be accessed if capable(CAP_SYS_ADMIN) which
> you can only have in the initial user namespace so for now there will
> alwasy be a mapping for project ids.

from_kuid and from_kgid can return -1 when a mapping fails, so it is
not just project quotas that are at issue here. Returning -1 as a
quota id is almost always going to be an invalid ID. If you can't
account quota correctly, then the operation should not be allowed to
proceed. IOWs, no mapping is an error from a quota perspective.

And FWIW, explanations like this need to be in the code....

> >> +static inline qid_t from_kqid_munged(struct user_namespace *user_ns,
> >> +				   struct kqid qid)
> >
> > What does munging do to the return value? how is it different to
> > from_kqid()? Document your API....
> 
> This bit certainly certainly could use a bit more explanation.

Yes, the lack of comments in your code is a bit disturbing.

> Mapping of uids and gids from one domain to another is not new in linux.
> It originates with the transition from 16bit identifiers to 32bit
> identifiers.  In most places when there is a 32bit identifier that can
> not be represented we return a fs_overflowid aka (u16)-2 aka nobody.
> 
> So in general when we want to pass a value to userspace from_kqid_munged
> is called, and if there is a mapping failure we report the value that
> userspace set fs_overflowuid or fs_overflowgid to.  For project ids it
> which are restricted to the initial user namespace no mapping failures
> can occur.

Please add this as a comment to the code.

> >> +static inline struct kqid make_kqid_uid(kuid_t uid)
> >> +{
> >> +	struct kqid kqid = {
> >> +		.type = USRQUOTA,
> >> +		.uid  = uid,
> >> +	};
> >> +	return kqid;
> >> +}
> >
> > Isn't this sort of construct frowned upon? i.e. returning a
> > structure out of scope? It may be inline code and hence work, but
> > this strikes me as a landmine waiting for someone to tread on....
> 
> Not at all because I am returning the structure by value.
> 
> Return a structure by reference is the case that doesn't work.

Right, but you completely missed my point. It's unconventional,
tricky code - returning a structure by value is not something that
is commonly used. If I have to stop and think hard about why 5 lines
of apparently simple code is really OK, then IMO you are doing
something wrong. I might only look at this once every 6 months - I
don't want to have to spend time working this tricky stuff out
every time I look at it...

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] userns: Add basic quota support v4
  2012-08-31  1:17                   ` Dave Chinner
@ 2012-09-05  5:20                     ` Eric W. Biederman
  2012-09-20  1:28                     ` Eric W. Biederman
  1 sibling, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-09-05  5:20 UTC (permalink / raw)
  To: Dave Chinner
  Cc: Jan Kara, linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
	Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das



Dave Chinner <david@fromorbit.com> writes:

> On Wed, Aug 29, 2012 at 02:31:26AM -0700, Eric W. Biederman wrote:
>> 
>> Dave thanks for taking the time to take a detailed look at this code.
>> 
>> Dave Chinner <david@fromorbit.com> writes:
>> 
>> > On Tue, Aug 28, 2012 at 12:09:56PM -0700, Eric W. Biederman wrote:



>> > How did you test that this all works?
>> 
>> By making it a compile error if you get a conversion wrong and making it
>> a rule not to make any logic changes.
>>
>> That combined with code review
>> and running the code a bit to make certain I did not horribly mess up.
>
> But no actual regression testing. You're messing with code that I
> will have to triage when it goes wrong for a user, so IMO your code
> has to pass the same bar as the code I write has to pass for review
> - please regression test your code and write new regression tests
> for new functionality.

I like the idea of regression tests.  In practice and also with xfstests
I find that I spend lots of time debugging and fixing and improving
tests and at the end of the day I find regression tests tell me
very little.

But I did figure I should give them a try since I have a rather
substantial xfs patch in my queue.

I added tests 111 and 232 to the expunged file because the don't
run to completion.

ltp/rwtest.sh needs to be run with #!/bin/bash instead of #!/bin/sh as
it contains serveral bashisms.

You need to have gawk installed instead of mawk because of a non-posix
call to asort somewhere in the test framework.

On my branch userns-always-map-user-v53 or on v3.6-rc1+
xfs: check for possible overflow in xfs_ioc_trim
xfs: unlock the AGI buffer when looping in xfs_dialloc
xfs: fix uninitialised variable in xfs_rtbuf_get()

When I run ./check in the from xfstests I get

Tue Sep  4 05:06:12 PDT 2012
    001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018
    019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036
    037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054
    055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072
    073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090
    091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108
    109 110 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
    128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
    146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
    164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
    182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
    200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
    218 219 220 221 222 223 224 225 226 227 228 229 230 231 233 234 235 236
    237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
    255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
    273 274 275 276 277 278 279 280 281 282 283 284 285 286
Not run:2
Failures: 018 081 082 106 107 136 167 171 206 219 229 234 250 280
Failed 14 of 165 tests

But since the results came back the same either way I think the tests
told me all they can.  The 14 failed tests and 1 bug don't seem to say
good things about xfs in general though.

Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [REVIEW][PATCH 10/15] userns: Convert debugfs to use kuid/kgid where appropriate.
  2012-08-26  0:03 ` [REVIEW][PATCH 10/15] userns: Convert debugfs to use kuid/kgid where appropriate Eric W. Biederman
@ 2012-09-05 21:09   ` Greg Kroah-Hartman
  0 siblings, 0 replies; 37+ messages in thread
From: Greg Kroah-Hartman @ 2012-09-05 21:09 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn, David Miller

On Sat, Aug 25, 2012 at 05:03:41PM -0700, Eric W. Biederman wrote:
> 
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [REVIEW][PATCH 12/15] userns: Convert drm to use kuid and kgid and struct pid where appropriate
  2012-08-26  0:05 ` [REVIEW][PATCH 12/15] userns: Convert drm to use kuid and kgid and struct pid where appropriate Eric W. Biederman
@ 2012-09-13  1:31   ` Dave Airlie
  2012-09-13  2:14     ` Eric W. Biederman
  0 siblings, 1 reply; 37+ messages in thread
From: Dave Airlie @ 2012-09-13  1:31 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, David Airlie, dri-devel

> Blink Blink this had not been converted to use struct pid ages ago?
>
> - On drm open capture the openers kuid and struct pid.
> - On drm close release the kuid and struct pid
> - When reporting the uid and pid convert the kuid and struct pid
>   into values in the appropriate namespace.
>

Hi Eric,

I'm fine with this seems okay, do you want me to merge it via drm-next?

Dave.

> Cc: David Airlie <airlied@linux.ie>
> Cc: dri-devel@lists.freedesktop.org
> Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
> ---
>  drivers/gpu/drm/drm_fops.c  |    3 ++-
>  drivers/gpu/drm/drm_info.c  |    5 +++--
>  drivers/gpu/drm/drm_ioctl.c |    4 ++--
>  include/drm/drmP.h          |    4 ++--
>  init/Kconfig                |    1 -
>  5 files changed, 9 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
> index 5062eec..433d2fa 100644
> --- a/drivers/gpu/drm/drm_fops.c
> +++ b/drivers/gpu/drm/drm_fops.c
> @@ -251,7 +251,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
>         filp->private_data = priv;
>         priv->filp = filp;
>         priv->uid = current_euid();
> -       priv->pid = task_pid_nr(current);
> +       priv->pid = get_pid(task_pid(current));
>         priv->minor = idr_find(&drm_minors_idr, minor_id);
>         priv->ioctl_count = 0;
>         /* for compatibility root is always authenticated */
> @@ -524,6 +524,7 @@ int drm_release(struct inode *inode, struct file *filp)
>         if (drm_core_check_feature(dev, DRIVER_PRIME))
>                 drm_prime_destroy_file_private(&file_priv->prime);
>
> +       put_pid(file_priv->pid);
>         kfree(file_priv);
>
>         /* ========================================================
> diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
> index 8928edb..eb0af39 100644
> --- a/drivers/gpu/drm/drm_info.c
> +++ b/drivers/gpu/drm/drm_info.c
> @@ -191,8 +191,9 @@ int drm_clients_info(struct seq_file *m, void *data)
>                 seq_printf(m, "%c %3d %5d %5d %10u %10lu\n",
>                            priv->authenticated ? 'y' : 'n',
>                            priv->minor->index,
> -                          priv->pid,
> -                          priv->uid, priv->magic, priv->ioctl_count);
> +                          pid_vnr(priv->pid),
> +                          from_kuid_munged(seq_user_ns(m), priv->uid),
> +                          priv->magic, priv->ioctl_count);
>         }
>         mutex_unlock(&dev->struct_mutex);
>         return 0;
> diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
> index 64a62c6..39a4383 100644
> --- a/drivers/gpu/drm/drm_ioctl.c
> +++ b/drivers/gpu/drm/drm_ioctl.c
> @@ -215,8 +215,8 @@ int drm_getclient(struct drm_device *dev, void *data,
>         list_for_each_entry(pt, &dev->filelist, lhead) {
>                 if (i++ >= idx) {
>                         client->auth = pt->authenticated;
> -                       client->pid = pt->pid;
> -                       client->uid = pt->uid;
> +                       client->pid = pid_vnr(pt->pid);
> +                       client->uid = from_kuid_munged(current_user_ns(), pt->uid);
>                         client->magic = pt->magic;
>                         client->iocs = pt->ioctl_count;
>                         mutex_unlock(&dev->struct_mutex);
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index d6b67bb..9bc5c6a 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -426,8 +426,8 @@ struct drm_prime_file_private {
>  /** File private data */
>  struct drm_file {
>         int authenticated;
> -       pid_t pid;
> -       uid_t uid;
> +       struct pid *pid;
> +       kuid_t uid;
>         drm_magic_t magic;
>         unsigned long ioctl_count;
>         struct list_head lhead;
> diff --git a/init/Kconfig b/init/Kconfig
> index d849ba2..2a388e5 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -930,7 +930,6 @@ config UIDGID_CONVERTED
>         depends on FS_POSIX_ACL = n
>         depends on QUOTA = n
>         depends on QUOTACTL = n
> -       depends on DRM = n
>
>         # Networking
>         depends on NET_9P = n
> --
> 1.7.5.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [REVIEW][PATCH 12/15] userns: Convert drm to use kuid and kgid and struct pid where appropriate
  2012-09-13  1:31   ` Dave Airlie
@ 2012-09-13  2:14     ` Eric W. Biederman
  2012-09-13  3:29       ` Dave Airlie
  0 siblings, 1 reply; 37+ messages in thread
From: Eric W. Biederman @ 2012-09-13  2:14 UTC (permalink / raw)
  To: Dave Airlie
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, David Airlie, dri-devel

Dave Airlie <airlied@gmail.com> writes:

>> Blink Blink this had not been converted to use struct pid ages ago?
>>
>> - On drm open capture the openers kuid and struct pid.
>> - On drm close release the kuid and struct pid
>> - When reporting the uid and pid convert the kuid and struct pid
>>   into values in the appropriate namespace.
>>
>
> Hi Eric,
>
> I'm fine with this seems okay, do you want me to merge it via
> drm-next?

My plan is to merge it via my user namespace tree.  And since you have
responed positively I will add your acked-by.  There are some nice
synergies when I get all of the changes in one tree.

If for some reason you want to carry this in your drm tree we can work
something out.

In this case I expect the change isn't big enough to worry about.

Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [REVIEW][PATCH 12/15] userns: Convert drm to use kuid and kgid and struct pid where appropriate
  2012-09-13  2:14     ` Eric W. Biederman
@ 2012-09-13  3:29       ` Dave Airlie
  0 siblings, 0 replies; 37+ messages in thread
From: Dave Airlie @ 2012-09-13  3:29 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, David Airlie, dri-devel

On Thu, Sep 13, 2012 at 12:14 PM, Eric W. Biederman
<ebiederm@xmission.com> wrote:
> Dave Airlie <airlied@gmail.com> writes:
>
>>> Blink Blink this had not been converted to use struct pid ages ago?
>>>
>>> - On drm open capture the openers kuid and struct pid.
>>> - On drm close release the kuid and struct pid
>>> - When reporting the uid and pid convert the kuid and struct pid
>>>   into values in the appropriate namespace.
>>>
>>
>> Hi Eric,
>>
>> I'm fine with this seems okay, do you want me to merge it via
>> drm-next?
>
> My plan is to merge it via my user namespace tree.  And since you have
> responed positively I will add your acked-by.  There are some nice
> synergies when I get all of the changes in one tree.
>
> If for some reason you want to carry this in your drm tree we can work
> something out.
>
> In this case I expect the change isn't big enough to worry about.

No all fine by me,

for formality sake:
Acked-by: Dave Airlie <airlied@redhat.com>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] userns: Add basic quota support v4
  2012-08-31  1:17                   ` Dave Chinner
  2012-09-05  5:20                     ` Eric W. Biederman
@ 2012-09-20  1:28                     ` Eric W. Biederman
  1 sibling, 0 replies; 37+ messages in thread
From: Eric W. Biederman @ 2012-09-20  1:28 UTC (permalink / raw)
  To: Dave Chinner
  Cc: Jan Kara, linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, Mark Fasheh, Joel Becker,
	Ben Myers, Alex Elder, Dmitry Monakhov, Abhijith Das


Dave thank you earlier taking some time to do review.  It made me
realize that my code was not as mature as it needed to be.

That said you missed a lot of important details, and I will aim at
to address some of the highlights.

Precedent in naming. <uidgid.h> that has been merged since 3.5, earlier
there is make_pte.   Much of your review sounds like you are unhappy
with the general infrastructure that was built for user namespaces,
and already merged.  Short of an overwhelmingly better suggestion
at this point I am not going to revisit naming.

Passing structures by value is a core part of the design and a necessity
for strong type safety in C, and again already in common use in the
kernel.

Using BUG on code paths that can not be triggered, simply means that
in that rare and unlikely event there is a clear trace to follow,
and xfs already has plenty of invocations of BUG, some of which
I managed to trigger with the xfs test suite.  So I can not find
much sense in your arguments about being clear that something is a BUG.

Your comments on where xfs uses projid are just laughable.

>> So I am inclined to rename this field projid, but I don't know if it is
>> worth respinning the patch for something so trivial.
>
> I'd like to think you are joking, given that the patch series is all
> about using consistent, verifiable identifiers... :/

The patch series is all about implementing the user namespace.

To make it hard to miss places where conversions need to between the
internal kernel form and the form stored in filesystems or the form that
userspace uses I use types that are not assignment compatible.  Pushing
the types deeper in the code keeps me honest and let's me find cases
I was not expecting like the ioctl interface of xfs that largely
duplicates much of the vfs functionality.

Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2012-09-20  1:28 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-25 23:54 [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
2012-08-25 23:58 ` [REVIEW][PATCH 01/15] userns: Enable building of pf_key sockets when user namespace support is enabled Eric W. Biederman
2012-08-25 23:59 ` [REVIEW][PATCH 02/15] userns: Make credential debugging user namespace safe Eric W. Biederman
2012-08-25 23:59 ` [REVIEW][PATCH 03/15] userns: Convert security/keys to the new userns infrastructure Eric W. Biederman
2012-08-26  0:00 ` [REVIEW][PATCH 04/15] userns: net: Call key_alloc with GLOBAL_ROOT_UID, GLOBAL_ROOT_GID instead of 0, 0 Eric W. Biederman
2012-08-26  0:00 ` [REVIEW][PATCH 05/15] userns: Convert ipc to use kuid and kgid where appropriate Eric W. Biederman
2012-08-26  0:01 ` [REVIEW][PATCH 07/15] userns: Convert taskstats to handle the user and pid namespaces Eric W. Biederman
2012-08-26  0:02 ` [REVIEW][PATCH 09/15] userns: Convert process event connector to handle kuids and kgids Eric W. Biederman
2012-08-26 12:33   ` Evgeniy Polyakov
2012-08-26 13:43     ` Eric W. Biederman
2012-08-26  0:03 ` [REVIEW][PATCH 10/15] userns: Convert debugfs to use kuid/kgid where appropriate Eric W. Biederman
2012-09-05 21:09   ` Greg Kroah-Hartman
2012-08-26  0:04 ` [REVIEW][PATCH 11/15] userns: Teach trace to use from_kuid Eric W. Biederman
2012-08-26  0:18   ` Steven Rostedt
2012-08-26  0:28     ` Eric W. Biederman
2012-08-26  0:05 ` [REVIEW][PATCH 12/15] userns: Convert drm to use kuid and kgid and struct pid where appropriate Eric W. Biederman
2012-09-13  1:31   ` Dave Airlie
2012-09-13  2:14     ` Eric W. Biederman
2012-09-13  3:29       ` Dave Airlie
2012-08-26  0:07 ` [REVIEW][PATCH 15/15] userns: Convert configfs to use kuid and kgid " Eric W. Biederman
2012-08-26 13:00 ` [PATCH 06/15] userns: Convert audit " Eric W. Biederman
     [not found] ` <9E0E8AAC-9548-4009-AE29-D368244D8EEA@dubeyko.com>
2012-08-26 14:25   ` [REVIEW][PATCH 0/15] userns subsystem conversions Eric W. Biederman
     [not found] ` <87harqecvk.fsf@xmission.com>
2012-08-27  8:50   ` [REVIEW][PATCH 13/15] userns: Add basic quota support Jan Kara
2012-08-27 15:54     ` Eric W. Biederman
2012-08-28  0:12     ` [PATCH] userns: Add basic quota support v2 Eric W. Biederman
2012-08-28  9:05       ` Jan Kara
2012-08-28  9:44         ` Boaz Harrosh
2012-08-28 17:34         ` Eric W. Biederman
2012-08-28 17:36           ` [PATCH] userns: Add basic quota support v3 Eric W. Biederman
2012-08-28 17:51           ` [PATCH] userns: Add basic quota support v2 Jan Kara
2012-08-28 19:09             ` [PATCH] userns: Add basic quota support v4 Eric W. Biederman
2012-08-29  2:10               ` Dave Chinner
2012-08-29  9:31                 ` Eric W. Biederman
2012-08-31  1:17                   ` Dave Chinner
2012-09-05  5:20                     ` Eric W. Biederman
2012-09-20  1:28                     ` Eric W. Biederman
2012-08-27  8:58   ` [REVIEW][PATCH 13/15] userns: Add basic quota support Steven Whitehouse

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).