Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2016-2021 Christoph Hellwig.
  4 */
  5#include <linux/module.h>
  6#include <linux/compiler.h>
  7#include <linux/fs.h>
  8#include <linux/iomap.h>
  9#include <linux/fiemap.h>
 10#include <linux/pagemap.h>
 
 
 
 11
 12static int iomap_to_fiemap(struct fiemap_extent_info *fi,
 13		const struct iomap *iomap, u32 flags)
 14{
 15	switch (iomap->type) {
 16	case IOMAP_HOLE:
 17		/* skip holes */
 18		return 0;
 19	case IOMAP_DELALLOC:
 20		flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN;
 21		break;
 22	case IOMAP_MAPPED:
 23		break;
 24	case IOMAP_UNWRITTEN:
 25		flags |= FIEMAP_EXTENT_UNWRITTEN;
 26		break;
 27	case IOMAP_INLINE:
 28		flags |= FIEMAP_EXTENT_DATA_INLINE;
 29		break;
 30	}
 31
 32	if (iomap->flags & IOMAP_F_MERGED)
 33		flags |= FIEMAP_EXTENT_MERGED;
 34	if (iomap->flags & IOMAP_F_SHARED)
 35		flags |= FIEMAP_EXTENT_SHARED;
 36
 37	return fiemap_fill_next_extent(fi, iomap->offset,
 38			iomap->addr != IOMAP_NULL_ADDR ? iomap->addr : 0,
 39			iomap->length, flags);
 40}
 41
 42static loff_t iomap_fiemap_iter(const struct iomap_iter *iter,
 43		struct fiemap_extent_info *fi, struct iomap *prev)
 
 44{
 45	int ret;
 
 46
 47	if (iter->iomap.type == IOMAP_HOLE)
 48		return iomap_length(iter);
 49
 50	ret = iomap_to_fiemap(fi, prev, 0);
 51	*prev = iter->iomap;
 52	switch (ret) {
 53	case 0:		/* success */
 54		return iomap_length(iter);
 55	case 1:		/* extent array full */
 56		return 0;
 57	default:	/* error */
 58		return ret;
 59	}
 60}
 61
 62int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
 63		u64 start, u64 len, const struct iomap_ops *ops)
 64{
 65	struct iomap_iter iter = {
 66		.inode		= inode,
 67		.pos		= start,
 68		.len		= len,
 69		.flags		= IOMAP_REPORT,
 70	};
 71	struct iomap prev = {
 72		.type		= IOMAP_HOLE,
 73	};
 74	int ret;
 75
 76	ret = fiemap_prep(inode, fi, start, &iter.len, 0);
 77	if (ret)
 78		return ret;
 79
 80	while ((ret = iomap_iter(&iter, ops)) > 0)
 81		iter.processed = iomap_fiemap_iter(&iter, fi, &prev);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 82
 83	if (prev.type != IOMAP_HOLE) {
 84		ret = iomap_to_fiemap(fi, &prev, FIEMAP_EXTENT_LAST);
 
 
 
 
 85		if (ret < 0)
 86			return ret;
 87	}
 88
 89	/* inode with no (attribute) mapping will give ENOENT */
 90	if (ret < 0 && ret != -ENOENT)
 91		return ret;
 92	return 0;
 93}
 94EXPORT_SYMBOL_GPL(iomap_fiemap);
 95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 96/* legacy ->bmap interface.  0 is the error return (!) */
 97sector_t
 98iomap_bmap(struct address_space *mapping, sector_t bno,
 99		const struct iomap_ops *ops)
100{
101	struct iomap_iter iter = {
102		.inode	= mapping->host,
103		.pos	= (loff_t)bno << mapping->host->i_blkbits,
104		.len	= i_blocksize(mapping->host),
105		.flags	= IOMAP_REPORT,
106	};
107	const unsigned int blkshift = mapping->host->i_blkbits - SECTOR_SHIFT;
108	int ret;
109
110	if (filemap_write_and_wait(mapping))
111		return 0;
112
113	bno = 0;
114	while ((ret = iomap_iter(&iter, ops)) > 0) {
115		if (iter.iomap.type == IOMAP_MAPPED)
116			bno = iomap_sector(&iter.iomap, iter.pos) >> blkshift;
117		/* leave iter.processed unset to abort loop */
118	}
119	if (ret)
120		return 0;
121
122	return bno;
123}
124EXPORT_SYMBOL_GPL(iomap_bmap);
v5.4
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2016-2018 Christoph Hellwig.
  4 */
  5#include <linux/module.h>
  6#include <linux/compiler.h>
  7#include <linux/fs.h>
  8#include <linux/iomap.h>
  9
 10struct fiemap_ctx {
 11	struct fiemap_extent_info *fi;
 12	struct iomap prev;
 13};
 14
 15static int iomap_to_fiemap(struct fiemap_extent_info *fi,
 16		struct iomap *iomap, u32 flags)
 17{
 18	switch (iomap->type) {
 19	case IOMAP_HOLE:
 20		/* skip holes */
 21		return 0;
 22	case IOMAP_DELALLOC:
 23		flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN;
 24		break;
 25	case IOMAP_MAPPED:
 26		break;
 27	case IOMAP_UNWRITTEN:
 28		flags |= FIEMAP_EXTENT_UNWRITTEN;
 29		break;
 30	case IOMAP_INLINE:
 31		flags |= FIEMAP_EXTENT_DATA_INLINE;
 32		break;
 33	}
 34
 35	if (iomap->flags & IOMAP_F_MERGED)
 36		flags |= FIEMAP_EXTENT_MERGED;
 37	if (iomap->flags & IOMAP_F_SHARED)
 38		flags |= FIEMAP_EXTENT_SHARED;
 39
 40	return fiemap_fill_next_extent(fi, iomap->offset,
 41			iomap->addr != IOMAP_NULL_ADDR ? iomap->addr : 0,
 42			iomap->length, flags);
 43}
 44
 45static loff_t
 46iomap_fiemap_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
 47		struct iomap *iomap)
 48{
 49	struct fiemap_ctx *ctx = data;
 50	loff_t ret = length;
 51
 52	if (iomap->type == IOMAP_HOLE)
 53		return length;
 54
 55	ret = iomap_to_fiemap(ctx->fi, &ctx->prev, 0);
 56	ctx->prev = *iomap;
 57	switch (ret) {
 58	case 0:		/* success */
 59		return length;
 60	case 1:		/* extent array full */
 61		return 0;
 62	default:
 63		return ret;
 64	}
 65}
 66
 67int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
 68		loff_t start, loff_t len, const struct iomap_ops *ops)
 69{
 70	struct fiemap_ctx ctx;
 71	loff_t ret;
 72
 73	memset(&ctx, 0, sizeof(ctx));
 74	ctx.fi = fi;
 75	ctx.prev.type = IOMAP_HOLE;
 
 
 
 
 76
 77	ret = fiemap_check_flags(fi, FIEMAP_FLAG_SYNC);
 78	if (ret)
 79		return ret;
 80
 81	if (fi->fi_flags & FIEMAP_FLAG_SYNC) {
 82		ret = filemap_write_and_wait(inode->i_mapping);
 83		if (ret)
 84			return ret;
 85	}
 86
 87	while (len > 0) {
 88		ret = iomap_apply(inode, start, len, IOMAP_REPORT, ops, &ctx,
 89				iomap_fiemap_actor);
 90		/* inode with no (attribute) mapping will give ENOENT */
 91		if (ret == -ENOENT)
 92			break;
 93		if (ret < 0)
 94			return ret;
 95		if (ret == 0)
 96			break;
 97
 98		start += ret;
 99		len -= ret;
100	}
101
102	if (ctx.prev.type != IOMAP_HOLE) {
103		ret = iomap_to_fiemap(fi, &ctx.prev, FIEMAP_EXTENT_LAST);
104		if (ret < 0)
105			return ret;
106	}
107
 
 
 
108	return 0;
109}
110EXPORT_SYMBOL_GPL(iomap_fiemap);
111
112static loff_t
113iomap_bmap_actor(struct inode *inode, loff_t pos, loff_t length,
114		void *data, struct iomap *iomap)
115{
116	sector_t *bno = data, addr;
117
118	if (iomap->type == IOMAP_MAPPED) {
119		addr = (pos - iomap->offset + iomap->addr) >> inode->i_blkbits;
120		if (addr > INT_MAX)
121			WARN(1, "would truncate bmap result\n");
122		else
123			*bno = addr;
124	}
125	return 0;
126}
127
128/* legacy ->bmap interface.  0 is the error return (!) */
129sector_t
130iomap_bmap(struct address_space *mapping, sector_t bno,
131		const struct iomap_ops *ops)
132{
133	struct inode *inode = mapping->host;
134	loff_t pos = bno << inode->i_blkbits;
135	unsigned blocksize = i_blocksize(inode);
 
 
 
 
 
136
137	if (filemap_write_and_wait(mapping))
138		return 0;
139
140	bno = 0;
141	iomap_apply(inode, pos, blocksize, 0, ops, &bno, iomap_bmap_actor);
 
 
 
 
 
 
 
142	return bno;
143}
144EXPORT_SYMBOL_GPL(iomap_bmap);