From patchwork Wed Aug 9 04:30:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hugh Dickins X-Patchwork-Id: 13347412 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 81AC8C04A94 for ; Wed, 9 Aug 2023 04:31:06 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id F182F6B0071; Wed, 9 Aug 2023 00:31:05 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id EC7FF8D0002; Wed, 9 Aug 2023 00:31:05 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id D689C8D0001; Wed, 9 Aug 2023 00:31:05 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id C508B6B0071 for ; Wed, 9 Aug 2023 00:31:05 -0400 (EDT) Received: from smtpin19.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 7F57A1407A3 for ; Wed, 9 Aug 2023 04:31:05 +0000 (UTC) X-FDA: 81103291290.19.6B43DE5 Received: from mail-yw1-f175.google.com (mail-yw1-f175.google.com [209.85.128.175]) by imf26.hostedemail.com (Postfix) with ESMTP id A951F140007 for ; Wed, 9 Aug 2023 04:31:03 +0000 (UTC) Authentication-Results: imf26.hostedemail.com; dkim=pass header.d=google.com header.s=20221208 header.b=HJptNXYy; dmarc=pass (policy=reject) header.from=google.com; spf=pass (imf26.hostedemail.com: domain of hughd@google.com designates 209.85.128.175 as permitted sender) smtp.mailfrom=hughd@google.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1691555463; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=0QEq4BtWj7XF+SzsAQAvfuVLV+e829beqWHSxHJfrd4=; b=wPWNyAqwilS+O8sWKCRhR+rgMcjDvRvCVfFHHdyDoIuakd1zVCE1Cs6c5Hm2UTx9XXoZ0A W4Tq7xDhlzUBE0FBo9VZRgcDroKf3oSV7/Rg0bmYzH7xBq45YsXK3u63lKVMGBL/BVKpbn zaUHkwA4zfBZZaYKw9k1FFb3XYKIaeI= ARC-Authentication-Results: i=1; imf26.hostedemail.com; dkim=pass header.d=google.com header.s=20221208 header.b=HJptNXYy; dmarc=pass (policy=reject) header.from=google.com; spf=pass (imf26.hostedemail.com: domain of hughd@google.com designates 209.85.128.175 as permitted sender) smtp.mailfrom=hughd@google.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1691555463; a=rsa-sha256; cv=none; b=wtcUEpPKv0EmVjfhkbCU1/C7AEZg0wFL37eZEPatwJQBB0lQKoYtOhAx5ZzyLddAl6OpU2 siyvPGT9LgDLo8dOPXj2VBhX13fpt5wK1zBgYCVm+JEryupIi/JWnSC/Ga3NdpiR2RTN42 f2sm4SIGVAf6dLHdVMINcHsOXjjMzLE= Received: by mail-yw1-f175.google.com with SMTP id 00721157ae682-583a8596e2aso62130337b3.1 for ; Tue, 08 Aug 2023 21:31:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1691555463; x=1692160263; h=mime-version:references:message-id:in-reply-to:subject:cc:to:from :date:from:to:cc:subject:date:message-id:reply-to; bh=0QEq4BtWj7XF+SzsAQAvfuVLV+e829beqWHSxHJfrd4=; b=HJptNXYyAYDNQBptp9KJN1ynN6d4xCu37HYicEN6u5bGotYv6/fxImpozw/WEF6Omm XWZa6948pq1yCfnYIPHZt+ZWG2sDZc0Ek3Xbq0KkHEJlVzDyOWyGO8vqhhio9SGnt+Gy kOUV4G21FiiPWrRBz6qOkWN/8WOKiZKJYBFV/QHl7tlDTu8sZGSQA/DMCaL8SEQ93aJE uIpYmLvLAp3D+BDbdhvTkCuWCOAj3CaJr9KZksD2j4vtQiUBkOMnE2VLOA4pSN3BwmEi ktY+0MhDjLeXRwsjx0AQKAbXt2oJQjNezKGDyUzB6awQdWLnvZ9a/RuBiLKePQBxQa0x YziQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1691555463; x=1692160263; h=mime-version:references:message-id:in-reply-to:subject:cc:to:from :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=0QEq4BtWj7XF+SzsAQAvfuVLV+e829beqWHSxHJfrd4=; b=ONOiyNMxatUsyiBhPc9ID4RLv1sFkcN8JVSA050fYnYHAT+4HA2ME/+MIW7T3XpeqW P5WlRIYte7u/Ehe2jTtSBbgdxunzYSkI9VSdVneAMkznrtuohPAAgRTQdOMc3xKuB/Fn EGX13zlLHk42PnZKUkEvKzh9H0mDQELxYMkw16eoNFSSz3QcrdhlZxXKqQaOv3vSpQoI qiJ1bZGV2ib6rDzLh/AZd+7PoxsvMGwD336XcmXsZD6GpSuYJ9kM3LmmRKRUxIp3fFKj 2wNlKtPffhpZlqOui5WcYUSYEbGcSEw2RjI43jwxowisMeEPPh/Tdzc5RgGjoR/QaCmy 4eVw== X-Gm-Message-State: AOJu0Yy2oRLFhYc5m5/h/ljx3Gf/SLLanyMHUSBjkZLsb5k2wSjDP7iI 1+hDb2iXxgelBEvgrBBNlmjA2Q== X-Google-Smtp-Source: AGHT+IFC/9yEPmxQ2d3jqattfPdMdJ9f0tThZS9o2vogrFxNROEZWWPd9XKK26aiRb6Kf73SCBCPeA== X-Received: by 2002:a25:361d:0:b0:d06:d1ae:dcf2 with SMTP id d29-20020a25361d000000b00d06d1aedcf2mr1670959yba.13.1691555462645; Tue, 08 Aug 2023 21:31:02 -0700 (PDT) Received: from ripple.attlocal.net (172-10-233-147.lightspeed.sntcca.sbcglobal.net. [172.10.233.147]) by smtp.gmail.com with ESMTPSA id d130-20020a254f88000000b00d0b0bbe574asm3212321ybb.44.2023.08.08.21.31.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Aug 2023 21:31:02 -0700 (PDT) Date: Tue, 8 Aug 2023 21:30:59 -0700 (PDT) From: Hugh Dickins X-X-Sender: hugh@ripple.attlocal.net To: Christian Brauner cc: Andrew Morton , Oleksandr Tymoshenko , Carlos Maiolino , Jeff Layton , Chuck Lever , Jan Kara , Miklos Szeredi , Daniel Xu , Chris Down , Tejun Heo , Greg Kroah-Hartman , Matthew Wilcox , Christoph Hellwig , Pete Zaitcev , Helge Deller , Topi Miettinen , Yu Kuai , linux-fsdevel@vger.kernel.org, linux-mm@kvack.org Subject: [PATCH vfs.tmpfs 1/5] xattr: simple_xattr_set() return old_xattr to be freed In-Reply-To: Message-ID: <158c6585-2aa7-d4aa-90ff-f7c3f8fe407c@google.com> References: MIME-Version: 1.0 X-Rspamd-Queue-Id: A951F140007 X-Rspam-User: X-Rspamd-Server: rspam04 X-Stat-Signature: rw64iwaimtyjfzsa1bkskcn8tjnsdu3m X-HE-Tag: 1691555463-563650 X-HE-Meta: U2FsdGVkX19gjlA5qVZZOmyo90nwpBKCyZM53nhebqiiYSSn4mr/KYeKM0yqJOtQ3F8M9ZPvjJzvjRdMUlzPHYCBW9MAM54qApWLxyKELP+q7Yb8xkVQcRY7nRSi0Ze+ShpEFucBqvM2NBqWqeSMymQBKuwyabwCSikrToLJgI49PxpA2SORuGyU1fcS4Bj7M3uTGRtP5KJZ1hwDXmOz62TFWYsFtuonjI08yAqzZfv1tybvtkUC5q4hSZv1WD010iB3uFe2F1xTfQ1Z58OCfg2KMY6QUFtpoOOv1rm9sZq1LVWA6DQF2UxUXWJdXR+NIUGdRnhEcgdPW+10JLj09TUPTBWGbsTNFktXBe8PmdGdu5q5dq8WZH8sbOUuj53vXPQRxmg6vqypzc4Bc2x3cL6gPe6EPwa77dMzPyENpM+EXuIp3EZCllM/3KNM1zR5eqKpTfu/RojpqDkLBlJ+mvujSobUsRHYLDlDf+r6u+vM/uRWV5feO1G2tX939eHLbfIj+pCxI/cCa8XT/dxq6xS5WHCvB7po1+kPQKQBum/+1s4+G8x7nokpg5aCcg8WS8mxp1d5pNyz3YTgCVqc23gFnY4/sHyd8+WuS3iO/HjXSG7DAfJ+JGkqSua9h3sJpslvPvYVWGDdUo5KNDTm/dgEAtllTTaKe1y95x0EumzBwk6HG07RWpa6CHxs8wPfd0SlQBNyAVItS/PWG132WRkkoZrK3JpiD3UzNMk3u5fG4PzeyQsa8QzKJ9L9Ii9Jm1WTonArQbblq/fADzH5Qap9BDrj8qVCMUq9ips6+bK0k7jQMNf4KbgnG7Fe+jbrJ5xunusTM3tL/hV9i7DNXNFDqdppAxE06OEVLaj+yjZ/pv2xvMOy5UlONRVjir8cSon2CNKQpc6qXWja4rpFOCa3qu38ubvk8dAwUlyBaXsoASabj1ybfEOK2HRqEmFrbaimVlGHKyUoD6bH2Lp puSombwQ irEM0ztTgxWLP3jC+Hx9OShw9LtX0erFY5eyWZq9JkyA+WDU53pWi5JL+f4ay/LnZjt/G8MK1skr2zNf6vbISiCDZ8psNz1d2DBGZETK0WvIMWM0gGcEE793Nd4YB7H3pp89PPGJ+r+U7t1toKlP5sFzlnBJgSeolG1eMkH4oM0QQ4iHSJvBXHhBZYVuhc9TPcaaGKC6daANr3gq/qLS0g2ZsfY9wq0GbD/HTKSOEpHFmscBD5AZjRczxCk6jEfIoCV9UejBQKcRxhSsL1pztq3Sy3mMHKizGmqE9yHsxguMTGlL9C8r1dxmgc2phmzkzy2tHzfFKE2gTwX5NLXir5J1l3juM1dh0K4UgTeU3Y/0xdsZdmg+WnvpHcRKbRmD5a5UI9SOoRaSEIu8bpt7gatD1LDk/69CflD46/RM1raNIkhrxcyyhiRDkr96jGdMSEGztl3ES1ENMldLX0IiqIPU8uA== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: tmpfs wants to support limited user extended attributes, but kernfs (or cgroupfs, the only kernfs with KERNFS_ROOT_SUPPORT_USER_XATTR) already supports user extended attributes through simple xattrs: but limited by a policy (128KiB per inode) too liberal to be used on tmpfs. To allow a different limiting policy for tmpfs, without affecting the policy for kernfs, change simple_xattr_set() to return the replaced or removed xattr (if any), leaving the caller to update their accounting then free the xattr (by simple_xattr_free(), renamed from the static free_simple_xattr()). Signed-off-by: Hugh Dickins Reviewed-by: Jan Kara Reviewed-by: Christian Brauner Reviewed-by: Carlos Maiolino --- fs/kernfs/inode.c | 46 +++++++++++++++++++++++++--------------- fs/xattr.c | 51 +++++++++++++++++++-------------------------- include/linux/xattr.h | 7 ++++--- mm/shmem.c | 10 +++++---- 4 files changed, 61 insertions(+), 53 deletions(-) diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index b22b74d1a115..fec5d5f78f07 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -306,11 +306,17 @@ int kernfs_xattr_get(struct kernfs_node *kn, const char *name, int kernfs_xattr_set(struct kernfs_node *kn, const char *name, const void *value, size_t size, int flags) { + struct simple_xattr *old_xattr; struct kernfs_iattrs *attrs = kernfs_iattrs(kn); if (!attrs) return -ENOMEM; - return simple_xattr_set(&attrs->xattrs, name, value, size, flags, NULL); + old_xattr = simple_xattr_set(&attrs->xattrs, name, value, size, flags); + if (IS_ERR(old_xattr)) + return PTR_ERR(old_xattr); + + simple_xattr_free(old_xattr); + return 0; } static int kernfs_vfs_xattr_get(const struct xattr_handler *handler, @@ -342,7 +348,7 @@ static int kernfs_vfs_user_xattr_add(struct kernfs_node *kn, { atomic_t *sz = &kn->iattr->user_xattr_size; atomic_t *nr = &kn->iattr->nr_user_xattrs; - ssize_t removed_size; + struct simple_xattr *old_xattr; int ret; if (atomic_inc_return(nr) > KERNFS_MAX_USER_XATTRS) { @@ -355,13 +361,18 @@ static int kernfs_vfs_user_xattr_add(struct kernfs_node *kn, goto dec_size_out; } - ret = simple_xattr_set(xattrs, full_name, value, size, flags, - &removed_size); - - if (!ret && removed_size >= 0) - size = removed_size; - else if (!ret) + old_xattr = simple_xattr_set(xattrs, full_name, value, size, flags); + if (!old_xattr) return 0; + + if (IS_ERR(old_xattr)) { + ret = PTR_ERR(old_xattr); + goto dec_size_out; + } + + ret = 0; + size = old_xattr->size; + simple_xattr_free(old_xattr); dec_size_out: atomic_sub(size, sz); dec_count_out: @@ -376,18 +387,19 @@ static int kernfs_vfs_user_xattr_rm(struct kernfs_node *kn, { atomic_t *sz = &kn->iattr->user_xattr_size; atomic_t *nr = &kn->iattr->nr_user_xattrs; - ssize_t removed_size; - int ret; + struct simple_xattr *old_xattr; - ret = simple_xattr_set(xattrs, full_name, value, size, flags, - &removed_size); + old_xattr = simple_xattr_set(xattrs, full_name, value, size, flags); + if (!old_xattr) + return 0; - if (removed_size >= 0) { - atomic_sub(removed_size, sz); - atomic_dec(nr); - } + if (IS_ERR(old_xattr)) + return PTR_ERR(old_xattr); - return ret; + atomic_sub(old_xattr->size, sz); + atomic_dec(nr); + simple_xattr_free(old_xattr); + return 0; } static int kernfs_vfs_user_xattr_set(const struct xattr_handler *handler, diff --git a/fs/xattr.c b/fs/xattr.c index e7bbb7f57557..ba37a8f5cfd1 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -1040,12 +1040,12 @@ const char *xattr_full_name(const struct xattr_handler *handler, EXPORT_SYMBOL(xattr_full_name); /** - * free_simple_xattr - free an xattr object + * simple_xattr_free - free an xattr object * @xattr: the xattr object * * Free the xattr object. Can handle @xattr being NULL. */ -static inline void free_simple_xattr(struct simple_xattr *xattr) +void simple_xattr_free(struct simple_xattr *xattr) { if (xattr) kfree(xattr->name); @@ -1164,7 +1164,6 @@ int simple_xattr_get(struct simple_xattrs *xattrs, const char *name, * @value: the value to store along the xattr * @size: the size of @value * @flags: the flags determining how to set the xattr - * @removed_size: the size of the removed xattr * * Set a new xattr object. * If @value is passed a new xattr object will be allocated. If XATTR_REPLACE @@ -1181,29 +1180,27 @@ int simple_xattr_get(struct simple_xattrs *xattrs, const char *name, * nothing if XATTR_CREATE is specified in @flags or @flags is zero. For * XATTR_REPLACE we fail as mentioned above. * - * Return: On success zero and on error a negative error code is returned. + * Return: On success, the removed or replaced xattr is returned, to be freed + * by the caller; or NULL if none. On failure a negative error code is returned. */ -int simple_xattr_set(struct simple_xattrs *xattrs, const char *name, - const void *value, size_t size, int flags, - ssize_t *removed_size) +struct simple_xattr *simple_xattr_set(struct simple_xattrs *xattrs, + const char *name, const void *value, + size_t size, int flags) { - struct simple_xattr *xattr = NULL, *new_xattr = NULL; + struct simple_xattr *old_xattr = NULL, *new_xattr = NULL; struct rb_node *parent = NULL, **rbp; int err = 0, ret; - if (removed_size) - *removed_size = -1; - /* value == NULL means remove */ if (value) { new_xattr = simple_xattr_alloc(value, size); if (!new_xattr) - return -ENOMEM; + return ERR_PTR(-ENOMEM); new_xattr->name = kstrdup(name, GFP_KERNEL); if (!new_xattr->name) { - free_simple_xattr(new_xattr); - return -ENOMEM; + simple_xattr_free(new_xattr); + return ERR_PTR(-ENOMEM); } } @@ -1217,12 +1214,12 @@ int simple_xattr_set(struct simple_xattrs *xattrs, const char *name, else if (ret > 0) rbp = &(*rbp)->rb_right; else - xattr = rb_entry(*rbp, struct simple_xattr, rb_node); - if (xattr) + old_xattr = rb_entry(*rbp, struct simple_xattr, rb_node); + if (old_xattr) break; } - if (xattr) { + if (old_xattr) { /* Fail if XATTR_CREATE is requested and the xattr exists. */ if (flags & XATTR_CREATE) { err = -EEXIST; @@ -1230,12 +1227,10 @@ int simple_xattr_set(struct simple_xattrs *xattrs, const char *name, } if (new_xattr) - rb_replace_node(&xattr->rb_node, &new_xattr->rb_node, - &xattrs->rb_root); + rb_replace_node(&old_xattr->rb_node, + &new_xattr->rb_node, &xattrs->rb_root); else - rb_erase(&xattr->rb_node, &xattrs->rb_root); - if (!err && removed_size) - *removed_size = xattr->size; + rb_erase(&old_xattr->rb_node, &xattrs->rb_root); } else { /* Fail if XATTR_REPLACE is requested but no xattr is found. */ if (flags & XATTR_REPLACE) { @@ -1260,12 +1255,10 @@ int simple_xattr_set(struct simple_xattrs *xattrs, const char *name, out_unlock: write_unlock(&xattrs->lock); - if (err) - free_simple_xattr(new_xattr); - else - free_simple_xattr(xattr); - return err; - + if (!err) + return old_xattr; + simple_xattr_free(new_xattr); + return ERR_PTR(err); } static bool xattr_is_trusted(const char *name) @@ -1386,7 +1379,7 @@ void simple_xattrs_free(struct simple_xattrs *xattrs) rbp_next = rb_next(rbp); xattr = rb_entry(rbp, struct simple_xattr, rb_node); rb_erase(&xattr->rb_node, &xattrs->rb_root); - free_simple_xattr(xattr); + simple_xattr_free(xattr); rbp = rbp_next; } } diff --git a/include/linux/xattr.h b/include/linux/xattr.h index d591ef59aa98..e37fe667ae04 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -116,11 +116,12 @@ struct simple_xattr { void simple_xattrs_init(struct simple_xattrs *xattrs); void simple_xattrs_free(struct simple_xattrs *xattrs); struct simple_xattr *simple_xattr_alloc(const void *value, size_t size); +void simple_xattr_free(struct simple_xattr *xattr); int simple_xattr_get(struct simple_xattrs *xattrs, const char *name, void *buffer, size_t size); -int simple_xattr_set(struct simple_xattrs *xattrs, const char *name, - const void *value, size_t size, int flags, - ssize_t *removed_size); +struct simple_xattr *simple_xattr_set(struct simple_xattrs *xattrs, + const char *name, const void *value, + size_t size, int flags); ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, char *buffer, size_t size); void simple_xattr_add(struct simple_xattrs *xattrs, diff --git a/mm/shmem.c b/mm/shmem.c index 0f83d86fd8b4..df3cabf54206 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3595,15 +3595,17 @@ static int shmem_xattr_handler_set(const struct xattr_handler *handler, size_t size, int flags) { struct shmem_inode_info *info = SHMEM_I(inode); - int err; + struct simple_xattr *old_xattr; name = xattr_full_name(handler, name); - err = simple_xattr_set(&info->xattrs, name, value, size, flags, NULL); - if (!err) { + old_xattr = simple_xattr_set(&info->xattrs, name, value, size, flags); + if (!IS_ERR(old_xattr)) { + simple_xattr_free(old_xattr); + old_xattr = NULL; inode->i_ctime = current_time(inode); inode_inc_iversion(inode); } - return err; + return PTR_ERR(old_xattr); } static const struct xattr_handler shmem_security_xattr_handler = {