From patchwork Wed Feb 11 15:11:48 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konstantin Khlebnikov X-Patchwork-Id: 5813301 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 4B3BEBF440 for ; Wed, 11 Feb 2015 15:14:33 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4737E201C0 for ; Wed, 11 Feb 2015 15:14:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3429C200D0 for ; Wed, 11 Feb 2015 15:14:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752974AbbBKPMw (ORCPT ); Wed, 11 Feb 2015 10:12:52 -0500 Received: from forward-corp1m.cmail.yandex.net ([5.255.216.100]:35325 "EHLO forward-corp1m.cmail.yandex.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752354AbbBKPL7 (ORCPT ); Wed, 11 Feb 2015 10:11:59 -0500 Received: from smtpcorp1m.mail.yandex.net (smtpcorp1m.mail.yandex.net [77.88.61.150]) by forward-corp1m.cmail.yandex.net (Yandex) with ESMTP id C7338603DF; Wed, 11 Feb 2015 18:11:49 +0300 (MSK) Received: from smtpcorp1m.mail.yandex.net (localhost [127.0.0.1]) by smtpcorp1m.mail.yandex.net (Yandex) with ESMTP id DDB0C2CA0439; Wed, 11 Feb 2015 18:11:48 +0300 (MSK) Received: from unknown (unknown [2a02:6b8:0:408:f4d2:daa0:d7a5:c625]) by smtpcorp1m.mail.yandex.net (nwsmtp/Yandex) with ESMTPSA id 1dzmZ2c194-BmOmf2PL; Wed, 11 Feb 2015 18:11:48 +0300 (using TLSv1.2 with cipher AES128-SHA (128/128 bits)) (Client certificate not present) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex-team.ru; s=default; t=1423667508; bh=dM9LLMlXPGzFSPUS2/8YUg8SdxsDpSzMcBBZ/pLZKwo=; h=Subject:From:To:Cc:Date:Message-ID:In-Reply-To:References: User-Agent:MIME-Version:Content-Type:Content-Transfer-Encoding; b=DpJbqdMIefS3CB7v86sGXG0wr3KmATeVjG0zZwMdQGDoZ7g5xt91oumD+J2Hx4YvO VD7rJiXQz2ojNP6BS/q3uN5TPPSFwOT6Mxd4J9L/WwLvKO2zRS58K4KAwtuWsZ+nlK CdWGRyvR7m9DFMsX2m/A0s9CnD8ctnknnTALPdPQ= Authentication-Results: smtpcorp1m.mail.yandex.net; dkim=pass header.i=@yandex-team.ru Subject: [PATCH RFC 2/6] quota: adds generic code for enforcing project quota limits From: Konstantin Khlebnikov To: Linux FS Devel , linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Jan Kara , Linux API , containers@lists.linux-foundation.org, Dave Chinner , Andy Lutomirski , Christoph Hellwig , Dmitry Monakhov , "Eric W. Biederman" , Li Xi , Theodore Ts'o , Al Viro Date: Wed, 11 Feb 2015 18:11:48 +0300 Message-ID: <20150211151148.6717.23016.stgit@buzz> In-Reply-To: <20150211151146.6717.62017.stgit@buzz> References: <20150211151146.6717.62017.stgit@buzz> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID,T_RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds support for a new quota type PRJQUOTA for project quota. [ Based on patch by Li Xi ] Permissions: Q_GETQUOTA: allows to query all projects present in current user-namespace Q_SETQUOTA: requires system-wide capability CAP_SYS_ADMIN Signed-off-by: Konstantin Khlebnikov Cc: Li Xi --- fs/quota/dquot.c | 37 +++++++++++++++++++++++++++++++++++-- fs/quota/quota.c | 8 ++++++-- fs/quota/quotaio_v2.h | 6 ++++-- include/linux/quota.h | 1 + include/linux/quotaops.h | 1 + include/uapi/linux/quota.h | 6 ++++-- 6 files changed, 51 insertions(+), 8 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 0ccd4ba..afa5f67 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -1159,8 +1159,8 @@ static int need_print_warning(struct dquot_warn *warn) return uid_eq(current_fsuid(), warn->w_dq_id.uid); case GRPQUOTA: return in_group_p(warn->w_dq_id.gid); - case PRJQUOTA: /* Never taken... Just make gcc happy */ - return 0; + case PRJQUOTA: + return 1; } return 0; } @@ -1399,6 +1399,8 @@ 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; + kprojid_t projid; + got[cnt] = NULL; if (type != -1 && cnt != type) continue; @@ -1409,6 +1411,10 @@ static void __dquot_initialize(struct inode *inode, int type) */ if (i_dquot(inode)[cnt]) continue; + + if (!sb_has_quota_active(sb, cnt)) + continue; + init_needed = 1; switch (cnt) { @@ -1418,6 +1424,13 @@ static void __dquot_initialize(struct inode *inode, int type) case GRPQUOTA: qid = make_kqid_gid(inode->i_gid); break; + case PRJQUOTA: + if (!sb->s_op->get_projid) + continue; + if (sb->s_op->get_projid(inode, &projid)) + continue; + qid = make_kqid_projid(projid); + break; } got[cnt] = dqget(sb, qid); } @@ -1951,6 +1964,22 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) EXPORT_SYMBOL(dquot_transfer); /* + * Helper function for transferring inode into another project. + */ +int dquot_transfer_project(struct inode *inode, kprojid_t projid) +{ + struct dquot *transfer_to[MAXQUOTAS] = {}; + struct super_block *sb = inode->i_sb; + int ret; + + transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(projid)); + ret = __dquot_transfer(inode, transfer_to); + dqput_all(transfer_to); + return ret; +} +EXPORT_SYMBOL(dquot_transfer_project); + +/* * Write info of quota file to disk */ int dquot_commit_info(struct super_block *sb, int type) @@ -2165,6 +2194,10 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, error = -EINVAL; goto out_fmt; } + if (type == PRJQUOTA && !sb->s_op->get_projid) { + error = -EINVAL; + goto out_fmt; + } /* Usage always has to be set... */ if (!(flags & DQUOT_USAGE_ENABLED)) { error = -EINVAL; diff --git a/fs/quota/quota.c b/fs/quota/quota.c index d14a799..0acd1bb 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -30,11 +30,15 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd, case Q_XGETQSTATV: case Q_XQUOTASYNC: break; - /* allow to query information for dquots we "own" */ + /* + * Allow to query information for user/group dquots we "own". + * Allow querying project quota present in our user-namespace. + */ case Q_GETQUOTA: case Q_XGETQUOTA: if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) || - (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id)))) + (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))) || + (type == PRJQUOTA && projid_valid(make_kprojid(current_user_ns(), id)))) break; /*FALLTHROUGH*/ default: diff --git a/fs/quota/quotaio_v2.h b/fs/quota/quotaio_v2.h index f1966b4..4e95430 100644 --- a/fs/quota/quotaio_v2.h +++ b/fs/quota/quotaio_v2.h @@ -13,12 +13,14 @@ */ #define V2_INITQMAGICS {\ 0xd9c01f11, /* USRQUOTA */\ - 0xd9c01927 /* GRPQUOTA */\ + 0xd9c01927, /* GRPQUOTA */\ + 0xd9c03f14, /* PRJQUOTA */\ } #define V2_INITQVERSIONS {\ 1, /* USRQUOTA */\ - 1 /* GRPQUOTA */\ + 1, /* GRPQUOTA */\ + 1, /* PRJQUOTA */\ } /* First generic header */ diff --git a/include/linux/quota.h b/include/linux/quota.h index d534e8e..8bad159 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -50,6 +50,7 @@ #undef USRQUOTA #undef GRPQUOTA +#undef PRJQUOTA enum quota_type { USRQUOTA = 0, /* element used for user quotas */ GRPQUOTA = 1, /* element used for group quotas */ diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index df73258..ba54745 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -104,6 +104,7 @@ int dquot_set_dqblk(struct super_block *sb, struct kqid id, int __dquot_transfer(struct inode *inode, struct dquot **transfer_to); int dquot_transfer(struct inode *inode, struct iattr *iattr); +int dquot_transfer_project(struct inode *inode, kprojid_t projid); static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type) { diff --git a/include/uapi/linux/quota.h b/include/uapi/linux/quota.h index 1f49b83..9c95b2c 100644 --- a/include/uapi/linux/quota.h +++ b/include/uapi/linux/quota.h @@ -36,11 +36,12 @@ #include #include -#define __DQUOT_VERSION__ "dquot_6.5.2" +#define __DQUOT_VERSION__ "dquot_6.6.0" -#define MAXQUOTAS 2 +#define MAXQUOTAS 3 #define USRQUOTA 0 /* element used for user quotas */ #define GRPQUOTA 1 /* element used for group quotas */ +#define PRJQUOTA 2 /* element used for project quotas */ /* * Definitions for the default names of the quotas files. @@ -48,6 +49,7 @@ #define INITQFNAMES { \ "user", /* USRQUOTA */ \ "group", /* GRPQUOTA */ \ + "project", /* PRJQUOTA */ \ "undefined", \ };