📄 fileio.sgml
字号:
<para>
The <structfield>f_ops</structfield> field contains a pointer to a
table of file I/O operations. This has the following structure:
</para>
<programlisting>
struct CYG_FILEOPS_TAG
{
int (*fo_read) (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
int (*fo_write) (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
int (*fo_lseek) (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
int (*fo_ioctl) (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
CYG_ADDRWORD data);
int (*fo_select) (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info);
int (*fo_fsync) (struct CYG_FILE_TAG *fp, int mode );
int (*fo_close) (struct CYG_FILE_TAG *fp);
int (*fo_fstat) (struct CYG_FILE_TAG *fp, struct stat *buf );
int (*fo_getinfo) (struct CYG_FILE_TAG *fp, int key, char *buf, int len );
int (*fo_setinfo) (struct CYG_FILE_TAG *fp, int key, char *buf, int len );
};
</programlisting>
<para>
It should be obvious from the names of most of these functions what
their responsibilities are. The <function>fo_getinfo()</function>
and <function>fo_setinfo()</function> function pointers, like their
counterparts in the filesystem structure, implement minor control and
info functions such as <function>fpathconf()</function>.
</para>
<para>
The second argument to the <function>fo_read()</function> and
<function>fo_write()</function> function pointers is a pointer to a
UIO structure:
</para>
<programlisting>
struct CYG_UIO_TAG
{
struct CYG_IOVEC_TAG *uio_iov; /* pointer to array of iovecs */
int uio_iovcnt; /* number of iovecs in array */
off_t uio_offset; /* offset into file this uio corresponds to */
ssize_t uio_resid; /* residual i/o count */
enum cyg_uio_seg uio_segflg; /* see above */
enum cyg_uio_rw uio_rw; /* see above */
};
struct CYG_IOVEC_TAG
{
void *iov_base; /* Base address. */
ssize_t iov_len; /* Length. */
};
</programlisting>
<para>
This structure encapsulates the parameters of any data transfer
operation. It provides support for scatter/gather operations and
records the progress of any data transfer. It is also compatible with
the I/O operations of any BSD-derived network stacks and filesystems.
</para>
<para>
When a file is opened (or a file object created by some other means,
such as <function>socket()</function> or <function>accept()</function>) it is the
responsibility of the filesystem open operation to initialize all the
fields of the object except the <structfield>f_ucount</structfield>,
<structfield>f_syncmode</structfield> and
<structfield>f_mte</structfield> fields. Since the
<structfield>f_flag</structfield> field will already contain bits belonging to the FILEIO
infrastructure, any changes to it must be made with the appropriate
logical operations.
</para>
</chapter>
<!-- }}} -->
<!-- {{{ Directories -->
<chapter id="fileio-directories">
<title>Directories</title>
<para>
Filesystem operations all take a directory pointer as one of their
arguments. A directory pointer is an opaque handle managed by the
filesystem. It should encapsulate a reference to a specific directory
within the filesystem. For example, it may be a pointer to the data
structure that represents that directory (such as an inode), or a
pointer to a pathname for the directory.
</para>
<para>
The <function>chdir()</function> filesystem function pointer has two
modes of use. When passed a pointer in the
<parameter>dir_out</parameter> argument, it should locate the named
directory and place a directory pointer there. If the
<parameter>dir_out</parameter> argument is NULL then the
<parameter>dir</parameter> argument is a previously generated
directory pointer that can now be disposed of. When the infrastructure
is implementing the <function>chdir()</function> function it makes two
calls to filesystem <function>chdir()</function> functions. The first
is to get a directory pointer for the new current directory. If this
succeeds the second is to dispose of the old current directory
pointer.
</para>
<para>
The <function>opendir()</function> function is used to open a
directory for reading. This results in an open file object that can be
read to return a sequence of <structname>struct dirent</structname>
objects. The only operations that are allowed on this file are
<function>read</function>, <function>lseek</function> and
<function>close</function>. Each read operation on this file should
return a single <structname>struct dirent</structname> object. When
the end of the directory is reached, zero should be returned. The only
seek operation allowed is a rewind to the start of the directory, by
supplying an offset of zero and a <parameter>whence</parameter>
specifier of <literal>SEEK_SET</literal>.
</para>
<para>
Most of these considerations are invisible to clients of a filesystem
since they will access directories via the POSIX
<function>opendir()</function>, <function>readdir()</function> and
<function>closedir()</function> functions.
</para>
<para>
Support for the <function>getcwd()</function> function is provided by
three mechanisms. The first is to use the
<literal>FS_INFO_GETCWD</literal> getinfo key on the filesystem to use
any internal support that it has for this. If that fails it falls back
on one of the two other mechanisms. If
<literal>CYGPKG_IO_FILEIO_TRACK_CWD</literal> is set then the current
directory is tracked textually in <function>chdir()</function> and the result of that is
reported in getcwd(). Otherwise an attempt is made to traverse the
directory tree to its root using ".." entries.
</para>
<para>
This last option is complicated and expensive, and relies on the
filesystem supporting "." and ".." entries. This is not always the
case, particularly if the filesystem has been ported from a
non-UNIX-compatible source. Tracking the pathname textually will
usually work, but might not produce optimum results when symbolic
links are being used.
</para>
</chapter>
<!-- }}} -->
<!-- {{{ Synchronization -->
<chapter id="fileio-synchronization">
<title>Synchronization</title>
<para>
The FILEIO infrastructure provides a synchronization mechanism for
controlling concurrent access to filesystems. This allows existing
filesystems to be ported to eCos, even if they do not have their own
synchronization mechanisms. It also allows new filesystems to be
implemented easily without having to consider the synchronization
issues.
</para>
<para>
The infrastructure maintains a mutex for each entry in each of
the main tables: filesystem table, mount table and file table. For
each class of operation each of these mutexes may be locked before the
corresponding filesystem operation is invoked.
</para>
<para>
The synchronization protocol required by a filesystem is described
by the <structfield>syncmode</structfield> field of the filesystem
table entry. This is a combination of the following flags:
</para>
<variablelist>
<varlistentry>
<term><literal>CYG_SYNCMODE_FILE_FILESYSTEM</literal></term>
<listitem>
<para>
Lock the filesystem table entry mutex
during all filesystem level operations.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>CYG_SYNCMODE_FILE_MOUNTPOINT</literal></term>
<listitem>
<para>
Lock the mount table entry mutex
during all filesystem level operations.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>CYG_SYNCMODE_IO_FILE</literal></term>
<listitem>
<para>
Lock the file table entry mutex during all
I/O operations.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>CYG_SYNCMODE_IO_FILESYSTEM</literal></term>
<listitem>
<para>
Lock the filesystem table entry mutex during all I/O operations.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>CYG_SYNCMODE_IO_MOUNTPOINT</literal></term>
<listitem><para>
Lock the mount table entry mutex during all I/O operations.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>CYG_SYNCMODE_SOCK_FILE</literal></term>
<listitem>
<para>
Lock the file table entry mutex during all socket operations.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>CYG_SYNCMODE_SOCK_NETSTACK</literal></term>
<listitem>
<para>
Lock the network stack table entry mutex during all socket operations.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>CYG_SYNCMODE_NONE</literal></term>
<listitem>
<para>
Perform no locking at all during any operations.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
The value of the <structfield>syncmode</structfield> field in the
filesystem table entry will be copied by the infrastructure to the
open file object after a successful <function>open()</function> operation.
</para>
</chapter>
<!-- }}} -->
<!-- {{{ Initialization and Mounting -->
<chapter id="fileio-mounting">
<title>Initialization and Mounting</title>
<para>
As mentioned previously, mount table entries can be sourced from two
places. Static entries may be defined by using the
<literal>MTAB_ENTRY()</literal> macro. Such entries will be
automatically mounted on system startup. For each entry in the mount
table that has a non-null <structfield>name</structfield> field the
filesystem table is searched for a match with the
<structfield>fsname</structfield> field. If a match is found the
filesystem's <structfield>mount</structfield> entry is called and if
successful the mount table entry marked valid and the
<structfield>fs</structfield> field initialized. The
<function>mount()</function> function is responsible for initializing
the <structfield>root</structfield> field.
</para>
<para>
The size of the mount table is defined by the configuration value
<literal>CYGNUM_FILEIO_MTAB_MAX</literal>. Any entries that have not
been statically defined are available for use by dynamic mounts.
</para>
<para>
A filesystem may be mounted dynamically by calling <function>mount()</function>. This
function has the following prototype:
</para>
<programlisting width=72>
int mount( const char *devname,
const char *dir,
const char *fsname);
</programlisting>
<para>
The <parameter>devname</parameter> argument identifies a device that
will be used by this filesystem and will be assigned to the
<structfield>devname</structfield> field of the mount table entry.
</para>
<para>
The <parameter>dir</parameter> argument is the mount point name, it
will be assigned to the <structfield>name</structfield> field of the
mount table entry.
</para>
<para>
The <parameter>fsname</parameter> argument is the name of the
implementing filesystem, it will be assigned to the
<structfield>fsname</structfield> entry of the mount table entry.
</para>
<para>
The process of mounting a filesystem dynamically is as follows. First
a search is made of the mount table for an entry with a NULL
<structfield>name</structfield> field to be used for the new mount
point. The filesystem table is then searched for an entry whose name
matches <structfield>fsname</structfield>. If this is successful then
the mount table entry is initialized and the filesystem's
<function>mount()</function> operation called. If this is successful,
the mount table entry is marked valid and the
<structfield>fs</structfield> field initialized.
</para>
<para>
Unmounting a filesystem is done by the <function>umount()</function>
function. This can unmount filesystems whether they were mounted
statically or dynamically.
</para>
<para>
The <function>umount()</function> function has the following prototype:
</para>
<programlisting width=72>
int umount( const char *name );
</programlisting>
<para>
The mount table is searched for a match between the
<parameter>name</parameter> argument and the entry
<structfield>name</structfield> field. When a match is found the
filesystem's <function>umount()</function> operation is called and if
successful, the mount table entry is invalidated by setting its
<structfield>valid</structfield> field false and the
<structfield>name</structfield> field to NULL.
</para>
<!--
-->
</chapter>
<!-- }}} -->
<!-- {{{ Sockets -->
<chapter id="fileio-sockets">
<title>Sockets</title>
<para>
If a network stack is present, then the FILEIO infrastructure also
provides access to the standard BSD socket calls.
</para>
<para>
The netstack table contains entries which describe the network
protocol stacks that are in the system image. Each resident stack
should export an entry to this table using the
<literal>NSTAB_ENTRY()</literal> macro.
</para>
<para>
Each table entry has the following structure:
</para>
<programlisting width=72>
struct cyg_nstab_entry
{
cyg_bool valid; // true if stack initialized
cyg_uint32 syncmode; // synchronization protocol
char *name; // stack name
char *devname; // hardware device name
CYG_ADDRWORD data; // private data value
int (*init)( cyg_nstab_entry *nste );
int (*socket)( cyg_nstab_entry *nste, int domain, int type,
int protocol, cyg_file *file );
};
</programlisting>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -