Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

nfsd.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Fri Oct  7 10:30:17 EDT 2005 by ken@xorian.net
00020 
00021 /*
00022  * vnfsd.C      This code handles RPC "NFS" data requests
00023  *              to the Vesta repository.
00024  *
00025  * Adapted for Vesta:
00026  *              Tim Mann, <mann@pa.dec.com>
00027  *
00028  * Authors of original user-space NFS server:
00029  *              Mark A. Shand, May 1988
00030  *              Donald J. Becker, <becker@super.org>
00031  *              Rick Sladkey, <jrs@world.std.com>
00032  *              Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
00033  *              Eric Kasten, <tigger@tigger.cl.msu.edu>
00034  *
00035  *              Copyright 1988 Mark A. Shand
00036  *              This software may be be used for any purpose provided
00037  *              the above copyright notice is retained.  It is supplied
00038  *              as is, with no warranty expressed or implied.
00039  */
00040 
00041 #ifdef __linux__
00042 // To get pthread_attr_setguardsize:
00043 #define _XOPEN_SOURCE 500
00044 // To keep _XOPEN_SOURCE from messing up Linux system headers:
00045 #define _BSD_SOURCE
00046 #endif
00047 
00048 #include <errno.h>
00049 #include <signal.h>
00050 #include <sys/time.h>
00051 #include <pthread.h>
00052 #include <Basics.H>
00053 #include <getopt.h>
00054 #include <assert.h>
00055 #include "nfsd.H"
00056 #include "logging.H"
00057 #include "AccessControl.H"
00058 #include "glue.H"
00059 
00060 #include "timing.H"
00061 
00062 #include "nfsStats.H"
00063 
00064 extern _PRO(void nfs_dispatch, (struct svc_req * rqstp, SVCXPRT * transp));
00065 static _PRO(int makesock, (int port, int proto, int socksz));
00066 
00067 extern void xdr_free();         /* fill this in later */
00068 
00069 void
00070 mallocfailed()
00071 {
00072     Repos::dprintf(DBG_ALWAYS, "malloc failed -- exiting\n");
00073     exit(1);
00074 }
00075 
00076 /*
00077  * The "wrappers" of the following functions came from `rpcgen -l nfs_prot.x`.
00078  * This normally generates the client routines, but it provides nice
00079  * prototypes for the server routines also.
00080  */
00081 
00082 int
00083 nfsd_nfsproc_null_2(void *argp, union result_types *resp,
00084                     AccessControl::Identity cred)
00085 {
00086     return 0;
00087 }
00088 
00089 int
00090 nfsd_nfsproc_getattr_2(nfs_fh *argp, union result_types *resp,
00091                        AccessControl::Identity cred)
00092 {
00093     return do_getattr(argp, &resp->r_attrstat.attrstat_u.attributes, cred);
00094 }
00095 
00096 int
00097 nfsd_nfsproc_setattr_2(sattrargs *argp, union result_types *resp,
00098                        AccessControl::Identity cred)
00099 {
00100     return do_setattr(argp, &resp->r_attrstat.attrstat_u.attributes, cred);
00101 }
00102 
00103 int
00104 nfsd_nfsproc_root_2(void *argp, union result_types *resp,
00105                        AccessControl::Identity cred)
00106 {
00107     return 0;
00108 }
00109 
00110 int
00111 nfsd_nfsproc_lookup_2(diropargs *argp, union result_types *resp,
00112                       AccessControl::Identity cred)
00113 {
00114     nfsstat status;
00115     diropokres *dp = &resp->r_diropres.diropres_u.diropres;
00116     status = do_lookup(argp, dp, cred);
00117     resp->r_diropres.status = status;
00118     return status;
00119 }
00120 
00121 int
00122 nfsd_nfsproc_readlink_2(nfs_fh *argp, union result_types *resp,
00123                         AccessControl::Identity cred)
00124 {
00125     nfsstat status;
00126     status = do_readlink(argp, resp->r_readlinkres.readlinkres_u.data, cred);
00127     resp->r_readlinkres.status = status;
00128     return status;
00129 }
00130 
00131 int
00132 nfsd_nfsproc_read_2(readargs *argp, union result_types *resp,
00133                     AccessControl::Identity cred)
00134 {
00135     nfsstat status;
00136     int fd;
00137     VestaSource* vs;
00138     int ofl; /* really a FdCache::OFlag */
00139 
00140     RECORD_TIME_POINT;
00141     if ((fd = fh_fd(&(argp->file), &status, O_RDONLY, &vs, &ofl, cred))== -1) {
00142         return ((int) status);
00143     }
00144     if (fd == DEVICE_FAKE_FD) {
00145         resp->r_readres.readres_u.reply.data.data_len = 0;
00146         status = NFS_OK;
00147     } else {
00148       RECORD_TIME_POINT;
00149       errno = 0;
00150       resp->r_readres.readres_u.reply.data.data_len =
00151         pread(fd, resp->r_readres.readres_u.reply.data.data_val,
00152               argp->count, (long) argp->offset);
00153       status = xlate_errno(errno);
00154     }
00155     if (status == NFS_OK) {
00156       RECORD_TIME_POINT;
00157         status = any_fattr(&resp->r_readres.readres_u.reply.attributes,
00158                            vs, fd);
00159     }
00160     RECORD_TIME_POINT;
00161     fd_inactive(vs, fd, ofl);
00162     RECORD_TIME_POINT;
00163     return status;
00164 }
00165 
00166 int
00167 nfsd_nfsproc_writecache_2(void *argp, union result_types *resp,
00168                           AccessControl::Identity cred)
00169 {
00170     return 0;
00171 }
00172 
00173 int
00174 nfsd_nfsproc_write_2(writeargs *argp, union result_types *resp,
00175                        AccessControl::Identity cred)
00176 {
00177     nfsstat status;
00178     int fd;
00179     VestaSource* vs;
00180     int ofl; /* really a FdCache::OFlag */
00181 
00182     RECORD_TIME_POINT;
00183     if ((fd = fh_fd(&(argp->file), &status, O_WRONLY, &vs, &ofl, cred))== -1) {
00184         return ((int) status);
00185     }
00186     if (fd == DEVICE_FAKE_FD) {
00187         status = NFS_OK;
00188     } else {
00189       RECORD_TIME_POINT;
00190       errno = 0;
00191       if (pwrite(fd, argp->data.data_val, argp->data.data_len, (long) argp->offset) !=
00192           argp->data.data_len) {
00193         Repos::dprintf(DBG_SRPC, " Write failure, errno is %d.\n", errno);
00194       }
00195       status = xlate_errno(errno);
00196     }
00197     if (status == NFS_OK) {
00198       RECORD_TIME_POINT;
00199         status = any_fattr(&resp->r_attrstat.attrstat_u.attributes,
00200                            vs, fd);
00201     }
00202     RECORD_TIME_POINT;
00203     fd_inactive(vs, fd, ofl);
00204     RECORD_TIME_POINT;
00205     return status;
00206 }
00207 
00208 int
00209 nfsd_nfsproc_create_2(createargs *argp, union result_types *resp,
00210                        AccessControl::Identity cred)
00211 {
00212     nfsstat status;
00213     status = do_create(argp, &resp->r_diropres.diropres_u.diropres, cred);
00214     resp->r_diropres.status = status;
00215     return status;
00216 }
00217 
00218 int
00219 nfsd_nfsproc_remove_2(diropargs *argp, union result_types *resp,
00220                        AccessControl::Identity cred)
00221 {
00222     nfsstat status;
00223     status = do_remove(argp, cred);
00224     resp->r_nfsstat = status;
00225     return status;
00226 }
00227 
00228 int
00229 nfsd_nfsproc_rename_2(renameargs *argp, union result_types *resp,
00230                        AccessControl::Identity cred)
00231 {
00232     nfsstat status;
00233     status = do_rename(argp, cred);
00234     resp->r_nfsstat = status;
00235     return status;
00236 }
00237 
00238 int
00239 nfsd_nfsproc_link_2(linkargs *argp, union result_types *resp,
00240                        AccessControl::Identity cred)
00241 {
00242     nfsstat status;
00243     status = do_hardlink(argp, cred);
00244     resp->r_nfsstat = status;
00245     return status;
00246 }
00247 
00248 int
00249 nfsd_nfsproc_symlink_2(symlinkargs *argp, union result_types *resp,
00250                        AccessControl::Identity cred)
00251 {
00252     nfsstat status;
00253     status = do_symlink(argp, cred);
00254     resp->r_nfsstat = status;
00255     return status;
00256 }
00257 
00258 int
00259 nfsd_nfsproc_mkdir_2(createargs *argp, union result_types *resp,
00260                        AccessControl::Identity cred)
00261 {
00262     nfsstat status;
00263     status = do_mkdir(argp, &resp->r_diropres.diropres_u.diropres, cred);
00264     resp->r_diropres.status = status;
00265     return status;
00266 }
00267 
00268 int
00269 nfsd_nfsproc_rmdir_2(diropargs *argp, union result_types *resp,
00270                        AccessControl::Identity cred)
00271 {
00272     nfsstat status;
00273     status = do_remove(argp, cred);
00274     resp->r_nfsstat = status;
00275     return status;
00276 }
00277 
00278 int
00279 nfsd_nfsproc_readdir_2(readdirargs *argp, union result_types *resp,
00280                        AccessControl::Identity cred)
00281 {
00282     return do_readdir(argp, resp, cred);
00283 }
00284 
00285 int
00286 nfsd_nfsproc_statfs_2(nfs_fh *argp, union result_types *resp, 
00287                        AccessControl::Identity cred)
00288 {
00289     return do_statfs(argp, resp, cred);
00290 }
00291 
00292 static int
00293 makesock(int port, int proto, int socksz)
00294 {
00295     struct sockaddr_in sin;
00296     int s;
00297     int sock_type;
00298 
00299     sock_type = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
00300     s = socket(AF_INET, sock_type, proto);
00301     if (s < 0) {
00302       int saved_errno = errno;
00303       Text etxt = Basics::errno_Text(saved_errno);
00304       Repos::dprintf(DBG_ALWAYS, "Could not make a socket: %s\n", etxt.cchars());
00305       return (-1);
00306     }
00307     memset((char *) &sin, 0, sizeof(sin));
00308     sin.sin_family = AF_INET;
00309     sin.sin_addr.s_addr = INADDR_ANY;
00310     sin.sin_port = htons(port);
00311 
00312     {
00313         int val = 1;
00314 
00315         if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
00316           {
00317             int saved_errno = errno;
00318             Text etxt = Basics::errno_Text(saved_errno);
00319             Repos::dprintf(DBG_ALWAYS, "setsockopt failed: %s\n", etxt.cchars());
00320           }
00321     }
00322 
00323 #ifdef SO_SNDBUF
00324     {
00325         int sblen, rblen;
00326 
00327         sblen = rblen = socksz;
00328 
00329         if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sblen, sizeof sblen) < 0)
00330           {
00331             int saved_errno = errno;
00332             Text etxt = Basics::errno_Text(saved_errno);
00333             Repos::dprintf(DBG_ALWAYS, "setsockopt(SO_SNDBUF, %d) failed: %s\n",
00334                            sblen, etxt.cchars());
00335           }
00336 
00337         if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rblen, sizeof rblen) < 0)
00338           {
00339             int saved_errno = errno;
00340             Text etxt = Basics::errno_Text(saved_errno);
00341             Repos::dprintf(DBG_ALWAYS, "setsockopt(SO_RCVBUF, %d) failed: %s\n",
00342                            rblen, etxt.cchars());
00343           }
00344     }
00345 #endif /* SO_SNDBUF */
00346 
00347     if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
00348       int saved_errno = errno;
00349       Text etxt = Basics::errno_Text(saved_errno);
00350       Repos::dprintf(DBG_ALWAYS,
00351                      "Could not bind name to socket: %s\n", etxt.cchars());
00352       return (-1);
00353     }
00354     return (s);
00355 }
00356 
00357 int nfs_port = NFS_PORT;
00358 char *MyNFSSocket = "";
00359 
00360 #define RQCRED_SIZE 480
00361 
00362 void *
00363 nfsd_thread(void *arg)
00364 {
00365   int nfs_socket = (int)(long) arg;
00366   SVCXPRT *xprt;
00367 
00368   signal(SIGPIPE, SIG_IGN);
00369   signal(SIGQUIT, SIG_DFL);
00370   signal(SIGSEGV, SIG_DFL);
00371   signal(SIGABRT, SIG_DFL);
00372   signal(SIGBUS, SIG_DFL);
00373   signal(SIGILL, SIG_DFL);
00374 
00375   xprt = svcudp_create(nfs_socket);
00376   assert(xprt != NULL);
00377 
00378   NFS_Call_Stats my_stats;
00379 
00380 #if defined(REPOS_PERF_DEBUG)
00381   Timing_Recorder *my_recorder = NEW(Timing_Recorder);
00382 #endif
00383 
00384   for (;;) {
00385     enum xprt_stat stat;
00386     struct rpc_msg msg;
00387     struct svc_req r;
00388     char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
00389     enum auth_stat why;
00390 
00391     msg.rm_call.cb_cred.oa_base = cred_area;
00392     msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
00393     r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
00394 
00395     if (SVC_RECV(xprt, &msg)) {
00396       NFS_Call_Stats::Helper stat_recorder(my_stats);
00397 
00398       r.rq_xprt = xprt;
00399       r.rq_prog = msg.rm_call.cb_prog;
00400       r.rq_vers = msg.rm_call.cb_vers;
00401       r.rq_proc = msg.rm_call.cb_proc;
00402       r.rq_cred = msg.rm_call.cb_cred;
00403 
00404       /* Authenticate */
00405       if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
00406         svcerr_auth(xprt, why);
00407         continue;
00408       }
00409       RECORD_TIME_POINT;
00410 
00411       /* Check this is really an NFS call */
00412       if (r.rq_prog != NFS_PROGRAM) {
00413         svcerr_noprog(xprt);
00414         continue;
00415       }
00416       if (r.rq_vers != NFS_VERSION) {
00417 #if __linux__
00418         /* extra two args are documented in svc.h
00419            but not in man page */
00420         svcerr_progvers(xprt, NFS_VERSION, NFS_VERSION);
00421 #else
00422         svcerr_progvers(xprt);
00423 #endif
00424         continue;
00425       }
00426 
00427       /* Do it */
00428       nfs_dispatch(&r, xprt);
00429     }
00430   }
00431   //return NULL; /* not reached */
00432 }
00433 
00434 static Basics::thread *nfsd_threads = NULL;
00435 
00436 void 
00437 nfsd_init(int nfs_threads)
00438 {
00439     int nfs_socket;
00440     struct sockaddr_in saddr;
00441     int addr_size, socksz;
00442     static char namebuf[MAXHOSTNAMELEN + 32];
00443     char *p;
00444     int i;
00445     Basics::thread_attr nfsda;
00446 
00447     /* Set MyNFSSocket for use in other modules */
00448     gethostname(namebuf, sizeof(namebuf));
00449     p = &namebuf[strlen(namebuf)];
00450     sprintf(p, ":%d", nfs_port);
00451     MyNFSSocket = namebuf;
00452 
00453     nfs_socket = 0;
00454     socksz = nfs_bufreqs * (NFS_MAXDATA + 1024);
00455     if ((nfs_socket = makesock(nfs_port, IPPROTO_UDP, socksz)) < 0) {
00456       int saved_errno = errno;
00457       Text etxt = Basics::errno_Text(saved_errno);
00458       fprintf(stderr,
00459               "nfsd: could not make a UDP socket: %s\n",
00460               etxt.cchars());
00461       exit(1);
00462     }
00463 
00464     if (nfs_threads == 0) nfs_threads = 1;
00465 
00466     nfsda.set_stacksize(256000L); /* guess */
00467 
00468 #if defined (_POSIX_THREAD_PRIORITY_SCHEDULING) && !defined(__linux__)
00469     // Linux only allows the superuser to use SCHED_RR
00470     nfsda.set_schedpolicy(SCHED_RR);
00471     nfsda.set_inheritsched(PTHREAD_EXPLICIT_SCHED);
00472     nfsda.set_sched_priority(sched_get_priority_min(SCHED_RR));
00473 #endif
00474 
00475     /* Attempt to work around bug in DEC threads that causes the
00476        nfsd threads to hang at times.  It didn't help, but I'm
00477        leaving it in anyway, since all these threads block in the
00478        kernel a lot. */
00479     // pthread_attr_setscope(&nfsda, PTHREAD_SCOPE_SYSTEM);
00480 
00481     nfsd_threads = NEW_PTRFREE_ARRAY(Basics::thread, nfs_threads);
00482     for (i=0; i<nfs_threads; i++) {
00483         /* There should be no reason to dup nfs_socket, but doing
00484            so *does* seem to work around the bug in DEC threads that
00485            otherwise makes all the nfsd threads hang at times.  (This
00486            hang does not occur when we link with the Mike Burrows thread
00487            library.)
00488            */
00489       nfsd_threads[i].fork(nfsd_thread,
00490                            reinterpret_cast<void *>(dup(nfs_socket)),
00491                            nfsda);
00492     }
00493 }
00494 

Generated on Mon May 8 00:48:45 2006 for Vesta by  doxygen 1.4.2