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,
};
|