From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ej1-f43.google.com (mail-ej1-f43.google.com [209.85.218.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 576313F787D for ; Thu, 7 May 2026 13:22:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.43 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778160131; cv=none; b=b3aXa4XYeyfi1w2NlRqZyVNBVE1eFS11hWvYtd/1Ihk4tsF76KWldv/WlSwgR9XpsWv9Dd67sW/iOrwcvetr+sWaR6fLxXBSsCWWmGMKLiZJS1+DNfJbK+5ri06Qz6Zyt8VqYF48QuxHUNdqkoEcyC1qh8bvzImHkbCE++EPfuQ= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778160131; c=relaxed/simple; bh=hM97rAik93hiBSiKWdSjs/IxZ8IgTuOkSMS5TAdFnTY=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W/36AUFTGHeRx82dxuKeCC8kX3iDrtMF6o9PFeCMl1sqd3rWEDteJmAGecRI83kZB4FHIEXqqN+XVkyZPlY0T2lHbkweA82cFTCg+j0lFXGfIEOhP2AOYn2as2hkVUw/GqY4JcjwCRw1ThibcTbAAlxBlwJzOiPle7WzjLeA5C4= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=permerror header.from=versity.com; spf=pass smtp.mailfrom=versity.com; dkim=pass (2048-bit key) header.d=versity.com header.i=@versity.com header.b=G/WBNVDB; arc=none smtp.client-ip=209.85.218.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=permerror header.from=versity.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=versity.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=versity.com header.i=@versity.com header.b="G/WBNVDB" Received: by mail-ej1-f43.google.com with SMTP id a640c23a62f3a-b8f97c626aaso148977366b.2 for ; Thu, 07 May 2026 06:22:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=versity.com; s=google; t=1778160127; x=1778764927; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=G8CGTT/vQiSWmpRTi2v54QB14Mrr0c9q1i8chJXDkdE=; b=G/WBNVDBC1vxp5CKVI6NhwqSFnZepOpI41eJjTk9F+C4CgrUUS4+egBdeoa2MtGzqy oKYLCEiiGrhXO2kU1ZK2qX8qz2r4fx1n2PXcpRVM7PUMm0nYW3IYVVDuBaHXCdU2w6Pf kGG9wiKa1bvbH2Txceu3nriGv7fBBh1YKxJuCV7wumfoST1F3jRQSvglGN1iVbHtAUCD RiBYW557FnbO1/FEea7O1NxVbTvGblUYVklvsvvUVO54fRuN7LDTL/vSx9lvh3NOVcmp D/lhRo7/d9GknFLcDeLgUwGy4/oDB7xelbGuXvEa8FjX+r5ozvTvvUaDwQEaA5d6LVer 3kUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778160127; x=1778764927; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=G8CGTT/vQiSWmpRTi2v54QB14Mrr0c9q1i8chJXDkdE=; b=R4LI5U/paW/ulRqbSwoikVXVKiFl3Fr3T6XHs0fdasWQA8YomO83jW03U7lPocwyF3 LVaeetK1BZRN3wsC8wvVYR6DmU+v5EgKetll44DEVOI/iGSO++wb7/ki0WJk/PEhOxBN h8O0D7vbfjfpZd4L/6gdpUo8Qkti0vQf2p2f7qKPUvlxrXC5AFfaFPYstaPKZWEs8EPO 8fCjo44iz+mpkXtDlM97AzIz3hvKajCBnp/t935QICCaAbaNMDqfqWg5BEceQISnEL3C F3k0i/qBDsnaHFAVdQJJQrvpxm5jo1DUqVleCsDDkYj+UC5E7V2UT4W43Ai4T9XcscPP hABA== X-Gm-Message-State: AOJu0YycHKw0sSrdyNAsh2T9KCqirkPHuXHHybcX4+yyytT5eY1wHMDl R/wKwpYxqvH8ISlVjdW0fQkvEuEQ1Razpx5crbmHGCvky8FgvztS7fymj+sD9TKEnXQgxgw6SzC AULCdNH0= X-Gm-Gg: AeBDievoFXrL24BgJfwF4CQO32ceaYMk8GE/BgA0Pmm48BsNM+oAg4I7MKSlam1d8mq W9e8IlZ0v6vizvoNLoGhJC4r9gUdtQqA5xd6UE+4ILrhbTchDH7dQ9ZkMPcKxyQkM39sLwaa5e4 ma5H3tFdE7o/TUoC9n8a1vtfrKoluye09+HeSXHHBDlqbLnPRhUbsNi9D+e9lQdD6FOaZMq5iQt uZLra4VLFnh50zx40NEz5yXYcPb335QqGzB4gvtibOfmpwz1MOKbnagsbDcwM61h17i7aQhlGDr DQVHfMMSGHqoZqO9v3vjlWVlntF5AI1c7RjuUngrTjSvQafHc7LCYelFMHczdg8/C8bUXHMHi3L hF//najeKINGGY26MT1McPiVCZuOQL8OzooFnnVlYUboTjsVP1iH8VwZ5ansKD2Vdcetw1IuqnZ 7gBU1mCrpY66RmKj4JPgwb024pgk+k0QHJNgjwZyYYdbE6SsFeY+m5T2DDUoDpXigJXls+opO5D MReN19G4haq3jWIUvr59G/lDEHbX8h3yaqRpA== X-Received: by 2002:a17:907:9307:b0:bc3:8551:c12f with SMTP id a640c23a62f3a-bc56c52181dmr478129566b.11.1778160126230; Thu, 07 May 2026 06:22:06 -0700 (PDT) Received: from localhost.localdomain (46-117-212-87.ftth.glasoperator.nl. [87.212.117.46]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-bc83364c5e3sm80638666b.35.2026.05.07.06.22.05 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 May 2026 06:22:05 -0700 (PDT) From: Valerie Aurora To: rpdfs-devel@lists.linux.dev Subject: [PATCH 6/6] rpdfs: add read_folio, dirty_folio, write_begin, write_end Date: Thu, 7 May 2026 15:21:53 +0200 Message-ID: <20260507132153.1161324-7-val@versity.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260507132153.1161324-1-val@versity.com> References: <20260507132153.1161324-1-val@versity.com> Precedence: bulk X-Mailing-List: rpdfs-devel@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit This commit completes basic file data read/write support, including avoidance of deadlock in read_folio. It does not include ->writepages() or readahead(). Signed-off-by: Valerie Aurora --- fs/rpdfs/data.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++ fs/rpdfs/inode.c | 1 + 2 files changed, 246 insertions(+) diff --git a/fs/rpdfs/data.c b/fs/rpdfs/data.c index b1ccf77ced7a..b3647e1ff42f 100644 --- a/fs/rpdfs/data.c +++ b/fs/rpdfs/data.c @@ -351,3 +351,248 @@ static int get_or_alloc_data_block(struct rpdfs_fs_info *rfi, struct rpdfs_trans ret, rpdfs_inode_ino(inode), lblk, refs ? le64_to_cpu(refs[0].bnr) : 0, *hnd_ret); return ret; } + +/* + * We have to avoid a potential deadlock between the kernel's lock on + * each folio and our cache consistency algorithm. The order of + * acquisition on a read or write or similar operation is: + * + * 1. kernel grabs folio lock, calls file system routine + * 2. local node attempts to get access to a block + * + * But invalidation of a page has this order: + * + * 1. remote node requests exclusive access to a block + * 2. local node receives cache invalidate message and tries to get folio lock + * + * If the local node is trying to get access to a block while another + * node tries to get exclusive access, we could end up with: + * + * 1. local node holds folio lock, can't get access to block + * 2. local node attempts to service invalidate request but can't get folio lock + * + * The solution is to acquire all blocks in non-blocking mode. If that + * fails, drop the folio lock and acquire the block in blocking mode, + * then release it and return AOP_TRUNCATED_PAGE. This return code means + * "the page was truncated away beneath me, please retry." The page + * cache will restart the read_folio operation, which will likely + * succeed (as long as no other node has requested the block since then). + * + * Note that readahead() should satisfy most read requests + * asynchronously, leaving us to do any remaining synchronous requests + * in read_folio(). + */ +static int rpdfs_read_folio(struct file *file, struct folio *folio) +{ + struct inode *inode = folio->mapping->host; + struct rpdfs_fs_info *rfi = RPDFS_INODE_FS(inode); + loff_t pos = folio_pos(folio); + size_t len = folio_size(folio); + struct rpdfs_block_handle *inode_hnd = NULL; + struct rpdfs_block_handle *blk_hnd = NULL; + rbaf_t rbaf = RBAF_NONBLOCK_MODE; + u64 lblk; + int ret; + + lblk = lblk_from_offset(pos); + + rpdfs_prd("ino %llu lblk %llu pos %lld len %lu", + rpdfs_inode_ino(inode), lblk, pos, len); + + /* we turn off atime always, inode will not be written */ + ret = rpdfs_inode_acquire(rfi, NULL, inode, &inode_hnd, RBAF_NONBLOCK_MODE); + if (ret == -EAGAIN) { + folio_unlock(folio); + + rpdfs_prd("could not acquire ino %llu non-blocking, ret %d, retrying", + rpdfs_inode_ino(inode), ret); + + ret = rpdfs_inode_acquire(rfi, NULL, inode, &inode_hnd, 0); + if (ret == 0) { + rpdfs_block_release(rfi, &inode_hnd); + ret = AOP_TRUNCATED_PAGE; + } + goto out; + } + if (ret < 0) + goto out_unlock; + + ret = get_or_alloc_data_block(rfi, NULL, inode, inode_hnd, lblk, rbaf, &blk_hnd); + if (ret == -EAGAIN) { + folio_unlock(folio); + + rpdfs_prd("could not acquire ino %llu lblk %llu non-blocking, ret %d, retrying", + rpdfs_inode_ino(inode), lblk, ret); + + rbaf &= ~RBAF_NONBLOCK_MODE; + ret = get_or_alloc_data_block(rfi, NULL, inode, inode_hnd, lblk, rbaf, &blk_hnd); + if (ret == 0) { + rpdfs_block_release(rfi, &blk_hnd); + ret = AOP_TRUNCATED_PAGE; + } + goto out; + } + if (ret < 0) + goto out_unlock; + + /* copy the data into the actual block */ + if (blk_hnd) + memcpy(folio_address(folio), blk_hnd->data, len); + else + memset(folio_address(folio), 0, len); + + rpdfs_prd("copied %4s len %lu to %4s", (char *) blk_hnd->data, len, + (char *) folio_address(folio)); + + folio_mark_uptodate(folio); +out_unlock: + folio_unlock(folio); +out: + rpdfs_block_release(rfi, &blk_hnd); + rpdfs_block_release(rfi, &inode_hnd); + + rpdfs_prd("ret %d", ret); + + return ret; +} + +static bool rpdfs_dirty_folio(struct address_space *mapping, struct folio *folio) +{ + rpdfs_prd("ino %lu index %lu", mapping->host->i_ino, folio->index); + + return filemap_dirty_folio(folio_mapping(folio), folio); +} + + +/* + * Info to be passed from write_begin to write_end to complete the write + * within a transaction. + */ +struct rpdfs_write_cb { + struct rpdfs_block_handle *inode_hnd; + struct rpdfs_block_handle *blk_hnd; + struct rpdfs_transaction txn; +}; + +/* + * Do whatever preparation is necessary to allocate space for a + * write. In the future it might check quotas, file system error state, + * etc. + * + * Called with the inode block already acquired read/write. Returns a + * locked folio on success. + */ +static int rpdfs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, + struct folio **foliop, void **fsdata) +{ + struct inode *inode = mapping->host; + struct rpdfs_fs_info *rfi = RPDFS_INODE_FS(inode); + struct folio *folio = NULL; + struct rpdfs_write_cb *cb; + rbaf_t rbaf; + u64 lblk; + int ret; + unsigned offset; + + lblk = lblk_from_offset(pos); + + rpdfs_prd("ino %llu lblk %llu pos %lld len %u", rpdfs_inode_ino(inode), lblk, pos, len); + + /* allocate txn and pass to write_end for updating inode i_size/times */ + cb = kzalloc(sizeof(struct rpdfs_write_cb), GFP_NOFS); + if (!cb) { + ret = -ENOMEM; + goto out; + } + + folio = __filemap_get_folio(mapping, pos >> PAGE_SHIFT, FGP_WRITEBEGIN, + mapping_gfp_mask(mapping)); + if (IS_ERR(folio)) { + ret = PTR_ERR(folio); + goto out; + } + + offset = offset_in_folio(folio, pos); + /* XXX use pos/len/offset to figure out when it is an overwrite */ + rbaf = RBAF_WRITE; + + ret = get_or_alloc_data_block(rfi, &cb->txn, inode, cb->inode_hnd, lblk, rbaf, &cb->blk_hnd); + if (ret < 0) + goto out; + + *foliop = folio; + *fsdata = cb; + ret = len; +out: + if (ret < 0) { + if (cb) { + rpdfs_txn_finish(rfi, &cb->txn); + kfree(cb); + } + if (!IS_ERR_OR_NULL(folio)) { + folio_unlock(folio); + folio_put(folio); + } + *foliop = NULL; + } + return ret; +} + +static int rpdfs_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct folio *folio, void *fsdata) +{ + struct inode *inode = mapping->host; + struct rpdfs_fs_info *rfi = RPDFS_INODE_FS(inode); + struct rpdfs_write_cb *cb = fsdata; + loff_t old_size = inode->i_size; + bool i_size_changed = false; + unsigned offset; + + offset = offset_in_folio(folio, pos); + /* + * Copy the data from the folio into the blcok. + * + * TODO: replace with writepages. + */ + memcpy(cb->blk_hnd->data + offset, folio_address(folio) + offset, len); + + rpdfs_prd("copied %4s len %d to %4s", (char *) folio_address(folio) + offset, len, + (char *) cb->blk_hnd->data + offset); + + if (pos + copied > inode->i_size) { + i_size_write(inode, pos + copied); + i_size_changed = true; + } + + folio_mark_dirty(folio); + folio_unlock(folio); + folio_put(folio); + + if (old_size < pos) + pagecache_isize_extended(inode, old_size, pos); + + /* mark inode dirty outside of folio lock for performance reasons */ + if (i_size_changed) + mark_inode_dirty(inode); + + /* finalize changes to the inode and block */ + rpdfs_block_release(rfi, &cb->blk_hnd); + rpdfs_inode_update(rfi, inode, cb->inode_hnd); + rpdfs_block_release(rfi, &cb->inode_hnd); + + rpdfs_txn_finish(rfi, &cb->txn); + kfree(cb); + + rpdfs_prd("i_size %lld copied %d", i_size_read(inode), copied); + + return copied; +} + +const struct address_space_operations rpdfs_aops = { + .read_folio = rpdfs_read_folio, + .dirty_folio = rpdfs_dirty_folio, + .write_begin = rpdfs_write_begin, + .write_end = rpdfs_write_end, +}; diff --git a/fs/rpdfs/inode.c b/fs/rpdfs/inode.c index fd0913e0e4b6..ec7f1e64ba18 100644 --- a/fs/rpdfs/inode.c +++ b/fs/rpdfs/inode.c @@ -163,6 +163,7 @@ void rpdfs_inode_init_ops(struct inode *inode) case S_IFREG: inode->i_op = &rpdfs_file_iops; inode->i_fop = &rpdfs_file_fops; + inode->i_mapping->a_ops = &rpdfs_aops; break; case S_IFDIR: inode->i_op = &rpdfs_dir_iops; -- 2.49.0