Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp2497534pxb; Mon, 18 Jan 2021 21:13:57 -0800 (PST) X-Google-Smtp-Source: ABdhPJweC1A8ku+XSOQ3TvPu7OH8lJey56fYW3lQ/gJotUqzvgiFgakIXrH4MAlXsnevPKKcwBnn X-Received: by 2002:a17:906:2898:: with SMTP id o24mr1810917ejd.215.1611033237465; Mon, 18 Jan 2021 21:13:57 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1611033237; cv=none; d=google.com; s=arc-20160816; b=ArAhT8z7WvMGRZ/6+J6jtCAm/cDjVPuapTMFlFENS7HlRnedKWYzgWJrWwTyAz5t+1 /cKietGsMJhjcIc9Y2Q9nux7gPlZnIMFVxVg70hWN0zCAfY5vL6b7DqA0xsRxziQnJyX v5pGvrjD6MRpkWQ6WhKDr1yPq02nVXcu+72GoAXgws2wGwu6WVcodx6ST/RHjbvGsj+O 0Zzcdq4gujCTtQ+cACayokFMHyxxBfemwHy2MIMxPa+zo+Mq714hLzisQJU/vKZO166B WAiY80kRhnGKYdFRgS1kADIsOgSha7nI6FappQ+NtMVnaTSzH7dmylIGqtObbjpcWKFT vrIQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=A6Oskm85exd2P1bwvPrwmP4Mb1gHUWUZWFETbfW9HMA=; b=Ggkf6NkmuuL6hLALHMJ0rPZXtNVic+2vQ4psM/veM3K/dqDG3KOJm6KxXpGkg3A05Z aNzgZZoO3yJNWg3k5M0vxX/80In3fMHJbu2209rWDlZsRtXAznSDPbuoqPBXru9dnWm1 UrhzBLM2P0pszsUQQOzixgV/ivcl2aqGm1PYAToa5pOQgPL/khII32Jxpl4+DblgFDJ1 HlNOIYyTpPrwi6L2KaKaOx6PNasaXfrtaDYTh5jFvtGRzCfwitn13JX6ByNm+FBDkfiX NSupBOEXJPzTEbMHWhM4dR8lNIWUkEQ2hq7IBwSCyyKjZmCbATLpTODxvEi45jqPvkeL mNCA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@android.com header.s=20161025 header.b=bYdZpB8M; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=android.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id b2si1046626ejk.68.2021.01.18.21.13.34; Mon, 18 Jan 2021 21:13:57 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@android.com header.s=20161025 header.b=bYdZpB8M; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=android.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2437543AbhARTga (ORCPT + 99 others); Mon, 18 Jan 2021 14:36:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34172 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2394009AbhARTaM (ORCPT ); Mon, 18 Jan 2021 14:30:12 -0500 Received: from mail-wm1-x330.google.com (mail-wm1-x330.google.com [IPv6:2a00:1450:4864:20::330]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1E659C061793 for ; Mon, 18 Jan 2021 11:29:00 -0800 (PST) Received: by mail-wm1-x330.google.com with SMTP id u14so10523944wmq.4 for ; Mon, 18 Jan 2021 11:29:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=android.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=A6Oskm85exd2P1bwvPrwmP4Mb1gHUWUZWFETbfW9HMA=; b=bYdZpB8MG5JNLUXwHli/yKfiXxAcvN2Q7jYSHPqaO03XhUqY+wQ2VBa4yE/j0O/Jy7 iyFJCLWrpxyBUmSp2txbwaPNh08vHqbtM9tqkrD7m1raYNkB6p6LKd96AB3qe6XaJR0p n2qWBilTCVYafTszKNxh5HH7ao2TVaVVyhddGBkkWj65sMULUpHOkZYHI/wIaWENpkpb OKRfxD8dC194oLXUTh7y54r7M3PjP6LGt/l6ZL0NGqQxXGyFqriwGukmMeiE12ZFHIpd SFC1QqOupppG5AoSRKw9QVbgTv+2MFkeQCJ9msLG9cXpsidBlvvQRvHmuwZy6PDRe/x8 /o6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=A6Oskm85exd2P1bwvPrwmP4Mb1gHUWUZWFETbfW9HMA=; b=s5O0fQLmBxPT9bkMa4LjeGHUW1W6v7vjiaPjhkyajLiBH9xfi5euTxYaswA20pbGo/ 1bWih/Fb9pcPIusLdxX3W8BdlyoW9MKTnrhLhBUqAo/WwURG+qvexVA1MoukQtpiyef6 QhDxz+fiIyHpbR6qMcXXkALQ878VEEaAIrE2ht560zHyRJtcarcreRiaHeNdI+b9WDo9 i+Ex1tr7+tLHpVC+8TWS6HZybYu/xXpu1EicAr4WH+K/XZQvAempHCMKCrLLmZIO0Pcq s7XMF2hb2JiYB8t1Ti6tQrwp4ORwm6iUVaQPanKhP1PitlFODaQBNqmoXX6Jg6OKe9JT UI/w== X-Gm-Message-State: AOAM532FDTHIpZXVytNnxjVSx17N5hYGkctSyPcoGcro+fVlNhy9pAop JjFH1as8oPJCONtE18Of8SGWow== X-Received: by 2002:a1c:1f86:: with SMTP id f128mr811746wmf.174.1610998138919; Mon, 18 Jan 2021 11:28:58 -0800 (PST) Received: from balsini.lon.corp.google.com ([2a00:79e0:d:210:41d4:8c90:d38:455d]) by smtp.gmail.com with ESMTPSA id h5sm33583299wrp.56.2021.01.18.11.28.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 Jan 2021 11:28:58 -0800 (PST) From: Alessio Balsini To: Miklos Szeredi Cc: Akilesh Kailash , Amir Goldstein , Antonio SJ Musumeci , David Anderson , Giuseppe Scrivano , Jann Horn , Jens Axboe , Martijn Coenen , Palmer Dabbelt , Paul Lawrence , Peng Tao , Stefano Duo , Zimuzo Ezeozue , wuyan , fuse-devel@lists.sourceforge.net, kernel-team@android.com, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH RESEND V11 4/7] fuse: Passthrough initialization and release Date: Mon, 18 Jan 2021 19:27:45 +0000 Message-Id: <20210118192748.584213-5-balsini@android.com> X-Mailer: git-send-email 2.30.0.284.gd98b1dd5eaa7-goog In-Reply-To: <20210118192748.584213-1-balsini@android.com> References: <20210118192748.584213-1-balsini@android.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Implement the FUSE passthrough ioctl() that associates the lower (passthrough) file system file with the fuse_file. The file descriptor passed to the ioctl() by the FUSE daemon is used to access the relative file pointer, that will be copied to the fuse_file data structure to consolidate the link between the FUSE and lower file system. To enable the passthrough mode, user space triggers the FUSE_DEV_IOC_PASSTHROUGH_OPEN ioctl() and, if the call succeeds, receives back an identifier that will be used at open/create response time in the fuse_open_out field to associate the FUSE file to the lower file system file. The value returned by the ioctl() to user space can be: - > 0: success, the identifier can be used as part of an open/create reply. - < 0: an error occurred. The value 0 has been left unused for backward compatibility: the fuse_open_out field that is used to pass the passthrough_fh back to the kernel uses the same bits that were previously as struct padding, zero-initialized in the common libfuse implementation. Removing the 0 value fixes the ambiguity between the case in which 0 corresponds to a real passthrough_fh or a missing implementation, simplifying the user space implementation. For the passthrough mode to be successfully activated, the lower file system file must implement both read_iter and write_iter file operations. This extra check avoids special pseudo files to be targeted for this feature. Passthrough comes with another limitation: if a FUSE file systems enables passthrough, this feature is no more available to other FUSE file systems stacked on top of it. This check is only performed when FUSE passthrough is requested for a specific file and would simply prevent the use of FUSE passthrough for that file, not limiting other file operations. Signed-off-by: Alessio Balsini --- fs/fuse/inode.c | 5 +++ fs/fuse/passthrough.c | 87 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index d5c46eafb419..bc327789f25d 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1133,6 +1133,11 @@ EXPORT_SYMBOL_GPL(fuse_send_init); static int free_fuse_passthrough(int id, void *p, void *data) { + struct fuse_passthrough *passthrough = (struct fuse_passthrough *)p; + + fuse_passthrough_release(passthrough); + kfree(p); + return 0; } diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c index 594060c654f8..cf720ca14a45 100644 --- a/fs/fuse/passthrough.c +++ b/fs/fuse/passthrough.c @@ -3,19 +3,102 @@ #include "fuse_i.h" #include +#include int fuse_passthrough_open(struct fuse_dev *fud, struct fuse_passthrough_out *pto) { - return -EINVAL; + int res; + struct file *passthrough_filp; + struct fuse_conn *fc = fud->fc; + struct inode *passthrough_inode; + struct super_block *passthrough_sb; + struct fuse_passthrough *passthrough; + + if (!fc->passthrough) + return -EPERM; + + /* This field is reserved for future implementation */ + if (pto->len != 0) + return -EINVAL; + + passthrough_filp = fget(pto->fd); + if (!passthrough_filp) { + pr_err("FUSE: invalid file descriptor for passthrough.\n"); + return -EBADF; + } + + if (!passthrough_filp->f_op->read_iter || + !passthrough_filp->f_op->write_iter) { + pr_err("FUSE: passthrough file misses file operations.\n"); + res = -EBADF; + goto err_free_file; + } + + passthrough_inode = file_inode(passthrough_filp); + passthrough_sb = passthrough_inode->i_sb; + if (passthrough_sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + pr_err("FUSE: fs stacking depth exceeded for passthrough\n"); + res = -EINVAL; + goto err_free_file; + } + + passthrough = kmalloc(sizeof(struct fuse_passthrough), GFP_KERNEL); + if (!passthrough) { + res = -ENOMEM; + goto err_free_file; + } + + passthrough->filp = passthrough_filp; + + idr_preload(GFP_KERNEL); + spin_lock(&fc->passthrough_req_lock); + res = idr_alloc(&fc->passthrough_req, passthrough, 1, 0, GFP_ATOMIC); + spin_unlock(&fc->passthrough_req_lock); + idr_preload_end(); + + if (res > 0) + return res; + + fuse_passthrough_release(passthrough); + kfree(passthrough); + +err_free_file: + fput(passthrough_filp); + + return res; } int fuse_passthrough_setup(struct fuse_conn *fc, struct fuse_file *ff, struct fuse_open_out *openarg) { - return -EINVAL; + struct fuse_passthrough *passthrough; + int passthrough_fh = openarg->passthrough_fh; + + if (!fc->passthrough) + return -EPERM; + + /* Default case, passthrough is not requested */ + if (passthrough_fh <= 0) + return -EINVAL; + + spin_lock(&fc->passthrough_req_lock); + passthrough = idr_remove(&fc->passthrough_req, passthrough_fh); + spin_unlock(&fc->passthrough_req_lock); + + if (!passthrough) + return -EINVAL; + + ff->passthrough = *passthrough; + kfree(passthrough); + + return 0; } void fuse_passthrough_release(struct fuse_passthrough *passthrough) { + if (passthrough->filp) { + fput(passthrough->filp); + passthrough->filp = NULL; + } } -- 2.30.0.284.gd98b1dd5eaa7-goog