summaryrefslogtreecommitdiff
path: root/fs/nilfs2/iomap.c
blob: 3ae3bf6ed36867fcf33d7f131083f3d3844b7bfa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// SPDX-License-Identifier: GPL-2.0+
/*
 * NILFS iomap support implementation.
 *
 * Written by Viacheslav Dubeyko.
 */

#include <linux/iomap.h>
#include <linux/pagemap.h>
#include "nilfs.h"
#include "mdt.h"
#include "iomap.h"

static int nilfs_iomap_begin(struct inode *inode, loff_t offset,
			     loff_t length, unsigned int flags,
			     struct iomap *iomap, struct iomap *srcmap)
{
	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
	struct nilfs_inode_info *ii = NILFS_I(inode);
	sector_t blkoff = offset >> inode->i_blkbits;
	unsigned int maxblocks;
	__u64 blknum = 0;
	int ret;

	/* Completely beyond EOF. Treat as hole */
	if (i_size_read(inode) <= offset) {
		iomap->type = IOMAP_HOLE;
		iomap->addr = IOMAP_NULL_ADDR;
		iomap->offset = offset;
		iomap->length = length;
		return 0;
	}

	/* Clamp length if the requested range goes beyond i_size */
	if (offset + length > i_size_read(inode)) {
		loff_t i_size = i_size_read(inode);
		unsigned int blocksize = i_blocksize(inode);

		length = round_up(i_size, blocksize) - offset;
	}

	maxblocks = min_t(loff_t, length >> inode->i_blkbits, INT_MAX);
	if (maxblocks == 0)
		maxblocks = 1;

	down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
	ret = nilfs_bmap_lookup_contig(ii->i_bmap, blkoff, &blknum, maxblocks);
	up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);

	if (ret == -ENOENT) {
		iomap->type = IOMAP_HOLE;
		iomap->addr = IOMAP_NULL_ADDR;
		iomap->offset = offset;
		iomap->length = min_t(loff_t, length, i_blocksize(inode));
		return 0;
	} else if (ret < 0)
		return ret;

	iomap->bdev = inode->i_sb->s_bdev;
	iomap->offset = offset;
	iomap->length = min_t(loff_t, length, (loff_t)ret << inode->i_blkbits);
	iomap->addr = (loff_t)blknum << inode->i_blkbits;
	iomap->type = IOMAP_MAPPED;
	iomap->flags = IOMAP_F_MERGED;

	return 0;
}

const struct iomap_ops nilfs_iomap_ops = {
	.iomap_begin = nilfs_iomap_begin,
};