summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/driver-api/index.rst1
-rw-r--r--Documentation/driver-api/loop-file-fmt.rst135
-rw-r--r--drivers/block/loop/loop_file_fmt.h231
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);