The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/lib/libsa/nfs.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: nfs.c,v 1.36 2003/09/04 12:02:10 he Exp $      */
    2 
    3 /*-
    4  *  Copyright (c) 1993 John Brezak
    5  *  All rights reserved.
    6  * 
    7  *  Redistribution and use in source and binary forms, with or without
    8  *  modification, are permitted provided that the following conditions
    9  *  are met:
   10  *  1. Redistributions of source code must retain the above copyright
   11  *     notice, this list of conditions and the following disclaimer.
   12  *  2. Redistributions in binary form must reproduce the above copyright
   13  *     notice, this list of conditions and the following disclaimer in the
   14  *     documentation and/or other materials provided with the distribution.
   15  *  3. The name of the author may not be used to endorse or promote products
   16  *     derived from this software without specific prior written permission.
   17  * 
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   21  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   28  * POSSIBILITY OF SUCH DAMAGE.
   29  */
   30 
   31 /*
   32  * XXX Does not currently implement:
   33  * XXX
   34  * XXX LIBSA_NO_FS_CLOSE
   35  * XXX LIBSA_NO_FS_SEEK
   36  * XXX LIBSA_NO_FS_WRITE
   37  * XXX LIBSA_NO_FS_SYMLINK (does this even make sense?)
   38  * XXX LIBSA_FS_SINGLECOMPONENT (does this even make sense?)
   39  */
   40 
   41 #include <sys/param.h>
   42 #include <sys/time.h>
   43 #include <sys/socket.h>
   44 #include <sys/stat.h>
   45 #ifdef _STANDALONE
   46 #include <lib/libkern/libkern.h>
   47 #else
   48 #include <string.h>
   49 #endif
   50 
   51 #include <netinet/in.h>
   52 #include <netinet/in_systm.h>
   53 
   54 #include "rpcv2.h"
   55 #include "nfsv2.h"
   56 
   57 #include "stand.h"
   58 #include "net.h"
   59 #include "nfs.h"
   60 #include "rpc.h"
   61 
   62 /* Define our own NFS attributes without NQNFS stuff. */
   63 struct nfsv2_fattrs {
   64         n_long  fa_type;
   65         n_long  fa_mode;
   66         n_long  fa_nlink;
   67         n_long  fa_uid;
   68         n_long  fa_gid;
   69         n_long  fa_size;
   70         n_long  fa_blocksize;
   71         n_long  fa_rdev;
   72         n_long  fa_blocks;
   73         n_long  fa_fsid;
   74         n_long  fa_fileid;
   75         struct nfsv2_time fa_atime;
   76         struct nfsv2_time fa_mtime;
   77         struct nfsv2_time fa_ctime;
   78 };
   79 
   80 
   81 struct nfs_read_args {
   82         u_char  fh[NFS_FHSIZE];
   83         n_long  off;
   84         n_long  len;
   85         n_long  xxx;                    /* XXX what's this for? */
   86 };
   87 
   88 /* Data part of nfs rpc reply (also the largest thing we receive) */
   89 #define NFSREAD_SIZE 1024
   90 struct nfs_read_repl {
   91         n_long  errno;
   92         struct  nfsv2_fattrs fa;
   93         n_long  count;
   94         u_char  data[NFSREAD_SIZE];
   95 };
   96 
   97 #ifndef NFS_NOSYMLINK
   98 struct nfs_readlnk_repl {
   99         n_long  errno;
  100         n_long  len;
  101         char    path[NFS_MAXPATHLEN];
  102 };
  103 #endif
  104 
  105 struct nfs_iodesc {
  106         struct  iodesc  *iodesc;
  107         off_t   off;
  108         u_char  fh[NFS_FHSIZE];
  109         struct nfsv2_fattrs fa; /* all in network order */
  110 };
  111 
  112 struct nfs_iodesc nfs_root_node;
  113 
  114 int     nfs_getrootfh __P((struct iodesc *, char *, u_char *));
  115 int     nfs_lookupfh __P((struct nfs_iodesc *, const char *, int,
  116             struct nfs_iodesc *));
  117 int     nfs_readlink __P((struct nfs_iodesc *, char *));
  118 ssize_t nfs_readdata __P((struct nfs_iodesc *, off_t, void *, size_t));
  119 
  120 /*
  121  * Fetch the root file handle (call mount daemon)
  122  * On error, return non-zero and set errno.
  123  */
  124 int
  125 nfs_getrootfh(d, path, fhp)
  126         struct iodesc *d;
  127         char *path;
  128         u_char *fhp;
  129 {
  130         int len;
  131         struct args {
  132                 n_long  len;
  133                 char    path[FNAME_SIZE];
  134         } *args;
  135         struct repl {
  136                 n_long  errno;
  137                 u_char  fh[NFS_FHSIZE];
  138         } *repl;
  139         struct {
  140                 n_long  h[RPC_HEADER_WORDS];
  141                 struct args d;
  142         } sdata;
  143         struct {
  144                 n_long  h[RPC_HEADER_WORDS];
  145                 struct repl d;
  146         } rdata;
  147         ssize_t cc;
  148         
  149 #ifdef NFS_DEBUG
  150         if (debug)
  151                 printf("nfs_getrootfh: %s\n", path);
  152 #endif
  153 
  154         args = &sdata.d;
  155         repl = &rdata.d;
  156 
  157         bzero(args, sizeof(*args));
  158         len = strlen(path);
  159         if ((size_t)len > sizeof(args->path))
  160                 len = sizeof(args->path);
  161         args->len = htonl(len);
  162         bcopy(path, args->path, len);
  163         len = 4 + roundup(len, 4);
  164 
  165         cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
  166             args, len, repl, sizeof(*repl));
  167         if (cc == -1) {
  168                 /* errno was set by rpc_call */
  169                 return (-1);
  170         }
  171         if (cc < 4) {
  172                 errno = EBADRPC;
  173                 return (-1);
  174         }
  175         if (repl->errno) {
  176                 errno = ntohl(repl->errno);
  177                 return (-1);
  178         }
  179         bcopy(repl->fh, fhp, sizeof(repl->fh));
  180         return (0);
  181 }
  182 
  183 /*
  184  * Lookup a file.  Store handle and attributes.
  185  * Return zero or error number.
  186  */
  187 int
  188 nfs_lookupfh(d, name, len, newfd)
  189         struct nfs_iodesc *d;
  190         const char *name;
  191         int len;
  192         struct nfs_iodesc *newfd;
  193 {
  194         int rlen;
  195         struct args {
  196                 u_char  fh[NFS_FHSIZE];
  197                 n_long  len;
  198                 char    name[FNAME_SIZE];
  199         } *args;
  200         struct repl {
  201                 n_long  errno;
  202                 u_char  fh[NFS_FHSIZE];
  203                 struct  nfsv2_fattrs fa;
  204         } *repl;
  205         struct {
  206                 n_long  h[RPC_HEADER_WORDS];
  207                 struct args d;
  208         } sdata;
  209         struct {
  210                 n_long  h[RPC_HEADER_WORDS];
  211                 struct repl d;
  212         } rdata;
  213         ssize_t cc;
  214         
  215 #ifdef NFS_DEBUG
  216         if (debug)
  217                 printf("lookupfh: called\n");
  218 #endif
  219 
  220         args = &sdata.d;
  221         repl = &rdata.d;
  222 
  223         bzero(args, sizeof(*args));
  224         bcopy(d->fh, args->fh, sizeof(args->fh));
  225         if ((size_t)len > sizeof(args->name))
  226                 len = sizeof(args->name);
  227         bcopy(name, args->name, len);
  228         args->len = htonl(len);
  229         len = 4 + roundup(len, 4);
  230         len += NFS_FHSIZE;
  231 
  232         rlen = sizeof(*repl);
  233 
  234         cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
  235             args, len, repl, rlen);
  236         if (cc == -1)
  237                 return (errno);         /* XXX - from rpc_call */
  238         if (cc < 4)
  239                 return (EIO);
  240         if (repl->errno) {
  241                 /* saerrno.h now matches NFS error numbers. */
  242                 return (ntohl(repl->errno));
  243         }
  244         bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
  245         bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
  246         return (0);
  247 }
  248 
  249 #ifndef NFS_NOSYMLINK
  250 /*
  251  * Get the destination of a symbolic link.
  252  */
  253 int
  254 nfs_readlink(d, buf)
  255         struct nfs_iodesc *d;
  256         char *buf;
  257 {
  258         struct {
  259                 n_long  h[RPC_HEADER_WORDS];
  260                 u_char fh[NFS_FHSIZE];
  261         } sdata;
  262         struct {
  263                 n_long  h[RPC_HEADER_WORDS];
  264                 struct nfs_readlnk_repl d;
  265         } rdata;
  266         ssize_t cc;
  267 
  268 #ifdef NFS_DEBUG
  269         if (debug)
  270                 printf("readlink: called\n");
  271 #endif
  272 
  273         bcopy(d->fh, sdata.fh, NFS_FHSIZE);
  274         cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
  275                       sdata.fh, NFS_FHSIZE,
  276                       &rdata.d, sizeof(rdata.d));
  277         if (cc == -1)
  278                 return (errno);
  279 
  280         if (cc < 4)
  281                 return (EIO);
  282         
  283         if (rdata.d.errno)
  284                 return (ntohl(rdata.d.errno));
  285 
  286         rdata.d.len = ntohl(rdata.d.len);
  287         if (rdata.d.len > NFS_MAXPATHLEN)
  288                 return (ENAMETOOLONG);
  289 
  290         bcopy(rdata.d.path, buf, rdata.d.len);
  291         buf[rdata.d.len] = 0;
  292         return (0);
  293 }
  294 #endif
  295 
  296 /*
  297  * Read data from a file.
  298  * Return transfer count or -1 (and set errno)
  299  */
  300 ssize_t
  301 nfs_readdata(d, off, addr, len)
  302         struct nfs_iodesc *d;
  303         off_t off;
  304         void *addr;
  305         size_t len;
  306 {
  307         struct nfs_read_args *args;
  308         struct nfs_read_repl *repl;
  309         struct {
  310                 n_long  h[RPC_HEADER_WORDS];
  311                 struct nfs_read_args d;
  312         } sdata;
  313         struct {
  314                 n_long  h[RPC_HEADER_WORDS];
  315                 struct nfs_read_repl d;
  316         } rdata;
  317         ssize_t cc;
  318         long x;
  319         size_t hlen, rlen;
  320 
  321         args = &sdata.d;
  322         repl = &rdata.d;
  323 
  324         bcopy(d->fh, args->fh, NFS_FHSIZE);
  325         args->off = htonl((n_long)off);
  326         if (len > NFSREAD_SIZE)
  327                 len = NFSREAD_SIZE;
  328         args->len = htonl((n_long)len);
  329         args->xxx = htonl((n_long)0);
  330         hlen = sizeof(*repl) - NFSREAD_SIZE;
  331 
  332         cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
  333             args, sizeof(*args),
  334             repl, sizeof(*repl));
  335         if (cc == -1) {
  336                 /* errno was already set by rpc_call */
  337                 return (-1);
  338         }
  339         if (cc < (ssize_t)hlen) {
  340                 errno = EBADRPC;
  341                 return (-1);
  342         }
  343         if (repl->errno) {
  344                 errno = ntohl(repl->errno);
  345                 return (-1);
  346         }
  347         rlen = cc - hlen;
  348         x = ntohl(repl->count);
  349         if (rlen < (size_t)x) {
  350                 printf("nfsread: short packet, %lu < %ld\n", (u_long) rlen, x);
  351                 errno = EBADRPC;
  352                 return(-1);
  353         }
  354         bcopy(repl->data, addr, x);
  355         return (x);
  356 }
  357 
  358 /*
  359  * nfs_mount - mount this nfs filesystem to a host
  360  * On error, return non-zero and set errno.
  361  */
  362 int
  363 nfs_mount(sock, ip, path)
  364         int sock;
  365         struct in_addr ip;
  366         char *path;
  367 {
  368         struct iodesc *desc;
  369         struct nfsv2_fattrs *fa;
  370 
  371         if (!(desc = socktodesc(sock))) {
  372                 errno = EINVAL;
  373                 return(-1);
  374         }
  375 
  376         /* Bind to a reserved port. */
  377         desc->myport = htons(--rpc_port);
  378         desc->destip = ip;
  379         if (nfs_getrootfh(desc, path, nfs_root_node.fh))
  380                 return (-1);
  381         nfs_root_node.iodesc = desc;
  382         /* Fake up attributes for the root dir. */
  383         fa = &nfs_root_node.fa;
  384         fa->fa_type  = htonl(NFDIR);
  385         fa->fa_mode  = htonl(0755);
  386         fa->fa_nlink = htonl(2);
  387 
  388 #ifdef NFS_DEBUG
  389         if (debug)
  390                 printf("nfs_mount: got fh for %s\n", path);
  391 #endif
  392 
  393         return(0);
  394 }
  395 
  396 /*
  397  * Open a file.
  398  * return zero or error number
  399  */
  400 int
  401 nfs_open(path, f)
  402         const char *path;
  403         struct open_file *f;
  404 {
  405         struct nfs_iodesc *newfd, *currfd;
  406         const char *cp;
  407 #ifndef NFS_NOSYMLINK
  408         const char *ncp;
  409         int c;
  410         char namebuf[NFS_MAXPATHLEN + 1];
  411         char linkbuf[NFS_MAXPATHLEN + 1];
  412         int nlinks = 0;
  413 #endif
  414         int error = 0;
  415 
  416 #ifdef NFS_DEBUG
  417         if (debug)
  418             printf("nfs_open: %s\n", path);
  419 #endif
  420         if (nfs_root_node.iodesc == NULL) {
  421                 printf("nfs_open: must mount first.\n");
  422                 return (ENXIO);
  423         }
  424 
  425         currfd = &nfs_root_node;
  426         newfd = 0;
  427 
  428 #ifndef NFS_NOSYMLINK
  429         cp = path;
  430         while (*cp) {
  431                 /*
  432                  * Remove extra separators
  433                  */
  434                 while (*cp == '/')
  435                         cp++;
  436 
  437                 if (*cp == '\0')
  438                         break;
  439                 /*
  440                  * Check that current node is a directory.
  441                  */
  442                 if (currfd->fa.fa_type != htonl(NFDIR)) {
  443                         error = ENOTDIR;
  444                         goto out;
  445                 }
  446                 
  447                 /* allocate file system specific data structure */
  448                 newfd = alloc(sizeof(*newfd));
  449                 newfd->iodesc = currfd->iodesc;
  450                 newfd->off = 0;
  451         
  452                 /*
  453                  * Get next component of path name.
  454                  */
  455                 {
  456                         int len = 0;
  457                         
  458                         ncp = cp;
  459                         while ((c = *cp) != '\0' && c != '/') {
  460                                 if (++len > NFS_MAXNAMLEN) {
  461                                         error = ENOENT;
  462                                         goto out;
  463                                 }
  464                                 cp++;
  465                         }
  466                 }
  467                 
  468                 /* lookup a file handle */
  469                 error = nfs_lookupfh(currfd, ncp, cp - ncp, newfd);
  470                 if (error)
  471                         goto out;
  472                 
  473                 /*
  474                  * Check for symbolic link
  475                  */
  476                 if (newfd->fa.fa_type == htonl(NFLNK)) {
  477                         int link_len, len;
  478                         
  479                         error = nfs_readlink(newfd, linkbuf);
  480                         if (error)
  481                                 goto out;
  482 
  483                         link_len = strlen(linkbuf);
  484                         len = strlen(cp);
  485 
  486                         if (link_len + len > MAXPATHLEN
  487                             || ++nlinks > MAXSYMLINKS) {
  488                                 error = ENOENT;
  489                                 goto out;
  490                         }
  491 
  492                         bcopy(cp, &namebuf[link_len], len + 1);
  493                         bcopy(linkbuf, namebuf, link_len);
  494                         
  495                         /*
  496                          * If absolute pathname, restart at root.
  497                          * If relative pathname, restart at parent directory.
  498                          */
  499                         cp = namebuf;
  500                         if (*cp == '/') {
  501                                 if (currfd != &nfs_root_node)
  502                                         free(currfd, sizeof(*currfd));
  503                                 currfd = &nfs_root_node;
  504                         }
  505 
  506                         free(newfd, sizeof(*newfd));
  507                         newfd = 0;
  508                         
  509                         continue;
  510                 }
  511                 
  512                 if (currfd != &nfs_root_node)
  513                         free(currfd, sizeof(*currfd));
  514                 currfd = newfd;
  515                 newfd = 0;
  516         }
  517 
  518         error = 0;
  519 
  520 out:
  521 #else
  522         /* allocate file system specific data structure */
  523         currfd = alloc(sizeof(*currfd));
  524         currfd->iodesc = nfs_root_node.iodesc;
  525         currfd->off = 0;
  526 
  527         cp = path;
  528         /*
  529          * Remove extra separators
  530          */
  531         while (*cp == '/')
  532                 cp++;
  533 
  534         /* XXX: Check for empty path here? */
  535 
  536         error = nfs_lookupfh(&nfs_root_node, cp, strlen(cp), currfd);
  537 #endif
  538         if (!error) {
  539                 f->f_fsdata = (void *)currfd;
  540                 return (0);
  541         }
  542                 
  543 #ifdef NFS_DEBUG
  544         if (debug)
  545                 printf("nfs_open: %s lookupfh failed: %s\n",
  546                     path, strerror(error));
  547 #endif
  548         if (currfd != &nfs_root_node)
  549                 free(currfd, sizeof(*currfd));
  550         if (newfd)
  551                 free(newfd, sizeof(*newfd));
  552 
  553         return (error);
  554 }
  555 
  556 int
  557 nfs_close(f)
  558         struct open_file *f;
  559 {
  560         struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
  561 
  562 #ifdef NFS_DEBUG
  563         if (debug)
  564                 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
  565 #endif
  566 
  567         if (fp)
  568                 free(fp, sizeof(struct nfs_iodesc));
  569         f->f_fsdata = (void *)0;
  570         
  571         return (0);
  572 }
  573 
  574 /*
  575  * read a portion of a file
  576  */
  577 int
  578 nfs_read(f, buf, size, resid)
  579         struct open_file *f;
  580         void *buf;
  581         size_t size;
  582         size_t *resid;  /* out */
  583 {
  584         struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
  585         ssize_t cc;
  586         char *addr = buf;
  587         
  588 #ifdef NFS_DEBUG
  589         if (debug)
  590                 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
  591                     (int)fp->off);
  592 #endif
  593         while ((int)size > 0) {
  594 #if !defined(LIBSA_NO_TWIDDLE)
  595                 twiddle();
  596 #endif
  597                 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
  598                 /* XXX maybe should retry on certain errors */
  599                 if (cc == -1) {
  600 #ifdef NFS_DEBUG
  601                         if (debug)
  602                                 printf("nfs_read: read: %s", strerror(errno));
  603 #endif
  604                         return (errno); /* XXX - from nfs_readdata */
  605                 }
  606                 if (cc == 0) {
  607 #ifdef NFS_DEBUG
  608                         if (debug)
  609                                 printf("nfs_read: hit EOF unexpectantly");
  610 #endif
  611                         goto ret;
  612                 }
  613                 fp->off += cc;
  614                 addr += cc;
  615                 size -= cc;
  616         }
  617 ret:
  618         if (resid)
  619                 *resid = size;
  620 
  621         return (0);
  622 }
  623 
  624 /*
  625  * Not implemented.
  626  */
  627 int
  628 nfs_write(f, buf, size, resid)
  629         struct open_file *f;
  630         void *buf;
  631         size_t size;
  632         size_t *resid;  /* out */
  633 {
  634         return (EROFS);
  635 }
  636 
  637 off_t
  638 nfs_seek(f, offset, where)
  639         struct open_file *f;
  640         off_t offset;
  641         int where;
  642 {
  643         struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
  644         n_long size = ntohl(d->fa.fa_size);
  645 
  646         switch (where) {
  647         case SEEK_SET:
  648                 d->off = offset;
  649                 break;
  650         case SEEK_CUR:
  651                 d->off += offset;
  652                 break;
  653         case SEEK_END:
  654                 d->off = size - offset;
  655                 break;
  656         default:
  657                 return (-1);
  658         }
  659 
  660         return (d->off);
  661 }
  662 
  663 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
  664 const int nfs_stat_types[8] = {
  665         0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
  666 
  667 int
  668 nfs_stat(f, sb)
  669         struct open_file *f;
  670         struct stat *sb;
  671 {
  672         struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
  673         n_long ftype, mode;
  674 
  675         ftype = ntohl(fp->fa.fa_type);
  676         mode  = ntohl(fp->fa.fa_mode);
  677         mode |= nfs_stat_types[ftype & 7];
  678 
  679         sb->st_mode  = mode;
  680         sb->st_nlink = ntohl(fp->fa.fa_nlink);
  681         sb->st_uid   = ntohl(fp->fa.fa_uid);
  682         sb->st_gid   = ntohl(fp->fa.fa_gid);
  683         sb->st_size  = ntohl(fp->fa.fa_size);
  684 
  685         return (0);
  686 }

Cache object: 78e0690ebf307a8dcacfea37528efe70


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.