diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/9pfs/codir.c | 40 | ||||
-rw-r--r-- | hw/9pfs/cofile.c | 131 | ||||
-rw-r--r-- | hw/9pfs/cofs.c | 20 | ||||
-rw-r--r-- | hw/9pfs/coxattr.c | 34 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-coth.h | 21 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p-local.c | 7 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p.c | 1847 | ||||
-rw-r--r-- | hw/9pfs/virtio-9p.h | 79 | ||||
-rw-r--r-- | hw/g364fb.c | 365 | ||||
-rw-r--r-- | hw/gt64xxx.c | 6 | ||||
-rw-r--r-- | hw/mips.h | 5 | ||||
-rw-r--r-- | hw/mips_jazz.c | 15 | ||||
-rw-r--r-- | hw/ppc_newworld.c | 5 | ||||
-rw-r--r-- | hw/ppc_oldworld.c | 6 | ||||
-rw-r--r-- | hw/sun4u.c | 8 | ||||
-rw-r--r-- | hw/vga.c | 1 | ||||
-rw-r--r-- | hw/xilinx_ethlite.c | 27 | ||||
-rw-r--r-- | hw/xilinx_intc.c | 29 | ||||
-rw-r--r-- | hw/xilinx_timer.c | 31 | ||||
-rw-r--r-- | hw/xilinx_uartlite.c | 32 |
20 files changed, 1108 insertions, 1601 deletions
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index 28f2ad7..3a257b9 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -17,16 +17,16 @@ #include "qemu-coroutine.h" #include "virtio-9p-coth.h" -int v9fs_co_readdir(V9fsState *s, V9fsFidState *fidp, struct dirent **dent) +int v9fs_co_readdir_r(V9fsState *s, V9fsFidState *fidp, struct dirent *dent, + struct dirent **result) { int err; v9fs_co_run_in_worker( { errno = 0; - /*FIXME!! need to switch to readdir_r */ - *dent = s->ops->readdir(&s->ctx, fidp->fs.dir); - if (!*dent && errno) { + err = s->ops->readdir_r(&s->ctx, fidp->fs.dir, dent, result); + if (!*result && errno) { err = -errno; } else { err = 0; @@ -83,3 +83,35 @@ int v9fs_co_mkdir(V9fsState *s, char *name, mode_t mode, uid_t uid, gid_t gid) }); return err; } + +int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp) +{ + int err; + + v9fs_co_run_in_worker( + { + fidp->fs.dir = s->ops->opendir(&s->ctx, fidp->path.data); + if (!fidp->fs.dir) { + err = -errno; + } else { + err = 0; + } + }); + return err; +} + +int v9fs_co_closedir(V9fsState *s, V9fsFidState *fidp) +{ + int err; + DIR *dir; + + dir = fidp->fs.dir; + v9fs_co_run_in_worker( + { + err = s->ops->closedir(&s->ctx, dir); + if (err < 0) { + err = -errno; + } + }); + return err; +} diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index a4c0ae7..e388146 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -30,3 +30,134 @@ int v9fs_co_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf) }); return err; } + +int v9fs_co_fstat(V9fsState *s, int fd, struct stat *stbuf) +{ + int err; + + v9fs_co_run_in_worker( + { + err = s->ops->fstat(&s->ctx, fd, stbuf); + if (err < 0) { + err = -errno; + } + }); + return err; +} + +int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags) +{ + int err; + + v9fs_co_run_in_worker( + { + fidp->fs.fd = s->ops->open(&s->ctx, fidp->path.data, flags); + if (fidp->fs.fd == -1) { + err = -errno; + } else { + err = 0; + } + }); + return err; +} + +int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, char *fullname, gid_t gid, + int flags, int mode) +{ + int err; + FsCred cred; + + cred_init(&cred); + cred.fc_mode = mode & 07777; + cred.fc_uid = fidp->uid; + cred.fc_gid = gid; + v9fs_co_run_in_worker( + { + fidp->fs.fd = s->ops->open2(&s->ctx, fullname, flags, &cred); + err = 0; + if (fidp->fs.fd == -1) { + err = -errno; + } + }); + return err; +} + +int v9fs_co_close(V9fsState *s, V9fsFidState *fidp) +{ + int fd; + int err; + + fd = fidp->fs.fd; + v9fs_co_run_in_worker( + { + err = s->ops->close(&s->ctx, fd); + if (err < 0) { + err = -errno; + } + }); + return err; +} + +int v9fs_co_fsync(V9fsState *s, V9fsFidState *fidp, int datasync) +{ + int fd; + int err; + + fd = fidp->fs.fd; + v9fs_co_run_in_worker( + { + err = s->ops->fsync(&s->ctx, fd, datasync); + if (err < 0) { + err = -errno; + } + }); + return err; +} + +int v9fs_co_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath) +{ + int err; + + v9fs_co_run_in_worker( + { + err = s->ops->link(&s->ctx, oldpath->data, newpath->data); + if (err < 0) { + err = -errno; + } + }); + return err; +} + +int v9fs_co_pwritev(V9fsState *s, V9fsFidState *fidp, + struct iovec *iov, int iovcnt, int64_t offset) +{ + int fd; + int err; + + fd = fidp->fs.fd; + v9fs_co_run_in_worker( + { + err = s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset); + if (err < 0) { + err = -errno; + } + }); + return err; +} + +int v9fs_co_preadv(V9fsState *s, V9fsFidState *fidp, + struct iovec *iov, int iovcnt, int64_t offset) +{ + int fd; + int err; + + fd = fidp->fs.fd; + v9fs_co_run_in_worker( + { + err = s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset); + if (err < 0) { + err = -errno; + } + }); + return err; +} diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 1f10632..a78fccb 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -169,3 +169,23 @@ int v9fs_co_rename(V9fsState *s, V9fsString *oldpath, V9fsString *newpath) }); return err; } + +int v9fs_co_symlink(V9fsState *s, V9fsFidState *fidp, + const char *oldpath, const char *newpath, gid_t gid) +{ + int err; + FsCred cred; + + cred_init(&cred); + cred.fc_uid = fidp->uid; + cred.fc_gid = gid; + cred.fc_mode = 0777; + v9fs_co_run_in_worker( + { + err = s->ops->symlink(&s->ctx, oldpath, newpath, &cred); + if (err < 0) { + err = -errno; + } + }); + return err; +} diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c index 2fba2c9..a289389 100644 --- a/hw/9pfs/coxattr.c +++ b/hw/9pfs/coxattr.c @@ -48,3 +48,37 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsString *path, }); return err; } + +int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path, + V9fsString *xattr_name, void *value, + size_t size, int flags) +{ + int err; + + v9fs_co_run_in_worker( + { + err = s->ops->lsetxattr(&s->ctx, path->data, + xattr_name->data, value, + size, flags); + if (err < 0) { + err = -errno; + } + }); + return err; +} + +int v9fs_co_lremovexattr(V9fsState *s, V9fsString *path, + V9fsString *xattr_name) +{ + int err; + + v9fs_co_run_in_worker( + { + err = s->ops->lremovexattr(&s->ctx, path->data, + xattr_name->data); + if (err < 0) { + err = -errno; + } + }); + return err; +} diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h index 11272d3..48defb7 100644 --- a/hw/9pfs/virtio-9p-coth.h +++ b/hw/9pfs/virtio-9p-coth.h @@ -57,8 +57,8 @@ typedef struct V9fsThPool { extern void co_run_in_worker_bh(void *); extern int v9fs_init_worker_threads(void); extern int v9fs_co_readlink(V9fsState *, V9fsString *, V9fsString *); -extern int v9fs_co_readdir(V9fsState *, V9fsFidState *, - struct dirent **); +extern int v9fs_co_readdir_r(V9fsState *, V9fsFidState *, + struct dirent *, struct dirent **result); extern off_t v9fs_co_telldir(V9fsState *, V9fsFidState *); extern void v9fs_co_seekdir(V9fsState *, V9fsFidState *, off_t); extern void v9fs_co_rewinddir(V9fsState *, V9fsFidState *); @@ -76,4 +76,21 @@ extern int v9fs_co_mknod(V9fsState *, V9fsString *, uid_t, extern int v9fs_co_mkdir(V9fsState *, char *, mode_t, uid_t, gid_t); extern int v9fs_co_remove(V9fsState *, V9fsString *); extern int v9fs_co_rename(V9fsState *, V9fsString *, V9fsString *); +extern int v9fs_co_fstat(V9fsState *, int, struct stat *); +extern int v9fs_co_opendir(V9fsState *, V9fsFidState *); +extern int v9fs_co_open(V9fsState *, V9fsFidState *, int); +extern int v9fs_co_open2(V9fsState *, V9fsFidState *, char *, gid_t, int, int); +extern int v9fs_co_lsetxattr(V9fsState *, V9fsString *, V9fsString *, + void *, size_t, int); +extern int v9fs_co_lremovexattr(V9fsState *, V9fsString *, V9fsString *); +extern int v9fs_co_closedir(V9fsState *, V9fsFidState *); +extern int v9fs_co_close(V9fsState *, V9fsFidState *); +extern int v9fs_co_fsync(V9fsState *, V9fsFidState *, int); +extern int v9fs_co_symlink(V9fsState *, V9fsFidState *, const char *, + const char *, gid_t); +extern int v9fs_co_link(V9fsState *, V9fsString *, V9fsString *); +extern int v9fs_co_pwritev(V9fsState *, V9fsFidState *, + struct iovec *, int, int64_t); +extern int v9fs_co_preadv(V9fsState *, V9fsFidState *, + struct iovec *, int, int64_t); #endif diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index 77904c3..61cbf8d 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -165,9 +165,10 @@ static off_t local_telldir(FsContext *ctx, DIR *dir) return telldir(dir); } -static struct dirent *local_readdir(FsContext *ctx, DIR *dir) +static int local_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry, + struct dirent **result) { - return readdir(dir); + return readdir_r(dir, entry, result); } static void local_seekdir(FsContext *ctx, DIR *dir, off_t off) @@ -532,7 +533,7 @@ FileOperations local_ops = { .opendir = local_opendir, .rewinddir = local_rewinddir, .telldir = local_telldir, - .readdir = local_readdir, + .readdir_r = local_readdir_r, .seekdir = local_seekdir, .preadv = local_preadv, .pwritev = local_pwritev, diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index eb33636..ad70768 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -77,160 +77,6 @@ void cred_init(FsCred *credp) credp->fc_rdev = -1; } -static int v9fs_do_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf) -{ - return s->ops->lstat(&s->ctx, path->data, stbuf); -} - -static int v9fs_do_close(V9fsState *s, int fd) -{ - return s->ops->close(&s->ctx, fd); -} - -static int v9fs_do_closedir(V9fsState *s, DIR *dir) -{ - return s->ops->closedir(&s->ctx, dir); -} - -static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags) -{ - return s->ops->open(&s->ctx, path->data, flags); -} - -static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path) -{ - return s->ops->opendir(&s->ctx, path->data); -} - -static void v9fs_do_rewinddir(V9fsState *s, DIR *dir) -{ - return s->ops->rewinddir(&s->ctx, dir); -} - -static off_t v9fs_do_telldir(V9fsState *s, DIR *dir) -{ - return s->ops->telldir(&s->ctx, dir); -} - -static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off) -{ - return s->ops->seekdir(&s->ctx, dir, off); -} - -static int v9fs_do_preadv(V9fsState *s, int fd, const struct iovec *iov, - int iovcnt, int64_t offset) -{ - return s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset); -} - -static int v9fs_do_pwritev(V9fsState *s, int fd, const struct iovec *iov, - int iovcnt, int64_t offset) -{ - return s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset); -} - -static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode) -{ - FsCred cred; - cred_init(&cred); - cred.fc_mode = mode; - return s->ops->chmod(&s->ctx, path->data, &cred); -} - -static int v9fs_do_mknod(V9fsState *s, char *name, - mode_t mode, dev_t dev, uid_t uid, gid_t gid) -{ - FsCred cred; - cred_init(&cred); - cred.fc_uid = uid; - cred.fc_gid = gid; - cred.fc_mode = mode; - cred.fc_rdev = dev; - return s->ops->mknod(&s->ctx, name, &cred); -} - -static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf) -{ - return s->ops->fstat(&s->ctx, fd, stbuf); -} - -static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid, - int flags, int mode) -{ - FsCred cred; - - cred_init(&cred); - cred.fc_uid = uid; - cred.fc_gid = gid; - cred.fc_mode = mode & 07777; - - return s->ops->open2(&s->ctx, fullname, flags, &cred); -} - -static int v9fs_do_symlink(V9fsState *s, V9fsFidState *fidp, - const char *oldpath, const char *newpath, gid_t gid) -{ - FsCred cred; - cred_init(&cred); - cred.fc_uid = fidp->uid; - cred.fc_gid = gid; - cred.fc_mode = 0777; - - return s->ops->symlink(&s->ctx, oldpath, newpath, &cred); -} - -static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath) -{ - return s->ops->link(&s->ctx, oldpath->data, newpath->data); -} - -static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size) -{ - return s->ops->truncate(&s->ctx, path->data, size); -} - -static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid) -{ - FsCred cred; - cred_init(&cred); - cred.fc_uid = uid; - cred.fc_gid = gid; - - return s->ops->chown(&s->ctx, path->data, &cred); -} - -static int v9fs_do_utimensat(V9fsState *s, V9fsString *path, - const struct timespec times[2]) -{ - return s->ops->utimensat(&s->ctx, path->data, times); -} - -static int v9fs_do_fsync(V9fsState *s, int fd, int datasync) -{ - return s->ops->fsync(&s->ctx, fd, datasync); -} - -static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf) -{ - return s->ops->statfs(&s->ctx, path->data, stbuf); -} - -static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path, - V9fsString *xattr_name, - void *value, size_t size, int flags) -{ - return s->ops->lsetxattr(&s->ctx, path->data, - xattr_name->data, value, size, flags); -} - -static int v9fs_do_lremovexattr(V9fsState *s, V9fsString *path, - V9fsString *xattr_name) -{ - return s->ops->lremovexattr(&s->ctx, path->data, - xattr_name->data); -} - - static void v9fs_string_init(V9fsString *str) { str->data = NULL; @@ -437,12 +283,12 @@ static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp) goto free_out; } if (fidp->fs.xattr.len) { - retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name, + retval = v9fs_co_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name, fidp->fs.xattr.value, fidp->fs.xattr.len, fidp->fs.xattr.flags); } else { - retval = v9fs_do_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name); + retval = v9fs_co_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name); } free_out: v9fs_string_free(&fidp->fs.xattr.name); @@ -472,15 +318,14 @@ static int free_fid(V9fsState *s, int32_t fid) *fidpp = fidp->next; if (fidp->fid_type == P9_FID_FILE) { - v9fs_do_close(s, fidp->fs.fd); + retval = v9fs_co_close(s, fidp); } else if (fidp->fid_type == P9_FID_DIR) { - v9fs_do_closedir(s, fidp->fs.dir); + retval = v9fs_co_closedir(s, fidp); } else if (fidp->fid_type == P9_FID_XATTR) { retval = v9fs_xattr_fid_clunk(s, fidp); } v9fs_string_free(&fidp->path); g_free(fidp); - return retval; } @@ -531,11 +376,10 @@ static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp) struct stat stbuf; int err; - err = v9fs_do_lstat(s, &fidp->path, &stbuf); - if (err) { + err = v9fs_co_lstat(s, &fidp->path, &stbuf); + if (err < 0) { return err; } - stat_to_qid(&stbuf, qidp); return 0; } @@ -1161,8 +1005,8 @@ static void v9fs_attach(void *opaque) int32_t fid, afid, n_uname; V9fsString uname, aname; V9fsFidState *fidp; - V9fsQID qid; size_t offset = 7; + V9fsQID qid; ssize_t err; pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname); @@ -1172,19 +1016,15 @@ static void v9fs_attach(void *opaque) err = -EINVAL; goto out; } - fidp->uid = n_uname; - v9fs_string_sprintf(&fidp->path, "%s", "/"); err = fid_to_qid(s, fidp, &qid); - if (err) { + if (err < 0) { err = -EINVAL; free_fid(s, fid); goto out; } - offset += pdu_marshal(pdu, offset, "Q", &qid); - err = offset; out: complete_pdu(s, pdu, err); @@ -1192,56 +1032,36 @@ out: v9fs_string_free(&aname); } -static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err) -{ - if (err == -1) { - err = -errno; - goto out; - } - - err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat); - if (err) { - goto out; - } - vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat); - err = vs->offset; - -out: - complete_pdu(s, vs->pdu, err); - v9fs_stat_free(&vs->v9stat); - g_free(vs); -} - static void v9fs_stat(void *opaque) { - V9fsPDU *pdu = opaque; - V9fsState *s = pdu->s; int32_t fid; - V9fsStatState *vs; + V9fsStat v9stat; ssize_t err = 0; + size_t offset = 7; + struct stat stbuf; + V9fsFidState *fidp; + V9fsPDU *pdu = opaque; + V9fsState *s = pdu->s; - vs = g_malloc(sizeof(*vs)); - vs->pdu = pdu; - vs->offset = 7; - - memset(&vs->v9stat, 0, sizeof(vs->v9stat)); - - pdu_unmarshal(vs->pdu, vs->offset, "d", &fid); - - vs->fidp = lookup_fid(s, fid); - if (vs->fidp == NULL) { + pdu_unmarshal(pdu, offset, "d", &fid); + fidp = lookup_fid(s, fid); + if (fidp == NULL) { err = -ENOENT; goto out; } - - err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf); - v9fs_stat_post_lstat(s, vs, err); - return; - + err = v9fs_co_lstat(s, &fidp->path, &stbuf); + if (err < 0) { + goto out; + } + err = stat_to_v9stat(s, &fidp->path, &stbuf, &v9stat); + if (err < 0) { + goto out; + } + offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat); + err = offset; + v9fs_stat_free(&v9stat); out: - complete_pdu(s, vs->pdu, err); - v9fs_stat_free(&vs->v9stat); - g_free(vs); + complete_pdu(s, pdu, err); } static void v9fs_getattr(void *opaque) @@ -1370,171 +1190,101 @@ out: complete_pdu(s, pdu, err); } -static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err) -{ - complete_pdu(s, vs->pdu, err); - - if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) { - for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) { - v9fs_string_free(&vs->wnames[vs->name_idx]); - } - - g_free(vs->wnames); - g_free(vs->qids); - } -} - -static void v9fs_walk_marshal(V9fsWalkState *vs) +static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids) { int i; - vs->offset = 7; - vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames); - - for (i = 0; i < vs->nwnames; i++) { - vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]); + size_t offset = 7; + offset += pdu_marshal(pdu, offset, "w", nwnames); + for (i = 0; i < nwnames; i++) { + offset += pdu_marshal(pdu, offset, "Q", &qids[i]); } -} - -static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs, - int err) -{ - if (err == -1) { - free_fid(s, vs->newfidp->fid); - v9fs_string_free(&vs->path); - err = -ENOENT; - goto out; - } - - stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]); - - vs->name_idx++; - if (vs->name_idx < vs->nwnames) { - v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data, - vs->wnames[vs->name_idx].data); - v9fs_string_copy(&vs->newfidp->path, &vs->path); - - err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf); - v9fs_walk_post_newfid_lstat(s, vs, err); - return; - } - - v9fs_string_free(&vs->path); - v9fs_walk_marshal(vs); - err = vs->offset; -out: - v9fs_walk_complete(s, vs, err); -} - -static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs, - int err) -{ - if (err == -1) { - v9fs_string_free(&vs->path); - err = -ENOENT; - goto out; - } - - stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]); - vs->name_idx++; - if (vs->name_idx < vs->nwnames) { - - v9fs_string_sprintf(&vs->path, "%s/%s", - vs->fidp->path.data, vs->wnames[vs->name_idx].data); - v9fs_string_copy(&vs->fidp->path, &vs->path); - - err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf); - v9fs_walk_post_oldfid_lstat(s, vs, err); - return; - } - - v9fs_string_free(&vs->path); - v9fs_walk_marshal(vs); - err = vs->offset; -out: - v9fs_walk_complete(s, vs, err); + return offset; } static void v9fs_walk(void *opaque) { + int name_idx; + V9fsQID *qids = NULL; + int i, err = 0; + V9fsString path; + uint16_t nwnames; + struct stat stbuf; + size_t offset = 7; + int32_t fid, newfid; + V9fsString *wnames = NULL; + V9fsFidState *fidp; + V9fsFidState *newfidp; V9fsPDU *pdu = opaque; V9fsState *s = pdu->s; - int32_t fid, newfid; - V9fsWalkState *vs; - int err = 0; - int i; - - vs = g_malloc(sizeof(*vs)); - vs->pdu = pdu; - vs->wnames = NULL; - vs->qids = NULL; - vs->offset = 7; - vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid, - &newfid, &vs->nwnames); + offset += pdu_unmarshal(pdu, offset, "ddw", &fid, + &newfid, &nwnames); - if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) { - vs->wnames = g_malloc0(sizeof(vs->wnames[0]) * vs->nwnames); - - vs->qids = g_malloc0(sizeof(vs->qids[0]) * vs->nwnames); - - for (i = 0; i < vs->nwnames; i++) { - vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s", - &vs->wnames[i]); + if (nwnames && nwnames <= P9_MAXWELEM) { + wnames = g_malloc0(sizeof(wnames[0]) * nwnames); + qids = g_malloc0(sizeof(qids[0]) * nwnames); + for (i = 0; i < nwnames; i++) { + offset += pdu_unmarshal(pdu, offset, "s", &wnames[i]); } - } else if (vs->nwnames > P9_MAXWELEM) { + + } else if (nwnames > P9_MAXWELEM) { err = -EINVAL; goto out; } - - vs->fidp = lookup_fid(s, fid); - if (vs->fidp == NULL) { + fidp = lookup_fid(s, fid); + if (fidp == NULL) { err = -ENOENT; goto out; } - - /* FIXME: is this really valid? */ if (fid == newfid) { - - BUG_ON(vs->fidp->fid_type != P9_FID_NONE); - v9fs_string_init(&vs->path); - vs->name_idx = 0; - - if (vs->name_idx < vs->nwnames) { - v9fs_string_sprintf(&vs->path, "%s/%s", - vs->fidp->path.data, vs->wnames[vs->name_idx].data); - v9fs_string_copy(&vs->fidp->path, &vs->path); - - err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf); - v9fs_walk_post_oldfid_lstat(s, vs, err); - return; + BUG_ON(fidp->fid_type != P9_FID_NONE); + v9fs_string_init(&path); + for (name_idx = 0; name_idx < nwnames; name_idx++) { + v9fs_string_sprintf(&path, "%s/%s", + fidp->path.data, wnames[name_idx].data); + v9fs_string_copy(&fidp->path, &path); + + err = v9fs_co_lstat(s, &fidp->path, &stbuf); + if (err < 0) { + v9fs_string_free(&path); + goto out; + } + stat_to_qid(&stbuf, &qids[name_idx]); } + v9fs_string_free(&path); } else { - vs->newfidp = alloc_fid(s, newfid); - if (vs->newfidp == NULL) { + newfidp = alloc_fid(s, newfid); + if (newfidp == NULL) { err = -EINVAL; goto out; } - - vs->newfidp->uid = vs->fidp->uid; - v9fs_string_init(&vs->path); - vs->name_idx = 0; - v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path); - - if (vs->name_idx < vs->nwnames) { - v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data, - vs->wnames[vs->name_idx].data); - v9fs_string_copy(&vs->newfidp->path, &vs->path); - - err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf); - v9fs_walk_post_newfid_lstat(s, vs, err); - return; + newfidp->uid = fidp->uid; + v9fs_string_init(&path); + v9fs_string_copy(&newfidp->path, &fidp->path); + for (name_idx = 0; name_idx < nwnames; name_idx++) { + v9fs_string_sprintf(&path, "%s/%s", newfidp->path.data, + wnames[name_idx].data); + v9fs_string_copy(&newfidp->path, &path); + err = v9fs_co_lstat(s, &newfidp->path, &stbuf); + if (err < 0) { + free_fid(s, newfidp->fid); + v9fs_string_free(&path); + goto out; + } + stat_to_qid(&stbuf, &qids[name_idx]); } + v9fs_string_free(&path); } - - v9fs_walk_marshal(vs); - err = vs->offset; + err = v9fs_walk_marshal(pdu, nwnames, qids); out: - v9fs_walk_complete(s, vs, err); + complete_pdu(s, pdu, err); + if (nwnames && nwnames <= P9_MAXWELEM) { + for (name_idx = 0; name_idx < nwnames; name_idx++) { + v9fs_string_free(&wnames[name_idx]); + } + g_free(wnames); + g_free(qids); + } } static int32_t get_iounit(V9fsState *s, V9fsString *name) @@ -1546,467 +1296,323 @@ static int32_t get_iounit(V9fsState *s, V9fsString *name) * iounit should be multiples of f_bsize (host filesystem block size * and as well as less than (client msize - P9_IOHDRSZ)) */ - if (!v9fs_do_statfs(s, name, &stbuf)) { + if (!v9fs_co_statfs(s, name, &stbuf)) { iounit = stbuf.f_bsize; iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize; } - if (!iounit) { iounit = s->msize - P9_IOHDRSZ; } return iounit; } -static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err) -{ - if (vs->fidp->fs.dir == NULL) { - err = -errno; - goto out; - } - vs->fidp->fid_type = P9_FID_DIR; - vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0); - err = vs->offset; -out: - complete_pdu(s, vs->pdu, err); - g_free(vs); - -} - -static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs) +static void v9fs_open(void *opaque) { - int err; - vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit); - err = vs->offset; - complete_pdu(s, vs->pdu, err); - g_free(vs); -} + int flags; + int iounit; + int32_t fid; + int32_t mode; + V9fsQID qid; + ssize_t err = 0; + size_t offset = 7; + struct stat stbuf; + V9fsFidState *fidp; + V9fsPDU *pdu = opaque; + V9fsState *s = pdu->s; -static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err) -{ - if (vs->fidp->fs.fd == -1) { - err = -errno; + if (s->proto_version == V9FS_PROTO_2000L) { + pdu_unmarshal(pdu, offset, "dd", &fid, &mode); + } else { + pdu_unmarshal(pdu, offset, "db", &fid, &mode); + } + fidp = lookup_fid(s, fid); + if (fidp == NULL) { + err = -ENOENT; goto out; } - vs->fidp->fid_type = P9_FID_FILE; - vs->iounit = get_iounit(s, &vs->fidp->path); - v9fs_open_post_getiounit(s, vs); - return; -out: - complete_pdu(s, vs->pdu, err); - g_free(vs); -} - -static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err) -{ - int flags; + BUG_ON(fidp->fid_type != P9_FID_NONE); - if (err) { - err = -errno; + err = v9fs_co_lstat(s, &fidp->path, &stbuf); + if (err < 0) { goto out; } - - stat_to_qid(&vs->stbuf, &vs->qid); - - if (S_ISDIR(vs->stbuf.st_mode)) { - vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path); - v9fs_open_post_opendir(s, vs, err); + stat_to_qid(&stbuf, &qid); + if (S_ISDIR(stbuf.st_mode)) { + err = v9fs_co_opendir(s, fidp); + if (err < 0) { + goto out; + } + fidp->fid_type = P9_FID_DIR; + offset += pdu_marshal(pdu, offset, "Qd", &qid, 0); + err = offset; } else { if (s->proto_version == V9FS_PROTO_2000L) { - flags = vs->mode; + flags = mode; flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT); /* Ignore direct disk access hint until the server supports it. */ flags &= ~O_DIRECT; } else { - flags = omode_to_uflags(vs->mode); + flags = omode_to_uflags(mode); } - vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags); - v9fs_open_post_open(s, vs, err); - } - return; -out: - complete_pdu(s, vs->pdu, err); - g_free(vs); -} - -static void v9fs_open(void *opaque) -{ - V9fsPDU *pdu = opaque; - V9fsState *s = pdu->s; - int32_t fid; - V9fsOpenState *vs; - ssize_t err = 0; - - vs = g_malloc(sizeof(*vs)); - vs->pdu = pdu; - vs->offset = 7; - vs->mode = 0; - - if (s->proto_version == V9FS_PROTO_2000L) { - pdu_unmarshal(vs->pdu, vs->offset, "dd", &fid, &vs->mode); - } else { - pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode); - } - - vs->fidp = lookup_fid(s, fid); - if (vs->fidp == NULL) { - err = -ENOENT; - goto out; - } - - BUG_ON(vs->fidp->fid_type != P9_FID_NONE); - - err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf); - - v9fs_open_post_lstat(s, vs, err); - return; -out: - complete_pdu(s, pdu, err); - g_free(vs); -} - -static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err) -{ - if (err == 0) { - v9fs_string_copy(&vs->fidp->path, &vs->fullname); - stat_to_qid(&vs->stbuf, &vs->qid); - vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, - vs->iounit); - err = vs->offset; - } else { - vs->fidp->fid_type = P9_FID_NONE; - err = -errno; - if (vs->fidp->fs.fd > 0) { - close(vs->fidp->fs.fd); + err = v9fs_co_open(s, fidp, flags); + if (err < 0) { + goto out; } + fidp->fid_type = P9_FID_FILE; + iounit = get_iounit(s, &fidp->path); + offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit); + err = offset; } - - complete_pdu(s, vs->pdu, err); - v9fs_string_free(&vs->name); - v9fs_string_free(&vs->fullname); - g_free(vs); -} - -static void v9fs_lcreate_post_get_iounit(V9fsState *s, V9fsLcreateState *vs, - int err) -{ - if (err) { - err = -errno; - goto out; - } - err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf); - -out: - v9fs_post_lcreate(s, vs, err); -} - -static void v9fs_lcreate_post_do_open2(V9fsState *s, V9fsLcreateState *vs, - int err) -{ - if (vs->fidp->fs.fd == -1) { - err = -errno; - goto out; - } - vs->fidp->fid_type = P9_FID_FILE; - vs->iounit = get_iounit(s, &vs->fullname); - v9fs_lcreate_post_get_iounit(s, vs, err); - return; - out: - v9fs_post_lcreate(s, vs, err); + complete_pdu(s, pdu, err); } static void v9fs_lcreate(void *opaque) { - V9fsPDU *pdu = opaque; - V9fsState *s = pdu->s; int32_t dfid, flags, mode; gid_t gid; - V9fsLcreateState *vs; ssize_t err = 0; + ssize_t offset = 7; + V9fsString fullname; + V9fsString name; + V9fsFidState *fidp; + struct stat stbuf; + V9fsQID qid; + int32_t iounit; + V9fsPDU *pdu = opaque; - vs = g_malloc(sizeof(*vs)); - vs->pdu = pdu; - vs->offset = 7; - - v9fs_string_init(&vs->fullname); - - pdu_unmarshal(vs->pdu, vs->offset, "dsddd", &dfid, &vs->name, &flags, - &mode, &gid); + v9fs_string_init(&fullname); + pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags, + &mode, &gid); - vs->fidp = lookup_fid(s, dfid); - if (vs->fidp == NULL) { + fidp = lookup_fid(pdu->s, dfid); + if (fidp == NULL) { err = -ENOENT; goto out; } - - v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data, - vs->name.data); + v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data); /* Ignore direct disk access hint until the server supports it. */ flags &= ~O_DIRECT; - vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid, - gid, flags, mode); - v9fs_lcreate_post_do_open2(s, vs, err); - return; - -out: - complete_pdu(s, vs->pdu, err); - v9fs_string_free(&vs->name); - g_free(vs); -} + err = v9fs_co_open2(pdu->s, fidp, fullname.data, gid, flags, mode); + if (err < 0) { + goto out; + } + fidp->fid_type = P9_FID_FILE; + iounit = get_iounit(pdu->s, &fullname); -static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err) -{ - if (err == -1) { - err = -errno; + err = v9fs_co_lstat(pdu->s, &fullname, &stbuf); + if (err < 0) { + fidp->fid_type = P9_FID_NONE; + if (fidp->fs.fd > 0) { + close(fidp->fs.fd); + } + goto out; } - complete_pdu(s, pdu, err); + v9fs_string_copy(&fidp->path, &fullname); + stat_to_qid(&stbuf, &qid); + offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit); + err = offset; +out: + complete_pdu(pdu->s, pdu, err); + v9fs_string_free(&name); + v9fs_string_free(&fullname); } static void v9fs_fsync(void *opaque) { - V9fsPDU *pdu = opaque; - V9fsState *s = pdu->s; + int err; int32_t fid; + int datasync; size_t offset = 7; V9fsFidState *fidp; - int datasync; - int err; + V9fsPDU *pdu = opaque; + V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dd", &fid, &datasync); fidp = lookup_fid(s, fid); if (fidp == NULL) { err = -ENOENT; - v9fs_post_do_fsync(s, pdu, err); - return; + goto out; + } + err = v9fs_co_fsync(s, fidp, datasync); + if (!err) { + err = offset; } - err = v9fs_do_fsync(s, fidp->fs.fd, datasync); - v9fs_post_do_fsync(s, pdu, err); +out: + complete_pdu(s, pdu, err); } static void v9fs_clunk(void *opaque) { - V9fsPDU *pdu = opaque; - V9fsState *s = pdu->s; + int err; int32_t fid; size_t offset = 7; - int err; + V9fsPDU *pdu = opaque; + V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "d", &fid); - err = free_fid(s, fid); if (err < 0) { goto out; } - - offset = 7; err = offset; out: complete_pdu(s, pdu, err); } -static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t); - -static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err) +static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, + V9fsFidState *fidp, int64_t off, int32_t max_count) { - if (err) { - goto out; - } - vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count); - vs->offset += vs->count; - err = vs->offset; -out: - complete_pdu(s, vs->pdu, err); - v9fs_stat_free(&vs->v9stat); - v9fs_string_free(&vs->name); - g_free(vs); - return; -} + size_t offset = 7; + int read_count; + int64_t xattr_len; -static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs, - ssize_t err) -{ - if (err) { - err = -errno; - goto out; - } - err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat); - if (err) { - goto out; + xattr_len = fidp->fs.xattr.len; + read_count = xattr_len - off; + if (read_count > max_count) { + read_count = max_count; + } else if (read_count < 0) { + /* + * read beyond XATTR value + */ + read_count = 0; } - - vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S", - &vs->v9stat); - if ((vs->len != (vs->v9stat.size + 2)) || - ((vs->count + vs->len) > vs->max_count)) { - v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos); - v9fs_read_post_seekdir(s, vs, err); - return; - } - vs->count += vs->len; - v9fs_stat_free(&vs->v9stat); - v9fs_string_free(&vs->name); - vs->dir_pos = vs->dent->d_off; - v9fs_co_readdir(s, vs->fidp, &vs->dent); - v9fs_read_post_readdir(s, vs, err); - return; -out: - v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos); - v9fs_read_post_seekdir(s, vs, err); - return; - + offset += pdu_marshal(pdu, offset, "d", read_count); + offset += pdu_pack(pdu, offset, + ((char *)fidp->fs.xattr.value) + off, + read_count); + return offset; } -static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err) +static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu, + V9fsFidState *fidp, int32_t max_count) { - if (vs->dent) { - memset(&vs->v9stat, 0, sizeof(vs->v9stat)); - v9fs_string_init(&vs->name); - v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data, - vs->dent->d_name); - err = v9fs_do_lstat(s, &vs->name, &vs->stbuf); - v9fs_read_post_dir_lstat(s, vs, err); - return; - } - - vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count); - vs->offset += vs->count; - err = vs->offset; - complete_pdu(s, vs->pdu, err); - g_free(vs); - return; -} + V9fsString name; + V9fsStat v9stat; + int len, err = 0; + int32_t count = 0; + struct stat stbuf; + off_t saved_dir_pos; + struct dirent *dent, *result; -static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err) -{ - v9fs_co_readdir(s, vs->fidp, &vs->dent); - v9fs_read_post_readdir(s, vs, err); - return; -} + /* save the directory position */ + saved_dir_pos = v9fs_co_telldir(s, fidp); + if (saved_dir_pos < 0) { + return saved_dir_pos; + } -static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs, - ssize_t err) -{ - vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir); - v9fs_read_post_telldir(s, vs, err); - return; -} + dent = g_malloc(sizeof(struct dirent)); -static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err) -{ - if (err < 0) { - /* IO error return the error */ - err = -errno; - goto out; - } - vs->total += vs->len; - vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt); - if (vs->total < vs->count && vs->len > 0) { - do { - if (0) { - print_sg(vs->sg, vs->cnt); - } - vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt, - vs->off); - if (vs->len > 0) { - vs->off += vs->len; - } - } while (vs->len == -1 && errno == EINTR); - if (vs->len == -1) { - err = -errno; + while (1) { + v9fs_string_init(&name); + err = v9fs_co_readdir_r(s, fidp, dent, &result); + if (err || !result) { + break; + } + v9fs_string_sprintf(&name, "%s/%s", fidp->path.data, dent->d_name); + err = v9fs_co_lstat(s, &name, &stbuf); + if (err < 0) { + goto out; } - v9fs_read_post_preadv(s, vs, err); - return; + err = stat_to_v9stat(s, &name, &stbuf, &v9stat); + if (err < 0) { + goto out; + } + /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */ + len = pdu_marshal(pdu, 11 + count, "S", &v9stat); + if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) { + /* Ran out of buffer. Set dir back to old position and return */ + v9fs_co_seekdir(s, fidp, saved_dir_pos); + v9fs_stat_free(&v9stat); + v9fs_string_free(&name); + g_free(dent); + return count; + } + count += len; + v9fs_stat_free(&v9stat); + v9fs_string_free(&name); + saved_dir_pos = dent->d_off; } - vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total); - vs->offset += vs->count; - err = vs->offset; - out: - complete_pdu(s, vs->pdu, err); - g_free(vs); -} - -static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs) -{ - ssize_t err = 0; - int read_count; - int64_t xattr_len; - - xattr_len = vs->fidp->fs.xattr.len; - read_count = xattr_len - vs->off; - if (read_count > vs->count) { - read_count = vs->count; - } else if (read_count < 0) { - /* - * read beyond XATTR value - */ - read_count = 0; + g_free(dent); + v9fs_string_free(&name); + if (err < 0) { + return err; } - vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", read_count); - vs->offset += pdu_pack(vs->pdu, vs->offset, - ((char *)vs->fidp->fs.xattr.value) + vs->off, - read_count); - err = vs->offset; - complete_pdu(s, vs->pdu, err); - g_free(vs); + return count; } static void v9fs_read(void *opaque) { - V9fsPDU *pdu = opaque; - V9fsState *s = pdu->s; int32_t fid; - V9fsReadState *vs; + int64_t off; ssize_t err = 0; + int32_t count = 0; + size_t offset = 7; + int32_t max_count; + V9fsFidState *fidp; + V9fsPDU *pdu = opaque; + V9fsState *s = pdu->s; - vs = g_malloc(sizeof(*vs)); - vs->pdu = pdu; - vs->offset = 7; - vs->total = 0; - vs->len = 0; - vs->count = 0; - - pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count); - - vs->fidp = lookup_fid(s, fid); - if (vs->fidp == NULL) { + pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count); + fidp = lookup_fid(s, fid); + if (fidp == NULL) { err = -EINVAL; goto out; } + if (fidp->fid_type == P9_FID_DIR) { - if (vs->fidp->fid_type == P9_FID_DIR) { - vs->max_count = vs->count; - vs->count = 0; - if (vs->off == 0) { - v9fs_do_rewinddir(s, vs->fidp->fs.dir); - } - v9fs_read_post_rewinddir(s, vs, err); - return; - } else if (vs->fidp->fid_type == P9_FID_FILE) { - vs->sg = vs->iov; - pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt); - vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt); - if (vs->total <= vs->count) { - vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt, - vs->off); - if (vs->len > 0) { - vs->off += vs->len; - } - err = vs->len; - v9fs_read_post_preadv(s, vs, err); + if (off == 0) { + v9fs_co_rewinddir(s, fidp); } - return; - } else if (vs->fidp->fid_type == P9_FID_XATTR) { - v9fs_xattr_read(s, vs); - return; + count = v9fs_do_readdir_with_stat(s, pdu, fidp, max_count); + if (count < 0) { + err = count; + goto out; + } + err = offset; + err += pdu_marshal(pdu, offset, "d", count); + err += count; + } else if (fidp->fid_type == P9_FID_FILE) { + int32_t cnt; + int32_t len; + struct iovec *sg; + struct iovec iov[128]; /* FIXME: bad, bad, bad */ + + sg = iov; + pdu_marshal(pdu, offset + 4, "v", sg, &cnt); + sg = cap_sg(sg, max_count, &cnt); + do { + if (0) { + print_sg(sg, cnt); + } + /* Loop in case of EINTR */ + do { + len = v9fs_co_preadv(s, fidp, sg, cnt, off); + if (len >= 0) { + off += len; + count += len; + } + } while (len == -EINTR); + if (len < 0) { + /* IO error return the error */ + err = len; + goto out; + } + sg = adjust_sg(sg, len, &cnt); + } while (count < max_count && len > 0); + err = offset; + err += pdu_marshal(pdu, offset, "d", count); + err += count; + } else if (fidp->fid_type == P9_FID_XATTR) { + err = v9fs_xattr_read(s, pdu, fidp, off, max_count); } else { err = -EINVAL; } out: complete_pdu(s, pdu, err); - g_free(vs); } static size_t v9fs_readdir_data_size(V9fsString *name) @@ -2027,16 +1633,19 @@ static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu, int len, err = 0; int32_t count = 0; off_t saved_dir_pos; - struct dirent *dent; + struct dirent *dent, *result; /* save the directory position */ saved_dir_pos = v9fs_co_telldir(s, fidp); if (saved_dir_pos < 0) { return saved_dir_pos; } + + dent = g_malloc(sizeof(struct dirent)); + while (1) { - err = v9fs_co_readdir(s, fidp, &dent); - if (err || !dent) { + err = v9fs_co_readdir_r(s, fidp, dent, &result); + if (err || !result) { break; } v9fs_string_init(&name); @@ -2045,6 +1654,7 @@ static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu, /* Ran out of buffer. Set dir back to old position and return */ v9fs_co_seekdir(s, fidp, saved_dir_pos); v9fs_string_free(&name); + g_free(dent); return count; } /* @@ -2066,6 +1676,7 @@ static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu, v9fs_string_free(&name); saved_dir_pos = dent->d_off; } + g_free(dent); if (err < 0) { return err; } @@ -2107,51 +1718,21 @@ out: complete_pdu(s, pdu, retval); } -static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs, - ssize_t err) -{ - if (err < 0) { - /* IO error return the error */ - err = -errno; - goto out; - } - vs->total += vs->len; - vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt); - if (vs->total < vs->count && vs->len > 0) { - do { - if (0) { - print_sg(vs->sg, vs->cnt); - } - vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, - vs->off); - if (vs->len > 0) { - vs->off += vs->len; - } - } while (vs->len == -1 && errno == EINTR); - if (vs->len == -1) { - err = -errno; - } - v9fs_write_post_pwritev(s, vs, err); - return; - } - vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total); - err = vs->offset; -out: - complete_pdu(s, vs->pdu, err); - g_free(vs); -} - -static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs) +static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, + int64_t off, int32_t count, + struct iovec *sg, int cnt) { int i, to_copy; ssize_t err = 0; int write_count; int64_t xattr_len; + size_t offset = 7; - xattr_len = vs->fidp->fs.xattr.len; - write_count = xattr_len - vs->off; - if (write_count > vs->count) { - write_count = vs->count; + + xattr_len = fidp->fs.xattr.len; + write_count = xattr_len - off; + if (write_count > count) { + write_count = count; } else if (write_count < 0) { /* * write beyond XATTR value len specified in @@ -2160,225 +1741,161 @@ static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs) err = -ENOSPC; goto out; } - vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count); - err = vs->offset; - vs->fidp->fs.xattr.copied_len += write_count; + offset += pdu_marshal(pdu, offset, "d", write_count); + err = offset; + fidp->fs.xattr.copied_len += write_count; /* * Now copy the content from sg list */ - for (i = 0; i < vs->cnt; i++) { - if (write_count > vs->sg[i].iov_len) { - to_copy = vs->sg[i].iov_len; + for (i = 0; i < cnt; i++) { + if (write_count > sg[i].iov_len) { + to_copy = sg[i].iov_len; } else { to_copy = write_count; } - memcpy((char *)vs->fidp->fs.xattr.value + vs->off, - vs->sg[i].iov_base, to_copy); + memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy); /* updating vs->off since we are not using below */ - vs->off += to_copy; + off += to_copy; write_count -= to_copy; } out: - complete_pdu(s, vs->pdu, err); - g_free(vs); + return err; } static void v9fs_write(void *opaque) { + int cnt; + ssize_t err; + int32_t fid; + int64_t off; + int32_t count; + int32_t len = 0; + int32_t total = 0; + size_t offset = 7; + V9fsFidState *fidp; + struct iovec iov[128]; /* FIXME: bad, bad, bad */ + struct iovec *sg = iov; V9fsPDU *pdu = opaque; V9fsState *s = pdu->s; - int32_t fid; - V9fsWriteState *vs; - ssize_t err; - - vs = g_malloc(sizeof(*vs)); - - vs->pdu = pdu; - vs->offset = 7; - vs->sg = vs->iov; - vs->total = 0; - vs->len = 0; - pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count, - vs->sg, &vs->cnt); - - vs->fidp = lookup_fid(s, fid); - if (vs->fidp == NULL) { + pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt); + fidp = lookup_fid(s, fid); + if (fidp == NULL) { err = -EINVAL; goto out; } - - if (vs->fidp->fid_type == P9_FID_FILE) { - if (vs->fidp->fs.fd == -1) { + if (fidp->fid_type == P9_FID_FILE) { + if (fidp->fs.fd == -1) { err = -EINVAL; goto out; } - } else if (vs->fidp->fid_type == P9_FID_XATTR) { + } else if (fidp->fid_type == P9_FID_XATTR) { /* * setxattr operation */ - v9fs_xattr_write(s, vs); - return; + err = v9fs_xattr_write(s, pdu, fidp, off, count, sg, cnt); + goto out; } else { err = -EINVAL; goto out; } - vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt); - if (vs->total <= vs->count) { - vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, vs->off); - if (vs->len > 0) { - vs->off += vs->len; + sg = cap_sg(sg, count, &cnt); + do { + if (0) { + print_sg(sg, cnt); } - err = vs->len; - v9fs_write_post_pwritev(s, vs, err); - } - return; + /* Loop in case of EINTR */ + do { + len = v9fs_co_pwritev(s, fidp, sg, cnt, off); + if (len >= 0) { + off += len; + total += len; + } + } while (len == -EINTR); + if (len < 0) { + /* IO error return the error */ + err = len; + goto out; + } + sg = adjust_sg(sg, len, &cnt); + } while (total < count && len > 0); + offset += pdu_marshal(pdu, offset, "d", total); + err = offset; out: - complete_pdu(s, vs->pdu, err); - g_free(vs); -} - -static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs) -{ - int err; - v9fs_string_copy(&vs->fidp->path, &vs->fullname); - stat_to_qid(&vs->stbuf, &vs->qid); - - vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit); - err = vs->offset; - - complete_pdu(s, vs->pdu, err); - v9fs_string_free(&vs->name); - v9fs_string_free(&vs->extension); - v9fs_string_free(&vs->fullname); - g_free(vs); -} - -static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err) -{ - if (err == 0) { - vs->iounit = get_iounit(s, &vs->fidp->path); - v9fs_create_post_getiounit(s, vs); - return; - } - - complete_pdu(s, vs->pdu, err); - v9fs_string_free(&vs->name); - v9fs_string_free(&vs->extension); - v9fs_string_free(&vs->fullname); - g_free(vs); -} - -static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err) -{ - if (err) { - err = -errno; - } - v9fs_post_create(s, vs, err); -} - -static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs, - int err) -{ - if (!vs->fidp->fs.dir) { - err = -errno; - } - vs->fidp->fid_type = P9_FID_DIR; - v9fs_post_create(s, vs, err); + complete_pdu(s, pdu, err); } -static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs, - int err) +static void v9fs_create(void *opaque) { - if (err) { - err = -errno; - goto out; - } + int32_t fid; + int err = 0; + size_t offset = 7; + V9fsFidState *fidp; + V9fsQID qid; + int32_t perm; + int8_t mode; + struct stat stbuf; + V9fsString name; + V9fsString extension; + V9fsString fullname; + int iounit; + V9fsPDU *pdu = opaque; - vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname); - v9fs_create_post_opendir(s, vs, err); - return; + v9fs_string_init(&fullname); -out: - v9fs_post_create(s, vs, err); -} + pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name, + &perm, &mode, &extension); -static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err) -{ - if (err < 0) { + fidp = lookup_fid(pdu->s, fid); + if (fidp == NULL) { + err = -EINVAL; goto out; } - err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf); - v9fs_create_post_dir_lstat(s, vs, err); - return; - -out: - v9fs_post_create(s, vs, err); -} - -static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err) -{ - if (err) { - vs->fidp->fid_type = P9_FID_NONE; - close(vs->fidp->fs.fd); - err = -errno; - } - v9fs_post_create(s, vs, err); - return; -} - -static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err) -{ - if (vs->fidp->fs.fd == -1) { - err = -errno; + v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data); + err = v9fs_co_lstat(pdu->s, &fullname, &stbuf); + if (!err) { + err = -EEXIST; goto out; - } - vs->fidp->fid_type = P9_FID_FILE; - err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf); - v9fs_create_post_fstat(s, vs, err); - - return; - -out: - v9fs_post_create(s, vs, err); - -} - -static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err) -{ - - if (err == 0 || errno != ENOENT) { - err = -errno; + } else if (err != -ENOENT) { goto out; } - - if (vs->perm & P9_STAT_MODE_DIR) { - err = v9fs_co_mkdir(s, vs->fullname.data, vs->perm & 0777, - vs->fidp->uid, -1); - v9fs_create_post_mkdir(s, vs, err); - } else if (vs->perm & P9_STAT_MODE_SYMLINK) { - err = v9fs_do_symlink(s, vs->fidp, vs->extension.data, - vs->fullname.data, -1); - v9fs_create_post_perms(s, vs, err); - } else if (vs->perm & P9_STAT_MODE_LINK) { - int32_t nfid = atoi(vs->extension.data); - V9fsFidState *nfidp = lookup_fid(s, nfid); + if (perm & P9_STAT_MODE_DIR) { + err = v9fs_co_mkdir(pdu->s, fullname.data, perm & 0777, + fidp->uid, -1); + if (err < 0) { + goto out; + } + err = v9fs_co_opendir(pdu->s, fidp); + if (err < 0) { + goto out; + } + fidp->fid_type = P9_FID_DIR; + } else if (perm & P9_STAT_MODE_SYMLINK) { + err = v9fs_co_symlink(pdu->s, fidp, extension.data, + fullname.data, -1); + if (err < 0) { + goto out; + } + } else if (perm & P9_STAT_MODE_LINK) { + int32_t nfid = atoi(extension.data); + V9fsFidState *nfidp = lookup_fid(pdu->s, nfid); if (nfidp == NULL) { - err = -errno; - v9fs_post_create(s, vs, err); + err = -EINVAL; + goto out; + } + err = v9fs_co_link(pdu->s, &nfidp->path, &fullname); + if (err < 0) { + goto out; } - err = v9fs_do_link(s, &nfidp->path, &vs->fullname); - v9fs_create_post_perms(s, vs, err); - } else if (vs->perm & P9_STAT_MODE_DEVICE) { + } else if (perm & P9_STAT_MODE_DEVICE) { char ctype; uint32_t major, minor; mode_t nmode = 0; - if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major, - &minor) != 3) { + if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) { err = -errno; - v9fs_post_create(s, vs, err); + goto out; } switch (ctype) { @@ -2390,134 +1907,95 @@ static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err) break; default: err = -EIO; - v9fs_post_create(s, vs, err); - } - - nmode |= vs->perm & 0777; - err = v9fs_do_mknod(s, vs->fullname.data, nmode, - makedev(major, minor), vs->fidp->uid, -1); - v9fs_create_post_perms(s, vs, err); - } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) { - err = v9fs_do_mknod(s, vs->fullname.data, S_IFIFO | (vs->perm & 0777), - 0, vs->fidp->uid, -1); - v9fs_post_create(s, vs, err); - } else if (vs->perm & P9_STAT_MODE_SOCKET) { - err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777), - 0, vs->fidp->uid, -1); - v9fs_post_create(s, vs, err); - } else { - vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid, - -1, omode_to_uflags(vs->mode)|O_CREAT, vs->perm); - - v9fs_create_post_open2(s, vs, err); - } - - return; - -out: - v9fs_post_create(s, vs, err); -} - -static void v9fs_create(void *opaque) -{ - V9fsPDU *pdu = opaque; - V9fsState *s = pdu->s; - int32_t fid; - V9fsCreateState *vs; - int err = 0; - - vs = g_malloc(sizeof(*vs)); - vs->pdu = pdu; - vs->offset = 7; - - v9fs_string_init(&vs->fullname); - - pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name, - &vs->perm, &vs->mode, &vs->extension); - - vs->fidp = lookup_fid(s, fid); - if (vs->fidp == NULL) { - err = -EINVAL; - goto out; - } - - v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data, - vs->name.data); - - err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf); - v9fs_create_post_lstat(s, vs, err); - return; - -out: - complete_pdu(s, vs->pdu, err); - v9fs_string_free(&vs->name); - v9fs_string_free(&vs->extension); - g_free(vs); -} + goto out; + } -static void v9fs_post_symlink(V9fsState *s, V9fsSymlinkState *vs, int err) -{ - if (err == 0) { - stat_to_qid(&vs->stbuf, &vs->qid); - vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid); - err = vs->offset; + nmode |= perm & 0777; + err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1, + makedev(major, minor), nmode); + if (err < 0) { + goto out; + } + } else if (perm & P9_STAT_MODE_NAMED_PIPE) { + err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1, + 0, S_IFIFO | (perm & 0777)); + if (err < 0) { + goto out; + } + } else if (perm & P9_STAT_MODE_SOCKET) { + err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1, + 0, S_IFSOCK | (perm & 0777)); + if (err < 0) { + goto out; + } } else { - err = -errno; + err = v9fs_co_open2(pdu->s, fidp, fullname.data, -1, + omode_to_uflags(mode)|O_CREAT, perm); + if (err < 0) { + goto out; + } + fidp->fid_type = P9_FID_FILE; } - complete_pdu(s, vs->pdu, err); - v9fs_string_free(&vs->name); - v9fs_string_free(&vs->symname); - v9fs_string_free(&vs->fullname); - g_free(vs); -} - -static void v9fs_symlink_post_do_symlink(V9fsState *s, V9fsSymlinkState *vs, - int err) -{ - if (err) { + err = v9fs_co_lstat(pdu->s, &fullname, &stbuf); + if (err < 0) { + fidp->fid_type = P9_FID_NONE; + if (fidp->fs.fd) { + close(fidp->fs.fd); + } goto out; } - err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf); + iounit = get_iounit(pdu->s, &fidp->path); + v9fs_string_copy(&fidp->path, &fullname); + stat_to_qid(&stbuf, &qid); + offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit); + err = offset; out: - v9fs_post_symlink(s, vs, err); + complete_pdu(pdu->s, pdu, err); + v9fs_string_free(&name); + v9fs_string_free(&extension); + v9fs_string_free(&fullname); } static void v9fs_symlink(void *opaque) { V9fsPDU *pdu = opaque; - V9fsState *s = pdu->s; + V9fsString name; + V9fsString symname; + V9fsString fullname; + V9fsFidState *dfidp; + V9fsQID qid; + struct stat stbuf; int32_t dfid; - V9fsSymlinkState *vs; int err = 0; gid_t gid; + size_t offset = 7; - vs = g_malloc(sizeof(*vs)); - vs->pdu = pdu; - vs->offset = 7; - - v9fs_string_init(&vs->fullname); - - pdu_unmarshal(vs->pdu, vs->offset, "dssd", &dfid, &vs->name, - &vs->symname, &gid); + v9fs_string_init(&fullname); + pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid); - vs->dfidp = lookup_fid(s, dfid); - if (vs->dfidp == NULL) { + dfidp = lookup_fid(pdu->s, dfid); + if (dfidp == NULL) { err = -EINVAL; goto out; } - v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->dfidp->path.data, - vs->name.data); - err = v9fs_do_symlink(s, vs->dfidp, vs->symname.data, - vs->fullname.data, gid); - v9fs_symlink_post_do_symlink(s, vs, err); - return; - + v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data); + err = v9fs_co_symlink(pdu->s, dfidp, symname.data, fullname.data, gid); + if (err < 0) { + goto out; + } + err = v9fs_co_lstat(pdu->s, &fullname, &stbuf); + if (err < 0) { + goto out; + } + stat_to_qid(&stbuf, &qid); + offset += pdu_marshal(pdu, offset, "Q", &qid); + err = offset; out: - complete_pdu(s, vs->pdu, err); - v9fs_string_free(&vs->name); - v9fs_string_free(&vs->symname); - g_free(vs); + complete_pdu(pdu->s, pdu, err); + v9fs_string_free(&name); + v9fs_string_free(&symname); + v9fs_string_free(&fullname); } static void v9fs_flush(void *opaque) @@ -2545,21 +2023,20 @@ static void v9fs_link(void *opaque) dfidp = lookup_fid(s, dfid); if (dfidp == NULL) { - err = -errno; + err = -ENOENT; goto out; } oldfidp = lookup_fid(s, oldfid); if (oldfidp == NULL) { - err = -errno; + err = -ENOENT; goto out; } v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data); - err = offset; - err = v9fs_do_link(s, &oldfidp->path, &fullname); - if (err) { - err = -errno; + err = v9fs_co_link(s, &oldfidp->path, &fullname); + if (!err) { + err = offset; } v9fs_string_free(&fullname); @@ -2594,39 +2071,6 @@ out: complete_pdu(pdu->s, pdu, err); } -static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err) -{ - if (err < 0) { - goto out; - } - - err = vs->offset; - -out: - v9fs_stat_free(&vs->v9stat); - complete_pdu(s, vs->pdu, err); - g_free(vs); -} - -static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err) -{ - if (err < 0) { - goto out; - } - if (vs->v9stat.length != -1) { - if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) { - err = -errno; - } - } - v9fs_wstat_post_truncate(s, vs, err); - return; - -out: - v9fs_stat_free(&vs->v9stat); - complete_pdu(s, vs->pdu, err); - g_free(vs); -} - static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp, int32_t newdirfid, V9fsString *name) { @@ -2695,24 +2139,6 @@ out: return err; } -static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err) -{ - if (err < 0) { - goto out; - } - - if (vs->v9stat.name.size != 0) { - err = v9fs_complete_rename(s, vs->fidp, -1, &vs->v9stat.name); - } - v9fs_wstat_post_rename(s, vs, err); - return; - -out: - v9fs_stat_free(&vs->v9stat); - complete_pdu(s, vs->pdu, err); - g_free(vs); -} - static void v9fs_rename(void *opaque) { int32_t fid; @@ -2742,143 +2168,90 @@ out: v9fs_string_free(&name); } -static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err) +static void v9fs_wstat(void *opaque) { - if (err < 0) { - goto out; - } + int32_t fid; + int err = 0; + int16_t unused; + V9fsStat v9stat; + size_t offset = 7; + struct stat stbuf; + V9fsFidState *fidp; + V9fsPDU *pdu = opaque; + V9fsState *s = pdu->s; - if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) { - if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid, - vs->v9stat.n_gid)) { - err = -errno; - } + pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat); + fidp = lookup_fid(s, fid); + if (fidp == NULL) { + err = -EINVAL; + goto out; } - v9fs_wstat_post_chown(s, vs, err); - return; - -out: - v9fs_stat_free(&vs->v9stat); - complete_pdu(s, vs->pdu, err); - g_free(vs); -} - -static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err) -{ - if (err < 0) { + /* do we need to sync the file? */ + if (donttouch_stat(&v9stat)) { + err = v9fs_co_fsync(s, fidp, 0); goto out; } - - if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) { + if (v9stat.mode != -1) { + uint32_t v9_mode; + err = v9fs_co_lstat(s, &fidp->path, &stbuf); + if (err < 0) { + goto out; + } + v9_mode = stat_to_v9mode(&stbuf); + if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) != + (v9_mode & P9_STAT_MODE_TYPE_BITS)) { + /* Attempting to change the type */ + err = -EIO; + goto out; + } + err = v9fs_co_chmod(s, &fidp->path, + v9mode_to_mode(v9stat.mode, + &v9stat.extension)); + if (err < 0) { + goto out; + } + } + if (v9stat.mtime != -1 || v9stat.atime != -1) { struct timespec times[2]; - if (vs->v9stat.atime != -1) { - times[0].tv_sec = vs->v9stat.atime; + if (v9stat.atime != -1) { + times[0].tv_sec = v9stat.atime; times[0].tv_nsec = 0; } else { times[0].tv_nsec = UTIME_OMIT; } - if (vs->v9stat.mtime != -1) { - times[1].tv_sec = vs->v9stat.mtime; + if (v9stat.mtime != -1) { + times[1].tv_sec = v9stat.mtime; times[1].tv_nsec = 0; } else { times[1].tv_nsec = UTIME_OMIT; } - - if (v9fs_do_utimensat(s, &vs->fidp->path, times)) { - err = -errno; + err = v9fs_co_utimensat(s, &fidp->path, times); + if (err < 0) { + goto out; } } - - v9fs_wstat_post_utime(s, vs, err); - return; - -out: - v9fs_stat_free(&vs->v9stat); - complete_pdu(s, vs->pdu, err); - g_free(vs); -} - -static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err) -{ - if (err == -1) { - err = -errno; - } - v9fs_stat_free(&vs->v9stat); - complete_pdu(s, vs->pdu, err); - g_free(vs); -} - -static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err) -{ - uint32_t v9_mode; - - if (err == -1) { - err = -errno; - goto out; - } - - v9_mode = stat_to_v9mode(&vs->stbuf); - - if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) != - (v9_mode & P9_STAT_MODE_TYPE_BITS)) { - /* Attempting to change the type */ - err = -EIO; + if (v9stat.n_gid != -1 || v9stat.n_uid != -1) { + err = v9fs_co_chown(s, &fidp->path, v9stat.n_uid, v9stat.n_gid); + if (err < 0) { goto out; + } } - - if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode, - &vs->v9stat.extension))) { - err = -errno; - } - v9fs_wstat_post_chmod(s, vs, err); - return; - -out: - v9fs_stat_free(&vs->v9stat); - complete_pdu(s, vs->pdu, err); - g_free(vs); -} - -static void v9fs_wstat(void *opaque) -{ - V9fsPDU *pdu = opaque; - V9fsState *s = pdu->s; - int32_t fid; - V9fsWstatState *vs; - int err = 0; - - vs = g_malloc(sizeof(*vs)); - vs->pdu = pdu; - vs->offset = 7; - - pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat); - - vs->fidp = lookup_fid(s, fid); - if (vs->fidp == NULL) { - err = -EINVAL; - goto out; - } - - /* do we need to sync the file? */ - if (donttouch_stat(&vs->v9stat)) { - err = v9fs_do_fsync(s, vs->fidp->fs.fd, 0); - v9fs_wstat_post_fsync(s, vs, err); - return; + if (v9stat.name.size != 0) { + err = v9fs_complete_rename(s, fidp, -1, &v9stat.name); + if (err < 0) { + goto out; + } } - - if (vs->v9stat.mode != -1) { - err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf); - v9fs_wstat_post_lstat(s, vs, err); - return; + if (v9stat.length != -1) { + err = v9fs_co_truncate(s, &fidp->path, v9stat.length); + if (err < 0) { + goto out; + } } - - v9fs_wstat_post_chmod(s, vs, err); - return; - + err = offset; out: - v9fs_stat_free(&vs->v9stat); - complete_pdu(s, vs->pdu, err); - g_free(vs); + v9fs_stat_free(&v9stat); + complete_pdu(s, pdu, err); } static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf) @@ -3006,89 +2379,81 @@ out: * do any thing in * qemu 9p server side lock code path. * So when a TLOCK request comes, always return success */ - static void v9fs_lock(void *opaque) { + int8_t status; + V9fsFlock *flock; + size_t offset = 7; + struct stat stbuf; + V9fsFidState *fidp; + int32_t fid, err = 0; V9fsPDU *pdu = opaque; V9fsState *s = pdu->s; - int32_t fid, err = 0; - V9fsLockState *vs; - - vs = g_malloc0(sizeof(*vs)); - vs->pdu = pdu; - vs->offset = 7; - vs->flock = g_malloc(sizeof(*vs->flock)); - pdu_unmarshal(vs->pdu, vs->offset, "dbdqqds", &fid, &vs->flock->type, - &vs->flock->flags, &vs->flock->start, &vs->flock->length, - &vs->flock->proc_id, &vs->flock->client_id); - - vs->status = P9_LOCK_ERROR; + flock = g_malloc(sizeof(*flock)); + pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type, + &flock->flags, &flock->start, &flock->length, + &flock->proc_id, &flock->client_id); + status = P9_LOCK_ERROR; /* We support only block flag now (that too ignored currently) */ - if (vs->flock->flags & ~P9_LOCK_FLAGS_BLOCK) { + if (flock->flags & ~P9_LOCK_FLAGS_BLOCK) { err = -EINVAL; goto out; } - vs->fidp = lookup_fid(s, fid); - if (vs->fidp == NULL) { + fidp = lookup_fid(s, fid); + if (fidp == NULL) { err = -ENOENT; goto out; } - - err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf); + err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf); if (err < 0) { - err = -errno; goto out; } - vs->status = P9_LOCK_SUCCESS; + status = P9_LOCK_SUCCESS; out: - vs->offset += pdu_marshal(vs->pdu, vs->offset, "b", vs->status); - complete_pdu(s, vs->pdu, err); - g_free(vs->flock); - g_free(vs); + err = offset; + err += pdu_marshal(pdu, offset, "b", status); + complete_pdu(s, pdu, err); + g_free(flock); } /* * When a TGETLOCK request comes, always return success because all lock * handling is done by client's VFS layer. */ - static void v9fs_getlock(void *opaque) { + size_t offset = 7; + struct stat stbuf; + V9fsFidState *fidp; + V9fsGetlock *glock; + int32_t fid, err = 0; V9fsPDU *pdu = opaque; V9fsState *s = pdu->s; - int32_t fid, err = 0; - V9fsGetlockState *vs; - vs = g_malloc0(sizeof(*vs)); - vs->pdu = pdu; - vs->offset = 7; + glock = g_malloc(sizeof(*glock)); + pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock->type, + &glock->start, &glock->length, &glock->proc_id, + &glock->client_id); - vs->glock = g_malloc(sizeof(*vs->glock)); - pdu_unmarshal(vs->pdu, vs->offset, "dbqqds", &fid, &vs->glock->type, - &vs->glock->start, &vs->glock->length, &vs->glock->proc_id, - &vs->glock->client_id); - - vs->fidp = lookup_fid(s, fid); - if (vs->fidp == NULL) { + fidp = lookup_fid(s, fid); + if (fidp == NULL) { err = -ENOENT; goto out; } - - err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf); + err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf); if (err < 0) { - err = -errno; goto out; } - vs->glock->type = F_UNLCK; - vs->offset += pdu_marshal(vs->pdu, vs->offset, "bqqds", vs->glock->type, - vs->glock->start, vs->glock->length, vs->glock->proc_id, - &vs->glock->client_id); + glock->type = F_UNLCK; + offset += pdu_marshal(pdu, offset, "bqqds", glock->type, + glock->start, glock->length, glock->proc_id, + &glock->client_id); + err = offset; out: - complete_pdu(s, vs->pdu, err); - g_free(vs->glock); - g_free(vs); + complete_pdu(s, pdu, err); + g_free(glock); } static void v9fs_mkdir(void *opaque) diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 46d79da..1d8c1b1 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -222,31 +222,6 @@ typedef struct V9fsState int32_t msize; } V9fsState; -typedef struct V9fsCreateState { - V9fsPDU *pdu; - size_t offset; - V9fsFidState *fidp; - V9fsQID qid; - int32_t perm; - int8_t mode; - struct stat stbuf; - V9fsString name; - V9fsString extension; - V9fsString fullname; - int iounit; -} V9fsCreateState; - -typedef struct V9fsLcreateState { - V9fsPDU *pdu; - size_t offset; - V9fsFidState *fidp; - V9fsQID qid; - int32_t iounit; - struct stat stbuf; - V9fsString name; - V9fsString fullname; -} V9fsLcreateState; - typedef struct V9fsStatState { V9fsPDU *pdu; size_t offset; @@ -278,19 +253,6 @@ typedef struct V9fsStatDotl { uint64_t st_data_version; } V9fsStatDotl; -typedef struct V9fsWalkState { - V9fsPDU *pdu; - size_t offset; - uint16_t nwnames; - int name_idx; - V9fsQID *qids; - V9fsFidState *fidp; - V9fsFidState *newfidp; - V9fsString path; - V9fsString *wnames; - struct stat stbuf; -} V9fsWalkState; - typedef struct V9fsOpenState { V9fsPDU *pdu; size_t offset; @@ -333,28 +295,6 @@ typedef struct V9fsWriteState { int cnt; } V9fsWriteState; -typedef struct V9fsWstatState -{ - V9fsPDU *pdu; - size_t offset; - int16_t unused; - V9fsStat v9stat; - V9fsFidState *fidp; - struct stat stbuf; -} V9fsWstatState; - -typedef struct V9fsSymlinkState -{ - V9fsPDU *pdu; - size_t offset; - V9fsString name; - V9fsString symname; - V9fsString fullname; - V9fsFidState *dfidp; - V9fsQID qid; - struct stat stbuf; -} V9fsSymlinkState; - typedef struct V9fsIattr { int32_t valid; @@ -403,16 +343,6 @@ typedef struct V9fsFlock V9fsString client_id; } V9fsFlock; -typedef struct V9fsLockState -{ - V9fsPDU *pdu; - size_t offset; - int8_t status; - struct stat stbuf; - V9fsFidState *fidp; - V9fsFlock *flock; -} V9fsLockState; - typedef struct V9fsGetlock { uint8_t type; @@ -422,15 +352,6 @@ typedef struct V9fsGetlock V9fsString client_id; } V9fsGetlock; -typedef struct V9fsGetlockState -{ - V9fsPDU *pdu; - size_t offset; - struct stat stbuf; - V9fsFidState *fidp; - V9fsGetlock *glock; -} V9fsGetlockState; - size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count, size_t offset, size_t size, int pack); diff --git a/hw/g364fb.c b/hw/g364fb.c index b3020c5..5e7bcfa 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -1,7 +1,7 @@ /* * QEMU G364 framebuffer Emulator. * - * Copyright (c) 2007-2009 Herve Poussineau + * Copyright (c) 2007-2011 Herve Poussineau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,27 +18,18 @@ */ #include "hw.h" -#include "mips.h" #include "console.h" #include "pixel_ops.h" - -//#define DEBUG_G364 - -#ifdef DEBUG_G364 -#define DPRINTF(fmt, ...) \ -do { printf("g364: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif -#define BADF(fmt, ...) \ -do { fprintf(stderr, "g364 ERROR: " fmt , ## __VA_ARGS__);} while (0) +#include "trace.h" +#include "sysbus.h" typedef struct G364State { /* hardware */ uint8_t *vram; - ram_addr_t vram_offset; - int vram_size; + uint32_t vram_size; qemu_irq irq; + MemoryRegion mem_vram; + MemoryRegion mem_ctrl; /* registers */ uint8_t color_palette[256][3]; uint8_t cursor_palette[3][3]; @@ -53,31 +44,32 @@ typedef struct G364State { int blanked; } G364State; -#define REG_ID 0x000000 -#define REG_BOOT 0x080000 -#define REG_DISPLAY 0x080118 -#define REG_VDISPLAY 0x080150 -#define REG_CTLA 0x080300 -#define REG_TOP 0x080400 -#define REG_CURS_PAL 0x080508 -#define REG_CURS_POS 0x080638 -#define REG_CLR_PAL 0x080800 -#define REG_CURS_PAT 0x081000 -#define REG_RESET 0x180000 +#define REG_BOOT 0x000000 +#define REG_DISPLAY 0x000118 +#define REG_VDISPLAY 0x000150 +#define REG_CTLA 0x000300 +#define REG_TOP 0x000400 +#define REG_CURS_PAL 0x000508 +#define REG_CURS_POS 0x000638 +#define REG_CLR_PAL 0x000800 +#define REG_CURS_PAT 0x001000 +#define REG_RESET 0x100000 #define CTLA_FORCE_BLANK 0x00000400 #define CTLA_NO_CURSOR 0x00800000 -static inline int check_dirty(ram_addr_t page) +static inline int check_dirty(G364State *s, ram_addr_t page) { - return cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG); + return memory_region_get_dirty(&s->mem_vram, page, DIRTY_MEMORY_VGA); } static inline void reset_dirty(G364State *s, ram_addr_t page_min, ram_addr_t page_max) { - cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE - 1, - VGA_DIRTY_FLAG); + memory_region_reset_dirty(&s->mem_vram, + page_min, + page_max + TARGET_PAGE_SIZE - page_min - 1, + DIRTY_MEMORY_VGA); } static void g364fb_draw_graphic8(G364State *s) @@ -110,11 +102,12 @@ static void g364fb_draw_graphic8(G364State *s) w = 4; break; default: - BADF("unknown host depth %d\n", ds_get_bits_per_pixel(s->ds)); + hw_error("g364: unknown host depth %d", + ds_get_bits_per_pixel(s->ds)); return; } - page = s->vram_offset; + page = 0; page_min = (ram_addr_t)-1; page_max = 0; @@ -135,7 +128,7 @@ static void g364fb_draw_graphic8(G364State *s) /* XXX: out of range in vram? */ data_display = dd = ds_get_data(s->ds); while (y < s->height) { - if (check_dirty(page)) { + if (check_dirty(s, page)) { if (y < ymin) ymin = ymax = y; if (page_min == (ram_addr_t)-1) @@ -262,7 +255,7 @@ static void g364fb_update_display(void *opaque) } else if (s->depth == 8) { g364fb_draw_graphic8(s); } else { - BADF("unknown guest depth %d\n", s->depth); + error_report("g364: unknown guest depth %d", s->depth); } qemu_irq_raise(s->irq); @@ -275,13 +268,12 @@ static inline void g364fb_invalidate_display(void *opaque) s->blanked = 0; for (i = 0; i < s->vram_size; i += TARGET_PAGE_SIZE) { - cpu_physical_memory_set_dirty(s->vram_offset + i); + memory_region_set_dirty(&s->mem_vram, i); } } -static void g364fb_reset(void *opaque) +static void g364fb_reset(G364State *s) { - G364State *s = opaque; qemu_irq_lower(s->irq); memset(s->color_palette, 0, sizeof(s->color_palette)); @@ -292,7 +284,7 @@ static void g364fb_reset(void *opaque) s->top_of_screen = 0; s->width = s->height = 0; memset(s->vram, 0, s->vram_size); - g364fb_invalidate_display(opaque); + g364fb_invalidate_display(s); } static void g364fb_screen_dump(void *opaque, const char *filename) @@ -304,7 +296,7 @@ static void g364fb_screen_dump(void *opaque, const char *filename) FILE *f; if (s->depth != 8) { - BADF("unknown guest depth %d\n", s->depth); + error_report("g364: unknown guest depth %d", s->depth); return; } @@ -336,7 +328,9 @@ static void g364fb_screen_dump(void *opaque, const char *filename) } /* called for accesses to io ports */ -static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr) +static uint64_t g364fb_ctrl_read(void *opaque, + target_phys_addr_t addr, + unsigned int size) { G364State *s = opaque; uint32_t val; @@ -353,9 +347,6 @@ static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr) val |= ((uint32_t)s->cursor_palette[idx][2] << 0); } else { switch (addr) { - case REG_ID: - val = 0x10; /* Mips G364 */ - break; case REG_DISPLAY: val = s->width / 4; break; @@ -367,33 +358,19 @@ static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr) break; default: { - BADF("invalid read at [" TARGET_FMT_plx "]\n", addr); + error_report("g364: invalid read at [" TARGET_FMT_plx "]", + addr); val = 0; break; } } } - DPRINTF("read 0x%08x at [" TARGET_FMT_plx "]\n", val, addr); + trace_g364fb_read(addr, val); return val; } -static uint32_t g364fb_ctrl_readw(void *opaque, target_phys_addr_t addr) -{ - uint32_t v = g364fb_ctrl_readl(opaque, addr & ~0x3); - if (addr & 0x2) - return v >> 16; - else - return v & 0xffff; -} - -static uint32_t g364fb_ctrl_readb(void *opaque, target_phys_addr_t addr) -{ - uint32_t v = g364fb_ctrl_readl(opaque, addr & ~0x3); - return (v >> (8 * (addr & 0x3))) & 0xff; -} - static void g364fb_update_depth(G364State *s) { static const int depths[8] = { 1, 2, 4, 8, 15, 16, 0 }; @@ -411,15 +388,18 @@ static void g364_invalidate_cursor_position(G364State *s) end = (ymax + 1) * ds_get_linesize(s->ds); for (i = start; i < end; i += TARGET_PAGE_SIZE) { - cpu_physical_memory_set_dirty(s->vram_offset + i); + memory_region_set_dirty(&s->mem_vram, i); } } -static void g364fb_ctrl_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void g364fb_ctrl_write(void *opaque, + target_phys_addr_t addr, + uint64_t val, + unsigned int size) { G364State *s = opaque; - DPRINTF("write 0x%08x at [" TARGET_FMT_plx "]\n", val, addr); + trace_g364fb_write(addr, val); if (addr >= REG_CLR_PAL && addr < REG_CLR_PAL + 0x800) { /* color palette */ @@ -442,120 +422,65 @@ static void g364fb_ctrl_writel(void *opaque, target_phys_addr_t addr, uint32_t v g364fb_invalidate_display(s); } else { switch (addr) { - case REG_ID: /* Card identifier; read-only */ - case REG_BOOT: /* Boot timing */ - case 0x80108: /* Line timing: half sync */ - case 0x80110: /* Line timing: back porch */ - case 0x80120: /* Line timing: short display */ - case 0x80128: /* Frame timing: broad pulse */ - case 0x80130: /* Frame timing: v sync */ - case 0x80138: /* Frame timing: v preequalise */ - case 0x80140: /* Frame timing: v postequalise */ - case 0x80148: /* Frame timing: v blank */ - case 0x80158: /* Line timing: line time */ - case 0x80160: /* Frame store: line start */ - case 0x80168: /* vram cycle: mem init */ - case 0x80170: /* vram cycle: transfer delay */ - case 0x80200: /* vram cycle: mask register */ - /* ignore */ - break; - case REG_TOP: - s->top_of_screen = val; - g364fb_invalidate_display(s); - break; - case REG_DISPLAY: - s->width = val * 4; - break; - case REG_VDISPLAY: - s->height = val / 2; - break; - case REG_CTLA: - s->ctla = val; - g364fb_update_depth(s); - g364fb_invalidate_display(s); - break; - case REG_CURS_POS: - g364_invalidate_cursor_position(s); - s->cursor_position = val; - g364_invalidate_cursor_position(s); - break; - case REG_RESET: - g364fb_reset(s); - break; - default: - BADF("invalid write of 0x%08x at [" TARGET_FMT_plx "]\n", val, addr); - break; + case REG_BOOT: /* Boot timing */ + case 0x00108: /* Line timing: half sync */ + case 0x00110: /* Line timing: back porch */ + case 0x00120: /* Line timing: short display */ + case 0x00128: /* Frame timing: broad pulse */ + case 0x00130: /* Frame timing: v sync */ + case 0x00138: /* Frame timing: v preequalise */ + case 0x00140: /* Frame timing: v postequalise */ + case 0x00148: /* Frame timing: v blank */ + case 0x00158: /* Line timing: line time */ + case 0x00160: /* Frame store: line start */ + case 0x00168: /* vram cycle: mem init */ + case 0x00170: /* vram cycle: transfer delay */ + case 0x00200: /* vram cycle: mask register */ + /* ignore */ + break; + case REG_TOP: + s->top_of_screen = val; + g364fb_invalidate_display(s); + break; + case REG_DISPLAY: + s->width = val * 4; + break; + case REG_VDISPLAY: + s->height = val / 2; + break; + case REG_CTLA: + s->ctla = val; + g364fb_update_depth(s); + g364fb_invalidate_display(s); + break; + case REG_CURS_POS: + g364_invalidate_cursor_position(s); + s->cursor_position = val; + g364_invalidate_cursor_position(s); + break; + case REG_RESET: + g364fb_reset(s); + break; + default: + error_report("g364: invalid write of 0x%" PRIx64 + " at [" TARGET_FMT_plx "]", val, addr); + break; } } qemu_irq_lower(s->irq); } -static void g364fb_ctrl_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - uint32_t old_val = g364fb_ctrl_readl(opaque, addr & ~0x3); - - if (addr & 0x2) - val = (val << 16) | (old_val & 0x0000ffff); - else - val = val | (old_val & 0xffff0000); - g364fb_ctrl_writel(opaque, addr & ~0x3, val); -} - -static void g364fb_ctrl_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - uint32_t old_val = g364fb_ctrl_readl(opaque, addr & ~0x3); - - switch (addr & 3) { - case 0: - val = val | (old_val & 0xffffff00); - break; - case 1: - val = (val << 8) | (old_val & 0xffff00ff); - break; - case 2: - val = (val << 16) | (old_val & 0xff00ffff); - break; - case 3: - val = (val << 24) | (old_val & 0x00ffffff); - break; - } - g364fb_ctrl_writel(opaque, addr & ~0x3, val); -} - -static CPUReadMemoryFunc * const g364fb_ctrl_read[3] = { - g364fb_ctrl_readb, - g364fb_ctrl_readw, - g364fb_ctrl_readl, -}; - -static CPUWriteMemoryFunc * const g364fb_ctrl_write[3] = { - g364fb_ctrl_writeb, - g364fb_ctrl_writew, - g364fb_ctrl_writel, +static const MemoryRegionOps g364fb_ctrl_ops = { + .read = g364fb_ctrl_read, + .write = g364fb_ctrl_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 4, + .impl.max_access_size = 4, }; -static int g364fb_load(QEMUFile *f, void *opaque, int version_id) +static int g364fb_post_load(void *opaque, int version_id) { G364State *s = opaque; - unsigned int i, vram_size; - - if (version_id != 1) - return -EINVAL; - - vram_size = qemu_get_be32(f); - if (vram_size < s->vram_size) - return -EINVAL; - qemu_get_buffer(f, s->vram, s->vram_size); - for (i = 0; i < 256; i++) - qemu_get_buffer(f, s->color_palette[i], 3); - for (i = 0; i < 3; i++) - qemu_get_buffer(f, s->cursor_palette[i], 3); - qemu_get_buffer(f, (uint8_t *)s->cursor, sizeof(s->cursor)); - s->cursor_position = qemu_get_be32(f); - s->ctla = qemu_get_be32(f); - s->top_of_screen = qemu_get_be32(f); - s->width = qemu_get_be32(f); - s->height = qemu_get_be32(f); /* force refresh */ g364fb_update_depth(s); @@ -564,52 +489,80 @@ static int g364fb_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static void g364fb_save(QEMUFile *f, void *opaque) -{ - G364State *s = opaque; - int i; - - qemu_put_be32(f, s->vram_size); - qemu_put_buffer(f, s->vram, s->vram_size); - for (i = 0; i < 256; i++) - qemu_put_buffer(f, s->color_palette[i], 3); - for (i = 0; i < 3; i++) - qemu_put_buffer(f, s->cursor_palette[i], 3); - qemu_put_buffer(f, (uint8_t *)s->cursor, sizeof(s->cursor)); - qemu_put_be32(f, s->cursor_position); - qemu_put_be32(f, s->ctla); - qemu_put_be32(f, s->top_of_screen); - qemu_put_be32(f, s->width); - qemu_put_be32(f, s->height); -} +static const VMStateDescription vmstate_g364fb = { + .name = "g364fb", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = g364fb_post_load, + .fields = (VMStateField[]) { + VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size), + VMSTATE_BUFFER_UNSAFE(color_palette, G364State, 0, 256 * 3), + VMSTATE_BUFFER_UNSAFE(cursor_palette, G364State, 0, 9), + VMSTATE_UINT16_ARRAY(cursor, G364State, 512), + VMSTATE_UINT32(cursor_position, G364State), + VMSTATE_UINT32(ctla, G364State), + VMSTATE_UINT32(top_of_screen, G364State), + VMSTATE_UINT32(width, G364State), + VMSTATE_UINT32(height, G364State), + VMSTATE_END_OF_LIST() + } +}; -int g364fb_mm_init(target_phys_addr_t vram_base, - target_phys_addr_t ctrl_base, int it_shift, - qemu_irq irq) +static void g364fb_init(DeviceState *dev, G364State *s) { - G364State *s; - int io_ctrl; - - s = g_malloc0(sizeof(G364State)); - - s->vram_size = 8 * 1024 * 1024; - s->vram_offset = qemu_ram_alloc(NULL, "g364fb.vram", s->vram_size); - s->vram = qemu_get_ram_ptr(s->vram_offset); - s->irq = irq; - - qemu_register_reset(g364fb_reset, s); - register_savevm(NULL, "g364fb", 0, 1, g364fb_save, g364fb_load, s); - g364fb_reset(s); + s->vram = g_malloc0(s->vram_size); s->ds = graphic_console_init(g364fb_update_display, g364fb_invalidate_display, g364fb_screen_dump, NULL, s); - cpu_register_physical_memory(vram_base, s->vram_size, s->vram_offset); + memory_region_init_io(&s->mem_ctrl, &g364fb_ctrl_ops, s, "ctrl", 0x180000); + memory_region_init_ram_ptr(&s->mem_vram, dev, "vram", + s->vram_size, s->vram); + memory_region_set_coalescing(&s->mem_vram); +} + +typedef struct { + SysBusDevice busdev; + G364State g364; +} G364SysBusState; - io_ctrl = cpu_register_io_memory(g364fb_ctrl_read, g364fb_ctrl_write, s, - DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(ctrl_base, 0x200000, io_ctrl); +static int g364fb_sysbus_init(SysBusDevice *dev) +{ + G364State *s = &FROM_SYSBUS(G364SysBusState, dev)->g364; + + g364fb_init(&dev->qdev, s); + sysbus_init_irq(dev, &s->irq); + sysbus_init_mmio_region(dev, &s->mem_ctrl); + sysbus_init_mmio_region(dev, &s->mem_vram); return 0; } + +static void g364fb_sysbus_reset(DeviceState *d) +{ + G364SysBusState *s = DO_UPCAST(G364SysBusState, busdev.qdev, d); + g364fb_reset(&s->g364); +} + +static SysBusDeviceInfo g364fb_sysbus_info = { + .init = g364fb_sysbus_init, + .qdev.name = "sysbus-g364", + .qdev.desc = "G364 framebuffer", + .qdev.size = sizeof(G364SysBusState), + .qdev.vmsd = &vmstate_g364fb, + .qdev.reset = g364fb_sysbus_reset, + .qdev.props = (Property[]) { + DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size, + 8 * 1024 * 1024), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void g364fb_register(void) +{ + sysbus_register_withprop(&g364fb_sysbus_info); +} + +device_init(g364fb_register); diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 6af9782..1c34253 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -297,7 +297,11 @@ static void gt64120_pci_mapping(GT64120State *s) s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21; s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21; isa_mem_base = s->PCI0IO_start; - isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length); + if (s->PCI0IO_length) { + isa_mmio_setup(&s->PCI0IO_mem, s->PCI0IO_length); + memory_region_add_subregion(get_system_memory(), s->PCI0IO_start, + &s->PCI0IO_mem); + } } } @@ -8,11 +8,6 @@ PCIBus *gt64120_register(qemu_irq *pic); /* bonito.c */ PCIBus *bonito_init(qemu_irq *pic); -/* g364fb.c */ -int g364fb_mm_init(target_phys_addr_t vram_base, - target_phys_addr_t ctrl_base, int it_shift, - qemu_irq irq); - /* mipsnet.c */ void mipsnet_init(int base, qemu_irq irq, NICInfo *nd); diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index 84ce061..f3c9f93 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -195,7 +195,20 @@ void mips_jazz_init (ram_addr_t ram_size, /* Video card */ switch (jazz_model) { case JAZZ_MAGNUM: - g364fb_mm_init(0x40000000, 0x60000000, 0, rc4030[3]); + dev = qdev_create(NULL, "sysbus-g364"); + qdev_init_nofail(dev); + sysbus = sysbus_from_qdev(dev); + sysbus_mmio_map(sysbus, 0, 0x60080000); + sysbus_mmio_map(sysbus, 1, 0x40000000); + sysbus_connect_irq(sysbus, 0, rc4030[3]); + { + /* Simple ROM, so user doesn't have to provide one */ + ram_addr_t rom_offset = qemu_ram_alloc(NULL, "g364fb.rom", 0x80000); + uint8_t *rom = qemu_get_ram_ptr(rom_offset); + cpu_register_physical_memory(0x60000000, 0x80000, + rom_offset | IO_MEM_ROM); + rom[0] = 0x10; /* Mips G364 */ + } break; case JAZZ_PICA61: isa_vga_mm_init(0x40000000, 0x60000000, 0, get_system_memory()); diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index 4727e07..fbd443d 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -146,6 +146,7 @@ static void ppc_core99_init (ram_addr_t ram_size, MacIONVRAMState *nvr; int bios_size; MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem, *escc_mem; + MemoryRegion *escc_bar = g_new(MemoryRegion, 1); MemoryRegion *ide_mem[3]; int ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; @@ -328,6 +329,8 @@ static void ppc_core99_init (ram_addr_t ram_size, escc_mem = escc_init(0x80013000, pic[0x25], pic[0x24], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); + memory_region_init_alias(escc_bar, "escc-bar", + escc_mem, 0, memory_region_size(escc_mem)); for(i = 0; i < nb_nics; i++) pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL); @@ -350,7 +353,7 @@ static void ppc_core99_init (ram_addr_t ram_size, adb_mouse_init(&adb_bus); macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem, - dbdma_mem, cuda_mem, NULL, 3, ide_mem, escc_mem); + dbdma_mem, cuda_mem, NULL, 3, ide_mem, escc_bar); if (usb_enabled) { usb_ohci_init_pci(pci_bus, -1); diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 0071fc9..235d2ef 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -83,7 +83,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, MacIONVRAMState *nvr; int bios_size; MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem; - MemoryRegion *escc_mem, *ide_mem[2]; + MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1), *ide_mem[2]; uint16_t ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; @@ -241,6 +241,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size, escc_mem = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); + memory_region_init_alias(escc_bar, "escc-bar", + escc_mem, 0, memory_region_size(escc_mem)); for(i = 0; i < nb_nics; i++) pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL); @@ -269,7 +271,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, pmac_format_nvram_partition(nvr, 0x2000); macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem, - dbdma_mem, cuda_mem, nvr, 2, ide_mem, escc_mem); + dbdma_mem, cuda_mem, nvr, 2, ide_mem, escc_bar); if (usb_enabled) { usb_ohci_init_pci(pci_bus, -1); @@ -261,7 +261,9 @@ void cpu_check_irqs(CPUState *env) pil |= 1 << 14; } - if (!pil) { + /* The bit corresponding to psrpil is (1<< psrpil), the next bit + is (2 << psrpil). */ + if (pil < (2 << env->psrpil)){ if (env->interrupt_request & CPU_INTERRUPT_HARD) { CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n", env->interrupt_index); @@ -293,10 +295,12 @@ void cpu_check_irqs(CPUState *env) break; } } - } else { + } else if (env->interrupt_request & CPU_INTERRUPT_HARD) { CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x " "current interrupt %x\n", pil, env->pil_in, env->softint, env->interrupt_index); + env->interrupt_index = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); } } @@ -176,6 +176,7 @@ static void vga_update_memory_access(VGACommonState *s) size = 0x8000; break; case 3: + default: base = 0xb8000; size = 0x8000; break; diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index f35ba84..6f44c84 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -50,6 +50,7 @@ struct xlx_ethlite { SysBusDevice busdev; + MemoryRegion mmio; qemu_irq irq; NICState *nic; NICConf conf; @@ -70,7 +71,8 @@ static inline void eth_pulse_irq(struct xlx_ethlite *s) } } -static uint32_t eth_readl (void *opaque, target_phys_addr_t addr) +static uint64_t +eth_read(void *opaque, target_phys_addr_t addr, unsigned int size) { struct xlx_ethlite *s = opaque; uint32_t r = 0; @@ -98,10 +100,12 @@ static uint32_t eth_readl (void *opaque, target_phys_addr_t addr) } static void -eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +eth_write(void *opaque, target_phys_addr_t addr, + uint64_t val64, unsigned int size) { struct xlx_ethlite *s = opaque; unsigned int base = 0; + uint32_t value = val64; addr >>= 2; switch (addr) @@ -146,12 +150,14 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) } } -static CPUReadMemoryFunc * const eth_read[] = { - NULL, NULL, ð_readl, -}; - -static CPUWriteMemoryFunc * const eth_write[] = { - NULL, NULL, ð_writel, +static const MemoryRegionOps eth_ops = { + .read = eth_read, + .write = eth_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } }; static int eth_can_rx(VLANClientState *nc) @@ -206,13 +212,12 @@ static NetClientInfo net_xilinx_ethlite_info = { static int xilinx_ethlite_init(SysBusDevice *dev) { struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev); - int regs; sysbus_init_irq(dev, &s->irq); s->rxbuf = 0; - regs = cpu_register_io_memory(eth_read, eth_write, s, DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, R_MAX * 4, regs); + memory_region_init_io(&s->mmio, ð_ops, s, "xilinx-ethlite", R_MAX * 4); + sysbus_init_mmio_region(dev, &s->mmio); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf, diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c index cb72d5a..58b73d9 100644 --- a/hw/xilinx_intc.c +++ b/hw/xilinx_intc.c @@ -40,6 +40,7 @@ struct xlx_pic { SysBusDevice busdev; + MemoryRegion mmio; qemu_irq parent_irq; /* Configuration reg chosen at synthesis-time. QEMU populates @@ -72,7 +73,8 @@ static void update_irq(struct xlx_pic *p) } } -static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) +static uint64_t +pic_read(void *opaque, target_phys_addr_t addr, unsigned int size) { struct xlx_pic *p = opaque; uint32_t r = 0; @@ -91,9 +93,11 @@ static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) } static void -pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +pic_write(void *opaque, target_phys_addr_t addr, + uint64_t val64, unsigned int size) { struct xlx_pic *p = opaque; + uint32_t value = val64; addr >>= 2; D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); @@ -116,14 +120,14 @@ pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value) update_irq(p); } -static CPUReadMemoryFunc * const pic_read[] = { - NULL, NULL, - &pic_readl, -}; - -static CPUWriteMemoryFunc * const pic_write[] = { - NULL, NULL, - &pic_writel, +static const MemoryRegionOps pic_ops = { + .read = pic_read, + .write = pic_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } }; static void irq_handler(void *opaque, int irq, int level) @@ -148,13 +152,12 @@ static void irq_handler(void *opaque, int irq, int level) static int xilinx_intc_init(SysBusDevice *dev) { struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev); - int pic_regs; qdev_init_gpio_in(&dev->qdev, irq_handler, 32); sysbus_init_irq(dev, &p->parent_irq); - pic_regs = cpu_register_io_memory(pic_read, pic_write, p, DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, R_MAX * 4, pic_regs); + memory_region_init_io(&p->mmio, &pic_ops, p, "xilinx-pic", R_MAX * 4); + sysbus_init_mmio_region(dev, &p->mmio); return 0; } diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index f1c7abc..8779c56 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -59,6 +59,7 @@ struct xlx_timer struct timerblock { SysBusDevice busdev; + MemoryRegion mmio; qemu_irq irq; uint32_t nr_timers; uint32_t freq_hz; @@ -85,7 +86,8 @@ static void timer_update_irq(struct timerblock *t) qemu_set_irq(t->irq, !!irq); } -static uint32_t timer_readl (void *opaque, target_phys_addr_t addr) +static uint64_t +timer_read(void *opaque, target_phys_addr_t addr, unsigned int size) { struct timerblock *t = opaque; struct xlx_timer *xt; @@ -134,11 +136,13 @@ static void timer_enable(struct xlx_timer *xt) } static void -timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +timer_write(void *opaque, target_phys_addr_t addr, + uint64_t val64, unsigned int size) { struct timerblock *t = opaque; struct xlx_timer *xt; unsigned int timer; + uint32_t value = val64; addr >>= 2; timer = timer_from_addr(addr); @@ -166,14 +170,14 @@ timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) timer_update_irq(t); } -static CPUReadMemoryFunc * const timer_read[] = { - NULL, NULL, - &timer_readl, -}; - -static CPUWriteMemoryFunc * const timer_write[] = { - NULL, NULL, - &timer_writel, +static const MemoryRegionOps timer_ops = { + .read = timer_read, + .write = timer_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } }; static void timer_hit(void *opaque) @@ -192,7 +196,6 @@ static int xilinx_timer_init(SysBusDevice *dev) { struct timerblock *t = FROM_SYSBUS(typeof (*t), dev); unsigned int i; - int timer_regs; /* All timers share a single irq line. */ sysbus_init_irq(dev, &t->irq); @@ -209,9 +212,9 @@ static int xilinx_timer_init(SysBusDevice *dev) ptimer_set_freq(xt->ptimer, t->freq_hz); } - timer_regs = cpu_register_io_memory(timer_read, timer_write, t, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, R_MAX * 4 * t->nr_timers, timer_regs); + memory_region_init_io(&t->mmio, &timer_ops, t, "xilinx-timer", + R_MAX * 4 * t->nr_timers); + sysbus_init_mmio_region(dev, &t->mmio); return 0; } diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c index 467a26c..ceb7b4d 100644 --- a/hw/xilinx_uartlite.c +++ b/hw/xilinx_uartlite.c @@ -49,6 +49,7 @@ struct xlx_uartlite { SysBusDevice busdev; + MemoryRegion mmio; CharDriverState *chr; qemu_irq irq; @@ -82,7 +83,8 @@ static void uart_update_status(struct xlx_uartlite *s) s->regs[R_STATUS] = r; } -static uint32_t uart_readl (void *opaque, target_phys_addr_t addr) +static uint64_t +uart_read(void *opaque, target_phys_addr_t addr, unsigned int size) { struct xlx_uartlite *s = opaque; uint32_t r = 0; @@ -107,9 +109,11 @@ static uint32_t uart_readl (void *opaque, target_phys_addr_t addr) } static void -uart_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +uart_write(void *opaque, target_phys_addr_t addr, + uint64_t val64, unsigned int size) { struct xlx_uartlite *s = opaque; + uint32_t value = val64; unsigned char ch = value; addr >>= 2; @@ -147,16 +151,14 @@ uart_writel (void *opaque, target_phys_addr_t addr, uint32_t value) uart_update_irq(s); } -static CPUReadMemoryFunc * const uart_read[] = { - &uart_readl, - &uart_readl, - &uart_readl, -}; - -static CPUWriteMemoryFunc * const uart_write[] = { - &uart_writel, - &uart_writel, - &uart_writel, +static const MemoryRegionOps uart_ops = { + .read = uart_read, + .write = uart_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4 + } }; static void uart_rx(void *opaque, const uint8_t *buf, int size) @@ -196,14 +198,12 @@ static void uart_event(void *opaque, int event) static int xilinx_uartlite_init(SysBusDevice *dev) { struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev); - int uart_regs; sysbus_init_irq(dev, &s->irq); uart_update_status(s); - uart_regs = cpu_register_io_memory(uart_read, uart_write, s, - DEVICE_NATIVE_ENDIAN); - sysbus_init_mmio(dev, R_MAX * 4, uart_regs); + memory_region_init_io(&s->mmio, &uart_ops, s, "xilinx-uartlite", R_MAX * 4); + sysbus_init_mmio_region(dev, &s->mmio); s->chr = qdev_init_chardev(&dev->qdev); if (s->chr) |