devmntn.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "../port/error.h"
  15. /*
  16. * References are managed as follows:
  17. * The channel to the server - a network connection or pipe - has one
  18. * reference for every Chan open on the server. The server channel has
  19. * c->mux set to the Mnt used for muxing control to that server. Mnts
  20. * have no reference count; they go away when c goes away.
  21. * Each channel derived from the mount point has mchan set to c,
  22. * and increfs/decrefs mchan to manage references on the server
  23. * connection.
  24. */
  25. #define MAXRPC (IOHDRSZ + 128 * 1024)
  26. struct Mntrpc {
  27. Chan *c; /* Channel for whom we are working */
  28. Mntrpc *list; /* Free/pending list */
  29. Fcall request; /* Outgoing file system protocol message */
  30. Fcall reply; /* Incoming reply */
  31. Mnt *m; /* Mount device during rpc */
  32. Rendez r; /* Place to hang out */
  33. u8 *rpc; /* I/O Data buffer */
  34. u32 rpclen; /* len of buffer */
  35. Block *b; /* reply blocks */
  36. char done; /* Rpc completed */
  37. u64 stime; /* start time for mnt statistics */
  38. u32 reqlen; /* request length for mnt statistics */
  39. u32 replen; /* reply length for mnt statistics */
  40. Mntrpc *flushed; /* message this one flushes */
  41. };
  42. enum {
  43. TAGSHIFT = 5, /* u32 has to be 32 bits */
  44. TAGMASK = (1 << TAGSHIFT) - 1,
  45. NMASK = (64 * 1024) >> TAGSHIFT,
  46. };
  47. struct Mntalloc {
  48. Lock Lock;
  49. Mnt *list; /* Mount devices in use */
  50. Mnt *mntfree; /* Free list */
  51. Mntrpc *rpcfree;
  52. int nrpcfree;
  53. int nrpcused;
  54. u32 id;
  55. u32 tagmask[NMASK];
  56. } mntalloc;
  57. Mnt *mntchk(Chan *);
  58. void mntdirfix(u8 *, Chan *);
  59. Mntrpc *mntflushalloc(Mntrpc *, u32);
  60. void mntflushfree(Mnt *, Mntrpc *);
  61. void mntfree(Mntrpc *);
  62. void mntgate(Mnt *);
  63. void mntpntfree(Mnt *);
  64. void mntqrm(Mnt *, Mntrpc *);
  65. Mntrpc *mntralloc(Chan *, u32);
  66. i32 mntrdwr(int, Chan *, void *, i32, i64);
  67. int mntrpcread(Mnt *, Mntrpc *);
  68. void mountio(Mnt *, Mntrpc *);
  69. void mountmux(Mnt *, Mntrpc *);
  70. void mountrpc(Mnt *, Mntrpc *);
  71. int rpcattn(void *);
  72. Chan *mntchann(void);
  73. extern char Esbadstat[];
  74. extern char Enoversion[];
  75. void (*mntstats)(int, Chan *, u64, u32);
  76. static void
  77. mntreset(void)
  78. {
  79. mntalloc.id = 1;
  80. mntalloc.tagmask[0] = 1; /* don't allow 0 as a tag */
  81. mntalloc.tagmask[NMASK - 1] = 0x80000000UL; /* don't allow NOTAG */
  82. fmtinstall('F', fcallfmt);
  83. fmtinstall('D', dirfmt);
  84. /* We can't install %M since eipfmt does and is used in the kernel [sape] */
  85. if(mfcinit != nil)
  86. mfcinit();
  87. }
  88. static Chan *
  89. mntattach(char *muxattach)
  90. {
  91. return mntattachversion(muxattach, "9P2000.L", Tlattach, mntchann);
  92. }
  93. static Walkqid *
  94. mntwalk(Chan *c, Chan *nc, char **name, int nname)
  95. {
  96. Proc *up = externup();
  97. int i, alloc;
  98. Mnt *mnt;
  99. Mntrpc *r;
  100. Walkqid *wq;
  101. if(nc != nil)
  102. print("mntwalk: nc != nil\n");
  103. if(nname > MAXWELEM)
  104. error("devmnt: too many name elements");
  105. alloc = 0;
  106. wq = smalloc(sizeof(Walkqid) + (nname - 1) * sizeof(Qid));
  107. if(waserror()){
  108. if(alloc && wq->clone != nil)
  109. cclose(wq->clone);
  110. free(wq);
  111. return nil;
  112. }
  113. alloc = 0;
  114. mnt = mntchk(c);
  115. r = mntralloc(c, mnt->msize);
  116. if(nc == nil){
  117. nc = devclone(c);
  118. /*
  119. * Until the other side accepts this fid,
  120. * we can't mntclose it.
  121. * nc->dev remains nil for now.
  122. */
  123. alloc = 1;
  124. }
  125. wq->clone = nc;
  126. if(waserror()){
  127. mntfree(r);
  128. nexterror();
  129. }
  130. r->request.type = Twalk;
  131. r->request.fid = c->fid;
  132. r->request.newfid = nc->fid;
  133. r->request.nwname = nname;
  134. memmove(r->request.wname, name, nname * sizeof(char *));
  135. mountrpc(mnt, r);
  136. if(r->reply.nwqid > nname)
  137. error("too many QIDs returned by walk");
  138. if(r->reply.nwqid < nname){
  139. if(alloc)
  140. cclose(nc);
  141. wq->clone = nil;
  142. if(r->reply.nwqid == 0){
  143. free(wq);
  144. wq = nil;
  145. goto Return;
  146. }
  147. }
  148. /* move new fid onto mnt device and update its qid */
  149. if(wq->clone != nil){
  150. if(wq->clone != c){
  151. wq->clone->dev = c->dev;
  152. //if(wq->clone->dev != nil) //XDYNX
  153. // devtabincr(wq->clone->dev);
  154. wq->clone->mchan = c->mchan;
  155. incref(&c->mchan->r);
  156. }
  157. if(r->reply.nwqid > 0)
  158. wq->clone->qid = r->reply.wqid[r->reply.nwqid - 1];
  159. }
  160. wq->nqid = r->reply.nwqid;
  161. for(i = 0; i < wq->nqid; i++)
  162. wq->qid[i] = r->reply.wqid[i];
  163. Return:
  164. poperror();
  165. mntfree(r);
  166. poperror();
  167. return wq;
  168. }
  169. // Here is the other place the mistakes in 9P2000.L bite us.
  170. // Putting all this system-dependent stuff in 9P is nasty but we can take it.
  171. // size[4] Tgetattr tag[2] fid[4] request_mask[8]
  172. // size[4] Rgetattr tag[2] valid[8] qid[13] mode[4] uid[4] gid[4] nlink[8]
  173. // rdev[8] size[8] blksize[8] blocks[8]
  174. // atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]
  175. // ctime_sec[8] ctime_nsec[8] btime_sec[8] btime_nsec[8]
  176. // gen[8] data_version[8]
  177. //
  178. // 9P:
  179. // size[2] total byte count of the following data
  180. // type[2] for kernel use
  181. // dev[4] for kernel use
  182. // qid.type[1]the type of the file (directory, etc.), represented as a bit vector corresponding to the high 8 bits of the file's mode word.
  183. // qid.vers[4]version number for given path
  184. // qid.path[8]the file server's unique identification for the file
  185. // mode[4] permissions and flags
  186. // atime[4] last access time
  187. // mtime[4] last modification time
  188. // length[8] length of file in bytes
  189. // name[ s ] file name; must be / if the file is the root directory of the server
  190. // uid[ s ] owner name
  191. // gid[ s ] group name
  192. // muid[ s ] name of the user who last modified the file
  193. static i32
  194. mntstat(Chan *c, u8 *dp, i32 n)
  195. {
  196. Proc *up = externup();
  197. Mnt *mnt;
  198. Mntrpc *r;
  199. usize nstat, nl;
  200. char *name;
  201. u8 *buf;
  202. if(n < BIT16SZ)
  203. error(Eshortstat);
  204. mnt = mntchk(c);
  205. r = mntralloc(c, mnt->msize);
  206. if(waserror()){
  207. mntfree(r);
  208. nexterror();
  209. }
  210. r->request.type = Tgetattr;
  211. r->request.fid = c->fid;
  212. mountrpc(mnt, r);
  213. name = chanpath(c);
  214. nl = strlen(name);
  215. buf = (u8 *)r->reply.data;
  216. nstat = STATFIXLEN + nl + 16; // max uid print + 0 null terminator
  217. // This looks crazy, right? It's how you tell the
  218. // caller there is more data to read. But you give it
  219. // no data. That avoids the mess of partial reads of
  220. // stat structs. The calling layer will likely hide the
  221. // mess under the rock.
  222. if(nstat > n){
  223. nstat = BIT16SZ;
  224. PBIT16(dp, nstat - 2);
  225. } else {
  226. // N.B. STATFIXLEN includes the strings lengths
  227. // AND the leading 16-bit size. The leading 16-bit size
  228. // is of a packet with 0 length strings is STATFIXLEN - 2
  229. // The offsets below include the leading 16-bit size
  230. u64 _64;
  231. u32 _32;
  232. int ul;
  233. // This is an offset for where the strings go.
  234. int o = STATFIXLEN - 4 * BIT16SZ + BIT16SZ;
  235. char *base = strrchr(name, '/');
  236. // If there is on no /, use the name, else use the
  237. // part of the string after the slash. This works
  238. // even if the name ends in /.
  239. if(base != nil)
  240. name = base + 1;
  241. nl = strlen(name);
  242. //hexdump(buf, 149);
  243. memset(dp, 0, n);
  244. // The Qid format is compatible, so just copy it.
  245. memmove(dp + 8, buf + 8, sizeof(Qid));
  246. // mode. It needs adjustment for DMDIR.
  247. _32 = GBIT32(buf + 21);
  248. if(buf[8] & QTDIR){
  249. _32 |= DMDIR;
  250. }
  251. PBIT32(dp + 21, _32);
  252. // The time wire format is compatible but sadly the sizes
  253. // differ. We have to get it and put it.
  254. // Plan 9 has a y2032 problem!
  255. _64 = GBIT64(buf + 48);
  256. PBIT32(dp + 25, (u32)_64);
  257. _64 = GBIT64(buf + 64);
  258. PBIT32(dp + 29, (u32)_64);
  259. // file length. Compatible bit encoding.
  260. memmove(dp + 33, buf + 49, sizeof(u64));
  261. // put the name as a string.
  262. sprint((char *)dp + o, "%s", name);
  263. // There are four BIT16SZ lengths at the
  264. // end. If they are > 0 then the strings are interspersed
  265. // between them.
  266. PBIT16(dp + o - 2, nl);
  267. o += nl + BIT16SZ;
  268. // UID
  269. _32 = GBIT32(buf + 25);
  270. // The next name is at o
  271. sprint((char *)dp + o, "%d", _32);
  272. // strlen safe as we zero the buffer?
  273. ul = strlen((char *)dp + o);
  274. PBIT16(dp + o - 2, ul);
  275. o += ul + BIT16SZ;
  276. nstat = o;
  277. // GID
  278. _32 = GBIT32(buf + 29);
  279. // The next name is at o
  280. sprint((char *)dp + o, "%d", _32);
  281. // strlen safe as we zero the buffer?
  282. ul = strlen((char *)dp + o);
  283. PBIT16(dp + o - 2, ul);
  284. o += ul;
  285. nstat = o;
  286. // MUID is empty
  287. nstat += 1 * BIT16SZ;
  288. // nstat includes whole stat size, but
  289. // the size in the record does not.
  290. // Subtract BIT16SZ for that reason.
  291. PBIT16(dp, nstat - BIT16SZ);
  292. validstat(dp, nstat);
  293. mntdirfix(dp, c);
  294. //hexdump(dp,nstat);
  295. }
  296. mntfree(r);
  297. poperror();
  298. return nstat;
  299. }
  300. // TODO: can we merge with the one in devmnt.c
  301. static Chan *
  302. mntopencreate(int type, Chan *c, char *name, int omode, int perm)
  303. {
  304. Proc *up = externup();
  305. Mnt *mnt;
  306. Mntrpc *r;
  307. mnt = mntchk(c);
  308. r = mntralloc(c, mnt->msize);
  309. if(waserror()){
  310. mntfree(r);
  311. nexterror();
  312. }
  313. r->request.type = type;
  314. r->request.fid = c->fid;
  315. // 9P2000.L -- another mess?
  316. if(omode == OEXEC)
  317. r->request.mode = OREAD;
  318. else
  319. r->request.mode = omode;
  320. if(type == Tcreate){
  321. r->request.perm = perm;
  322. r->request.name = name;
  323. }
  324. mountrpc(mnt, r);
  325. c->qid = r->reply.qid;
  326. c->offset = 0;
  327. c->mode = openmode(omode);
  328. c->iounit = r->reply.iounit;
  329. c->writeoffset = 0;
  330. c->buffend = 0;
  331. c->writebuff = nil;
  332. c->buffsize = mnt->msize;
  333. if(c->iounit == 0 || c->iounit > mnt->msize - IOHDRSZ)
  334. c->iounit = mnt->msize - IOHDRSZ;
  335. c->flag |= COPEN;
  336. poperror();
  337. mntfree(r);
  338. if(c->flag & CCACHE)
  339. mfcopen(c);
  340. return c;
  341. }
  342. static Chan *
  343. mntopen(Chan *c, int omode)
  344. {
  345. // 9P2000.L differentiates by file type,
  346. // unlike Plan 9. We have to treat, e.g.,
  347. // directories and files differently (!).
  348. // Using different system calls for files
  349. // and directories is a great idea, said
  350. // no one ever.
  351. u8 t = c->qid.type;
  352. if(t & QTDIR){
  353. } else if(t){
  354. error("only dirs or regular files");
  355. }
  356. return mntopencreate(Tlopen, c, nil, omode, 0);
  357. }
  358. static void
  359. mntcreate(Chan *c, char *name, int omode, int perm)
  360. {
  361. mntopencreate(Tlcreate, c, name, omode, perm);
  362. }
  363. static void
  364. mntclunk(Chan *c, int t)
  365. {
  366. Proc *up = externup();
  367. Mnt *mnt;
  368. Mntrpc *r;
  369. mnt = mntchk(c);
  370. r = mntralloc(c, mnt->msize);
  371. if(waserror()){
  372. mntfree(r);
  373. nexterror();
  374. }
  375. r->request.type = t;
  376. r->request.fid = c->fid;
  377. mountrpc(mnt, r);
  378. mntfree(r);
  379. poperror();
  380. }
  381. static void
  382. mntclose(Chan *c)
  383. {
  384. if(c->buffend > 0){
  385. mntrdwr(Twrite, c, c->writebuff, c->buffend, c->writeoffset);
  386. }
  387. c->buffend = 0;
  388. free(c->writebuff);
  389. c->writebuff = nil;
  390. mntclunk(c, Tclunk);
  391. }
  392. static void
  393. mntremove(Chan *c)
  394. {
  395. mntclunk(c, Tremove);
  396. }
  397. static i32
  398. mntwstat(Chan *c, u8 *dp, i32 n)
  399. {
  400. Proc *up = externup();
  401. Mnt *mnt;
  402. Mntrpc *r;
  403. mnt = mntchk(c);
  404. r = mntralloc(c, mnt->msize);
  405. if(waserror()){
  406. mntfree(r);
  407. nexterror();
  408. }
  409. r->request.type = Twstat;
  410. r->request.fid = c->fid;
  411. r->request.nstat = n;
  412. r->request.stat = dp;
  413. mountrpc(mnt, r);
  414. poperror();
  415. mntfree(r);
  416. return n;
  417. }
  418. static i32
  419. mntread(Chan *c, void *buf, i32 n, i64 off)
  420. {
  421. Proc *up = externup();
  422. u8 *p, *e;
  423. int nc, cache, isdir;
  424. isdir = 0;
  425. cache = c->flag & CCACHE;
  426. if(c->qid.type & QTDIR){
  427. cache = 0;
  428. isdir = 1;
  429. }
  430. p = buf;
  431. if(cache){
  432. nc = mfcread(c, buf, n, off);
  433. if(nc > 0){
  434. n -= nc;
  435. if(n == 0)
  436. return nc;
  437. p += nc;
  438. off += nc;
  439. }
  440. n = mntrdwr(Tread, c, p, n, off);
  441. mfcupdate(c, p, n, off);
  442. return n + nc;
  443. }
  444. // Flush if we're reading this file. Would be nice to see if
  445. // read could be satisfied from buffer.
  446. if(c->buffend > 0){
  447. mntrdwr(Twrite, c, c->writebuff, c->buffend, c->writeoffset);
  448. }
  449. // Long story.
  450. // Reads on directories have taken a long path. In the original 45 years ago Unix I cut my teeth on,
  451. // one could open a file and read it. If it were a directory, data was returned as 14 bytes of name
  452. // and 2 bytes of inumber.
  453. // There were obvious problems here, the most basic being that the on-disk format was directly
  454. // returned to a program. Hence readdir, which was an attempt at an abstraction: it returned
  455. // the names and little else. So what happens in, say, ls -l? it looks something like this:
  456. // entries := readdir()
  457. // for each entry, stat() the entry.
  458. // Now it was well known in the 1980s that this is a disaster on a network: there is at
  459. // least one packet for each directory entry.
  460. // For directory reads, it's much, much better to grow the amount
  461. // of data in a packet, even data not used, than to add lots of packets when more
  462. // info is needed. Measurement has shown this over and over. Hence NFS3 READDIRPLUS.
  463. // Plan 9 and 9P, circa 1991, introduced a major improvement:
  464. // directories are like files, and one can now read them again. This is really important:
  465. // o means you can import a directory over 9p and just read from it
  466. // o removes a need for a readdir system call
  467. // o avoids a special op in 9p to read directories
  468. // o no need to have the kernel unpack the information, just relay to user space
  469. // Were readdir brought into 9P, the addition would impact 9P, the kernel, all user
  470. // libraries, and all user programs, in not very good ways.
  471. // This is one of the subtle design elements of Plan 9 that not even many Plan 9 users
  472. // think about.
  473. // Directory reads return stat records, which are an endian- and word-length independent
  474. // representation of the file metadata.
  475. // 9p supports this kind of read directly.
  476. // A read of a directory on Plan 9 returns metadata, in other words, so there are no
  477. // extra stats per entry as in the Unix model.
  478. // Unix and Linux, sadly, retained the old model. A Linux readdir returns dirents.
  479. // If you want to know more, stat each entry. We're back to the bad old days.
  480. // What's this look like on 9P?
  481. // 1. read the dir
  482. // 2. for each element, walk to it.
  483. // 3. stat it.
  484. // 9P2000.L had a chance to fix this in a way that would have worked well for Plan 9
  485. // as well as some hypothetical future Linux with a more powerful readdir model,
  486. // but sadly it instead baked in those limitations.
  487. // We don't want to reflect that mess to user mode in Harvey, so we have to
  488. // convert the 9P2000.L information to plan 9 stat structs, losing information
  489. // in the process.
  490. // 9P2000.L stat information looks like this:
  491. // qid[13] offset[8] type[1] name[s]
  492. //
  493. // Plan 9 stat looks like this:
  494. //
  495. // size[2] total byte count of the following data
  496. // type[2] for kernel use
  497. // dev[4] for kernel use
  498. // qid.type[1] the type of the file (directory, etc.), represented as a bit vector corresponding to the high 8 bits of the file's mode word.
  499. // qid.vers[4] version number for given path
  500. // qid.path[8] the file server's unique identification for the file
  501. // mode[4] permissions and flags
  502. // atime[4] last access time
  503. // mtime[4] last modification time
  504. // length[8] length of file in bytes
  505. // name[ s ] file name; must be / if the file is the root directory of the server
  506. // uid[ s ] owner name
  507. // gid[ s ] group name
  508. // muid[ s ] name of the user who last modified the file
  509. //
  510. // Important point here: note that in 9P2000.L, they had to add a stat structure.
  511. // There is no such thing needed in 9P2000; it's the province of the kernel, not
  512. // the protocol. Hopefully this illustrates the differences in the model.
  513. //
  514. // The size of a 9P stat struct is:
  515. // ../../../include/fcall.h:#define STATFIXLEN (BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ) amount of fixed length data in a stat buffer */
  516. // size + qidsz + what is that 5? type and 4 sizes for strings + dev,mod,atime,mtime + length
  517. // Note that for now we can only fill in the name; to better fill this in we'll need to do the
  518. // walk/stat operation.
  519. // Rough algorithm:
  520. // zero buf. Useful so that the default length strings for uid, gid, muid will be empty.
  521. // compute length of record.
  522. // copy the name out. copy the qid out. copy the record size out. Continue.
  523. memset(buf, 0, n);
  524. if(isdir){
  525. u8 *b = buf;
  526. int tot = 0;
  527. int a = n / 8;
  528. if(a == 0)
  529. a = 128;
  530. u8 *m = mallocz(n, 0);
  531. if(waserror()){
  532. free(m);
  533. }
  534. memset(m, 0, n);
  535. n = mntrdwr(Treaddir, c, m, a, off);
  536. if(n == 0){
  537. free(m);
  538. poperror();
  539. return tot;
  540. }
  541. if(n < 4)
  542. error(Esbadstat);
  543. // TODO: we're going to have to stat each returned
  544. // entry because this 9P2000.L design requires us to.
  545. // Why is it that way? To match how Linux works.
  546. // And Linux works the way Unix worked in 1972.
  547. // Fantastic.
  548. p = m;
  549. e = &m[n];
  550. while(p < e){
  551. int namesz = GBIT16(p + 22);
  552. // Move the Qid. No need to change it; 9P2000.L and 9P Qids are the same.
  553. memmove(b + 8, p, sizeof(Qid));
  554. // Move the name, including the name's length.
  555. memmove(b + 41, p + 22, namesz + BIT16SZ);
  556. // Story the whole record length, not including the
  557. // the 16-bit length field.
  558. // "size[2] total byte count of the following data"
  559. PBIT16(b, STATFIXLEN + namesz - BIT16SZ);
  560. // advance p by the size of the 9P2000.L record
  561. p += 24 + namesz;
  562. // advance b by the size of the Plan 9 stat record
  563. b += STATFIXLEN + namesz;
  564. }
  565. if(p != e)
  566. error(Esbadstat);
  567. n = b - (u8 *)buf;
  568. free(m);
  569. poperror();
  570. } else {
  571. n = mntrdwr(Tread, c, buf, n, off);
  572. }
  573. return n;
  574. }
  575. static i32
  576. mntwrite(Chan *c, void *buf, i32 n, i64 off)
  577. {
  578. int result = n;
  579. int offset = 0;
  580. if(c->writebuff == nil){
  581. c->writebuff = (unsigned char *)malloc(c->buffsize);
  582. if(c->writebuff == nil){
  583. print("devmntn: write buffer allocation of %d bytes failed\n", c->buffsize);
  584. return mntrdwr(Twrite, c, buf, n, off);
  585. }
  586. }
  587. if(off != c->writeoffset + c->buffend){
  588. // non-continuous write - flush cached data
  589. mntrdwr(Twrite, c, c->writebuff, c->buffend, c->writeoffset);
  590. c->buffend = 0;
  591. c->writeoffset = off;
  592. }
  593. while(n + c->buffend >= c->buffsize){
  594. offset = c->mux->msize - c->buffend;
  595. n -= offset;
  596. memmove(&c->writebuff[c->buffend], buf, offset);
  597. mntrdwr(Twrite, c, c->writebuff, c->mux->msize, c->writeoffset);
  598. c->writeoffset += offset;
  599. }
  600. memmove(&c->writebuff[c->buffend], buf + offset, n);
  601. c->buffend += n;
  602. return result;
  603. }
  604. Chan *
  605. mntchann(void)
  606. {
  607. Chan *c;
  608. c = devattach('N', 0);
  609. lock(&mntalloc.Lock);
  610. c->devno = mntalloc.id++;
  611. unlock(&mntalloc.Lock);
  612. if(c->mchan)
  613. panic("mntchan non-zero %#p", c->mchan);
  614. return c;
  615. }
  616. Dev mntndevtab = {
  617. .dc = 'N',
  618. .name = "mntn",
  619. .reset = mntreset,
  620. .init = devinit,
  621. .shutdown = devshutdown,
  622. .attach = mntattach,
  623. .walk = mntwalk,
  624. .stat = mntstat,
  625. .open = mntopen,
  626. .create = mntcreate,
  627. .close = mntclose,
  628. .read = mntread,
  629. .bread = devbread,
  630. .write = mntwrite,
  631. .bwrite = devbwrite,
  632. .remove = mntremove,
  633. .wstat = mntwstat,
  634. };