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,