Next Previous Contents

4. The Path of a request

This section traces the path that a single request takes as it is processed by knfsd. This essentially shows the flow of control.

When the nfsd service is started by the nfsd user level program, nfssvc.c::nfsd_svc is called. This calls svc_create_thread from the sunrpc module to create a number of threads for serving requests that arrive for the nfs service. Each thread runs nfssvc.c::nfsd which handles requests in a loop. This routine, and most of what is called by is, runs protected by the big kernel lock, so SMP issues are non-issues.

nfsd repeatedly calls svc_recv to receive a request. When it receives a valid request it is finds out which client the IP address corresponds to (exp_getclient) and passes the request back to the sunrpc module using svc_process. These two call, and hence everything that nfsd does except for waiting for for new requests, are performed with a readlock on the export table.

The client identity is used to a minor extent by the sunrpc module in that if no valid client was found, and the procedure requested was not the NULL procedure, then the request is rejected with a bad credentials error status. This checking is enabled by setting rqstp->rq_auth to 1 in nfsd.

The sunrpc module decodes the rpc request and passes it back to nfsd_dispatch. This is selected by the nfsd_program structure at the end of nfssvc.c.

nfsd_dispatch checks to see if the request has already been seen and the reply been cached (see separate section on the request cache). If it has, then the remembered reply is returned. Otherwise the arguments are decoded, and the appropriate procedure is called. When this procedure returns the result is appropriate encoded into the response buffer, and cached if caching is appropriate for that procedure.

The different procedures are declared in the nfsd_procedures2 and nfsd_procedures3 sturctures which are defined in nfsproc.c and nfs3proc.c. For each procedure there is defined:

Each the function handling each different procedure naturally proceeds quite differently. There are however still some similarities that can be commented on.

Most nfsd_proc_* procedures simply pass the arguments on to nfsd_* in vfs.c which contains common code for versions 2 and 3. Other processing that is done at this level is preparing bufferes for return data (e.g. nfsd_proc_readlink) and calling fh_put on the file handle if nothing is needed from it.

A distinct exception to this pattern is nfsd_proc_create, I think because NFSv2 create is very different to NFSv3 create (FIXME expand on this, after understanding it).

Within each nfsd_* call in vfs.c, the common first step is to call fh_verify on a file handle to make sure that it is valid and that the relevant user has the required access.

fh_verify is defined in nfsfh.c. It uses find_fh_dentry (which is described elsewhere) to find the dentry for the file, is it is valid, does a number of other validity check, and finally calls nfsd_permission to see if the user has the required access. The sequence of checks is described elsewhere (FIXME one day...).

If fh_verify reports success, then the nfsd_* function goes about its specific task and eventually returns. This will cause the results to be encoded, possibly cached, and sent back to the RPC client.


Next Previous Contents