fs/udf/inode.c

Source file repositories/reference/linux-study-clean/fs/udf/inode.c

File Facts

System
Linux kernel
Corpus path
fs/udf/inode.c
Extension
.c
Size
70080 bytes
Lines
2460
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct udf_map_rq {
	sector_t lblk;
	udf_pblk_t pblk;
	int iflags;		/* UDF_MAP_ flags determining behavior */
	int oflags;		/* UDF_BLK_ flags reporting results */
};

static int udf_map_block(struct inode *inode, struct udf_map_rq *map)
{
	int ret;
	struct udf_inode_info *iinfo = UDF_I(inode);

	if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB))
		return -EFSCORRUPTED;

	map->oflags = 0;
	if (!(map->iflags & UDF_MAP_CREATE)) {
		struct kernel_lb_addr eloc;
		uint32_t elen;
		sector_t offset;
		struct extent_position epos = {};
		int8_t etype;

		down_read(&iinfo->i_data_sem);
		ret = inode_bmap(inode, map->lblk, &epos, &eloc, &elen, &offset,
				 &etype);
		if (ret < 0)
			goto out_read;
		if (ret > 0 && etype == (EXT_RECORDED_ALLOCATED >> 30)) {
			map->pblk = udf_get_lb_pblock(inode->i_sb, &eloc,
							offset);
			map->oflags |= UDF_BLK_MAPPED;
			ret = 0;
		}
out_read:
		up_read(&iinfo->i_data_sem);
		brelse(epos.bh);

		return ret;
	}

	down_write(&iinfo->i_data_sem);
	/*
	 * Block beyond EOF and prealloc extents? Just discard preallocation
	 * as it is not useful and complicates things.
	 */
	if (((loff_t)map->lblk) << inode->i_blkbits >= iinfo->i_lenExtents)
		udf_discard_prealloc(inode);
	udf_clear_extent_cache(inode);
	ret = inode_getblk(inode, map);
	up_write(&iinfo->i_data_sem);
	return ret;
}

static int __udf_get_block(struct inode *inode, sector_t block,
			   struct buffer_head *bh_result, int flags)
{
	int err;
	struct udf_map_rq map = {
		.lblk = block,
		.iflags = flags,
	};

	err = udf_map_block(inode, &map);
	if (err < 0)
		return err;
	if (map.oflags & UDF_BLK_MAPPED) {
		map_bh(bh_result, inode->i_sb, map.pblk);
		if (map.oflags & UDF_BLK_NEW)
			set_buffer_new(bh_result);
	}
	return 0;
}

int udf_get_block(struct inode *inode, sector_t block,
		  struct buffer_head *bh_result, int create)
{
	int flags = create ? UDF_MAP_CREATE : 0;

	/*
	 * We preallocate blocks only for regular files. It also makes sense
	 * for directories but there's a problem when to drop the
	 * preallocation. We might use some delayed work for that but I feel
	 * it's overengineering for a filesystem like UDF.
	 */
	if (!S_ISREG(inode->i_mode))
		flags |= UDF_MAP_NOPREALLOC;
	return __udf_get_block(inode, block, bh_result, flags);
}

Annotation

Implementation Notes