From patchwork Tue Jun 27 20:53:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 13295026 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 C3B4DEB64D9 for ; Tue, 27 Jun 2023 20:53:14 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 60DEF8D0003; Tue, 27 Jun 2023 16:53:14 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 5A2338D0001; Tue, 27 Jun 2023 16:53:14 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 410A38D0003; Tue, 27 Jun 2023 16:53:14 -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 29FA38D0001 for ; Tue, 27 Jun 2023 16:53:14 -0400 (EDT) Received: from smtpin03.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id CAC0E1605C7 for ; Tue, 27 Jun 2023 20:53:13 +0000 (UTC) X-FDA: 80949727866.03.B7F7ADC Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by imf28.hostedemail.com (Postfix) with ESMTP id DCBD9C0012 for ; Tue, 27 Jun 2023 20:53:11 +0000 (UTC) Authentication-Results: imf28.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=AsfRUUBQ; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf28.hostedemail.com: domain of cel@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=cel@kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1687899192; 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:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=YGaralgLRaoHAX7jqshxsm1kVgaoqcFMmqkjfjAOd0A=; b=VhbvuXU81p5v6WySU2woafP2IjMaVJ/CcunbLQPfmSzQHd/Jz3FKeCqVvoEXTSHop4LoV4 G1TgyFjO5TQXROGEPg75Q2JAjf79CMd8noH22pQgHdQarhaq1o2ED+03SMqBp0OMQ4tG9N t4iuS0l3geHQEvPI4H+/Gl1OURQXg1Y= ARC-Authentication-Results: i=1; imf28.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=AsfRUUBQ; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf28.hostedemail.com: domain of cel@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=cel@kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1687899192; a=rsa-sha256; cv=none; b=lJxUjgpKTIquK9NizDgvdLlcDNrJsVUYH3HCwctO8VaD3F3wYuE8N+TikJNlFWJJqhn0dE 8TTDES4dBgvsmJD6JKPW/yQ31sjS8OpjMiP0qrP3bo9yUeZjX5dODPuvTxz2fhfeL4zC0E 7G7CSE0TGIXXx0xz0XsBGWnyVAKhtN8= Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 1A1DD61233; Tue, 27 Jun 2023 20:53:11 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id E1008C433C9; Tue, 27 Jun 2023 20:53:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1687899190; bh=uDfTpqtgCWtUzszg8NsN8i3VJhtB66ykQkSTdRnCRjc=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=AsfRUUBQvlvcfShVqC49ri0eIUchu7MUUwuUxYHcTnlDnaFyZFi9tESuXmfcmsSo9 IJpfV5N3y5AmG3Pg/Gjgk8dqWZB5Fs7VL6XljyrAT9k5CpbzLdQrYSNrabh2qsuDUa +6KFDB0y1HILKAKPU2PiJMIZw/Xh+avyh8TnKNv7d9LmWcsi9h4EPbQqeJddy13Tm5 YzztQ4Bi9ZBZ96uqJ/9ypl060deYrY/iASHmFqdS7atJi14bAOP+Wr6HuNNW4s0URF C/NhCHUAyNNsfGQl1wxE9fQVPredj3zYSJENuTQrmjX3OP9jgus2WETPhSu1l6mR7/ yOsInYXhHakiA== Subject: [PATCH v5 1/3] libfs: Add directory operations for stable offsets From: Chuck Lever To: viro@zeniv.linux.org.uk, brauner@kernel.org, hughd@google.com, akpm@linux-foundation.org Cc: Chuck Lever , jlayton@redhat.com, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Date: Tue, 27 Jun 2023 16:53:09 -0400 Message-ID: <168789918896.157531.14644838088821804546.stgit@manet.1015granger.net> In-Reply-To: <168789864000.157531.11122232592994999253.stgit@manet.1015granger.net> References: <168789864000.157531.11122232592994999253.stgit@manet.1015granger.net> User-Agent: StGit/1.5 MIME-Version: 1.0 X-Rspamd-Queue-Id: DCBD9C0012 X-Rspam-User: X-Rspamd-Server: rspam05 X-Stat-Signature: ticggzpsyswf3xrmdiwajx9xpmqxe834 X-HE-Tag: 1687899191-949628 X-HE-Meta: U2FsdGVkX18Cxb0nOqcSZzS4ytzC5tKv6WdPzW51reT7As96aUwcWQV9Je3T3hDrZXPBJh6x1+fz/7y3Lsx8SU65eWcQ7jb+I0uIOpF7DICIFKFKQ+tSi6TNH9vptIHyn+cvBHk+SRM8cvXzzwsGo6BeO+zxLYEqbFZvv0c2C3DWU5lHuM7WqSKexHyCCMS/7ajOSB4TM+ro0A2ww4algpmu1JzuCNk7Jg74WmIyrCjJNNYUlQat8yRITUzz7jHACL5lTd9Aby7f5roWYWCy1ed535T4Gl3V8XapAyM7AjFSES/tJAF1nvbZAcv9mKF6DSLfAQIb8I/0+eoaowaaRyu0hFLrlDm57nWdPcq3RB3uZMYkiSJ698gXqSK551l6i1ClQcEm0t+yYBHGPiZf14Vb52ZUhwQAciO7IiX4gq9zjUtDT0AwucGPn2vgInjyC/+Lrcasb3LeA9K+8lJ2gpNLo+F4jEVg88GUY1K+PDSy3w8KF06L4Cof4ycklSltY4RcmbUcmJbwwYeMk6eSoniACQZIoY/1UAWF31lw9gBuP45CC+hWksYIyFNsvABzQwAn/JohExSsZ4ZLjoCm5ROGc+7BgPee2Z/xUPRc2gQnOaZqrRQv4WMKdjADr4eM0Vp25MoDDkR0BG2Tr/sL0uJedHyEnon78Mhv9495Du1x50A4Wck67kcwZ0UQvIUByuidy9srF2Yrdd5zl+l7cHHpkwfgQXSaKmN2qklt7vWGboK7NtzfPnr3cMXYSbHkwfXABztZAE3Z+7AxUIZ4kcG+dW8eJXyUPT0/OEhA1CCaak4/JgW/SBywSg5lFttq730ViHkAPLdJbha9U+fcTti61FD0gIrvRA5nXDjrplA08yKQ7o7x0mvtnxvy6ClFmi20eiJMIiQJrQlZrJLUmYryI6LnUUcEuEDSBeV1b9G//0aZwF2yJbiyGh3wn56LynZa1kwg2e6G4i/L8vr e6vrPXvj HefmvKsB6c15l593HwLXLquhbP19p/TUpTcEIbdlCovq2C/byUhgNrozFikTFWvaW9MS2usuC96Rpu8hzyAM0rqVc7vUYNDue5i5oC4W5SXM0ThDC3yaeR3UGSqZGvP72H1AmyQFjvCR6V5GmiwAw4iGZO7qZqARQLTP3IzIxj+4XG0EnjDnA1nN926ca8RgmZ/bFUwFrt1CW6WW8Efll3nuPi91RINNy4oVz8PqH2PYGZSPyJdICV1Dxpv9H3/IOoaCWwFFlSrpyDMSbZgfl4sdAow== 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: From: Chuck Lever Create a vector of directory operations in fs/libfs.c that handles directory seeks and readdir via stable offsets instead of the current cursor-based mechanism. For the moment these are unused. Signed-off-by: Chuck Lever --- fs/libfs.c | 252 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 19 ++++ 2 files changed, 271 insertions(+) diff --git a/fs/libfs.c b/fs/libfs.c index 89cf614a3271..9940dce049e6 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -239,6 +239,258 @@ const struct inode_operations simple_dir_inode_operations = { }; EXPORT_SYMBOL(simple_dir_inode_operations); +static struct stable_offset_ctx *stable_ctx_get(struct inode *inode) +{ + return inode->i_op->get_so_ctx(inode); +} + +static void stable_offset_set(struct dentry *dentry, unsigned long offset) +{ + dentry->d_fsdata = (void *)offset; +} + +static unsigned long stable_offset_get(struct dentry *dentry) +{ + return (unsigned long)dentry->d_fsdata; +} + +/** + * stable_offset_init - initialize a parent directory + * @so_ctx: directory offset map to be initialized + * + */ +void stable_offset_init(struct stable_offset_ctx *so_ctx) +{ + xa_init_flags(&so_ctx->xa, XA_FLAGS_ALLOC1); + + /* 0 is '.', 1 is '..', so always start with offset 2 */ + so_ctx->next_offset = 2; +} + +/** + * stable_offset_add - Add an entry to a directory's stable offset map + * @so_ctx: directory offset ctx to be updated + * @dentry: new dentry being added + * + * Returns zero on success. @so_ctx and the dentry offset are updated. + * Otherwise, a negative errno value is returned. + */ +int stable_offset_add(struct stable_offset_ctx *so_ctx, struct dentry *dentry) +{ + static const struct xa_limit limit = XA_LIMIT(2, U32_MAX); + u32 offset; + int ret; + + if (stable_offset_get(dentry) != 0) + return -EBUSY; + + ret = xa_alloc_cyclic(&so_ctx->xa, &offset, dentry, limit, + &so_ctx->next_offset, GFP_KERNEL); + if (ret < 0) + return ret; + + stable_offset_set(dentry, offset); + return 0; +} + +/** + * stable_offset_remove - Remove an entry to a directory's stable offset map + * @so_ctx: directory offset ctx to be updated + * @dentry: dentry being removed + * + */ +void stable_offset_remove(struct stable_offset_ctx *so_ctx, + struct dentry *dentry) +{ + unsigned long index = stable_offset_get(dentry); + + if (index == 0) + return; + + xa_erase(&so_ctx->xa, index); + stable_offset_set(dentry, 0); +} + +/** + * stable_offset_rename_exchange - exchange rename with stable directory offsets + * @old_dir: parent of dentry being moved + * @old_dentry: dentry being moved + * @new_dir: destination parent + * @new_dentry: destination dentry + * + * Returns zero on success. Otherwise a negative errno is returned and the + * rename is rolled back. + */ +int stable_offset_rename_exchange(struct inode *old_dir, + struct dentry *old_dentry, + struct inode *new_dir, + struct dentry *new_dentry) +{ + struct stable_offset_ctx *old_ctx = stable_ctx_get(old_dir); + struct stable_offset_ctx *new_ctx = stable_ctx_get(new_dir); + unsigned long old_index = stable_offset_get(old_dentry); + unsigned long new_index = stable_offset_get(new_dentry); + int ret; + + stable_offset_remove(old_ctx, old_dentry); + stable_offset_remove(new_ctx, new_dentry); + + ret = stable_offset_add(new_ctx, old_dentry); + if (ret) + goto out_restore; + + ret = stable_offset_add(old_ctx, new_dentry); + if (ret) { + stable_offset_remove(new_ctx, old_dentry); + goto out_restore; + } + + ret = simple_rename_exchange(old_dir, old_dentry, new_dir, new_dentry); + if (ret) { + stable_offset_remove(new_ctx, old_dentry); + stable_offset_remove(old_ctx, new_dentry); + goto out_restore; + } + return 0; + +out_restore: + stable_offset_set(old_dentry, old_index); + xa_store(&old_ctx->xa, old_index, old_dentry, GFP_KERNEL); + stable_offset_set(new_dentry, new_index); + xa_store(&new_ctx->xa, new_index, new_dentry, GFP_KERNEL); + return ret; +} + +/** + * stable_offset_destroy - Release offset map + * @so_ctx: directory offset ctx that is about to be destroyed + * + * During fs teardown (eg. umount), a directory's offset map might still + * contain entries. xa_destroy() cleans out anything that remains. + */ +void stable_offset_destroy(struct stable_offset_ctx *so_ctx) +{ + xa_destroy(&so_ctx->xa); +} + +/** + * stable_dir_llseek - Advance the read position of a directory descriptor + * @file: an open directory whose position is to be updated + * @offset: a byte offset + * @whence: enumerator describing the starting position for this update + * + * SEEK_END, SEEK_DATA, and SEEK_HOLE are not supported for directories. + * + * Returns the updated read position if successful; otherwise a + * negative errno is returned and the read position remains unchanged. + */ +static loff_t stable_dir_llseek(struct file *file, loff_t offset, int whence) +{ + switch (whence) { + case SEEK_CUR: + offset += file->f_pos; + fallthrough; + case SEEK_SET: + if (offset >= 0) + break; + fallthrough; + default: + return -EINVAL; + } + + return vfs_setpos(file, offset, U32_MAX); +} + +static struct dentry *stable_find_next(struct xa_state *xas) +{ + struct dentry *child, *found = NULL; + + rcu_read_lock(); + child = xas_next_entry(xas, U32_MAX); + if (!child) + goto out; + spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); + if (simple_positive(child)) + found = dget_dlock(child); + spin_unlock(&child->d_lock); +out: + rcu_read_unlock(); + return found; +} + +static bool stable_dir_emit(struct dir_context *ctx, struct dentry *dentry) +{ + loff_t offset = stable_offset_get(dentry); + struct inode *inode = d_inode(dentry); + + return ctx->actor(ctx, dentry->d_name.name, dentry->d_name.len, offset, + inode->i_ino, fs_umode_to_dtype(inode->i_mode)); +} + +static void stable_iterate_dir(struct dentry *dir, struct dir_context *ctx) +{ + struct stable_offset_ctx *so_ctx = stable_ctx_get(d_inode(dir)); + XA_STATE(xas, &so_ctx->xa, ctx->pos); + struct dentry *dentry; + + while (true) { + spin_lock(&dir->d_lock); + dentry = stable_find_next(&xas); + spin_unlock(&dir->d_lock); + if (!dentry) + break; + + if (!stable_dir_emit(ctx, dentry)) { + dput(dentry); + break; + } + + dput(dentry); + ctx->pos = xas.xa_index + 1; + } +} + +/** + * stable_readdir - Emit entries starting at offset @ctx->pos + * @file: an open directory to iterate over + * @ctx: directory iteration context + * + * Caller must hold @file's i_rwsem to prevent insertion or removal of + * entries during this call. + * + * On entry, @ctx->pos contains an offset that represents the first entry + * to be read from the directory. + * + * The operation continues until there are no more entries to read, or + * until the ctx->actor indicates there is no more space in the caller's + * output buffer. + * + * On return, @ctx->pos contains an offset that will read the next entry + * in this directory when shmem_readdir() is called again with @ctx. + * + * Return values: + * %0 - Complete + */ +static int stable_readdir(struct file *file, struct dir_context *ctx) +{ + struct dentry *dir = file->f_path.dentry; + + lockdep_assert_held(&d_inode(dir)->i_rwsem); + + if (!dir_emit_dots(file, ctx)) + return 0; + + stable_iterate_dir(dir, ctx); + return 0; +} + +const struct file_operations stable_dir_operations = { + .llseek = stable_dir_llseek, + .iterate_shared = stable_readdir, + .read = generic_read_dir, + .fsync = noop_fsync, +}; + static struct dentry *find_next_child(struct dentry *parent, struct dentry *prev) { struct dentry *child = NULL; diff --git a/include/linux/fs.h b/include/linux/fs.h index 133f0640fb24..16be31bd81f7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1767,6 +1767,7 @@ struct dir_context { struct iov_iter; struct io_uring_cmd; +struct stable_offset_ctx; struct file_operations { struct module *owner; @@ -1854,6 +1855,7 @@ struct inode_operations { int (*fileattr_set)(struct mnt_idmap *idmap, struct dentry *dentry, struct fileattr *fa); int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa); + struct stable_offset_ctx *(*get_so_ctx)(struct inode *inode); } ____cacheline_aligned; static inline ssize_t call_read_iter(struct file *file, struct kiocb *kio, @@ -2954,6 +2956,23 @@ extern ssize_t simple_read_from_buffer(void __user *to, size_t count, extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos, const void __user *from, size_t count); +struct stable_offset_ctx { + struct xarray xa; + u32 next_offset; +}; + +void stable_offset_init(struct stable_offset_ctx *so_ctx); +int stable_offset_add(struct stable_offset_ctx *so_ctx, struct dentry *dentry); +void stable_offset_remove(struct stable_offset_ctx *so_ctx, + struct dentry *dentry); +int stable_offset_rename_exchange(struct inode *old_dir, + struct dentry *old_dentry, + struct inode *new_dir, + struct dentry *new_dentry); +void stable_offset_destroy(struct stable_offset_ctx *so_ctx); + +extern const struct file_operations stable_dir_operations; + extern int __generic_file_fsync(struct file *, loff_t, loff_t, int); extern int generic_file_fsync(struct file *, loff_t, loff_t, int); From patchwork Tue Jun 27 20:53:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 13295027 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 5826BEB64D9 for ; Tue, 27 Jun 2023 20:53:21 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id EE71A8D0005; Tue, 27 Jun 2023 16:53:20 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id E704E8D0001; Tue, 27 Jun 2023 16:53:20 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id CEA778D0005; Tue, 27 Jun 2023 16:53:20 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0013.hostedemail.com [216.40.44.13]) by kanga.kvack.org (Postfix) with ESMTP id BAB848D0001 for ; Tue, 27 Jun 2023 16:53:20 -0400 (EDT) Received: from smtpin12.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id 82E6A40A17 for ; Tue, 27 Jun 2023 20:53:20 +0000 (UTC) X-FDA: 80949728160.12.2BA57F3 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by imf12.hostedemail.com (Postfix) with ESMTP id A5B5940007 for ; Tue, 27 Jun 2023 20:53:18 +0000 (UTC) Authentication-Results: imf12.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b="ZQx/UsZy"; spf=pass (imf12.hostedemail.com: domain of cel@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=cel@kernel.org; dmarc=pass (policy=none) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1687899198; 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:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=w7U1ETJF3+b23Qu0/lBzi5jnA7O+fNb1OvT4FhatSZs=; b=tcAm65LxWSUZ/J8oEJSWiccN1QsZehbG30CJq2nw0yZ9UDyZJdW/B5aIrXxkb2cIsPsn3p zKlZZGBocPK1H95ZQXUMF/A3XdfAZbcUzLDdR6p0yTfn8+g1b7oynd1eJxGvzh0Y30h7ce 7eFFJ56x99rPFSzQKZMpaN0QQEdmWN4= ARC-Authentication-Results: i=1; imf12.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b="ZQx/UsZy"; spf=pass (imf12.hostedemail.com: domain of cel@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=cel@kernel.org; dmarc=pass (policy=none) header.from=kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1687899198; a=rsa-sha256; cv=none; b=c/8PTQu3c6/xmbc+5mGFP2l5yIj81cvveOooJ6SgZw6GgylPa8hvhmzArwI5gDhzXNZ4fo hy7UsrpRf0HQ7Sn/PIl0V5Ru+s3jfAVnjWODuppjoPh4vLj9zujM9Nj2HZX9FLyIZ/81n+ gYgS98rE1NTtm+WixnPiyOMm6OS0Twg= Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id D3F166121B; Tue, 27 Jun 2023 20:53:17 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 956B7C433C8; Tue, 27 Jun 2023 20:53:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1687899197; bh=e4I/gNHDIjpSKufk2xxM8B41vPKw1FE7ZKuVtO31ayU=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=ZQx/UsZypzNmJsOCaPFJvsSA0E291nghrjaD7ve+fzrq+xkHa/7XJDDqfcKkSYv2Q eAe3J7BAwoTKcVVd8JYKBImzZC32NK0j36dAN1Ho94daTL6oubGB405E++oI5toTvk 8VKGxUiMbXSUCs1qhvoGFqulorX+BB2Z1QUXXgSusNJlDp2SUzj3HjlSjwEp2oTLuB y2WJuNFgVwRtS1KrvnDVptZWnPytWz6kGBx+Zx1BRI6T71oyatywrVOj3sI32gqpIb GNkTTDOEUKmOHSX1X+x33gZDbWncW0mxsOG1nxypWOBkvIC/TS5c9ahPNQ2qvyAFCg t6ScQt8hZF0Og== Subject: [PATCH v5 2/3] shmem: Refactor shmem_symlink() From: Chuck Lever To: viro@zeniv.linux.org.uk, brauner@kernel.org, hughd@google.com, akpm@linux-foundation.org Cc: Jeff Layton , Christoph Hellwig , Chuck Lever , jlayton@redhat.com, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Date: Tue, 27 Jun 2023 16:53:15 -0400 Message-ID: <168789919571.157531.3616549508867843146.stgit@manet.1015granger.net> In-Reply-To: <168789864000.157531.11122232592994999253.stgit@manet.1015granger.net> References: <168789864000.157531.11122232592994999253.stgit@manet.1015granger.net> User-Agent: StGit/1.5 MIME-Version: 1.0 X-Rspamd-Queue-Id: A5B5940007 X-Rspam-User: X-Stat-Signature: yh5xccpounjghb8zse94eopghegxaz3a X-Rspamd-Server: rspam01 X-HE-Tag: 1687899198-286352 X-HE-Meta: U2FsdGVkX1++ZWa45AYDUIvGTTwkZiuC7vLtmHWjxGC37au+fbYTFCg93O8fVjEODKbnLccKzNMdx0NOXU/TqCTNz3jHRxNoSvomeCrk7VAaOSQLl7YJGaosDom8oAhVJT4vq8nVK9ESF8JyOOaoK4rBFUBAjsWrsQQU0uKOrbqsEIsFtfNZDJAOk1NFba1LOSoccr2eiZlqryhL1UU/+XjbY1NsGI7k5OeTzr46uytj+Ot2oXsqOVivTyYKB9ihw2K7/CxuZ5k3Bc53Nf3Fl0ByemqLOauieb8B7BjwTErgHGFBEHdVSxUarFJqwhX+TR6HRssbqnQrTNFi4Drn9wYdqQ1zUEEbULQx4is2a/9zMPMvK7IWhGH+JiPoOH3B14MTfwoEzu5NZajMhR6TBMChD8wfp/8/GUsy7IrG6emcmnd+hD5QfM3pkeO9sX5XfPe9G4/rFkWiyZ0ZdPpYqHTNqdnUdr3zJ8OsIZ/YG7pPZRSo4iUo6zVGK8z811rg0hVw74fVP6GrcV//xOdDkK1Bwv2Ekt13OhRPR2FvM6biyf5QHuC9dHzFjO3z3ye4LRi2gfRqxBIrlUqZ+qd9TdWqxu5NKT7H9T3rB+ggOuzwZvXnJxrDNy3gP1F7rIHaisM5iuntIdpWnJVQc91cmycA3jKD3LxY2/BamWw7LNK/H8sKb7gzOCTl2uVL/V1a62qTzy5ZKG+VgLgghviLdu6eE150cIf6fJZfoffMOCc7INYxq7ZA8cJetLPD/gcjZGbgcPY+tcC6yaCCbXoKdHRnZpR3tHy55IIF09CoWLJCV4XwxJziIbc/3PX9mDId52vblf1/i4f2xVWqqqWLHqDwTpVtNVu/ygSLUkLpHzKlvXzeb8RNjuCJ/wLdA2oaJWV38iDBqxd510Wevgjvkl7f6X0dHRV8pcipVNysCmI2WjBHBhkoGtrcyT3lK8su1Sq/BKam+GR3eKlGakA //G96sjL yFB9ln5IaZaYPWpoozRyU7n+nt1WyZEnqoH7JlELCsKpZda/8P9pSqt5ddX9aSxfIKyQYo03PiRCnbluLIfjfSyw11o23UQS/vfOdCWg6dbnFHmmNxRU97x75OV2wkUpcfWP6hdiR2vrrwQkiLUmuDJKunDY85WoCokIZm1LTeFgr2KizifV1/KeqYgnwMIsbfkGxDmnYj/bk+NeHCPMl/qRB1FkuogHdiRgK4WDQ2bMtJgjiisKFJkrT4lMHT/6OXUFkERL+nRif2jpLepUf3VMivjJeH9MWMfp0YAcsnH9kz4G5mTkTqOjEIPxGYa5uqN5DvwXvSUsQNKNi4+NGNyGX6QnN7+jzIyyZqTt3XjNQ0roGwgd2tncZJg== 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: From: Chuck Lever De-duplicate the error handling paths. No change in behavior is expected. Suggested-by: Jeff Layton Reviewed-by: Christoph Hellwig Signed-off-by: Chuck Lever --- mm/shmem.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/mm/shmem.c b/mm/shmem.c index e40a08c5c6d7..721f9fd064aa 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3161,26 +3161,22 @@ static int shmem_symlink(struct mnt_idmap *idmap, struct inode *dir, error = security_inode_init_security(inode, dir, &dentry->d_name, shmem_initxattrs, NULL); - if (error && error != -EOPNOTSUPP) { - iput(inode); - return error; - } + if (error && error != -EOPNOTSUPP) + goto out_iput; inode->i_size = len-1; if (len <= SHORT_SYMLINK_LEN) { inode->i_link = kmemdup(symname, len, GFP_KERNEL); if (!inode->i_link) { - iput(inode); - return -ENOMEM; + error = -ENOMEM; + goto out_iput; } inode->i_op = &shmem_short_symlink_operations; } else { inode_nohighmem(inode); error = shmem_get_folio(inode, 0, &folio, SGP_WRITE); - if (error) { - iput(inode); - return error; - } + if (error) + goto out_iput; inode->i_mapping->a_ops = &shmem_aops; inode->i_op = &shmem_symlink_inode_operations; memcpy(folio_address(folio), symname, len); @@ -3195,6 +3191,9 @@ static int shmem_symlink(struct mnt_idmap *idmap, struct inode *dir, d_instantiate(dentry, inode); dget(dentry); return 0; +out_iput: + iput(inode); + return error; } static void shmem_put_link(void *arg) From patchwork Tue Jun 27 20:53:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 13295028 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 06B40EB64DC for ; Tue, 27 Jun 2023 20:53:28 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 96B948E0001; Tue, 27 Jun 2023 16:53:27 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 8F3D78D0003; Tue, 27 Jun 2023 16:53:27 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 76C5C8E0002; Tue, 27 Jun 2023 16:53:27 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id 5E6C08E0001 for ; Tue, 27 Jun 2023 16:53:27 -0400 (EDT) Received: from smtpin21.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 38D4F1C84D2 for ; Tue, 27 Jun 2023 20:53:27 +0000 (UTC) X-FDA: 80949728454.21.151EFCC Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by imf23.hostedemail.com (Postfix) with ESMTP id 4B5EF14001A for ; Tue, 27 Jun 2023 20:53:25 +0000 (UTC) Authentication-Results: imf23.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=cw5NBXwU; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf23.hostedemail.com: domain of cel@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=cel@kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1687899205; 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:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=IVRA4LuYgryusvGNycgIEnToESTLR/r3jiitgFBq024=; b=F3JANSZERSqBbw5kGXhLAtS+ZNk2wB1DhZLtBSUndN/8QklbzmqwnBZcqqGU8FDOYVaE7D We6f+dLlKHs8EsNWh4kpFPfGF6TC6JiLeo5KUHwW5ENMyIJaSoaJjfRUZ/xh2/rZz3W0Yj arn3IK4q30qhdwmy2VcMeHM8fqIXhRY= ARC-Authentication-Results: i=1; imf23.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=cw5NBXwU; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf23.hostedemail.com: domain of cel@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=cel@kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1687899205; a=rsa-sha256; cv=none; b=w9lJVtK069rVO+6OXviA4gCUdGsq9aqIqpFOgTxSmRk8JNjvuF2w2XhoQliqKs31Dt+g3m s+zt82+S5S389cSDv5LLJKwvqTB6wV6ZRDOYWo3PHXEF+bZBH5otEGydUJ/pzmBK3sTZjq LlFTIKiE2axWulY8iK68J+dYI2xMhzg= Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 7489961233; Tue, 27 Jun 2023 20:53:24 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 589AAC43391; Tue, 27 Jun 2023 20:53:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1687899203; bh=VcvsaV4KxMlmRuP+vSOdBppGCMFeBmAT+SZOmu9unoY=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=cw5NBXwU6J6Nj5iOaHVocZ/cDPlNj14e5dIs4l65tiB8Jdsw6wcAUxjfHCTmsi0M7 t9C1wapA7FZz1Xyxc3Wc8rLM9jwJU/S78WNus8mKEONwjmc8OxuBqi23k8zyP5wvvI xF5MRgg3VaK92hMXJHZ7hh+h4Mqow/9sjXxN0qOeWehWVanELcQ/u9MZ8YQ6JXQsPI oYPX0eN7rLruCxw4rcvNwGxn8hGPd4YUI5caN7IhG/guEJ0SDhtGiGrK4smhmv43i5 82j1iJCDsPfvwQ4LnL0We+GedVfBcw5x1A+I67BS460YlCqlGkZCbdpNeZS5ocXw+s Lm3g4L9xS5NvA== Subject: [PATCH v5 3/3] shmem: stable directory offsets From: Chuck Lever To: viro@zeniv.linux.org.uk, brauner@kernel.org, hughd@google.com, akpm@linux-foundation.org Cc: Chuck Lever , jlayton@redhat.com, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Date: Tue, 27 Jun 2023 16:53:22 -0400 Message-ID: <168789920248.157531.11502183761509096222.stgit@manet.1015granger.net> In-Reply-To: <168789864000.157531.11122232592994999253.stgit@manet.1015granger.net> References: <168789864000.157531.11122232592994999253.stgit@manet.1015granger.net> User-Agent: StGit/1.5 MIME-Version: 1.0 X-Rspamd-Queue-Id: 4B5EF14001A X-Rspam-User: X-Rspamd-Server: rspam02 X-Stat-Signature: ntkxz5qxjcp6k19d3esyuu14r9asubfe X-HE-Tag: 1687899205-138669 X-HE-Meta: U2FsdGVkX1+ZqyqCBFUUGNozqRuoZIBdvjDNFIjtXyGeFGI7rymWxiXZ+eJzM12H7gJ9CsiV0Fv0qJ8WxH+oFQOEh/VVT4Ft57RwtBwLd1NmWWdm7ghXdko5SIsRka8xeMieqAwbIlTMqwQdnNuDCZliR3bbBSSielZ4Suwuvan+PP+FYR4iI3nDKeP1j6qiNnmYypRfj0lpZAhzplg1R57wIhDeUfWgzwdZ/M2PSZ42J3spslP5l7LoGUNOF6zD4ezqerIkrX3g6eu5PL/uR3O/jtDZGxGGcj8rc9Jc2nb7k5UGKUWIcwEUFx67JwXRWEUJHk8RP8n479A5Jkrq6RVItNRpEx/vAUsJ/4tBPyD/xFv/2niSOsyrApf9Nqr7Bv5bLyUNpbzCd/IZ3Duj06uQm6OU4jG5/UYBCBOwwKCFNI+O+fbJaQO3IHcK9gavHvTj6dEnTXQCfIbMHW+EQ2XPh92OQtoLfjLnihVzRuP78iPDWmN2t/FHsgExGwu7KLaM/hJ92kLlQSnXXglJxWHztPIUdIFAVdsqPpMojpSKfRmMToqGFBEdo3GJrOcProFMpHyrNiCGhr/Gl/G43oCAq/ixdr7wxU2F4SK5/HXyQm2e1gohhoel55MG/98wUpl+kgMevc7JCxG01yCGj0KTlJPF4GCH54vh/V3Sh2xiIVtOjaPmJRVsKk2NMfYUxbyYtBu7IU3juhF3LUZM6O/2Bat2MbD5w0IqUa/C0Hg+Ad11TG6WfMimKuX7+Zn1bUOhReytvinqjFkGi+5+PzD6Gn6KFy89IGpI1b4kLhmApplFhaTLlm9RGtr8AojvKUMelrUD3hyOlnjW7d2AZrgio8YAJdPLX4/LZR0lmIKbALOAx8Sq/XWPZR36pSfqygWuNIPmLlaYc/cxBsTga2DPf/5goRpCWtZ2NRgN8g4HgCNfhQ67F6lgxJhxpzjXSkxEAVC2Rte6Zrn8+DQ kljrAhqe jp2dfZTQvmiNfA/RnFzoiT9j/ckk6vbCNBvguI7OGl7UrhDXGJAGeJJRQnmLkvmSW4amEw9JCzxAYQu8bTw+l4qD5340kQMTJElSDFvTUJEnbOne4yNAItK+CGnYueChlh8Ph9KFtLcE33jFb6KSw1Y8aFhH7lIYPV4gAlmhMm133K45B/nPvOmzQJcS60bik4XoS8q9qx7X1h24tFJjjIrHs+5t6tjYJEIYaV2H9z/gxaPySNDq/QVMYmhUqfPSmhN6b75yp9QxXjqQTgTA8A46aJA== 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: From: Chuck Lever The current cursor-based directory offset mechanism doesn't work when a tmpfs filesystem is exported via NFS. This is because NFS clients do not open directories. Each server-side READDIR operation has to open the directory, read it, then close it. The cursor state for that directory, being associated strictly with the opened struct file, is thus discarded after each NFS READDIR operation. Directory offsets are cached not only by NFS clients, but also by user space libraries on those clients. Essentially there is no way to invalidate those caches when directory offsets have changed on an NFS server after the offset-to-dentry mapping changes. Thus the whole application stack depends on unchanging directory offsets. The solution we've come up with is to make the directory offset for each file in a tmpfs filesystem stable for the life of the directory entry it represents. shmem_readdir() and shmem_dir_llseek() now use an xarray to map each directory offset (an loff_t integer) to the memory address of a struct dentry. Signed-off-by: Chuck Lever --- include/linux/shmem_fs.h | 1 + mm/shmem.c | 47 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index 9029abd29b1c..d2c67333028c 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h @@ -27,6 +27,7 @@ struct shmem_inode_info { atomic_t stop_eviction; /* hold when working on inode */ struct timespec64 i_crtime; /* file creation time */ unsigned int fsflags; /* flags for FS_IOC_[SG]ETFLAGS */ + struct stable_offset_ctx dir_offsets; struct inode vfs_inode; }; diff --git a/mm/shmem.c b/mm/shmem.c index 721f9fd064aa..5782fe1edc75 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2355,6 +2355,11 @@ static void shmem_set_inode_flags(struct inode *inode, unsigned int fsflags) #define shmem_initxattrs NULL #endif +static struct stable_offset_ctx *shmem_so_ctx(struct inode *inode) +{ + return &SHMEM_I(inode)->dir_offsets; +} + static struct inode *shmem_get_inode(struct mnt_idmap *idmap, struct super_block *sb, struct inode *dir, umode_t mode, dev_t dev, unsigned long flags) @@ -2410,7 +2415,8 @@ static struct inode *shmem_get_inode(struct mnt_idmap *idmap, struct super_block /* Some things misbehave if size == 0 on a directory */ inode->i_size = 2 * BOGO_DIRENT_SIZE; inode->i_op = &shmem_dir_inode_operations; - inode->i_fop = &simple_dir_operations; + inode->i_fop = &stable_dir_operations; + stable_offset_init(shmem_so_ctx(inode)); break; case S_IFLNK: /* @@ -2950,7 +2956,10 @@ shmem_mknod(struct mnt_idmap *idmap, struct inode *dir, if (error && error != -EOPNOTSUPP) goto out_iput; - error = 0; + error = stable_offset_add(shmem_so_ctx(dir), dentry); + if (error) + goto out_iput; + dir->i_size += BOGO_DIRENT_SIZE; dir->i_ctime = dir->i_mtime = current_time(dir); inode_inc_iversion(dir); @@ -3027,6 +3036,13 @@ static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentr goto out; } + ret = stable_offset_add(shmem_so_ctx(dir), dentry); + if (ret) { + if (inode->i_nlink) + shmem_free_inode(inode->i_sb); + goto out; + } + dir->i_size += BOGO_DIRENT_SIZE; inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode); inode_inc_iversion(dir); @@ -3045,6 +3061,8 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry) if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode)) shmem_free_inode(inode->i_sb); + stable_offset_remove(shmem_so_ctx(dir), dentry); + dir->i_size -= BOGO_DIRENT_SIZE; inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode); inode_inc_iversion(dir); @@ -3103,24 +3121,29 @@ static int shmem_rename2(struct mnt_idmap *idmap, { struct inode *inode = d_inode(old_dentry); int they_are_dirs = S_ISDIR(inode->i_mode); + int error; if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) return -EINVAL; if (flags & RENAME_EXCHANGE) - return simple_rename_exchange(old_dir, old_dentry, new_dir, new_dentry); + return stable_offset_rename_exchange(old_dir, old_dentry, + new_dir, new_dentry); if (!simple_empty(new_dentry)) return -ENOTEMPTY; if (flags & RENAME_WHITEOUT) { - int error; - error = shmem_whiteout(idmap, old_dir, old_dentry); if (error) return error; } + stable_offset_remove(shmem_so_ctx(old_dir), old_dentry); + error = stable_offset_add(shmem_so_ctx(new_dir), old_dentry); + if (error) + return error; + if (d_really_is_positive(new_dentry)) { (void) shmem_unlink(new_dir, new_dentry); if (they_are_dirs) { @@ -3164,19 +3187,23 @@ static int shmem_symlink(struct mnt_idmap *idmap, struct inode *dir, if (error && error != -EOPNOTSUPP) goto out_iput; + error = stable_offset_add(shmem_so_ctx(dir), dentry); + if (error) + goto out_iput; + inode->i_size = len-1; if (len <= SHORT_SYMLINK_LEN) { inode->i_link = kmemdup(symname, len, GFP_KERNEL); if (!inode->i_link) { error = -ENOMEM; - goto out_iput; + goto out_remove_offset; } inode->i_op = &shmem_short_symlink_operations; } else { inode_nohighmem(inode); error = shmem_get_folio(inode, 0, &folio, SGP_WRITE); if (error) - goto out_iput; + goto out_remove_offset; inode->i_mapping->a_ops = &shmem_aops; inode->i_op = &shmem_symlink_inode_operations; memcpy(folio_address(folio), symname, len); @@ -3191,6 +3218,9 @@ static int shmem_symlink(struct mnt_idmap *idmap, struct inode *dir, d_instantiate(dentry, inode); dget(dentry); return 0; + +out_remove_offset: + stable_offset_remove(shmem_so_ctx(dir), dentry); out_iput: iput(inode); return error; @@ -3920,6 +3950,8 @@ static void shmem_destroy_inode(struct inode *inode) { if (S_ISREG(inode->i_mode)) mpol_free_shared_policy(&SHMEM_I(inode)->policy); + if (S_ISDIR(inode->i_mode)) + stable_offset_destroy(shmem_so_ctx(inode)); } static void shmem_init_inode(void *foo) @@ -4000,6 +4032,7 @@ static const struct inode_operations shmem_dir_inode_operations = { .mknod = shmem_mknod, .rename = shmem_rename2, .tmpfile = shmem_tmpfile, + .get_so_ctx = shmem_so_ctx, #endif #ifdef CONFIG_TMPFS_XATTR .listxattr = shmem_listxattr,