00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #ifdef __linux__
00042
00043 #define _XOPEN_SOURCE 500
00044
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();
00068
00069 void
00070 mallocfailed()
00071 {
00072 Repos::dprintf(DBG_ALWAYS, "malloc failed -- exiting\n");
00073 exit(1);
00074 }
00075
00076
00077
00078
00079
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;
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;
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
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
00405 if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
00406 svcerr_auth(xprt, why);
00407 continue;
00408 }
00409 RECORD_TIME_POINT;
00410
00411
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
00419
00420 svcerr_progvers(xprt, NFS_VERSION, NFS_VERSION);
00421 #else
00422 svcerr_progvers(xprt);
00423 #endif
00424 continue;
00425 }
00426
00427
00428 nfs_dispatch(&r, xprt);
00429 }
00430 }
00431
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
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);
00467
00468 #if defined (_POSIX_THREAD_PRIORITY_SCHEDULING) && !defined(__linux__)
00469
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
00476
00477
00478
00479
00480
00481 nfsd_threads = NEW_PTRFREE_ARRAY(Basics::thread, nfs_threads);
00482 for (i=0; i<nfs_threads; i++) {
00483
00484
00485
00486
00487
00488
00489 nfsd_threads[i].fork(nfsd_thread,
00490 reinterpret_cast<void *>(dup(nfs_socket)),
00491 nfsda);
00492 }
00493 }
00494