xref: /linux/drivers/md/persistent-data/dm-block-manager.h (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
13bd94003SHeinz Mauelshagen /* SPDX-License-Identifier: GPL-2.0-only */
23241b1d3SJoe Thornber /*
33241b1d3SJoe Thornber  * Copyright (C) 2011 Red Hat, Inc.
43241b1d3SJoe Thornber  *
53241b1d3SJoe Thornber  * This file is released under the GPL.
63241b1d3SJoe Thornber  */
73241b1d3SJoe Thornber 
83241b1d3SJoe Thornber #ifndef _LINUX_DM_BLOCK_MANAGER_H
93241b1d3SJoe Thornber #define _LINUX_DM_BLOCK_MANAGER_H
103241b1d3SJoe Thornber 
113241b1d3SJoe Thornber #include <linux/types.h>
123241b1d3SJoe Thornber #include <linux/blkdev.h>
133241b1d3SJoe Thornber 
143241b1d3SJoe Thornber /*----------------------------------------------------------------*/
153241b1d3SJoe Thornber 
163241b1d3SJoe Thornber /*
173241b1d3SJoe Thornber  * Block number.
183241b1d3SJoe Thornber  */
193241b1d3SJoe Thornber typedef uint64_t dm_block_t;
203241b1d3SJoe Thornber struct dm_block;
213241b1d3SJoe Thornber 
223241b1d3SJoe Thornber dm_block_t dm_block_location(struct dm_block *b);
233241b1d3SJoe Thornber void *dm_block_data(struct dm_block *b);
243241b1d3SJoe Thornber 
253241b1d3SJoe Thornber /*----------------------------------------------------------------*/
263241b1d3SJoe Thornber 
273241b1d3SJoe Thornber /*
283241b1d3SJoe Thornber  * @name should be a unique identifier for the block manager, no longer
293241b1d3SJoe Thornber  * than 32 chars.
303241b1d3SJoe Thornber  *
313241b1d3SJoe Thornber  * @max_held_per_thread should be the maximum number of locks, read or
323241b1d3SJoe Thornber  * write, that an individual thread holds at any one time.
333241b1d3SJoe Thornber  */
343241b1d3SJoe Thornber struct dm_block_manager;
353241b1d3SJoe Thornber struct dm_block_manager *dm_block_manager_create(
3686a3238cSHeinz Mauelshagen 	struct block_device *bdev, unsigned int block_size,
3786a3238cSHeinz Mauelshagen 	unsigned int max_held_per_thread);
383241b1d3SJoe Thornber void dm_block_manager_destroy(struct dm_block_manager *bm);
39d4830012SLi Lingfeng void dm_block_manager_reset(struct dm_block_manager *bm);
403241b1d3SJoe Thornber 
4186a3238cSHeinz Mauelshagen unsigned int dm_bm_block_size(struct dm_block_manager *bm);
423241b1d3SJoe Thornber dm_block_t dm_bm_nr_blocks(struct dm_block_manager *bm);
433241b1d3SJoe Thornber 
443241b1d3SJoe Thornber /*----------------------------------------------------------------*/
453241b1d3SJoe Thornber 
463241b1d3SJoe Thornber /*
473241b1d3SJoe Thornber  * The validator allows the caller to verify newly-read data and modify
483241b1d3SJoe Thornber  * the data just before writing, e.g. to calculate checksums.  It's
493241b1d3SJoe Thornber  * important to be consistent with your use of validators.  The only time
503241b1d3SJoe Thornber  * you can change validators is if you call dm_bm_write_lock_zero.
513241b1d3SJoe Thornber  */
523241b1d3SJoe Thornber struct dm_block_validator {
533241b1d3SJoe Thornber 	const char *name;
54*0b60be16SChristophe JAILLET 	void (*prepare_for_write)(const struct dm_block_validator *v,
55*0b60be16SChristophe JAILLET 				  struct dm_block *b, size_t block_size);
563241b1d3SJoe Thornber 
573241b1d3SJoe Thornber 	/*
583241b1d3SJoe Thornber 	 * Return 0 if the checksum is valid or < 0 on error.
593241b1d3SJoe Thornber 	 */
60*0b60be16SChristophe JAILLET 	int (*check)(const struct dm_block_validator *v,
61*0b60be16SChristophe JAILLET 		     struct dm_block *b, size_t block_size);
623241b1d3SJoe Thornber };
633241b1d3SJoe Thornber 
643241b1d3SJoe Thornber /*----------------------------------------------------------------*/
653241b1d3SJoe Thornber 
663241b1d3SJoe Thornber /*
673241b1d3SJoe Thornber  * You can have multiple concurrent readers or a single writer holding a
683241b1d3SJoe Thornber  * block lock.
693241b1d3SJoe Thornber  */
703241b1d3SJoe Thornber 
713241b1d3SJoe Thornber /*
723241b1d3SJoe Thornber  * dm_bm_lock() locks a block and returns through @result a pointer to
733241b1d3SJoe Thornber  * memory that holds a copy of that block.  If you have write-locked the
743241b1d3SJoe Thornber  * block then any changes you make to memory pointed to by @result will be
753241b1d3SJoe Thornber  * written back to the disk sometime after dm_bm_unlock is called.
763241b1d3SJoe Thornber  */
773241b1d3SJoe Thornber int dm_bm_read_lock(struct dm_block_manager *bm, dm_block_t b,
78*0b60be16SChristophe JAILLET 		    const struct dm_block_validator *v,
793241b1d3SJoe Thornber 		    struct dm_block **result);
803241b1d3SJoe Thornber 
813241b1d3SJoe Thornber int dm_bm_write_lock(struct dm_block_manager *bm, dm_block_t b,
82*0b60be16SChristophe JAILLET 		     const struct dm_block_validator *v,
833241b1d3SJoe Thornber 		     struct dm_block **result);
843241b1d3SJoe Thornber 
853241b1d3SJoe Thornber /*
863241b1d3SJoe Thornber  * The *_try_lock variants return -EWOULDBLOCK if the block isn't
873241b1d3SJoe Thornber  * available immediately.
883241b1d3SJoe Thornber  */
893241b1d3SJoe Thornber int dm_bm_read_try_lock(struct dm_block_manager *bm, dm_block_t b,
90*0b60be16SChristophe JAILLET 			const struct dm_block_validator *v,
913241b1d3SJoe Thornber 			struct dm_block **result);
923241b1d3SJoe Thornber 
933241b1d3SJoe Thornber /*
943241b1d3SJoe Thornber  * Use dm_bm_write_lock_zero() when you know you're going to
953241b1d3SJoe Thornber  * overwrite the block completely.  It saves a disk read.
963241b1d3SJoe Thornber  */
973241b1d3SJoe Thornber int dm_bm_write_lock_zero(struct dm_block_manager *bm, dm_block_t b,
98*0b60be16SChristophe JAILLET 			  const struct dm_block_validator *v,
993241b1d3SJoe Thornber 			  struct dm_block **result);
1003241b1d3SJoe Thornber 
1014c7da06fSMikulas Patocka void dm_bm_unlock(struct dm_block *b);
1023241b1d3SJoe Thornber 
1033241b1d3SJoe Thornber /*
1043241b1d3SJoe Thornber  * It's a common idiom to have a superblock that should be committed last.
1053241b1d3SJoe Thornber  *
1063241b1d3SJoe Thornber  * @superblock should be write-locked on entry. It will be unlocked during
1073241b1d3SJoe Thornber  * this function.  All dirty blocks are guaranteed to be written and flushed
1083241b1d3SJoe Thornber  * before the superblock.
1093241b1d3SJoe Thornber  *
1103241b1d3SJoe Thornber  * This method always blocks.
1113241b1d3SJoe Thornber  */
112a9d45396SJoe Thornber int dm_bm_flush(struct dm_block_manager *bm);
1133241b1d3SJoe Thornber 
11404f17c80SJoe Thornber /*
1159b7aaa64SJoe Thornber  * Request data is prefetched into the cache.
11604f17c80SJoe Thornber  */
11704f17c80SJoe Thornber void dm_bm_prefetch(struct dm_block_manager *bm, dm_block_t b);
11804f17c80SJoe Thornber 
11931097557SJoe Thornber /*
12031097557SJoe Thornber  * Switches the bm to a read only mode.  Once read-only mode
12131097557SJoe Thornber  * has been entered the following functions will return -EPERM.
12231097557SJoe Thornber  *
12331097557SJoe Thornber  *   dm_bm_write_lock
12431097557SJoe Thornber  *   dm_bm_write_lock_zero
12531097557SJoe Thornber  *   dm_bm_flush_and_unlock
12631097557SJoe Thornber  *
12731097557SJoe Thornber  * Additionally you should not use dm_bm_unlock_move, however no error will
12831097557SJoe Thornber  * be returned if you do.
12931097557SJoe Thornber  */
13049f154c7SMike Snitzer bool dm_bm_is_read_only(struct dm_block_manager *bm);
13131097557SJoe Thornber void dm_bm_set_read_only(struct dm_block_manager *bm);
1329b7aaa64SJoe Thornber void dm_bm_set_read_write(struct dm_block_manager *bm);
13331097557SJoe Thornber 
1343241b1d3SJoe Thornber u32 dm_bm_checksum(const void *data, size_t len, u32 init_xor);
1353241b1d3SJoe Thornber 
1363241b1d3SJoe Thornber /*----------------------------------------------------------------*/
1373241b1d3SJoe Thornber 
1383241b1d3SJoe Thornber #endif	/* _LINUX_DM_BLOCK_MANAGER_H */
139