* fuse_tcmur - access tcmu-runner devices through a fuse mount
@ 2019-07-23 21:01 David Butterfield
0 siblings, 0 replies; only message in thread
From: David Butterfield @ 2019-07-23 21:01 UTC (permalink / raw)
To: target-devel
[-- Attachment #1: Type: text/plain, Size: 4159 bytes --]
DESCRIPTION
fuse_tcmur provides access to tcmu-runner devices through a fuse(8) mount.
Each tcmu-runner device is represented by a node in the fuse filesystem
tree. The devices can be accessed via the nodes, for example with dd(1),
and can be mounted as filesystems.
The diagram shows the components of the fuse_tcmur program (to the right of
kernel). fuse_tcmur sits in the middle, providing a main program and the
translation between fuse operations and tcmu-runner handler operations.
fuse_tree is a simple tree-structure implemented on libfuse. Like /proc,
the existence of nodes in the tree is controlled only by the server, not
through filesystem operations. But individual leaf nodes may be readable
and/or writable through the filesystem depending on permissions.
.--fuse_operations
|
/tcmur <==> kernel <==> libfuse <==> fuse_tree
^ |
-errno | | fuse_node_ops
\V
fuse_tcmur
^ |
cmd->done | | calls to tcmur_*
| V
libtcmur <==> tcmur-handler
tcmur-handler is one of the binaries in /usr/local/lib/tcmu-runner/.
libtcmur is a usermode API to the loadable tcmu-runner handlers. LIO, TCMU,
and tcmur-runner are uninvolved -- libtcmur only loads and uses the
handlers, and only the block-I/O entry points are called (not handle_cmd).
fuse_tree(3) and libtcmur(3) are independent -- each usable for its purpose
without reference to the other. In the middle is fuse_tcmur, which links
them together, and consists of three parts:
The main() program initializes the other parts and calls fuse_main().
The fuse_tcmur part translates I/O requests between fuse and libtcmur.
The fuse_tcmur_ctl part interprets commands written to a node in the
fuse filesystem -- commands can be written with cat(1) or echo(1) to
/tcmur/dev/tcmur.
FILES
When a handler is loaded, an empty directory node appears for it in
/tcmur/sys/modules
When a device is added, a node appears in /tcmur/dev/<subtype><minornumber>
The /tcmur/dev nodes appear as regular files (rather than block devices),
but they can still be mounted as filesystems, e.g.
sudo mount /tcmur/dev/ram000 /mnt/k
NOTES
The source is in the libtcmur branch (default) at
https://github.com/DavidButterfield/tcmu-runner.git
First make in the main tcmu-runner directory, to get version.h and the binary
handlers:
cmake .
make
sudo make install
Then cd into the libtcmur subdirectory where there is a hacked-up makefile
that creates the fuse_tcmur binary. Today there are no dependencies
computed, so always
make clean; make
The program will attempt to create the mount-point directory that fuse will
mount on. This will succeed if the program is run as superuser; otherwise
you can create it manually first with
sudo mkdir /tcmur
The server presently runs only one thread. Despite this, the time for a
script to download a few repositories and build a software package is only a
few percent longer through the fuse mount to a tcmu-runner ramdisk, as
compared with a regular kernel filesystem mount to my home directory
spinning disk. (Not an optimal comparison, but it's what I have at hand.)
BUGS
No doubt. This code was born in July 2019. The makefile leaves much to be
desired.
So far I have only tested it using handler_ram.so, because that's the
handler that can be used without figuring out how to install and run
sophisticated back-end software.
SEE ALSO
fuse_tree(3), libtcmur(3), fuse(8), tcmu-runner(8)
AUTHOR
David A. Butterfield
Manpage updated 23 Jul 2019
[-- Attachment #2: fuse_tcmur.1 --]
[-- Type: text/plain, Size: 4880 bytes --]
fuse_tcmur(1) User Commands fuse_tcmur(1)
NAME
fuse_tcmur - access tcmu-runner devices through a fuse mount
SYNOPSIS
fuse_tcmur
echo "command" > /tcmur/dev/tcmur
Commands:
load subtype # load tcmu-runner handler for subtype
unload subtype
add minornumber /subtype/handler-cfg-string
remove minornumber
help
source command-file-name # read commands from file
dump # dump the fuse tree structure
DESCRIPTION
fuse_tcmur provides access to tcmu-runner devices through a fuse(8) mount.
Each tcmu-runner device is represented by a node in the fuse filesystem
tree. The devices can be accessed via the nodes, for example with dd(1),
and can be mounted as filesystems.
Each tcmu device is denoted by a unique minor number, which is specified
when the device is added. All tcmu-runner handlers share one minor-space.
The diagram shows the components of the fuse_tcmur program (to the right of
kernel). fuse_tcmur sits in the middle, providing a main program and the
translation between fuse operations and tcmu-runner handler operations.
fuse_tree is a simple tree-structure implemented on libfuse. Like /proc,
the existence of nodes in the tree is controlled only by the server, not
through filesystem operations. But individual leaf nodes may be readable
and/or writable through the filesystem depending on permissions.
.--fuse_operations
|
/tcmur <==> kernel <==> libfuse <==> fuse_tree
^ |
-errno | | fuse_node_ops
\V
fuse_tcmur
^ |
cmd->done | | calls to tcmur_*
| V
libtcmur <==> tcmur-handler
tcmur-handler is one of the binaries in /usr/local/lib/tcmu-runner/.
libtcmur is a usermode API to the loadable tcmu-runner handlers. LIO, TCMU,
and tcmur-runner are uninvolved -- libtcmur only loads and uses the
handlers, and only the block-I/O entry points are called (not handle_cmd).
fuse_tree(3) and libtcmur(3) are independent -- each usable for its purpose
without reference to the other. In the middle is fuse_tcmur, which links
them together, and consists of three parts:
The main() program initializes the other parts and calls fuse_main().
The fuse_tcmur part translates I/O requests between fuse and libtcmur.
The fuse_tcmur_ctl part interprets commands written to a node in the
fuse filesystem -- commands can be written with cat(1) or echo(1) to
/tcmur/dev/tcmur.
FILES
When a handler is loaded, an empty directory node appears for it in
/tcmur/sys/modules
When a device is added, a node appears in /tcmur/dev/<subtype><minornumber>
The /tcmur/dev nodes appear as regular files (rather than block devices),
but they can still be mounted as filesystems, e.g.
sudo mount /tcmur/dev/ram000 /mnt/k
NOTES
The source is in the libtcmur branch (default) at
https://github.com/DavidButterfield/tcmu-runner.git
First make in the main tcmu-runner directory, to get version.h and the binary
handlers:
cmake .
make
sudo make install
Then cd into the libtcmur subdirectory where there is a hacked-up makefile
that creates the fuse_tcmur binary. Today there are no dependencies
computed, so always
make clean; make
The program will attempt to create the mount-point directory that fuse will
mount on. This will succeed if the program is run as superuser; otherwise
you can create it manually first with
sudo mkdir /tcmur
The server presently runs only one thread. Despite this, the time for a
script to download a few repositories and build a software package is only a
few percent longer through the fuse mount to a tcmu-runner ramdisk, as
compared with a regular kernel filesystem mount to my home directory
spinning disk. (Not an optimal comparison, but it's what I have at hand.)
BUGS
No doubt. This code was born in July 2019. The makefile leaves much to be
desired.
So far I have only tested it using handler_ram.so, because that's the
handler that can be used without figuring out how to install and run
sophisticated back-end software.
SEE ALSO
fuse_tree(3), libtcmur(3), fuse(8), tcmu-runner(8)
AUTHOR
David A. Butterfield
Manpage updated 23 Jul 2019
[-- Attachment #3: fuse_tree.3 --]
[-- Type: text/plain, Size: 4484 bytes --]
fuse_tree(3) Linux Programmer's Manual fuse_tree(3)
NAME
fuse_tree -- API to fuse filesystem tree
SYNOPSIS
#include "fuse_tree.h"
error_t fuse_tree_init(const char * mountpoint);
error_t fuse_tree_exit(void);
error_t fuse_loop_run(void * unused);
fuse_node_t fuse_node_add(
const char * name, fuse_node_t parent, mode_t,
const struct fuse_node_ops *, uintptr_t data);
error_t fuse_node_remove(const char * name , fuse_node_t parent);
fuse_node_t fuse_tree_mkdir(const char * name, fuse_node_t parent);
error_t fuse_tree_rmdir(const char * name, fuse_node_t parent);
fuse_node_t fuse_node_lookup(const char * path);
uintptr_t fuse_node_data_get(fuse_node_t);
void fuse_node_update_mode(fuse_node_t, mode_t);
void fuse_node_update_size(fuse_node_t, size_t);
void fuse_node_update_mtime(fuse_node_t);
char * fuse_tree_fmt(void);
DESCRIPTION
fuse_tree maintains a filesystem tree, implementing fuse_operations. Like
/proc, the tree itself is managed internally by the application -- there is
no creation of files or directories through system calls on the mounted fuse
filesystem.
However, also like /proc, individual files represented in the tree may be
readable and/or writable through the mounted filesystem, depending on
permissions.
When adding a node to the tree, the application can supply a fuse_node_ops
vector specifying functions to be called to back filesystem operations on the
node. The struct fuse_node_ops includes these members, all of which are
optional to fill in:
int (*open) (fuse_node_t, uintptr_t data);
int (*release)(fuse_node_t, uintptr_t data);
int (*fsync) (uintptr_t data, int datasync);
ssize_t (*read) (uintptr_t data, void * buf, size_t, loff_t);
ssize_t (*write) (uintptr_t data, const char * buf, size_t, loff_t);
fuse_tree_init() should be called before any of the other calls described
here, passing the path to the mount point to be used for the fuse mount.
fuse_tree_exit() should be called last after any other calls described here.
fuse_loop_run() should be called to run fuse_main().
fuse_node_add() adds a node with the given name under the given parent node.
fuse_node_remove() removes it. The last "data" argument is private to the caller
and is passed to the fuse_node_ops callback functions.
fuse_tree_mkdir() creates a new child directory fuse_node with the specified
name under the specified parent fuse_node. fuse_tree_rmdir() removes it.
fuse_node_lookup() returns a pointer to the fuse_node representing the path
string. Path string is the full path from the fuse mount, starting with '/'.
fuse_node_data_get() returns the private data specified to fuse_node_add.
fuse_node_update_mode() updates the fuse_node's mode permissions.
fuse_node_update_size() updates the fuse_node's size in bytes.
fuse_node_update_mtime() updates the fuse_node's modification time to the
present.
fuse_tree_fmt() returns a human-readable string representing the fuse tree.
The string should be freed by the caller when done with it.
RETURN VALUE
Upon successful completion, functions returning type error_t return zero.
Failures return -errno.
fuse_node_add() and fuse_tree_mkdir() each return a pointer to the new
fuse_node, or NULL on error.
fuse_node_lookup() returns a pointer to the fuse_node, or NULL if the path
is not found.
fuse_tree_fmt() returns a freeable human-readable debugging string
representing the fuse tree.
ERRORS
fnode_remove()
-EBUSY fuse_node is open by some process through the fuse FS
-ENOENT named fnode not found under parent
fuse_tree_rmdir()
-ENOENT named fnode not found under parent
-ENOTEMPTY directory node is not empty
fuse_tree_init()
-EINVAL mountpoint does not start with '/', or it ends in '/'
fuse_tree_exit()
-EBUSY root node still has child(ren)
fuse_loop_run()
errors returned by fuse_main()
errors returned by asprintf()
NOTES
BUGS
fuse_node_lookup() should hold the returned node, and a new function should
be added to drop it.
There should be a threading option passed to fuse_loop_run(). At present
it always runs fuse single-threaded.
SEE ALSO
fuse(8)
AUTHOR
David A. Butterfield
Manpage updated 23 Jul 2019
[-- Attachment #4: libtcmur.3 --]
[-- Type: text/plain, Size: 6547 bytes --]
libtcmur(3) Linux Programmer's Manual libtcmur(3)
NAME
libtcmur -- usermode API to tcmu-runner block storage handlers
SYNOPSIS
#include "libtcmur.h"
error_t libtcmur_init(const char * handler_prefix);
error_t libtcmur_exit(void);
error_t tcmur_handler_load(const char * subtype);
error_t tcmur_handler_unload(const char * subtype);
error_t tcmur_check_config(char const * cfgstring);
error_t tcmur_device_add(int minor, const char * cfgstring);
error_t tcmur_device_remove(int minor);
error_t tcmur_read(int minor, struct tcmulib_cmd *,
struct iovec *, size_t niov, size_t, loff_t);
error_t tcmur_write(int minor, struct tcmulib_cmd *,
struct iovec *, size_t niov, size_t, loff_t);
error_t tcmur_flush(int minor, struct tcmulib_cmd *);
ssize_t tcmur_get_size(int minor);
ssize_t tcmur_get_block_size(int minor);
ssize_t tcmur_get_max_xfer(int minor);
const char * tcmur_get_dev_name(int minor);
DESCRIPTION
libtcmur provides a usermode application programming interface to access
block storage services through tcmu-runner block storage handlers.
Note that LIO, TCMU and tcmu-runner are uninvolved -- libtcmur only calls
the tcmu-runner loadable storage handlers, e.g. qcow, glfs, ram, etc.
libtcmur makes use of the handler read, write, and flush block I/O
functions only -- no calls are made to handle_cmd().
Functions returning type error_t return zero for success, otherwise -errno.
Call libtcmur_init() once before using libtcmur services. If handler_prefix
is NULL, the default is used: "/usr/local/lib/tcmu-runner/handler_". The
expected handler paths are the concatenation of:
handler_prefix tcmu_subtype ".so"
Call libtcmur_exit() once last, after any other functions described here.
tcmur_handler_load() will dlopen() a tcmu-runner handler of the given
subtype and load it into the program for use. tcmur_handler_unload()
unloads it.
tcmur_check_config() checks a handler device configuration string for
validity. The handler for the configuration must already have been loaded
using tcmur_handler_load(). cfgstring takes this form, specifying the
handler's TCMU subtype:
/subtype/handler-cfg-string
See tcmu-runner(8) for more about subtype and handler-cfg-string.
tcmur_device_add() adds a device, with specified cfgstring, as the
specified tcmur minor number. tcmur_device_remove() removes the specified
minor. The handler is determined from the subtype in the first segment of
cfgstring. All tcmur subtypes share a common space of minor numbers.
tcmur_read(), tcmur_write() and tcmur_flush() start I/O operations to the
specified minor. Errors in the I/O start process can be reported by -errno
return from these calls. A return value of zero denotes a successful I/O
start, in which case there will be a completion call to cmd->done(), which
may report either an "sts" error, or success (denoted by TCMU_STS_OK).
Note that the completion call may occur before the request call returns.
tcmur_read() and tcmur_write() take an iovec array with niov elements, an
I/O size in bytes, and a seek offset into the device where the I/O begins.
struct tcmulib_cmd includes this field, which must be set before passing
the command to tcmur_read(), tcmur_write(), or tcmur_flush():
cmd_done_t done; /* completion callback */
The callback function is of this type:
typedef
void (*cmd_done_t)(struct tcmu_device *, struct tcmulib_cmd *, int);
The third argument to the callback is TCMU status (see libtcmu_common.h).
tcmur_get_size() returns the size in bytes of the specified minor. If the
minor does not exist then the return is a -errno.
tcmur_get_block_size() returns the block size in bytes of the specified
minor. If the minor does not exist then the return is a -errno.
tcmur_get_max_xfer() returns the maximum I/O size in bytes of the specified
minor. If the minor does not exist then the return is a -errno.
tcmur_get_dev_name() returns the device name of the specified minor. If
the minor does not exist then the return is NULL.
RETURN VALUE
Upon successful completion, functions returning type error_t return zero.
All functions return -errno on failure, except tcmur_get_dev_name(), which
returns NULL in that case.
ERRORS
tcmur_read()
tcmur_write()
-ENODEV no device at specified minor (including minor out of range)
-ENXIO handler does not implement the requested function
-EINVAL I/O would exceed device bounds
-EIO I/O completed with nonzero "sts"
tcmur_flush()
-ENODEV no device at specified minor
-EIO I/O completed with nonzero "sts"
tcmur_get_size(), tcmur_get_block_size(), tcmur_get_max_xfer()
-ENODEV no device at specified minor
tcmur_device_add()
-ENODEV minor number out of range
-EBUSY minor number already in use by prior add
errors returned by tcmur_check_config()
errors returned by rhandler->open()
tcmur_device_remove()
-ENODEV no device at specified minor
tcmur_check_config()
-ENXIO no loaded handler subtype matches this config string
-EINVAL config string does not start with '/'
-EINVAL config string is too long
errors returned by rhandler->check_config()
tcmur_handler_load()
-EEXIST handler already loaded for the specified subtype
-ENOSPC all handler slots are in use
-ENOMEM failed to asprintf the handler path
-ENOENT failed to dlopen the handler path
-EBADF failed to dlsym("handler_init")
-EIO handler_init returned non-zero
tcmur_handler_unload()
-ENOENT no handler is loaded for the specified subtype
-EBUSY handler has existing devices (added but not removed)
libtcmur_exit()
-EBUSY a handler is still loaded
NOTES
BUGS
Not all symbols possibly referenced by handlers are implemented.
Some such symbols are "stubbed out" and print a warning if called.
Others do not exist, which will disallow loading of referencing handlers.
There is no check for an attempt to add the same device twice.
There is no generic way to specify the device size, block size, or maximum
I/O size.
libtcmur_exit() should auto-unload any handlers that have no devices
currently added.
SEE ALSO
tcmu-runner(8)
AUTHOR
David A. Butterfield
Manpage updated 23 Jul 2019
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2019-07-23 21:01 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-23 21:01 fuse_tcmur - access tcmu-runner devices through a fuse mount David Butterfield
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.