From patchwork Tue Nov 22 02:15:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24120 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1956411wrr; Mon, 21 Nov 2022 18:18:07 -0800 (PST) X-Google-Smtp-Source: AA0mqf5rB1Dn5TYij813NMRC6Xv5hpmT10VCC90MDbCkUyAmitDtRdcXM8Sl/JOX4cQRIWHIbYgk X-Received: by 2002:a17:902:e94e:b0:188:f3b9:7156 with SMTP id b14-20020a170902e94e00b00188f3b97156mr1834561pll.76.1669083486937; Mon, 21 Nov 2022 18:18:06 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083486; cv=none; d=google.com; s=arc-20160816; b=hZYmxDRRs4Ib1+vGKZbvj00AkRk/U+p3PUIkUrfoqR/oz5PN3XCk2V/6sEgz6/0mHW cXR3za4N42lu+GgHK9DlQ2lWC/fOtS6BNyE0l6T1ic/6ncg2yXk77UsFT6GLuGA7mMrU yGSjUrUxf077uY6awuDlzIRZlRK7E+nmdpUemDdGz4lbeEUFw5Axwp5ZKjFI1S4wfAPr HowXL2tZGjlY66v0m5V4U3qlYCmCfKK49dqYk5Tyry0FzqJFmTWKx1hTVylypI0PY3tH YxHnSB+wUglwJHL+dwj1gIDtl6O5zHPi+u4n+g9Yv1ExW4Hyw+utIrvdhdr+Qjbe2hBR slKw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=JJiNTZDAcyBcjnZ9p/mphnfF01eV5b88yfC5YuUnZmM=; b=bLKjSa1u8bcOtCJOpOh1MZzoiogaNIbDryjEONTLmrfs/+WhPV9oBdpqRb6l8GywUr uREi/wm0TrvNPPUJ6Ux+nRkBIUY/oKTwXCLCYc3ELk1aZGyHkZMwhW1yMZx3i2soNpy5 iaKNS0PVnBpCrJ6itiEr6YIO95QD93o1NeoWPZ0iwEn3TRzei1aN52lC1wad0kViv4Km y6T5RHLaQ9AotVIq33UGro9/VaRW9zG2ZMGuvv7RMY31q3MrJjtl7WZP324wVuXOz/bz UWuAVOdTGNMfGx+NfwxCJuq3uPD2+c6tm4R3upjAkqY7Cn4UJQU1V/HW4NdxBu4uSMv9 MjvQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=cfFs8F08; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id il3-20020a17090b164300b002024f3f1f8bsi13858664pjb.70.2022.11.21.18.17.54; Mon, 21 Nov 2022 18:18:06 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=cfFs8F08; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229519AbiKVCQE (ORCPT + 99 others); Mon, 21 Nov 2022 21:16:04 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41572 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232361AbiKVCP5 (ORCPT ); Mon, 21 Nov 2022 21:15:57 -0500 Received: from mail-pl1-x649.google.com (mail-pl1-x649.google.com [IPv6:2607:f8b0:4864:20::649]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 065A0E14D7 for ; Mon, 21 Nov 2022 18:15:57 -0800 (PST) Received: by mail-pl1-x649.google.com with SMTP id l7-20020a170902f68700b001890d921b36so6209888plg.2 for ; Mon, 21 Nov 2022 18:15:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=JJiNTZDAcyBcjnZ9p/mphnfF01eV5b88yfC5YuUnZmM=; b=cfFs8F08u2LB6NT9MopIhiguqfQ7WXtFPUO7m1nt1MVmOu8TptOmISB0P+7KLmTetQ Dx6lCs7ljbXbkaXpWqn/sW+iZOX+CNmO7ANeKRWLmvWd0aGdTYHO92RDZ1f/BrwkmBDP esLlCvlF97McdXxQ7QmYwruQ2pTwIQx0q70gHeZE2pWIzYszefNf0R6ekyDZrQ3Bt13l YT3P4alOgbtMQFtKHuealnqJv7qBSCbl1waS4ud1ps5m+emFEYQ+c1p9be6XzvR0zo+O dLPKt+o3ppBSzUto+aIhc/AtAxi6lFKW2dBnHW+Fj58e8ptadwzho1KMyUrjYFPCbA6U jTbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=JJiNTZDAcyBcjnZ9p/mphnfF01eV5b88yfC5YuUnZmM=; b=u5aa+65t5mHgwBIBA/zkLZluA0hwH/sgqD/uTBy9134iYzV7ro0azJ48C64rH9xd53 WU/8mKnTimDw8IwJgnMXZrtX9EnuRhaMXTMqfCVG4n/uVXSeu8W7VPUFUJa7tWZPK52b 0YGC+2c8DCO4WNzDYJ912R7b7jpBxdIn9s6G1LINPlWyCl84dpdT6y7FyP3ps5MWHvJD pW275r4r9B2ELBCC7xjLW4KVQsNbPt9wwS2q7pI+zUWm8RWc7Mhc/a1c0iDdvG24N7bK apy2b1j2zutzAU5MIVAbZJ3xY7vs80SWr3IZDaq14JyBCkqwSDP9K4f6HKabWXdgNElm C1ug== X-Gm-Message-State: ANoB5pnF0Txb9w18T1G3PoNrIJpANHTWWfHAYvf4QUqvln8P4zVTBuiv 8RADPi5zhTKaT/7fUyA7ir6S/m47+GE= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a65:67c5:0:b0:477:76c0:1d13 with SMTP id b5-20020a6567c5000000b0047776c01d13mr3165786pgs.55.1669083356254; Mon, 21 Nov 2022 18:15:56 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:16 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-2-drosen@google.com> Subject: [RFC PATCH v2 01/21] fs: Generic function to convert iocb to rw flags From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Alessio Balsini , Alessio Balsini X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750160886415958723?= X-GMAIL-MSGID: =?utf-8?q?1750160886415958723?= From: Alessio Balsini OverlayFS implements its own function to translate iocb flags into rw flags, so that they can be passed into another vfs call. With commit ce71bfea207b4 ("fs: align IOCB_* flags with RWF_* flags") Jens created a 1:1 matching between the iocb flags and rw flags, simplifying the conversion. Reduce the OverlayFS code by making the flag conversion function generic and reusable. Signed-off-by: Alessio Balsini --- fs/overlayfs/file.c | 23 +++++------------------ include/linux/fs.h | 5 +++++ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index a1a22f58ba18..287ae968852a 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c @@ -15,6 +15,8 @@ #include #include "overlayfs.h" +#define OVL_IOCB_MASK (IOCB_DSYNC | IOCB_HIPRI | IOCB_NOWAIT | IOCB_SYNC) + struct ovl_aio_req { struct kiocb iocb; refcount_t ref; @@ -240,22 +242,6 @@ static void ovl_file_accessed(struct file *file) touch_atime(&file->f_path); } -static rwf_t ovl_iocb_to_rwf(int ifl) -{ - rwf_t flags = 0; - - if (ifl & IOCB_NOWAIT) - flags |= RWF_NOWAIT; - if (ifl & IOCB_HIPRI) - flags |= RWF_HIPRI; - if (ifl & IOCB_DSYNC) - flags |= RWF_DSYNC; - if (ifl & IOCB_SYNC) - flags |= RWF_SYNC; - - return flags; -} - static inline void ovl_aio_put(struct ovl_aio_req *aio_req) { if (refcount_dec_and_test(&aio_req->ref)) { @@ -315,7 +301,8 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter) old_cred = ovl_override_creds(file_inode(file)->i_sb); if (is_sync_kiocb(iocb)) { ret = vfs_iter_read(real.file, iter, &iocb->ki_pos, - ovl_iocb_to_rwf(iocb->ki_flags)); + iocb_to_rw_flags(iocb->ki_flags, + OVL_IOCB_MASK)); } else { struct ovl_aio_req *aio_req; @@ -379,7 +366,7 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter) if (is_sync_kiocb(iocb)) { file_start_write(real.file); ret = vfs_iter_write(real.file, iter, &iocb->ki_pos, - ovl_iocb_to_rwf(ifl)); + iocb_to_rw_flags(ifl, OVL_IOCB_MASK)); file_end_write(real.file); /* Update size */ ovl_copyattr(inode); diff --git a/include/linux/fs.h b/include/linux/fs.h index e654435f1651..c913106fdd65 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3434,6 +3434,11 @@ static inline int kiocb_set_rw_flags(struct kiocb *ki, rwf_t flags) return 0; } +static inline rwf_t iocb_to_rw_flags(int ifl, int iocb_mask) +{ + return ifl & iocb_mask; +} + static inline ino_t parent_ino(struct dentry *dentry) { ino_t res; From patchwork Tue Nov 22 02:15:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24121 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1956413wrr; Mon, 21 Nov 2022 18:18:07 -0800 (PST) X-Google-Smtp-Source: AA0mqf5Tu+g9GTSxvN1vwZ4bR9QJ5EcSxS+gjBaYOu12AiP28na5uP2+wc438khOlUqF/WCWjuYN X-Received: by 2002:a63:f95a:0:b0:46f:5be0:feb9 with SMTP id q26-20020a63f95a000000b0046f5be0feb9mr19858227pgk.485.1669083487060; Mon, 21 Nov 2022 18:18:07 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083487; cv=none; d=google.com; s=arc-20160816; b=HDnrKgbXaUPlq3Wv5Ni6EgLl3UrLkSUEQR3D5+RVkJvR0O8fyRNbr+nBtDZ6VYfgit yK/1TCJCwyqP3b7aPat775BT9qQxkdIycuyKDQvNmn3wt4V+EhKdPpl7VFwi1aOT0z4a yXvil8okF38HtFojrmLdphXHBQSBVmC2eEFGMkOtjmmW0ehEh9Wk/rjNaFFA8LOXXHNC ctIK1PjBBa2++UfnkW+pf5/oVyeEUPdatVhWCP7uZJQj4tA0868MQ50IpyyWQdRze0KV C3TWhVM5r2dQ7lOpQhUMv9DuT4VJLJHA2f8umKFc8jl5V9zuvsuBHLIbwqg8P5AYDl+Q kMdQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=Y0CYFA8id+z3HCWs5kIS2LaBGk6W/Uf1gWskynavTxc=; b=RUBcid/cKajtkKzSOVIbpYtaf5I9Lzdwuk51+CtiRNMfKHqjlnWJ5OBW3ONWbM3o+O 2DEEgu9LBWiTFXB8jzeKmSN7pfFYz+2+UUfCyt0BRfH0RBaRZc3n4KAwy3ZrKTTFvcU2 TlWB3I+k7YYnE+NW6ytY1QdNFifLQaNVALMaktwaiDrIB8QnKoOLJQGQ87ugQTSqt72L 1APj6nuOv+GFV5h7hgGEhRXGBqv2NdK5lxygYLIDl/0vY0FP5/45bVmtazl1L5teuxOa QEhvMjkAU6PpVHgq6GxEeTJcnsItVqaqA22IyNblWaTL+b0OCrwOtE3YGvcrGWyJ+63H Wxvw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=ShxBlDIA; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id q10-20020a056a00150a00b0056bce3dfaa8si13510030pfu.27.2022.11.21.18.17.54; Mon, 21 Nov 2022 18:18:07 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=ShxBlDIA; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232494AbiKVCQJ (ORCPT + 99 others); Mon, 21 Nov 2022 21:16:09 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41600 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229553AbiKVCQA (ORCPT ); Mon, 21 Nov 2022 21:16:00 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2F417E0CB1 for ; Mon, 21 Nov 2022 18:15:59 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id p188-20020a2542c5000000b006ea37a57e20so6626442yba.13 for ; Mon, 21 Nov 2022 18:15:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Y0CYFA8id+z3HCWs5kIS2LaBGk6W/Uf1gWskynavTxc=; b=ShxBlDIAwmGqs4fi1P8OTQDitIxkzNdyy6obpBx2DiuBICfglgIm/sEJ56k72mcrDk 7sLoBmC3BCBKNBVTw+a5yisI9f+LbrX/R2U/hPfRfpMyfdvSp6UftfpxF8ptuAxhR1Mc QGRV0dQNmsWkVelI+ut+E9YXVVVey/xFndnaY0+7hsgFk0UClNwfx7uB/GiuIE3WJxKQ 1tWaQL+uuqyCVQsmD7uv1PiRFexy5YwGgOZ9H2D50koMDi22pO5sT5Kyfhs1JNRKiAwl aIbAYznQ2PAOlxao5zbdAc37GRH4JJZVovarG4GlgWKkZq84useB0vbbhW6mKS1ak4Gp rFrg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Y0CYFA8id+z3HCWs5kIS2LaBGk6W/Uf1gWskynavTxc=; b=0YJrh+fJUK80RUQQRLdK5HHb0WJsSJbZxaTN9q2k1W8qMHFuht8ED4YEZENLbBQzPQ Cg9CMyin/TDv55BmrIEDt+rmlre0IQ06f7vveMiinOH3TO+oijYj1Tc7JRxAudr2Byi0 z5BVE6iPolBeKPyeMLqG3cQiKPAZAmlzRl2dzgnB51qRypY6mU7FGocYE/25LRdyk5U+ 1x1R1rtLZ3DbQxG4Fvi026XEQA155cI/fS9E7OtwPDfCQTCxhcWVkMv5O1Carvv0Cg8J 8bcfOBYP4NuxO3kE6eWhORjc0tbDFt3tZiF+PNAofVZ0yqK9wRMQsFN9ftU7vOGvKIrO DdZA== X-Gm-Message-State: ANoB5pm3Rzhefk+Xwqb5KJw9h9lKnu0EWhAwxhIppjdoD94Ujt4E4MUr QRoZjrTBf7e+iZmApXtVAtmpSFpVx4g= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a81:994a:0:b0:36f:d061:dfcd with SMTP id q71-20020a81994a000000b0036fd061dfcdmr1364844ywg.188.1669083358500; Mon, 21 Nov 2022 18:15:58 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:17 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-3-drosen@google.com> Subject: [RFC PATCH v2 02/21] fuse-bpf: Update fuse side uapi From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750160886643595740?= X-GMAIL-MSGID: =?utf-8?q?1750160886643595740?= Adds structures which will be used to inform fuse about what it is being stacked on top of. Once filters are in place, error_in will inform the post filter if the backing call returned an error. Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- include/uapi/linux/fuse.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 76ee8f9e024a..0e19076729d9 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -576,6 +576,21 @@ struct fuse_entry_out { struct fuse_attr attr; }; +#define FUSE_BPF_MAX_ENTRIES 2 + +enum fuse_bpf_type { + FUSE_ENTRY_BACKING = 1, + FUSE_ENTRY_BPF = 2, + FUSE_ENTRY_REMOVE_BACKING = 3, + FUSE_ENTRY_REMOVE_BPF = 4, +}; + +struct fuse_bpf_entry_out { + uint32_t entry_type; + uint32_t unused; + uint64_t fd; +}; + struct fuse_forget_in { uint64_t nlookup; }; @@ -874,7 +889,7 @@ struct fuse_in_header { uint32_t uid; uint32_t gid; uint32_t pid; - uint32_t padding; + uint32_t error_in; }; struct fuse_out_header { From patchwork Tue Nov 22 02:15:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24122 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1956419wrr; Mon, 21 Nov 2022 18:18:09 -0800 (PST) X-Google-Smtp-Source: AA0mqf6jhxcGa0r7uE86BdsEQR8pc/fhw+jt7e2u1uScIpT17XmJuzRh1dwy9Q2J8XmzZQsc6ARZ X-Received: by 2002:a17:903:2694:b0:188:53b9:f003 with SMTP id jf20-20020a170903269400b0018853b9f003mr2384642plb.170.1669083489333; Mon, 21 Nov 2022 18:18:09 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083489; cv=none; d=google.com; s=arc-20160816; b=rgDE1k1K4soIFCZWx9omBSTfjxVptflOOjbHtmDaQ/tEX5K1PwItJe05/EKohf9jib cHNNCd53Q5sqKs8jwzgAgMQUIYXueXfEgK7mHz0f1C/e+Ts4YRDTwMeBkft+ChsOGXXt YSCqhISHgjVJsk55qvxp/JveFYbzsFvd1irvC1G/qEJ6TGxii4dQBxgOW4iyC65CWCRh EzfzqgUa2ppiYRzFkuuniEPFbD1aJnqsRTwjh7Toz3W0/gUfTTM8uBuSpLhYPBm1b1W4 5+iYrNI8MCK0FDWmsZDCWwveLsnppbuwsoixgG0Xhpaqkc7wWnfFhTiWxmnaGtmTBB0Z 7qpg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=76QMXC6mJ9CAtH5i+yrdnZDHqT+yu4res8J20D/aqg0=; b=0WrUzc/nQBJE1vP7Ck8f3f/3Dg4VjHjJwcyytbIaLxM7Sp+E28eHM9PrigSpcuzl7p mnbcQOWCGdPh+K9Vi7mqaTkPjQ91nRuokIPbFtbyH+oXkg0uiR8C/0QK2PCOasaj5IMw YDFrOMG/K4smL42ReU02OAJnXZI2UlvUmKkd8wp4hiN+Uf39uKgYtDWveHec4Y9Xky9j JY5+1oSs5b9vC1VGDLHy7epKeZUcy5AaIrZ/ut9iJx+IDdvsbBv/Rejyddb+fg4oixMH f7gJaZ3h9Ds2vkf4y+TFio+bEh2zspxrCLJ/DHshcTeP14noA1RBJ/JIUDFtSx53Gwyo hm2g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=l2D1VL2C; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id n19-20020a635913000000b0046ec381a28bsi12886990pgb.25.2022.11.21.18.17.56; Mon, 21 Nov 2022 18:18:09 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=l2D1VL2C; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232435AbiKVCQX (ORCPT + 99 others); Mon, 21 Nov 2022 21:16:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41652 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232475AbiKVCQD (ORCPT ); Mon, 21 Nov 2022 21:16:03 -0500 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C7E96E14D7 for ; Mon, 21 Nov 2022 18:16:01 -0800 (PST) Received: by mail-yb1-xb4a.google.com with SMTP id y6-20020a25b9c6000000b006c1c6161716so12406594ybj.8 for ; Mon, 21 Nov 2022 18:16:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=76QMXC6mJ9CAtH5i+yrdnZDHqT+yu4res8J20D/aqg0=; b=l2D1VL2CNvcisUBCfC7TgWMOqx1HOlygw+itHxo7cwEflDooq8QM69jmRhG7gICfG1 hTRGKLnw8K5QuEa9EZLI8ENeRVJuE5SOMmwyPEJjhVZy0H050FJFI8bz4Vc6mrIwQZiN IHCMrogofo5yeziIRnPzb2b9NCBrL1dKOr1Rsx6IvGn9BCrV+CvaI40xmoq/Pkys4N5M T3A4myoeL008QjavUGxH+DQmWe0rU2ZlIK4qlzvsHCPG7wJ1NfooXYDhkk2wqyNTgLh6 h4HPd9c+S/3Z1zd8RBtIkE3BvCURRYwFwWk/vQDvb+L1wb6OV2nLlCOUJuixxEhWkpxi G6lA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=76QMXC6mJ9CAtH5i+yrdnZDHqT+yu4res8J20D/aqg0=; b=CEGGliAkEYPpN/ZXX6Bxm+B7XD5i1GQgB0LEZUflcIumH8tnciV37njeTS2L7RvW3a xOM1UPpeAw5eTFK8bkjhBp2pEy59i5Du/yjR2URNNszDMJ+SeovNAZss75fy0/gPywan rTdEk1Bf5j6cCjKmn+jyOYkfadDlCyvK3tAH1ONhqPosSevnx5N+I4Xbzi+8RjBmC4x9 pSeO79J0XzND9ipv98MngafhzOmLNFMH+VrRAzAMmRdGCZPs8NU3aJeAuhSLpTfwTrr2 zpWObr0uqzL5nyKnFeZRhFfYcsU9Qplqdc5u4aWnhrVbTaA3Y9MpMgp4CK2BkI8hmvIG rCOg== X-Gm-Message-State: ANoB5pmeoTq5AoNgC8W//5+wfcATfiBF5ZlOlyhyC+vJnPtjDSPio4aY LzxXzS2/7so4zeAhx94//nQH1efwWnc= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a25:1c07:0:b0:6dd:fed7:8128 with SMTP id c7-20020a251c07000000b006ddfed78128mr1729703ybc.131.1669083360508; Mon, 21 Nov 2022 18:16:00 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:18 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-4-drosen@google.com> Subject: [RFC PATCH v2 03/21] fuse-bpf: Prepare for fuse-bpf patch From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750160889219030822?= X-GMAIL-MSGID: =?utf-8?q?1750160889219030822?= This moves some functions and structs around to make the following patch easier to read. Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/dir.c | 30 ------------------------------ fs/fuse/fuse_i.h | 35 +++++++++++++++++++++++++++++++++++ fs/fuse/inode.c | 44 ++++++++++++++++++++++---------------------- 3 files changed, 57 insertions(+), 52 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index bb97a384dc5d..168903cadb54 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -46,10 +46,6 @@ static inline u64 fuse_dentry_time(const struct dentry *entry) } #else -union fuse_dentry { - u64 time; - struct rcu_head rcu; -}; static inline void __fuse_dentry_settime(struct dentry *dentry, u64 time) { @@ -83,27 +79,6 @@ static void fuse_dentry_settime(struct dentry *dentry, u64 time) __fuse_dentry_settime(dentry, time); } -/* - * FUSE caches dentries and attributes with separate timeout. The - * time in jiffies until the dentry/attributes are valid is stored in - * dentry->d_fsdata and fuse_inode->i_time respectively. - */ - -/* - * Calculate the time in jiffies until a dentry/attributes are valid - */ -static u64 time_to_jiffies(u64 sec, u32 nsec) -{ - if (sec || nsec) { - struct timespec64 ts = { - sec, - min_t(u32, nsec, NSEC_PER_SEC - 1) - }; - - return get_jiffies_64() + timespec64_to_jiffies(&ts); - } else - return 0; -} /* * Set dentry and possibly attribute timeouts from the lookup/mk* @@ -115,11 +90,6 @@ void fuse_change_entry_timeout(struct dentry *entry, struct fuse_entry_out *o) time_to_jiffies(o->entry_valid, o->entry_valid_nsec)); } -static u64 attr_timeout(struct fuse_attr_out *o) -{ - return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); -} - u64 entry_attr_timeout(struct fuse_entry_out *o) { return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 98a9cf531873..57453296e662 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -63,6 +63,14 @@ struct fuse_forget_link { struct fuse_forget_link *next; }; +/** FUSE specific dentry data */ +#if BITS_PER_LONG < 64 +union fuse_dentry { + u64 time; + struct rcu_head rcu; +}; +#endif + /** FUSE inode */ struct fuse_inode { /** Inode data */ @@ -1319,4 +1327,31 @@ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, void fuse_file_release(struct inode *inode, struct fuse_file *ff, unsigned int open_flags, fl_owner_t id, bool isdir); +/* + * FUSE caches dentries and attributes with separate timeout. The + * time in jiffies until the dentry/attributes are valid is stored in + * dentry->d_fsdata and fuse_inode->i_time respectively. + */ + +/* + * Calculate the time in jiffies until a dentry/attributes are valid + */ +static inline u64 time_to_jiffies(u64 sec, u32 nsec) +{ + if (sec || nsec) { + struct timespec64 ts = { + sec, + min_t(u32, nsec, NSEC_PER_SEC - 1) + }; + + return get_jiffies_64() + timespec64_to_jiffies(&ts); + } else + return 0; +} + +static inline u64 attr_timeout(struct fuse_attr_out *o) +{ + return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); +} + #endif /* _FS_FUSE_I_H */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 6b3beda16c1b..504336d56a7f 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -162,6 +162,28 @@ static ino_t fuse_squash_ino(u64 ino64) return ino; } +static void fuse_fill_attr_from_inode(struct fuse_attr *attr, + const struct fuse_inode *fi) +{ + *attr = (struct fuse_attr){ + .ino = fi->inode.i_ino, + .size = fi->inode.i_size, + .blocks = fi->inode.i_blocks, + .atime = fi->inode.i_atime.tv_sec, + .mtime = fi->inode.i_mtime.tv_sec, + .ctime = fi->inode.i_ctime.tv_sec, + .atimensec = fi->inode.i_atime.tv_nsec, + .mtimensec = fi->inode.i_mtime.tv_nsec, + .ctimensec = fi->inode.i_ctime.tv_nsec, + .mode = fi->inode.i_mode, + .nlink = fi->inode.i_nlink, + .uid = fi->inode.i_uid.val, + .gid = fi->inode.i_gid.val, + .rdev = fi->inode.i_rdev, + .blksize = 1u << fi->inode.i_blkbits, + }; +} + void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, u64 attr_valid, u32 cache_mask) { @@ -1386,28 +1408,6 @@ void fuse_dev_free(struct fuse_dev *fud) } EXPORT_SYMBOL_GPL(fuse_dev_free); -static void fuse_fill_attr_from_inode(struct fuse_attr *attr, - const struct fuse_inode *fi) -{ - *attr = (struct fuse_attr){ - .ino = fi->inode.i_ino, - .size = fi->inode.i_size, - .blocks = fi->inode.i_blocks, - .atime = fi->inode.i_atime.tv_sec, - .mtime = fi->inode.i_mtime.tv_sec, - .ctime = fi->inode.i_ctime.tv_sec, - .atimensec = fi->inode.i_atime.tv_nsec, - .mtimensec = fi->inode.i_mtime.tv_nsec, - .ctimensec = fi->inode.i_ctime.tv_nsec, - .mode = fi->inode.i_mode, - .nlink = fi->inode.i_nlink, - .uid = fi->inode.i_uid.val, - .gid = fi->inode.i_gid.val, - .rdev = fi->inode.i_rdev, - .blksize = 1u << fi->inode.i_blkbits, - }; -} - static void fuse_sb_defaults(struct super_block *sb) { sb->s_magic = FUSE_SUPER_MAGIC; From patchwork Tue Nov 22 02:15:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24128 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1956866wrr; Mon, 21 Nov 2022 18:19:20 -0800 (PST) X-Google-Smtp-Source: AA0mqf6crC8sDLZsbt8gHHW/dJKWh9b1zOSZcaMwjU8HW8vcOU7x+P+7jYx4CDjbN+1xMTjw92dM X-Received: by 2002:a63:224c:0:b0:46b:8e9:747 with SMTP id t12-20020a63224c000000b0046b08e90747mr1264530pgm.365.1669083559827; Mon, 21 Nov 2022 18:19:19 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083559; cv=none; d=google.com; s=arc-20160816; b=iTavk16WP/lhDIS/CuWAgSZsHAqu+7agSflg/lXJIFYFOSqU3A9UwHlAwgSg5B9ojZ pKM512HSv3YC3Ot8z1E9vj0CbFozgCbpM8fEc6WVFgCzaeYxwi5KyzvadmLf638oAdRM /j0tGOzhgFbQ+Yi6KhjpH6jcIDbWLb0ALx1GGoFdtShY3jPHyQroQs2e1+lUyeK1pvIe /H+1pud4m7rdxU6iGG/H6H808kh+68IFf7HkrPyReXf877Ilq/0qLF4IP9o3Gi3PqJbk GOpa/ejGUQdNrbMz3i+HJHl7SLodKjrvz8HSmmSX0Vi6FDLL6kZiayvAlI9AXUjPbLmm 7jhQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=9UWu0g2nySQwX4/9jlio/nP2cnjQwiiQ4/U1fMJ0ICI=; b=jsntNcrjrx6MNgT0iwrbihNyAT3LMWAke1ZSC6StqVGhfKsKa512M76DMH8VkHHkYN PKNFEQpg8IIjVDP6HzBdSv8VjTeIM86LQdpl+Y4Q3iJHwxBMMH3mJh1Kp3EmY+UdrmWs 4/im5+pgJIgl6435X+emeRhm68sv6OkDfqGfs8koxCBluggX50QimOWTg+Jbicn/xssq 3L5hNrLporG5THm5ASkZi5FijINTSmM7QRmItA6H0ur4r71CqKShu69ZZs/emhv91bGg EXP26eEox0cWfCszlgTDxgrCzirYRW6lRCU0mVgSbhCUSjk5MHKtHfF7lq29ZYtdDt0l 5vDw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=eSiZHiU5; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id u9-20020a170902e80900b00177568a0e53si6337366plg.252.2022.11.21.18.19.06; Mon, 21 Nov 2022 18:19:19 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=eSiZHiU5; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232444AbiKVCQf (ORCPT + 99 others); Mon, 21 Nov 2022 21:16:35 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42122 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232346AbiKVCQU (ORCPT ); Mon, 21 Nov 2022 21:16:20 -0500 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1432BE3D11 for ; Mon, 21 Nov 2022 18:16:04 -0800 (PST) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-391bd92f931so121218797b3.22 for ; Mon, 21 Nov 2022 18:16:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=9UWu0g2nySQwX4/9jlio/nP2cnjQwiiQ4/U1fMJ0ICI=; b=eSiZHiU5wNVl1snjTpE+NZ07db+97rzIZjpcXnkKAGctoRyTIv0dHUQKvs2wQJiHfP Km4ftAFV9YtwF4+WPgEEiTM4PGAC8VZVyFhWzL33VmKpPiu3zTgVa9CvCCdziDA1T0f/ HO1H1uMWxm9MvA+Q0pW7fXVmH3+r0wzGN2XHKRvDX6EVaTthtZD1WE8YpGfaiDU5SuOG yTSBX3P5geOrmw7nshHDuUJpRemavX1Mt5mxUXIMp3ln8sOtQC4wdWsXMxrvuR7ujZfy V+In2Held2pdZ6osqv/RN4Ul/OE/NrocsiePU1HzFOHvo6QQ00wd7Z8aD+tsGQdshvww /n7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=9UWu0g2nySQwX4/9jlio/nP2cnjQwiiQ4/U1fMJ0ICI=; b=4/voLmYeX8tv2LXE5nDJbNj3F9WSzo2roMKLiIOMkqoL3TZtCNlqQvGXn86Mkw5aEp JOqVKqcVt4UsvBWlclSwNEurVVuY3HT/l6ESZtl9rdgJkqBPC7VP2ykNE4qIMrZXJP0c dpHoHZdXsgigSfC2qgI+euWPVSb8dhfoi3MHAN9qLgpXsHJnnRwD1p5HoGgv9SFv37j4 PZcnIxa1pyX4Z/rZn9WG8JXlBSTI3c/6DmFJzMG7bxN9MlPhf37XfcuKzwPfPkKB2TDE 53ukfHeeQKFxqm2K6SqCagsBExHkymZ+9+gYfibVBVyNFAbKN1g2DQJLTbIt5i4aCA5I Lq8w== X-Gm-Message-State: ANoB5pkh/qgB0lv6Rg/wzTb9G+942uyzbi5EuoWiCiOpmS29Oz8r4JML Bgg2/4Y7J0YZFnSFxM8ovT3jN6qE4Ro= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a81:920c:0:b0:3a7:c0d4:8c6b with SMTP id j12-20020a81920c000000b003a7c0d48c6bmr0ywg.377.1669083363364; Mon, 21 Nov 2022 18:16:03 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:19 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-5-drosen@google.com> Subject: [RFC PATCH v2 04/21] fuse: Add fuse-bpf, a stacked fs extension for FUSE From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence , Alessio Balsini X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750160962743381993?= X-GMAIL-MSGID: =?utf-8?q?1750160962743381993?= Fuse-bpf provides a short circuit path for Fuse implementations that act as a stacked filesystem. For cases that are directly unchanged, operations are passed directly to the backing filesystem. Small adjustments can be handled by bpf prefilters or postfilters, with the option to fall back to userspace as needed. Fuse implementations may supply backing node information, as well as bpf programs via an optional add on to the lookup structure. This has been split over the next set of patches for readability. Clusters of fuse ops have been split into their own patches, as well as the actual bpf calls and userspace calls for filters. Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence Signed-off-by: Alessio Balsini --- fs/fuse/Kconfig | 8 + fs/fuse/Makefile | 1 + fs/fuse/backing.c | 392 ++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/dev.c | 41 ++++- fs/fuse/dir.c | 187 +++++++++++++++++----- fs/fuse/file.c | 25 ++- fs/fuse/fuse_i.h | 99 +++++++++++- fs/fuse/inode.c | 189 +++++++++++++++++----- fs/fuse/ioctl.c | 2 +- 9 files changed, 861 insertions(+), 83 deletions(-) create mode 100644 fs/fuse/backing.c diff --git a/fs/fuse/Kconfig b/fs/fuse/Kconfig index 038ed0b9aaa5..3a64fa73e591 100644 --- a/fs/fuse/Kconfig +++ b/fs/fuse/Kconfig @@ -52,3 +52,11 @@ config FUSE_DAX If you want to allow mounting a Virtio Filesystem with the "dax" option, answer Y. + +config FUSE_BPF + bool "Adds BPF to fuse" + depends on FUSE_FS + depends on BPF + help + Extends FUSE by adding BPF to prefilter calls and potentially pass to a + backing file system diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile index 0c48b35c058d..a0853c439db2 100644 --- a/fs/fuse/Makefile +++ b/fs/fuse/Makefile @@ -9,5 +9,6 @@ obj-$(CONFIG_VIRTIO_FS) += virtiofs.o fuse-y := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o ioctl.o fuse-$(CONFIG_FUSE_DAX) += dax.o +fuse-$(CONFIG_FUSE_BPF) += backing.o virtiofs-y := virtio_fs.o diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c new file mode 100644 index 000000000000..5a59a8963d52 --- /dev/null +++ b/fs/fuse/backing.c @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FUSE-BPF: Filesystem in Userspace with BPF + * Copyright (c) 2021 Google LLC + */ + +#include "fuse_i.h" + +#include +#include +#include +#include + +/* + * expression statement to wrap the backing filter logic + * struct inode *inode: inode with bpf and backing inode + * typedef io: (typically complex) type whose components fuse_args can point to. + * An instance of this type is created locally and passed to initialize + * void initialize_in(struct fuse_args *fa, io *in_out, args...): function that sets + * up fa and io based on args + * void initialize_out(struct fuse_args *fa, io *in_out, args...): function that sets + * up fa and io based on args + * int backing(struct fuse_bpf_args_internal *fa, args...): function that actually performs + * the backing io operation + * void *finalize(struct fuse_bpf_args *, args...): function that performs any final + * work needed to commit the backing io + */ +#define fuse_bpf_backing(inode, io, out, initialize_in, initialize_out, \ + backing, finalize, args...) \ +({ \ + struct fuse_inode *fuse_inode = get_fuse_inode(inode); \ + struct fuse_args fa = { 0 }; \ + bool initialized = false; \ + bool handled = false; \ + ssize_t res; \ + io feo = { 0 }; \ + int error = 0; \ + \ + do { \ + if (!fuse_inode || !fuse_inode->backing_inode) \ + break; \ + \ + handled = true; \ + error = initialize_in(&fa, &feo, args); \ + if (error) \ + break; \ + \ + error = initialize_out(&fa, &feo, args); \ + if (error) \ + break; \ + \ + initialized = true; \ + \ + error = backing(&fa, out, args); \ + if (error < 0) \ + fa.error_in = error; \ + \ + } while (false); \ + \ + if (initialized && handled) { \ + res = finalize(&fa, out, args); \ + if (res) \ + error = res; \ + } \ + \ + *out = error ? _Generic((*out), \ + default : \ + error, \ + struct dentry * : \ + ERR_PTR(error), \ + const char * : \ + ERR_PTR(error) \ + ) : (*out); \ + handled; \ +}) + +static void fuse_get_backing_path(struct file *file, struct path *path) +{ + path_get(&file->f_path); + *path = file->f_path; +} + +static bool has_file(int type) +{ + return type == FUSE_ENTRY_BACKING; +} + +/* + * The optional fuse bpf entry lists the backing file for a particular + * lookup. These are inherited by default. + * + * In the future, we may support multiple bpfs, and multiple backing files for + * the bpf to choose between. + * + * Currently, the expected format is possibly a bpf program, then the backing + * file. Changing only the bpf is valid, though meaningless if there isn't an + * inherited backing file. + * + * Support for the bpf program will be added in a later patch + * + */ +int parse_fuse_bpf_entry(struct fuse_bpf_entry *fbe, int num) +{ + struct fuse_bpf_entry_out *fbeo; + struct file *file; + bool has_backing = false; + int num_entries; + int err = -EINVAL; + int i; + + if (num > 0) + num_entries = num; + else + num_entries = FUSE_BPF_MAX_ENTRIES; + + for (i = 0; i < num_entries; i++) { + file = NULL; + fbeo = &fbe->out[i]; + + /* reserved for future use */ + if (fbeo->unused != 0) + goto out_err; + + if (has_file(fbeo->entry_type)) { + file = fget(fbeo->fd); + if (!file) { + err = -EBADF; + goto out_err; + } + } + + switch (fbeo->entry_type) { + case 0: + if (num == -1) + num_entries = i; + else + goto out_err; + break; + case FUSE_ENTRY_REMOVE_BACKING: + if (fbe->backing_action) + goto out_err; + fbe->backing_action = FUSE_BPF_REMOVE; + break; + case FUSE_ENTRY_BACKING: + if (fbe->backing_action) + goto out_err; + fuse_get_backing_path(file, &fbe->backing_path); + fbe->backing_action = FUSE_BPF_SET; + has_backing = true; + break; + default: + err = -EINVAL; + goto out_err; + } + if (has_file(fbeo->entry_type)) { + fput(file); + file = NULL; + } + } + + fbe->is_used = num_entries > 0; + + return 0; +out_err: + if (file) + fput(file); + if (has_backing) + path_put_init(&fbe->backing_path); + return err; +} + +static void fuse_stat_to_attr(struct fuse_conn *fc, struct inode *inode, + struct kstat *stat, struct fuse_attr *attr) +{ + unsigned int blkbits; + + /* see the comment in fuse_change_attributes() */ + if (fc->writeback_cache && S_ISREG(inode->i_mode)) { + stat->size = i_size_read(inode); + stat->mtime.tv_sec = inode->i_mtime.tv_sec; + stat->mtime.tv_nsec = inode->i_mtime.tv_nsec; + stat->ctime.tv_sec = inode->i_ctime.tv_sec; + stat->ctime.tv_nsec = inode->i_ctime.tv_nsec; + } + + attr->ino = stat->ino; + attr->mode = (inode->i_mode & S_IFMT) | (stat->mode & 07777); + attr->nlink = stat->nlink; + attr->uid = from_kuid(fc->user_ns, stat->uid); + attr->gid = from_kgid(fc->user_ns, stat->gid); + attr->atime = stat->atime.tv_sec; + attr->atimensec = stat->atime.tv_nsec; + attr->mtime = stat->mtime.tv_sec; + attr->mtimensec = stat->mtime.tv_nsec; + attr->ctime = stat->ctime.tv_sec; + attr->ctimensec = stat->ctime.tv_nsec; + attr->size = stat->size; + attr->blocks = stat->blocks; + + if (stat->blksize != 0) + blkbits = ilog2(stat->blksize); + else + blkbits = inode->i_sb->s_blocksize_bits; + + attr->blksize = 1 << blkbits; +} + +/******************************************************************************* + * Directory operations after here * + ******************************************************************************/ + +struct fuse_lookup_io { + struct fuse_entry_out feo; + struct fuse_bpf_entry fbe; +}; + +static int fuse_lookup_initialize_in(struct fuse_args *fa, struct fuse_lookup_io *fli, + struct inode *dir, struct dentry *entry, unsigned int flags) +{ + *fa = (struct fuse_args) { + .nodeid = get_fuse_inode(dir)->nodeid, + .opcode = FUSE_LOOKUP, + .in_numargs = 1, + .in_args[0] = (struct fuse_in_arg) { + .size = entry->d_name.len + 1, + .value = (void *) entry->d_name.name, + }, + }; + + return 0; +} + +static int fuse_lookup_initialize_out(struct fuse_args *fa, struct fuse_lookup_io *fli, + struct inode *dir, struct dentry *entry, unsigned int flags) +{ + fa->out_numargs = 2; + fa->out_argvar = true; + fa->is_lookup = true; + fa->out_args[0] = (struct fuse_arg) { + .size = sizeof(fli->feo), + .value = &fli->feo, + }; + fa->out_args[1] = (struct fuse_arg) { + .size = sizeof(fli->fbe.out), + .value = fli->fbe.out, + }; + + return 0; +} + +static int fuse_lookup_backing(struct fuse_args *fa, struct dentry **out, struct inode *dir, + struct dentry *entry, unsigned int flags) +{ + struct fuse_dentry *fuse_entry = get_fuse_dentry(entry); + struct fuse_dentry *dir_fuse_entry = get_fuse_dentry(entry->d_parent); + struct dentry *dir_backing_entry = dir_fuse_entry->backing_path.dentry; + struct inode *dir_backing_inode = dir_backing_entry->d_inode; + struct fuse_entry_out *feo = (void *)fa->out_args[0].value; + struct dentry *backing_entry; + const char *name; + struct kstat stat; + int len; + int err; + + /* TODO this will not handle lookups over mount points */ + inode_lock_nested(dir_backing_inode, I_MUTEX_PARENT); + name = entry->d_name.name; + len = entry->d_name.len; + + backing_entry = lookup_one_len(name, dir_backing_entry, len); + inode_unlock(dir_backing_inode); + + if (IS_ERR(backing_entry)) + return PTR_ERR(backing_entry); + + fuse_entry->backing_path = (struct path) { + .dentry = backing_entry, + .mnt = mntget(dir_fuse_entry->backing_path.mnt), + }; + + if (d_is_negative(backing_entry)) + return 0; + + err = vfs_getattr(&fuse_entry->backing_path, &stat, + STATX_BASIC_STATS, 0); + if (err) { + path_put_init(&fuse_entry->backing_path); + return err; + } + + fuse_stat_to_attr(get_fuse_conn(dir), + backing_entry->d_inode, &stat, &feo->attr); + return 0; +} + +int fuse_handle_backing(struct fuse_bpf_entry *fbe, struct path *backing_path) +{ + switch (fbe->backing_action) { + case FUSE_BPF_UNCHANGED: + /* backing inode/path are added in fuse_lookup_backing */ + break; + + case FUSE_BPF_REMOVE: + path_put_init(backing_path); + break; + + case FUSE_BPF_SET: { + if (!fbe->backing_path.dentry) + return -EINVAL; + + path_put(backing_path); + *backing_path = fbe->backing_path; + fbe->backing_path.dentry = NULL; + fbe->backing_path.mnt = NULL; + + break; + } + + default: + return -EINVAL; + } + + return 0; +} + +static int fuse_lookup_finalize(struct fuse_args *fa, struct dentry **out, + struct inode *dir, struct dentry *entry, unsigned int flags) +{ + struct fuse_dentry *fd; + struct dentry *backing_dentry; + struct inode *inode, *backing_inode; + struct inode *d_inode = entry->d_inode; + struct fuse_entry_out *feo = fa->out_args[0].value; + struct fuse_bpf_entry_out *febo = fa->out_args[1].value; + struct fuse_bpf_entry *fbe = container_of(febo, struct fuse_bpf_entry, out[0]); + int error = -1; + u64 target_nodeid = 0; + + parse_fuse_bpf_entry(fbe, -1); + fd = get_fuse_dentry(entry); + if (!fd) + return -EIO; + error = fuse_handle_backing(fbe, &fd->backing_path); + if (error) + return error; + backing_dentry = fd->backing_path.dentry; + if (!backing_dentry) + return -ENOENT; + backing_inode = backing_dentry->d_inode; + if (!backing_inode) { + *out = 0; + return 0; + } + + if (d_inode) + target_nodeid = get_fuse_inode(d_inode)->nodeid; + + inode = fuse_iget_backing(dir->i_sb, target_nodeid, backing_inode); + + if (IS_ERR(inode)) + return PTR_ERR(inode); + + get_fuse_inode(inode)->nodeid = feo->nodeid; + + *out = d_splice_alias(inode, entry); + return 0; +} + +int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct dentry *entry, unsigned int flags) +{ + return fuse_bpf_backing(dir, struct fuse_lookup_io, out, + fuse_lookup_initialize_in, fuse_lookup_initialize_out, + fuse_lookup_backing, fuse_lookup_finalize, + dir, entry, flags); +} + +int fuse_revalidate_backing(struct dentry *entry, unsigned int flags) +{ + struct fuse_dentry *fuse_dentry = get_fuse_dentry(entry); + struct dentry *backing_entry = fuse_dentry->backing_path.dentry; + + spin_lock(&backing_entry->d_lock); + if (d_unhashed(backing_entry)) { + spin_unlock(&backing_entry->d_lock); + return 0; + } + spin_unlock(&backing_entry->d_lock); + + if (unlikely(backing_entry->d_flags & DCACHE_OP_REVALIDATE)) + return backing_entry->d_op->d_revalidate(backing_entry, flags); + return 1; +} diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index b4a6e0a1b945..79d2fb6adc83 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -238,6 +238,11 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, { struct fuse_iqueue *fiq = &fc->iq; + if (nodeid == 0) { + kfree(forget); + return; + } + forget->forget_one.nodeid = nodeid; forget->forget_one.nlookup = nlookup; @@ -1006,10 +1011,38 @@ static int fuse_copy_one(struct fuse_copy_state *cs, void *val, unsigned size) return 0; } +/* Copy the fuse-bpf lookup args and verify them */ +#ifdef CONFIG_FUSE_BPF +static int fuse_copy_lookup(struct fuse_copy_state *cs, void *val, unsigned size) +{ + struct fuse_bpf_entry_out *fbeo = (struct fuse_bpf_entry_out *)val; + struct fuse_bpf_entry *feb = container_of(fbeo, struct fuse_bpf_entry, out[0]); + int num_entries = size / sizeof(*fbeo); + int err; + + if (size && size % sizeof(*fbeo) != 0) + return -EINVAL; + + if (num_entries > FUSE_BPF_MAX_ENTRIES) + return -EINVAL; + err = fuse_copy_one(cs, val, size); + if (err) + return err; + if (size) + err = parse_fuse_bpf_entry(feb, num_entries); + return err; +} +#else +static int fuse_copy_lookup(struct fuse_copy_state *cs, void *val, unsigned size) +{ + return fuse_copy_one(cs, val, size); +} +#endif + /* Copy request arguments to/from userspace buffer */ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs, unsigned argpages, struct fuse_arg *args, - int zeroing) + int zeroing, unsigned is_lookup) { int err = 0; unsigned i; @@ -1018,6 +1051,8 @@ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs, struct fuse_arg *arg = &args[i]; if (i == numargs - 1 && argpages) err = fuse_copy_pages(cs, arg->size, zeroing); + else if (i == numargs - 1 && is_lookup) + err = fuse_copy_lookup(cs, arg->value, arg->size); else err = fuse_copy_one(cs, arg->value, arg->size); } @@ -1295,7 +1330,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, err = fuse_copy_one(cs, &req->in.h, sizeof(req->in.h)); if (!err) err = fuse_copy_args(cs, args->in_numargs, args->in_pages, - (struct fuse_arg *) args->in_args, 0); + (struct fuse_arg *) args->in_args, 0, 0); fuse_copy_finish(cs); spin_lock(&fpq->lock); clear_bit(FR_LOCKED, &req->flags); @@ -1834,7 +1869,7 @@ static int copy_out_args(struct fuse_copy_state *cs, struct fuse_args *args, lastarg->size -= diffsize; } return fuse_copy_args(cs, args->out_numargs, args->out_pages, - args->out_args, args->page_zeroing); + args->out_args, args->page_zeroing, args->is_lookup); } /* diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 168903cadb54..fb7c6988f0d9 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -34,7 +34,7 @@ static void fuse_advise_use_readdirplus(struct inode *dir) set_bit(FUSE_I_ADVISE_RDPLUS, &fi->state); } -#if BITS_PER_LONG >= 64 +#if BITS_PER_LONG >= 64 && !defined(CONFIG_FUSE_BPF) static inline void __fuse_dentry_settime(struct dentry *entry, u64 time) { entry->d_fsdata = (void *) time; @@ -49,12 +49,12 @@ static inline u64 fuse_dentry_time(const struct dentry *entry) static inline void __fuse_dentry_settime(struct dentry *dentry, u64 time) { - ((union fuse_dentry *) dentry->d_fsdata)->time = time; + ((struct fuse_dentry *) dentry->d_fsdata)->time = time; } static inline u64 fuse_dentry_time(const struct dentry *entry) { - return ((union fuse_dentry *) entry->d_fsdata)->time; + return ((struct fuse_dentry *) entry->d_fsdata)->time; } #endif @@ -79,6 +79,17 @@ static void fuse_dentry_settime(struct dentry *dentry, u64 time) __fuse_dentry_settime(dentry, time); } +void fuse_init_dentry_root(struct dentry *root, struct file *backing_dir) +{ +#ifdef CONFIG_FUSE_BPF + struct fuse_dentry *fuse_dentry = root->d_fsdata; + + if (backing_dir) { + fuse_dentry->backing_path = backing_dir->f_path; + path_get(&fuse_dentry->backing_path); + } +#endif +} /* * Set dentry and possibly attribute timeouts from the lookup/mk* @@ -150,7 +161,8 @@ static void fuse_invalidate_entry(struct dentry *entry) static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args, u64 nodeid, const struct qstr *name, - struct fuse_entry_out *outarg) + struct fuse_entry_out *outarg, + struct fuse_bpf_entry_out *bpf_outarg) { memset(outarg, 0, sizeof(struct fuse_entry_out)); args->opcode = FUSE_LOOKUP; @@ -158,10 +170,43 @@ static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args, args->in_numargs = 1; args->in_args[0].size = name->len + 1; args->in_args[0].value = name->name; - args->out_numargs = 1; + args->out_argvar = true; + args->out_numargs = 2; args->out_args[0].size = sizeof(struct fuse_entry_out); args->out_args[0].value = outarg; + args->out_args[1].size = sizeof(struct fuse_bpf_entry_out) * FUSE_BPF_MAX_ENTRIES; + args->out_args[1].value = bpf_outarg; + args->is_lookup = 1; +} + +#ifdef CONFIG_FUSE_BPF +static bool backing_data_changed(struct fuse_inode *fi, struct dentry *entry, + struct fuse_bpf_entry *bpf_arg) +{ + struct path new_backing_path; + struct inode *new_backing_inode; + int err; + bool ret = true; + + if (!entry) + return false; + + get_fuse_backing_path(entry, &new_backing_path); + + err = fuse_handle_backing(bpf_arg, &new_backing_path); + new_backing_inode = d_inode(new_backing_path.dentry); + + if (err) + goto put_inode; + + ret = (fi->backing_inode != new_backing_inode || + !path_equal(&get_fuse_dentry(entry)->backing_path, &new_backing_path)); + +put_inode: + path_put(&new_backing_path); + return ret; } +#endif /* * Check whether the dentry is still valid @@ -183,9 +228,23 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) inode = d_inode_rcu(entry); if (inode && fuse_is_bad(inode)) goto invalid; - else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) || + +#ifdef CONFIG_FUSE_BPF + /* TODO: Do we need bpf support for revalidate? + * If the lower filesystem says the entry is invalid, FUSE probably shouldn't + * try to fix that without going through the normal lookup path... + */ + if (get_fuse_dentry(entry)->backing_path.dentry) { + ret = fuse_revalidate_backing(entry, flags); + if (ret <= 0) { + goto out; + } + } +#endif + if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) || (flags & (LOOKUP_EXCL | LOOKUP_REVAL))) { struct fuse_entry_out outarg; + struct fuse_bpf_entry bpf_arg; FUSE_ARGS(args); struct fuse_forget_link *forget; u64 attr_version; @@ -197,27 +256,44 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) ret = -ECHILD; if (flags & LOOKUP_RCU) goto out; - fm = get_fuse_mount(inode); + parent = dget_parent(entry); + +#ifdef CONFIG_FUSE_BPF + /* TODO: Once we're handling timeouts for backing inodes, do a + * bpf based lookup_revalidate here. + */ + if (get_fuse_inode(parent->d_inode)->backing_inode) { + dput(parent); + ret = 1; + goto out; + } +#endif forget = fuse_alloc_forget(); ret = -ENOMEM; - if (!forget) + if (!forget) { + dput(parent); goto out; + } attr_version = fuse_get_attr_version(fm->fc); - parent = dget_parent(entry); fuse_lookup_init(fm->fc, &args, get_node_id(d_inode(parent)), - &entry->d_name, &outarg); + &entry->d_name, &outarg, bpf_arg.out); ret = fuse_simple_request(fm, &args); dput(parent); + /* Zero nodeid is same as -ENOENT */ if (!ret && !outarg.nodeid) ret = -ENOENT; - if (!ret) { + if (!ret || bpf_arg.is_used) { fi = get_fuse_inode(inode); if (outarg.nodeid != get_node_id(inode) || +#ifdef CONFIG_FUSE_BPF + (bpf_arg.is_used && + backing_data_changed(fi, entry, &bpf_arg)) || +#endif (bool) IS_AUTOMOUNT(inode) != (bool) (outarg.attr.flags & FUSE_ATTR_SUBMOUNT)) { fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); @@ -259,17 +335,20 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) goto out; } -#if BITS_PER_LONG < 64 +#if BITS_PER_LONG < 64 || defined(CONFIG_FUSE_BPF) static int fuse_dentry_init(struct dentry *dentry) { - dentry->d_fsdata = kzalloc(sizeof(union fuse_dentry), + dentry->d_fsdata = kzalloc(sizeof(struct fuse_dentry), GFP_KERNEL_ACCOUNT | __GFP_RECLAIMABLE); return dentry->d_fsdata ? 0 : -ENOMEM; } static void fuse_dentry_release(struct dentry *dentry) { - union fuse_dentry *fd = dentry->d_fsdata; + struct fuse_dentry *fd = dentry->d_fsdata; + + if (fd && fd->backing_path.dentry) + path_put(&fd->backing_path); kfree_rcu(fd, rcu); } @@ -310,7 +389,7 @@ static struct vfsmount *fuse_dentry_automount(struct path *path) const struct dentry_operations fuse_dentry_operations = { .d_revalidate = fuse_dentry_revalidate, .d_delete = fuse_dentry_delete, -#if BITS_PER_LONG < 64 +#if BITS_PER_LONG < 64 || defined(CONFIG_FUSE_BPF) .d_init = fuse_dentry_init, .d_release = fuse_dentry_release, #endif @@ -318,7 +397,7 @@ const struct dentry_operations fuse_dentry_operations = { }; const struct dentry_operations fuse_root_dentry_operations = { -#if BITS_PER_LONG < 64 +#if BITS_PER_LONG < 64 || defined(CONFIG_FUSE_BPF) .d_init = fuse_dentry_init, .d_release = fuse_dentry_release, #endif @@ -336,11 +415,13 @@ bool fuse_invalid_attr(struct fuse_attr *attr) attr->size > LLONG_MAX; } -int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name, - struct fuse_entry_out *outarg, struct inode **inode) +int fuse_lookup_name(struct super_block *sb, u64 nodeid, + const struct qstr *name, struct fuse_entry_out *outarg, + struct dentry *entry, struct inode **inode) { struct fuse_mount *fm = get_fuse_mount_super(sb); FUSE_ARGS(args); + struct fuse_bpf_entry bpf_arg = { 0 }; struct fuse_forget_link *forget; u64 attr_version; int err; @@ -358,23 +439,56 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name attr_version = fuse_get_attr_version(fm->fc); - fuse_lookup_init(fm->fc, &args, nodeid, name, outarg); + fuse_lookup_init(fm->fc, &args, nodeid, name, outarg, bpf_arg.out); err = fuse_simple_request(fm, &args); - /* Zero nodeid is same as -ENOENT, but with valid timeout */ - if (err || !outarg->nodeid) - goto out_put_forget; - err = -EIO; - if (!outarg->nodeid) - goto out_put_forget; - if (fuse_invalid_attr(&outarg->attr)) - goto out_put_forget; - - *inode = fuse_iget(sb, outarg->nodeid, outarg->generation, - &outarg->attr, entry_attr_timeout(outarg), - attr_version); +#ifdef CONFIG_FUSE_BPF + if (bpf_arg.is_used) { + /* TODO Make sure this handles invalid handles */ + struct path *backing_path; + struct inode *backing_inode; + + err = -ENOENT; + if (!entry) + goto out_queue_forget; + + err = -EINVAL; + backing_path = &bpf_arg.backing_path; + if (!backing_path->dentry) + goto out_queue_forget; + + err = fuse_handle_backing(&bpf_arg, + &get_fuse_dentry(entry)->backing_path); + if (err) + goto out_queue_forget; + + backing_inode = d_inode(get_fuse_dentry(entry)->backing_path.dentry); + *inode = fuse_iget_backing(sb, outarg->nodeid, backing_inode); + if (!*inode) + goto out_queue_forget; + } else +#endif + { + /* Zero nodeid is same as -ENOENT, but with valid timeout */ + if (err || !outarg->nodeid) + goto out_put_forget; + + err = -EIO; + if (!outarg->nodeid) + goto out_put_forget; + if (fuse_invalid_attr(&outarg->attr)) + goto out_put_forget; + + *inode = fuse_iget(sb, outarg->nodeid, outarg->generation, + &outarg->attr, entry_attr_timeout(outarg), + attr_version); + } + err = -ENOMEM; - if (!*inode) { +#ifdef CONFIG_FUSE_BPF +out_queue_forget: +#endif + if (!*inode && outarg->nodeid) { fuse_queue_forget(fm->fc, forget, outarg->nodeid, 1); goto out; } @@ -399,9 +513,12 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, if (fuse_is_bad(dir)) return ERR_PTR(-EIO); + if (fuse_bpf_lookup(&newent, dir, entry, flags)) + return newent; + locked = fuse_lock_inode(dir); err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name, - &outarg, &inode); + &outarg, entry, &inode); fuse_unlock_inode(dir, locked); if (err == -ENOENT) { outarg_valid = false; @@ -1295,6 +1412,7 @@ static int fuse_permission(struct user_namespace *mnt_userns, struct fuse_conn *fc = get_fuse_conn(inode); bool refreshed = false; int err = 0; + struct fuse_inode *fi = get_fuse_inode(inode); if (fuse_is_bad(inode)) return -EIO; @@ -1307,7 +1425,6 @@ static int fuse_permission(struct user_namespace *mnt_userns, */ if (fc->default_permissions || ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { - struct fuse_inode *fi = get_fuse_inode(inode); u32 perm_mask = STATX_MODE | STATX_UID | STATX_GID; if (perm_mask & READ_ONCE(fi->inval_mask) || @@ -1484,7 +1601,7 @@ static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd, FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR); } -static bool update_mtime(unsigned ivalid, bool trust_local_mtime) +static inline bool update_mtime(unsigned int ivalid, bool trust_local_mtime) { /* Always update if mtime is explicitly set */ if (ivalid & ATTR_MTIME_SET) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 71bfb663aac5..503327be3942 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -8,6 +8,7 @@ #include "fuse_i.h" +#include #include #include #include @@ -125,13 +126,18 @@ static void fuse_file_put(struct fuse_file *ff, bool sync, bool isdir) } struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, - unsigned int open_flags, bool isdir) + unsigned int open_flags, bool isdir, struct file *file) { struct fuse_conn *fc = fm->fc; struct fuse_file *ff; int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; - ff = fuse_file_alloc(fm); + if (file && file->private_data) { + ff = file->private_data; + file->private_data = NULL; + } else { + ff = fuse_file_alloc(fm); + } if (!ff) return ERR_PTR(-ENOMEM); @@ -169,7 +175,7 @@ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file, bool isdir) { - struct fuse_file *ff = fuse_file_open(fm, nodeid, file->f_flags, isdir); + struct fuse_file *ff = fuse_file_open(fm, nodeid, file->f_flags, isdir, file); if (!IS_ERR(ff)) file->private_data = ff; @@ -1873,6 +1879,19 @@ int fuse_write_inode(struct inode *inode, struct writeback_control *wbc) */ WARN_ON(wbc->for_reclaim); + /** + * TODO - fully understand why this is necessary + * + * With fuse-bpf, fsstress fails if rename is enabled without this + * + * We are getting writes here on directory inodes, which do not have an + * initialized file list so crash. + * + * The question is why we are getting those writes + */ + if (!S_ISREG(inode->i_mode)) + return 0; + ff = __fuse_write_file_get(fi); err = fuse_flush_times(inode, ff); if (ff) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 57453296e662..d67325af5e72 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -31,6 +33,7 @@ #include #include #include +#include /** Default max number of pages that can be used in a single read request */ #define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32 @@ -64,11 +67,35 @@ struct fuse_forget_link { }; /** FUSE specific dentry data */ -#if BITS_PER_LONG < 64 -union fuse_dentry { - u64 time; - struct rcu_head rcu; +#if BITS_PER_LONG < 64 || defined(CONFIG_FUSE_BPF) +struct fuse_dentry { + union { + u64 time; + struct rcu_head rcu; + }; + struct path backing_path; }; + +static inline struct fuse_dentry *get_fuse_dentry(const struct dentry *entry) +{ + return entry->d_fsdata; +} +#endif + +#ifdef CONFIG_FUSE_BPF +static inline void get_fuse_backing_path(const struct dentry *d, + struct path *path) +{ + struct fuse_dentry *di = get_fuse_dentry(d); + + if (!di) { + *path = (struct path) { .mnt = 0, .dentry = 0 }; + return; + } + + *path = di->backing_path; + path_get(path); +} #endif /** FUSE inode */ @@ -76,6 +103,14 @@ struct fuse_inode { /** Inode data */ struct inode inode; +#ifdef CONFIG_FUSE_BPF + /** + * Backing inode, if this inode is from a backing file system. + * If this is set, nodeid is 0. + */ + struct inode *backing_inode; +#endif + /** Unique ID, which identifies the inode between userspace * and kernel */ u64 nodeid; @@ -226,6 +261,14 @@ struct fuse_file { } readdir; +#ifdef CONFIG_FUSE_BPF + /** + * TODO: Reconcile with passthrough file + * backing file when in bpf mode + */ + struct file *backing_file; +#endif + /** RB node to be linked on fuse_conn->polled_files */ struct rb_node polled_node; @@ -257,6 +300,7 @@ struct fuse_page_desc { struct fuse_args { uint64_t nodeid; uint32_t opcode; + uint32_t error_in; unsigned short in_numargs; unsigned short out_numargs; bool force:1; @@ -269,6 +313,7 @@ struct fuse_args { bool page_zeroing:1; bool page_replace:1; bool may_block:1; + bool is_lookup:1; struct fuse_in_arg in_args[3]; struct fuse_arg out_args[2]; void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error); @@ -522,6 +567,7 @@ struct fuse_fs_context { unsigned int max_read; unsigned int blksize; const char *subtype; + struct file *root_dir; /* DAX device, may be NULL */ struct dax_device *dax_dev; @@ -965,12 +1011,16 @@ extern const struct dentry_operations fuse_root_dentry_operations; /** * Get a filled in inode */ +struct inode *fuse_iget_backing(struct super_block *sb, + u64 nodeid, + struct inode *backing_inode); struct inode *fuse_iget(struct super_block *sb, u64 nodeid, int generation, struct fuse_attr *attr, u64 attr_valid, u64 attr_version); int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name, - struct fuse_entry_out *outarg, struct inode **inode); + struct fuse_entry_out *outarg, + struct dentry *entry, struct inode **inode); /** * Send FORGET command @@ -1115,6 +1165,7 @@ void fuse_invalidate_entry_cache(struct dentry *entry); void fuse_invalidate_atime(struct inode *inode); u64 entry_attr_timeout(struct fuse_entry_out *o); +void fuse_init_dentry_root(struct dentry *root, struct file *backing_dir); void fuse_change_entry_timeout(struct dentry *entry, struct fuse_entry_out *o); /** @@ -1323,10 +1374,46 @@ int fuse_fileattr_set(struct user_namespace *mnt_userns, /* file.c */ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, - unsigned int open_flags, bool isdir); + unsigned int open_flags, bool isdir, + struct file *file); void fuse_file_release(struct inode *inode, struct fuse_file *ff, unsigned int open_flags, fl_owner_t id, bool isdir); +/* backing.c */ + +enum fuse_bpf_set { + FUSE_BPF_UNCHANGED = 0, + FUSE_BPF_SET, + FUSE_BPF_REMOVE, +}; + +struct fuse_bpf_entry { + struct fuse_bpf_entry_out out[FUSE_BPF_MAX_ENTRIES]; + + enum fuse_bpf_set backing_action; + struct path backing_path; + bool is_used; +}; + +int parse_fuse_bpf_entry(struct fuse_bpf_entry *fbe, int num_entries); + +#ifdef CONFIG_FUSE_BPF + +int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct dentry *entry, unsigned int flags); + +#else + +static inline int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct dentry *entry, unsigned int flags) +{ + return 0; +} + +#endif // CONFIG_FUSE_BPF + +int fuse_handle_backing(struct fuse_bpf_entry *feb, struct path *backing_path); + +int fuse_revalidate_backing(struct dentry *entry, unsigned int flags); + /* * FUSE caches dentries and attributes with separate timeout. The * time in jiffies until the dentry/attributes are valid is stored in diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 504336d56a7f..224d7dfe754d 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -78,6 +78,9 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) fi->i_time = 0; fi->inval_mask = 0; +#ifdef CONFIG_FUSE_BPF + fi->backing_inode = NULL; +#endif fi->nodeid = 0; fi->nlookup = 0; fi->attr_version = 0; @@ -120,6 +123,10 @@ static void fuse_evict_inode(struct inode *inode) /* Will write inode on close/munmap and in all other dirtiers */ WARN_ON(inode->i_state & I_DIRTY_INODE); +#ifdef CONFIG_FUSE_BPF + iput(fi->backing_inode); +#endif + truncate_inode_pages_final(&inode->i_data); clear_inode(inode); if (inode->i_sb->s_flags & SB_ACTIVE) { @@ -163,24 +170,24 @@ static ino_t fuse_squash_ino(u64 ino64) } static void fuse_fill_attr_from_inode(struct fuse_attr *attr, - const struct fuse_inode *fi) + const struct inode *inode) { *attr = (struct fuse_attr){ - .ino = fi->inode.i_ino, - .size = fi->inode.i_size, - .blocks = fi->inode.i_blocks, - .atime = fi->inode.i_atime.tv_sec, - .mtime = fi->inode.i_mtime.tv_sec, - .ctime = fi->inode.i_ctime.tv_sec, - .atimensec = fi->inode.i_atime.tv_nsec, - .mtimensec = fi->inode.i_mtime.tv_nsec, - .ctimensec = fi->inode.i_ctime.tv_nsec, - .mode = fi->inode.i_mode, - .nlink = fi->inode.i_nlink, - .uid = fi->inode.i_uid.val, - .gid = fi->inode.i_gid.val, - .rdev = fi->inode.i_rdev, - .blksize = 1u << fi->inode.i_blkbits, + .ino = inode->i_ino, + .size = inode->i_size, + .blocks = inode->i_blocks, + .atime = inode->i_atime.tv_sec, + .mtime = inode->i_mtime.tv_sec, + .ctime = inode->i_ctime.tv_sec, + .atimensec = inode->i_atime.tv_nsec, + .mtimensec = inode->i_mtime.tv_nsec, + .ctimensec = inode->i_ctime.tv_nsec, + .mode = inode->i_mode, + .nlink = inode->i_nlink, + .uid = inode->i_uid.val, + .gid = inode->i_gid.val, + .rdev = inode->i_rdev, + .blksize = 1u << inode->i_blkbits, }; } @@ -351,28 +358,105 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { fuse_init_common(inode); - init_special_inode(inode, inode->i_mode, - new_decode_dev(attr->rdev)); + init_special_inode(inode, inode->i_mode, attr->rdev); } else BUG(); } +struct fuse_inode_identifier { + u64 nodeid; + struct inode *backing_inode; +}; + static int fuse_inode_eq(struct inode *inode, void *_nodeidp) { - u64 nodeid = *(u64 *) _nodeidp; - if (get_node_id(inode) == nodeid) - return 1; - else - return 0; + struct fuse_inode_identifier *fii = + (struct fuse_inode_identifier *) _nodeidp; + struct fuse_inode *fi = get_fuse_inode(inode); + + return fii->nodeid == fi->nodeid; +} + +static int fuse_inode_backing_eq(struct inode *inode, void *_nodeidp) +{ + struct fuse_inode_identifier *fii = + (struct fuse_inode_identifier *) _nodeidp; + struct fuse_inode *fi = get_fuse_inode(inode); + + return fii->nodeid == fi->nodeid +#ifdef CONFIG_FUSE_BPF + && fii->backing_inode == fi->backing_inode +#endif + ; } static int fuse_inode_set(struct inode *inode, void *_nodeidp) { - u64 nodeid = *(u64 *) _nodeidp; - get_fuse_inode(inode)->nodeid = nodeid; + struct fuse_inode_identifier *fii = + (struct fuse_inode_identifier *) _nodeidp; + struct fuse_inode *fi = get_fuse_inode(inode); + + fi->nodeid = fii->nodeid; + + return 0; +} + +static int fuse_inode_backing_set(struct inode *inode, void *_nodeidp) +{ + struct fuse_inode_identifier *fii = + (struct fuse_inode_identifier *) _nodeidp; + struct fuse_inode *fi = get_fuse_inode(inode); + + fi->nodeid = fii->nodeid; +#ifdef CONFIG_FUSE_BPF + BUG_ON(fi->backing_inode != NULL); + fi->backing_inode = fii->backing_inode; + if (fi->backing_inode) + ihold(fi->backing_inode); +#endif + return 0; } +struct inode *fuse_iget_backing(struct super_block *sb, u64 nodeid, + struct inode *backing_inode) +{ + struct inode *inode; + struct fuse_inode *fi; + struct fuse_conn *fc = get_fuse_conn_super(sb); + struct fuse_inode_identifier fii = { + .nodeid = nodeid, + .backing_inode = backing_inode, + }; + struct fuse_attr attr; + unsigned long hash = (unsigned long) backing_inode; + + if (nodeid) + hash = nodeid; + + fuse_fill_attr_from_inode(&attr, backing_inode); + inode = iget5_locked(sb, hash, fuse_inode_backing_eq, + fuse_inode_backing_set, &fii); + if (!inode) + return NULL; + + if ((inode->i_state & I_NEW)) { + inode->i_flags |= S_NOATIME; + if (!fc->writeback_cache) + inode->i_flags |= S_NOCMTIME; + fuse_init_common(inode); + unlock_new_inode(inode); + } + + fi = get_fuse_inode(inode); + fuse_init_inode(inode, &attr); + spin_lock(&fi->lock); + fi->nlookup++; + spin_unlock(&fi->lock); + + return inode; +} + struct inode *fuse_iget(struct super_block *sb, u64 nodeid, int generation, struct fuse_attr *attr, u64 attr_valid, u64 attr_version) @@ -380,6 +464,9 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, struct inode *inode; struct fuse_inode *fi; struct fuse_conn *fc = get_fuse_conn_super(sb); + struct fuse_inode_identifier fii = { + .nodeid = nodeid, + }; /* * Auto mount points get their node id from the submount root, which is @@ -401,7 +488,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, } retry: - inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid); + inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &fii); if (!inode) return NULL; @@ -433,13 +520,16 @@ struct inode *fuse_ilookup(struct fuse_conn *fc, u64 nodeid, { struct fuse_mount *fm_iter; struct inode *inode; + struct fuse_inode_identifier fii = { + .nodeid = nodeid, + }; WARN_ON(!rwsem_is_locked(&fc->killsb)); list_for_each_entry(fm_iter, &fc->mounts, fc_entry) { if (!fm_iter->sb) continue; - inode = ilookup5(fm_iter->sb, nodeid, fuse_inode_eq, &nodeid); + inode = ilookup5(fm_iter->sb, nodeid, fuse_inode_eq, &fii); if (inode) { if (fm) *fm = fm_iter; @@ -669,6 +759,7 @@ enum { OPT_ALLOW_OTHER, OPT_MAX_READ, OPT_BLKSIZE, + OPT_ROOT_DIR, OPT_ERR }; @@ -683,6 +774,7 @@ static const struct fs_parameter_spec fuse_fs_parameters[] = { fsparam_u32 ("max_read", OPT_MAX_READ), fsparam_u32 ("blksize", OPT_BLKSIZE), fsparam_string ("subtype", OPT_SUBTYPE), + fsparam_u32 ("root_dir", OPT_ROOT_DIR), {} }; @@ -766,6 +858,12 @@ static int fuse_parse_param(struct fs_context *fsc, struct fs_parameter *param) ctx->blksize = result.uint_32; break; + case OPT_ROOT_DIR: + ctx->root_dir = fget(result.uint_32); + if (!ctx->root_dir) + return invalfc(fsc, "Unable to open root directory"); + break; + default: return -EINVAL; } @@ -778,6 +876,8 @@ static void fuse_free_fsc(struct fs_context *fsc) struct fuse_fs_context *ctx = fsc->fs_private; if (ctx) { + if (ctx->root_dir) + fput(ctx->root_dir); kfree(ctx->subtype); kfree(ctx); } @@ -905,15 +1005,29 @@ struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) } EXPORT_SYMBOL_GPL(fuse_conn_get); -static struct inode *fuse_get_root_inode(struct super_block *sb, unsigned mode) +static struct inode *fuse_get_root_inode(struct super_block *sb, + unsigned int mode, + struct file *backing_fd) { struct fuse_attr attr; - memset(&attr, 0, sizeof(attr)); + struct inode *inode; + memset(&attr, 0, sizeof(attr)); attr.mode = mode; attr.ino = FUSE_ROOT_ID; attr.nlink = 1; - return fuse_iget(sb, 1, 0, &attr, 0, 0); + inode = fuse_iget(sb, 1, 0, &attr, 0, 0); + if (!inode) + return NULL; + +#ifdef CONFIG_FUSE_BPF + if (backing_fd) { + get_fuse_inode(inode)->backing_inode = backing_fd->f_inode; + ihold(backing_fd->f_inode); + } +#endif + + return inode; } struct fuse_inode_handle { @@ -928,11 +1042,14 @@ static struct dentry *fuse_get_dentry(struct super_block *sb, struct inode *inode; struct dentry *entry; int err = -ESTALE; + struct fuse_inode_identifier fii = { + .nodeid = handle->nodeid, + }; if (handle->nodeid == 0) goto out_err; - inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid); + inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &fii); if (!inode) { struct fuse_entry_out outarg; const struct qstr name = QSTR_INIT(".", 1); @@ -941,7 +1058,7 @@ static struct dentry *fuse_get_dentry(struct super_block *sb, goto out_err; err = fuse_lookup_name(sb, handle->nodeid, &name, &outarg, - &inode); + NULL, &inode); if (err && err != -ENOENT) goto out_err; if (err || !inode) { @@ -1035,13 +1152,14 @@ static struct dentry *fuse_get_parent(struct dentry *child) struct inode *inode; struct dentry *parent; struct fuse_entry_out outarg; + const struct qstr name = QSTR_INIT("..", 2); int err; if (!fc->export_support) return ERR_PTR(-ESTALE); err = fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode), - &dotdot_name, &outarg, &inode); + &name, &outarg, NULL, &inode); if (err) { if (err == -ENOENT) return ERR_PTR(-ESTALE); @@ -1451,7 +1569,7 @@ static int fuse_fill_super_submount(struct super_block *sb, if (parent_sb->s_subtype && !sb->s_subtype) return -ENOMEM; - fuse_fill_attr_from_inode(&root_attr, parent_fi); + fuse_fill_attr_from_inode(&root_attr, &parent_fi->inode); root = fuse_iget(sb, parent_fi->nodeid, 0, &root_attr, 0, 0); /* * This inode is just a duplicate, so it is not looked up and @@ -1580,11 +1698,12 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) fc->no_force_umount = ctx->no_force_umount; err = -ENOMEM; - root = fuse_get_root_inode(sb, ctx->rootmode); + root = fuse_get_root_inode(sb, ctx->rootmode, ctx->root_dir); sb->s_d_op = &fuse_root_dentry_operations; root_dentry = d_make_root(root); if (!root_dentry) goto err_dev_free; + fuse_init_dentry_root(root_dentry, ctx->root_dir); /* Root dentry doesn't have .d_revalidate */ sb->s_d_op = &fuse_dentry_operations; diff --git a/fs/fuse/ioctl.c b/fs/fuse/ioctl.c index 61d8afcb10a3..8bc8d50917e2 100644 --- a/fs/fuse/ioctl.c +++ b/fs/fuse/ioctl.c @@ -422,7 +422,7 @@ static struct fuse_file *fuse_priv_ioctl_prepare(struct inode *inode) if (!S_ISREG(inode->i_mode) && !isdir) return ERR_PTR(-ENOTTY); - return fuse_file_open(fm, get_node_id(inode), O_RDONLY, isdir); + return fuse_file_open(fm, get_node_id(inode), O_RDONLY, isdir, NULL); } static void fuse_priv_ioctl_cleanup(struct inode *inode, struct fuse_file *ff) From patchwork Tue Nov 22 02:15:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24123 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1956550wrr; Mon, 21 Nov 2022 18:18:28 -0800 (PST) X-Google-Smtp-Source: AA0mqf7CfW/+kS7lep2Ez9l1jnFgYBedf9mOhW54xihsEOJB4sfPNpJ2h26keBQ3nRg3kF/QqQI/ X-Received: by 2002:a05:6a00:21c8:b0:560:e4d1:8df5 with SMTP id t8-20020a056a0021c800b00560e4d18df5mr1887304pfj.39.1669083508185; Mon, 21 Nov 2022 18:18:28 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083508; cv=none; d=google.com; s=arc-20160816; b=dNVKRriKZJoyDjC9uIwXoAbPWRAi1X58NJo+ov3mfMpwB8/YpppWpo4Wc1hcZiTyUz NdreQFXeEkl5nblE5TdIdqmELfoga/i20tapWr2jNVWa3XJjptJ11h9Qc+mqnINmvML8 FLbdVmHQQlRkDRKyQgWnxMgzw45EvbEQPRnV/mewukhq0HJ+KUqrjbe2E7SppwavDzl7 CTGzM4fPK6ZDS2oDZ4WGo+n+if+5MVzQxu5ecUtGQYTcQxNaQqQtfSPNIny14nJXuhoW 0eMqoRud6/06T0JX3vcAFouzCWx26Dk3eRdsRz8ChxBngGYXg+brON7tTIj9AjAOkPZH gjAw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=w2q3Pe5xMPw4X/9LVfd4DivdDutjiK3KnsX8KQ2N8hg=; b=bx/FX510b3CQIhy4IAYTnFwRd4gmgoCCt97FXzxpGhMlgUmf6EFmmDH7SknlSbSr7o JEzNIyGQXUnXxTpDsoO1YfRSZSxa0hYn2OaFz8AIe3vCY8ZPNC87yKlUA2+ZTKTbyeHJ Arm2+9RI6S0AJa8qvvdDpzvIIv+TYqp1WPGlBQDhsPJuEd8Cx0ZGvT7JIAS/F9lC10g7 f5F4FRZBtXZC8leKGQl4y9zIdNKjvZG627DacSRoID12du2oaYCDE7Efl6FH8T+sx2Vi w1Nde32iAAuPbRpxxvnKe+8vjNVftaH4SaPwalaXnv73mmVZQDRzHvkrlX4pPMB7fdUG y2lg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b="aTBA/4Jq"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id k7-20020aa788c7000000b0056d568dc21dsi13754117pff.153.2022.11.21.18.18.14; Mon, 21 Nov 2022 18:18:28 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b="aTBA/4Jq"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231837AbiKVCQo (ORCPT + 99 others); Mon, 21 Nov 2022 21:16:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42122 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232455AbiKVCQc (ORCPT ); Mon, 21 Nov 2022 21:16:32 -0500 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9D7CAE3D36 for ; Mon, 21 Nov 2022 18:16:06 -0800 (PST) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-399c3d7b039so72214397b3.3 for ; Mon, 21 Nov 2022 18:16:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=w2q3Pe5xMPw4X/9LVfd4DivdDutjiK3KnsX8KQ2N8hg=; b=aTBA/4JqNfwuIeF/z6qbwtHTisSmHirpljRg/jqvop/zWE55jxwONCGDNplDOvHIUW EdpMWtBWdM/Q73DKy22ZiPzuWMZIje8JjbI6oo1SzHSUA74BDWub9IHwW0c1jTUAMbyG qOkCaE9aSL9MCjO6dYMB9PFb0aSX8Hfbqe2UBhcL5iq8ZkRxKNPjQ5ioSBSVeFYk0Qqm Z6DISHRrhTLBKncu7nRqFeA8S3zpz179cTjAmXPcklE8oU9QjNuSHkGrM1Ep/EIROqyT +Xu7VQDk/YnBsHGQZGJERKD3mSGCPFH4bds3NFKtzGnpePnm86694b/7JnzRw2PKb2tW dKoQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=w2q3Pe5xMPw4X/9LVfd4DivdDutjiK3KnsX8KQ2N8hg=; b=Gg4bptFsB56DqMow85R9BkfA2KgjoPSiq6C50lq1vHeBftyHhH0ExzzoyWVlpXweR3 j3q8adhyASsR1eVa/GLCUuUnRmB4UPPPLfMjQ93bahreWywq5NNF1aYX0XaKSCZ9fxp2 GgJ0Zh13ja5ZNVDettovLGLMB3b2JbZo98F0lBDPhR98p73xnLZHUK8KssaUxjS9NAbA PG3UwursDidm8OSOPI06XIjhxQwisRc9eSoA7WfvApdRapmH+kOApu4l4TrwgFxqrVOg Xx47hlcQGFgyY9BLvVyyX+jX9w2jEdv9+QEvPXszQ7E2dugfQmoLcCwkSGJRGn/AspXA sk/w== X-Gm-Message-State: ANoB5plbRcTh/1e0W2s+pYEj2Z8fQdbAv5/AuYaTiUZI6jFda9KCp2+9 hy/13V6DREPQhjrVtyRadkr52bovdBo= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a81:47c2:0:b0:388:7d2:587b with SMTP id u185-20020a8147c2000000b0038807d2587bmr3633337ywa.416.1669083365933; Mon, 21 Nov 2022 18:16:05 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:20 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-6-drosen@google.com> Subject: [RFC PATCH v2 05/21] fuse-bpf: Add ioctl interface for /dev/fuse From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750160908193423679?= X-GMAIL-MSGID: =?utf-8?q?1750160908193423679?= This introduces an alternative method of responding to fuse requests. Lookups supplying a backing fd or bpf will need to call through the ioctl to ensure there can be no attempts to fool priveledged processes into inadvertantly performing other actions. Signed-off-by: Daniel Rosenberg --- fs/fuse/dev.c | 56 ++++++++++++++++++++++++++++++++------- fs/fuse/fuse_i.h | 1 + include/uapi/linux/fuse.h | 1 + 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 79d2fb6adc83..fbc519c37e66 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1013,18 +1013,19 @@ static int fuse_copy_one(struct fuse_copy_state *cs, void *val, unsigned size) /* Copy the fuse-bpf lookup args and verify them */ #ifdef CONFIG_FUSE_BPF -static int fuse_copy_lookup(struct fuse_copy_state *cs, void *val, unsigned size) +static int fuse_copy_lookup(struct fuse_copy_state *cs, unsigned via_ioctl, void *val, unsigned size) { struct fuse_bpf_entry_out *fbeo = (struct fuse_bpf_entry_out *)val; struct fuse_bpf_entry *feb = container_of(fbeo, struct fuse_bpf_entry, out[0]); int num_entries = size / sizeof(*fbeo); int err; - if (size && size % sizeof(*fbeo) != 0) + if (size && (size % sizeof(*fbeo) != 0 || !via_ioctl)) return -EINVAL; if (num_entries > FUSE_BPF_MAX_ENTRIES) return -EINVAL; + err = fuse_copy_one(cs, val, size); if (err) return err; @@ -1033,7 +1034,7 @@ static int fuse_copy_lookup(struct fuse_copy_state *cs, void *val, unsigned size return err; } #else -static int fuse_copy_lookup(struct fuse_copy_state *cs, void *val, unsigned size) +static int fuse_copy_lookup(struct fuse_copy_state *cs, unsigned via_ioctl, void *val, unsigned size) { return fuse_copy_one(cs, val, size); } @@ -1042,7 +1043,7 @@ static int fuse_copy_lookup(struct fuse_copy_state *cs, void *val, unsigned size /* Copy request arguments to/from userspace buffer */ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs, unsigned argpages, struct fuse_arg *args, - int zeroing, unsigned is_lookup) + int zeroing, unsigned is_lookup, unsigned via_ioct) { int err = 0; unsigned i; @@ -1052,7 +1053,7 @@ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs, if (i == numargs - 1 && argpages) err = fuse_copy_pages(cs, arg->size, zeroing); else if (i == numargs - 1 && is_lookup) - err = fuse_copy_lookup(cs, arg->value, arg->size); + err = fuse_copy_lookup(cs, via_ioct, arg->value, arg->size); else err = fuse_copy_one(cs, arg->value, arg->size); } @@ -1330,7 +1331,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, err = fuse_copy_one(cs, &req->in.h, sizeof(req->in.h)); if (!err) err = fuse_copy_args(cs, args->in_numargs, args->in_pages, - (struct fuse_arg *) args->in_args, 0, 0); + (struct fuse_arg *) args->in_args, 0, 0, 0); fuse_copy_finish(cs); spin_lock(&fpq->lock); clear_bit(FR_LOCKED, &req->flags); @@ -1869,7 +1870,8 @@ static int copy_out_args(struct fuse_copy_state *cs, struct fuse_args *args, lastarg->size -= diffsize; } return fuse_copy_args(cs, args->out_numargs, args->out_pages, - args->out_args, args->page_zeroing, args->is_lookup); + args->out_args, args->page_zeroing, args->is_lookup, + args->via_ioctl); } /* @@ -1879,7 +1881,7 @@ static int copy_out_args(struct fuse_copy_state *cs, struct fuse_args *args, * it from the list and copy the rest of the buffer to the request. * The request is finished by calling fuse_request_end(). */ -static ssize_t fuse_dev_do_write(struct fuse_dev *fud, +static ssize_t fuse_dev_do_write(struct fuse_dev *fud, bool from_ioctl, struct fuse_copy_state *cs, size_t nbytes) { int err; @@ -1951,6 +1953,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, if (!req->args->page_replace) cs->move_pages = 0; + req->args->via_ioctl = from_ioctl; if (oh.error) err = nbytes != sizeof(oh) ? -EINVAL : 0; else @@ -1989,7 +1992,7 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from) fuse_copy_init(&cs, 0, from); - return fuse_dev_do_write(fud, &cs, iov_iter_count(from)); + return fuse_dev_do_write(fud, false, &cs, iov_iter_count(from)); } static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe, @@ -2070,7 +2073,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe, if (flags & SPLICE_F_MOVE) cs.move_pages = 1; - ret = fuse_dev_do_write(fud, &cs, len); + ret = fuse_dev_do_write(fud, false, &cs, len); pipe_lock(pipe); out_free: @@ -2283,6 +2286,33 @@ static int fuse_device_clone(struct fuse_conn *fc, struct file *new) return 0; } +// Provides an alternate means to respond to a fuse request +static int fuse_handle_ioc_response(struct fuse_dev *dev, void *buff, uint32_t size) +{ + struct fuse_copy_state cs; + struct iovec *iov = NULL; + struct iov_iter iter; + int res; + + if (size > PAGE_SIZE) + return -EINVAL; + iov = (struct iovec *) __get_free_page(GFP_KERNEL); + if (!iov) + return -ENOMEM; + + iov->iov_base = buff; + iov->iov_len = size; + + iov_iter_init(&iter, READ, iov, 1, size); + fuse_copy_init(&cs, 0, &iter); + + + res = fuse_dev_do_write(dev, true, &cs, size); + free_page((unsigned long) iov); + + return res; +} + static long fuse_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -2316,6 +2346,12 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd, } break; default: + if (_IOC_TYPE(cmd) == FUSE_DEV_IOC_MAGIC + && _IOC_NR(cmd) == _IOC_NR(FUSE_DEV_IOC_BPF_RESPONSE(0)) + && _IOC_DIR(cmd) == _IOC_WRITE) { + res = fuse_handle_ioc_response(fuse_get_dev(file), (void *) arg, _IOC_SIZE(cmd)); + break; + } res = -ENOTTY; break; } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index d67325af5e72..3452530aba94 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -314,6 +314,7 @@ struct fuse_args { bool page_replace:1; bool may_block:1; bool is_lookup:1; + bool via_ioctl:1; struct fuse_in_arg in_args[3]; struct fuse_arg out_args[2]; void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error); diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 0e19076729d9..e49e5a8e044c 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -972,6 +972,7 @@ struct fuse_notify_retrieve_in { /* Device ioctls: */ #define FUSE_DEV_IOC_MAGIC 229 #define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t) +#define FUSE_DEV_IOC_BPF_RESPONSE(N) _IOW(FUSE_DEV_IOC_MAGIC, 125, char[N]) struct fuse_lseek_in { uint64_t fh; From patchwork Tue Nov 22 02:15:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24124 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1956553wrr; Mon, 21 Nov 2022 18:18:29 -0800 (PST) X-Google-Smtp-Source: AA0mqf6LRVdrQ8Kli504Y7vNA2+HyWtXYwVZlAHSzjntV42YJtcRJQK6ztJ9Eu5soodl0ZVwkbnD X-Received: by 2002:a17:902:d650:b0:189:f86:ecb with SMTP id y16-20020a170902d65000b001890f860ecbmr12613978plh.45.1669083509105; Mon, 21 Nov 2022 18:18:29 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083509; cv=none; d=google.com; s=arc-20160816; b=BZMmUdgXXtiRyRhpVlrBsYLtw0oJUNcduOAnRprMjHZT6BL6RrAD9qRW6cPkURyiE0 wsRhxZRJKVNtOHQzVoLHzVWapE2sAjv9MSA5b72ePWWfMR6qiJPHaNzqXxHMDM8FZ+YE cSdrB/0DuQtVOb8cGqwqLJljXYIiibM/LEvW1ugRuPoudk2I2bpV4TFGZ9l+Csd0oGYd QdlnRZcmGT/iYz8jjIns1N5ttMX8YBxLzMm8TcQjoL8wOpfLGAFMU0X6yYk9m3VH3iB3 RrF9OiNOHQ7Q4+eZUF8t0B2nCSWpwHvG8i9M3R6ZQnDvVa+IGLP/qOpf9zCFn8Y7/IeV RWgQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=J0kBTpGRrZ4fbYeP7Bh1hsOct+NKdkC7fVmp/4th4/s=; b=LexwqGDaTix/wa64h1tZYC1S1XAoaroGJGEPlEHY9Lot6kdSsX7TgHbQhx6aWiuYAi 9PNUvwXpmYjISkmkHb8eBmafwLUNrHRg3+hwVEhnQyev9FtNbliHegAeq37S0kt3uqit XitnLmjDKJZusDuQWcVGrhlpVj5j01beSM4DS2AwjJo2lKECQVT1gEb7SWHNCpbzAP5m F26sPIq4dYffwMvMPVZ+mt9JXOYlvs+eWOQtuzz6+qa61Taze9Fj622xdck0CGekNBCB P8fznEIoixgQ/HKRQQ5wlLhEEOv6a7/fz/kr/r50OUB+w/NP+QKM+ZdIeX3BRa8GNXje c0Iw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=PTyyzqK8; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id l6-20020a170902ec0600b00186e34524besi12019912pld.522.2022.11.21.18.18.16; Mon, 21 Nov 2022 18:18:29 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=PTyyzqK8; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231928AbiKVCQt (ORCPT + 99 others); Mon, 21 Nov 2022 21:16:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41970 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232552AbiKVCQe (ORCPT ); Mon, 21 Nov 2022 21:16:34 -0500 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C37A5E634D for ; Mon, 21 Nov 2022 18:16:08 -0800 (PST) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-36810cfa61fso127414127b3.6 for ; Mon, 21 Nov 2022 18:16:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=J0kBTpGRrZ4fbYeP7Bh1hsOct+NKdkC7fVmp/4th4/s=; b=PTyyzqK8VIpYcc3Jnv1HwKlTZVtN825+P2qskFJugJ/DNoyLCfdNJgvvb4WK//Litx 9PSdHS+fDIZijxFoVEzf+iNQufz0lxZloF1cOdSlQxtrE3mGt+L7NNZ7cAq+QY79+G+5 qDhW62Uexhw5NGJYa+8of89/EQtHfE3nO8G2fOeaWQ4CRwdC6fVqUCyjN41ZDHRvzP0e 1D4semdRyxKDsXvvOZn8BhhTnael1tURdERVZKJGOgEYACViGTrodjUlJBmnKctQGZd1 WHhMCxTizWOZtXg3xr0jXG4k/8eB3tTqtQsiIsWRi9nQDHQUvHOz09sNxIWD/ti3qwf2 kzFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=J0kBTpGRrZ4fbYeP7Bh1hsOct+NKdkC7fVmp/4th4/s=; b=Kt6DAr5TrS3ZXa5pZ2EhJ+WQlXhbSBUh5d1u1lqtYY9NcGPEMHLJo/U+jYPMm8OY9Q Ud6DGZrUgmjk8oAu/n0vdKF6Lc607DubGLR75TCuIuAPqLEwCfZcek6jydSzomuB3W/p thCNT7NahyOoZIp+WsHcJu0ZyL7fWX/FiadQSFcuulkhy5wvUsBo116b3+ojd8UaLYWg b9YvI4YRTeAjQndRkb88C0k7jz4wEs3UVMejFC1KKto5UJjcxsxGiKJxiAei2Lq276Z6 rd/XojFWVSqGFXLsd1YP4LFGhshGS/2lGmcOH3tPv/1g0TJQ0+YWvP5S1ZOorJEdXJKC QpmA== X-Gm-Message-State: ANoB5pmTgaHHf+cs9bFBrbxp5WjxcRmo7veobc3gav7UUwc5MEqvcNAb K5wLtOVRIa/ES3pOtAb36PbVa5mZWeI= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a05:6902:118e:b0:6e7:f54:b3d6 with SMTP id m14-20020a056902118e00b006e70f54b3d6mr4166933ybu.577.1669083368110; Mon, 21 Nov 2022 18:16:08 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:21 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-7-drosen@google.com> Subject: [RFC PATCH v2 06/21] fuse-bpf: Don't support export_operations From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750160909372288550?= X-GMAIL-MSGID: =?utf-8?q?1750160909372288550?= In the future, we may choose to support these, but it poses some challenges. In order to create a disconnected dentry/inode, we'll need to encode the mountpoint and bpf into the file_handle, which means we'd need a stable representation of them. This also won't hold up to cases where the bpf is not stateless. One possibility is registering bpf programs and mounts in a specific order, so they can be assigned consistent ids we can use in the file_handle. We can defer to the lower filesystem for the lower inode's representation in the file_handle. Signed-off-by: Daniel Rosenberg --- fs/fuse/inode.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 224d7dfe754d..bafb2832627d 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1100,6 +1100,14 @@ static int fuse_encode_fh(struct inode *inode, u32 *fh, int *max_len, nodeid = get_fuse_inode(inode)->nodeid; generation = inode->i_generation; +#ifdef CONFIG_FUSE_BPF + /* TODO: Does it make sense to support this in some cases? */ + if (!nodeid && get_fuse_inode(inode)->backing_inode) { + *max_len = 0; + return FILEID_INVALID; + } +#endif + fh[0] = (u32)(nodeid >> 32); fh[1] = (u32)(nodeid & 0xffffffff); fh[2] = generation; From patchwork Tue Nov 22 02:15:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24125 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1956622wrr; Mon, 21 Nov 2022 18:18:40 -0800 (PST) X-Google-Smtp-Source: AA0mqf7Rvg8sxafSmPiwCNyGLe1igeO6a3vdqh0jC6JhTZRd8MpX3cSMxq3KVthpL5qzt3RvoAj5 X-Received: by 2002:a17:90a:2e0c:b0:218:c1d3:4cd8 with SMTP id q12-20020a17090a2e0c00b00218c1d34cd8mr4671924pjd.37.1669083520619; Mon, 21 Nov 2022 18:18:40 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083520; cv=none; d=google.com; s=arc-20160816; b=fDXf1w7TFiYq7pBGEnROZezZOqG1MY3hl+sc7XN1LgAjOD4wtG5Iy/NHcPPH013j73 wYVbWSXTZxw+XiZnsW/S0j53hIu7D/BX8I5wDo/0BTbvNdEyPGjDx4dfcPGNRfHbFzWx OAu+6Sac/D57SflMPmLaA4dcDR+ypJmIfzuez707gtIHxFtowobejj45/Mi2xx0pgHFV DjS3aDfHDq7AYopqRXhAUaOFKDIW/J27eJOyQ+uhuKlBHMdDqiakXyCxPbCzWELyk10N TXe8GK1mq7n5GoHEo2WvW4oE5zoflq0XJVrNHdPcFXPkFCOjf187sGT8zjQByj+qLmZI Bm7Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=vP4dk37Xutp/zfeNLDJTOudpRYQEN0iw5Uyo2Mo/Ols=; b=rzWSXZpEcvD2NL7eIn/LktfufHkAzrh4au39kFlnJ/njNEFM9+z/4E4uIKx0qDxTSD ONgyNZ/b7dwiFVHJcUVIOeZnO7P+x3CPoSufF7UClPkJxNU9EwcEKlGDTumt8R0YWfvO rPul8HWxdHYd3nQTLqYh6IwWh2OkkPAIKUxiLA5JubBmw42eVkDQGxvoE5MOTtm2/ce9 5xPweCZNjvi3GGmUBN3j/xOpBNRV8uFheeD4CoCxgMxIs0B0wUZEzNXYKFJgDa9acP8L Ecb3B1C0gcwxla5GtaN3/hsM3eWoCOfyFz6HvuAALWyPHrcll121TRZr3kDnG2466ZZD N4XA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b="DY/+xVmp"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id a14-20020a170902ecce00b00178431e09bdsi12427655plh.230.2022.11.21.18.18.27; Mon, 21 Nov 2022 18:18:40 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b="DY/+xVmp"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232629AbiKVCRQ (ORCPT + 99 others); Mon, 21 Nov 2022 21:17:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42760 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232573AbiKVCQg (ORCPT ); Mon, 21 Nov 2022 21:16:36 -0500 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A487FE636A for ; Mon, 21 Nov 2022 18:16:10 -0800 (PST) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-399c3d7b039so72215517b3.3 for ; Mon, 21 Nov 2022 18:16:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=vP4dk37Xutp/zfeNLDJTOudpRYQEN0iw5Uyo2Mo/Ols=; b=DY/+xVmpzHQ3WvEhCX7ieUerHnSB5Lpd6FMaZi6jH6pOfb5qnq5SVm2kzYA7oUL/nw WO9LLKurB78pQ87qElgkNJZ7ImFLGJB6Yh+edXbaQDZNC2NdhxOLAIXfA1Vcf2LkB58P Qn1iFXabi4oOuviuNqWNZGySxV5cfswF7VqpPyA+R3g+3OCV4lvTpIgjkXFytSdsz+LW MHnhROSy/7ZBDK9u9g04Gvn/e5l8NapW2aA0nEHFDnH3IO7QGeHiN/jCcm6kCn72+7Dj JjGtw49yT4bnRddNuuZ4Zgv7DSxrlKLXNb/0Ajf19HiN91NjSd8wXrF0iKLI8LWWc/iQ 1Nzw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=vP4dk37Xutp/zfeNLDJTOudpRYQEN0iw5Uyo2Mo/Ols=; b=rKUAhHwPmkrGEBgElgMzFCreQ/mXPfdFTwKxOFeEaQBJdCXzhAhUuVFFW8XmMOL5UV Ojy9+eozLcITk4W4+FHqbERHQA4kWQ6BJSu8D3PXPgPE15+YB1DZf6Ff5zcitmbGT1SU xa67eDwAr/JfAoVtTerrAvrE+lMtS+SsT2u0Ioq9seh6LDiPnjIqqJXDCb/xZq7bL+Br 0vMv+njKWncgvTCSISJB8oIG0da9baZgw413hCosgFTsv0L2w7eJcHq2j+CSY8EQTrkb J/jEWvnb/yjxqsoEogkyae9K5WC7K1U2HAc7Zx/MUwnrSLmNh9T/ms/MOXjUntP20VIP pHwA== X-Gm-Message-State: ANoB5pnLWZNdOD0kd/ob1EqqhKOvTFtB8SeCHuVUq25cjJwKSPZxUPQf WGOM7ElYs9X2BXIJD+LPWyemTzyueLo= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a25:eb04:0:b0:6cf:e761:41ed with SMTP id d4-20020a25eb04000000b006cfe76141edmr3734311ybs.82.1669083370436; Mon, 21 Nov 2022 18:16:10 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:22 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-8-drosen@google.com> Subject: [RFC PATCH v2 07/21] fuse-bpf: Add support for FUSE_ACCESS From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750160922040763378?= X-GMAIL-MSGID: =?utf-8?q?1750160922040763378?= Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/dir.c | 6 ++++++ fs/fuse/fuse_i.h | 6 ++++++ 3 files changed, 57 insertions(+) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 5a59a8963d52..670e82d68e36 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -390,3 +390,48 @@ int fuse_revalidate_backing(struct dentry *entry, unsigned int flags) return backing_entry->d_op->d_revalidate(backing_entry, flags); return 1; } + +static int fuse_access_initialize_in(struct fuse_args *fa, struct fuse_access_in *fai, + struct inode *inode, int mask) +{ + *fai = (struct fuse_access_in) { + .mask = mask, + }; + + *fa = (struct fuse_args) { + .opcode = FUSE_ACCESS, + .nodeid = get_node_id(inode), + .in_numargs = 1, + .in_args[0].size = sizeof(*fai), + .in_args[0].value = fai, + }; + + return 0; +} + +static int fuse_access_initialize_out(struct fuse_args *fa, struct fuse_access_in *fai, + struct inode *inode, int mask) +{ + return 0; +} + +static int fuse_access_backing(struct fuse_args *fa, int *out, struct inode *inode, int mask) +{ + struct fuse_inode *fi = get_fuse_inode(inode); + const struct fuse_access_in *fai = fa->in_args[0].value; + + *out = inode_permission(&init_user_ns, fi->backing_inode, fai->mask); + return 0; +} + +static int fuse_access_finalize(struct fuse_args *fa, int *out, struct inode *inode, int mask) +{ + return 0; +} + +int fuse_bpf_access(int *out, struct inode *inode, int mask) +{ + return fuse_bpf_backing(inode, struct fuse_access_in, out, + fuse_access_initialize_in, fuse_access_initialize_out, + fuse_access_backing, fuse_access_finalize, inode, mask); +} diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index fb7c6988f0d9..4e19320889ed 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1364,6 +1364,9 @@ static int fuse_access(struct inode *inode, int mask) struct fuse_access_in inarg; int err; + if (fuse_bpf_access(&err, inode, mask)) + return err; + BUG_ON(mask & MAY_NOT_BLOCK); if (fm->fc->no_access) @@ -1420,6 +1423,9 @@ static int fuse_permission(struct user_namespace *mnt_userns, if (!fuse_allow_current_process(fc)) return -EACCES; + if (fuse_bpf_access(&err, inode, mask)) + return err; + /* * If attributes are needed, refresh them before proceeding */ diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 3452530aba94..db3f703c700f 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1401,6 +1401,7 @@ int parse_fuse_bpf_entry(struct fuse_bpf_entry *fbe, int num_entries); #ifdef CONFIG_FUSE_BPF int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct dentry *entry, unsigned int flags); +int fuse_bpf_access(int *out, struct inode *inode, int mask); #else @@ -1409,6 +1410,11 @@ static inline int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct return 0; } +static inline int fuse_bpf_access(int *out, struct inode *inode, int mask) +{ + return 0; +} + #endif // CONFIG_FUSE_BPF int fuse_handle_backing(struct fuse_bpf_entry *feb, struct path *backing_path); From patchwork Tue Nov 22 02:15:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24126 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1956689wrr; Mon, 21 Nov 2022 18:18:49 -0800 (PST) X-Google-Smtp-Source: AA0mqf6ONldKV5OfikVHwq3KAPGQx0aGyMFLoHgZklHsskmGd13y7XhjlCcFbSLZw1Zf2kvxlAmp X-Received: by 2002:a62:3084:0:b0:56d:dd2a:c494 with SMTP id w126-20020a623084000000b0056ddd2ac494mr2310386pfw.76.1669083529684; Mon, 21 Nov 2022 18:18:49 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083529; cv=none; d=google.com; s=arc-20160816; b=MU86cBVqdhRvh2k1+M5H2u4QIsXHWXBD8Ti2f+XirJloyy4Q6kYfTPl4uYX9OMqEjL Y72/5sbbw0pm8Ljx/dbDoc+a2+cvfnkdWZct3VeuYGHTGYli7dpIcw7w5JblW1Ye5BGE j8DEqGXOaH9TXegJrmLeRhkCYhNx7miVtYmmDM6lLu2Pataw6OkNUQNYAZjGXqIMp7Sa Db5U0HspSmg5MWE35ANW48Qge8ljjSyR0YwWytZFcSmLpS/znCvEyfR1QVw3hUsfY5xQ ZYsqO6y3zRzWKVZajCUW/qlZil4gtouYL6M0e++rJ4gRgBnG925IE7BVgI1gWX02Ymtj eP8A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=YI7vW6c4K96rrFjk3kAmKImDsQ1aqnDC905YGpSrwzg=; b=wXS4WFR6ysOfGPvnuR5e/G2jSZRGnMbt7/A5d3KgUnrPPxIWTKWvM893WBF4QKSagC hDY8zOerdr9bJTpr2L5sQ2NpsrDNwXUOjF8MZ8fRTDoBdZA8YHKokblHB6I6u//JT10N v+9INz+btqqlwR1Zf4z/G02dfo8hwOL3/us9+7NMy5ija09nmDVDqKdz75rJfZ3L6DNQ erSVqEc0lG1XRSzd4tiMRDJyvvSQnXysACvHWOuMjiXvR9+S0eYJ1HoaxLm/59k/sraO g0/RR9kw12bRq7u/RhwAfno+uaywe9gcGkBJkk0xjdIuyFjsY2G/jJMzLsQW5wn/I1dl 6ClQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=QjoJIIfx; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id k9-20020a170902d58900b0017f7faef235si13568285plh.148.2022.11.21.18.18.34; Mon, 21 Nov 2022 18:18:49 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=QjoJIIfx; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231936AbiKVCRW (ORCPT + 99 others); Mon, 21 Nov 2022 21:17:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42642 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232106AbiKVCQi (ORCPT ); Mon, 21 Nov 2022 21:16:38 -0500 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 054BDE6378 for ; Mon, 21 Nov 2022 18:16:12 -0800 (PST) Received: by mail-yb1-xb4a.google.com with SMTP id h16-20020a255f50000000b006e880b47e6fso9682419ybm.6 for ; Mon, 21 Nov 2022 18:16:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=YI7vW6c4K96rrFjk3kAmKImDsQ1aqnDC905YGpSrwzg=; b=QjoJIIfxEO0QcSPemPtaHnOA3LOIMlbI0LWuX5Qcvau93ztFNlhi6LpWUYlXE5V6lR s+/YMob9Vz1BugWRNv0XR1XHOFD5K48n+WY8PC4yBmcG1k5Bro/WAglb1fsEe87u/U38 wRUxe8rfXhhdOD6+W97hB8aZVBiiIRQ23y3AgJ9G+p7yUdXJePBNkRahA0wfaL+st6bw fwci5sDqdYCh1ja1BPHV9lFNw7YpJKkvFpu0JRvoQSKxbX1U4lj3XRM2dULPxY8TQrg2 t7lXb/vX6HgrpmFyOYkgGmvUnSIf6zizvQ59C9VGjUaEIUt5rLIctZ29RCV6wVb22Cz9 EbKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=YI7vW6c4K96rrFjk3kAmKImDsQ1aqnDC905YGpSrwzg=; b=eHWUtKyqlVmlm1y37Qu7qZ5vikKfppOlbRly4gOhSBpeiNqM62kmjj65iOu9I8guSI sBE1CcqKTbjdKgk1gGdD9HHwkf6InAhkgxouF/MVnzIN+6IghMZVHmRgtdfNW+/8tkxb qEUjaLirxI2GBZKrD4Va0awIFb5t5S3yyiuk3Ko3vuI8c7Vdz4ikr5F6oSm0zTVfVqeq ebQW2vpj5Vs3yqqebC/gH4DKHyjVYabhVpq5ZHA6qcIvYk0a6fb/c3t/M0JQlngONHJg +hH7+3wkHvS3DVFioa+1HRMoFJausFUJhMnzedaO7HbTg4xs5eTDDiXkK1kZzLG01wXA TmaQ== X-Gm-Message-State: ANoB5pmwOKADj1SXHXwF+cqNGu6F9lYvEpQj4mv/WpP0ijsHHcgSZyE+ 6vFP7zkKF+rRCNsbP3IPVc3rnDmFmoo= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a25:d704:0:b0:6b3:369f:7436 with SMTP id o4-20020a25d704000000b006b3369f7436mr2526513ybg.172.1669083372616; Mon, 21 Nov 2022 18:16:12 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:23 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-9-drosen@google.com> Subject: [RFC PATCH v2 08/21] fuse-bpf: Partially add mapping support From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750160930956281930?= X-GMAIL-MSGID: =?utf-8?q?1750160930956281930?= This adds a backing implementation for mapping, but no bpf counterpart yet. Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 37 +++++++++++++++++++++++++++++++++++++ fs/fuse/file.c | 6 ++++++ fs/fuse/fuse_i.h | 4 +++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 670e82d68e36..8d862bc64acd 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -205,6 +205,43 @@ static void fuse_stat_to_attr(struct fuse_conn *fc, struct inode *inode, attr->blksize = 1 << blkbits; } +ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma) +{ + int ret; + struct fuse_file *ff = file->private_data; + struct inode *fuse_inode = file_inode(file); + struct file *backing_file = ff->backing_file; + struct inode *backing_inode = file_inode(backing_file); + + if (!backing_file->f_op->mmap) + return -ENODEV; + + if (WARN_ON(file != vma->vm_file)) + return -EIO; + + vma->vm_file = get_file(backing_file); + + ret = call_mmap(vma->vm_file, vma); + + if (ret) + fput(backing_file); + else + fput(file); + + if (file->f_flags & O_NOATIME) + return ret; + + if ((!timespec64_equal(&fuse_inode->i_mtime, &backing_inode->i_mtime) || + !timespec64_equal(&fuse_inode->i_ctime, + &backing_inode->i_ctime))) { + fuse_inode->i_mtime = backing_inode->i_mtime; + fuse_inode->i_ctime = backing_inode->i_ctime; + } + touch_atime(&file->f_path); + + return ret; +} + /******************************************************************************* * Directory operations after here * ******************************************************************************/ diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 503327be3942..24fd4f33105c 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2452,6 +2452,12 @@ static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) if (FUSE_IS_DAX(file_inode(file))) return fuse_dax_mmap(file, vma); +#ifdef CONFIG_FUSE_BPF + /* TODO - this is simply passthrough, not a proper BPF filter */ + if (ff->backing_file) + return fuse_backing_mmap(file, vma); +#endif + if (ff->open_flags & FOPEN_DIRECT_IO) { /* Can't provide the coherency needed for MAP_SHARED */ if (vma->vm_flags & VM_MAYSHARE) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index db3f703c700f..95d67afcff05 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1417,7 +1417,9 @@ static inline int fuse_bpf_access(int *out, struct inode *inode, int mask) #endif // CONFIG_FUSE_BPF -int fuse_handle_backing(struct fuse_bpf_entry *feb, struct path *backing_path); +ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma); + +int fuse_handle_backing(struct fuse_bpf_entry *fbe, struct path *backing_path); int fuse_revalidate_backing(struct dentry *entry, unsigned int flags); From patchwork Tue Nov 22 02:15:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24127 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1956731wrr; Mon, 21 Nov 2022 18:18:57 -0800 (PST) X-Google-Smtp-Source: AA0mqf7m/LqeND0VsSwDOuTe/hvoOLCXsj4J1fjxUb4f7FJ1Sckr/ykgR6gB2+w0zTWJDgXBAdlB X-Received: by 2002:a17:90b:2d8b:b0:212:fe4a:c378 with SMTP id sj11-20020a17090b2d8b00b00212fe4ac378mr23795128pjb.82.1669083537387; Mon, 21 Nov 2022 18:18:57 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083537; cv=none; d=google.com; s=arc-20160816; b=pS2o3SfhVwXhu+hofMQZgwdJz/k9Z6Tn08CDvgN+eKcdO4/KFv2EAY76A+PLVE8k7c fA2ydF9t9voCP6kG+ygovDPVHuImGLissnKNQqiXYqlSb9od9EuCE0yRjSRuPJDM3u2h 6FfUeG5dUHy6QG2z+M4xXp/RrQptV1Gp/qvVaFKitNBWpcfYOr+xLUKJ8RhB2riDo06b mkG+cD2bpjb4R7MiHrWYZbrM835KKlhrBS/KPq/5k+vigADjRcp7VeuLPIfHylnmvT1m u7UEpXp0Uvf1GjygWQoSSFJLcEY/FYYUtLM69zeKHKLkDIuzumItfjpOkODu5vOWkJhh jZGQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=mBD6bGviTnQaNR8TlIrtDcNsv7AoSToN0hwSmPU39NM=; b=b58DZ4JHaPhIr8PrcQuvG4YgMOUFhIR18owDvwkw/o6mgW09GbG2gEQkUMEmC9JJNN bA0n4fRRARbbq4WkwrKiEW1V3fGiMIqzjnMmoXDyJhZG/1TxK3X2p8eA9nb3iyjgw1Ts 6zm43y4aXrTsPxd01l0AyHpj/Zdcuma1wXTrIrllqq6TgDvHY+u1lDeweM/BULqyVIoL wd3Fuqy1K3z09PSYwfFupfxqavhb4PsWspwmR04SLHqOhtI/Zm0Dw62+NMPmCBdCw/2I dB7SbIZL4j4KyE7gMZyTVw7V7Z/qiOTntAB395GLqrRNEEZ3Yy27fCoRQpOW+SrYIMDD Fdrw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=oKcvpaX8; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id w3-20020a170902e88300b00188dba5d7dbsi14343635plg.78.2022.11.21.18.18.39; Mon, 21 Nov 2022 18:18:57 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=oKcvpaX8; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232500AbiKVCRx (ORCPT + 99 others); Mon, 21 Nov 2022 21:17:53 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42570 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232597AbiKVCRB (ORCPT ); Mon, 21 Nov 2022 21:17:01 -0500 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 62AC9E674D for ; Mon, 21 Nov 2022 18:16:15 -0800 (PST) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-37360a6236fso129248737b3.12 for ; Mon, 21 Nov 2022 18:16:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=mBD6bGviTnQaNR8TlIrtDcNsv7AoSToN0hwSmPU39NM=; b=oKcvpaX8yBxVrqjzpCwp8hRJbcWcrVDPsDHSTtU/JumfrQNEB9LNqF2bZQDgm66L23 ezgqXB2c8vNVR5Ss+f0VlAAkX7XbGHrjbnnMn7F2oqVZtP8ZWNt7oydnS1QJUerPmQrw wZlW7iK35Eki/V2aGDIyRlsqTBNDWVYquyeLToqnZuW5Dk/b7LAie/wJsfzS3DkKBD2Z UTRBDxexsXEWuJSNee5jmYV9WWIOxyhAQPI0DgGAvgfFII8jVxgE22HiU1GNrHiYDYUL 1O33KGWuGc2xU5ucwwHWvW+lMdsOuhQ+wShSsdOzU36NkBFSAmPL0D30z2fGKF6c0j0K MJ1Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=mBD6bGviTnQaNR8TlIrtDcNsv7AoSToN0hwSmPU39NM=; b=iNyiIG848Mjc4BkBh2e0j57/NtXArHEzt38QernVl57sVnU+RE6hpoCKgCOP8oFybK 2cUe4QIZi0AhOa+ibm/xvvp7elvAcrC/65NtR899q0MB7XXI4TMprTPPv5oRIMpbiU2R Maiz7nUEa/B+HuwYHY1FBMAnhzaEOiwPM8yzMImPECPhqrWmNMJdWRAbkBa86BgOJnww 2GNjmJux8/pFX4U8OqTnYtXnvBjvN7KnnqAbFBNtaloY9gds8qL+DXCWb1T/pedgXjoh 0Qslbi8N/TSwMPD8IbCGmryNxeJrm31b4sHGCty9HW+m2Q6MMjqbAxu3K3XlWqpV5TZp CG/g== X-Gm-Message-State: ACrzQf3x/8KQVdrW2ObjOgd0zDCsfyLI8PG70TRZSgAmjB8lY3ZEKxHa vYAulWi77pjQNl/PEl20CmgeaEaJZAE= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a81:86c2:0:b0:332:a104:f7e4 with SMTP id w185-20020a8186c2000000b00332a104f7e4mr66525980ywf.505.1669083374599; Mon, 21 Nov 2022 18:16:14 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:24 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-10-drosen@google.com> Subject: [RFC PATCH v2 09/21] fuse-bpf: Add lseek support From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750160939190969444?= X-GMAIL-MSGID: =?utf-8?q?1750160939190969444?= Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/file.c | 3 ++ fs/fuse/fuse_i.h | 6 ++++ 3 files changed, 97 insertions(+) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 8d862bc64acd..76f48872ed35 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -205,6 +205,94 @@ static void fuse_stat_to_attr(struct fuse_conn *fc, struct inode *inode, attr->blksize = 1 << blkbits; } +struct fuse_lseek_io { + struct fuse_lseek_in fli; + struct fuse_lseek_out flo; +}; + +static int fuse_lseek_initialize_in(struct fuse_args *fa, struct fuse_lseek_io *flio, + struct file *file, loff_t offset, int whence) +{ + struct fuse_file *fuse_file = file->private_data; + + flio->fli = (struct fuse_lseek_in) { + .fh = fuse_file->fh, + .offset = offset, + .whence = whence, + }; + + *fa = (struct fuse_args) { + .nodeid = get_node_id(file->f_inode), + .opcode = FUSE_LSEEK, + .in_numargs = 1, + .in_args[0].size = sizeof(flio->fli), + .in_args[0].value = &flio->fli, + }; + + return 0; +} + +static int fuse_lseek_initialize_out(struct fuse_args *fa, struct fuse_lseek_io *flio, + struct file *file, loff_t offset, int whence) +{ + fa->out_numargs = 1; + fa->out_args[0].size = sizeof(flio->flo); + fa->out_args[0].value = &flio->flo; + + return 0; +} + +static int fuse_lseek_backing(struct fuse_args *fa, loff_t *out, + struct file *file, loff_t offset, int whence) +{ + const struct fuse_lseek_in *fli = fa->in_args[0].value; + struct fuse_lseek_out *flo = fa->out_args[0].value; + struct fuse_file *fuse_file = file->private_data; + struct file *backing_file = fuse_file->backing_file; + + /* TODO: Handle changing of the file handle */ + if (offset == 0) { + if (whence == SEEK_CUR) { + flo->offset = file->f_pos; + *out = flo->offset; + return 0; + } + + if (whence == SEEK_SET) { + flo->offset = vfs_setpos(file, 0, 0); + *out = flo->offset; + return 0; + } + } + + inode_lock(file->f_inode); + backing_file->f_pos = file->f_pos; + *out = vfs_llseek(backing_file, fli->offset, fli->whence); + flo->offset = *out; + inode_unlock(file->f_inode); + return 0; +} + +static int fuse_lseek_finalize(struct fuse_args *fa, loff_t *out, + struct file *file, loff_t offset, int whence) +{ + struct fuse_lseek_out *flo = fa->out_args[0].value; + + if (!fa->error_in) + file->f_pos = flo->offset; + *out = flo->offset; + return 0; +} + +int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t offset, int whence) +{ + return fuse_bpf_backing(inode, struct fuse_lseek_io, out, + fuse_lseek_initialize_in, fuse_lseek_initialize_out, + fuse_lseek_backing, + fuse_lseek_finalize, + file, offset, whence); +} + ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma) { int ret; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 24fd4f33105c..e90b3e2d5452 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2704,6 +2704,9 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence) loff_t retval; struct inode *inode = file_inode(file); + if (fuse_bpf_lseek(&retval, inode, file, offset, whence)) + return retval; + switch (whence) { case SEEK_SET: case SEEK_CUR: diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 95d67afcff05..108c2ea15a49 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1400,11 +1400,17 @@ int parse_fuse_bpf_entry(struct fuse_bpf_entry *fbe, int num_entries); #ifdef CONFIG_FUSE_BPF +int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t offset, int whence); int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct dentry *entry, unsigned int flags); int fuse_bpf_access(int *out, struct inode *inode, int mask); #else +static inline int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t offset, int whence) +{ + return 0; +} + static inline int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct dentry *entry, unsigned int flags) { return 0; From patchwork Tue Nov 22 02:15:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24131 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1957188wrr; Mon, 21 Nov 2022 18:20:05 -0800 (PST) X-Google-Smtp-Source: AA0mqf6yQfyoQWHiFoSZMjqPWv01IzbCtZhRDQyFWH4WKfdKwg1VV7ov90Wh1azGPu4anIiPnF3G X-Received: by 2002:a17:903:2783:b0:186:a97d:6bc8 with SMTP id jw3-20020a170903278300b00186a97d6bc8mr2267744plb.101.1669083605299; Mon, 21 Nov 2022 18:20:05 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083605; cv=none; d=google.com; s=arc-20160816; b=qT5K7tw5eTR76fJOqgiUdSXSeOATH+v/WQTvHAYNl+Jr4Rf3WKeYXxa5N6yn1Z0k26 fV9YZ9pIk4mjXx2Dx2nC/bAfPyMOZ5o3st09SXKmXed/l9ZWu4wKnESunjdlAsjCjBKR Efwvwk3rO/yjKyBv8/6AvuOTukCXr7XqmjspA/Bqy0oGTYZZHQ8qJ9rifbx7zYdwWy+S qjgZ/ZqdqdBm3i2rLo8PwrdE/nsMbSABiDkjwyBQ2LfqDqSNk77ZmGXZ6a2PVES/Psbu 01TIAqeYOyKVKEDSeItIwf2OPG4XcNYgLSiumusiR7b5qdMJnW9Qr18EekjKefPpQd+t FZhA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=/H+L2cRtspRUVOzDKfhmH9r0h1z7XV5y5jiKoA2w7Jo=; b=x2eLRkkPINusymTNFVrNz3HlE3cQrF56NvQy+TNr3Btn37dvmdJ0D0IzxdtzjhphFB EEW4qarohQRGBd8oULo5nteA1Wujh0tfY+9pY7TVPQXfZvkdogoYd077DssqD45vk7BY W1ZOF/bPdH9jC8CxX1y1uIkCNG6/TeKONc3XhUfDf6AsxS8j8AGlvdtw9RIYhRkYBIZv 0FbOJUgUSbxseMrEyKXWRDPiMTBofheZaami/Mru2TcLcNMphSof6nH+S6Zc5nZXdSK1 yuGa8T0CiyFh7Bvys2jhDhA2JZ7F3kAj03DtjGurn+9DJZnnKwfTiaOIvas42uVGNmss pPAw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=GkbYhSRu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id 144-20020a621896000000b0056b82fbafebsi11893577pfy.379.2022.11.21.18.19.52; Mon, 21 Nov 2022 18:20:05 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=GkbYhSRu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230460AbiKVCR7 (ORCPT + 99 others); Mon, 21 Nov 2022 21:17:59 -0500 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 S232603AbiKVCRC (ORCPT ); Mon, 21 Nov 2022 21:17:02 -0500 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 39340E675D for ; Mon, 21 Nov 2022 18:16:18 -0800 (PST) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-352e29ff8c2so130290337b3.21 for ; Mon, 21 Nov 2022 18:16:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=/H+L2cRtspRUVOzDKfhmH9r0h1z7XV5y5jiKoA2w7Jo=; b=GkbYhSRuG3pnC12YeGswQtbl8Qkm/FgEIiaZy5lmsxd6nnIJGVSGgoCrt6HlEko6Ki C6yr+mtFUhPtVnoaJg/ByALo10sNnWpcBCubg/D8R0ssNLL3XjyN46mJHVC5Um8b16CU orSmyP3WSpCgYDTcMIiZcxb2R80zdMKhHpr45RrSwbcJgu+a3jL9Xhb8MiJaYe2teBth L8HZN6e2FJlFs1cfNF808/GPl/xs2NrIzv6kCLjM5O/xSQgt9ou3kcdxWqlecQ+QDqfO utLWnK4t1OVh8O7dFmQ1g64uSIWNxLOGjQxuWWbknOLE404qWDNW8Qs3bG4NsLYvtmbe jw9Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=/H+L2cRtspRUVOzDKfhmH9r0h1z7XV5y5jiKoA2w7Jo=; b=sRl0sCoMnP2lh1Av2MuUjXcRFRqB4ZEKMzXL0MhJaXWVSyiw/jS0HVZHuVt8854K+P uHlY/HybA+zdbZ0PSZClAeBqiFFFgxmJPeNoCH4CyWPCWS4Qy+ll+ohr5Dh4QKGCDY56 RPfy2+LcUhLVUGHEaZNAaW6Jr9KQr0M1H3sqSIhh0VV5sMD99x9eBC2s+5R1YpbKQAfZ WGEQBGgbfyVFLGE/DQirlHXOdhYpEoY13n+9LZcyqHc0GIbGnaBV4jJUhddIrQ0Wst/l qX00U0x3Jab1SxF8oXRYArF3Jjzmn89xikscz1kTTNjuW+Y04ZnhBTjEQCujp6hOD7KR t/pA== X-Gm-Message-State: ANoB5pkN8Le3PPDkF1BQMIRB6eXaY8aBforpUbeZWJglzgf+NdZl3Rku zrOYPm1iAPJlqI9gGZyLXE0jx58FQPA= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a05:690c:845:b0:3a5:36e5:94eb with SMTP id bz5-20020a05690c084500b003a536e594ebmr5266716ywb.39.1669083377322; Mon, 21 Nov 2022 18:16:17 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:25 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-11-drosen@google.com> Subject: [RFC PATCH v2 10/21] fuse-bpf: Add support for fallocate From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750161010236074339?= X-GMAIL-MSGID: =?utf-8?q?1750161010236074339?= Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/file.c | 3 +++ fs/fuse/fuse_i.h | 6 +++++ 3 files changed, 67 insertions(+) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 76f48872ed35..51aadeb1b7dc 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -330,6 +330,64 @@ ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma) return ret; } +static int fuse_file_fallocate_initialize_in(struct fuse_args *fa, + struct fuse_fallocate_in *ffi, + struct file *file, int mode, loff_t offset, loff_t length) +{ + struct fuse_file *ff = file->private_data; + + *ffi = (struct fuse_fallocate_in) { + .fh = ff->fh, + .offset = offset, + .length = length, + .mode = mode, + }; + + *fa = (struct fuse_args) { + .opcode = FUSE_FALLOCATE, + .nodeid = ff->nodeid, + .in_numargs = 1, + .in_args[0].size = sizeof(*ffi), + .in_args[0].value = ffi, + }; + + return 0; +} + +static int fuse_file_fallocate_initialize_out(struct fuse_args *fa, + struct fuse_fallocate_in *ffi, + struct file *file, int mode, loff_t offset, loff_t length) +{ + return 0; +} + +static int fuse_file_fallocate_backing(struct fuse_args *fa, int *out, + struct file *file, int mode, loff_t offset, loff_t length) +{ + const struct fuse_fallocate_in *ffi = fa->in_args[0].value; + struct fuse_file *ff = file->private_data; + + *out = vfs_fallocate(ff->backing_file, ffi->mode, ffi->offset, + ffi->length); + return 0; +} + +static int fuse_file_fallocate_finalize(struct fuse_args *fa, int *out, + struct file *file, int mode, loff_t offset, loff_t length) +{ + return 0; +} + +int fuse_bpf_file_fallocate(int *out, struct inode *inode, struct file *file, int mode, loff_t offset, loff_t length) +{ + return fuse_bpf_backing(inode, struct fuse_fallocate_in, out, + fuse_file_fallocate_initialize_in, + fuse_file_fallocate_initialize_out, + fuse_file_fallocate_backing, + fuse_file_fallocate_finalize, + file, mode, offset, length); +} + /******************************************************************************* * Directory operations after here * ******************************************************************************/ diff --git a/fs/fuse/file.c b/fs/fuse/file.c index e90b3e2d5452..ab3cd43556e0 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2997,6 +2997,9 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, bool block_faults = FUSE_IS_DAX(inode) && lock_inode; + if (fuse_bpf_file_fallocate(&err, inode, file, mode, offset, length)) + return err; + if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) return -EOPNOTSUPP; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 108c2ea15a49..4351dbc7f10d 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1401,6 +1401,7 @@ int parse_fuse_bpf_entry(struct fuse_bpf_entry *fbe, int num_entries); #ifdef CONFIG_FUSE_BPF int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t offset, int whence); +int fuse_bpf_file_fallocate(int *out, struct inode *inode, struct file *file, int mode, loff_t offset, loff_t length); int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct dentry *entry, unsigned int flags); int fuse_bpf_access(int *out, struct inode *inode, int mask); @@ -1411,6 +1412,11 @@ static inline int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file * return 0; } +static inline int fuse_bpf_file_fallocate(int *out, struct inode *inode, struct file *file, int mode, loff_t offset, loff_t length) +{ + return 0; +} + static inline int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct dentry *entry, unsigned int flags) { return 0; From patchwork Tue Nov 22 02:15:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24129 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1956911wrr; Mon, 21 Nov 2022 18:19:26 -0800 (PST) X-Google-Smtp-Source: AA0mqf55xqjH8gWLWjYh1phRm8petvmxxZmQ6Baf23Qt7JI2XwwMZOKZlrT5jpHIpVe/VOS1vYao X-Received: by 2002:a17:902:cf02:b0:186:c372:72d6 with SMTP id i2-20020a170902cf0200b00186c37272d6mr14749828plg.25.1669083566650; Mon, 21 Nov 2022 18:19:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083566; cv=none; d=google.com; s=arc-20160816; b=bMTubYlIJ6GqW+Lun3J6gwo6ScCWQi02D/NFl7G6H/AWn+34bGBDZoqruoySOxpdZj KTYegcPeg5VrW7AWCMfnT/y+FmpKsSi9j/YgSbeLQrdh583N1vUckcJJhb2rxazNyu27 d/hWzR+l5ikovrlJ/rvCGV++N+611u7algmVufp0yWd9H54/KWam1B7M1OGXJIYUVL2b xGUdSjDWBasyA2WeM9oS4mdaG3tbqXEw3D1M//G4Ol4D9OdUOHoS3iysKUyFlQA/+Jwb BhZ30qWDUG4ddJ+RwHmFMladxPnSk0bYcabwTbzsPeDosWjlWmUWJX5dCd6EWkYC5Jtp y2xA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=78iV0IOgPJQWyL/mQIMxjEmfCaR2pA5J6aYjL9H4JYo=; b=xDSx9prz12YnuvuzxvX9hU8x3ZXXJB0SXdIb+/7I4wyozhlXCaYI9ly0ZubvL3TuFy bUtCR68499wOCu4Fy4X2s3T5mFnjBa3o8328xe77jajzCE21OHnZGmhJLdsHYQ8iiMno 2+FiW8kHr9fKoU5w5oEFGgIPeghzcVKl47BS53k70ISOv/aNwQNbgKzv8IEFZD/3A8tj 9TSscK7zA69161x32/7D/hOkCRmzZZQjjNaxIViqfnnIluGyAk577j7giLSr6CPPYyBE Hqd2BJVxZiGwJiRIeS2Nim6BRqZj9vX8cOvbDChXeAzTXVijjxujGSZEqYRycaqTOQiR eFjg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=gHf8zmM7; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id v135-20020a63618d000000b0047764bac806si5566261pgb.749.2022.11.21.18.19.13; Mon, 21 Nov 2022 18:19:26 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=gHf8zmM7; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232573AbiKVCSE (ORCPT + 99 others); Mon, 21 Nov 2022 21:18:04 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43418 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232607AbiKVCRH (ORCPT ); Mon, 21 Nov 2022 21:17:07 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 79DD4E6353 for ; Mon, 21 Nov 2022 18:16:19 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id e198-20020a2537cf000000b006e699f20c51so12383981yba.7 for ; Mon, 21 Nov 2022 18:16:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=78iV0IOgPJQWyL/mQIMxjEmfCaR2pA5J6aYjL9H4JYo=; b=gHf8zmM74lrP+ge6ba1Qf4CO+Nh8VrJVNTDNaB6851IfJmOnkJ9ucSQHZ88q1KOTd+ scELBI5K48bn/AvOvHx+ifRIumMlSCEwFxJpxi2umJX8mnAjEqaEO6/stVSz4IJufrDX dcFF5dQpT7vbFhruef2o5VdJRcpO8uUmBSSz6S7QfwY0RLpSM6MCa+I2pB3eqEeb3Acp M1J1HugnhLOmrs4z2U67ABsYmbFXtQB+TgX2i34vlhHkAiCWRqVvh+kjjkSlgEC0PiRZ KZadGpwzL6nMOVpKqP1JCEfC84/rhDeQlsu6WgPM9C+S+FP03gX6W3GRxsTIvDham//l h4Lw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=78iV0IOgPJQWyL/mQIMxjEmfCaR2pA5J6aYjL9H4JYo=; b=TM1b+jBvcaRqNkPW6zEtsFSSEdQcdyTVCT7j+GPbdweoUKIW4CsVm0MaN/YyvNL7qs JKre495/5Xr0XyTUvhXbOX6pHUx4EQjduBg3EG/Wkovpt4knX6/2ivj5x5OzHZEQmiJg HA692IuULCXt2xCSocFyKzUQCOmT9bMPNRih8P0t21sHkmolPPIa5mSyycxDlJiTccAq sN1BcWxzLYM192zMLBC6rlIOjo6PDXGfj7cpeYEnvHRVDYI4TqBgxNgQEtHvUFOuzTxk Y6Fb460F7n/bi0jfyfQUUqdZX0hikYdEved1bAK2L2g7Q11EYjIxmL7yii0x+xZ45izL guJA== X-Gm-Message-State: ANoB5pn22jIfk8+pCiNeezGW9Y4EE18cxjss26hz+QKnD35iNuA9QRia HCd0RVePwi52XPuL0Ai9gC80TiW73Bk= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a5b:bcd:0:b0:6cf:f46b:c28f with SMTP id c13-20020a5b0bcd000000b006cff46bc28fmr4030875ybr.520.1669083379336; Mon, 21 Nov 2022 18:16:19 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:26 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-12-drosen@google.com> Subject: [RFC PATCH v2 11/21] fuse-bpf: Support file/dir open/close From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750160969926549493?= X-GMAIL-MSGID: =?utf-8?q?1750160969926549493?= Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 356 ++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/dir.c | 8 ++ fs/fuse/file.c | 7 + fs/fuse/fuse_i.h | 26 ++++ 4 files changed, 397 insertions(+) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 51aadeb1b7dc..c8e95abc04aa 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -205,6 +205,362 @@ static void fuse_stat_to_attr(struct fuse_conn *fc, struct inode *inode, attr->blksize = 1 << blkbits; } +struct fuse_open_io { + struct fuse_open_in foi; + struct fuse_open_out foo; +}; + +static int fuse_open_initialize_in(struct fuse_args *fa, struct fuse_open_io *foio, + struct inode *inode, struct file *file, bool isdir) +{ + foio->foi = (struct fuse_open_in) { + .flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY), + }; + *fa = (struct fuse_args) { + .nodeid = get_fuse_inode(inode)->nodeid, + .opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN, + .in_numargs = 1, + .in_args[0] = (struct fuse_in_arg) { + .size = sizeof(foio->foi), + .value = &foio->foi, + }, + }; + + return 0; +} + +static int fuse_open_initialize_out(struct fuse_args *fa, struct fuse_open_io *foio, + struct inode *inode, struct file *file, bool isdir) +{ + foio->foo = (struct fuse_open_out) { 0 }; + + fa->out_numargs = 1; + fa->out_args[0] = (struct fuse_arg) { + .size = sizeof(foio->foo), + .value = &foio->foo, + }; + + return 0; +} + +static int fuse_open_backing(struct fuse_args *fa, int *out, + struct inode *inode, struct file *file, bool isdir) +{ + struct fuse_mount *fm = get_fuse_mount(inode); + const struct fuse_open_in *foi = fa->in_args[0].value; + struct fuse_file *ff; + int mask; + struct fuse_dentry *fd = get_fuse_dentry(file->f_path.dentry); + struct file *backing_file; + + ff = fuse_file_alloc(fm); + if (!ff) + return -ENOMEM; + file->private_data = ff; + + switch (foi->flags & O_ACCMODE) { + case O_RDONLY: + mask = MAY_READ; + break; + + case O_WRONLY: + mask = MAY_WRITE; + break; + + case O_RDWR: + mask = MAY_READ | MAY_WRITE; + break; + + default: + return -EINVAL; + } + + *out = inode_permission(&init_user_ns, + get_fuse_inode(inode)->backing_inode, mask); + if (*out) + return *out; + + backing_file = + dentry_open(&fd->backing_path, foi->flags, current_cred()); + + if (IS_ERR(backing_file)) { + fuse_file_free(ff); + file->private_data = NULL; + return PTR_ERR(backing_file); + } + ff->backing_file = backing_file; + + *out = 0; + return 0; +} + +static int fuse_open_finalize(struct fuse_args *fa, int *out, + struct inode *inode, struct file *file, bool isdir) +{ + struct fuse_file *ff = file->private_data; + struct fuse_open_out *foo = fa->out_args[0].value; + + if (ff) { + ff->fh = foo->fh; + ff->nodeid = get_fuse_inode(inode)->nodeid; + } + return 0; +} + +int fuse_bpf_open(int *out, struct inode *inode, struct file *file, bool isdir) +{ + return fuse_bpf_backing(inode, struct fuse_open_io, out, + fuse_open_initialize_in, fuse_open_initialize_out, + fuse_open_backing, + fuse_open_finalize, + inode, file, isdir); +} + +struct fuse_create_open_io { + struct fuse_create_in fci; + struct fuse_entry_out feo; + struct fuse_open_out foo; +}; + +static int fuse_create_open_initialize_in(struct fuse_args *fa, struct fuse_create_open_io *fcoio, + struct inode *dir, struct dentry *entry, + struct file *file, unsigned int flags, umode_t mode) +{ + fcoio->fci = (struct fuse_create_in) { + .flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY), + .mode = mode, + }; + + *fa = (struct fuse_args) { + .nodeid = get_node_id(dir), + .opcode = FUSE_CREATE, + .in_numargs = 2, + .in_args[0] = (struct fuse_in_arg) { + .size = sizeof(fcoio->fci), + .value = &fcoio->fci, + }, + .in_args[1] = (struct fuse_in_arg) { + .size = entry->d_name.len + 1, + .value = (void *) entry->d_name.name, + }, + }; + + return 0; +} + +static int fuse_create_open_initialize_out(struct fuse_args *fa, struct fuse_create_open_io *fcoio, + struct inode *dir, struct dentry *entry, + struct file *file, unsigned int flags, umode_t mode) +{ + fcoio->feo = (struct fuse_entry_out) { 0 }; + fcoio->foo = (struct fuse_open_out) { 0 }; + + fa->out_numargs = 2; + fa->out_args[0] = (struct fuse_arg) { + .size = sizeof(fcoio->feo), + .value = &fcoio->feo, + }; + fa->out_args[1] = (struct fuse_arg) { + .size = sizeof(fcoio->foo), + .value = &fcoio->foo, + }; + + return 0; +} + +static int fuse_open_file_backing(struct inode *inode, struct file *file) +{ + struct fuse_mount *fm = get_fuse_mount(inode); + struct dentry *entry = file->f_path.dentry; + struct fuse_dentry *fuse_dentry = get_fuse_dentry(entry); + struct fuse_file *fuse_file; + struct file *backing_file; + + fuse_file = fuse_file_alloc(fm); + if (!fuse_file) + return -ENOMEM; + file->private_data = fuse_file; + + backing_file = dentry_open(&fuse_dentry->backing_path, file->f_flags, + current_cred()); + if (IS_ERR(backing_file)) { + fuse_file_free(fuse_file); + file->private_data = NULL; + return PTR_ERR(backing_file); + } + fuse_file->backing_file = backing_file; + + return 0; +} + +static int fuse_create_open_backing(struct fuse_args *fa, int *out, + struct inode *dir, struct dentry *entry, + struct file *file, unsigned int flags, umode_t mode) +{ + struct fuse_inode *dir_fuse_inode = get_fuse_inode(dir); + struct path backing_path; + struct inode *inode = NULL; + struct dentry *backing_parent; + struct dentry *newent; + const struct fuse_create_in *fci = fa->in_args[0].value; + + get_fuse_backing_path(entry, &backing_path); + if (!backing_path.dentry) + return -EBADF; + + if (IS_ERR(backing_path.dentry)) + return PTR_ERR(backing_path.dentry); + + if (d_really_is_positive(backing_path.dentry)) { + *out = -EIO; + goto out; + } + + backing_parent = dget_parent(backing_path.dentry); + inode_lock_nested(dir_fuse_inode->backing_inode, I_MUTEX_PARENT); + *out = vfs_create(&init_user_ns, d_inode(backing_parent), + backing_path.dentry, fci->mode, true); + inode_unlock(d_inode(backing_parent)); + dput(backing_parent); + if (*out) + goto out; + + inode = fuse_iget_backing(dir->i_sb, 0, backing_path.dentry->d_inode); + if (IS_ERR(inode)) { + *out = PTR_ERR(inode); + goto out; + } + + newent = d_splice_alias(inode, entry); + if (IS_ERR(newent)) { + *out = PTR_ERR(newent); + goto out; + } + + entry = newent ? newent : entry; + *out = finish_open(file, entry, fuse_open_file_backing); + +out: + path_put(&backing_path); + return *out; +} + +static int fuse_create_open_finalize(struct fuse_args *fa, int *out, + struct inode *dir, struct dentry *entry, + struct file *file, unsigned int flags, umode_t mode) +{ + struct fuse_file *ff = file->private_data; + struct fuse_inode *fi = get_fuse_inode(file->f_inode); + struct fuse_entry_out *feo = fa->out_args[0].value; + struct fuse_open_out *foo = fa->out_args[1].value; + + if (fi) + fi->nodeid = feo->nodeid; + if (ff) + ff->fh = foo->fh; + return 0; +} + +int fuse_bpf_create_open(int *out, struct inode *dir, struct dentry *entry, + struct file *file, unsigned int flags, umode_t mode) +{ + return fuse_bpf_backing(dir, struct fuse_create_open_io, out, + fuse_create_open_initialize_in, + fuse_create_open_initialize_out, + fuse_create_open_backing, + fuse_create_open_finalize, + dir, entry, file, flags, mode); +} + +static int fuse_release_initialize_in(struct fuse_args *fa, struct fuse_release_in *fri, + struct inode *inode, struct file *file) +{ + struct fuse_file *fuse_file = file->private_data; + + /* Always put backing file whatever bpf/userspace says */ + fput(fuse_file->backing_file); + + *fri = (struct fuse_release_in) { + .fh = ((struct fuse_file *)(file->private_data))->fh, + }; + + *fa = (struct fuse_args) { + .nodeid = get_fuse_inode(inode)->nodeid, + .opcode = FUSE_RELEASE, + .in_numargs = 1, + .in_args[0].size = sizeof(*fri), + .in_args[0].value = fri, + }; + + return 0; +} + +static int fuse_release_initialize_out(struct fuse_args *fa, struct fuse_release_in *fri, + struct inode *inode, struct file *file) +{ + return 0; +} + +static int fuse_releasedir_initialize_in(struct fuse_args *fa, + struct fuse_release_in *fri, + struct inode *inode, struct file *file) +{ + struct fuse_file *fuse_file = file->private_data; + + /* Always put backing file whatever bpf/userspace says */ + fput(fuse_file->backing_file); + + *fri = (struct fuse_release_in) { + .fh = ((struct fuse_file *)(file->private_data))->fh, + }; + + *fa = (struct fuse_args) { + .nodeid = get_fuse_inode(inode)->nodeid, + .opcode = FUSE_RELEASEDIR, + .in_numargs = 1, + .in_args[0].size = sizeof(*fri), + .in_args[0].value = fri, + }; + + return 0; +} + +static int fuse_releasedir_initialize_out(struct fuse_args *fa, + struct fuse_release_in *fri, + struct inode *inode, struct file *file) +{ + return 0; +} + +static int fuse_release_backing(struct fuse_args *fa, int *out, + struct inode *inode, struct file *file) +{ + return 0; +} + +static int fuse_release_finalize(struct fuse_args *fa, int *out, + struct inode *inode, struct file *file) +{ + fuse_file_free(file->private_data); + *out = 0; + return 0; +} + +int fuse_bpf_release(int *out, struct inode *inode, struct file *file) +{ + return fuse_bpf_backing(inode, struct fuse_release_in, out, + fuse_release_initialize_in, fuse_release_initialize_out, + fuse_release_backing, fuse_release_finalize, + inode, file); +} + +int fuse_bpf_releasedir(int *out, struct inode *inode, struct file *file) +{ + return fuse_bpf_backing(inode, struct fuse_release_in, out, + fuse_releasedir_initialize_in, fuse_releasedir_initialize_out, + fuse_release_backing, fuse_release_finalize, inode, file); +} + struct fuse_lseek_io { struct fuse_lseek_in fli; struct fuse_lseek_out flo; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 4e19320889ed..e330a6af9ee7 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -635,6 +635,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, /* Userspace expects S_IFREG in create mode */ BUG_ON((mode & S_IFMT) != S_IFREG); + if (fuse_bpf_create_open(&err, dir, entry, file, flags, mode)) + return err; + forget = fuse_alloc_forget(); err = -ENOMEM; if (!forget) @@ -1554,6 +1557,11 @@ static int fuse_dir_open(struct inode *inode, struct file *file) static int fuse_dir_release(struct inode *inode, struct file *file) { + int err = 0; + + if (fuse_bpf_releasedir(&err, inode, file)) + return err; + fuse_release_common(file, true); return 0; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index ab3cd43556e0..70a5bd5403ca 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -241,6 +241,9 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir) if (err) return err; + if (fuse_bpf_open(&err, inode, file, isdir)) + return err; + if (is_wb_truncate || dax_truncate) inode_lock(inode); @@ -349,6 +352,10 @@ static int fuse_open(struct inode *inode, struct file *file) static int fuse_release(struct inode *inode, struct file *file) { struct fuse_conn *fc = get_fuse_conn(inode); + int err; + + if (fuse_bpf_release(&err, inode, file)) + return err; /* * Dirty pages might remain despite write_inode_now() call from diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 4351dbc7f10d..794b1a06079c 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1400,6 +1400,11 @@ int parse_fuse_bpf_entry(struct fuse_bpf_entry *fbe, int num_entries); #ifdef CONFIG_FUSE_BPF +int fuse_bpf_open(int *err, struct inode *inode, struct file *file, bool isdir); +int fuse_bpf_create_open(int *out, struct inode *dir, struct dentry *entry, + struct file *file, unsigned int flags, umode_t mode); +int fuse_bpf_release(int *out, struct inode *inode, struct file *file); +int fuse_bpf_releasedir(int *out, struct inode *inode, struct file *file); int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t offset, int whence); int fuse_bpf_file_fallocate(int *out, struct inode *inode, struct file *file, int mode, loff_t offset, loff_t length); int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct dentry *entry, unsigned int flags); @@ -1407,6 +1412,27 @@ int fuse_bpf_access(int *out, struct inode *inode, int mask); #else +static inline int fuse_bpf_open(int *err, struct inode *inode, struct file *file, bool isdir) +{ + return 0; +} + +static inline int fuse_bpf_create_open(int *out, struct inode *dir, struct dentry *entry, + struct file *file, unsigned int flags, umode_t mode) +{ + return 0; +} + +static inline int fuse_bpf_release(int *out, struct inode *inode, struct file *file) +{ + return 0; +} + +static inline int fuse_bpf_releasedir(int *out, struct inode *inode, struct file *file) +{ + return 0; +} + static inline int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t offset, int whence) { return 0; From patchwork Tue Nov 22 02:15:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24130 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1956979wrr; Mon, 21 Nov 2022 18:19:37 -0800 (PST) X-Google-Smtp-Source: AA0mqf7bx8cIb52cG93pRAH1BFR+HiP0c28B8VwA+XuZakk2S3HSowtUO46/np8+KCexFpyQAiof X-Received: by 2002:a17:90a:d811:b0:213:aa8:dda with SMTP id a17-20020a17090ad81100b002130aa80ddamr23937906pjv.111.1669083576919; Mon, 21 Nov 2022 18:19:36 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083576; cv=none; d=google.com; s=arc-20160816; b=y7sWXDfoDUITLC2S3pqbIQ6tbK6hmFhjsntTeUbHYgAP4wJepsA2yQGk7Aw8P7WXF7 XCzTRYcsz94p/YVpKzkJhn90eZtMa56sdip8GpEYSpqao25Dm3I4PqAUdNoMyEJWHSQW 2rUHPXN8QTmkRfT35SimYj4PEa0WnoPZfAe+xSXoKJtGwD0gPM3PEY+HyB9Dghm9du5t eFzPl+esAUSO1QTH59VncMsTK7mHYOmoZ+/ekfJMJK01G4nsubRWdoe3ybRn8uy8Q30i 9h7BEArc2IBgYAUcjpn+7TM8HqXviz49JSGuBTUy47+Zh/oSew9axdLx2Q2cC7I+dk5Z ONJw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=ydyHUSUVRLNupkLXr6P8WzdsU341BmaDDMAW+LRksTY=; b=YgZVtIEHKWpL2vd7Ughp4syXqr5GwwoteGrlN8wGhQZP6siVb2UbdSs2Hbv02L735O DekM8laGqsKX0a7GjAaEUGeeGUKIZVvdMKVTMjvS54brluZ0hjUs70hcMbOcZjiAokkX wWVHHqrbFCq6Gcv+pbzdkA+31qxVJWR6Dr4I2LIShqsuxA7LX1ZmQGOeRC015S8m2cxQ mWutlS0J0I5TQvcA2JgRwbl0yIO4oFwbH8gq/LbDm5N2XiMAtbAj4GSnFMza26exkibd RQ1YILmgPIOwqC9vjRBn/TkJ1GOQ1hzyDj54INEpYXl+3QZrSCbW87OHs66dNWRJ19/i DexA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=k+KyxhZM; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id n9-20020a170903110900b0018729febdaesi14681915plh.122.2022.11.21.18.19.22; Mon, 21 Nov 2022 18:19:36 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=k+KyxhZM; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232613AbiKVCSP (ORCPT + 99 others); Mon, 21 Nov 2022 21:18:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43554 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232618AbiKVCRO (ORCPT ); Mon, 21 Nov 2022 21:17:14 -0500 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 660BBE6779 for ; Mon, 21 Nov 2022 18:16:22 -0800 (PST) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-38f92b4b3f2so127643557b3.1 for ; Mon, 21 Nov 2022 18:16:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=ydyHUSUVRLNupkLXr6P8WzdsU341BmaDDMAW+LRksTY=; b=k+KyxhZMTRllx3lQFyjWbf+28UVtsTsFqm5n+/aW2I9WhizNoXiOdaaQkDKJd5Rj0u hO64pYowvIgPhLWK5B50w4OIjBXWqMsmXMsK3BpMofw9xupyoMj8iGDFjKiS5ZLGtIQM vf2CqSanuhwMpqzaA6j2GmjhW+C6WXaqn+aCrvwrJyf+Bg+VKdVJX3zH/5z95QjOmAYR 6oG/oLULfWKPkw2tcp6VjKDSHdn66CHYe0CqwzBwuBYF2/GVTIHJUuPWJD7jLAuH3wlr DX4zRU8SXoKcbpHwtFdX+EOOV3uwqJ+eie1fI7Ta+5aREznvRvC2rn3Gi6vz7/pJw9gI dVYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=ydyHUSUVRLNupkLXr6P8WzdsU341BmaDDMAW+LRksTY=; b=RHhQ3a81dAhB+Auee5Kjdftt7DvVzmiWyGJSl6gz2XinMlpXhtWxFN3K/IB8EosOfD f62WqOs0g4hc6PPiGWzXvRpLBcQiufz8QUJKib7m+e1J2JRPvTCv+Vd3KB5+dbwd0p5x PqWGB4rF+MLLQbBgqBBa7J9r17GAPSoOfuM3gK+IA8e2Z9y7ErnnQ9+GStOgx7uBSr5T lM3gidi/Hz+PIyRopufeMvL76aFlueqdBeKNDj8ckrzGSs8UA/yiHtZcUjVbmVrZkPM6 HtwxjaairHSCbfCjbxqo0Gu2ZgQBS3vL8tzgQrGaGdfWX0IMnuTnPqoVZ2f8Pb1EW+VK QHDg== X-Gm-Message-State: ANoB5plZAr29Lbyu7usbSeWZTFglMQaHjSuu5J4QmQXDbXvUwJlQ7TdB L97xg8Z76DUjF5rOSlBtfXMwlGRPbtg= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a0d:ea96:0:b0:3a6:4f96:2639 with SMTP id t144-20020a0dea96000000b003a64f962639mr1916559ywe.440.1669083381448; Mon, 21 Nov 2022 18:16:21 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:27 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-13-drosen@google.com> Subject: [RFC PATCH v2 12/21] fuse-bpf: Support mknod/unlink/mkdir/rmdir From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750160980807146634?= X-GMAIL-MSGID: =?utf-8?q?1750160980807146634?= Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 306 ++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/dir.c | 14 +++ fs/fuse/fuse_i.h | 24 ++++ 3 files changed, 344 insertions(+) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index c8e95abc04aa..a7505d6887e0 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -205,6 +205,13 @@ static void fuse_stat_to_attr(struct fuse_conn *fc, struct inode *inode, attr->blksize = 1 << blkbits; } +/* + * Unused io passed to fuse_bpf_backing when io operation needs no scratch space + */ +struct fuse_unused_io { + int unused; +}; + struct fuse_open_io { struct fuse_open_in foi; struct fuse_open_out foo; @@ -930,6 +937,305 @@ int fuse_revalidate_backing(struct dentry *entry, unsigned int flags) return 1; } +static int fuse_mknod_initialize_in(struct fuse_args *fa, struct fuse_mknod_in *fmi, + struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) +{ + *fmi = (struct fuse_mknod_in) { + .mode = mode, + .rdev = new_encode_dev(rdev), + .umask = current_umask(), + }; + *fa = (struct fuse_args) { + .nodeid = get_node_id(dir), + .opcode = FUSE_MKNOD, + .in_numargs = 2, + .in_args[0] = (struct fuse_in_arg) { + .size = sizeof(*fmi), + .value = fmi, + }, + .in_args[1] = (struct fuse_in_arg) { + .size = entry->d_name.len + 1, + .value = (void *) entry->d_name.name, + }, + }; + + return 0; +} + +static int fuse_mknod_initialize_out(struct fuse_args *fa, struct fuse_mknod_in *fmi, + struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) +{ + return 0; +} + +static int fuse_mknod_backing(struct fuse_args *fa, int *out, + struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) +{ + const struct fuse_mknod_in *fmi = fa->in_args[0].value; + struct fuse_inode *fuse_inode = get_fuse_inode(dir); + struct inode *backing_inode = fuse_inode->backing_inode; + struct path backing_path; + struct inode *inode = NULL; + + get_fuse_backing_path(entry, &backing_path); + if (!backing_path.dentry) + return -EBADF; + + inode_lock_nested(backing_inode, I_MUTEX_PARENT); + mode = fmi->mode; + if (!IS_POSIXACL(backing_inode)) + mode &= ~fmi->umask; + *out = vfs_mknod(&init_user_ns, backing_inode, backing_path.dentry, mode, + new_decode_dev(fmi->rdev)); + inode_unlock(backing_inode); + if (*out) + goto out; + if (d_really_is_negative(backing_path.dentry) || + unlikely(d_unhashed(backing_path.dentry))) { + *out = -EINVAL; + /** + * TODO: overlayfs responds to this situation with a + * lookupOneLen. Should we do that too? + */ + goto out; + } + inode = fuse_iget_backing(dir->i_sb, fuse_inode->nodeid, backing_inode); + if (IS_ERR(inode)) { + *out = PTR_ERR(inode); + goto out; + } + d_instantiate(entry, inode); +out: + path_put(&backing_path); + return *out; +} + +static int fuse_mknod_finalize(struct fuse_args *fa, int *out, + struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) +{ + return 0; +} + +int fuse_bpf_mknod(int *out, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) +{ + return fuse_bpf_backing(dir, struct fuse_mknod_in, out, + fuse_mknod_initialize_in, fuse_mknod_initialize_out, + fuse_mknod_backing, fuse_mknod_finalize, + dir, entry, mode, rdev); +} + +static int fuse_mkdir_initialize_in(struct fuse_args *fa, struct fuse_mkdir_in *fmi, + struct inode *dir, struct dentry *entry, umode_t mode) +{ + *fmi = (struct fuse_mkdir_in) { + .mode = mode, + .umask = current_umask(), + }; + *fa = (struct fuse_args) { + .nodeid = get_node_id(dir), + .opcode = FUSE_MKDIR, + .in_numargs = 2, + .in_args[0] = (struct fuse_in_arg) { + .size = sizeof(*fmi), + .value = fmi, + }, + .in_args[1] = (struct fuse_in_arg) { + .size = entry->d_name.len + 1, + .value = (void *) entry->d_name.name, + }, + }; + + return 0; +} + +static int fuse_mkdir_initialize_out(struct fuse_args *fa, struct fuse_mkdir_in *fmi, + struct inode *dir, struct dentry *entry, umode_t mode) +{ + return 0; +} + +static int fuse_mkdir_backing(struct fuse_args *fa, int *out, + struct inode *dir, struct dentry *entry, umode_t mode) +{ + const struct fuse_mkdir_in *fmi = fa->in_args[0].value; + struct fuse_inode *fuse_inode = get_fuse_inode(dir); + struct inode *backing_inode = fuse_inode->backing_inode; + struct path backing_path; + struct inode *inode = NULL; + struct dentry *d; + + get_fuse_backing_path(entry, &backing_path); + if (!backing_path.dentry) + return -EBADF; + + inode_lock_nested(backing_inode, I_MUTEX_PARENT); + mode = fmi->mode; + if (!IS_POSIXACL(backing_inode)) + mode &= ~fmi->umask; + *out = vfs_mkdir(&init_user_ns, backing_inode, backing_path.dentry, + mode); + if (*out) + goto out; + if (d_really_is_negative(backing_path.dentry) || + unlikely(d_unhashed(backing_path.dentry))) { + d = lookup_one_len(entry->d_name.name, + backing_path.dentry->d_parent, + entry->d_name.len); + if (IS_ERR(d)) { + *out = PTR_ERR(d); + goto out; + } + dput(backing_path.dentry); + backing_path.dentry = d; + } + inode = fuse_iget_backing(dir->i_sb, fuse_inode->nodeid, backing_inode); + if (IS_ERR(inode)) { + *out = PTR_ERR(inode); + goto out; + } + d_instantiate(entry, inode); +out: + inode_unlock(backing_inode); + path_put(&backing_path); + return *out; +} + +static int fuse_mkdir_finalize(struct fuse_args *fa, int *out, + struct inode *dir, struct dentry *entry, umode_t mode) +{ + return 0; +} + +int fuse_bpf_mkdir(int *out, struct inode *dir, struct dentry *entry, umode_t mode) +{ + return fuse_bpf_backing(dir, struct fuse_mkdir_in, out, + fuse_mkdir_initialize_in, fuse_mkdir_initialize_out, + fuse_mkdir_backing, fuse_mkdir_finalize, + dir, entry, mode); +} + +static int fuse_rmdir_initialize_in(struct fuse_args *fa, struct fuse_unused_io *unused, + struct inode *dir, struct dentry *entry) +{ + *fa = (struct fuse_args) { + .nodeid = get_node_id(dir), + .opcode = FUSE_RMDIR, + .in_numargs = 1, + .in_args[0] = (struct fuse_in_arg) { + .size = entry->d_name.len + 1, + .value = (void *) entry->d_name.name, + }, + }; + + return 0; +} + +static int fuse_rmdir_initialize_out(struct fuse_args *fa, struct fuse_unused_io *unused, + struct inode *dir, struct dentry *entry) +{ + return 0; +} + +static int fuse_rmdir_backing(struct fuse_args *fa, int *out, + struct inode *dir, struct dentry *entry) +{ + struct path backing_path; + struct dentry *backing_parent_dentry; + struct inode *backing_inode; + + get_fuse_backing_path(entry, &backing_path); + if (!backing_path.dentry) + return -EBADF; + + backing_parent_dentry = dget_parent(backing_path.dentry); + backing_inode = d_inode(backing_parent_dentry); + + inode_lock_nested(backing_inode, I_MUTEX_PARENT); + *out = vfs_rmdir(&init_user_ns, backing_inode, backing_path.dentry); + inode_unlock(backing_inode); + + dput(backing_parent_dentry); + if (!*out) + d_drop(entry); + path_put(&backing_path); + return *out; +} + +static int fuse_rmdir_finalize(struct fuse_args *fa, int *out, struct inode *dir, struct dentry *entry) +{ + return 0; +} + +int fuse_bpf_rmdir(int *out, struct inode *dir, struct dentry *entry) +{ + return fuse_bpf_backing(dir, struct fuse_unused_io, out, + fuse_rmdir_initialize_in, fuse_rmdir_initialize_out, + fuse_rmdir_backing, fuse_rmdir_finalize, + dir, entry); +} + +static int fuse_unlink_initialize_in(struct fuse_args *fa, struct fuse_unused_io *unused, + struct inode *dir, struct dentry *entry) +{ + *fa = (struct fuse_args) { + .nodeid = get_node_id(dir), + .opcode = FUSE_UNLINK, + .in_numargs = 1, + .in_args[0] = (struct fuse_in_arg) { + .size = entry->d_name.len + 1, + .value = (void *) entry->d_name.name, + }, + }; + + return 0; +} + +static int fuse_unlink_initialize_out(struct fuse_args *fa, struct fuse_unused_io *unused, + struct inode *dir, struct dentry *entry) +{ + return 0; +} + +static int fuse_unlink_backing(struct fuse_args *fa, int *out, struct inode *dir, struct dentry *entry) +{ + struct path backing_path; + struct dentry *backing_parent_dentry; + struct inode *backing_inode; + + get_fuse_backing_path(entry, &backing_path); + if (!backing_path.dentry) + return -EBADF; + + /* TODO Not sure if we should reverify like overlayfs, or get inode from d_parent */ + backing_parent_dentry = dget_parent(backing_path.dentry); + backing_inode = d_inode(backing_parent_dentry); + + inode_lock_nested(backing_inode, I_MUTEX_PARENT); + *out = vfs_unlink(&init_user_ns, backing_inode, backing_path.dentry, + NULL); + inode_unlock(backing_inode); + + dput(backing_parent_dentry); + if (!*out) + d_drop(entry); + path_put(&backing_path); + return *out; +} + +static int fuse_unlink_finalize(struct fuse_args *fa, int *out, + struct inode *dir, struct dentry *entry) +{ + return 0; +} + +int fuse_bpf_unlink(int *out, struct inode *dir, struct dentry *entry) +{ + return fuse_bpf_backing(dir, struct fuse_unused_io, out, + fuse_unlink_initialize_in, fuse_unlink_initialize_out, + fuse_unlink_backing, fuse_unlink_finalize, + dir, entry); +} + static int fuse_access_initialize_in(struct fuse_args *fa, struct fuse_access_in *fai, struct inode *inode, int mask) { diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index e330a6af9ee7..729a0348fa01 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -869,6 +869,10 @@ static int fuse_mknod(struct user_namespace *mnt_userns, struct inode *dir, struct fuse_mknod_in inarg; struct fuse_mount *fm = get_fuse_mount(dir); FUSE_ARGS(args); + int err; + + if (fuse_bpf_mknod(&err, dir, entry, mode, rdev)) + return err; if (!fm->fc->dont_mask) mode &= ~current_umask(); @@ -915,6 +919,10 @@ static int fuse_mkdir(struct user_namespace *mnt_userns, struct inode *dir, struct fuse_mkdir_in inarg; struct fuse_mount *fm = get_fuse_mount(dir); FUSE_ARGS(args); + int err; + + if (fuse_bpf_mkdir(&err, dir, entry, mode)) + return err; if (!fm->fc->dont_mask) mode &= ~current_umask(); @@ -1001,6 +1009,9 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) if (fuse_is_bad(dir)) return -EIO; + if (fuse_bpf_unlink(&err, dir, entry)) + return err; + args.opcode = FUSE_UNLINK; args.nodeid = get_node_id(dir); args.in_numargs = 1; @@ -1024,6 +1035,9 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) if (fuse_is_bad(dir)) return -EIO; + if (fuse_bpf_rmdir(&err, dir, entry)) + return err; + args.opcode = FUSE_RMDIR; args.nodeid = get_node_id(dir); args.in_numargs = 1; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 794b1a06079c..dc5bba2a75ab 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1403,6 +1403,10 @@ int parse_fuse_bpf_entry(struct fuse_bpf_entry *fbe, int num_entries); int fuse_bpf_open(int *err, struct inode *inode, struct file *file, bool isdir); int fuse_bpf_create_open(int *out, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode); +int fuse_bpf_mknod(int *out, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev); +int fuse_bpf_mkdir(int *out, struct inode *dir, struct dentry *entry, umode_t mode); +int fuse_bpf_rmdir(int *out, struct inode *dir, struct dentry *entry); +int fuse_bpf_unlink(int *out, struct inode *dir, struct dentry *entry); int fuse_bpf_release(int *out, struct inode *inode, struct file *file); int fuse_bpf_releasedir(int *out, struct inode *inode, struct file *file); int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t offset, int whence); @@ -1423,6 +1427,26 @@ static inline int fuse_bpf_create_open(int *out, struct inode *dir, struct dentr return 0; } +static inline int fuse_bpf_mknod(int *out, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) +{ + return 0; +} + +static inline int fuse_bpf_mkdir(int *out, struct inode *dir, struct dentry *entry, umode_t mode) +{ + return 0; +} + +static inline int fuse_bpf_rmdir(int *out, struct inode *dir, struct dentry *entry) +{ + return 0; +} + +static inline int fuse_bpf_unlink(int *out, struct inode *dir, struct dentry *entry) +{ + return 0; +} + static inline int fuse_bpf_release(int *out, struct inode *inode, struct file *file) { return 0; From patchwork Tue Nov 22 02:15:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24135 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1957385wrr; Mon, 21 Nov 2022 18:20:32 -0800 (PST) X-Google-Smtp-Source: AA0mqf7KABY8fTlbv0K7XK3ll2hKVlT20kZa+5P4C2Z5S+Lc3td420hUFjwGa/KRE6K+s97NGn0G X-Received: by 2002:a17:90a:8b03:b0:213:16d2:4d4c with SMTP id y3-20020a17090a8b0300b0021316d24d4cmr23745858pjn.70.1669083632121; Mon, 21 Nov 2022 18:20:32 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083632; cv=none; d=google.com; s=arc-20160816; b=niMO7idmJEXRe6Wd6G/4QveWcMqFxf99prycXNFuXz8E31sgkXy39z9q/Y9OxNj0Oi 6bmC6m/jlbxQ5YTBVa0gT3RHQJjs+uG2YVNSNt2uw3nQd26SmlzUKiu44azOb6nqgPRS kRn+tcCBu48oka4g493MY0eoueWZK8F5NBEvu2U5NGaStjEDNoBSfUE02jA6TJVYBeDa LAdbH7gIoPosuapy2BHMkKKkWh9isF3aBOnW7As8v/NxY6hng53YGxWUhz9vTYjygN5Z kQmZGpGPR0Q0rd3U9vQsQObLKgJTVyTSuYi2gXWLFevS4sYcvePJ7W3TXQBh32gKLT7I uwTQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=mZmovE66ZdqhOmBbykw9B8nSGupb/ebR6gSpmGb5LGI=; b=CB9nkwFQFZ/2Weth8QBYQl0yAU/JumRCCiokADIPUhVGA9qxrfI+I2IUI0jC1Ix8n+ Gtx/u+1IuYLSyBm7SkH9L98JsniEfD3dYLGHXSDFG+lWeVwJ8e+Mkaxf9nWmTwaij3ue kvOF+p+/+na9hRJiRCvTSjVKf8bBztNNzgL/rtdILKVl8IigGjzeiXOJyv+PsxYw5dku RL+lJEnD3BEgbVXcIvSDNO4CbGWVh5y99bKrv8wNsp2u9dl7cfnV2Yq2zDyc5bQgNtUG jsaZ9rYGFSSrXwLk9MVwEr/1kxFGsf7qXmikQXPUDtjeY5V9moGuje/cPfvusr3xS41F fYeA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=o7bbni3n; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id mr20-20020a17090b239400b001fac102fdeesi11256354pjb.95.2022.11.21.18.20.19; Mon, 21 Nov 2022 18:20:32 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=o7bbni3n; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232641AbiKVCSW (ORCPT + 99 others); Mon, 21 Nov 2022 21:18:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42812 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232209AbiKVCRR (ORCPT ); Mon, 21 Nov 2022 21:17:17 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EABF5E6EDE for ; Mon, 21 Nov 2022 18:16:23 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id a5-20020a25af05000000b006e450a5e507so12711012ybh.22 for ; Mon, 21 Nov 2022 18:16:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=mZmovE66ZdqhOmBbykw9B8nSGupb/ebR6gSpmGb5LGI=; b=o7bbni3nAcZylijRv69Vs5PD7bchjW2PbDqhDwTIf/E1XkYKIhh8XNGNi/YPCo0HZF pNkTB/LJmEZ1oIf8pbwqXf1yAqIu1gby/ZQSrozaSQFqMLUNSQ+G4wPg2+s1okCgHcpI rCdLKMiB+OugLqqK1dHnnlANqrm/izNKItafjIuJM84hklmpSFFZ0tGtA1F95XtRip9p 0xy1xmnk9oFyZrX0QZB5Z/1zJsrsFzwy1XXnJge9o59l+jdFndAI/TDt2xseMgc30VLg gl1+UHW8205lO3C4cSBQFSH8IuXm8TsTbL4nFlsnurGz1y19fyCqMnlIbqZ4Hlvv83V+ J/MA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=mZmovE66ZdqhOmBbykw9B8nSGupb/ebR6gSpmGb5LGI=; b=DzfebmPgitLCTBSKxwn/OuUuduNLPFrw//EDlQ+hBZUyNLQQLHloWKkupEsQHmOUrj fICW0qV2MGMOfh1BXX7gb5ER24I9Jb4rXhBC1f4FWau1DuRSnjFVDRERU3vGIPv2EEtG UW+VPeruE9a3UjsFizhmTAOPj9s0u7Atc6cSw+9QNx1A8iBI56p64dfUIgW9qeU62Fmp yb55LhufNu+8nYySn6FMosTuXTpFFXqlWG7COb/m6BszMe1IeD+N2uxAn0MAGOuwbnER gy3BaICpEJlvBuOSHCgZS5WxaeMJwUEarzN1/Y069nJKAsVWg/pdx/s0FyzNO6BUODHr PB5Q== X-Gm-Message-State: ANoB5pkjuy0RcFBoRB1wQ9ayv5D0vs3Z+cbKJ02EEtJaSGiDbxvcZoVB ntNAu/QwqHPJ6ItaC0x7CKzrADvNoOs= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a05:6902:50c:b0:6dd:df31:a7a2 with SMTP id x12-20020a056902050c00b006dddf31a7a2mr19543665ybs.635.1669083383456; Mon, 21 Nov 2022 18:16:23 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:28 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-14-drosen@google.com> Subject: [RFC PATCH v2 13/21] fuse-bpf: Add support for read/write iter From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750161038358658422?= X-GMAIL-MSGID: =?utf-8?q?1750161038358658422?= This includes adjustments from Amir Goldstein's patch to FUSE Passthrough Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 377 ++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/control.c | 2 +- fs/fuse/file.c | 8 + fs/fuse/fuse_i.h | 19 ++- fs/fuse/inode.c | 13 ++ 5 files changed, 417 insertions(+), 2 deletions(-) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index a7505d6887e0..425815d7f5dc 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -10,6 +10,7 @@ #include #include #include +#include /* * expression statement to wrap the backing filter logic @@ -74,6 +75,89 @@ handled; \ }) +#define FUSE_BPF_IOCB_MASK (IOCB_APPEND | IOCB_DSYNC | IOCB_HIPRI | IOCB_NOWAIT | IOCB_SYNC) + +struct fuse_bpf_aio_req { + struct kiocb iocb; + refcount_t ref; + struct kiocb *iocb_orig; + struct timespec64 pre_atime; +}; + +static struct kmem_cache *fuse_bpf_aio_request_cachep; + +static void fuse_file_accessed(struct file *dst_file, struct file *src_file) +{ + struct inode *dst_inode; + struct inode *src_inode; + + if (dst_file->f_flags & O_NOATIME) + return; + + dst_inode = file_inode(dst_file); + src_inode = file_inode(src_file); + + if ((!timespec64_equal(&dst_inode->i_mtime, &src_inode->i_mtime) || + !timespec64_equal(&dst_inode->i_ctime, &src_inode->i_ctime))) { + dst_inode->i_mtime = src_inode->i_mtime; + dst_inode->i_ctime = src_inode->i_ctime; + } + + touch_atime(&dst_file->f_path); +} + +static void fuse_copyattr(struct file *dst_file, struct file *src_file) +{ + struct inode *dst = file_inode(dst_file); + struct inode *src = file_inode(src_file); + + dst->i_atime = src->i_atime; + dst->i_mtime = src->i_mtime; + dst->i_ctime = src->i_ctime; + i_size_write(dst, i_size_read(src)); + fuse_invalidate_attr(dst); +} + +static void fuse_file_start_write(struct file *fuse_file, struct file *backing_file, + loff_t pos, size_t count) +{ + struct inode *inode = file_inode(fuse_file); + struct fuse_inode *fi = get_fuse_inode(inode); + + if (inode->i_size < pos + count) + set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); + + file_start_write(backing_file); +} + +static void fuse_file_end_write(struct file *fuse_file, struct file *backing_file, + loff_t pos, size_t res) +{ + struct inode *inode = file_inode(fuse_file); + struct fuse_inode *fi = get_fuse_inode(inode); + + file_end_write(backing_file); + + if (res > 0) + fuse_write_update_attr(inode, pos, res); + + clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); + fuse_invalidate_attr(inode); +} + +static void fuse_file_start_read(struct file *backing_file, struct timespec64 *pre_atime) +{ + *pre_atime = file_inode(backing_file)->i_atime; +} + +static void fuse_file_end_read(struct file *fuse_file, struct file *backing_file, + struct timespec64 *pre_atime) +{ + /* Mimic atime update policy of passthrough inode, not the value */ + if (!timespec64_equal(&file_inode(backing_file)->i_atime, pre_atime)) + fuse_invalidate_atime(file_inode(fuse_file)); +} + static void fuse_get_backing_path(struct file *file, struct path *path) { path_get(&file->f_path); @@ -656,6 +740,283 @@ int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t o file, offset, whence); } +static inline void fuse_bpf_aio_put(struct fuse_bpf_aio_req *aio_req) +{ + if (refcount_dec_and_test(&aio_req->ref)) + kmem_cache_free(fuse_bpf_aio_request_cachep, aio_req); +} + +static void fuse_bpf_aio_cleanup_handler(struct fuse_bpf_aio_req *aio_req, long res) +{ + struct kiocb *iocb = &aio_req->iocb; + struct kiocb *iocb_orig = aio_req->iocb_orig; + struct file *filp = iocb->ki_filp; + struct file *fuse_filp = iocb_orig->ki_filp; + + if (iocb->ki_flags & IOCB_WRITE) { + __sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb, + SB_FREEZE_WRITE); + fuse_file_end_write(iocb_orig->ki_filp, iocb->ki_filp, iocb->ki_pos, res); + } else { + fuse_file_end_read(fuse_filp, filp, &aio_req->pre_atime); + } + iocb_orig->ki_pos = iocb->ki_pos; + fuse_bpf_aio_put(aio_req); +} + +static void fuse_bpf_aio_rw_complete(struct kiocb *iocb, long res) +{ + struct fuse_bpf_aio_req *aio_req = + container_of(iocb, struct fuse_bpf_aio_req, iocb); + struct kiocb *iocb_orig = aio_req->iocb_orig; + + fuse_bpf_aio_cleanup_handler(aio_req, res); + iocb_orig->ki_complete(iocb_orig, res); +} + +struct fuse_read_iter_out { + uint64_t ret; +}; +struct fuse_file_read_iter_io { + struct fuse_read_in fri; + struct fuse_read_iter_out frio; +}; + +static int fuse_file_read_iter_initialize_in(struct fuse_args *fa, struct fuse_file_read_iter_io *fri, + struct kiocb *iocb, struct iov_iter *to) +{ + struct file *file = iocb->ki_filp; + struct fuse_file *ff = file->private_data; + + fri->fri = (struct fuse_read_in) { + .fh = ff->fh, + .offset = iocb->ki_pos, + .size = to->count, + }; + + /* TODO we can't assume 'to' is a kvec */ + /* TODO we also can't assume the vector has only one component */ + *fa = (struct fuse_args) { + .opcode = FUSE_READ, + .nodeid = ff->nodeid, + .in_numargs = 1, + .in_args[0].size = sizeof(fri->fri), + .in_args[0].value = &fri->fri, + /* + * TODO Design this properly. + * Possible approach: do not pass buf to bpf + * If going to userland, do a deep copy + * For extra credit, do that to/from the vector, rather than + * making an extra copy in the kernel + */ + }; + + return 0; +} + +static int fuse_file_read_iter_initialize_out(struct fuse_args *fa, struct fuse_file_read_iter_io *fri, + struct kiocb *iocb, struct iov_iter *to) +{ + fri->frio = (struct fuse_read_iter_out) { + .ret = fri->fri.size, + }; + + fa->out_numargs = 1; + fa->out_args[0].size = sizeof(fri->frio); + fa->out_args[0].value = &fri->frio; + + return 0; +} + +static int fuse_file_read_iter_backing(struct fuse_args *fa, ssize_t *out, + struct kiocb *iocb, struct iov_iter *to) +{ + struct fuse_read_iter_out *frio = fa->out_args[0].value; + struct file *file = iocb->ki_filp; + struct fuse_file *ff = file->private_data; + + if (!iov_iter_count(to)) + return 0; + + if ((iocb->ki_flags & IOCB_DIRECT) && + (!ff->backing_file->f_mapping->a_ops || + !ff->backing_file->f_mapping->a_ops->direct_IO)) + return -EINVAL; + + /* TODO This just plain ignores any change to fuse_read_in */ + if (is_sync_kiocb(iocb)) { + struct timespec64 pre_atime; + + fuse_file_start_read(ff->backing_file, &pre_atime); + *out = vfs_iter_read(ff->backing_file, to, &iocb->ki_pos, + iocb_to_rw_flags(iocb->ki_flags, FUSE_BPF_IOCB_MASK)); + fuse_file_end_read(file, ff->backing_file, &pre_atime); + } else { + struct fuse_bpf_aio_req *aio_req; + + *out = -ENOMEM; + aio_req = kmem_cache_zalloc(fuse_bpf_aio_request_cachep, GFP_KERNEL); + if (!aio_req) + goto out; + + aio_req->iocb_orig = iocb; + fuse_file_start_read(ff->backing_file, &aio_req->pre_atime); + kiocb_clone(&aio_req->iocb, iocb, ff->backing_file); + aio_req->iocb.ki_complete = fuse_bpf_aio_rw_complete; + refcount_set(&aio_req->ref, 2); + *out = vfs_iocb_iter_read(ff->backing_file, &aio_req->iocb, to); + fuse_bpf_aio_put(aio_req); + if (*out != -EIOCBQUEUED) + fuse_bpf_aio_cleanup_handler(aio_req, *out); + } + + frio->ret = *out; + + /* TODO Need to point value at the buffer for post-modification */ + +out: + fuse_file_accessed(file, ff->backing_file); + + return *out; +} + +static int fuse_file_read_iter_finalize(struct fuse_args *fa, ssize_t *out, + struct kiocb *iocb, struct iov_iter *to) +{ + struct fuse_read_iter_out *frio = fa->out_args[0].value; + + *out = frio->ret; + + return 0; +} + +int fuse_bpf_file_read_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *to) +{ + return fuse_bpf_backing(inode, struct fuse_file_read_iter_io, out, + fuse_file_read_iter_initialize_in, + fuse_file_read_iter_initialize_out, + fuse_file_read_iter_backing, + fuse_file_read_iter_finalize, + iocb, to); +} + +struct fuse_write_iter_out { + uint64_t ret; +}; +struct fuse_file_write_iter_io { + struct fuse_write_in fwi; + struct fuse_write_out fwo; + struct fuse_write_iter_out fwio; +}; + +static int fuse_file_write_iter_initialize_in(struct fuse_args *fa, + struct fuse_file_write_iter_io *fwio, + struct kiocb *iocb, struct iov_iter *from) +{ + struct file *file = iocb->ki_filp; + struct fuse_file *ff = file->private_data; + + *fwio = (struct fuse_file_write_iter_io) { + .fwi.fh = ff->fh, + .fwi.offset = iocb->ki_pos, + .fwi.size = from->count, + }; + + /* TODO we can't assume 'from' is a kvec */ + *fa = (struct fuse_args) { + .opcode = FUSE_WRITE, + .nodeid = ff->nodeid, + .in_numargs = 2, + .in_args[0].size = sizeof(fwio->fwi), + .in_args[0].value = &fwio->fwi, + .in_args[1].size = fwio->fwi.size, + .in_args[1].value = from->kvec->iov_base, + }; + + return 0; +} + +static int fuse_file_write_iter_initialize_out(struct fuse_args *fa, + struct fuse_file_write_iter_io *fwio, + struct kiocb *iocb, struct iov_iter *from) +{ + /* TODO we can't assume 'from' is a kvec */ + fa->out_numargs = 1; + fa->out_args[0].size = sizeof(fwio->fwio); + fa->out_args[0].value = &fwio->fwio; + + return 0; +} + +static int fuse_file_write_iter_backing(struct fuse_args *fa, ssize_t *out, + struct kiocb *iocb, struct iov_iter *from) +{ + struct file *file = iocb->ki_filp; + struct fuse_file *ff = file->private_data; + struct fuse_write_iter_out *fwio = fa->out_args[0].value; + ssize_t count = iov_iter_count(from); + + if (!count) + return 0; + + /* TODO This just plain ignores any change to fuse_write_in */ + /* TODO uint32_t seems smaller than ssize_t.... right? */ + inode_lock(file_inode(file)); + + fuse_copyattr(file, ff->backing_file); + + if (is_sync_kiocb(iocb)) { + fuse_file_start_write(file, ff->backing_file, iocb->ki_pos, count); + *out = vfs_iter_write(ff->backing_file, from, &iocb->ki_pos, + iocb_to_rw_flags(iocb->ki_flags, FUSE_BPF_IOCB_MASK)); + fuse_file_end_write(file, ff->backing_file, iocb->ki_pos, *out); + } else { + struct fuse_bpf_aio_req *aio_req; + + *out = -ENOMEM; + aio_req = kmem_cache_zalloc(fuse_bpf_aio_request_cachep, GFP_KERNEL); + if (!aio_req) + goto out; + + fuse_file_start_write(file, ff->backing_file, iocb->ki_pos, count); + __sb_writers_release(file_inode(ff->backing_file)->i_sb, SB_FREEZE_WRITE); + aio_req->iocb_orig = iocb; + kiocb_clone(&aio_req->iocb, iocb, ff->backing_file); + aio_req->iocb.ki_complete = fuse_bpf_aio_rw_complete; + refcount_set(&aio_req->ref, 2); + *out = vfs_iocb_iter_write(ff->backing_file, &aio_req->iocb, from); + fuse_bpf_aio_put(aio_req); + if (*out != -EIOCBQUEUED) + fuse_bpf_aio_cleanup_handler(aio_req, *out); + } + +out: + inode_unlock(file_inode(file)); + fwio->ret = *out; + if (*out < 0) + return *out; + return 0; +} + +static int fuse_file_write_iter_finalize(struct fuse_args *fa, ssize_t *out, + struct kiocb *iocb, struct iov_iter *from) +{ + struct fuse_write_iter_out *fwio = fa->out_args[0].value; + + *out = fwio->ret; + return 0; +} + +int fuse_bpf_file_write_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *from) +{ + return fuse_bpf_backing(inode, struct fuse_file_write_iter_io, out, + fuse_file_write_iter_initialize_in, + fuse_file_write_iter_initialize_out, + fuse_file_write_iter_backing, + fuse_file_write_iter_finalize, + iocb, from); +} + ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma) { int ret; @@ -1280,3 +1641,19 @@ int fuse_bpf_access(int *out, struct inode *inode, int mask) fuse_access_initialize_in, fuse_access_initialize_out, fuse_access_backing, fuse_access_finalize, inode, mask); } + +int __init fuse_bpf_init(void) +{ + fuse_bpf_aio_request_cachep = kmem_cache_create("fuse_bpf_aio_req", + sizeof(struct fuse_bpf_aio_req), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!fuse_bpf_aio_request_cachep) + return -ENOMEM; + + return 0; +} + +void __exit fuse_bpf_cleanup(void) +{ + kmem_cache_destroy(fuse_bpf_aio_request_cachep); +} diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 247ef4f76761..685552453751 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -378,7 +378,7 @@ int __init fuse_ctl_init(void) return register_filesystem(&fuse_ctl_fs_type); } -void __exit fuse_ctl_cleanup(void) +void fuse_ctl_cleanup(void) { unregister_filesystem(&fuse_ctl_fs_type); } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 70a5bd5403ca..59f3d85106d3 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1604,6 +1604,7 @@ static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) struct file *file = iocb->ki_filp; struct fuse_file *ff = file->private_data; struct inode *inode = file_inode(file); + ssize_t ret; if (fuse_is_bad(inode)) return -EIO; @@ -1611,6 +1612,9 @@ static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) if (FUSE_IS_DAX(inode)) return fuse_dax_read_iter(iocb, to); + if (fuse_bpf_file_read_iter(&ret, inode, iocb, to)) + return ret; + if (!(ff->open_flags & FOPEN_DIRECT_IO)) return fuse_cache_read_iter(iocb, to); else @@ -1622,6 +1626,7 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) struct file *file = iocb->ki_filp; struct fuse_file *ff = file->private_data; struct inode *inode = file_inode(file); + ssize_t ret = 0; if (fuse_is_bad(inode)) return -EIO; @@ -1629,6 +1634,9 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (FUSE_IS_DAX(inode)) return fuse_dax_write_iter(iocb, from); + if (fuse_bpf_file_write_iter(&ret, inode, iocb, from)) + return ret; + if (!(ff->open_flags & FOPEN_DIRECT_IO)) return fuse_cache_write_iter(iocb, from); else diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index dc5bba2a75ab..25cedaa9014c 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1130,7 +1130,7 @@ int fuse_dev_init(void); void fuse_dev_cleanup(void); int fuse_ctl_init(void); -void __exit fuse_ctl_cleanup(void); +void fuse_ctl_cleanup(void); /** * Simple request sending that does request allocation and freeing @@ -1410,6 +1410,8 @@ int fuse_bpf_unlink(int *out, struct inode *dir, struct dentry *entry); int fuse_bpf_release(int *out, struct inode *inode, struct file *file); int fuse_bpf_releasedir(int *out, struct inode *inode, struct file *file); int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t offset, int whence); +int fuse_bpf_file_read_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *to); +int fuse_bpf_file_write_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *from); int fuse_bpf_file_fallocate(int *out, struct inode *inode, struct file *file, int mode, loff_t offset, loff_t length); int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct dentry *entry, unsigned int flags); int fuse_bpf_access(int *out, struct inode *inode, int mask); @@ -1462,6 +1464,16 @@ static inline int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file * return 0; } +static inline int fuse_bpf_file_read_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *to) +{ + return 0; +} + +static inline int fuse_bpf_file_write_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *from) +{ + return 0; +} + static inline int fuse_bpf_file_fallocate(int *out, struct inode *inode, struct file *file, int mode, loff_t offset, loff_t length) { return 0; @@ -1512,4 +1524,9 @@ static inline u64 attr_timeout(struct fuse_attr_out *o) return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); } +#ifdef CONFIG_FUSE_BPF +int __init fuse_bpf_init(void); +void __exit fuse_bpf_cleanup(void); +#endif /* CONFIG_FUSE_BPF */ + #endif /* _FS_FUSE_I_H */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index bafb2832627d..9781faff6df6 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -2094,11 +2094,21 @@ static int __init fuse_init(void) if (res) goto err_sysfs_cleanup; +#ifdef CONFIG_FUSE_BPF + res = fuse_bpf_init(); + if (res) + goto err_ctl_cleanup; +#endif + sanitize_global_limit(&max_user_bgreq); sanitize_global_limit(&max_user_congthresh); return 0; +#ifdef CONFIG_FUSE_BPF + err_ctl_cleanup: + fuse_ctl_cleanup(); +#endif err_sysfs_cleanup: fuse_sysfs_cleanup(); err_dev_cleanup: @@ -2116,6 +2126,9 @@ static void __exit fuse_exit(void) fuse_ctl_cleanup(); fuse_sysfs_cleanup(); fuse_fs_cleanup(); +#ifdef CONFIG_FUSE_BPF + fuse_bpf_cleanup(); +#endif fuse_dev_cleanup(); } From patchwork Tue Nov 22 02:15:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24132 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1957243wrr; Mon, 21 Nov 2022 18:20:11 -0800 (PST) X-Google-Smtp-Source: AA0mqf7mwQrBBd3vKnEEG9tO4f9sqDwfzdgJjInv5FM/ZmMxVKoJ+AhxITURXy4EXJljXSW58aE1 X-Received: by 2002:a63:520b:0:b0:43c:6412:994f with SMTP id g11-20020a63520b000000b0043c6412994fmr1434660pgb.421.1669083610951; Mon, 21 Nov 2022 18:20:10 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083610; cv=none; d=google.com; s=arc-20160816; b=NygYzTDBG7/Oyu9G/fx76AB9NP83KV6wc0qsdg4Tn1Pk9wCTIaw5Br38fRLiByGTts rTFlbf57r8mFr1WjsJjJih6IqOBgtRL1XteWW4YWPIoSHPl5R7s20BZzSelRcX1awmIY nZwqq9CodttXFaELA0WwY3So+6HKQzySYr661Q+5y9QYC5VEoOO2LCl10zPxwpjb5v15 BtQlKSlb3pkQ0qYgmMG+hSOf4nJRfyFfMFr6Ebi1bYIKotYVqlCW4mLxB/8l4RuUJWz9 gkKJ4GqE5P8tqk8dcHwh+27ZPDUxdOS0nu6UySjtA/i4GqmDHmVXPI2JBDYcTUNG8Vnr DxaA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=sXC86U5/hdvmtqoI3CrBqri1fBKx6hffM6aKsOurzIQ=; b=bVCvLsQec5WLKLbREFmI9vYJNWMSort33Dfx0MAprHuBik5GNBuor8BarSHTgn7V8K is2z13DVWOEX13OMxLX4gzZDJN38sCw0MP3obvmXfhDc8vnpP8GENmqn3q3K/iH5MGgP xMFYr4N/m9fwfqEs6i/V6Y2+6RRG5fYSBzHP04n+MSrO+zhGMueJBm3mhNnt1SosYq3X hrHdED8IoeAEqyqDcLXGoC8F7ql46kJpqgDjdLnsKlo810bvTbhEdpwiPCm4tg6Tn+Lb XIXLt+DKiORfzZycm8WiH6D9FhDFMsRpelJSf75T+YSl0evIkgcPfNvi6uNuieNi693s 8dVg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=nviEqECc; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id u9-20020a170902e80900b00177568a0e53si6337366plg.252.2022.11.21.18.19.57; Mon, 21 Nov 2022 18:20:10 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=nviEqECc; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232655AbiKVCTO (ORCPT + 99 others); Mon, 21 Nov 2022 21:19:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43384 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232482AbiKVCRx (ORCPT ); Mon, 21 Nov 2022 21:17:53 -0500 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 49A77E6ED5 for ; Mon, 21 Nov 2022 18:16:26 -0800 (PST) Received: by mail-yb1-xb4a.google.com with SMTP id f126-20020a255184000000b006cb2aebd124so12535276ybb.11 for ; Mon, 21 Nov 2022 18:16:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=sXC86U5/hdvmtqoI3CrBqri1fBKx6hffM6aKsOurzIQ=; b=nviEqECcUVQGFZCSjYX27H4M5ju7f+JT7lEyRab0UT5tVqqZE8Nr3TDs0EYlPUSSRs IgVAP+mJQk0CFNsd0y2gZllcV9H5NC6rztxOhHtbo2yj20wWri1irhqXA0aEpof27HPJ /2mVbS/N1xkIu4emdYQWAs34awPkiLIz1dX5QmHedJTpqS2auwDSAwRDXZ5kV4uw80bW lcrV3OSql4Gqyn+NM/cCyEw0DYv9BxSFlBZW3oVxq4MqyDQanhisbwCzf2ekYZQaJr9m slJntZYFnJ2tls7oCuJKp6UhuZbW7W7/FRkg2LQaPjFYBH1ZHSpGhD7doqxaX1FJJpKn tjww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=sXC86U5/hdvmtqoI3CrBqri1fBKx6hffM6aKsOurzIQ=; b=l3t2YHRhTIB6UBXYsOrXiVJPvcbE533uCyK0dNu7DKOBC0EMddXbtJXiTK+rmG/VIu T6d59hr08U5Ls0OBtNYw6vpHFeGJstRKtPu0jmLh+Eln4bfttXALHH/rtoKqZJic9VjN Ujv79EIKsQWmqC8YgnDms3KPECYpHkvp62vSk4OgPKaj2p0cvc4LJOJ/jwvPYyurqxMO qdK2kt7IZTlG+jqXE7Ewci5KnA+c9j7+70gPWFhxxZP6OYtsEqb6WXVsD/49FkH9Dqjl 5cuhmiLdYLbhzk0ZMCPEN5KWsqIGnporprRyQYy07CBJwHWSAPNLxOWGCEI17W92lXpR 0gXw== X-Gm-Message-State: ANoB5pmvsX7jutiYPsCigyi07DKxc3XrhxBYLJGBu8DMFPRhCA/MYEQ7 osGxejHfh8GHY7YHiT/T1tLIbuz4S6U= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a05:6902:729:b0:6dc:c7e9:17e0 with SMTP id l9-20020a056902072900b006dcc7e917e0mr5539541ybt.411.1669083385614; Mon, 21 Nov 2022 18:16:25 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:29 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-15-drosen@google.com> Subject: [RFC PATCH v2 14/21] fuse-bpf: support FUSE_READDIR From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750161016177558373?= X-GMAIL-MSGID: =?utf-8?q?1750161016177558373?= Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 185 ++++++++++++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 6 ++ fs/fuse/readdir.c | 5 ++ include/uapi/linux/fuse.h | 6 ++ 4 files changed, 202 insertions(+) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 425815d7f5dc..a15b5c107cfe 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -1597,6 +1597,191 @@ int fuse_bpf_unlink(int *out, struct inode *dir, struct dentry *entry) dir, entry); } +struct fuse_read_io { + struct fuse_read_in fri; + struct fuse_read_out fro; +}; + +static int fuse_readdir_initialize_in(struct fuse_args *fa, struct fuse_read_io *frio, + struct file *file, struct dir_context *ctx, + bool *force_again, bool *allow_force, bool is_continued) +{ + struct fuse_file *ff = file->private_data; + + *fa = (struct fuse_args) { + .nodeid = ff->nodeid, + .opcode = FUSE_READDIR, + .in_numargs = 1, + .in_args[0] = (struct fuse_in_arg) { + .size = sizeof(frio->fri), + .value = &frio->fri, + }, + }; + + frio->fri = (struct fuse_read_in) { + .fh = ff->fh, + .offset = ctx->pos, + .size = PAGE_SIZE, + }; + + *force_again = false; + *allow_force = true; + return 0; +} + +static int fuse_readdir_initialize_out(struct fuse_args *fa, struct fuse_read_io *frio, + struct file *file, struct dir_context *ctx, + bool *force_again, bool *allow_force, bool is_continued) +{ + u8 *page = (u8 *)__get_free_page(GFP_KERNEL); + + if (!page) + return -ENOMEM; + + fa->out_argvar = true; + fa->out_numargs = 2; + fa->out_args[0] = (struct fuse_arg) { + .size = sizeof(frio->fro), + .value = &frio->fro, + }; + fa->out_args[1] = (struct fuse_arg) { + .size = PAGE_SIZE, + .value = page, + }; + frio->fro = (struct fuse_read_out) { + .again = 0, + .offset = 0, + }; + + return 0; +} + +struct extfuse_ctx { + struct dir_context ctx; + u8 *addr; + size_t offset; +}; + +static bool filldir(struct dir_context *ctx, const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct extfuse_ctx *ec = container_of(ctx, struct extfuse_ctx, ctx); + struct fuse_dirent *fd = (struct fuse_dirent *)(ec->addr + ec->offset); + + if (ec->offset + sizeof(struct fuse_dirent) + namelen > PAGE_SIZE) + return false; + + *fd = (struct fuse_dirent) { + .ino = ino, + .off = offset, + .namelen = namelen, + .type = d_type, + }; + + memcpy(fd->name, name, namelen); + ec->offset += FUSE_DIRENT_SIZE(fd); + + return true; +} + +static int parse_dirfile(char *buf, size_t nbytes, struct dir_context *ctx) +{ + while (nbytes >= FUSE_NAME_OFFSET) { + struct fuse_dirent *dirent = (struct fuse_dirent *) buf; + size_t reclen = FUSE_DIRENT_SIZE(dirent); + + if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) + return -EIO; + if (reclen > nbytes) + break; + if (memchr(dirent->name, '/', dirent->namelen) != NULL) + return -EIO; + + ctx->pos = dirent->off; + if (!dir_emit(ctx, dirent->name, dirent->namelen, dirent->ino, + dirent->type)) + break; + + buf += reclen; + nbytes -= reclen; + } + + return 0; +} + + +static int fuse_readdir_backing(struct fuse_args *fa, int *out, + struct file *file, struct dir_context *ctx, + bool *force_again, bool *allow_force, bool is_continued) +{ + struct fuse_file *ff = file->private_data; + struct file *backing_dir = ff->backing_file; + struct fuse_read_out *fro = fa->out_args[0].value; + struct extfuse_ctx ec; + + ec = (struct extfuse_ctx) { + .ctx.actor = filldir, + .ctx.pos = ctx->pos, + .addr = fa->out_args[1].value, + }; + + if (!ec.addr) + return -ENOMEM; + + if (!is_continued) + backing_dir->f_pos = file->f_pos; + + *out = iterate_dir(backing_dir, &ec.ctx); + if (ec.offset == 0) + *allow_force = false; + fa->out_args[1].size = ec.offset; + + fro->offset = ec.ctx.pos; + fro->again = false; + + return *out; +} + +static int fuse_readdir_finalize(struct fuse_args *fa, int *out, + struct file *file, struct dir_context *ctx, + bool *force_again, bool *allow_force, bool is_continued) +{ + struct fuse_read_out *fro = fa->out_args[0].value; + struct fuse_file *ff = file->private_data; + struct file *backing_dir = ff->backing_file; + + *out = parse_dirfile(fa->out_args[1].value, fa->out_args[1].size, ctx); + *force_again = !!fro->again; + if (*force_again && !*allow_force) + *out = -EINVAL; + + ctx->pos = fro->offset; + backing_dir->f_pos = fro->offset; + + free_page((unsigned long)fa->out_args[1].value); + return *out; +} + +int fuse_bpf_readdir(int *out, struct inode *inode, struct file *file, struct dir_context *ctx) +{ + int ret; + bool allow_force; + bool force_again = false; + bool is_continued = false; + +again: + ret = fuse_bpf_backing(inode, struct fuse_read_io, out, + fuse_readdir_initialize_in, fuse_readdir_initialize_out, + fuse_readdir_backing, fuse_readdir_finalize, + file, ctx, &force_again, &allow_force, is_continued); + if (force_again && *out >= 0) { + is_continued = true; + goto again; + } + + return ret; +} + static int fuse_access_initialize_in(struct fuse_args *fa, struct fuse_access_in *fai, struct inode *inode, int mask) { diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 25cedaa9014c..0ea3fb74caab 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1414,6 +1414,7 @@ int fuse_bpf_file_read_iter(ssize_t *out, struct inode *inode, struct kiocb *ioc int fuse_bpf_file_write_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *from); int fuse_bpf_file_fallocate(int *out, struct inode *inode, struct file *file, int mode, loff_t offset, loff_t length); int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct dentry *entry, unsigned int flags); +int fuse_bpf_readdir(int *out, struct inode *inode, struct file *file, struct dir_context *ctx); int fuse_bpf_access(int *out, struct inode *inode, int mask); #else @@ -1484,6 +1485,11 @@ static inline int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct return 0; } +static inline int fuse_bpf_readdir(int *out, struct inode *inode, struct file *file, struct dir_context *ctx) +{ + return 0; +} + static inline int fuse_bpf_access(int *out, struct inode *inode, int mask) { return 0; diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index e8deaacf1832..f32105679057 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -20,6 +20,8 @@ static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx) if (!fc->do_readdirplus) return false; + if (fi->nodeid == 0) + return false; if (!fc->readdirplus_auto) return true; if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state)) @@ -582,6 +584,9 @@ int fuse_readdir(struct file *file, struct dir_context *ctx) if (fuse_is_bad(inode)) return -EIO; + if (fuse_bpf_readdir(&err, inode, file, ctx)) + return err; + mutex_lock(&ff->readdir.lock); err = UNCACHED; diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index e49e5a8e044c..8c13483f240e 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -709,6 +709,12 @@ struct fuse_read_in { uint32_t padding; }; +struct fuse_read_out { + uint64_t offset; + uint32_t again; + uint32_t padding; +}; + #define FUSE_COMPAT_WRITE_IN_SIZE 24 struct fuse_write_in { From patchwork Tue Nov 22 02:15:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24133 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1957299wrr; Mon, 21 Nov 2022 18:20:20 -0800 (PST) X-Google-Smtp-Source: AA0mqf6wlSn4CbCKREEmzAFgbcH+aeviqt9sUGfC7DVwbHzEAoia0iWbsD7aViZouri7AUg+++aT X-Received: by 2002:a63:c48:0:b0:470:1186:de85 with SMTP id 8-20020a630c48000000b004701186de85mr6550000pgm.609.1669083620178; Mon, 21 Nov 2022 18:20:20 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083620; cv=none; d=google.com; s=arc-20160816; b=mWLD856n1hdsyTUDkCRNyZECGPKtgrRgtNR42CwrYyHtSbH2iPvbZ3YP1XlMMeF70O JpLTkDzPpOY8Tpjix+bhjZFXStqZqDsunobQ9pDMGnFGuZjUXNM77mfT/7fSr74TVtaW OV+mHJJ4fR1m+Jtk7eicl9T5scJpD90+1jXu30ChbFUbOZv5DYE8Wv+zcz2ATM3EhkLG f2wclnYCQrS2/sdcuQgYhiBeQIJ0LKYxH/2Tp/wOERlvV5izH/jSiebMqJbTK+LxMmDx 73TXZXFM8kxHOuaIhGbDeUoH3duxgb7eRBedwvT3duCoaof13IV8/4Mm0MCQr1gtPfup xZXQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=+7lnONjHdi886Ig9Mqdu5pD+AjkqXhnQE6noiyOFdJA=; b=bl0UKeS8LlxGcRKkkNe6Mpm/9a+g7zSXXK/ASPEnu+52SwJZp0q/uy1RqgTL8Basli X5UqXFtnN7rJqARTKMFdOOQgB1vZryb7hM+vqpyqBz93s4h/jNpQgB/kxhF4tofbOpt3 aNsNhfS4P4QRYly3NgKN+MpSyaUx4SlZ4REsXW0JWOx12/CjxziuSodw0MkU+hu9fD/A cl4SWeXLGoffBTBjk8beHloUI3kKK2b6gV+lhU2H/Mw2bzkmZ9QGEY/sUztZrhU7WDXT 6evH1+uwWxKoSBPlvGeR8fCOj11G6jK6/jCn6V22gwue3WxgT+ChkPJjipjaLUYfd+FN BZPg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=lrtwBrtX; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id px17-20020a17090b271100b002129a8204d2si12421993pjb.44.2022.11.21.18.20.06; Mon, 21 Nov 2022 18:20:20 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=lrtwBrtX; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231735AbiKVCTV (ORCPT + 99 others); Mon, 21 Nov 2022 21:19:21 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42600 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232542AbiKVCR5 (ORCPT ); Mon, 21 Nov 2022 21:17:57 -0500 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7E5BBE871A for ; Mon, 21 Nov 2022 18:16:29 -0800 (PST) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-391bd92f931so121225087b3.22 for ; Mon, 21 Nov 2022 18:16:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=+7lnONjHdi886Ig9Mqdu5pD+AjkqXhnQE6noiyOFdJA=; b=lrtwBrtXPPkYidFgin2J04BdRiJSMvbPz4VqiHsVwzBDAG9kDpeEPdifXAxmHw9zI0 NKIkiPinjAMKlnqhSyv2sygr81lgE3nvzHVOn8k8x8uiH8dfmKseRpx7dw9KRkf7Hg2c lXbCB4QF3JdaNV7G03QBFnoniUskfNIfqqijZfJCWFEjW/44GdV8ysqFYt+GCyXJfN6g r+1L/JiP9nTm8+tZ0g8k577RNDvLHeONZM4F+pfQhpVob28c+olV32piW3TxFwIYXYLH 57nmypvY34lk73vshQ6JxZ9nW5b8Rqizz3+kFsf9bb7liLpnIuarGf6lY2UXRbNq1ZoX ucUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=+7lnONjHdi886Ig9Mqdu5pD+AjkqXhnQE6noiyOFdJA=; b=X88mwxpNMGUOJOvJ9+0pzRBO/KP+Lh+AjgyRvbmyMH5zXtRdL+ks3k65byak3KfAtS +SjZP1Eq2XuHlDZ5cwoLaVDG5r/1YHZ8hmB4lnrEQbLyjyMSontCdpOuCEQoqnmEhvkF ucf4ZRILVcrWYL+bNegZ0ZiB20irqz/lSCQixotUUsTrk9fkusWLJPIdA6TpidpeIf99 DwrZiXlJubWgILpyi+IM+byhQHgMnaXFhwZma+w+Xi2OWBQ3O8LM0W/FA2PtqnvefCKt 4w5M1HWhNzS/MKLnDFnSfP5LLFyXfyp2iPCdI/ODcHBQbGDf35qUvPJ67AGZmj1t1HI1 LwkQ== X-Gm-Message-State: ACrzQf0FEwgY0cCF5wxNQFkf2f1w2k4sNlpzytBnAIDTnETcXFA2J40S KHw7LJWIXZ4tb5ogqegWiHfSUCQPGGU= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a25:1181:0:b0:6bf:bd96:2b01 with SMTP id 123-20020a251181000000b006bfbd962b01mr63735903ybr.17.1669083388163; Mon, 21 Nov 2022 18:16:28 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:30 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-16-drosen@google.com> Subject: [RFC PATCH v2 15/21] fuse-bpf: Add support for sync operations From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750161025800940760?= X-GMAIL-MSGID: =?utf-8?q?1750161025800940760?= Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/dir.c | 3 + fs/fuse/file.c | 6 ++ fs/fuse/fuse_i.h | 18 ++++++ 4 files changed, 169 insertions(+) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index a15b5c107cfe..719292e03b18 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -652,6 +652,58 @@ int fuse_bpf_releasedir(int *out, struct inode *inode, struct file *file) fuse_release_backing, fuse_release_finalize, inode, file); } +static int fuse_flush_initialize_in(struct fuse_args *fa, struct fuse_flush_in *ffi, + struct file *file, fl_owner_t id) +{ + struct fuse_file *fuse_file = file->private_data; + + *ffi = (struct fuse_flush_in) { + .fh = fuse_file->fh, + }; + + *fa = (struct fuse_args) { + .nodeid = get_node_id(file->f_inode), + .opcode = FUSE_FLUSH, + .in_numargs = 1, + .in_args[0].size = sizeof(*ffi), + .in_args[0].value = ffi, + .force = true, + }; + + return 0; +} + +static int fuse_flush_initialize_out(struct fuse_args *fa, struct fuse_flush_in *ffi, + struct file *file, fl_owner_t id) +{ + return 0; +} + +static int fuse_flush_backing(struct fuse_args *fa, int *out, struct file *file, fl_owner_t id) +{ + struct fuse_file *fuse_file = file->private_data; + struct file *backing_file = fuse_file->backing_file; + + *out = 0; + if (backing_file->f_op->flush) + *out = backing_file->f_op->flush(backing_file, id); + return *out; +} + +static int fuse_flush_finalize(struct fuse_args *fa, int *out, struct file *file, fl_owner_t id) +{ + return 0; +} + +int fuse_bpf_flush(int *out, struct inode *inode, struct file *file, fl_owner_t id) +{ + return fuse_bpf_backing(inode, struct fuse_flush_in, out, + fuse_flush_initialize_in, fuse_flush_initialize_out, + fuse_flush_backing, + fuse_flush_finalize, + file, id); +} + struct fuse_lseek_io { struct fuse_lseek_in fli; struct fuse_lseek_out flo; @@ -740,6 +792,96 @@ int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t o file, offset, whence); } +static int fuse_fsync_initialize_in(struct fuse_args *fa, struct fuse_fsync_in *ffi, + struct file *file, loff_t start, loff_t end, int datasync) +{ + struct fuse_file *fuse_file = file->private_data; + + *ffi = (struct fuse_fsync_in) { + .fh = fuse_file->fh, + .fsync_flags = datasync ? FUSE_FSYNC_FDATASYNC : 0, + }; + + *fa = (struct fuse_args) { + .nodeid = get_fuse_inode(file->f_inode)->nodeid, + .opcode = FUSE_FSYNC, + .in_numargs = 1, + .in_args[0].size = sizeof(*ffi), + .in_args[0].value = ffi, + .force = true, + }; + + return 0; +} + +static int fuse_fsync_initialize_out(struct fuse_args *fa, struct fuse_fsync_in *ffi, + struct file *file, loff_t start, loff_t end, int datasync) +{ + return 0; +} + +static int fuse_fsync_backing(struct fuse_args *fa, int *out, + struct file *file, loff_t start, loff_t end, int datasync) +{ + struct fuse_file *fuse_file = file->private_data; + struct file *backing_file = fuse_file->backing_file; + const struct fuse_fsync_in *ffi = fa->in_args[0].value; + int new_datasync = (ffi->fsync_flags & FUSE_FSYNC_FDATASYNC) ? 1 : 0; + + *out = vfs_fsync(backing_file, new_datasync); + return 0; +} + +static int fuse_fsync_finalize(struct fuse_args *fa, int *out, + struct file *file, loff_t start, loff_t end, int datasync) +{ + return 0; +} + +int fuse_bpf_fsync(int *out, struct inode *inode, struct file *file, loff_t start, loff_t end, int datasync) +{ + return fuse_bpf_backing(inode, struct fuse_fsync_in, out, + fuse_fsync_initialize_in, fuse_fsync_initialize_out, + fuse_fsync_backing, fuse_fsync_finalize, + file, start, end, datasync); +} + +static int fuse_dir_fsync_initialize_in(struct fuse_args *fa, struct fuse_fsync_in *ffi, + struct file *file, loff_t start, loff_t end, int datasync) +{ + struct fuse_file *fuse_file = file->private_data; + + *ffi = (struct fuse_fsync_in) { + .fh = fuse_file->fh, + .fsync_flags = datasync ? FUSE_FSYNC_FDATASYNC : 0, + }; + + *fa = (struct fuse_args) { + .nodeid = get_fuse_inode(file->f_inode)->nodeid, + .opcode = FUSE_FSYNCDIR, + .in_numargs = 1, + .in_args[0].size = sizeof(*ffi), + .in_args[0].value = ffi, + .force = true, + }; + + return 0; +} + +static int fuse_dir_fsync_initialize_out(struct fuse_args *fa, struct fuse_fsync_in *ffi, + struct file *file, loff_t start, loff_t end, int datasync) +{ + return 0; +} + +int fuse_bpf_dir_fsync(int *out, struct inode *inode, struct file *file, loff_t start, loff_t end, int datasync) +{ + return fuse_bpf_backing(inode, struct fuse_fsync_in, out, + fuse_dir_fsync_initialize_in, fuse_dir_fsync_initialize_out, + fuse_fsync_backing, fuse_fsync_finalize, + file, start, end, datasync); +} + static inline void fuse_bpf_aio_put(struct fuse_bpf_aio_req *aio_req) { if (refcount_dec_and_test(&aio_req->ref)) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 729a0348fa01..55ed3fb9d4a3 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1591,6 +1591,9 @@ static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end, if (fuse_is_bad(inode)) return -EIO; + if (fuse_bpf_dir_fsync(&err, inode, file, start, end, datasync)) + return err; + if (fc->no_fsyncdir) return 0; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 59f3d85106d3..fa9ee2740a42 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -502,6 +502,9 @@ static int fuse_flush(struct file *file, fl_owner_t id) if (fuse_is_bad(inode)) return -EIO; + if (fuse_bpf_flush(&err, file_inode(file), file, id)) + return err; + if (ff->open_flags & FOPEN_NOFLUSH && !fm->fc->writeback_cache) return 0; @@ -577,6 +580,9 @@ static int fuse_fsync(struct file *file, loff_t start, loff_t end, if (fuse_is_bad(inode)) return -EIO; + if (fuse_bpf_fsync(&err, inode, file, start, end, datasync)) + return err; + inode_lock(inode); /* diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 0ea3fb74caab..cb087364e9bb 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1409,7 +1409,10 @@ int fuse_bpf_rmdir(int *out, struct inode *dir, struct dentry *entry); int fuse_bpf_unlink(int *out, struct inode *dir, struct dentry *entry); int fuse_bpf_release(int *out, struct inode *inode, struct file *file); int fuse_bpf_releasedir(int *out, struct inode *inode, struct file *file); +int fuse_bpf_flush(int *out, struct inode *inode, struct file *file, fl_owner_t id); int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t offset, int whence); +int fuse_bpf_fsync(int *out, struct inode *inode, struct file *file, loff_t start, loff_t end, int datasync); +int fuse_bpf_dir_fsync(int *out, struct inode *inode, struct file *file, loff_t start, loff_t end, int datasync); int fuse_bpf_file_read_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *to); int fuse_bpf_file_write_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *from); int fuse_bpf_file_fallocate(int *out, struct inode *inode, struct file *file, int mode, loff_t offset, loff_t length); @@ -1460,11 +1463,26 @@ static inline int fuse_bpf_releasedir(int *out, struct inode *inode, struct file return 0; } +static inline int fuse_bpf_flush(int *out, struct inode *inode, struct file *file, fl_owner_t id) +{ + return 0; +} + static inline int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t offset, int whence) { return 0; } +static inline int fuse_bpf_fsync(int *out, struct inode *inode, struct file *file, loff_t start, loff_t end, int datasync) +{ + return 0; +} + +static inline int fuse_bpf_dir_fsync(int *out, struct inode *inode, struct file *file, loff_t start, loff_t end, int datasync) +{ + return 0; +} + static inline int fuse_bpf_file_read_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *to) { return 0; From patchwork Tue Nov 22 02:15:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24134 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1957310wrr; Mon, 21 Nov 2022 18:20:21 -0800 (PST) X-Google-Smtp-Source: AA0mqf57uSfRYliV98Ko3tlME8tii6tBB/TdwON8ZCXGnAlC6swn9IIigkntpR0wCsCj1pUfdpoQ X-Received: by 2002:a17:902:f155:b0:189:33cd:648 with SMTP id d21-20020a170902f15500b0018933cd0648mr887816plb.134.1669083621241; Mon, 21 Nov 2022 18:20:21 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083621; cv=none; d=google.com; s=arc-20160816; b=AbcpeGbsH1+6D7GMYicT36znR5K6Ydcq6EOjypuwFVFNn5WdXf4uoJejsX2KCdjBd1 m+uTIpH2vXec5AmxdIwIaFbtMA9Y7EKJoizN3v12145LBkygik6ROA3K1Prxs4KAXcSn lxRBjTcKWdn9bNd4IDzBhNWNKiJhZHqm/pXgiqrWJAt9qnZ/kjNzPGdnJ4CZ+Zhxcfcp RQTGy9xWWCe+Q0Vhmw0hmx4R7Oy2RiCl2HbhZhCkxRlihBtrqrQChxbcsfFBScbIl+YC Ngljdn6v91g9dQEkY8unRE8EQc6oAr7d8rTXSk0SJnHUmo1TdHxMqT5A2uDbouHOv6+A ybBg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=3ZCLjcJ4R3eU9/lQk3QpcBgc0zLovUHl4lozHOuR1ro=; b=vLjIEiEeMZkYX1ZW9sniTJLTMNQthgWvL7evg+uBXZ1EaqVWgtvNikI+HO19C54nBP E3y54mkOSpyJx325gLqqnxT/8OZErBoiefTc0MY4uYqGiRk/SmF6Mgl/bOAGYsv+k3rq bo+DKrTjZXPvKhJ4DuH2jIK1/9o7lXHbZzdXcJCj7Ek9QjylUqr2/XCW6CvJx5VZR1gJ ebj4/I5PMciIU84h5Bv5tSRAZ6EUbmKsIBTwCBVwluoWM/rMZc7R3tg7lo9UKn8kDFQS TlYgnKIPkDDZt6duBC6N1DpnLHDcI60MFn9IThvcuY7x5K0L7LxPYVBIfJeKiq1/0d3b 2WAg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=Onag8LXK; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id k9-20020a170902d58900b0017f7faef235si13568285plh.148.2022.11.21.18.20.07; Mon, 21 Nov 2022 18:20:21 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=Onag8LXK; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231536AbiKVCT0 (ORCPT + 99 others); Mon, 21 Nov 2022 21:19:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43526 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232577AbiKVCSF (ORCPT ); Mon, 21 Nov 2022 21:18:05 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6AB3CE6EDA for ; Mon, 21 Nov 2022 18:16:31 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id e198-20020a2537cf000000b006e699f20c51so12384308yba.7 for ; Mon, 21 Nov 2022 18:16:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=3ZCLjcJ4R3eU9/lQk3QpcBgc0zLovUHl4lozHOuR1ro=; b=Onag8LXKUEYkNQDXASyE2XfkV9WriZxyqN3f46RXUNf+xJTp5wc9/Ps0FZY4IkN/So AbmMbh0t8c0JnZvIieoFSE1EBshobKjZxKzNu97r2WkhJB1X/Ia6lpQBhufU7YzfmkAv YDjy4vUmCdmgGRkRHuzn1To8UaEOwRZ6WUtH7P8oqZpARoArEyNJrPPn+4HH4pmP+F1c d+CZeBxp97d6qmi6opkagbdWjO+WAhv/lud28ORlHNp68nkXZc+2xBT0Tpc9iMS6lhWa 0NWCnjXNlGUVxaYC99FCDe6hQ6b17FEytdtdSgwGyJeul8NCakUZyFsIDAsf540osdoG 0f+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=3ZCLjcJ4R3eU9/lQk3QpcBgc0zLovUHl4lozHOuR1ro=; b=i93Sgju52RGoGjXUvJBvAhePIdSATxvcxGW3DD10oueRzZPhMnIB9Xr+yxLqq3Xk7P WwndB/GzfNlPrbTle2LJOpmvPrKyRgBnqzNPD1/8XQF8FG7bciUB4Z0Ew5qce6ronwgE ZpE6VIK1tP3RFqSR7z9V+NNZUFxI6vjUSTRibeMt5alGYbPtPUiMnXBkH6yMLKcFIA/p I2AEj93B/KqPQw6nh9IubKaQHPrQwWt/Q4zjpJmhxfKYTXdHD8+oxJTIx7uLzMvNlWnG g9P3ElbCnknZW28yycKcePTDyYTMCYTAi7x5p7ooIE7Uv+LT/+K6eD4hv/3X6heJNy2/ deeQ== X-Gm-Message-State: ANoB5plKSH5q+FZpmLQi3j+gIRjnDlPLg6l9qAk30r7Gi0JnX0EA1qSh PXcHh6XQSa4WWCEW+WslLP5bIH6P3yU= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a0d:ebcd:0:b0:39b:9c96:b6b7 with SMTP id u196-20020a0debcd000000b0039b9c96b6b7mr3ywe.450.1669083390850; Mon, 21 Nov 2022 18:16:30 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:31 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-17-drosen@google.com> Subject: [RFC PATCH v2 16/21] fuse-bpf: Add Rename support From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750161027296335431?= X-GMAIL-MSGID: =?utf-8?q?1750161027296335431?= Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/dir.c | 7 ++ fs/fuse/fuse_i.h | 18 ++++ 3 files changed, 235 insertions(+) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 719292e03b18..333181d6ad73 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -1677,6 +1677,216 @@ int fuse_bpf_rmdir(int *out, struct inode *dir, struct dentry *entry) dir, entry); } +static int fuse_rename_backing_common(struct inode *olddir, + struct dentry *oldent, + struct inode *newdir, + struct dentry *newent, unsigned int flags) +{ + int err = 0; + struct path old_backing_path; + struct path new_backing_path; + struct dentry *old_backing_dir_dentry; + struct dentry *old_backing_dentry; + struct dentry *new_backing_dir_dentry; + struct dentry *new_backing_dentry; + struct dentry *trap = NULL; + struct inode *target_inode; + struct renamedata rd; + + //TODO Actually deal with changing anything that isn't a flag + get_fuse_backing_path(oldent, &old_backing_path); + if (!old_backing_path.dentry) + return -EBADF; + get_fuse_backing_path(newent, &new_backing_path); + if (!new_backing_path.dentry) { + /* + * TODO A file being moved from a backing path to another + * backing path which is not yet instrumented with FUSE-BPF. + * This may be slow and should be substituted with something + * more clever. + */ + err = -EXDEV; + goto put_old_path; + } + if (new_backing_path.mnt != old_backing_path.mnt) { + err = -EXDEV; + goto put_new_path; + } + old_backing_dentry = old_backing_path.dentry; + new_backing_dentry = new_backing_path.dentry; + old_backing_dir_dentry = dget_parent(old_backing_dentry); + new_backing_dir_dentry = dget_parent(new_backing_dentry); + target_inode = d_inode(newent); + + trap = lock_rename(old_backing_dir_dentry, new_backing_dir_dentry); + if (trap == old_backing_dentry) { + err = -EINVAL; + goto put_parents; + } + if (trap == new_backing_dentry) { + err = -ENOTEMPTY; + goto put_parents; + } + + rd = (struct renamedata) { + .old_mnt_userns = &init_user_ns, + .old_dir = d_inode(old_backing_dir_dentry), + .old_dentry = old_backing_dentry, + .new_mnt_userns = &init_user_ns, + .new_dir = d_inode(new_backing_dir_dentry), + .new_dentry = new_backing_dentry, + .flags = flags, + }; + err = vfs_rename(&rd); + if (err) + goto unlock; + if (target_inode) + fsstack_copy_attr_all(target_inode, + get_fuse_inode(target_inode)->backing_inode); + fsstack_copy_attr_all(d_inode(oldent), d_inode(old_backing_dentry)); +unlock: + unlock_rename(old_backing_dir_dentry, new_backing_dir_dentry); +put_parents: + dput(new_backing_dir_dentry); + dput(old_backing_dir_dentry); +put_new_path: + path_put(&new_backing_path); +put_old_path: + path_put(&old_backing_path); + return err; +} + +static int fuse_rename2_initialize_in(struct fuse_args *fa, struct fuse_rename2_in *fri, + struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent, + unsigned int flags) +{ + *fri = (struct fuse_rename2_in) { + .newdir = get_node_id(newdir), + .flags = flags, + }; + *fa = (struct fuse_args) { + .nodeid = get_node_id(olddir), + .opcode = FUSE_RENAME2, + .in_numargs = 3, + .in_args[0] = (struct fuse_in_arg) { + .size = sizeof(*fri), + .value = fri, + }, + .in_args[1] = (struct fuse_in_arg) { + .size = oldent->d_name.len + 1, + .value = (void *) oldent->d_name.name, + }, + .in_args[2] = (struct fuse_in_arg) { + .size = newent->d_name.len + 1, + .value = (void *) newent->d_name.name, + }, + }; + + return 0; +} + +static int fuse_rename2_initialize_out(struct fuse_args *fa, struct fuse_rename2_in *fri, + struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent, + unsigned int flags) +{ + return 0; +} + +static int fuse_rename2_backing(struct fuse_args *fa, int *out, + struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent, + unsigned int flags) +{ + const struct fuse_rename2_in *fri = fa->in_args[0].value; + + /* TODO: deal with changing dirs/ents */ + *out = fuse_rename_backing_common(olddir, oldent, newdir, newent, + fri->flags); + return *out; +} + +static int fuse_rename2_finalize(struct fuse_args *fa, int *out, + struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent, + unsigned int flags) +{ + return 0; +} + +int fuse_bpf_rename2(int *out, struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent, + unsigned int flags) +{ + return fuse_bpf_backing(olddir, struct fuse_rename2_in, out, + fuse_rename2_initialize_in, + fuse_rename2_initialize_out, fuse_rename2_backing, + fuse_rename2_finalize, + olddir, oldent, newdir, newent, flags); +} + +static int fuse_rename_initialize_in(struct fuse_args *fa, struct fuse_rename_in *fri, + struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent) +{ + *fri = (struct fuse_rename_in) { + .newdir = get_node_id(newdir), + }; + *fa = (struct fuse_args) { + .nodeid = get_node_id(olddir), + .opcode = FUSE_RENAME, + .in_numargs = 3, + .in_args[0] = (struct fuse_in_arg) { + .size = sizeof(*fri), + .value = fri, + }, + .in_args[1] = (struct fuse_in_arg) { + .size = oldent->d_name.len + 1, + .value = (void *) oldent->d_name.name, + }, + .in_args[2] = (struct fuse_in_arg) { + .size = newent->d_name.len + 1, + .value = (void *) newent->d_name.name, + }, + }; + + return 0; +} + +static int fuse_rename_initialize_out(struct fuse_args *fa, struct fuse_rename_in *fri, + struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent) +{ + return 0; +} + +static int fuse_rename_backing(struct fuse_args *fa, int *out, + struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent) +{ + /* TODO: deal with changing dirs/ents */ + *out = fuse_rename_backing_common(olddir, oldent, newdir, newent, 0); + return *out; +} + +static int fuse_rename_finalize(struct fuse_args *fa, int *out, + struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent) +{ + return 0; +} + +int fuse_bpf_rename(int *out, struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent) +{ + return fuse_bpf_backing(olddir, struct fuse_rename_in, out, + fuse_rename_initialize_in, + fuse_rename_initialize_out, fuse_rename_backing, + fuse_rename_finalize, + olddir, oldent, newdir, newent); +} + static int fuse_unlink_initialize_in(struct fuse_args *fa, struct fuse_unused_io *unused, struct inode *dir, struct dentry *entry) { diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 55ed3fb9d4a3..6ad0eb92de3b 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1116,6 +1116,10 @@ static int fuse_rename2(struct user_namespace *mnt_userns, struct inode *olddir, return -EINVAL; if (flags) { + if (fuse_bpf_rename2(&err, olddir, oldent, newdir, newent, flags)) + return err; + + /* TODO: how should this go with bpfs involved? */ if (fc->no_rename2 || fc->minor < 23) return -EINVAL; @@ -1127,6 +1131,9 @@ static int fuse_rename2(struct user_namespace *mnt_userns, struct inode *olddir, err = -EINVAL; } } else { + if (fuse_bpf_rename(&err, olddir, oldent, newdir, newent)) + return err; + err = fuse_rename_common(olddir, oldent, newdir, newent, 0, FUSE_RENAME, sizeof(struct fuse_rename_in)); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index cb087364e9bb..3338ac84d083 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1406,6 +1406,11 @@ int fuse_bpf_create_open(int *out, struct inode *dir, struct dentry *entry, int fuse_bpf_mknod(int *out, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev); int fuse_bpf_mkdir(int *out, struct inode *dir, struct dentry *entry, umode_t mode); int fuse_bpf_rmdir(int *out, struct inode *dir, struct dentry *entry); +int fuse_bpf_rename2(int *out, struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent, + unsigned int flags); +int fuse_bpf_rename(int *out, struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent); int fuse_bpf_unlink(int *out, struct inode *dir, struct dentry *entry); int fuse_bpf_release(int *out, struct inode *inode, struct file *file); int fuse_bpf_releasedir(int *out, struct inode *inode, struct file *file); @@ -1448,6 +1453,19 @@ static inline int fuse_bpf_rmdir(int *out, struct inode *dir, struct dentry *ent return 0; } +static inline int fuse_bpf_rename2(int *out, struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent, + unsigned int flags) +{ + return 0; +} + +static inline int fuse_bpf_rename(int *out, struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent) +{ + return 0; +} + static inline int fuse_bpf_unlink(int *out, struct inode *dir, struct dentry *entry) { return 0; From patchwork Tue Nov 22 02:15:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24138 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1957600wrr; Mon, 21 Nov 2022 18:21:06 -0800 (PST) X-Google-Smtp-Source: AA0mqf486ZQCLLZm8pqv245YnLUpzvVy/hhcUjhYT1EEYeqFhXbTzbOTEEMMNc3B+HBNS02OU41c X-Received: by 2002:a17:90b:19c3:b0:212:de1a:355b with SMTP id nm3-20020a17090b19c300b00212de1a355bmr23705371pjb.1.1669083666317; Mon, 21 Nov 2022 18:21:06 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083666; cv=none; d=google.com; s=arc-20160816; b=RkXYqu/CntYexbENIq/NSJWIxSIKRm3Y7e4uTg8V5gFhMxtkyi5Hf5uhdaFRzwOk0K xmaFxkrCh36bS5y1nYZj3qEHEEpk3+V/PvVnBgIyPAMK9Fo1PUZh85v08NTBKlp4ym8S PF+h73ULlq0WlurZljc8PZFFYDaCEc9H/ANSoRNItQbj8F5bpMoSCAZnTS2dFAvrppme emyy7JII0JUxNT5uW3GmZQVs0+8KqNaMQYiAVXYWhg0L58Bfa2PWS88njIUxh0EuFb47 zZkdw6Rly/NZas6zg38z2zm7FkKBzmMmYqP5IvyGGlzgJIARdcRa13Sfz/ug9pv4A7Ly FCSw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=vK6IEU0rl0A24X4GIdUEvjRzL9edAkzNEa8n9WiUMOU=; b=dPdhrG2FQ2tLmDmmw6MUva+gj2tV6ehzwKhbX2Fzj5NWn7dryzu48PcNcZ16UO2xj7 VVyNtwRkVDRkeJTjx8ZDzugApO35ms02Kchw5SSPjIr7bYxm4nDM58LqIv68mx6D2M16 HEI17ht8o9hYJfUuq9j5H/LrqQoJJCZPueKWbhFIWc7uMA/hASO45tLm980qsXMKrD1v iNQI1w7wPxrRveRN2EBYn2KhZy2Y8M3mJ4uh614zLnYfosAp1Pkg6cYUQXbbqDNFPP+W Bps/o/y4F1vPRHN/hF6kYEk3MeVYkLQkE47Udd2hg2/sGwykiqxRCFaqhqLs/gGITSIO b/Lw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=nMVdkL0X; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id a63-20020a639042000000b004772ac75588si11167259pge.161.2022.11.21.18.20.53; Mon, 21 Nov 2022 18:21:06 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=nMVdkL0X; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231879AbiKVCUB (ORCPT + 99 others); Mon, 21 Nov 2022 21:20:01 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42654 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232632AbiKVCSW (ORCPT ); Mon, 21 Nov 2022 21:18:22 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6F5A5E8720 for ; Mon, 21 Nov 2022 18:16:34 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id i10-20020a25f20a000000b006ea4f43c0ddso6529279ybe.21 for ; Mon, 21 Nov 2022 18:16:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=vK6IEU0rl0A24X4GIdUEvjRzL9edAkzNEa8n9WiUMOU=; b=nMVdkL0Xs5RgzWRONSx7pNImE+bdCfORjqA/LqFEd467SrKJfeWf6eN7nWhCoYvm8i lKE791H13iGM9kcYULB5UfWIT7xYH8K0/qG2RNjqHoa3PwzjAgp201p8gC7hDeLwDbuI KRMgvcAME8kkAHQkq1IKt6UoKtL5lk/lrppet4xXxkvnIZ2jZRAIf1ZlzdvA9a9T+pVJ CnUcjD9wra0H99CSqH1Q8CksG93wEUjbHpF1gS0mzvHoaJLRNXhBi/dkAY0BQfB0sSqQ P5RX2FYAas3eiojJoqiNofyNGKolBNM/dV9mQ70c1wBz5OKscuESwcZHX6KvA+cdNL2V 4DpA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=vK6IEU0rl0A24X4GIdUEvjRzL9edAkzNEa8n9WiUMOU=; b=0e5x5tfym16i58SbPD1Om3AcsAPD3vcRkJQYptssbRsFeE3kJmyjYPpep6AkmNx0WK 6tNSkQcGF65GTBYwDSJaRSASOKxg4ymeixM20j33Iu64AfGEPVaukRBIJ8TxOrgsqj5q Ma50bslp1IE1FLRte2WNZnxDIYhm4KqxLFA3IOU9aYPO5nZRcxgra0o3g6lKGwB+tSd6 75hxuhzWo9ZwW9FZV2gHR115Xxggz3lOZIkHtJGtfCGpWxHF8KFfaH9Ws8yOGleR63CX UT1TxEXLfnMLg1A3O7bRae/4BqkiXtBtSv8FyAy9MiHfdXNw2M0Nya3rw7E+G+vSHyWh S/Vg== X-Gm-Message-State: ANoB5pmuTzGtJo54w8/bfTK+9fIcFFdbQykI0qZULMzeZmNZdBEFFQsC O/KP8gt/Qi2ZE+9VFKqy6qi2NIgccXY= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a81:4e14:0:b0:39d:5ff1:4418 with SMTP id c20-20020a814e14000000b0039d5ff14418mr2ywb.381.1669083393403; Mon, 21 Nov 2022 18:16:33 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:32 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-18-drosen@google.com> Subject: [RFC PATCH v2 17/21] fuse-bpf: Add attr support From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750161074418549465?= X-GMAIL-MSGID: =?utf-8?q?1750161074418549465?= Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 281 ++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/dir.c | 68 ++--------- fs/fuse/fuse_i.h | 102 +++++++++++++++++ fs/fuse/inode.c | 17 +-- 4 files changed, 398 insertions(+), 70 deletions(-) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 333181d6ad73..e2fe8c3aac2d 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -1949,6 +1949,287 @@ int fuse_bpf_unlink(int *out, struct inode *dir, struct dentry *entry) dir, entry); } +struct fuse_getattr_io { + struct fuse_getattr_in fgi; + struct fuse_attr_out fao; +}; + +static int fuse_getattr_initialize_in(struct fuse_args *fa, struct fuse_getattr_io *fgio, + const struct dentry *entry, struct kstat *stat, + u32 request_mask, unsigned int flags) +{ + fgio->fgi = (struct fuse_getattr_in) { + .getattr_flags = flags, + .fh = -1, /* TODO is this OK? */ + }; + + *fa = (struct fuse_args) { + .nodeid = get_node_id(entry->d_inode), + .opcode = FUSE_GETATTR, + .in_numargs = 1, + .in_args[0] = (struct fuse_in_arg) { + .size = sizeof(fgio->fgi), + .value = &fgio->fgi, + }, + }; + + return 0; +} + +static int fuse_getattr_initialize_out(struct fuse_args *fa, struct fuse_getattr_io *fgio, + const struct dentry *entry, struct kstat *stat, + u32 request_mask, unsigned int flags) +{ + fgio->fao = (struct fuse_attr_out) { 0 }; + + fa->out_numargs = 1; + fa->out_args[0] = (struct fuse_arg) { + .size = sizeof(fgio->fao), + .value = &fgio->fao, + }; + + return 0; +} + +static int fuse_getattr_backing(struct fuse_args *fa, int *out, + const struct dentry *entry, struct kstat *stat, + u32 request_mask, unsigned int flags) +{ + struct path *backing_path = &get_fuse_dentry(entry)->backing_path; + struct inode *backing_inode = backing_path->dentry->d_inode; + struct fuse_attr_out *fao = fa->out_args[0].value; + struct kstat tmp; + + if (!stat) + stat = &tmp; + + *out = vfs_getattr(backing_path, stat, request_mask, flags); + + if (!*out) + fuse_stat_to_attr(get_fuse_conn(entry->d_inode), backing_inode, + stat, &fao->attr); + + return 0; +} + +static int finalize_attr(struct inode *inode, struct fuse_attr_out *outarg, + u64 attr_version, struct kstat *stat) +{ + int err = 0; + + if (fuse_invalid_attr(&outarg->attr) || + ((inode->i_mode ^ outarg->attr.mode) & S_IFMT)) { + fuse_make_bad(inode); + err = -EIO; + } else { + fuse_change_attributes(inode, &outarg->attr, + attr_timeout(outarg), + attr_version); + if (stat) + fuse_fillattr(inode, &outarg->attr, stat); + } + return err; +} + +static int fuse_getattr_finalize(struct fuse_args *fa, int *out, + const struct dentry *entry, struct kstat *stat, + u32 request_mask, unsigned int flags) +{ + struct fuse_attr_out *outarg = fa->out_args[0].value; + struct inode *inode = entry->d_inode; + u64 attr_version = fuse_get_attr_version(get_fuse_mount(inode)->fc); + + /* TODO: Ensure this doesn't happen if we had an error getting attrs in + * backing. + */ + *out = finalize_attr(inode, outarg, attr_version, stat); + return 0; +} + +int fuse_bpf_getattr(int *out, struct inode *inode, const struct dentry *entry, struct kstat *stat, + u32 request_mask, unsigned int flags) +{ + return fuse_bpf_backing(inode, struct fuse_getattr_io, out, + fuse_getattr_initialize_in, fuse_getattr_initialize_out, + fuse_getattr_backing, fuse_getattr_finalize, + entry, stat, request_mask, flags); +} + +static void fattr_to_iattr(struct fuse_conn *fc, + const struct fuse_setattr_in *arg, + struct iattr *iattr) +{ + unsigned int fvalid = arg->valid; + + if (fvalid & FATTR_MODE) + iattr->ia_valid |= ATTR_MODE, iattr->ia_mode = arg->mode; + if (fvalid & FATTR_UID) { + iattr->ia_valid |= ATTR_UID; + iattr->ia_uid = make_kuid(fc->user_ns, arg->uid); + } + if (fvalid & FATTR_GID) { + iattr->ia_valid |= ATTR_GID; + iattr->ia_gid = make_kgid(fc->user_ns, arg->gid); + } + if (fvalid & FATTR_SIZE) + iattr->ia_valid |= ATTR_SIZE, iattr->ia_size = arg->size; + if (fvalid & FATTR_ATIME) { + iattr->ia_valid |= ATTR_ATIME; + iattr->ia_atime.tv_sec = arg->atime; + iattr->ia_atime.tv_nsec = arg->atimensec; + if (!(fvalid & FATTR_ATIME_NOW)) + iattr->ia_valid |= ATTR_ATIME_SET; + } + if (fvalid & FATTR_MTIME) { + iattr->ia_valid |= ATTR_MTIME; + iattr->ia_mtime.tv_sec = arg->mtime; + iattr->ia_mtime.tv_nsec = arg->mtimensec; + if (!(fvalid & FATTR_MTIME_NOW)) + iattr->ia_valid |= ATTR_MTIME_SET; + } + if (fvalid & FATTR_CTIME) { + iattr->ia_valid |= ATTR_CTIME; + iattr->ia_ctime.tv_sec = arg->ctime; + iattr->ia_ctime.tv_nsec = arg->ctimensec; + } +} + +struct fuse_setattr_io { + struct fuse_setattr_in fsi; + struct fuse_attr_out fao; +}; + +static int fuse_setattr_initialize_in(struct fuse_args *fa, struct fuse_setattr_io *fsio, + struct dentry *dentry, struct iattr *attr, struct file *file) +{ + struct fuse_conn *fc = get_fuse_conn(dentry->d_inode); + + *fsio = (struct fuse_setattr_io) { 0 }; + iattr_to_fattr(fc, attr, &fsio->fsi, true); + + *fa = (struct fuse_args) { + .opcode = FUSE_SETATTR, + .nodeid = get_node_id(dentry->d_inode), + .in_numargs = 1, + .in_args[0].size = sizeof(fsio->fsi), + .in_args[0].value = &fsio->fsi, + }; + + return 0; +} + +static int fuse_setattr_initialize_out(struct fuse_args *fa, struct fuse_setattr_io *fsio, + struct dentry *dentry, struct iattr *attr, struct file *file) +{ + fa->out_numargs = 1; + fa->out_args[0].size = sizeof(fsio->fao); + fa->out_args[0].value = &fsio->fao; + + return 0; +} + +static int fuse_setattr_backing(struct fuse_args *fa, int *out, + struct dentry *dentry, struct iattr *attr, struct file *file) +{ + struct fuse_conn *fc = get_fuse_conn(dentry->d_inode); + const struct fuse_setattr_in *fsi = fa->in_args[0].value; + struct iattr new_attr = { 0 }; + struct path *backing_path = &get_fuse_dentry(dentry)->backing_path; + + fattr_to_iattr(fc, fsi, &new_attr); + /* TODO: Some info doesn't get saved by the attr->fattr->attr transition + * When we actually allow the bpf to change these, we may have to consider + * the extra flags more, or pass more info into the bpf. Until then we can + * keep everything except for ATTR_FILE, since we'd need a file on the + * lower fs. For what it's worth, neither f2fs nor ext4 make use of that + * even if it is present. + */ + new_attr.ia_valid = attr->ia_valid & ~ATTR_FILE; + inode_lock(d_inode(backing_path->dentry)); + *out = notify_change(&init_user_ns, backing_path->dentry, &new_attr, + NULL); + inode_unlock(d_inode(backing_path->dentry)); + + if (*out == 0 && (new_attr.ia_valid & ATTR_SIZE)) + i_size_write(dentry->d_inode, new_attr.ia_size); + return 0; +} + +static int fuse_setattr_finalize(struct fuse_args *fa, int *out, + struct dentry *dentry, struct iattr *attr, struct file *file) +{ + return 0; +} + +int fuse_bpf_setattr(int *out, struct inode *inode, struct dentry *dentry, struct iattr *attr, struct file *file) +{ + return fuse_bpf_backing(inode, struct fuse_setattr_io, out, + fuse_setattr_initialize_in, fuse_setattr_initialize_out, + fuse_setattr_backing, fuse_setattr_finalize, dentry, attr, file); +} + +static int fuse_statfs_initialize_in(struct fuse_args *fa, struct fuse_statfs_out *fso, + struct dentry *dentry, struct kstatfs *buf) +{ + *fa = (struct fuse_args) { + .nodeid = get_node_id(d_inode(dentry)), + .opcode = FUSE_STATFS, + }; + + return 0; +} + +static int fuse_statfs_initialize_out(struct fuse_args *fa, struct fuse_statfs_out *fso, + struct dentry *dentry, struct kstatfs *buf) +{ + *fso = (struct fuse_statfs_out) { 0 }; + + fa->out_numargs = 1; + fa->out_args[0].size = sizeof(fso); + fa->out_args[0].value = fso; + + return 0; +} + +static int fuse_statfs_backing(struct fuse_args *fa, int *out, + struct dentry *dentry, struct kstatfs *buf) +{ + struct path backing_path; + struct fuse_statfs_out *fso = fa->out_args[0].value; + + *out = 0; + get_fuse_backing_path(dentry, &backing_path); + if (!backing_path.dentry) + return -EBADF; + *out = vfs_statfs(&backing_path, buf); + path_put(&backing_path); + buf->f_type = FUSE_SUPER_MAGIC; + + //TODO Provide postfilter opportunity to modify + if (!*out) + convert_statfs_to_fuse(&fso->st, buf); + + return 0; +} + +static int fuse_statfs_finalize(struct fuse_args *fa, int *out, + struct dentry *dentry, struct kstatfs *buf) +{ + struct fuse_statfs_out *fso = fa->out_args[0].value; + + if (!fa->error_in) + convert_fuse_statfs(buf, &fso->st); + return 0; +} + +int fuse_bpf_statfs(int *out, struct inode *inode, struct dentry *dentry, struct kstatfs *buf) +{ + return fuse_bpf_backing(dentry->d_inode, struct fuse_statfs_out, out, + fuse_statfs_initialize_in, fuse_statfs_initialize_out, + fuse_statfs_backing, fuse_statfs_finalize, + dentry, buf); +} + struct fuse_read_io { struct fuse_read_in fri; struct fuse_read_out fro; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 6ad0eb92de3b..899de6c84c2e 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1168,7 +1168,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, return err; } -static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, +void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, struct kstat *stat) { unsigned int blkbits; @@ -1245,6 +1245,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, } static int fuse_update_get_attr(struct inode *inode, struct file *file, + const struct path *path, struct kstat *stat, u32 request_mask, unsigned int flags) { @@ -1254,6 +1255,9 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file, u32 inval_mask = READ_ONCE(fi->inval_mask); u32 cache_mask = fuse_get_cache_mask(inode); + if (fuse_bpf_getattr(&err, inode, path->dentry, stat, request_mask, flags)) + return err; + if (flags & AT_STATX_FORCE_SYNC) sync = true; else if (flags & AT_STATX_DONT_SYNC) @@ -1277,7 +1281,7 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file, int fuse_update_attributes(struct inode *inode, struct file *file, u32 mask) { - return fuse_update_get_attr(inode, file, NULL, mask, 0); + return fuse_update_get_attr(inode, file, &file->f_path, NULL, mask, 0); } int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid, @@ -1639,58 +1643,6 @@ static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd, FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR); } -static inline bool update_mtime(unsigned int ivalid, bool trust_local_mtime) -{ - /* Always update if mtime is explicitly set */ - if (ivalid & ATTR_MTIME_SET) - return true; - - /* Or if kernel i_mtime is the official one */ - if (trust_local_mtime) - return true; - - /* If it's an open(O_TRUNC) or an ftruncate(), don't update */ - if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE))) - return false; - - /* In all other cases update */ - return true; -} - -static void iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr, - struct fuse_setattr_in *arg, bool trust_local_cmtime) -{ - unsigned ivalid = iattr->ia_valid; - - if (ivalid & ATTR_MODE) - arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; - if (ivalid & ATTR_UID) - arg->valid |= FATTR_UID, arg->uid = from_kuid(fc->user_ns, iattr->ia_uid); - if (ivalid & ATTR_GID) - arg->valid |= FATTR_GID, arg->gid = from_kgid(fc->user_ns, iattr->ia_gid); - if (ivalid & ATTR_SIZE) - arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; - if (ivalid & ATTR_ATIME) { - arg->valid |= FATTR_ATIME; - arg->atime = iattr->ia_atime.tv_sec; - arg->atimensec = iattr->ia_atime.tv_nsec; - if (!(ivalid & ATTR_ATIME_SET)) - arg->valid |= FATTR_ATIME_NOW; - } - if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_cmtime)) { - arg->valid |= FATTR_MTIME; - arg->mtime = iattr->ia_mtime.tv_sec; - arg->mtimensec = iattr->ia_mtime.tv_nsec; - if (!(ivalid & ATTR_MTIME_SET) && !trust_local_cmtime) - arg->valid |= FATTR_MTIME_NOW; - } - if ((ivalid & ATTR_CTIME) && trust_local_cmtime) { - arg->valid |= FATTR_CTIME; - arg->ctime = iattr->ia_ctime.tv_sec; - arg->ctimensec = iattr->ia_ctime.tv_nsec; - } -} - /* * Prevent concurrent writepages on inode * @@ -1805,6 +1757,9 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, bool trust_local_cmtime = is_wb; bool fault_blocked = false; + if (fuse_bpf_setattr(&err, inode, dentry, attr, file)) + return err; + if (!fc->default_permissions) attr->ia_valid |= ATTR_FORCE; @@ -1984,7 +1939,8 @@ static int fuse_setattr(struct user_namespace *mnt_userns, struct dentry *entry, * ia_mode calculation may have used stale i_mode. * Refresh and recalculate. */ - ret = fuse_do_getattr(inode, NULL, file); + if (!fuse_bpf_getattr(&ret, inode, entry, NULL, 0, 0)) + ret = fuse_do_getattr(inode, NULL, file); if (ret) return ret; @@ -2041,7 +1997,7 @@ static int fuse_getattr(struct user_namespace *mnt_userns, return -EACCES; } - return fuse_update_get_attr(inode, NULL, stat, request_mask, flags); + return fuse_update_get_attr(inode, NULL, path, stat, request_mask, flags); } static const struct inode_operations fuse_dir_inode_operations = { diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 3338ac84d083..8ecaf55e4632 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1422,6 +1422,10 @@ int fuse_bpf_file_read_iter(ssize_t *out, struct inode *inode, struct kiocb *ioc int fuse_bpf_file_write_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *from); int fuse_bpf_file_fallocate(int *out, struct inode *inode, struct file *file, int mode, loff_t offset, loff_t length); int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct dentry *entry, unsigned int flags); +int fuse_bpf_getattr(int *out, struct inode *inode, const struct dentry *entry, struct kstat *stat, + u32 request_mask, unsigned int flags); +int fuse_bpf_setattr(int *out, struct inode *inode, struct dentry *dentry, struct iattr *attr, struct file *file); +int fuse_bpf_statfs(int *out, struct inode *inode, struct dentry *dentry, struct kstatfs *buf); int fuse_bpf_readdir(int *out, struct inode *inode, struct file *file, struct dir_context *ctx); int fuse_bpf_access(int *out, struct inode *inode, int mask); @@ -1521,6 +1525,22 @@ static inline int fuse_bpf_lookup(struct dentry **out, struct inode *dir, struct return 0; } +static inline int fuse_bpf_getattr(int *out, struct inode *inode, const struct dentry *entry, struct kstat *stat, + u32 request_mask, unsigned int flags) +{ + return 0; +} + +static inline int fuse_bpf_setattr(int *out, struct inode *inode, struct dentry *dentry, struct iattr *attr, struct file *file) +{ + return 0; +} + +static inline int fuse_bpf_statfs(int *out, struct inode *inode, struct dentry *dentry, struct kstatfs *buf) +{ + return 0; +} + static inline int fuse_bpf_readdir(int *out, struct inode *inode, struct file *file, struct dir_context *ctx) { return 0; @@ -1566,6 +1586,88 @@ static inline u64 attr_timeout(struct fuse_attr_out *o) return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); } +static inline bool update_mtime(unsigned int ivalid, bool trust_local_mtime) +{ + /* Always update if mtime is explicitly set */ + if (ivalid & ATTR_MTIME_SET) + return true; + + /* Or if kernel i_mtime is the official one */ + if (trust_local_mtime) + return true; + + /* If it's an open(O_TRUNC) or an ftruncate(), don't update */ + if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE))) + return false; + + /* In all other cases update */ + return true; +} + +void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, + struct kstat *stat); + +static inline void iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr, + struct fuse_setattr_in *arg, bool trust_local_cmtime) +{ + unsigned int ivalid = iattr->ia_valid; + + if (ivalid & ATTR_MODE) + arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; + if (ivalid & ATTR_UID) + arg->valid |= FATTR_UID, arg->uid = from_kuid(fc->user_ns, iattr->ia_uid); + if (ivalid & ATTR_GID) + arg->valid |= FATTR_GID, arg->gid = from_kgid(fc->user_ns, iattr->ia_gid); + if (ivalid & ATTR_SIZE) + arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; + if (ivalid & ATTR_ATIME) { + arg->valid |= FATTR_ATIME; + arg->atime = iattr->ia_atime.tv_sec; + arg->atimensec = iattr->ia_atime.tv_nsec; + if (!(ivalid & ATTR_ATIME_SET)) + arg->valid |= FATTR_ATIME_NOW; + } + if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_cmtime)) { + arg->valid |= FATTR_MTIME; + arg->mtime = iattr->ia_mtime.tv_sec; + arg->mtimensec = iattr->ia_mtime.tv_nsec; + if (!(ivalid & ATTR_MTIME_SET) && !trust_local_cmtime) + arg->valid |= FATTR_MTIME_NOW; + } + if ((ivalid & ATTR_CTIME) && trust_local_cmtime) { + arg->valid |= FATTR_CTIME; + arg->ctime = iattr->ia_ctime.tv_sec; + arg->ctimensec = iattr->ia_ctime.tv_nsec; + } +} + +static inline void convert_statfs_to_fuse(struct fuse_kstatfs *attr, struct kstatfs *stbuf) +{ + attr->bsize = stbuf->f_bsize; + attr->frsize = stbuf->f_frsize; + attr->blocks = stbuf->f_blocks; + attr->bfree = stbuf->f_bfree; + attr->bavail = stbuf->f_bavail; + attr->files = stbuf->f_files; + attr->ffree = stbuf->f_ffree; + attr->namelen = stbuf->f_namelen; + /* fsid is left zero */ +} + +static inline void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) +{ + stbuf->f_type = FUSE_SUPER_MAGIC; + stbuf->f_bsize = attr->bsize; + stbuf->f_frsize = attr->frsize; + stbuf->f_blocks = attr->blocks; + stbuf->f_bfree = attr->bfree; + stbuf->f_bavail = attr->bavail; + stbuf->f_files = attr->files; + stbuf->f_ffree = attr->ffree; + stbuf->f_namelen = attr->namelen; + /* fsid is left zero */ +} + #ifdef CONFIG_FUSE_BPF int __init fuse_bpf_init(void); void __exit fuse_bpf_cleanup(void); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 9781faff6df6..1e7d45977144 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -616,20 +616,6 @@ static void fuse_send_destroy(struct fuse_mount *fm) } } -static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) -{ - stbuf->f_type = FUSE_SUPER_MAGIC; - stbuf->f_bsize = attr->bsize; - stbuf->f_frsize = attr->frsize; - stbuf->f_blocks = attr->blocks; - stbuf->f_bfree = attr->bfree; - stbuf->f_bavail = attr->bavail; - stbuf->f_files = attr->files; - stbuf->f_ffree = attr->ffree; - stbuf->f_namelen = attr->namelen; - /* fsid is left zero */ -} - static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; @@ -643,6 +629,9 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } + if (fuse_bpf_statfs(&err, dentry->d_inode, dentry, buf)) + return err; + memset(&outarg, 0, sizeof(outarg)); args.in_numargs = 0; args.opcode = FUSE_STATFS; From patchwork Tue Nov 22 02:15:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24136 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1957558wrr; Mon, 21 Nov 2022 18:20:59 -0800 (PST) X-Google-Smtp-Source: AA0mqf7AO6z1vX8gNXLwedaWrmO6RxSD3+v9ORXoW6Qtiyp398m1pc+zog+VPgPA0b2h+NsWHXpO X-Received: by 2002:a65:68da:0:b0:477:4a00:6ce8 with SMTP id k26-20020a6568da000000b004774a006ce8mr4229540pgt.502.1669083658887; Mon, 21 Nov 2022 18:20:58 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083658; cv=none; d=google.com; s=arc-20160816; b=mLIMxp+tZu/6OOBSZr/SlyrpFoGBTPoRmzf3UXDRnWdcZzylNDv/IolL6q4yTq6Dbt 9ov9qTeYTSJfqviuIZvyHCkRu3HF7qTx9Icu9g5Fb9lHmQDqTJFAdUwdHeflChoGNMyd VyMekzBQVakcQYGdbfCDqfD4WB2JuBv4SEzMtKH0lKzrPpbdynj/WUHnyGNCJWJQ8WY7 cUCAvHiPDmhDlrW5SvIZcM54DXmuiegt0nojIbZHpP3V3A2s4M9iN+6ohBoU51k1dmJB TTUNVCC+LFouUV4zOz67wijcho56DHJp49PnNG3SLBukvPv7rre6b0VmlcbHCccDzCnA Cq+Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=JFeUA3PbRtSHLNTEDynEdKNNWrqo68m/Sv/Ri911v1M=; b=MHNX33jbiFU7saEeQAA0nobRQ/b2EQjzmf1Haf78MlzJLA7NUNVUP9YbTPubYBMycG o+R56Kdi7mnOQCdyXrb07aRtWgXKNHF5wLe4WPU9YsiF6d6hbVFuJFlg4uXQs6rw3jUX HK4/UWsWnpmBn8LETytEh9TlieArcUTG4S/2qQ/n7vtPKF7T6ck6aJPTMur01GqSqDnL 0OwXzZco1HGwNh2+dU9D1yR4i5egK8ik+2d7WG4lioRLCda1fn4xo9ZQ4Dc0FeiWMvt2 wwoYO7binmfPDdlZrJjzJNnqhQpjWUtt8E8gENyFwjzRfsJK2GzR8fHYiytXVR3rijt1 e3JQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b="jg7q/4Hf"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id mu7-20020a17090b388700b00218c111625csi3092672pjb.150.2022.11.21.18.20.45; Mon, 21 Nov 2022 18:20:58 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b="jg7q/4Hf"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232632AbiKVCUE (ORCPT + 99 others); Mon, 21 Nov 2022 21:20:04 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42120 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232161AbiKVCTF (ORCPT ); Mon, 21 Nov 2022 21:19:05 -0500 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8D281E3D32 for ; Mon, 21 Nov 2022 18:16:36 -0800 (PST) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-393fc59d09fso106742247b3.18 for ; Mon, 21 Nov 2022 18:16:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=JFeUA3PbRtSHLNTEDynEdKNNWrqo68m/Sv/Ri911v1M=; b=jg7q/4HfLHsfBt1WL7tTNuB5B3bVu3bIH4ZmZLOvwtQ++pw/Tx1jZZa4cToMI7GJuy /+lbOSx4g82Rlg9a5y/azwCt2yFOG98n9bt6C1ANmyhGJMlJppMM0j7/OkqkOY8Em2Pn ACwO37txtQ7G0zdyJFLcw3XG2ghjR6lyLUPfcylAaC8vAuJdx7dhnSLyv+no1VmDeTWi 6x51K9Xxu5mQSw28bsPkIZ4RefCbZJ2aA8BR8/zYcigYEEaPEl4Vfh4Ii4NdyiJlzW+2 gqqz3L8Phg2zStOowpAC0DLKwASkP01kQ/jECUID7+e7lkmH/w1sWUT5Upoo7ejloHCI YOkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=JFeUA3PbRtSHLNTEDynEdKNNWrqo68m/Sv/Ri911v1M=; b=j6tI+XfCN5Bojc7Wr6stKC2w+Ov1xwNp289LQB7pvQyokXv2dUpITQVS6KC1ZYLbzD uoPNu04sThhVkYYCHrGViroTYBUBOXR5vSUvZtmsA98AwkRVfQx2hsTvgnNCWH06ovR7 x3CWF9HzJFPbADkJteyzE3SpWxap42xmBZxhpSRYf7lCM2CIGa3BY2zotqvEQKJFIbzW GHRX/9J27ivUt6nCnc6ttg3FUQTevXRLYy7qg6wgrMv2Vjw/+REWXglpNdvVHxUAAn2Y Kux5a1oGK/KDuqjprEASuCSO15NaPGsrKDYG2IMtiSFUgB6QrQC8PgWmVYefPzaRbK9+ 71Sw== X-Gm-Message-State: ANoB5pnoFS/lX7qjDJ8cG6c7ogtSEBmnZeizDv/HJWUSjY4wc8CZfIDN zQn8qUjN/v6HnNliACRKdm+FcnbFlgc= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a05:6902:1201:b0:6ec:73bd:1376 with SMTP id s1-20020a056902120100b006ec73bd1376mr1ybu.40.1669083395835; Mon, 21 Nov 2022 18:16:35 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:33 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-19-drosen@google.com> Subject: [RFC PATCH v2 18/21] fuse-bpf: Add support for FUSE_COPY_FILE_RANGE From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750161066561998329?= X-GMAIL-MSGID: =?utf-8?q?1750161066561998329?= Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/file.c | 4 +++ fs/fuse/fuse_i.h | 10 ++++++ 3 files changed, 99 insertions(+) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index e2fe8c3aac2d..36c8688c4463 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -792,6 +792,91 @@ int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t o file, offset, whence); } +struct fuse_copy_file_range_io { + struct fuse_copy_file_range_in fci; + struct fuse_write_out fwo; +}; + +static int fuse_copy_file_range_initialize_in(struct fuse_args *fa, + struct fuse_copy_file_range_io *fcf, + struct file *file_in, loff_t pos_in, struct file *file_out, + loff_t pos_out, size_t len, unsigned int flags) +{ + struct fuse_file *fuse_file_in = file_in->private_data; + struct fuse_file *fuse_file_out = file_out->private_data; + + fcf->fci = (struct fuse_copy_file_range_in) { + .fh_in = fuse_file_in->fh, + .off_in = pos_in, + .nodeid_out = fuse_file_out->nodeid, + .fh_out = fuse_file_out->fh, + .off_out = pos_out, + .len = len, + .flags = flags, + }; + + *fa = (struct fuse_args) { + .nodeid = get_node_id(file_in->f_inode), + .opcode = FUSE_COPY_FILE_RANGE, + .in_numargs = 1, + .in_args[0].size = sizeof(fcf->fci), + .in_args[0].value = &fcf->fci, + }; + + return 0; +} + +static int fuse_copy_file_range_initialize_out(struct fuse_args *fa, + struct fuse_copy_file_range_io *fcf, + struct file *file_in, loff_t pos_in, struct file *file_out, + loff_t pos_out, size_t len, unsigned int flags) +{ + fa->out_numargs = 1; + fa->out_args[0].size = sizeof(fcf->fwo); + fa->out_args[0].value = &fcf->fwo; + + return 0; +} + +static int fuse_copy_file_range_backing(struct fuse_args *fa, ssize_t *out, struct file *file_in, + loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, + unsigned int flags) +{ + const struct fuse_copy_file_range_in *fci = fa->in_args[0].value; + struct fuse_file *fuse_file_in = file_in->private_data; + struct file *backing_file_in = fuse_file_in->backing_file; + struct fuse_file *fuse_file_out = file_out->private_data; + struct file *backing_file_out = fuse_file_out->backing_file; + + /* TODO: Handle changing of in/out files */ + if (backing_file_out) + *out = vfs_copy_file_range(backing_file_in, fci->off_in, backing_file_out, + fci->off_out, fci->len, fci->flags); + else + *out = generic_copy_file_range(file_in, pos_in, file_out, pos_out, len, + flags); + return 0; +} + +static int fuse_copy_file_range_finalize(struct fuse_args *fa, ssize_t *out, struct file *file_in, + loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, + unsigned int flags) +{ + return 0; +} + +int fuse_bpf_copy_file_range(ssize_t *out, struct inode *inode, struct file *file_in, + loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, + unsigned int flags) +{ + return fuse_bpf_backing(inode, struct fuse_copy_file_range_io, out, + fuse_copy_file_range_initialize_in, + fuse_copy_file_range_initialize_out, + fuse_copy_file_range_backing, + fuse_copy_file_range_finalize, + file_in, pos_in, file_out, pos_out, len, flags); +} + static int fuse_fsync_initialize_in(struct fuse_args *fa, struct fuse_fsync_in *ffi, struct file *file, loff_t start, loff_t end, int datasync) { diff --git a/fs/fuse/file.c b/fs/fuse/file.c index fa9ee2740a42..8153e78ff1d6 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -3127,6 +3127,10 @@ static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in, bool is_unstable = (!fc->writeback_cache) && ((pos_out + len) > inode_out->i_size); + if (fuse_bpf_copy_file_range(&err, file_inode(file_in), file_in, pos_in, + file_out, pos_out, len, flags)) + return err; + if (fc->no_copy_file_range) return -EOPNOTSUPP; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 8ecaf55e4632..275b649bb5ed 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1416,6 +1416,9 @@ int fuse_bpf_release(int *out, struct inode *inode, struct file *file); int fuse_bpf_releasedir(int *out, struct inode *inode, struct file *file); int fuse_bpf_flush(int *out, struct inode *inode, struct file *file, fl_owner_t id); int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file *file, loff_t offset, int whence); +int fuse_bpf_copy_file_range(ssize_t *out, struct inode *inode, struct file *file_in, loff_t pos_in, + struct file *file_out, loff_t pos_out, + size_t len, unsigned int flags); int fuse_bpf_fsync(int *out, struct inode *inode, struct file *file, loff_t start, loff_t end, int datasync); int fuse_bpf_dir_fsync(int *out, struct inode *inode, struct file *file, loff_t start, loff_t end, int datasync); int fuse_bpf_file_read_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *to); @@ -1495,6 +1498,13 @@ static inline int fuse_bpf_lseek(loff_t *out, struct inode *inode, struct file * return 0; } +static inline int fuse_bpf_copy_file_range(ssize_t *out, struct inode *inode, struct file *file_in, loff_t pos_in, + struct file *file_out, loff_t pos_out, + size_t len, unsigned int flags) +{ + return 0; +} + static inline int fuse_bpf_fsync(int *out, struct inode *inode, struct file *file, loff_t start, loff_t end, int datasync) { return 0; From patchwork Tue Nov 22 02:15:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24137 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1957603wrr; Mon, 21 Nov 2022 18:21:06 -0800 (PST) X-Google-Smtp-Source: AA0mqf7GVwe+AQfjXorOemjrI2+CxqL9NgQ5LuZchvIf4mB5z1wkouZRM91d0xuMnJ4hYwEeO8Yz X-Received: by 2002:a17:90a:5c85:b0:20a:92d2:226a with SMTP id r5-20020a17090a5c8500b0020a92d2226amr11902802pji.155.1669083666479; Mon, 21 Nov 2022 18:21:06 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083666; cv=none; d=google.com; s=arc-20160816; b=habQrwKqGMpU8nvuVFPjVLZORqn5Ut9WRkviB79dkr3/pSD/B0Xx+sZKMTucJ1x6BQ AudflCx8Oxkb9Vqv89VjB9PGPosvXfNPaTN5G4IptSzkM5VLsZ/1lQXajUBRftOApgAL iXIZBydNioG8kFIAyLI/IEBSbWtIJi2yvAZjeZ47YkGPpXLxOS+YxxO9Hg/7DGLWO2nN i5AfGenZcRi7ma9HbX+l0nN5SHk2jgM3/L+RclVjXTSRG1FWmjXi1uTCH5Oojgy6aKZs oxEz5J6mp0Qdmm9aoQhtHzoNpfPaWGSLbfIFmE9wfiGPOUpYrtTJQAXMeT6Gw4gKlQbl T0bQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=0L2EwBSVK6gMt275n9P0FS+q+J4F8LKg12isFlJjWcc=; b=ws0APkEgf68LjbcVm8vlDz2PMlwza2ZDqeC1gvQR2iUa8FjJpJ8cZsIeVfL1cPC8f7 0BwxlxkGwD9dwmeIfIJRUyfl6afNwqWcHB75fibIuUSq9PSUqPhi9A6uYDVtF7ahqNn8 rJyYuP3BRg1JOkQHIgvVHFur3eFHz9Lg/NAd0duEAU5++JDrIZNwkGM80yAB0kWjA9cc i0KWsZuMQqewKQAFLcOflOEcBYNnh2YqNQ4spToVS2V+AVmD9TtysGV/pbPPFxZMcnqq SrKKnDWIYoK2DVii3cAvVAV3bdayC1Ox/kaIts/mTgMY1+pDCvrsBTYf8NwrrSJAWK4O ytjw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=b2iwtmjG; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id n16-20020a170903111000b00176841aa2e3si14279765plh.93.2022.11.21.18.20.53; Mon, 21 Nov 2022 18:21:06 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=b2iwtmjG; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232693AbiKVCU0 (ORCPT + 99 others); Mon, 21 Nov 2022 21:20:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43420 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231856AbiKVCTR (ORCPT ); Mon, 21 Nov 2022 21:19:17 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6EA0AE6346 for ; Mon, 21 Nov 2022 18:16:39 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id t5-20020a5b07c5000000b006dfa2102debso12478152ybq.4 for ; Mon, 21 Nov 2022 18:16:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=0L2EwBSVK6gMt275n9P0FS+q+J4F8LKg12isFlJjWcc=; b=b2iwtmjGXWqJQaJjBO+sHKmft5jbP35hxZFYnha0+A9WixhUAm4CdAuHnP0ktaGaw4 DDxlj91SlXqXiMIedrhYVc2MuXzDPTsnIapc/W6VBjn+gCAUuxdwguG/qDR0gk2IMiFx 4zlKrB5b/CIOsG6Yg3noh99/LJ+k8c1790XSDPWNzJytJ674BCoCHnx1vgBpMOFC61qD UeJr1CjS0bLFcMtQZ4tCQ2SiMd/ng2/ofy1NpEx9Qe7R9S2LRnZG4EncOLnYnc8GdMs0 CR3tu66M4z4AqJQB6L3NkrD9AQ05bbvhFJXPpmH/7syYS4jeqfUywFufcq8EY9q8BLLN vk/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=0L2EwBSVK6gMt275n9P0FS+q+J4F8LKg12isFlJjWcc=; b=qpbgMzHfRneyGUj3+JU9dNyo+6/O6EPPq0BBsu7z9zhKPAQuIXnzukLiBdgBsR+9to Gxb3nuy3l+AixhYfKfFEScYwAAqDejYxHLYKGx2P0f6jvwxyfgBKCOjeHGN33zb39t23 uHcRX8jqEmmNhXZVwpoZMqeGY6SxedVhfiiUzwgKZkquiGSR5i2BR6Z0/td9mrlrrhFh PbLjGsrtNn5iiRp5bRRffMUu4uOaU/Kv8vhbRhEpzamxobqx06aTcvtARD8jFgEYO93t OG9IcE/L2/Asw+wlTeuUc3t0ZaXHXUUNVw6cZnaVa++WLwb/Vh99N3uVfJMNQk8LWuA+ BN6Q== X-Gm-Message-State: ANoB5pm/ZzoISMztEYmfqkHJ0Ln3mZv3aoPp0Bp2N8UnOCm31HJdHl2h 4fpyXm2JQo0a1tTqGrKUSYRHsbx3Fmo= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a25:ab14:0:b0:6e9:916d:3f4d with SMTP id u20-20020a25ab14000000b006e9916d3f4dmr6ybi.346.1669083398353; Mon, 21 Nov 2022 18:16:38 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:34 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-20-drosen@google.com> Subject: [RFC PATCH v2 19/21] fuse-bpf: Add xattr support From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750161075083521482?= X-GMAIL-MSGID: =?utf-8?q?1750161075083521482?= Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 285 ++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 30 +++++ fs/fuse/xattr.c | 18 +++ 3 files changed, 333 insertions(+) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 36c8688c4463..05fb88865289 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -967,6 +967,291 @@ int fuse_bpf_dir_fsync(int *out, struct inode *inode, struct file *file, loff_t file, start, end, datasync); } +struct fuse_getxattr_io { + struct fuse_getxattr_in fgi; + struct fuse_getxattr_out fgo; +}; + +static int fuse_getxattr_initialize_in(struct fuse_args *fa, + struct fuse_getxattr_io *fgio, + struct dentry *dentry, const char *name, void *value, + size_t size) +{ + *fgio = (struct fuse_getxattr_io) { + .fgi.size = size, + }; + + *fa = (struct fuse_args) { + .nodeid = get_fuse_inode(dentry->d_inode)->nodeid, + .opcode = FUSE_GETXATTR, + .in_numargs = 2, + .in_args[0] = (struct fuse_in_arg) { + .size = sizeof(fgio->fgi), + .value = &fgio->fgi, + }, + .in_args[1] = (struct fuse_in_arg) { + .size = strlen(name) + 1, + .value = (void *) name, + }, + }; + + return 0; +} + +static int fuse_getxattr_initialize_out(struct fuse_args *fa, + struct fuse_getxattr_io *fgio, + struct dentry *dentry, const char *name, void *value, + size_t size) +{ + fa->out_numargs = 1; + if (size) { + fa->out_argvar = true; + fa->out_args[0].size = size; + fa->out_args[0].value = value; + } else { + fa->out_args[0].size = sizeof(fgio->fgo); + fa->out_args[0].value = &fgio->fgo; + } + return 0; +} + +static int fuse_getxattr_backing(struct fuse_args *fa, int *out, + struct dentry *dentry, const char *name, void *value, + size_t size) +{ + ssize_t ret = vfs_getxattr(&init_user_ns, + get_fuse_dentry(dentry)->backing_path.dentry, + fa->in_args[1].value, value, size); + + if (fa->out_argvar) + fa->out_args[0].size = ret; + else + ((struct fuse_getxattr_out *)fa->out_args[0].value)->size = ret; + + return 0; +} + +static int fuse_getxattr_finalize(struct fuse_args *fa, int *out, + struct dentry *dentry, const char *name, void *value, + size_t size) +{ + struct fuse_getxattr_out *fgo; + + if (fa->out_argvar) { + *out = fa->out_args[0].size; + return 0; + } + + fgo = fa->out_args[0].value; + + *out = fgo->size; + return 0; +} + +int fuse_bpf_getxattr(int *out, struct inode *inode, struct dentry *dentry, const char *name, + void *value, size_t size) +{ + return fuse_bpf_backing(inode, struct fuse_getxattr_io, out, + fuse_getxattr_initialize_in, fuse_getxattr_initialize_out, + fuse_getxattr_backing, fuse_getxattr_finalize, + dentry, name, value, size); +} + +static int fuse_listxattr_initialize_in(struct fuse_args *fa, + struct fuse_getxattr_io *fgio, + struct dentry *dentry, char *list, size_t size) +{ + *fgio = (struct fuse_getxattr_io) { + .fgi.size = size, + }; + + *fa = (struct fuse_args) { + .nodeid = get_fuse_inode(dentry->d_inode)->nodeid, + .opcode = FUSE_LISTXATTR, + .in_numargs = 1, + .in_args[0] = + (struct fuse_in_arg) { + .size = sizeof(fgio->fgi), + .value = &fgio->fgi, + }, + }; + + return 0; +} + +static int fuse_listxattr_initialize_out(struct fuse_args *fa, + struct fuse_getxattr_io *fgio, + struct dentry *dentry, char *list, size_t size) +{ + fa->out_numargs = 1; + + if (size) { + fa->out_argvar = true; + fa->out_args[0].size = size; + fa->out_args[0].value = (void *)list; + } else { + fa->out_args[0].size = sizeof(fgio->fgo); + fa->out_args[0].value = &fgio->fgo; + } + return 0; +} + +static int fuse_listxattr_backing(struct fuse_args *fa, ssize_t *out, struct dentry *dentry, + char *list, size_t size) +{ + *out = vfs_listxattr(get_fuse_dentry(dentry)->backing_path.dentry, list, size); + + if (*out < 0) + return *out; + + if (fa->out_argvar) + fa->out_args[0].size = *out; + else + ((struct fuse_getxattr_out *)fa->out_args[0].value)->size = *out; + + return 0; +} + +static int fuse_listxattr_finalize(struct fuse_args *fa, ssize_t *out, struct dentry *dentry, + char *list, size_t size) +{ + struct fuse_getxattr_out *fgo; + + if (fa->error_in) + return 0; + + if (fa->out_argvar) { + *out = fa->out_args[0].size; + return 0; + } + + fgo = fa->out_args[0].value; + *out = fgo->size; + return 0; +} + +int fuse_bpf_listxattr(ssize_t *out, struct inode *inode, struct dentry *dentry, + char *list, size_t size) +{ + return fuse_bpf_backing(inode, struct fuse_getxattr_io, out, + fuse_listxattr_initialize_in, fuse_listxattr_initialize_out, + fuse_listxattr_backing, fuse_listxattr_finalize, + dentry, list, size); +} + +static int fuse_setxattr_initialize_in(struct fuse_args *fa, + struct fuse_setxattr_in *fsxi, + struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) +{ + *fsxi = (struct fuse_setxattr_in) { + .size = size, + .flags = flags, + }; + + *fa = (struct fuse_args) { + .nodeid = get_fuse_inode(dentry->d_inode)->nodeid, + .opcode = FUSE_SETXATTR, + .in_numargs = 3, + .in_args[0] = (struct fuse_in_arg) { + .size = sizeof(*fsxi), + .value = fsxi, + }, + .in_args[1] = (struct fuse_in_arg) { + .size = strlen(name) + 1, + .value = (void *) name, + }, + .in_args[2] = (struct fuse_in_arg) { + .size = size, + .value = (void *) value, + }, + }; + + return 0; +} + +static int fuse_setxattr_initialize_out(struct fuse_args *fa, + struct fuse_setxattr_in *fsxi, + struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) +{ + return 0; +} + +static int fuse_setxattr_backing(struct fuse_args *fa, int *out, struct dentry *dentry, + const char *name, const void *value, size_t size, + int flags) +{ + *out = vfs_setxattr(&init_user_ns, + get_fuse_dentry(dentry)->backing_path.dentry, name, + value, size, flags); + return 0; +} + +static int fuse_setxattr_finalize(struct fuse_args *fa, int *out, struct dentry *dentry, + const char *name, const void *value, size_t size, + int flags) +{ + return 0; +} + +int fuse_bpf_setxattr(int *out, struct inode *inode, struct dentry *dentry, + const char *name, const void *value, size_t size, int flags) +{ + return fuse_bpf_backing(inode, struct fuse_setxattr_in, out, + fuse_setxattr_initialize_in, fuse_setxattr_initialize_out, + fuse_setxattr_backing, fuse_setxattr_finalize, + dentry, name, value, size, flags); +} + +static int fuse_removexattr_initialize_in(struct fuse_args *fa, + struct fuse_unused_io *unused, + struct dentry *dentry, const char *name) +{ + *fa = (struct fuse_args) { + .nodeid = get_fuse_inode(dentry->d_inode)->nodeid, + .opcode = FUSE_REMOVEXATTR, + .in_numargs = 1, + .in_args[0] = (struct fuse_in_arg) { + .size = strlen(name) + 1, + .value = (void *) name, + }, + }; + + return 0; +} + +static int fuse_removexattr_initialize_out(struct fuse_args *fa, + struct fuse_unused_io *unused, + struct dentry *dentry, const char *name) +{ + return 0; +} + +static int fuse_removexattr_backing(struct fuse_args *fa, int *out, + struct dentry *dentry, const char *name) +{ + struct path *backing_path = &get_fuse_dentry(dentry)->backing_path; + + /* TODO account for changes of the name by prefilter */ + *out = vfs_removexattr(&init_user_ns, backing_path->dentry, name); + return 0; +} + +static int fuse_removexattr_finalize(struct fuse_args *fa, int *out, + struct dentry *dentry, const char *name) +{ + return 0; +} + +int fuse_bpf_removexattr(int *out, struct inode *inode, struct dentry *dentry, const char *name) +{ + return fuse_bpf_backing(inode, struct fuse_unused_io, out, + fuse_removexattr_initialize_in, fuse_removexattr_initialize_out, + fuse_removexattr_backing, fuse_removexattr_finalize, + dentry, name); +} + static inline void fuse_bpf_aio_put(struct fuse_bpf_aio_req *aio_req) { if (refcount_dec_and_test(&aio_req->ref)) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 275b649bb5ed..37b29a3ea330 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1421,6 +1421,13 @@ int fuse_bpf_copy_file_range(ssize_t *out, struct inode *inode, struct file *fil size_t len, unsigned int flags); int fuse_bpf_fsync(int *out, struct inode *inode, struct file *file, loff_t start, loff_t end, int datasync); int fuse_bpf_dir_fsync(int *out, struct inode *inode, struct file *file, loff_t start, loff_t end, int datasync); +int fuse_bpf_getxattr(int *out, struct inode *inode, struct dentry *dentry, + const char *name, void *value, size_t size); +int fuse_bpf_listxattr(ssize_t *out, struct inode *inode, struct dentry *dentry, char *list, size_t size); +int fuse_bpf_setxattr(int *out, struct inode *inode, struct dentry *dentry, + const char *name, const void *value, size_t size, + int flags); +int fuse_bpf_removexattr(int *out, struct inode *inode, struct dentry *dentry, const char *name); int fuse_bpf_file_read_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *to); int fuse_bpf_file_write_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *from); int fuse_bpf_file_fallocate(int *out, struct inode *inode, struct file *file, int mode, loff_t offset, loff_t length); @@ -1515,6 +1522,29 @@ static inline int fuse_bpf_dir_fsync(int *out, struct inode *inode, struct file return 0; } +static inline int fuse_bpf_getxattr(int *out, struct inode *inode, struct dentry *dentry, + const char *name, void *value, size_t size) +{ + return 0; +} + +static inline int fuse_bpf_listxattr(ssize_t *out, struct inode *inode, struct dentry *dentry, char *list, size_t size) +{ + return 0; +} + +static inline int fuse_bpf_setxattr(int *out, struct inode *inode, struct dentry *dentry, + const char *name, const void *value, size_t size, + int flags) +{ + return 0; +} + +static inline int fuse_bpf_removexattr(int *out, struct inode *inode, struct dentry *dentry, const char *name) +{ + return 0; +} + static inline int fuse_bpf_file_read_iter(ssize_t *out, struct inode *inode, struct kiocb *iocb, struct iov_iter *to) { return 0; diff --git a/fs/fuse/xattr.c b/fs/fuse/xattr.c index 0d3e7177fce0..857e7d3a0dab 100644 --- a/fs/fuse/xattr.c +++ b/fs/fuse/xattr.c @@ -118,6 +118,9 @@ ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) if (fuse_is_bad(inode)) return -EIO; + if (fuse_bpf_listxattr(&ret, inode, entry, list, size)) + return ret; + if (!fuse_allow_current_process(fm->fc)) return -EACCES; @@ -182,9 +185,14 @@ static int fuse_xattr_get(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, const char *name, void *value, size_t size) { + int err; + if (fuse_is_bad(inode)) return -EIO; + if (fuse_bpf_getxattr(&err, inode, dentry, name, value, size)) + return err; + return fuse_getxattr(inode, name, value, size); } @@ -194,9 +202,19 @@ static int fuse_xattr_set(const struct xattr_handler *handler, const char *name, const void *value, size_t size, int flags) { + int err; + bool handled; + if (fuse_is_bad(inode)) return -EIO; + if (value) + handled = fuse_bpf_setxattr(&err, inode, dentry, name, value, size, flags); + else + handled = fuse_bpf_removexattr(&err, inode, dentry, name); + if (handled) + return err; + if (!value) return fuse_removexattr(inode, name); From patchwork Tue Nov 22 02:15:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24139 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1957814wrr; Mon, 21 Nov 2022 18:21:38 -0800 (PST) X-Google-Smtp-Source: AA0mqf54EebSv7A9Zgt1yX4KKzC4KgIOYQS1742kx4kmTn4MJN2bOrJlQsXrdit9rF4ECBzJgDiB X-Received: by 2002:a17:903:191:b0:186:5cda:1e01 with SMTP id z17-20020a170903019100b001865cda1e01mr2590638plg.111.1669083698047; Mon, 21 Nov 2022 18:21:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083698; cv=none; d=google.com; s=arc-20160816; b=OLb76cXLkfhF7hs+iI40NMNCx55CnFCy0OW0z+3A5+9l0WLZvehSMbwXpwu+/RySqT 0wYGXdhWhkixIL4j3/1T11kBvddAiKuu+9RXIBhcqsCnj2B+HVK9kHsDi1U0dvy0xCHp 7V6jqrnBoJBX+bYaQd1vsXjI55CvXwAudyu+BrnJaFWEyls4KOgcO16wA+I6b2ID5+4k j0s3TcB/7v+P2vANhLISM+w4WMiQYCVyTdL3h5+BjxgvMyKVDBEbmSBA1bk/x0WqGvL7 5h1BHn42FsVP9c4fmujsSlMuu19Pl3GEa/Z9w9LoJ5Iwm8h9OvwdSWOGVNPqIYLO3q6X Or3A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=xynMcMsTuZqMLXL5ELmNHCW5CNZGRvCuOQzJlNlxPiE=; b=U/f1WEBmt5ejHYYP4EJ0Z3QmNpWQDaAfJHswvwn7Mzz8IBzWrAvRA80ThrI5zHVV9R 1T4T+Rv0N6vZTdy9PGG3fXQA9hKrPAxTTt64Xz5cHDyLKElER6N8aEhAR0zQwHROQrKw pTs2dvW2Kgj/jZPsiW0aVXeNPkcKyWLk0DwRo701X9SvIvjUup2nc1vTuCrzQZrUd7dR JPUP2ySD8GLSe2D78tdoMabQ8P9OQSwtmX2GEzeFC74PLFYTLcat6i63XCxxDkOthgb8 anoGwq+u2T0zH+jv0lN9rbWhmurQWFjJgGxx2ADrMO0p6eciyqL4Ihyqhjfq/VfW29je deOQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=OUOhjEq4; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id h18-20020a656392000000b00476ce2ae030si12580715pgv.153.2022.11.21.18.21.24; Mon, 21 Nov 2022 18:21:38 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=OUOhjEq4; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232706AbiKVCUp (ORCPT + 99 others); Mon, 21 Nov 2022 21:20:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43554 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232591AbiKVCTk (ORCPT ); Mon, 21 Nov 2022 21:19:40 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C5926E9148 for ; Mon, 21 Nov 2022 18:16:41 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id a1-20020a056902056100b006e6f103d4c1so12687090ybt.23 for ; Mon, 21 Nov 2022 18:16:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=xynMcMsTuZqMLXL5ELmNHCW5CNZGRvCuOQzJlNlxPiE=; b=OUOhjEq4CnL9PVEr0QtLZtsjmGIU43rGzRaSI9yqkOCe/Tq6OgBYhpEJftwd6UWyQ/ 5eeE3FmCGczyreI5r/W4v9N5jqJoGlmQM2q02oW82bjyNtSfMiVAKuuRlyzzRCpqIjcK JqE5A8cs7Nov5Mp1Pr5ppPvmjSjUDvqdNwrEJcxCVXa1nPeGGAqVPzHzrRRvLfekRmG7 QN92GztkE/9jyU1ktQ0mdS+rYMrfjbUKE1XfIg7zDourWrv+MzvWMpNiFOUi1VzoyY63 oGRcclGwP2xBOMc//CIF4OX7JWonfe7495+rdT4v40NBqMMb/aLuZjA/x9Bb7/9mHKQn NAIQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=xynMcMsTuZqMLXL5ELmNHCW5CNZGRvCuOQzJlNlxPiE=; b=1EC8G9bhIOj6vHl9wkwPzeHcnMOMeFowNFWK9vnX+xQhH+n861EAA5qr3QS4nq3hO/ 1e70COO+ZV9Hpgh0/gUG+ApWlFGhJ6BaatSc3NeqvqQd4MLzUUEEzBZ8FDHJHL1ErGT4 yPT9/S96m9E/L0m+hyfk0JYZi9YgC6iWFGVLg7Iobs2HI7Md6Ov5IQf244mtrlkLgzJk y+cSwdu3SMEihWcMqQrhKXkqzmtJ5g4v18pHgnEGCUWWCn4tE7nsNNhHP/+rVBDZNbeJ tI85g1Kq2meMq281MN274NWYcZ1ZiHFwBu/gnCq/qmY765PwVdRMJFP/u6VMVFejnb3D 36SA== X-Gm-Message-State: ANoB5pmIIYX1IRdVhOTn4kGTz0KhkDJ/hdsYuPrkzMbFjb7w8HdmmlPm 6K3v+DVbGv15ydAY7H9a6Exds5NtEoo= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a25:ae12:0:b0:6d0:704:f19f with SMTP id a18-20020a25ae12000000b006d00704f19fmr4415884ybj.191.1669083400889; Mon, 21 Nov 2022 18:16:40 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:35 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-21-drosen@google.com> Subject: [RFC PATCH v2 20/21] fuse-bpf: Add symlink/link support From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750161107444653545?= X-GMAIL-MSGID: =?utf-8?q?1750161107444653545?= Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/backing.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/dir.c | 11 ++ fs/fuse/fuse_i.h | 20 ++++ 3 files changed, 302 insertions(+) diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 05fb88865289..a77414e8f3df 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -2319,6 +2319,104 @@ int fuse_bpf_unlink(int *out, struct inode *dir, struct dentry *entry) dir, entry); } +static int fuse_link_initialize_in(struct fuse_args *fa, struct fuse_link_in *fli, + struct dentry *entry, struct inode *dir, + struct dentry *newent) +{ + struct inode *src_inode = entry->d_inode; + + *fli = (struct fuse_link_in) { + .oldnodeid = get_node_id(src_inode), + }; + + fa->opcode = FUSE_LINK; + fa->in_numargs = 2; + fa->in_args[0].size = sizeof(*fli); + fa->in_args[0].value = fli; + fa->in_args[1].size = newent->d_name.len + 1; + fa->in_args[1].value = (void *) newent->d_name.name; + + return 0; +} + +static int fuse_link_initialize_out(struct fuse_args *fa, struct fuse_link_in *fli, + struct dentry *entry, struct inode *dir, + struct dentry *newent) +{ + return 0; +} + +static int fuse_link_backing(struct fuse_args *fa, int *out, struct dentry *entry, + struct inode *dir, struct dentry *newent) +{ + struct path backing_old_path; + struct path backing_new_path; + struct dentry *backing_dir_dentry; + struct inode *fuse_new_inode = NULL; + struct fuse_inode *fuse_dir_inode = get_fuse_inode(dir); + struct inode *backing_dir_inode = fuse_dir_inode->backing_inode; + + *out = 0; + get_fuse_backing_path(entry, &backing_old_path); + if (!backing_old_path.dentry) + return -EBADF; + + get_fuse_backing_path(newent, &backing_new_path); + if (!backing_new_path.dentry) { + *out = -EBADF; + goto err_dst_path; + } + + backing_dir_dentry = dget_parent(backing_new_path.dentry); + backing_dir_inode = d_inode(backing_dir_dentry); + + inode_lock_nested(backing_dir_inode, I_MUTEX_PARENT); + *out = vfs_link(backing_old_path.dentry, &init_user_ns, + backing_dir_inode, backing_new_path.dentry, NULL); + inode_unlock(backing_dir_inode); + if (*out) + goto out; + + if (d_really_is_negative(backing_new_path.dentry) || + unlikely(d_unhashed(backing_new_path.dentry))) { + *out = -EINVAL; + /** + * TODO: overlayfs responds to this situation with a + * lookupOneLen. Should we do that too? + */ + goto out; + } + + fuse_new_inode = fuse_iget_backing(dir->i_sb, fuse_dir_inode->nodeid, backing_dir_inode); + if (IS_ERR(fuse_new_inode)) { + *out = PTR_ERR(fuse_new_inode); + goto out; + } + d_instantiate(newent, fuse_new_inode); + +out: + dput(backing_dir_dentry); + path_put(&backing_new_path); +err_dst_path: + path_put(&backing_old_path); + return *out; +} + +static int fuse_link_finalize(struct fuse_args *fa, int *out, struct dentry *entry, + struct inode *dir, struct dentry *newent) +{ + return 0; +} + +int fuse_bpf_link(int *out, struct inode *inode, struct dentry *entry, + struct inode *newdir, struct dentry *newent) +{ + return fuse_bpf_backing(inode, struct fuse_link_in, out, + fuse_link_initialize_in, fuse_link_initialize_out, + fuse_link_backing, fuse_link_finalize, entry, + newdir, newent); +} + struct fuse_getattr_io { struct fuse_getattr_in fgi; struct fuse_attr_out fao; @@ -2600,6 +2698,179 @@ int fuse_bpf_statfs(int *out, struct inode *inode, struct dentry *dentry, struct dentry, buf); } +static int fuse_get_link_initialize_in(struct fuse_args *fa, struct fuse_unused_io *unused, + struct inode *inode, struct dentry *dentry, + struct delayed_call *callback) +{ + /* + * TODO + * If we want to handle changing these things, we'll need to copy + * the lower fs's data into our own buffer, and provide our own callback + * to free that buffer. + * + * Pre could change the name we're looking at + * postfilter can change the name we return + * + * We ought to only make that buffer if it's been requested, so leaving + * this unimplemented for the moment + */ + *fa = (struct fuse_args) { + .opcode = FUSE_READLINK, + .nodeid = get_node_id(inode), + .in_numargs = 1, + .in_args[0] = (struct fuse_in_arg) { + .size = dentry->d_name.len + 1, + .value = (void *) dentry->d_name.name, + }, + /* + * .out_argvar = 1, + * .out_numargs = 1, + * .out_args[0].size = , + * .out_args[0].value = , + */ + }; + + return 0; +} + +static int fuse_get_link_initialize_out(struct fuse_args *fa, struct fuse_unused_io *unused, + struct inode *inode, struct dentry *dentry, + struct delayed_call *callback) +{ + /* + * .out_argvar = 1, + * .out_numargs = 1, + * .out_args[0].size = , + * .out_args[0].value = , + */ + + return 0; +} + +static int fuse_get_link_backing(struct fuse_args *fa, const char **out, + struct inode *inode, struct dentry *dentry, + struct delayed_call *callback) +{ + struct path backing_path; + + if (!dentry) { + *out = ERR_PTR(-ECHILD); + return PTR_ERR(*out); + } + + get_fuse_backing_path(dentry, &backing_path); + if (!backing_path.dentry) { + *out = ERR_PTR(-ECHILD); + return PTR_ERR(*out); + } + + /* + * TODO: If we want to do our own thing, copy the data and then call the + * callback + */ + *out = vfs_get_link(backing_path.dentry, callback); + + path_put(&backing_path); + return 0; +} + +static int fuse_get_link_finalize(struct fuse_args *fa, const char **out, + struct inode *inode, struct dentry *dentry, + struct delayed_call *callback) +{ + return 0; +} + +int fuse_bpf_get_link(const char **out, struct inode *inode, struct dentry *dentry, + struct delayed_call *callback) +{ + return fuse_bpf_backing(inode, struct fuse_unused_io, out, + fuse_get_link_initialize_in, fuse_get_link_initialize_out, + fuse_get_link_backing, + fuse_get_link_finalize, + inode, dentry, callback); +} + +static int fuse_symlink_initialize_in(struct fuse_args *fa, struct fuse_unused_io *unused, + struct inode *dir, struct dentry *entry, const char *link, int len) +{ + *fa = (struct fuse_args) { + .nodeid = get_node_id(dir), + .opcode = FUSE_SYMLINK, + .in_numargs = 2, + .in_args[0] = (struct fuse_in_arg) { + .size = entry->d_name.len + 1, + .value = (void *) entry->d_name.name, + }, + .in_args[1] = (struct fuse_in_arg) { + .size = len, + .value = (void *) link, + }, + }; + + return 0; +} + +static int fuse_symlink_initialize_out(struct fuse_args *fa, struct fuse_unused_io *unused, + struct inode *dir, struct dentry *entry, const char *link, int len) +{ + return 0; +} + +static int fuse_symlink_backing(struct fuse_args *fa, int *out, + struct inode *dir, struct dentry *entry, const char *link, int len) +{ + struct fuse_inode *fuse_inode = get_fuse_inode(dir); + struct inode *backing_inode = fuse_inode->backing_inode; + struct path backing_path; + struct inode *inode = NULL; + + *out = 0; + //TODO Actually deal with changing the backing entry in symlink + get_fuse_backing_path(entry, &backing_path); + if (!backing_path.dentry) + return -EBADF; + + inode_lock_nested(backing_inode, I_MUTEX_PARENT); + *out = vfs_symlink(&init_user_ns, backing_inode, backing_path.dentry, + link); + inode_unlock(backing_inode); + if (*out) + goto out; + if (d_really_is_negative(backing_path.dentry) || + unlikely(d_unhashed(backing_path.dentry))) { + *out = -EINVAL; + /** + * TODO: overlayfs responds to this situation with a + * lookupOneLen. Should we do that too? + */ + goto out; + } + inode = fuse_iget_backing(dir->i_sb, fuse_inode->nodeid, backing_inode); + if (IS_ERR(inode)) { + *out = PTR_ERR(inode); + goto out; + } + d_instantiate(entry, inode); +out: + path_put(&backing_path); + return *out; +} + +static int fuse_symlink_finalize(struct fuse_args *fa, int *out, + struct inode *dir, struct dentry *entry, const char *link, int len) +{ + return 0; +} + +int fuse_bpf_symlink(int *out, struct inode *dir, struct dentry *entry, const char *link, int len) +{ + return fuse_bpf_backing(dir, struct fuse_unused_io, out, + fuse_symlink_initialize_in, fuse_symlink_initialize_out, + fuse_symlink_backing, fuse_symlink_finalize, + dir, entry, link, len); +} + struct fuse_read_io { struct fuse_read_in fri; struct fuse_read_out fro; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 899de6c84c2e..1f9105edc7e2 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -945,6 +945,10 @@ static int fuse_symlink(struct user_namespace *mnt_userns, struct inode *dir, struct fuse_mount *fm = get_fuse_mount(dir); unsigned len = strlen(link) + 1; FUSE_ARGS(args); + int err; + + if (fuse_bpf_symlink(&err, dir, entry, link, len)) + return err; args.opcode = FUSE_SYMLINK; args.in_numargs = 2; @@ -1151,6 +1155,9 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, struct fuse_mount *fm = get_fuse_mount(inode); FUSE_ARGS(args); + if (fuse_bpf_link(&err, inode, entry, newdir, newent)) + return err; + memset(&inarg, 0, sizeof(inarg)); inarg.oldnodeid = get_node_id(inode); args.opcode = FUSE_LINK; @@ -1543,12 +1550,16 @@ static const char *fuse_get_link(struct dentry *dentry, struct inode *inode, { struct fuse_conn *fc = get_fuse_conn(inode); struct page *page; + const char *out = NULL; int err; err = -EIO; if (fuse_is_bad(inode)) goto out_err; + if (fuse_bpf_get_link(&out, inode, dentry, callback)) + return out; + if (fc->cache_symlinks) return page_get_link(dentry, inode, callback); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 37b29a3ea330..99c9231ec98b 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1412,6 +1412,7 @@ int fuse_bpf_rename2(int *out, struct inode *olddir, struct dentry *oldent, int fuse_bpf_rename(int *out, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent); int fuse_bpf_unlink(int *out, struct inode *dir, struct dentry *entry); +int fuse_bpf_link(int *out, struct inode *inode, struct dentry *entry, struct inode *dir, struct dentry *newent); int fuse_bpf_release(int *out, struct inode *inode, struct file *file); int fuse_bpf_releasedir(int *out, struct inode *inode, struct file *file); int fuse_bpf_flush(int *out, struct inode *inode, struct file *file, fl_owner_t id); @@ -1436,6 +1437,9 @@ int fuse_bpf_getattr(int *out, struct inode *inode, const struct dentry *entry, u32 request_mask, unsigned int flags); int fuse_bpf_setattr(int *out, struct inode *inode, struct dentry *dentry, struct iattr *attr, struct file *file); int fuse_bpf_statfs(int *out, struct inode *inode, struct dentry *dentry, struct kstatfs *buf); +int fuse_bpf_get_link(const char **out, struct inode *inode, struct dentry *dentry, + struct delayed_call *callback); +int fuse_bpf_symlink(int *out, struct inode *dir, struct dentry *entry, const char *link, int len); int fuse_bpf_readdir(int *out, struct inode *inode, struct file *file, struct dir_context *ctx); int fuse_bpf_access(int *out, struct inode *inode, int mask); @@ -1485,6 +1489,11 @@ static inline int fuse_bpf_unlink(int *out, struct inode *dir, struct dentry *en return 0; } +static inline int fuse_bpf_link(int *out, struct inode *inode, struct dentry *entry, struct inode *dir, struct dentry *newent) +{ + return 0; +} + static inline int fuse_bpf_release(int *out, struct inode *inode, struct file *file) { return 0; @@ -1581,6 +1590,17 @@ static inline int fuse_bpf_statfs(int *out, struct inode *inode, struct dentry * return 0; } +static inline int fuse_bpf_get_link(const char **out, struct inode *inode, struct dentry *dentry, + struct delayed_call *callback) +{ + return 0; +} + +static inline int fuse_bpf_symlink(int *out, struct inode *dir, struct dentry *entry, const char *link, int len) +{ + return 0; +} + static inline int fuse_bpf_readdir(int *out, struct inode *inode, struct file *file, struct dir_context *ctx) { return 0; From patchwork Tue Nov 22 02:15:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 24140 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1957953wrr; Mon, 21 Nov 2022 18:22:02 -0800 (PST) X-Google-Smtp-Source: AA0mqf4wFKIjcESUI4AJKvuRuxEZf7zyD2FpwORQfNSTx7I89WgEEvIFAS6ZOgqp3IJP5gAn07HH X-Received: by 2002:a17:90a:7d06:b0:213:600:36a1 with SMTP id g6-20020a17090a7d0600b00213060036a1mr23036244pjl.14.1669083722668; Mon, 21 Nov 2022 18:22:02 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669083722; cv=none; d=google.com; s=arc-20160816; b=C3qG9MT23EE8p/XXKnL1OoW74q7G7kQFPLLU7RcS8RX0xB9mQaqxItzV1HguLrwMXu o6Wh5I/SZb4MxhwH/AW5Tp4I/KWHM/8pNtiOHcLTFctwBX7khbfUAz8IPre1TQeeGfDE n5iw4SwcNKq3KDMmy5kGTKqWWOqzq3xx64QmyjV2bohB/p7+3U/j4bWo7aKWuCu881/k wVSSYe/DmqB6IVHnvI5IJ3C5uA3U3se0voMuDELJ7hSWq1g+LlslN0bZI2qOdX19igpy /FWGIZPc9r0jjgIK/0Rsu54hvqC2LTuIWmbhZAqG/QHkMuj1jdFRxeyIMp4drqusiUeQ rIqA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=tJXvhRhAgfuVfe2WyHPR4tz1JKdoKAJyNeGFfWGwJfA=; b=PkQt9RLO0EyqV17ZKCJE4vrnX/MgICufIjWo0SvXc0O92b67ccFQ+UhhuLpr548lw8 m12h5NpNiBjfgnNOqhZS7RiYMTbSz+PKmWGjf6uRPTE6IEtVB6479UjV5p+K05zEDwac sG8I+nDDDJZYUH0GJQ2hTI9YYsZgUXb21KZSktef9xo1QB36xqRujiEiKfQ1T43suMkr wpr3DHK5ZPPl2I0SknARzywI4nRYbh99BH8COVDWRDQQBZWrRJ74fBFAFIN4NUXr4fW3 GCCKqeHeSxhfzEGlnTb49wAoB+U0wlkE/rglknPwmiKy07LidnnTbIxvn4YuNv9e3NS7 HBhw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=qGkvx8TF; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id c20-20020a6566d4000000b00476cc6391fcsi12046089pgw.445.2022.11.21.18.21.49; Mon, 21 Nov 2022 18:22:02 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=qGkvx8TF; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232711AbiKVCUu (ORCPT + 99 others); Mon, 21 Nov 2022 21:20:50 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42352 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232661AbiKVCTm (ORCPT ); Mon, 21 Nov 2022 21:19:42 -0500 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 36891E9152 for ; Mon, 21 Nov 2022 18:16:44 -0800 (PST) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-3a0e59c5ad7so44822497b3.20 for ; Mon, 21 Nov 2022 18:16:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=tJXvhRhAgfuVfe2WyHPR4tz1JKdoKAJyNeGFfWGwJfA=; b=qGkvx8TFpzkUW6hJpxPR4PKq3xLOu9Os7QX2lTMWCilalOFz9Xa1h5bFbtSpucKkWm TltFT8llXWJ7GhU2/JCvGPxUKKyf+M5vl3oAklLsvD1oxP8MTw156iiPERz5BlwYWBaw /Aotf3Al2u6liOXujyYy4ynyF1St9jqgbgFkLtP2NvI1Bj6udJvaG0Xmp52Kx7gzMg1Z adtT/ZnVZK6ZkF1A3IJqIRE5Nn89VCvBJgCK2auE41NBM56Tw2QLxlXT3TEm6s4rCvbA y+aBIj+GuWxJUkSGWY++ynL0CiCHeRY6X5vmgLh4cigCoA8tF6uoSbhGFr6AmKQfLhY7 hKQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=tJXvhRhAgfuVfe2WyHPR4tz1JKdoKAJyNeGFfWGwJfA=; b=yoInZ6MUvr+tSbgYF37z6HY4cvjuw7iTsQOjcSqQVXGgFc1XRhG2l5CIqmbqPkjEcF JzLAVymQF/mKdnl+VpaBLvdnXjGL+CMeDqMVdPWrUpiJYeaU6BkNWmbbeu13TNDk6+9Y YL0MgCIBuDyMMdXmf2/ccUqtpuwJphUm0tY5PFOhmGGFeFDSBDNvRGSHrGnsvgBJSc5e MeKEk0QEJhgRJ2O/1Svp+HE8258DroaqfmxV8B+K7nZz1NH67sydHvK9ti0Yv0xnGAms YXfMLehCBcie/4C839pCW2u1Gk2Og1+74GYFFVQDooI+vtP7YVI8z9M3HrLjZKdMKsDc ek+g== X-Gm-Message-State: ANoB5pmab45tN/GBa5orG/Em/HprzkjodVPbihQecFUj2AZtFs3Nf8Ry 6/89Rjc9hpJhBSr5PJVHkusOew0r4xw= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:200:8539:aadd:13be:6e82]) (user=drosen job=sendgmr) by 2002:a25:bd03:0:b0:6e6:9336:f565 with SMTP id f3-20020a25bd03000000b006e69336f565mr0ybk.598.1669083402808; Mon, 21 Nov 2022 18:16:42 -0800 (PST) Date: Mon, 21 Nov 2022 18:15:36 -0800 In-Reply-To: <20221122021536.1629178-1-drosen@google.com> Mime-Version: 1.0 References: <20221122021536.1629178-1-drosen@google.com> X-Mailer: git-send-email 2.38.1.584.g0f3c55d4c2-goog Message-ID: <20221122021536.1629178-22-drosen@google.com> Subject: [RFC PATCH v2 21/21] fuse-bpf: allow mounting with no userspace daemon From: Daniel Rosenberg To: Miklos Szeredi Cc: Amir Goldstein , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-unionfs@vger.kernel.org, bpf@vger.kernel.org, kernel-team@android.com, Daniel Rosenberg , Paul Lawrence X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750161133369178327?= X-GMAIL-MSGID: =?utf-8?q?1750161133369178327?= When using fuse-bpf in pure passthrough mode, we don't explicitly need a userspace daemon. This allows simple testing of the backing operations. Signed-off-by: Daniel Rosenberg Signed-off-by: Paul Lawrence --- fs/fuse/fuse_i.h | 4 ++++ fs/fuse/inode.c | 25 +++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 99c9231ec98b..402d80d35958 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -564,6 +564,7 @@ struct fuse_fs_context { bool no_control:1; bool no_force_umount:1; bool legacy_opts_show:1; + bool no_daemon:1; enum fuse_dax_mode dax_mode; unsigned int max_read; unsigned int blksize; @@ -842,6 +843,9 @@ struct fuse_conn { /* Is tmpfile not implemented by fs? */ unsigned int no_tmpfile:1; + /** BPF Only, no Daemon running */ + unsigned int no_daemon:1; + /** The number of requests waiting for completion */ atomic_t num_waiting; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 1e7d45977144..4820edcc242a 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -749,6 +749,7 @@ enum { OPT_MAX_READ, OPT_BLKSIZE, OPT_ROOT_DIR, + OPT_NO_DAEMON, OPT_ERR }; @@ -764,6 +765,7 @@ static const struct fs_parameter_spec fuse_fs_parameters[] = { fsparam_u32 ("blksize", OPT_BLKSIZE), fsparam_string ("subtype", OPT_SUBTYPE), fsparam_u32 ("root_dir", OPT_ROOT_DIR), + fsparam_flag ("no_daemon", OPT_NO_DAEMON), {} }; @@ -853,6 +855,11 @@ static int fuse_parse_param(struct fs_context *fsc, struct fs_parameter *param) return invalfc(fsc, "Unable to open root directory"); break; + case OPT_NO_DAEMON: + ctx->no_daemon = true; + ctx->fd_present = true; + break; + default: return -EINVAL; } @@ -1411,7 +1418,7 @@ void fuse_send_init(struct fuse_mount *fm) ia->args.nocreds = true; ia->args.end = process_init_reply; - if (fuse_simple_background(fm, &ia->args, GFP_KERNEL) != 0) + if (unlikely(fm->fc->no_daemon) || fuse_simple_background(fm, &ia->args, GFP_KERNEL) != 0) process_init_reply(fm, &ia->args, -ENOTCONN); } EXPORT_SYMBOL_GPL(fuse_send_init); @@ -1693,6 +1700,7 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) fc->destroy = ctx->destroy; fc->no_control = ctx->no_control; fc->no_force_umount = ctx->no_force_umount; + fc->no_daemon = ctx->no_daemon; err = -ENOMEM; root = fuse_get_root_inode(sb, ctx->rootmode, ctx->root_dir); @@ -1739,7 +1747,7 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) struct fuse_fs_context *ctx = fsc->fs_private; int err; - if (!ctx->file || !ctx->rootmode_present || + if (!!ctx->file == ctx->no_daemon || !ctx->rootmode_present || !ctx->user_id_present || !ctx->group_id_present) return -EINVAL; @@ -1747,10 +1755,12 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) * Require mount to happen from the same user namespace which * opened /dev/fuse to prevent potential attacks. */ - if ((ctx->file->f_op != &fuse_dev_operations) || - (ctx->file->f_cred->user_ns != sb->s_user_ns)) - return -EINVAL; - ctx->fudptr = &ctx->file->private_data; + if (ctx->file) { + if ((ctx->file->f_op != &fuse_dev_operations) || + (ctx->file->f_cred->user_ns != sb->s_user_ns)) + return -EINVAL; + ctx->fudptr = &ctx->file->private_data; + } err = fuse_fill_super_common(sb, ctx); if (err) @@ -1800,6 +1810,9 @@ static int fuse_get_tree(struct fs_context *fsc) fsc->s_fs_info = fm; + if (ctx->no_daemon) + return get_tree_nodev(fsc, fuse_fill_super); + if (ctx->fd_present) ctx->file = fget(ctx->fd);