[an error occurred while processing this directive]
The NFS client library provides a simple interface for accessing files on an NFS server. The majority of these functions provide an asynchronous interface. Instead of blocking until the NFS transaction is complete you instead pass a function pointer, which will be called when the operation is complete. The first argument of these function is token which you also specify on the call. More information on NFS can be found in the NFS RFC.
This documents the basic functionality and functions
provided. You will probably want to look at the header files
rpc.h
and nfs.h
which defines the
structures used.
If you are running this code at home you will need to set up an
NFS server on your machine. This requires running
portmapper
, mountd
and
nfsd
. The NFS code also relies on the UDP time
protocol to generate a unique transaction ID on boot.
int nfs_init(struct ip_addr server);
This function should be called once at startup, passing the adderss of your NFS server.
void nfs_timeout(void);
Since NFS runs over UDP, an unreliable protocol, it is possible
that packets may be dropped. To allow NFS to retransmit packets
that might have been dropped you must arrange for
nfs_timeout
to be called every 100ms. This could be
achieved by either extending your clock driver, or using L4_Sleep
.
int mnt_get_export_list(void)
This is simply a debugging function which will print out a list of mount points available on the server.
unsigned int mnt_mount(char* dir, struct cookie *pfh);
This will mount a filesystem and return a cookie to it in
pfh
. In your assignment you will be mounting the
/tftpboot
filesystem. The returned cookie will be
used on subsequent NFS transactions.
int nfs_lookup(struct cookie *directory, char *name, void
(*func) (uintptr_t token, int status, struct cookie * fh, fattr_t
*attr), uintptr_t
token);
Before you are able to complete any operation on a file you
must obtain a handle to it. This is what the
nfs_lookup
function provides. This function will find
a file named name
in the specified
directory
. The root directory is of course the handle
returned from mnt_mount
. When the transaction has
completed it will call the func
you pass. This will
be called with your token
, and a status
code.
If the call is successful status will be zero, and you will also
be passed a handle to the file, and its current attributes. NB:
The pointers *fh
and *attr
are only
valid during the call, if you need to keep them you must copy them
into some other memory.
int nfs_getattr(struct cookie *fh, void (*func)
(uintptr_t, int, fattr_t *), uintptr_t token);
This function is the equivilant of the UNIX stat
function. It will find the current attributes on a given file
handle (*fh
). The attributes are passed back through
the callback func
. You may be able to avoid using
this call since nfs_lookup
, nfs_read
and
nfs_write
also return the current file
attributes.
int nfs_create(struct cookie *fh, char *name, sattr_t
*sat, void (*func) (uintptr_t, int, struct cookie *, fattr_t *),
uintptr_t token);
This function is used to create a new file named
name
with the attributes sat
. On
completion func
is called with a handle to the new
file and its attributes.
int nfs_read(struct cookie *fh, int pos, int count, void
(*func) (uintptr_t, int, fattr_t *attr, int bytes_read, char *data), uintptr_t
token);
nfs_read
will read count
bytes of
data, starting at a given pos
from the provided file
handle. On completion your func
is called with the
current file attributes, the number of bytes_read
and
a pointer to the data
. The data is only available for
the duration of the system call, after which it is reused for other
network packets. You will most likely need to copy this data into a
user's data buffer.
int nfs_write(struct cookie *fh, int offset, int count,
void *data, void (*func) (uintptr_t, int, fattr_t *), uintptr_t
token);
nfs_write
will write count
bytes of
data
at a specific offset
. When the
transaction is completed your func
will be called with
the status and the current file attributes.
int nfs_readdir(struct cookie *pfh, int cookie, int
read_size, void (*func) (uintptr_t token, int status, int num_entries, struct
nfs_filename *filenames, int next_cookie),
uintptr_t token);
struct nfs_filename {
int size;
const char *filename;
};
This function reads the contents, that is the filenames, from a
directory pfh
. When complete this transaction will
call func
with a pointer an array of
filenames
. This array is num_entries
long. Each entry in the array contains a size
and a
pointer to the filename
. Note that
filename
is NOT a null terminated string. Its length
is specified by the size
. As with other NFS callbacks
the data here is only valid for the duration of the call and must
be copied elsewhere if required.
The next_cookie
argument indicates whether there
are more directory entries available. If next_cookie
is zero then all directory entries have been read. If it is greater
than zero then there are more entries available and this value
should be passed as the cookie
argument to another
nfs_readdir
request. Note that zero should be passed
as the initial cookie
value.
The read_size
parameter specifies the number of
bytes of data to read on each request.