diff options
-rw-r--r-- | Documentation/driver-api/index.rst | 1 | ||||
-rw-r--r-- | Documentation/driver-api/loop-file-fmt.rst | 135 | ||||
-rw-r--r-- | drivers/block/loop/loop_file_fmt.h | 231 |
3 files changed, 364 insertions, 3 deletions
diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index d12a80f386a6..605a3a398ce3 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -51,6 +51,7 @@ available subsections can be seen below. mmc/index nvdimm/index w1 + loop-file-fmt rapidio/index s390-drivers vme diff --git a/Documentation/driver-api/loop-file-fmt.rst b/Documentation/driver-api/loop-file-fmt.rst new file mode 100644 index 000000000000..335fde30f364 --- /dev/null +++ b/Documentation/driver-api/loop-file-fmt.rst @@ -0,0 +1,135 @@ +=========================================== +Loopback block device file format subsystem +=========================================== + +This document outlines the file format subsystem used in the loopback block +device module. This subsystem deals with the abstraction of direct file access +to allow the implementation of various disk file formats. The subsystem can +handle ... + + - read + - write + - discard + - flush + - sector size + +... operations of a loop device. + +Therefore, the subsystem provides an internal API for the loop device module to +access its functionality and exports a file format driver API to implement any +file format driver for loop devices. + + +Use the file format subsystem +============================= + +At the moment, the file format subsystem is only intended to be used from the +loopback device module to provide a specific file format implementation per +configured loop device. Therefore, the loop device module can use the following +internal file format API functions to set up loop file formats and access the +file format subsystem. + + +Internal subsystem API +---------------------- + +.. kernel-doc:: drivers/block/loop/loop_file_fmt.h + :functions: loop_file_fmt_alloc loop_file_fmt_free \ + loop_file_fmt_set_lo loop_file_fmt_get_lo + loop_file_fmt_init loop_file_fmt_exit \ + loop_file_fmt_read loop_file_fmt_read_aio \ + loop_file_fmt_write loop_file_fmt_write_aio \ + loop_file_fmt_discard loop_file_fmt_flush \ + loop_file_fmt_sector_size loop_file_fmt_change + + +Finite state machine +-------------------- + +To prevent a misuse of the internal file format API, the file format subsystem +implements an finite state machine. The state machine consists of two states +and a transition for each internal API function. The state +*file_fmt_uninitialized* of a loop file format denotes that the file format is +already allocated but not initialized. After the initialization, the file +format's state is set to *file_fmt_initialized*. In this state, all IO related +file format operations can be accessed. + +.. note:: If an internal API call does not succeed the file format's state \ + does not change accordingly to its transition and remains in the \ + original state before the API call. + +The entire implemented finite state machine looks like the following: + +.. kernel-render:: DOT + :alt: loop file format states + :caption: File format states and transitions + + digraph file_fmt_states { + rankdir = LR; + node [ shape = point, label = "" ] ENTRY, EXIT; + node [ shape = circle, label = "file_fmt_uninitialized" ] UN; + node [ shape = doublecircle, label = "file_fmt_initialized" ] IN; + subgraph helper { + rank = "same"; + ENTRY -> UN [ label = "loop_file_fmt_alloc()" ]; + UN -> EXIT [ label = "loop_file_fmt_free()" ]; + } + UN -> IN [ label = "loop_file_fmt_init()" ]; + IN -> UN [ label = "loop_file_fmt_exit()" ]; + IN -> IN [ label = "loop_file_fmt_read()\nloop_file_fmt_read_aio()\nloop_file_fmt_write()\n loop_file_fmt_write_aio()\nloop_file_fmt_discard()\nloop_file_fmt_flush()\nloop_file_fmt_sector_size()\nloop_file_fmt_change()" ]; + } + + +Write file format drivers +========================= + +A file format driver for the loop file format subsystem is implemented as +kernel module. In the kernel module's code, the file format driver structure is +statically allocated and must be initialized. An example definition would look +like:: + + struct loop_file_fmt_driver raw_file_fmt_driver = { + .name = "RAW", + .file_fmt_type = LO_FILE_FMT_RAW, + .ops = &raw_file_fmt_ops, + .owner = THIS_MODULE + }; + +The definition assigns a *name* to the file format driver. The *file_fmt_type* +field is set to the file format type that the driver implements. The *owner* +specifies the driver's owner and is used to lock the kernel module of the +driver if the file format driver is in use. The most important field of a loop +file format driver is the specification of its implementation. Therefore, the +*ops* field proposes all file format operations that the driver implement by +link to a statically allocated operations structure. + +.. note:: All fields of the **loop_file_fmt_driver** structure must be \ + initialized and set up accordingly, otherwise the driver does not \ + work properly. + +An example of such an operations structure looks like:: + + struct loop_file_fmt_ops raw_file_fmt_ops = { + .init = NULL, + .exit = NULL, + .read = raw_file_fmt_read, + .write = raw_file_fmt_write, + .read_aio = raw_file_fmt_read_aio, + .write_aio = raw_file_fmt_write_aio, + .discard = raw_file_fmt_discard, + .flush = raw_file_fmt_flush, + .sector_size = raw_file_fmt_sector_size + }; + +The operations structure consists of a bunch of functions pointers which are +set in this example to some functions of the binary raw disk file format +implemented in the example driver. If a function is not available in the +driver's implementation the function pointer in the operations structure must +be set to *NULL*. + +If all definitions are available and set up correctly the driver can be +registered and later on unregistered by using the following functions exported +by the file format subsystem: + +.. kernel-doc:: drivers/block/loop/loop_file_fmt.h + :functions: loop_file_fmt_register_driver loop_file_fmt_unregister_driver diff --git a/drivers/block/loop/loop_file_fmt.h b/drivers/block/loop/loop_file_fmt.h index 208c8f7cbc31..cd62dee60bf7 100644 --- a/drivers/block/loop/loop_file_fmt.h +++ b/drivers/block/loop/loop_file_fmt.h @@ -14,32 +14,88 @@ struct loop_file_fmt; -/* data structure representing the file format subsystem interface */ +/** + * struct loop_file_fmt_ops - File format subsystem operations + * + * Data structure representing the file format subsystem interface. + */ struct loop_file_fmt_ops { + /** + * @init: Initialization callback function + */ int (*init) (struct loop_file_fmt *lo_fmt); + + /** + * @exit: Release callback function + */ void (*exit) (struct loop_file_fmt *lo_fmt); + /** + * @read: Read IO callback function + */ int (*read) (struct loop_file_fmt *lo_fmt, struct request *rq); + + /** + * @write: Write IO callback function + */ int (*write) (struct loop_file_fmt *lo_fmt, struct request *rq); + + /** + * @read_aio: Asynchronous read IO callback function + */ int (*read_aio) (struct loop_file_fmt *lo_fmt, struct request *rq); + + /** + * @write_aio: Asynchronous write IO callback function + */ int (*write_aio) (struct loop_file_fmt *lo_fmt, struct request *rq); + + /** + * @discard: Discard IO callback function + */ int (*discard) (struct loop_file_fmt *lo_fmt, struct request *rq); + /** + * @flush: Flush callback function + */ int (*flush) (struct loop_file_fmt *lo_fmt); + /** + * @sector_size: Get sector size callback function + */ loff_t (*sector_size) (struct loop_file_fmt *lo_fmt); }; -/* data structure for implementing file format drivers */ +/** + * struct loop_file_fmt_driver - File format subsystem driver + * + * Data structure to implement file format drivers for the file format + * subsystem. + */ struct loop_file_fmt_driver { + /** + * @name: Name of the file format driver + */ const char *name; + + /** + * @file_fmt_type: Loop file format type of the file format driver + */ const u32 file_fmt_type; + + /** + * @ops: Driver's implemented file format operations + */ struct loop_file_fmt_ops *ops; + + /** + * @ops: Owner of the file format driver + */ struct module *owner; }; @@ -77,49 +133,218 @@ enum { file_fmt_initialized }; -/* data structure for using with the file format subsystem */ +/** + * struct loop_file_fmt - Loop file format + * + * Data structure to use with the file format the loop file format subsystem. + */ struct loop_file_fmt { + /** + * @file_fmt_type: Current type of the loop file format + */ u32 file_fmt_type; + + /** + * @file_fmt_state: Current state of the loop file format + */ int file_fmt_state; + + /** + * @lo: Link to a file format's loop device + */ struct loop_device *lo; + + /** + * @private_data: Optional link to a file format's driver specific data + */ void *private_data; }; + /* subsystem functions for the driver implementation */ + +/** + * loop_file_fmt_register_driver - Register a loop file format driver + * @drv: File format driver + * + * Registers the specified loop file format driver @drv by the loop file format + * subsystem. + */ extern int loop_file_fmt_register_driver(struct loop_file_fmt_driver *drv); + +/** + * loop_file_fmt_unregister_driver - Unregister a loop file format driver + * @drv: File format driver + * + * Unregisters the specified loop file format driver @drv from the loop file + * format subsystem. + */ extern void loop_file_fmt_unregister_driver(struct loop_file_fmt_driver *drv); + /* subsystem functions for subsystem usage */ + +/** + * loop_file_fmt_alloc - Allocate a loop file format + * + * Dynamically allocates a loop file format and returns a pointer to the + * created loop file format. + */ extern struct loop_file_fmt *loop_file_fmt_alloc(void); + +/** + * loop_file_fmt_free - Free an allocated loop file format + * @lo_fmt: Loop file format + * + * Frees the already allocated loop file format @lo_fmt. + */ extern void loop_file_fmt_free(struct loop_file_fmt *lo_fmt); +/** + * loop_file_fmt_set_lo - Set the loop file format's loop device + * @lo_fmt: Loop file format + * @lo: Loop device + * + * The link to the loop device @lo is set in the loop file format @lo_fmt. + */ extern int loop_file_fmt_set_lo(struct loop_file_fmt *lo_fmt, struct loop_device *lo); + +/** + * loop_file_fmt_get_lo - Get the loop file format's loop device + * @lo_fmt: Loop file format + * + * Returns a pointer to the loop device of the loop file format @lo_fmt. + */ extern struct loop_device *loop_file_fmt_get_lo(struct loop_file_fmt *lo_fmt); +/** + * loop_file_fmt_init - Initialize a loop file format + * @lo_fmt: Loop file format + * @file_fmt_type: Type of the file format + * + * Initializes the specified loop file format @lo_fmt and sets up the correct + * file format type @file_fmt_type. Depending on @file_fmt_type, the correct + * loop file format driver is loaded in the subsystems backend. If no loop file + * format driver for the specified file format is available an error is + * returned. + */ extern int loop_file_fmt_init(struct loop_file_fmt *lo_fmt, u32 file_fmt_type); + +/** + * loop_file_fmt_exit - Release a loop file format + * @lo_fmt: Loop file format + * + * Releases the specified loop file format @lo_fmt and all its resources. + */ extern void loop_file_fmt_exit(struct loop_file_fmt *lo_fmt); +/** + * loop_file_fmt_read - Read IO from a loop file format + * @lo_fmt: Loop file format + * @rq: IO Request + * + * Reads IO from the file format's loop device by sending the IO read request + * @rq to the loop file format subsystem. The subsystem calls the registered + * callback function of the suitable loop file format driver. + */ extern int loop_file_fmt_read(struct loop_file_fmt *lo_fmt, struct request *rq); + +/** + * loop_file_fmt_read_aio - Read IO from a loop file format asynchronously + * @lo_fmt: Loop file format + * @rq: IO Request + * + * Reads IO from the file format's loop device asynchronously by sending the + * IO read aio request @rq to the loop file format subsystem. The subsystem + * calls the registered callback function of the suitable loop file format + * driver. + */ extern int loop_file_fmt_read_aio(struct loop_file_fmt *lo_fmt, struct request *rq); + +/** + * loop_file_fmt_write - Write IO to a loop file format + * @lo_fmt: Loop file format + * @rq: IO Request + * + * Write IO to the file format's loop device by sending the IO write request + * @rq to the loop file format subsystem. The subsystem calls the registered + * callback function of the suitable loop file format driver. + */ extern int loop_file_fmt_write(struct loop_file_fmt *lo_fmt, struct request *rq); + +/** + * loop_file_fmt_write_aio - Write IO to a loop file format asynchronously + * @lo_fmt: Loop file format + * @rq: IO Request + * + * Write IO to the file format's loop device asynchronously by sending the + * IO write aio request @rq to the loop file format subsystem. The subsystem + * calls the registered callback function of the suitable loop file format + * driver. + */ extern int loop_file_fmt_write_aio(struct loop_file_fmt *lo_fmt, struct request *rq); + +/** + * loop_file_fmt_discard - Discard IO on a loop file format + * @lo_fmt: Loop file format + * @rq: IO Request + * + * Discard IO on the file format's loop device by sending the IO discard + * request @rq to the loop file format subsystem. The subsystem calls the + * registered callback function of the suitable loop file format driver. + */ extern int loop_file_fmt_discard(struct loop_file_fmt *lo_fmt, struct request *rq); +/** + * loop_file_fmt_flush - Flush a loop file format + * @lo_fmt: Loop file format + * + * Flush the file format's loop device by calling the registered callback + * function of the suitable loop file format driver. + */ extern int loop_file_fmt_flush(struct loop_file_fmt *lo_fmt); +/** + * loop_file_fmt_sector_size - Get sector size of a loop file format + * @lo_fmt: Loop file format + * + * Returns the physical sector size of the loop file format's loop device. + * If the loop file format implements a sparse disk image format, then this + * function returns the virtual sector size. + */ extern loff_t loop_file_fmt_sector_size(struct loop_file_fmt *lo_fmt); +/** + * loop_file_fmt_change - Change the loop file format's type + * @lo_fmt: Loop file format + * @file_fmt_type_new: Loop file format type + * + * Changes the file format type of the already initialized loop file format + * @lo_fmt. Therefore, the function releases the old file format and frees all + * of its resources before the loop file format @lo_fmt is initialized and set + * up with the new file format @file_fmt_type_new. + */ extern int loop_file_fmt_change(struct loop_file_fmt *lo_fmt, u32 file_fmt_type_new); + /* helper functions of the subsystem */ + +/** + * loop_file_fmt_print_type - Convert file format type to string + * @file_fmt_type: Loop file format type + * @file_fmt_name: Loop file format type string + * + * Converts the specified numeric @file_fmt_type value into a human readable + * string stating the file format as string in @file_fmt_name. + */ extern ssize_t loop_file_fmt_print_type(u32 file_fmt_type, char *file_fmt_name); |