fs/gfs2/bmap.c

Source file repositories/reference/linux-study-clean/fs/gfs2/bmap.c

File Facts

System
Linux kernel
Corpus path
fs/gfs2/bmap.c
Extension
.c
Size
66644 bytes
Lines
2510
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 metapath {
	struct buffer_head *mp_bh[GFS2_MAX_META_HEIGHT];
	__u16 mp_list[GFS2_MAX_META_HEIGHT];
	int mp_fheight; /* find_metapath height */
	int mp_aheight; /* actual height (lookup height) */
};

static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length);

/**
 * gfs2_unstuffer_folio - unstuff a stuffed inode into a block cached by a folio
 * @ip: the inode
 * @dibh: the dinode buffer
 * @block: the block number that was allocated
 * @folio: The folio.
 *
 * Returns: errno
 */
static int gfs2_unstuffer_folio(struct gfs2_inode *ip, struct buffer_head *dibh,
			       u64 block, struct folio *folio)
{
	struct inode *inode = &ip->i_inode;

	if (!folio_test_uptodate(folio)) {
		void *kaddr = kmap_local_folio(folio, 0);
		u64 dsize = i_size_read(inode);
 
		memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize);
		memset(kaddr + dsize, 0, folio_size(folio) - dsize);
		kunmap_local(kaddr);

		folio_mark_uptodate(folio);
	}

	if (gfs2_is_jdata(ip)) {
		struct buffer_head *bh = folio_buffers(folio);

		if (!bh)
			bh = create_empty_buffers(folio,
				BIT(inode->i_blkbits), BIT(BH_Uptodate));

		if (!buffer_mapped(bh))
			map_bh(bh, inode->i_sb, block);

		set_buffer_uptodate(bh);
		gfs2_trans_add_data(ip->i_gl, bh);
	} else {
		folio_mark_dirty(folio);
		gfs2_ordered_add_inode(ip);
	}

	return 0;
}

static int __gfs2_unstuff_inode(struct gfs2_inode *ip, struct folio *folio)
{
	struct buffer_head *bh, *dibh;
	struct gfs2_dinode *di;
	u64 block = 0;
	int isdir = gfs2_is_dir(ip);
	int error;

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (error)
		return error;

	if (i_size_read(&ip->i_inode)) {
		/* Get a free block, fill it with the stuffed data,
		   and write it out to disk */

		unsigned int n = 1;
		error = gfs2_alloc_blocks(ip, &block, &n, 0);
		if (error)
			goto out_brelse;
		if (isdir) {
			gfs2_trans_remove_revoke(GFS2_SB(&ip->i_inode), block, 1);
			error = gfs2_dir_get_new_buffer(ip, block, &bh);
			if (error)
				goto out_brelse;
			gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_meta_header),
					      dibh, sizeof(struct gfs2_dinode));
			brelse(bh);
		} else {
			error = gfs2_unstuffer_folio(ip, dibh, block, folio);
			if (error)
				goto out_brelse;
		}
	}

	/*  Set up the pointer to the new block  */

Annotation

Implementation Notes