From nobody Sun May 10 09:53:56 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E0888C433EF for ; Tue, 17 May 2022 10:10:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343685AbiEQKKL (ORCPT ); Tue, 17 May 2022 06:10:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43314 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245739AbiEQKIp (ORCPT ); Tue, 17 May 2022 06:08:45 -0400 Received: from mail-pj1-x102b.google.com (mail-pj1-x102b.google.com [IPv6:2607:f8b0:4864:20::102b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DAC432F3AF; Tue, 17 May 2022 03:08:06 -0700 (PDT) Received: by mail-pj1-x102b.google.com with SMTP id pq9-20020a17090b3d8900b001df622bf81dso1816330pjb.3; Tue, 17 May 2022 03:08:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :organization; bh=KC2IL7bq9JaftL0PBIHzRSzDKaZoyx/rqcDB3M8Fc1c=; b=FheqoOtNnbai//NihxwErCMS8fCSMCwGzE0rOFHhUfTl/knBuOmyY+2Oy7WPtlI0Wl eB5ywjvR0vzP/af0YkFJHH7f8v3Ak3tA5N2STkinB3bhcTKJ/E1ixdzBTAx5DR1yui3+ KCtILyaTy2RLlKqq/V+apBmYuyMRhQv8xaLUqEKD+VqH6g+6o0Iz6leATav98xuGM8zv CcI0vqeRtlnRMDPD/cCwihkqXnZt8+dYgUzpBvFpK0y96cGz7XtfCFnbHV1xuvDsSzfa cVMIR6SQZ3w4kDY8e+xfGjRSp6FPN6wrvVvpMQ2FLoEnJU6BLpT7Q/zIA8nRIXmNomb/ kOFg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:organization; bh=KC2IL7bq9JaftL0PBIHzRSzDKaZoyx/rqcDB3M8Fc1c=; b=y74fwugfetgCl2Cg0n6+Me+B3bsaQ2uwB02UgTQBgDqJL8RQ6b5Kvti2Zzmg+Krx7t 996WMnd/8kkdKx2UQqJTzu4o4pTVgO56wY8vL/WqjeS4TjNsuwS6tLLFJFOtniCNncGW EjAT5ufd4Wmc3AGB8/XbwFvA4+qNBT7AdFbSbBWQCWjgmObKGto7HBppxHJBY5SwWzbd OSh1n07g+Bk7+LgYmp9VKXBkNy1PqdEr7lzCRWmOFRgyV4TyjeRx1g4dj98kNxr3poog meMJHVgVRHTSUW5NICgdoF3q6Pj6Vi1MBfWf87bcKa4d1Q2En+xfZa7on9jYRJpN7oKP S9xA== X-Gm-Message-State: AOAM530GbDsLe1NLDQ6+3uKUUKaEIThTZ/vsaF/m4H6pNKgstqOxXgx8 VLGUkITn4VZMcSlgZjQjDTk= X-Google-Smtp-Source: ABdhPJytqSM+LRkVD/ZDSIVem1/MzIRqNvzDCVWiqI4gMrVJmeUCXmrAqh50p+VEgQdT82WMMdPLlQ== X-Received: by 2002:a17:902:a583:b0:15d:197b:9259 with SMTP id az3-20020a170902a58300b0015d197b9259mr22135914plb.51.1652782086087; Tue, 17 May 2022 03:08:06 -0700 (PDT) Received: from localhost.localdomain ([219.91.171.244]) by smtp.googlemail.com with ESMTPSA id a10-20020a631a0a000000b003c6ab6ba06csm8202595pga.79.2022.05.17.03.08.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 May 2022 03:08:05 -0700 (PDT) From: Dharmendra Singh To: miklos@szeredi.hu, vgoyal@redhat.com Cc: Dharmendra Singh , linux-fsdevel@vger.kernel.org, fuse-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org, bschubert@ddn.com, Dharmendra Singh Subject: [PATCH v5 1/3] FUSE: Avoid lookups in fuse create Date: Tue, 17 May 2022 15:37:42 +0530 Message-Id: <20220517100744.26849-2-dharamhans87@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220517100744.26849-1-dharamhans87@gmail.com> References: <20220517100744.26849-1-dharamhans87@gmail.com> Organization: DDN STORAGE Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Dharmendra Singh When we go for creating a file (O_CREAT), we trigger a lookup to FUSE USER space. It is very much likely that file does not exist yet as O_CREAT is passed to open(). This extra lookup call can be avoided. Here is how current fuse create works: A. Looks up dentry (if d_in_lookup() is set. B. If dentry is positive or O_CREAT is not set, return. C. If server supports atomic create + open, use that to create file and open it as well. D. If server does not support atomic create + open, just create file using "mknod" and return. VFS will take care of opening the file. Here is how the proposed patch would work: A. Skip lookup if extended create is supported and file is being created. B. Remains same. if dentry is positive or O_CREATE is not set, return. C. If server supports new extended create, use that. D. If not, if server supports atomic create + open, use that E. If not, fall back to mknod and do not open file. (Current code returns file attributes from user space as part of reply of FUSE_CREATE call itself.) It is expected that USER SPACE create the file, open it and fills in the attributes which are then used to make inode stand/revalidate in the kernel cache. Also if file was newly created(does not exist yet by this time) in USER SPACE then it should be indicated in `struct fuse_file_info` by setting a bit which is again used by libfuse to send some flags back to fuse kernel to indicate that that file was newly created. These flags are used by kernel to indicate changes in parent directory. Fuse kernel automatically detects if extended create is implemented by libfuse/USER SPACE or not. And depending upon the outcome of this check all further creates are decided to be extended create or the old create way. If libfuse/USER SPACE has not implemented the extended create operation then by default behaviour remains same i.e we do not optimize lookup calls which are triggered before create calls into libfuse. Signed-off-by: Dharmendra Singh --- fs/fuse/dir.c | 84 +++++++++++++++++++++++++++++++++------ fs/fuse/fuse_i.h | 6 +++ include/uapi/linux/fuse.h | 3 ++ 3 files changed, 81 insertions(+), 12 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 656e921f3506..ed9da8d6b57b 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -523,7 +523,7 @@ static int get_security_context(struct dentry *entry, u= mode_t mode, */ static int fuse_create_open(struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, - umode_t mode) + umode_t mode, uint32_t opcode) { int err; struct inode *inode; @@ -535,8 +535,10 @@ static int fuse_create_open(struct inode *dir, struct = dentry *entry, struct fuse_entry_out outentry; struct fuse_inode *fi; struct fuse_file *ff; + struct dentry *res =3D NULL; void *security_ctx =3D NULL; u32 security_ctxlen; + bool ext_create =3D (opcode =3D=3D FUSE_CREATE_EXT ? true : false); =20 /* Userspace expects S_IFREG in create mode */ BUG_ON((mode & S_IFMT) !=3D S_IFREG); @@ -566,7 +568,7 @@ static int fuse_create_open(struct inode *dir, struct d= entry *entry, inarg.open_flags |=3D FUSE_OPEN_KILL_SUIDGID; } =20 - args.opcode =3D FUSE_CREATE; + args.opcode =3D opcode; args.nodeid =3D get_node_id(dir); args.in_numargs =3D 2; args.in_args[0].size =3D sizeof(inarg); @@ -613,9 +615,37 @@ static int fuse_create_open(struct inode *dir, struct = dentry *entry, goto out_err; } kfree(forget); - d_instantiate(entry, inode); + /* + * In extended create, fuse_lookup() was skipped, which also uses + * d_splice_alias(). As we come directly here after picking up dentry + * it is very much likely that dentry has DCACHE_PAR_LOOKUP flag set + * on it so call d_splice_alias(). + */ + if (!ext_create && !d_in_lookup(entry)) + d_instantiate(entry, inode); + else { + res =3D d_splice_alias(inode, entry); + if (IS_ERR(res)) { + /* Close the file in user space, but do not unlink it, + * if it was created - with network file systems other + * clients might have already accessed it. + */ + fi =3D get_fuse_inode(inode); + fuse_sync_release(fi, ff, flags); + fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); + err =3D PTR_ERR(res); + goto out_err; + } + } fuse_change_entry_timeout(entry, &outentry); - fuse_dir_changed(dir); + /* + * This should be always set when the file is created, but only + * CREATE_EXT introduced FOPEN_FILE_CREATED to user space. + */ + if (!ext_create || (outopen.open_flags & FOPEN_FILE_CREATED)) { + fuse_dir_changed(dir); + file->f_mode |=3D FMODE_CREATED; + } err =3D finish_open(file, entry, generic_file_open); if (err) { fi =3D get_fuse_inode(inode); @@ -634,6 +664,29 @@ static int fuse_create_open(struct inode *dir, struct = dentry *entry, return err; } =20 +static int fuse_create_ext(struct inode *dir, struct dentry *entry, + struct file *file, unsigned int flags, + umode_t mode) +{ + int err; + struct fuse_conn *fc =3D get_fuse_conn(dir); + + if (fc->no_create_ext) + return -ENOSYS; + + err =3D fuse_create_open(dir, entry, file, flags, mode, + FUSE_CREATE_EXT); + /* If ext create is not implemented then indicate in fc so that next + * request falls back to normal create instead of going into libufse and + * returning with -ENOSYS. + */ + if (err =3D=3D -ENOSYS) { + if (!fc->no_create_ext) + fc->no_create_ext =3D 1; + } + return err; +} + static int fuse_mknod(struct user_namespace *, struct inode *, struct dent= ry *, umode_t, dev_t); static int fuse_atomic_open(struct inode *dir, struct dentry *entry, @@ -643,29 +696,35 @@ static int fuse_atomic_open(struct inode *dir, struct= dentry *entry, int err; struct fuse_conn *fc =3D get_fuse_conn(dir); struct dentry *res =3D NULL; + bool create =3D flags & O_CREAT ? true : false; =20 if (fuse_is_bad(dir)) return -EIO; =20 - if (d_in_lookup(entry)) { +lookup: + if ((!create || fc->no_create_ext) && d_in_lookup(entry)) { res =3D fuse_lookup(dir, entry, 0); if (IS_ERR(res)) return PTR_ERR(res); - if (res) entry =3D res; } - - if (!(flags & O_CREAT) || d_really_is_positive(entry)) + if (!create || d_really_is_positive(entry)) goto no_open; =20 - /* Only creates */ - file->f_mode |=3D FMODE_CREATED; - if (fc->no_create) goto mknod; =20 - err =3D fuse_create_open(dir, entry, file, flags, mode); + if (!fc->no_create_ext) { + err =3D fuse_create_ext(dir, entry, file, flags, mode); + /* If libfuse/user space has not implemented extended create, + * fall back to normal create. + */ + if (err =3D=3D -ENOSYS) + goto lookup; + } else + err =3D fuse_create_open(dir, entry, file, flags, mode, + FUSE_CREATE); if (err =3D=3D -ENOSYS) { fc->no_create =3D 1; goto mknod; @@ -683,6 +742,7 @@ static int fuse_atomic_open(struct inode *dir, struct d= entry *entry, } =20 /* + * Code shared between mknod, mkdir, symlink and link */ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args, diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index e8e59fbdefeb..266133dcab5e 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -669,6 +669,12 @@ struct fuse_conn { /** Is open/release not implemented by fs? */ unsigned no_open:1; =20 + /* + * Is atomic lookup-create-open(extended create) not implemented + * by fs? + */ + unsigned no_create_ext:1; + /** Is opendir/releasedir not implemented by fs? */ unsigned no_opendir:1; =20 diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index d6ccee961891..bebe4be3f1cb 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -301,6 +301,7 @@ struct fuse_file_lock { * FOPEN_CACHE_DIR: allow caching this directory * FOPEN_STREAM: the file is stream-like (no file position at all) * FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_C= ACHE) + * FOPEN_FILE_CREATED: the file was actually created */ #define FOPEN_DIRECT_IO (1 << 0) #define FOPEN_KEEP_CACHE (1 << 1) @@ -308,6 +309,7 @@ struct fuse_file_lock { #define FOPEN_CACHE_DIR (1 << 3) #define FOPEN_STREAM (1 << 4) #define FOPEN_NOFLUSH (1 << 5) +#define FOPEN_FILE_CREATED (1 << 6) =20 /** * INIT request/reply flags @@ -537,6 +539,7 @@ enum fuse_opcode { FUSE_SETUPMAPPING =3D 48, FUSE_REMOVEMAPPING =3D 49, FUSE_SYNCFS =3D 50, + FUSE_CREATE_EXT =3D 51, =20 /* CUSE specific operations */ CUSE_INIT =3D 4096, --=20 2.17.1 From nobody Sun May 10 09:53:56 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5BD6AC433F5 for ; Tue, 17 May 2022 10:11:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344525AbiEQKLn (ORCPT ); Tue, 17 May 2022 06:11:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45688 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343593AbiEQKJo (ORCPT ); Tue, 17 May 2022 06:09:44 -0400 Received: from mail-pl1-x629.google.com (mail-pl1-x629.google.com [IPv6:2607:f8b0:4864:20::629]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 301AD47388; Tue, 17 May 2022 03:08:11 -0700 (PDT) Received: by mail-pl1-x629.google.com with SMTP id n18so16903917plg.5; Tue, 17 May 2022 03:08:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :organization; bh=UmRh5WeDJb4FxIPG+OEtpyHlfmIGfbV1ERHbKbuEXYE=; b=GWgmAxIVkNS1hGtn9UXI/hhbF+NlDnsuo1E29/vgNHDT9rX780CQX384vlcp8cBNSW D0pm5QJwf/IZBxQ96by1TRF87mu8+gqRrI/78FWqJUI9Yd9hK6LogzLmOu1Cw6LNG3yp T7Dm7NswUYZb9cOI5A7frGvpf/WJss6DFjc7aBzeYKLX+eqZ+GhaKEvg5Nb9sDhW11go CBQfnbCUlOswlkMhAiwlf+eKMpdY/l0JUkRwIyF7lSbgfsDBTjfzP+ekrsW3OBeDdU3c +Ckt5AF6GSeHUCDwzUfThV7ChJNA/Cmwg9hTQylZm/oyY3f3GFstT1UJg3zadTBz0sKD wpdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:organization; bh=UmRh5WeDJb4FxIPG+OEtpyHlfmIGfbV1ERHbKbuEXYE=; b=41P5rCnLXm/us3LKrTt3gxiRvJSrozzo8M/NAhChpoqBCqEnDSoXYDiCsYKgd5+Yp1 5lP/5dCvasAPaGWuZLomI3L8ojELGK5iH8gi6I76oFuxmBoDoTEGMjhVovrVmtU78p6C MLqrkg4wFfXnC6Kf5nwvRWTfi+frxjk0ZPKS4T+AFUPMbYjoDCIBGNBO4PmsyMT05R1e N9laQInNAt/sTCr1tjJg1hn9EHIJMD+UwdHA0aAuGAfwj35EADvpyovIvOp47iDQEZjY 8ZqIryy5BhaGRtgEQPfGCeOR2VAZXH+E0bDCed0bzo+GSDIy9NJ7SOaIbOlvWycADQfo ntCw== X-Gm-Message-State: AOAM533jgd+ZlcxuTQXLzjL5IMQsxTeWjixYrRhsqEsuw1852DUMriYW wjx8L0eNyqQzhalymtrPQHs= X-Google-Smtp-Source: ABdhPJznjwSaPYLoRL29ez7lvADpiJ2YQUbUx8jjWJHSiWCTYjYJvVYOysHYKrK0biU4ndLkTZ2IxQ== X-Received: by 2002:a17:902:8501:b0:15c:ea4b:1398 with SMTP id bj1-20020a170902850100b0015cea4b1398mr21712865plb.109.1652782091353; Tue, 17 May 2022 03:08:11 -0700 (PDT) Received: from localhost.localdomain ([219.91.171.244]) by smtp.googlemail.com with ESMTPSA id a10-20020a631a0a000000b003c6ab6ba06csm8202595pga.79.2022.05.17.03.08.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 May 2022 03:08:11 -0700 (PDT) From: Dharmendra Singh To: miklos@szeredi.hu, vgoyal@redhat.com Cc: Dharmendra Singh , linux-fsdevel@vger.kernel.org, fuse-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org, bschubert@ddn.com, Dharmendra Singh Subject: [PATCH v5 2/3] FUSE: Rename fuse_create_open() to fuse_atomic_common() Date: Tue, 17 May 2022 15:37:43 +0530 Message-Id: <20220517100744.26849-3-dharamhans87@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220517100744.26849-1-dharamhans87@gmail.com> References: <20220517100744.26849-1-dharamhans87@gmail.com> Organization: DDN STORAGE Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This patch just changes function name as it is used in next patch to make code better readable. Signed-off-by: Dharmendra Singh --- fs/fuse/dir.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index ed9da8d6b57b..517c9add014d 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -521,9 +521,9 @@ static int get_security_context(struct dentry *entry, u= mode_t mode, * If the filesystem doesn't support this, then fall back to separate * 'mknod' + 'open' requests. */ -static int fuse_create_open(struct inode *dir, struct dentry *entry, - struct file *file, unsigned int flags, - umode_t mode, uint32_t opcode) +static int fuse_atomic_common(struct inode *dir, struct dentry *entry, + struct file *file, unsigned int flags, + umode_t mode, uint32_t opcode) { int err; struct inode *inode; @@ -674,8 +674,8 @@ static int fuse_create_ext(struct inode *dir, struct de= ntry *entry, if (fc->no_create_ext) return -ENOSYS; =20 - err =3D fuse_create_open(dir, entry, file, flags, mode, - FUSE_CREATE_EXT); + err =3D fuse_atomic_common(dir, entry, file, flags, mode, + FUSE_CREATE_EXT); /* If ext create is not implemented then indicate in fc so that next * request falls back to normal create instead of going into libufse and * returning with -ENOSYS. @@ -723,8 +723,8 @@ static int fuse_atomic_open(struct inode *dir, struct d= entry *entry, if (err =3D=3D -ENOSYS) goto lookup; } else - err =3D fuse_create_open(dir, entry, file, flags, mode, - FUSE_CREATE); + err =3D fuse_atomic_common(dir, entry, file, flags, mode, + FUSE_CREATE); if (err =3D=3D -ENOSYS) { fc->no_create =3D 1; goto mknod; --=20 2.17.1 From nobody Sun May 10 09:53:56 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A06E4C433EF for ; Tue, 17 May 2022 10:10:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343618AbiEQKKo (ORCPT ); Tue, 17 May 2022 06:10:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44664 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343711AbiEQKK1 (ORCPT ); Tue, 17 May 2022 06:10:27 -0400 Received: from mail-pl1-x630.google.com (mail-pl1-x630.google.com [IPv6:2607:f8b0:4864:20::630]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1D52B48E5C; Tue, 17 May 2022 03:08:17 -0700 (PDT) Received: by mail-pl1-x630.google.com with SMTP id m12so16908832plb.4; Tue, 17 May 2022 03:08:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :organization; bh=nSi8lK2ej4jIE2r69Kt4C5FMLn19t1lg4OcZ7Ppi7IU=; b=UWfYE+cpD9WMJu9KnJuygH3cS+SM3blxo0BVKxeZelk2xlsTyaklywaJVMXsx78o1I e7NLkGSQPUa7m5xcJ4WY7cDx01SSVqDjzIw1FQYlGfXCXsI+40h2/hVVrsgvqWfJ0hcz pC9QyV3mTFWk0VonSIC1kUSs7JuOnJwSy4C6e7rBo3hwy3MGVhdmzI8wNV59hfub/Tu9 A7rAFlb4r44YbnrFU1nbwZC+dSJJ/SGeWbRrc7VIyO5j25rTMqxYAbrRNTvVZPys/sXB 2u7gQP7/txtGSqwiT20JKgRrj8IJw3pXPCTcFRQMu74mz/mGcdHDLXXmtpFmCLaLllnP FPug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:organization; bh=nSi8lK2ej4jIE2r69Kt4C5FMLn19t1lg4OcZ7Ppi7IU=; b=dG5kPtzYZrMXTlDhOsdEWmSTVnby1M6vVSPuWjAmp7LK7zJV+DDLROPBWSir+sZeaM a3v6j8BHl+lru0c/gzsb6JkiBRprN9t95HdxlOtv/jtJPfIDeae9eOh6FGAGR7gA3Ke0 01cBbObRLlgwUwXJnY3RTEJXGdcEoezkJhN/H9EOYLc+6FrbqmufLpjxAMQ7z+nxFGqz rpBdgz9wX9OjpSG8vLtdyA/Mc4fFiY3g6MPmXfwiaHnC5+yUFzBgoOpL7frAAFooeP7/ 8lNk9AoNrlmEpRRebCuk3BZ1b71kmCHYV0a3nC+iGZWxe8fDlhv7unUEyl5b9PPo4zzP fXlQ== X-Gm-Message-State: AOAM530/BTnJbXt4jsZOxKHAxMwDweKY7u7y11GSO2DkTG0tZivDjG8v HDwqN6ZMPEPslysOraCBKK8CcM9NapalkzZQ X-Google-Smtp-Source: ABdhPJxgo0Wpy3KbEIsntRkAH+/+GKHFDPPdJ5mefTYTF58kO0wQA3UMMkLkCE2pprzLUInzPxu1Aw== X-Received: by 2002:a17:902:e84d:b0:15e:b0af:477b with SMTP id t13-20020a170902e84d00b0015eb0af477bmr21452788plg.49.1652782096536; Tue, 17 May 2022 03:08:16 -0700 (PDT) Received: from localhost.localdomain ([219.91.171.244]) by smtp.googlemail.com with ESMTPSA id a10-20020a631a0a000000b003c6ab6ba06csm8202595pga.79.2022.05.17.03.08.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 May 2022 03:08:16 -0700 (PDT) From: Dharmendra Singh To: miklos@szeredi.hu, vgoyal@redhat.com Cc: Dharmendra Singh , linux-fsdevel@vger.kernel.org, fuse-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org, bschubert@ddn.com, Dharmendra Singh Subject: [PATCH v5 3/3] FUSE: Implement atomic lookup + open Date: Tue, 17 May 2022 15:37:44 +0530 Message-Id: <20220517100744.26849-4-dharamhans87@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220517100744.26849-1-dharamhans87@gmail.com> References: <20220517100744.26849-1-dharamhans87@gmail.com> Organization: DDN STORAGE Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" We can optimize aggressive lookups which are triggered when there is normal open for file/dir (dentry is new/negative). Here in this case since we are anyway going to open the file/dir with USER SPACE, avoid this separate lookup call into libfuse and combine it with open call into libfuse. This lookup + open in single call to libfuse has been named as atomic open. It is expected that USER SPACE opens the file and fills in the attributes, which are then used to make inode stand/revalidate in the kernel cache. Signed-off-by: Dharmendra Singh --- fs/fuse/dir.c | 109 ++++++++++++++++++++++++++++---------- fs/fuse/fuse_i.h | 3 ++ include/uapi/linux/fuse.h | 2 +- 3 files changed, 84 insertions(+), 30 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 517c9add014d..cb99e529b3e9 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -516,14 +516,15 @@ static int get_security_context(struct dentry *entry,= umode_t mode, } =20 /* - * Atomic create+open operation + * If user has not implemented create ext or Atomic open + lookup + * then fall back to usual Atomic create/open operations. * - * If the filesystem doesn't support this, then fall back to separate - * 'mknod' + 'open' requests. + * If the filesystem doesn't support Atomic create + open, then + * fall back to separate 'mknod' + 'open' requests. */ static int fuse_atomic_common(struct inode *dir, struct dentry *entry, - struct file *file, unsigned int flags, - umode_t mode, uint32_t opcode) + struct dentry **alias, struct file *file, + unsigned int flags, umode_t mode, uint32_t opcode) { int err; struct inode *inode; @@ -538,10 +539,21 @@ static int fuse_atomic_common(struct inode *dir, stru= ct dentry *entry, struct dentry *res =3D NULL; void *security_ctx =3D NULL; u32 security_ctxlen; - bool ext_create =3D (opcode =3D=3D FUSE_CREATE_EXT ? true : false); + bool simple_create =3D (opcode =3D=3D FUSE_CREATE ? true : false); + bool create_ops =3D (simple_create || opcode =3D=3D FUSE_CREATE_EXT) ? + true : false; + bool skipped_lookup =3D (opcode =3D=3D FUSE_CREATE_EXT || + opcode =3D=3D FUSE_ATOMIC_OPEN) ? true : false; + + if (alias) + *alias =3D NULL; =20 /* Userspace expects S_IFREG in create mode */ - BUG_ON((mode & S_IFMT) !=3D S_IFREG); + if (create_ops && (mode & S_IFMT) !=3D S_IFREG) { + WARN_ON(1); + err =3D -EINVAL; + goto out_err; + } =20 forget =3D fuse_alloc_forget(); err =3D -ENOMEM; @@ -616,33 +628,38 @@ static int fuse_atomic_common(struct inode *dir, stru= ct dentry *entry, } kfree(forget); /* - * In extended create, fuse_lookup() was skipped, which also uses - * d_splice_alias(). As we come directly here after picking up dentry - * it is very much likely that dentry has DCACHE_PAR_LOOKUP flag set - * on it so call d_splice_alias(). + * In extended create/atomic open, fuse_lookup() is skipped which also + * uses d_splice_alias(). As we come directly here after picking up + * dentry it is very much likely that dentry has DCACHE_PAR_LOOKUP flag + * set on it so call d_splice_alias(). */ - if (!ext_create && !d_in_lookup(entry)) - d_instantiate(entry, inode); - else { + if (skipped_lookup) { res =3D d_splice_alias(inode, entry); - if (IS_ERR(res)) { - /* Close the file in user space, but do not unlink it, - * if it was created - with network file systems other - * clients might have already accessed it. - */ - fi =3D get_fuse_inode(inode); - fuse_sync_release(fi, ff, flags); - fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); - err =3D PTR_ERR(res); - goto out_err; + if (res) { + if (IS_ERR(res)) { + /* Close the file in user space, but do not unlink it, + * if it was created - with network file systems other + * clients might have already accessed it. + */ + fi =3D get_fuse_inode(inode); + fuse_sync_release(fi, ff, flags); + fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); + err =3D PTR_ERR(res); + goto out_err; + } + entry =3D res; + if (alias) + *alias =3D res; } - } + } else + d_instantiate(entry, inode); + fuse_change_entry_timeout(entry, &outentry); /* * This should be always set when the file is created, but only * CREATE_EXT introduced FOPEN_FILE_CREATED to user space. */ - if (!ext_create || (outopen.open_flags & FOPEN_FILE_CREATED)) { + if (simple_create || (outopen.open_flags & FOPEN_FILE_CREATED)) { fuse_dir_changed(dir); file->f_mode |=3D FMODE_CREATED; } @@ -674,7 +691,7 @@ static int fuse_create_ext(struct inode *dir, struct de= ntry *entry, if (fc->no_create_ext) return -ENOSYS; =20 - err =3D fuse_atomic_common(dir, entry, file, flags, mode, + err =3D fuse_atomic_common(dir, entry, NULL, file, flags, mode, FUSE_CREATE_EXT); /* If ext create is not implemented then indicate in fc so that next * request falls back to normal create instead of going into libufse and @@ -687,6 +704,31 @@ static int fuse_create_ext(struct inode *dir, struct d= entry *entry, return err; } =20 +static int fuse_do_atomic_open(struct inode *dir, struct dentry *entry, + struct dentry **alias, struct file *file, + unsigned int flags, umode_t mode) +{ + int err; + struct fuse_conn *fc =3D get_fuse_conn(dir); + + if (fc->no_atomic_open) + return -ENOSYS; + + err =3D fuse_atomic_common(dir, entry, alias, file, flags, mode, + FUSE_ATOMIC_OPEN); + + /* Set if atomic open not implemented */ + if (err =3D=3D -ENOSYS) { + if (!fc->no_atomic_open) + fc->no_atomic_open =3D 1; + + } else if (!fc->atomic_o_trunc) { + /* If atomic open is set then imply atomic truncate as well */ + fc->atomic_o_trunc =3D 1; + } + return err; +} + static int fuse_mknod(struct user_namespace *, struct inode *, struct dent= ry *, umode_t, dev_t); static int fuse_atomic_open(struct inode *dir, struct dentry *entry, @@ -695,13 +737,22 @@ static int fuse_atomic_open(struct inode *dir, struct= dentry *entry, { int err; struct fuse_conn *fc =3D get_fuse_conn(dir); - struct dentry *res =3D NULL; + struct dentry *res =3D NULL, *alias =3D NULL; bool create =3D flags & O_CREAT ? true : false; =20 if (fuse_is_bad(dir)) return -EIO; =20 + if (!create && !fc->no_atomic_open) { + err =3D fuse_do_atomic_open(dir, entry, &alias, + file, flags, mode); + res =3D alias; + if (err !=3D -ENOSYS) + goto out_dput; + } + lookup: + /* Fall back to open- user space does not have full atomic open */ if ((!create || fc->no_create_ext) && d_in_lookup(entry)) { res =3D fuse_lookup(dir, entry, 0); if (IS_ERR(res)) @@ -723,7 +774,7 @@ static int fuse_atomic_open(struct inode *dir, struct d= entry *entry, if (err =3D=3D -ENOSYS) goto lookup; } else - err =3D fuse_atomic_common(dir, entry, file, flags, mode, + err =3D fuse_atomic_common(dir, entry, NULL, file, flags, mode, FUSE_CREATE); if (err =3D=3D -ENOSYS) { fc->no_create =3D 1; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 266133dcab5e..949c230e14c7 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -675,6 +675,9 @@ struct fuse_conn { */ unsigned no_create_ext:1; =20 + /** Is atomic open implemented by fs ? */ + unsigned no_atomic_open : 1; + /** Is opendir/releasedir not implemented by fs? */ unsigned no_opendir:1; =20 diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index bebe4be3f1cb..f4c94e5bbffc 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -540,7 +540,7 @@ enum fuse_opcode { FUSE_REMOVEMAPPING =3D 49, FUSE_SYNCFS =3D 50, FUSE_CREATE_EXT =3D 51, - + FUSE_ATOMIC_OPEN =3D 52, /* CUSE specific operations */ CUSE_INIT =3D 4096, =20 --=20 2.17.1