📄 server.c
字号:
/* * * Copyright (C) 2001 Josh Cates (cates@mit.edu), * Frank Dabek (fdabek@lcs.mit.edu), * Massachusetts Institute of Technology * * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */// KNOWN ISSUES:// * READDIR// - client always re-requests entries in a directory, why?// * READDIRP// - completely broken/not really implemented// * READ// - does not deal with request which span blocks// - pre-fetching not implemented// * LOOKUP// - linear scan algo could be improved, to return NOENT// when it is sure that the entry does not exists// - or binary lookup could be implemented// * GENERAL// - possibly, embedded inodes to improve LOOKUP performance// - can make lots of optimizations to filesystem structure which are easy when// the FS is read-only, but hard in a read-write filesystem, namely embedded inodes// - copy the dispatch routine from sfsrocd// * XXX// - search for this and find more things to fix// // fileids == lower_64_bits (sha1(path))// sfs_hash == chordID == nfs_fh3//#include <dhash_common.h>#include <dhblock_keyhash.h>#include "chordcd.h"#include "rxx.h"#include "arpc.h"#include "xdr_suio.h"#include "afsnode.h"#include "id_utils.h"#define LSD_SOCKET "/tmp/chord-sock"#define CMTU 1024#define PREFETCH_BLOCKS 8static void splitpath (vec<str> &out, str in);static fattr3 ro2nfsattr (sfsro_inode *si);// XXX keep in sync with same function in sfsrodb/sfsrodb.Cstatic uint64path2fileid(const str path){ char buf[sha1::hashsize]; bzero(buf, sha1::hashsize); sha1_hash (buf, path.cstr (), path.len ()); return gethyper (buf); // XXX not using all 160 bits of the hash}chord_server::chord_server (u_int cache_maxsize) : dh (LSD_SOCKET), data_cache (cache_maxsize){}voidchord_server::setrootfh (str root, cbfh_t rfh_cb){ static rxx path_regexp ("chord:([0-9a-zA-Z+-]*)$"); if (!path_regexp.search (root)) { warn << "Malformated root filesystem name: " << root << "\n"; (*rfh_cb) (NULL); } else { str rootfhstr = path_regexp[1]; chordID ID; if (!str2chordID (rootfhstr, ID)) { warn << "Malformed root filesystem name: " << root << "\n"; (*rfh_cb) (NULL); } warn << "reading root " << ID << "\n"; //fetch the root file handle too.. fetch_data (false, ID, DHASH_KEYHASH, wrap (this, &chord_server::getroot_fh, rfh_cb)); }}voidchord_server::getroot_fh (cbfh_t rfh_cb, ptr<sfsro_data> d){ if (!d) { warn << "root block was null\n"; (*rfh_cb) (NULL); } else if (d->type != CFS_FSINFO) { warn << "root block had wrong type\n"; (*rfh_cb) (NULL); } else { warn << "Mounted filesystem.\n"; warn << " start : " << ctime((time_t *)&(d->fsinfo->start)); warn << " duration : " << d->fsinfo->duration << " seconds \n"; warn << " blocksize : " << d->fsinfo->blocksize << "\n"; this->rootdirID = d->fsinfo->rootfh; this->fsinfo = *d->fsinfo; fetch_data (false, rootdirID, wrap (this, &chord_server::getrootdir_cb, rfh_cb)); }} voidchord_server::getrootdir_cb (cbfh_t rfh_cb, ptr<sfsro_data> data){ if (data && data->type == SFSRO_INODE && data->inode->type == SFSRODIR) { this->rootdir = data; // XXX verify file handle nfs_fh3 *fh = New nfs_fh3; chordid_to_nfsfh (&rootdirID, fh); (*rfh_cb) (fh); } else { warn << "root directory invalid\n"; (*rfh_cb) (NULL); }}voidchord_server::dispatch (ref<nfsserv> ns, nfscall *sbp){ switch(sbp->proc()) { case NFSPROC3_READLINK: { nfs_fh3 *nfh = sbp->Xtmpl getarg<nfs_fh3> (); chordID fh = nfsfh_to_chordid (nfh); fetch_data (false, fh, wrap (this, &chord_server::readlink_inode_cb, sbp, fh)); } break; case NFSPROC3_GETATTR: { nfs_fh3 *nfh = sbp->Xtmpl getarg<nfs_fh3> (); chordID fh = nfsfh_to_chordid (nfh); fetch_data (false, fh, wrap (this, &chord_server::getattr_inode_cb, sbp, fh)); } break; case NFSPROC3_FSSTAT: { fsstat3res res (NFS3_OK); rpc_clear (res); sbp->reply (&res); } break; case NFSPROC3_FSINFO: { int blocksize = fsinfo.blocksize; fsinfo3res res (NFS3_OK); res.resok->rtmax = blocksize; res.resok->rtpref = blocksize; res.resok->rtmult = 512; res.resok->wtmax = blocksize; res.resok->wtpref = blocksize; res.resok->wtmult = 8192; res.resok->dtpref = blocksize; res.resok->maxfilesize = INT64 (0x7fffffffffffffff); res.resok->time_delta.seconds = 0; res.resok->time_delta.nseconds = 1; res.resok->properties = (FSF3_LINK | FSF3_SYMLINK | FSF3_HOMOGENEOUS); sbp->reply (&res); } break; case NFSPROC3_ACCESS: { access3args *aa = sbp->Xtmpl getarg<access3args> (); nfs_fh3 *nfh = &(aa->object); chordID fh = nfsfh_to_chordid (nfh); fetch_data (false, fh, wrap (this, &chord_server::access_inode_cb, sbp, fh)); } break; case NFSPROC3_LOOKUP: { diropargs3 *dirop = sbp->Xtmpl getarg<diropargs3> (); nfs_fh3 *nfh = &(dirop->dir); chordID fh = nfsfh_to_chordid (nfh); fetch_data (false, fh, wrap (this, &chord_server::lookup_inode_cb, sbp, fh)); } break; case NFSPROC3_READDIR: { readdir3args *readdirop = sbp->Xtmpl getarg<readdir3args> (); nfs_fh3 *nfh = &(readdirop->dir); chordID fh = nfsfh_to_chordid (nfh); fetch_data (false, fh, wrap (this, &chord_server::readdir_inode_cb, sbp, fh)); } break; case NFSPROC3_READDIRPLUS: { readdirplus3args *readdirop = sbp->Xtmpl getarg<readdirplus3args> (); nfs_fh3 *nfh = &(readdirop->dir); chordID fh = nfsfh_to_chordid (nfh); fetch_data (false, fh, wrap (this, &chord_server::readdirp_inode_cb, sbp, fh)); } break; case NFSPROC3_READ: { read3args *ra = sbp->Xtmpl getarg<read3args> (); nfs_fh3 *nfh = &(ra->file); chordID fh = nfsfh_to_chordid (nfh); fetch_data (false, fh, wrap (this, &chord_server::read_inode_cb, sbp, fh)); } break; case NFSPROC3_NULL: { sbp->reply (NULL); return; } break; case NFSPROC_CLOSE: break; default: { sbp->error (NFS3ERR_ROFS); return; } break; }}// ---------------- operations ---------------voidchord_server::readlink_inode_cb (nfscall *sbp, chordID ID, ptr<sfsro_data> data){ if (!data) sbp->error (NFS3ERR_STALE); else if (data->type != SFSRO_INODE) sbp->error (NFS3ERR_IO); else if (data->inode->type != SFSROLNK) sbp->error (NFS3ERR_IO); else if (data->inode->lnk->dest.len () <= 0) sbp->error (NFS3ERR_INVAL); else { readlink3res nfsres (NFS3_OK); nfsres.resok->data = data->inode->lnk->dest; sbp->reply(&nfsres); }}voidchord_server::getattr_inode_cb (nfscall *sbp, chordID ID, ptr<sfsro_data> data) { if (!data) sbp->error (NFS3ERR_STALE); else if (data->type != SFSRO_INODE) sbp->error (NFS3ERR_IO); else { getattr3res nfsres (NFS3_OK); *nfsres.attributes = ro2nfsattr (data->inode); sbp->reply (&nfsres); }}voidchord_server::access_inode_cb (nfscall *sbp, chordID ID, ptr<sfsro_data> data) { if (!data) sbp->error (NFS3ERR_STALE); else if (data->type != SFSRO_INODE) sbp->error (NFS3ERR_IO); else { access3args *aa = sbp->Xtmpl getarg<access3args> (); uint32 access_req = aa->access; access3res nfsres (NFS3_OK); nfsres.resok->access = access_check (data->inode, access_req); sbp->reply (&nfsres); }}uint32chord_server::access_check(sfsro_inode *ip, uint32 access_req){ uint32 r = 0; switch (ip->type) { case SFSRODIR: r = ACCESS3_READ | ACCESS3_LOOKUP; break; case SFSRODIR_OPAQ: r = ACCESS3_LOOKUP; break; case SFSROREG_EXEC: r = ACCESS3_READ | ACCESS3_EXECUTE; break; case SFSROLNK: case SFSROREG: r = ACCESS3_READ; break; } return (access_req & r);}voidchord_server::lookup_inode_cb (nfscall *sbp, chordID ID, ptr<sfsro_data> data){ if (!data) sbp->error (NFS3ERR_STALE); else if (data->type != SFSRO_INODE) sbp->error (NFS3ERR_IO); else if (data->inode->type != SFSRODIR && data->inode->type != SFSRODIR_OPAQ) sbp->error (NFS3ERR_NOTDIR); else { diropargs3 *dirop = sbp->Xtmpl getarg<diropargs3> (); lookup (data, ID, dirop->name, wrap (this, &chord_server::lookup_lookup_cb, sbp, data, ID)); }}voidchord_server::lookup_lookup_cb (nfscall *sbp, ptr<sfsro_data> dirdata, chordID dirID, ptr<sfsro_data> data, chordID dataID, nfsstat3 status){ if (status == NFS3_OK) { lookup3res *nfsres = sbp->Xtmpl getres<lookup3res> (); nfsres->set_status (NFS3_OK); nfsres->resok->dir_attributes.set_present (true); *nfsres->resok->dir_attributes.attributes = ro2nfsattr (dirdata->inode); nfs_fh3 nfh; chordid_to_nfsfh (&dataID, &nfh); nfsres->resok->object = nfh; nfsres->resok->obj_attributes.set_present (true); *nfsres->resok->obj_attributes.attributes = ro2nfsattr (data->inode); sbp->reply (nfsres); } else { sbp->error (status); }}voidchord_server::readdir_inode_cb (nfscall *sbp, chordID dataID, ptr<sfsro_data> data){ if (!data) sbp->error (NFS3ERR_STALE); else if (data->type != SFSRO_INODE) sbp->error (NFS3ERR_IO); else if (data->inode->type != SFSRODIR && data->inode->type != SFSRODIR_OPAQ) sbp->error (NFS3ERR_NOTDIR); else { readdir3args *nfsargs = sbp->Xtmpl getarg<readdir3args> (); uint32 blockno = nfsargs->cookie >> 32; read_file_data (false, blockno, data->inode->reg, wrap (this, &chord_server::readdir_fetch_dirdata_cb, sbp, data, dataID)); }}voidchord_server::readdir_fetch_dirdata_cb (nfscall *sbp, ptr<sfsro_data> dirInodeData, chordID dirInodeID, ptr<sfsro_data> dirblk){ if (dirblk == NULL) { sbp->error (NFS3ERR_IO); } else if (dirblk->type != SFSRO_DIRBLK) { sbp->error (NFS3ERR_IO); } else { readdir3args *nfsargs = sbp->Xtmpl getarg<readdir3args> (); uint32 blockno = nfsargs->cookie >> 32; uint32 entryno = (uint32)nfsargs->cookie; sfsro_directory *dir = dirblk->dir; readdir3res nfsres (NFS3_OK); nfsres.resok->dir_attributes.set_present (true); *nfsres.resok->dir_attributes.attributes = ro2nfsattr(dirInodeData->inode); nfsres.resok->reply.eof = false; rpc_ptr<entry3> *direntp = &nfsres.resok->reply.entries; sfsro_dirent *roe = dir->entries; int space = nfsargs->count - 184; // reserve hdr and trailing NULL dirent //warn << "------ cookie " << nfsargs->cookie << " ---------\n"; for (uint i = 1; space > 0 && roe ; roe = roe->nextentry, i++) { if (i <= entryno) continue; //warn << "i " << i << ", entryno " << entryno << ", space " << space; //warn << ", roe[" << roe->name << ", fileid " << roe->fileid << "]\n"; space -= ((roe->name.len() + 3) & ~3) + 24; // marshaled entry size if (space >= 0) { (*direntp).alloc (); (*direntp)->name = roe->name; (*direntp)->fileid = roe->fileid; (*direntp)->cookie = (uint64 (blockno)) << 32 | i; if (!roe) (*direntp)->cookie = (uint64 (blockno + 1)) << 32; direntp = &(*direntp)->nextentry; } } nfsres.resok->reply.eof = (!roe && dir->eof); sbp->reply (&nfsres); }}voidchord_server::readdirp_inode_cb (nfscall *sbp, chordID ID, ptr<sfsro_data> data){ if (!data) sbp->error (NFS3ERR_STALE); else if (data->type != SFSRO_INODE) sbp->error (NFS3ERR_IO); else if (data->inode->type != SFSRODIR && data->inode->type != SFSRODIR_OPAQ) sbp->error (NFS3ERR_NOTDIR); else { fetch_data (false, sfshash_to_chordid(&data->inode->reg->direct[0]), wrap (this, &chord_server::readdirp_fetch_dir_data, sbp, data, ID)); }}voidchord_server::readdirp_fetch_dir_data (nfscall *sbp, ptr<sfsro_data> dirdata, chordID dirID, ptr<sfsro_data> data) { sfsro_directory *dir = data->dir; readdirplus3args *readdirop = sbp->Xtmpl getarg<readdirplus3args> (); readdirplus3res *nfsres = sbp->Xtmpl getres<readdirplus3res> (); rpc_clear (*nfsres); nfsres->set_status (NFS3_OK); nfsres->resok->dir_attributes.set_present (true); *nfsres->resok->dir_attributes.attributes = ro2nfsattr (dirdata->inode); size_t off = readdirop->cookie; sfsro_dirent *roe = dir->entries; uint32 i = 0; while (roe) { roe = roe->nextentry; i++; } uint32 n = MIN(i, readdirop->maxcount); roe = dir->entries; rpc_ptr<entryplus3> *last = &(nfsres->resok->reply.entries); for (uint32 j = 0; j < n; j++) { (*last).alloc (); assert (0); //fh2fileid (&roe->fh, &(*last)->fileid); // XXX broken (*last)->name = roe->name; // XXX Make LINUX happy off += sizeof ((*last)->fileid) + roe->name.len(); if (j + 1 >= n) (*last)->cookie = INT64 (0x400ffffffff); else (*last)->cookie = off; (*last)->name_attributes.set_present(0); (*last)->name_handle.set_present(0); last = &(*last)->nextentry; roe = roe->nextentry; } nfsres->resok->reply.eof = (i < n) ? 0 : 1; sbp->reply (nfsres);}voidchord_server::read_inode_cb (nfscall *sbp, chordID ID, ptr<sfsro_data> data){ read3args *ra = sbp->Xtmpl getarg<read3args> (); if (!data) sbp->error (NFS3ERR_STALE); else if (data->type != SFSRO_INODE) sbp->error (NFS3ERR_IO); else if (data->inode->type != SFSROREG && data->inode->type != SFSROREG_EXEC) { sbp->error (NFS3ERR_IO); } else if (ra->offset >= data->inode->reg->size) { read3res nfsres(NFS3_OK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -