diff mbox

userns: Add basic quota support v4

Message ID 87y5ky6dff.fsf_-_@xmission.com
State Not Applicable, archived
Delegated to: David Miller
Headers show

Commit Message

Eric W. Biederman Aug. 28, 2012, 7:09 p.m. UTC
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(-)

Comments

Dave Chinner Aug. 29, 2012, 2:10 a.m. UTC | #1
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.
Eric W. Biederman Aug. 29, 2012, 9:31 a.m. UTC | #2
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

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dave Chinner Aug. 31, 2012, 1:17 a.m. UTC | #3
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.
Eric W. Biederman Sept. 5, 2012, 5:20 a.m. UTC | #4
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
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Eric W. Biederman Sept. 20, 2012, 1:28 a.m. UTC | #5
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
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

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