- filled in group field, previously missing.
[npfs.git] / fs / ufs.c
blobf6d4312d838c7d6fa3d1f9ef0bbda2f1db8b47c6
1 /*
2 * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * LATCHESAR IONKOV AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
23 //#define _XOPEN_SOURCE 500
24 #define _BSD_SOURCE
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <pthread.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <string.h>
34 #include <dirent.h>
35 #include <fcntl.h>
36 #include <utime.h>
37 #include "npfs.h"
38 #include "ufs.h"
40 #if SYSNAME == Linux
41 #define NPFS_USE_AIO
42 #else
43 #undef NPFS_USE_AIO
44 #endif
46 #undef NPFS_USE_AIO
48 #define NELEM(x) (sizeof(x)/sizeof((x)[0]))
50 typedef struct Fid Fid;
52 struct Fid {
53 char* path;
54 int omode;
55 int fd;
56 DIR* dir;
57 int diroffset;
58 char* direntname;
59 struct stat stat;
62 Npsrv *srv;
63 int debuglevel;
64 int sameuser;
66 char *Estatfailed = "stat failed";
67 char *Ebadfid = "fid unknown or out of range";
68 char *Enoextension = "empty extension while creating special file";
69 char *Eformat = "incorrect extension format";
70 char *Ecreatesocket = "cannot create socket";
71 //char *E = "";
73 static int fidstat(Fid *fid);
74 static void ustat2qid(struct stat *st, Npqid *qid);
75 static u8 ustat2qidtype(struct stat *st);
76 static u32 umode2npmode(mode_t umode, int dotu);
77 static mode_t npstat2umode(Npstat *st, int dotu);
78 static void ustat2npwstat(char *path, struct stat *st, Npwstat *wstat, int dotu, Npuserpool *up);
80 static int npfs_aio_read(Npfid *fid, Npfcall *rread, u64 offset, u32 count, Npreq *);
81 static int npfs_aio_write(Npfid *fid, u8 *data, u64 offset, u32 count, Npreq *);
83 #ifdef NPFS_USE_AIO
84 #include <libaio.h>
85 typedef struct Aioreq Aioreq;
87 struct Aioreq {
88 struct iocb iocb;
89 Npreq* req;
90 Npfid* fid;
91 Npfcall* rread;
92 Aioreq* next;
93 Aioreq* prev;
96 int use_aio = 1;
97 io_context_t aio_ctx;
98 pthread_mutex_t aio_lock = PTHREAD_MUTEX_INITIALIZER;
99 Aioreq *aio_reqs;
100 #else
101 int use_aio = 0;
102 #endif
104 pthread_t aio_thread;
106 static int
107 fidstat(Fid *fid)
109 if (lstat(fid->path, &fid->stat) < 0)
110 return errno;
112 if (S_ISDIR(fid->stat.st_mode))
113 fid->stat.st_size = 0;
115 return 0;
118 static Fid*
119 npfs_fidalloc() {
120 Fid *f;
122 f = malloc(sizeof(*f));
124 f->path = NULL;
125 f->omode = -1;
126 f->fd = -1;
127 f->dir = NULL;
128 f->diroffset = 0;
129 f->direntname = NULL;
131 return f;
134 void
135 npfs_fiddestroy(Npfid *fid)
137 Fid *f;
139 f = fid->aux;
140 if (!f)
141 return;
143 if (f->fd != -1)
144 close(f->fd);
146 if (f->dir)
147 closedir(f->dir);
149 free(f->path);
150 free(f);
153 static void
154 create_rerror(int ecode)
156 char buf[256];
158 strerror_r(ecode, buf, sizeof(buf));
159 np_werror(buf, ecode);
162 static int
163 omode2uflags(u8 mode)
165 int ret;
167 ret = 0;
168 switch (mode & 3) {
169 case Oread:
170 ret = O_RDONLY;
171 break;
173 case Ordwr:
174 ret = O_RDWR;
175 break;
177 case Owrite:
178 ret = O_WRONLY;
179 break;
181 case Oexec:
182 ret = O_RDONLY;
183 break;
186 if (mode & Otrunc)
187 ret |= O_TRUNC;
189 if (mode & Oappend)
190 ret |= O_APPEND;
192 if (mode & Oexcl)
193 ret |= O_EXCL;
195 return ret;
198 static void
199 ustat2qid(struct stat *st, Npqid *qid)
201 int n;
203 qid->path = 0;
204 n = sizeof(qid->path);
205 if (n > sizeof(st->st_ino))
206 n = sizeof(st->st_ino);
207 memmove(&qid->path, &st->st_ino, n);
208 qid->version = st->st_mtime ^ (st->st_size << 8);
209 qid->type = ustat2qidtype(st);
212 static u8
213 ustat2qidtype(struct stat *st)
215 u8 ret;
217 ret = 0;
218 if (S_ISDIR(st->st_mode))
219 ret |= Qtdir;
221 if (S_ISLNK(st->st_mode))
222 ret |= Qtsymlink;
224 return ret;
227 static u32
228 umode2npmode(mode_t umode, int dotu)
230 u32 ret;
232 ret = umode & 0777;
233 if (S_ISDIR(umode))
234 ret |= Dmdir;
236 if (dotu) {
237 if (S_ISLNK(umode))
238 ret |= Dmsymlink;
239 if (S_ISSOCK(umode))
240 ret |= Dmsocket;
241 if (S_ISFIFO(umode))
242 ret |= Dmnamedpipe;
243 if (S_ISBLK(umode))
244 ret |= Dmdevice;
245 if (S_ISCHR(umode))
246 ret |= Dmdevice;
247 if (umode & S_ISUID)
248 ret |= Dmsetuid;
249 if (umode & S_ISGID)
250 ret |= Dmsetgid;
253 return ret;
256 static mode_t
257 np2umode(u32 mode, Npstr *extension, int dotu)
259 mode_t ret;
261 ret = mode & 0777;
262 if (mode & Dmdir)
263 ret |= S_IFDIR;
265 if (dotu) {
266 if (mode & Dmsymlink)
267 ret |= S_IFLNK;
268 if (mode & Dmsocket)
269 ret |= S_IFSOCK;
270 if (mode & Dmnamedpipe)
271 ret |= S_IFIFO;
272 if (mode & Dmdevice) {
273 if (extension && extension->str[0] == 'c')
274 ret |= S_IFCHR;
275 else
276 ret |= S_IFBLK;
280 if (!(ret&~0777))
281 ret |= S_IFREG;
283 if (mode & Dmsetuid)
284 ret |= S_ISUID;
285 if (mode & Dmsetgid)
286 ret |= S_ISGID;
288 return ret;
291 static mode_t
292 npstat2umode(Npstat *st, int dotu)
294 return np2umode(st->mode, &st->extension, dotu);
297 static void
298 ustat2npwstat(char *path, struct stat *st, Npwstat *wstat, int dotu, Npuserpool *up)
300 int err;
301 Npuser *u;
302 Npgroup *g;
303 char *s, ext[256];
305 memset(wstat, 0, sizeof(*wstat));
306 ustat2qid(st, &wstat->qid);
307 wstat->mode = umode2npmode(st->st_mode, dotu);
308 wstat->atime = st->st_atime;
309 wstat->mtime = st->st_mtime;
310 wstat->length = st->st_size;
312 u = up->uid2user(up, st->st_uid);
313 g = up->gid2group(up, st->st_gid);
315 wstat->uid = u?u->uname:"???";
316 wstat->gid = g?g->gname:"???";
317 wstat->muid = "";
319 wstat->extension = NULL;
320 if (dotu) {
321 wstat->n_uid = st->st_uid;
322 wstat->n_gid = st->st_gid;
324 if (wstat->mode & Dmsymlink) {
325 err = readlink(path, ext, sizeof(ext) - 1);
326 if (err < 0)
327 err = 0;
329 ext[err] = '\0';
330 } else if (wstat->mode & Dmdevice) {
331 snprintf(ext, sizeof(ext), "%c %u %u",
332 S_ISCHR(st->st_mode)?'c':'b',
333 major(st->st_rdev), minor(st->st_rdev));
334 } else {
335 ext[0] = '\0';
338 wstat->extension = strdup(ext);
341 s = strrchr(path, '/');
342 if (s)
343 wstat->name = s + 1;
344 else
345 wstat->name = path;
348 static inline void
349 npfs_set_user(Npuser *user)
351 if (sameuser)
352 return;
354 if (geteuid() == user->uid)
355 return;
357 np_change_user(user);
360 Npfcall*
361 npfs_attach(Npfid *nfid, Npfid *nafid, Npstr *uname, Npstr *aname)
363 int err;
364 Npfcall* ret;
365 Fid *fid;
366 Npqid qid;
367 char *user;
369 user = NULL;
370 ret = NULL;
372 npfs_set_user(nfid->user);
373 if (nafid != NULL) {
374 np_werror(Enoauth, EIO);
375 goto done;
378 fid = npfs_fidalloc();
379 fid->omode = -1;
380 if (aname->len==0 || *aname->str!='/')
381 fid->path = strdup("/");
382 else
383 fid->path = np_strdup(aname);
385 nfid->aux = fid;
386 err = fidstat(fid);
387 if (err < 0) {
388 create_rerror(err);
389 goto done;
392 ustat2qid(&fid->stat, &qid);
393 ret = np_create_rattach(&qid);
394 np_fid_incref(nfid);
396 done:
397 return ret;
401 npfs_clone(Npfid *fid, Npfid *newfid)
403 Fid *f, *nf;
405 f = fid->aux;
406 nf = npfs_fidalloc();
407 nf->path = strdup(f->path);
408 newfid->aux = nf;
410 return 1;
415 npfs_walk(Npfid *fid, Npstr* wname, Npqid *wqid)
417 int n;
418 Fid *f;
419 struct stat st;
420 char *path;
422 f = fid->aux;
423 npfs_set_user(fid->user);
424 n = fidstat(f);
425 if (n < 0)
426 create_rerror(n);
428 n = strlen(f->path);
429 path = malloc(n + wname->len + 2);
430 memcpy(path, f->path, n);
431 path[n] = '/';
432 memcpy(path + n + 1, wname->str, wname->len);
433 path[n + wname->len + 1] = '\0';
435 if (lstat(path, &st) < 0) {
436 free(path);
437 create_rerror(errno);
438 return 0;
441 free(f->path);
442 f->path = path;
443 ustat2qid(&st, wqid);
445 return 1;
448 Npfcall*
449 npfs_open(Npfid *fid, u8 mode)
451 int err;
452 Fid *f;
453 Npqid qid;
455 f = fid->aux;
456 npfs_set_user(fid->user);
457 if ((err = fidstat(f)) < 0)
458 create_rerror(err);
460 if (S_ISDIR(f->stat.st_mode)) {
461 f->dir = opendir(f->path);
462 if (!f->dir)
463 create_rerror(errno);
464 } else {
465 f->fd = open(f->path, omode2uflags(mode));
466 if (f->fd < 0)
467 create_rerror(errno);
470 err = fidstat(f);
471 if (err < 0)
472 create_rerror(err);
474 f->omode = mode;
475 ustat2qid(&f->stat, &qid);
476 return np_create_ropen(&qid, 0);
479 static int
480 npfs_create_special(Npfid *fid, char *path, u32 perm, Npstr *extension)
482 int nfid, err;
483 int nmode, major, minor;
484 char ctype;
485 mode_t umode;
486 Npfid *ofid;
487 Fid *f, *of;
488 char *ext;
490 f = fid->aux;
491 if (!perm&Dmnamedpipe && !extension->len) {
492 np_werror(Enoextension, EIO);
493 return -1;
496 umode = np2umode(perm, extension, fid->conn->dotu);
497 ext = np_strdup(extension);
498 if (perm & Dmsymlink) {
499 if (symlink(ext, path) < 0) {
500 err = errno;
501 fprintf(stderr, "symlink %s %s %d\n", ext, path, err);
502 create_rerror(err);
503 goto error;
505 } else if (perm & Dmlink) {
506 if (sscanf(ext, "%d", &nfid) == 0) {
507 np_werror(Eformat, EIO);
508 goto error;
511 ofid = np_fid_find(fid->conn, nfid);
512 if (!ofid) {
513 np_werror(Eunknownfid, EIO);
514 goto error;
517 of = ofid->aux;
518 if (link(of->path, path) < 0) {
519 create_rerror(errno);
520 goto error;
522 } else if (perm & Dmdevice) {
523 if (sscanf(ext, "%c %u %u", &ctype, &major, &minor) != 3) {
524 np_werror(Eformat, EIO);
525 goto error;
528 nmode = 0;
529 switch (ctype) {
530 case 'c':
531 nmode = S_IFCHR;
532 break;
534 case 'b':
535 nmode = S_IFBLK;
536 break;
538 default:
539 np_werror(Eformat, EIO);
540 goto error;
543 nmode |= perm & 0777;
544 if (mknod(path, nmode, makedev(major, minor)) < 0) {
545 create_rerror(errno);
546 goto error;
548 } else if (perm & Dmnamedpipe) {
549 if (mknod(path, S_IFIFO | (umode&0777), 0) < 0) {
550 create_rerror(errno);
551 goto error;
555 f->omode = 0;
556 if (!perm&Dmsymlink && chmod(path, umode)<0) {
557 create_rerror(errno);
558 goto error;
561 free(ext);
562 return 0;
564 error:
565 free(ext);
566 return -1;
570 Npfcall*
571 npfs_create(Npfid *fid, Npstr *name, u32 perm, u8 mode, Npstr *extension)
573 int n, err, omode;
574 Fid *f;
575 Npfcall *ret;
576 Npqid qid;
577 char *npath;
578 struct stat st;
580 ret = NULL;
581 omode = mode;
582 f = fid->aux;
583 if ((err = fidstat(f)) < 0)
584 create_rerror(err);
586 n = strlen(f->path);
587 npath = malloc(n + name->len + 2);
588 memmove(npath, f->path, n);
589 npath[n] = '/';
590 memmove(npath + n + 1, name->str, name->len);
591 npath[n + name->len + 1] = '\0';
593 if (lstat(npath, &st)==0 || errno!=ENOENT) {
594 np_werror(Eexist, EEXIST);
595 goto out;
598 if (perm & Dmdir) {
599 if (mkdir(npath, perm & 0777) < 0) {
600 create_rerror(errno);
601 goto out;
604 if (lstat(npath, &f->stat) < 0) {
605 create_rerror(errno);
606 rmdir(npath);
607 goto out;
610 f->dir = opendir(npath);
611 if (!f->dir) {
612 create_rerror(errno);
613 remove(npath);
614 goto out;
616 } else if (perm & (Dmnamedpipe|Dmsymlink|Dmlink|Dmdevice)) {
617 if (npfs_create_special(fid, npath, perm, extension) < 0)
618 goto out;
620 if (lstat(npath, &f->stat) < 0) {
621 create_rerror(errno);
622 remove(npath);
623 goto out;
625 } else {
626 f->fd = open(npath, O_CREAT|omode2uflags(mode),
627 perm & 0777);
628 if (f->fd < 0) {
629 create_rerror(errno);
630 goto out;
633 if (lstat(npath, &f->stat) < 0) {
634 create_rerror(errno);
635 remove(npath);
636 goto out;
640 free(f->path);
641 f->path = npath;
642 f->omode = omode;
643 npath = NULL;
644 ustat2qid(&f->stat, &qid);
645 ret = np_create_rcreate(&qid, 0);
647 out:
648 free(npath);
649 return ret;
653 npfs_read_dir(Npfid *fid, u8* buf, u64 offset, u32 count, int dotu)
655 int i, n, plen;
656 char *dname, *path;
657 struct dirent *dirent;
658 struct stat st;
659 Npwstat wstat;
660 Fid *f;
662 f = fid->aux;
663 if (offset == 0) {
664 rewinddir(f->dir);
665 f->diroffset = 0;
668 plen = strlen(f->path);
669 n = 0;
670 dirent = NULL;
671 dname = f->direntname;
672 while (n < count) {
673 if (!dname) {
674 dirent = readdir(f->dir);
675 if (!dirent)
676 break;
678 if (strcmp(dirent->d_name, ".") == 0
679 || strcmp(dirent->d_name, "..") == 0)
680 continue;
682 dname = dirent->d_name;
685 path = malloc(plen + strlen(dname) + 2);
686 sprintf(path, "%s/%s", f->path, dname);
688 if (lstat(path, &st) < 0) {
689 free(path);
690 create_rerror(errno);
691 return 0;
694 ustat2npwstat(path, &st, &wstat, dotu, fid->conn->srv->upool);
695 i = np_serialize_stat(&wstat, buf + n, count - n - 1, dotu);
696 free(wstat.extension);
697 free(path);
698 path = NULL;
699 if (i==0)
700 break;
702 dname = NULL;
703 n += i;
706 if (f->direntname) {
707 free(f->direntname);
708 f->direntname = NULL;
711 if (dirent)
712 f->direntname = strdup(dirent->d_name);
714 f->diroffset += n;
715 return n;
718 Npfcall*
719 npfs_read(Npfid *fid, u64 offset, u32 count, Npreq *req)
721 int n;
722 Fid *f;
723 Npfcall *ret;
725 f = fid->aux;
726 ret = np_alloc_rread(count);
727 npfs_set_user(fid->user);
728 if (f->dir)
729 n = npfs_read_dir(fid, ret->data, offset, count, fid->conn->dotu);
730 else {
731 if (use_aio) {
732 n = npfs_aio_read(fid, ret, offset, count, req);
733 if (n >= 0)
734 return NULL;
737 n = pread(f->fd, ret->data, count, offset);
738 if (n < 0)
739 create_rerror(errno);
742 if (np_haserror()) {
743 free(ret);
744 ret = NULL;
745 } else
746 np_set_rread_count(ret, n);
748 return ret;
751 Npfcall*
752 npfs_write(Npfid *fid, u64 offset, u32 count, u8 *data, Npreq *req)
754 int n;
755 Fid *f;
757 f = fid->aux;
758 npfs_set_user(fid->user);
760 if (use_aio) {
761 n = npfs_aio_write(fid, data, offset, count, req);
762 // fprintf(stderr, "$$ %d\n", n);
763 if (n >= 0)
764 return NULL;
767 n = pwrite(f->fd, data, count, offset);
768 if (n < 0)
769 create_rerror(errno);
771 return np_create_rwrite(n);
774 Npfcall*
775 npfs_clunk(Npfid *fid)
777 Fid *f;
778 Npfcall *ret;
780 f = fid->aux;
781 ret = np_create_rclunk();
782 // np_fid_decref(fid);
783 return ret;
786 Npfcall*
787 npfs_remove(Npfid *fid)
789 Fid *f;
790 Npfcall *ret;
792 ret = NULL;
793 f = fid->aux;
794 npfs_set_user(fid->user);
795 if (remove(f->path) < 0) {
796 create_rerror(errno);
797 goto out;
800 ret = np_create_rremove();
802 out:
803 // np_fid_decref(fid);
804 return ret;
808 Npfcall*
809 npfs_stat(Npfid *fid)
811 int err;
812 Fid *f;
813 Npfcall *ret;
814 Npwstat wstat;
816 f = fid->aux;
817 npfs_set_user(fid->user);
818 err = fidstat(f);
819 if (err < 0)
820 create_rerror(err);
822 ustat2npwstat(f->path, &f->stat, &wstat, fid->conn->dotu, fid->conn->srv->upool);
824 ret = np_create_rstat(&wstat, fid->conn->dotu);
825 free(wstat.extension);
827 return ret;
830 Npfcall*
831 npfs_wstat(Npfid *fid, Npstat *stat)
833 int err;
834 Fid *f;
835 Npfcall *ret;
836 uid_t uid;
837 gid_t gid;
838 char *npath, *p, *s;
839 Npuser *user;
840 Npgroup *group;
841 struct utimbuf tb;
842 Npuserpool *up;
844 ret = NULL;
845 f = fid->aux;
846 up = fid->conn->srv->upool;
847 npfs_set_user(fid->user);
848 err = fidstat(f);
849 if (err < 0) {
850 create_rerror(err);
851 goto out;
854 if (fid->conn->dotu) {
855 uid = stat->n_uid;
856 gid = stat->n_gid;
857 } else {
858 uid = (uid_t) -1;
859 gid = (gid_t) -1;
862 if (uid == -1 && stat->uid.len) {
863 s = np_strdup(&stat->uid);
864 user = up->uname2user(up, s);
865 free(s);
866 if (!user) {
867 np_werror(Eunknownuser, EIO);
868 goto out;
871 uid = user->uid;
874 if (gid == -1 && stat->gid.len) {
875 s = np_strdup(&stat->gid);
876 group = up->gname2group(up, s);
877 free(s);
878 if (!group) {
879 np_werror(Eunknownuser, EIO);
880 goto out;
883 gid = group->gid;
886 if (stat->mode != (u32)~0) {
887 if (stat->mode&Dmdir && !S_ISDIR(f->stat.st_mode)) {
888 np_werror(Edirchange, EIO);
889 goto out;
892 if (chmod(f->path, npstat2umode(stat, fid->conn->dotu)) < 0) {
893 create_rerror(errno);
894 goto out;
898 if (stat->mtime != (u32)~0) {
899 tb.actime = 0;
900 tb.modtime = stat->mtime;
901 if (utime(f->path, &tb) < 0) {
902 create_rerror(errno);
903 goto out;
907 if (gid != -1) {
908 if (chown(f->path, uid, gid) < 0) {
909 create_rerror(errno);
910 goto out;
914 if (stat->name.len != 0) {
915 p = strrchr(f->path, '/');
916 if (!p)
917 p = f->path + strlen(f->path);
919 npath = malloc(stat->name.len + (p - f->path) + 2);
920 memcpy(npath, f->path, p - f->path);
921 npath[p - f->path] = '/';
922 memcpy(npath + (p - f->path) + 1, stat->name.str, stat->name.len);
923 npath[(p - f->path) + 1 + stat->name.len] = 0;
924 if (strcmp(npath, f->path) != 0) {
925 if (rename(f->path, npath) < 0) {
926 create_rerror(errno);
927 goto out;
930 free(f->path);
931 f->path = npath;
935 if (stat->length != ~0) {
936 if (truncate(f->path, stat->length) < 0) {
937 create_rerror(errno);
938 goto out;
941 ret = np_create_rwstat();
943 out:
944 return ret;
947 #ifdef NPFS_USE_AIO
948 static void
949 npfs_aio_respond(Aioreq *areq, struct io_event *event, int flush)
951 int count;
952 Npfcall *rc;
953 char buf[128];
955 count = event->res;
956 rc = NULL;
958 if (count<0 && !flush) {
959 if (areq->req->tcall->type == Tread)
960 free(areq->rread);
962 if (strerror_r(count, buf, sizeof(buf)))
963 strcpy(buf, "unknown error");
965 rc = np_create_rerror(buf, count, areq->req->conn->dotu);
966 } else {
967 if (areq->req->tcall->type == Tread) {
968 rc = areq->rread;
969 np_set_rread_count(rc, count);
970 } else {
971 rc = np_create_rwrite(count);
975 // np_fid_decref(areq->fid);
976 np_respond(areq->req, rc);
977 free(areq);
979 #endif
981 void
982 npfs_flush(Npreq *req)
984 if (req->tcall->type!=Tread && req->tcall->type!=Twrite)
985 return;
987 #ifdef NPFS_USE_AIO
989 struct io_event event;
990 Aioreq *areq;
992 pthread_mutex_lock(&aio_lock);
993 for(areq = aio_reqs; areq != NULL; areq = areq->next) {
994 if (areq->req == req) {
995 io_cancel(aio_ctx, &areq->iocb, &event);
996 npfs_aio_respond(areq, &event, 1);
998 if (areq->prev)
999 areq->prev->next = areq->next;
1000 else
1001 aio_reqs = areq->next;
1002 if (areq->next)
1003 areq->next->prev = areq->prev;
1005 free(areq);
1006 break;
1009 pthread_mutex_unlock(&aio_lock);
1011 #endif
1013 return;
1017 npfs_aio_init(int n)
1019 int ret = 0;
1021 #ifdef NPFS_USE_AIO
1022 ret = io_queue_init(n, &aio_ctx);
1023 #endif
1025 return ret;
1029 /*static*/ int
1030 npfs_aio_read(Npfid *fid, Npfcall *rread, u64 offset, u32 count, Npreq *req)
1032 int ret = ENOSYS;
1034 #ifdef NPFS_USE_AIO
1035 Fid *f;
1036 Aioreq *areq;
1037 struct iocb *iocbs[1];
1039 f = fid->aux;
1040 areq = malloc(sizeof(*areq));
1041 areq->req = req;
1042 areq->fid = fid;
1043 areq->rread = rread;
1044 pthread_mutex_lock(&aio_lock);
1045 areq->next = aio_reqs;
1046 areq->prev = NULL;
1047 aio_reqs = areq;
1048 pthread_mutex_unlock(&aio_lock);
1049 io_prep_pread(&areq->iocb, f->fd, rread->data, count, offset);
1050 iocbs[0] = &areq->iocb;
1051 ret = io_submit(aio_ctx, 1, iocbs);
1052 #endif
1054 return ret;
1057 /*static*/ int
1058 npfs_aio_write(Npfid *fid, u8 *data, u64 offset, u32 count, Npreq *req)
1060 int ret = ENOSYS;
1062 #ifdef NPFS_USE_AIO
1063 Fid *f;
1064 Aioreq *areq;
1065 struct iocb *iocbs[1];
1067 f = fid->aux;
1068 areq = malloc(sizeof(*areq));
1069 areq->req = req;
1070 areq->fid = fid;
1071 pthread_mutex_lock(&aio_lock);
1072 areq->next = aio_reqs;
1073 areq->prev = NULL;
1074 aio_reqs = areq;
1075 pthread_mutex_unlock(&aio_lock);
1076 io_prep_pwrite(&areq->iocb, f->fd, data, count, offset);
1077 iocbs[0] = &areq->iocb;
1078 ret = io_submit(aio_ctx, 1, iocbs);
1079 #endif
1081 return ret;
1084 void*
1085 npfs_aio_proc(void *a)
1087 #ifdef NPFS_USE_AIO
1088 int i, n, count;
1089 Aioreq *areq;
1090 struct timespec ts;
1091 struct io_event events[8];
1093 ts.tv_sec = 100;
1094 ts.tv_nsec = 0;
1096 for(;;) {
1097 n = io_getevents(aio_ctx, 1, 1 /* sizeof(events) / sizeof(events[0]) */,
1098 events, &ts);
1100 // fprintf(stderr,"++ %d\n", n);
1101 for(i = 0; i < n; i++) {
1102 count = events[i].res;
1103 areq = (Aioreq *) ((char *) events[i].obj -
1104 (int) (&((Aioreq *)0)->iocb));
1106 npfs_aio_respond(areq, &events[i], 0);
1109 #endif
1111 return NULL;