From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ed1-f43.google.com (mail-ed1-f43.google.com [209.85.208.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 72408378D8D for ; Fri, 24 Jul 2026 05:26:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.43 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784870781; cv=none; b=O2Oitp+0ANqkqfoZ9Z8gpO0f/NidZiNohl1rLhuWWRH9IaS/JnRxs3Ghhu9llkbsxovK9PnWMOl+sv41JjFqMWbgjdYUjtMf0Ig3JuA2ttJtuIzVhn/aCmZkWxJ2fQhITame5rlcIQcF3x/HmyUUWr/6DCTRZsTqI3SI4dq6zxQ= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784870781; c=relaxed/simple; bh=4RnSXRlFTtcvpuBj2UrW/EbdX0woNfnxDksjMbfaxjI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ljKiHU3M2DADGfN6WxjQwzk11SCE+lfkd1ye5aiVyyq8xpOpKbYF7kNOQZSqzylP71/yTCYB6dJ5iCzU6mHSAXmFccB94Gihy/3JhOFaULHQIxtAZmsXtHvvKzjLkW23T2PPphfVbaar6Ba/evPEGk7ZnYVzgZOlfu5linw60hM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=suse.com; spf=pass smtp.mailfrom=suse.com; dkim=pass (2048-bit key) header.d=suse.com header.i=@suse.com header.b=MqmXLkqf; arc=none smtp.client-ip=209.85.208.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=suse.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=suse.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=suse.com header.i=@suse.com header.b="MqmXLkqf" Received: by mail-ed1-f43.google.com with SMTP id 4fb4d7f45d1cf-69c3044e4b2so3023a12.2 for ; Thu, 23 Jul 2026 22:26:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=google; t=1784870778; x=1785475578; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=kv1usJVqUmBl0SRtdM1BtqDPTmR0aDfg3c/KtIYHeqI=; b=MqmXLkqfvuf2DkQNNYl2P6NlsYuMng2mG4PWO5Ioi8L2sH6EqQqYc960e3VnWP349t Gxd6VdYB7V1phZhEKASfpqIqg96ipwOlOmfdljLttRYkqnbP11CkfyI+JX625xYQDXFM Av6MQweNDz6+CLCWF0Bb3/M4YGo6iE/g088OIsTfb+/hD0fv584jvHa0O8ZjgamxVIAo 7wlN6Gzp+C9u30pOykU7hElY9N455K7kwRZKWYQPzNFFy5lyw8jSssdYnBV0nahusXM7 +O4aebwmjkgLa8d4WBH15DcN8CQAzX9QBZfYCCfT5gU9PtCQUEUIrz1OVkuCU28Y6NNI nRmg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784870778; x=1785475578; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=kv1usJVqUmBl0SRtdM1BtqDPTmR0aDfg3c/KtIYHeqI=; b=ec7Yb2SFC5Ek2mnMghPv0N4FbbDhvsAixzFenPq6s4F/aQCMQe4aV2tc+gydlw/x0Z NSeiLXbojUm5iLMnf19uqA/c2yxZb6XZTP/tXrgruXXfhA1Q9O1Zr2Wyr5N+pTDnxLov wQlCskAjgHWsnTRYhgWkrqkfc5UdOi34egIxdMpzCDNc1J3U1CUEg4hngf9BKK3LfgWS Xb2oPIh7/mSSHqmMmy84uXsxRRZUu4kHMHcoD1sJEwvqlO/zSbMN89MOOuCcfjoVVsda 0QR4vCOI6AyUbgbrjggzHHrmTesVZVogDcdX21LPAe6yTIC02bA87irWyAvKbGbafqRX YmyA== X-Forwarded-Encrypted: i=1; AHgh+RpJ1yQRslXz15LFDkyZ0/9yYD7leS5xB4jnsz21s7az45QYYpQoJQN9BvSmTYJmwboaHGD0ffiDwqTpQKA=@vger.kernel.org X-Gm-Message-State: AOJu0YyQKxj/kHzWRBTr6yLmeZ1k611oeUKguyl/H6yD4w7f5VDhj76S 1D8RLYJh29c59sAshG38nmt5f/aFWFLFZtolpxHUJai0LVJ8u6vsAmpnPva2zFNDucU= X-Gm-Gg: AR+sD11Ufp4LIsI8ZAEiELtY9s2caE5CC4Tio1p6euwNGE++K1LeFWUMabhc+VY/WUv efbTMRbk58kXq3rpUUGXMoF8eQVZPbOAJAlvB1Ulo7Z3rIB/hKv3oSX+QxqqkDSas2hH2B5yTkL 3rW+sk0/QsCEF5NKWqspixhTIVIWBmPxjyMBmK8rpoumRNnYw8L3ErgqAMFrgGTna89nmDdr91E QR48frZMXUQ/jQcHHhlNIxaqubGbt+qN5Fuo+b7O7ORMkC0iYO6SSXFCZeNxiGaManVy/9W3gUy a/ZxOZIxz6h3LvdcnW7XlrmEKJcz73XqeHaE4jaVbfZn9evUFgJledE9754b/kHESxzFhS8yrOW K+WYeLux44gNXa4voFsVXOc4aLtUF2S/vfZKPKnSyUZvd1E3zadyttUa+j+jmk8PjRQ5hfEJOqH fJTSU= X-Received: by 2002:a17:907:3e0f:b0:c12:c7ca:d704 with SMTP id a640c23a62f3a-c1c6ecdd8femr66625966b.6.1784870777662; Thu, 23 Jul 2026 22:26:17 -0700 (PDT) Received: from p15.suse.cz ([202.127.77.110]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-38f039b1ce3sm898577a91.4.2026.07.23.22.26.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jul 2026 22:26:16 -0700 (PDT) From: Heming Zhao To: joseph.qi@linux.alibaba.com, mark@fasheh.com, jlbec@evilplan.org Cc: Heming Zhao , ocfs2-devel@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [RFC PATCH 1/3] ocfs2: Add new ocfs2_map_blocks() to introduce iomap feature Date: Fri, 24 Jul 2026 13:25:55 +0800 Message-ID: <20260724052559.15409-2-heming.zhao@suse.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260724052559.15409-1-heming.zhao@suse.com> References: <20260724052559.15409-1-heming.zhao@suse.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit As part of migrating OCFS2 DIO read/write code paths towards the modern and high-performant iomap framework, this patch introduces an iomap API to replace old high-overhead VFS buffer_head structure paths. This patch establishes the foundational block mapping routines required by subsequent iomap integration patches. The implementation draws inspiration from ext4_map_blocks(). Signed-off-by: Heming Zhao --- fs/ocfs2/aops.c | 94 +++++++++++++++++++++++++++++++++++++++ fs/ocfs2/aops.h | 2 + fs/ocfs2/buffer_head_io.c | 12 ----- fs/ocfs2/ocfs2.h | 45 ++++++++++++++++++- 4 files changed, 140 insertions(+), 13 deletions(-) diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 4acdbb70882c..08df5e3b5196 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -126,6 +126,100 @@ static int ocfs2_lock_get_block(struct inode *inode, sector_t iblock, return ret; } +int ocfs2_map_blocks(struct inode *inode, struct ocfs2_map_block *map, + int flags) +{ + int err = 0; + unsigned int ext_flags; + u64 max_blocks = map->len; + u64 p_blkno, count, past_eof; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + int create = flags & OCFS2_GET_BLOCKS_CREATE; + + if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SYSTEM_FILE) + mlog(ML_NOTICE, "map_block on system inode 0x%p (%llu)\n", + inode, inode->i_ino); + + if (S_ISLNK(inode->i_mode)) { + /* + * TODO: refer ocfs2_get_block() to handle + * ocfs2_read_folio in the future + */ + mlog(ML_NOTICE, "map_block on S_ISLNK file, node 0x%p (%llu)\n", + inode, inode->i_ino); + dump_stack(); + goto bail; + } + + err = ocfs2_extent_map_get_blocks(inode, map->lblk, &p_blkno, &count, + &ext_flags); + if (err) { + mlog(ML_ERROR, "get_blocks() failed, inode: 0x%p, " + "block: %llu\n", inode, map->lblk); + goto bail; + } + + if (max_blocks < count) + count = max_blocks; + + map->pblk = p_blkno; + map->len = count; + + /* + * ocfs2 never allocates in this function - the only time we + * need to use MAP_NEW is when we're extending i_size on a file + * system which doesn't support holes, in which case MAP_NEW + * allows __block_write_begin() to zero. + * + * If we see this on a sparse file system, then a truncate has + * raced us and removed the cluster. In this case, we clear + * the buffers dirty and uptodate bits and let the buffer code + * ignore it as a hole. + */ + if (create && map->pblk == 0 && ocfs2_sparse_alloc(osb)) { + map->flags &= ~(OCFS2_MAP_DIRTY | OCFS2_MAP_UPTODATE); + goto bail; + } + + if (p_blkno) { + if (ext_flags & OCFS2_EXT_UNWRITTEN) { + map->flags |= OCFS2_MAP_UNWRITTEN; + } else if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) { + /* Treat the unwritten extent as a hole for zeroing purposes. */ + map->flags |= OCFS2_MAP_MAPPED; + } else { + /* nothing to do */ + } + } + + if (!ocfs2_sparse_alloc(osb)) { + if (map->pblk == 0) { + err = -EIO; + mlog(ML_ERROR, + "iblock = %llu p_blkno = %llu blkno=(%llu)\n", + (unsigned long long)map->lblk, + (unsigned long long)map->pblk, + (unsigned long long)OCFS2_I(inode)->ip_blkno); + mlog(ML_ERROR, "Size %llu, clusters %u\n", + (unsigned long long)i_size_read(inode), + OCFS2_I(inode)->ip_clusters); + dump_stack(); + goto bail; + } + } + + past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode)); + + if (create && (map->lblk >= past_eof)) + map->flags |= OCFS2_MAP_NEW; + +bail: + if (err < 0) + return -EIO; + else + return map->len; +} + int ocfs2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h index 114efc9111e4..8dd6edd7c1a1 100644 --- a/fs/ocfs2/aops.h +++ b/fs/ocfs2/aops.h @@ -42,6 +42,8 @@ int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size); int ocfs2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create); +int ocfs2_map_blocks(struct inode *inode, struct ocfs2_map_block *map, + int flags); /* all ocfs2_dio_end_io()'s fault */ #define ocfs2_iocb_is_rw_locked(iocb) \ test_bit(0, (unsigned long *)&iocb->private) diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c index 7bfe377af2df..493f2209cca5 100644 --- a/fs/ocfs2/buffer_head_io.c +++ b/fs/ocfs2/buffer_head_io.c @@ -23,18 +23,6 @@ #include "buffer_head_io.h" #include "ocfs2_trace.h" -/* - * Bits on bh->b_state used by ocfs2. - * - * These MUST be after the JBD2 bits. Hence, we use BH_JBDPrivateStart. - */ -enum ocfs2_state_bits { - BH_NeedsValidate = BH_JBDPrivateStart, -}; - -/* Expand the magic b_state functions */ -BUFFER_FNS(NeedsValidate, needs_validate); - int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh, struct ocfs2_caching_info *ci) { diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 62cad6522c7a..095f7ae5dded 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -509,7 +509,50 @@ struct ocfs2_super struct ocfs2_filecheck_sysfs_entry osb_fc_ent; }; -#define OCFS2_SB(sb) ((struct ocfs2_super *)(sb)->s_fs_info) +/* + * Bits on bh->b_state used by ocfs2. + * + * These MUST be after the JBD2 bits. Hence, we use BH_JBDPrivateStart. + */ +enum ocfs2_state_bits { + BH_NeedsValidate = BH_JBDPrivateStart, +}; + +/* Expand the magic b_state functions */ +BUFFER_FNS(NeedsValidate, needs_validate); + +/* + * Logical to physical block mapping, used by ocfs2_map_blocks() + * + * This structure is used to pass requests into ocfs2_map_blocks() as + * well as to store the information returned by ocfs2_map_blocks(). It + * takes less room on the stack than a struct buffer_head. + */ +#define OCFS2_MAP_NEW BIT(BH_New) +#define OCFS2_MAP_MAPPED BIT(BH_Mapped) +#define OCFS2_MAP_UNWRITTEN BIT(BH_Unwritten) +/* useless? #define OCFS2_MAP_BOUNDARY BIT(BH_Boundary) */ +/* useless? #define OCFS2_MAP_DELAYED BIT(BH_Delay) */ +#define OCFS2_MAP_DIRTY BIT(BH_Dirty) +#define OCFS2_MAP_UPTODATE BIT(BH_Uptodate) +#define OCFS2_MAP_NEEDS_VALIDATE BIT(BH_NeedsValidate) +#define OCFS2_MAP_DEFER_COMPLETION BIT(BH_Defer_Completion) +#define OCFS2_MAP_FLAGS (OCFS2_MAP_NEW | OCFS2_MAP_MAPPED |\ + OCFS2_MAP_DIRTY | OCFS2_MAP_UPTODATE |\ + OCFS2_MAP_NEEDS_VALIDATE |\ + OCFS2_MAP_DEFER_COMPLETION) + +struct ocfs2_map_block { + u64 pblk; /* physical block# */ + u64 lblk; /* logical block# */ + u64 len; /* number of block */ + unsigned int flags; +}; + +/* Flags used by ocfs2_map_blocks() */ +#define OCFS2_GET_BLOCKS_CREATE (0x0001) + +#define OCFS2_SB(sb) ((struct ocfs2_super *)(sb)->s_fs_info) /* Useful typedef for passing around journal access functions */ typedef int (*ocfs2_journal_access_func)(handle_t *handle, -- 2.54.0