This allows futimens() in the guest to stay functional even if the file was unlinked.
Signed-off-by: Greg Kurz <gr...@kaod.org> --- fsdev/file-op-9p.h | 2 ++ hw/9pfs/9p-handle.c | 10 ++++++++++ hw/9pfs/9p-local.c | 10 ++++++++++ hw/9pfs/9p-proxy.c | 10 ++++++++++ hw/9pfs/9p-synth.c | 8 ++++++++ hw/9pfs/9p.c | 18 ++++++++++++++++-- hw/9pfs/cofs.c | 18 ++++++++++++++++++ hw/9pfs/coth.h | 1 + 8 files changed, 75 insertions(+), 2 deletions(-) diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index 930bcc623f8b..811ca234cf86 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -141,6 +141,8 @@ struct FileOperations V9fsPath *newdir, const char *new_name); int (*unlinkat)(FsContext *ctx, V9fsPath *dir, const char *name, int flags); int (*ftruncate)(FsContext *, int, V9fsFidOpenState *, off_t); + int (*futimens)(FsContext *, int, V9fsFidOpenState *, + const struct timespec *); void *opaque; }; diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c index 197c2c7efbb5..382b4d57927a 100644 --- a/hw/9pfs/9p-handle.c +++ b/hw/9pfs/9p-handle.c @@ -400,6 +400,15 @@ static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path, return ret; } +static int handle_futimens(FsContext *s, int fid_type, V9fsFidOpenState *fs, + const struct timespec *buf) +{ + int fd; + + fd = v9fs_get_fd_fid(fid_type, fs); + return qemu_futimens(fd, buf); +} + static int handle_remove(FsContext *ctx, const char *path) { errno = EOPNOTSUPP; @@ -706,4 +715,5 @@ FileOperations handle_ops = { .renameat = handle_renameat, .unlinkat = handle_unlinkat, .ftruncate = handle_ftruncate, + .futimens = handle_futimens, }; diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index b4c31c49da69..46ac7aab7c47 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -953,6 +953,15 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path, return ret; } +static int local_futimens(FsContext *s, int fid_type, V9fsFidOpenState *fs, + const struct timespec *buf) +{ + int fd; + + fd = v9fs_get_fd_fid(fid_type, fs); + return qemu_futimens(fd, buf); +} + static int local_remove(FsContext *ctx, const char *path) { int err; @@ -1290,4 +1299,5 @@ FileOperations local_ops = { .renameat = local_renameat, .unlinkat = local_unlinkat, .ftruncate = local_ftruncate, + .futimens = local_futimens, }; diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c index 9abcc201bd67..cbc94b645852 100644 --- a/hw/9pfs/9p-proxy.c +++ b/hw/9pfs/9p-proxy.c @@ -923,6 +923,15 @@ static int proxy_utimensat(FsContext *s, V9fsPath *fs_path, return retval; } +static int proxy_futimens(FsContext *s, int fid_type, V9fsFidOpenState *fs, + const struct timespec *buf) +{ + int fd; + + fd = v9fs_get_fd_fid(fid_type, fs); + return qemu_futimens(fd, buf); +} + static int proxy_remove(FsContext *ctx, const char *path) { int retval; @@ -1221,4 +1230,5 @@ FileOperations proxy_ops = { .renameat = proxy_renameat, .unlinkat = proxy_unlinkat, .ftruncate = proxy_ftruncate, + .futimens = proxy_futimens, }; diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index 70c71ce305c9..c4770792a79f 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -412,6 +412,13 @@ static int synth_utimensat(FsContext *fs_ctx, V9fsPath *path, return 0; } +static int synth_futimens(FsContext *fs_ctx, int fid_type, V9fsFidOpenState *fs, + const struct timespec *buf) +{ + errno = EPERM; + return -1; +} + static int synth_remove(FsContext *ctx, const char *path) { errno = EPERM; @@ -574,4 +581,5 @@ FileOperations synth_ops = { .renameat = synth_renameat, .unlinkat = synth_unlinkat, .ftruncate = synth_ftruncate, + .futimens = synth_futimens, }; diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 3aa4c8e22ed9..97dba6190809 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -1194,6 +1194,20 @@ static int v9fs_do_truncate(V9fsPDU *pdu, V9fsFidState *fidp, off_t size) return err; } +static int v9fs_do_utimens(V9fsPDU *pdu, V9fsFidState *fidp, + struct timespec times[2]) +{ + int err; + + if (fid_has_file(fidp)) { + err = v9fs_co_futimens(pdu, fidp, times); + } else { + err = v9fs_co_utimensat(pdu, &fidp->path, times); + } + + return err; +} + /* Attribute flags */ #define P9_ATTR_MODE (1 << 0) #define P9_ATTR_UID (1 << 1) @@ -1254,7 +1268,7 @@ static void v9fs_setattr(void *opaque) } else { times[1].tv_nsec = UTIME_OMIT; } - err = v9fs_co_utimensat(pdu, &fidp->path, times); + err = v9fs_do_utimens(pdu, fidp, times); if (err < 0) { goto out; } @@ -2749,7 +2763,7 @@ static void v9fs_wstat(void *opaque) } else { times[1].tv_nsec = UTIME_OMIT; } - err = v9fs_co_utimensat(pdu, &fidp->path, times); + err = v9fs_do_utimens(pdu, fidp, times); if (err < 0) { goto out; } diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 969c24730cb0..1ed9c298f98d 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -133,6 +133,24 @@ int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path, return err; } +int v9fs_co_futimens(V9fsPDU *pdu, V9fsFidState *fidp, struct timespec times[2]) +{ + int err; + V9fsState *s = pdu->s; + + if (v9fs_request_cancelled(pdu)) { + return -EINTR; + } + v9fs_co_run_in_worker( + { + err = s->ops->futimens(&s->ctx, fidp->fid_type, &fidp->fs, times); + if (err < 0) { + err = -errno; + } + }); + return err; +} + int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid) { int err; diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h index 4f493ad29ec4..c4e90059f00c 100644 --- a/hw/9pfs/coth.h +++ b/hw/9pfs/coth.h @@ -95,5 +95,6 @@ extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *, extern int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t, V9fsStatDotl *v9stat); extern int v9fs_co_ftruncate(V9fsPDU *, V9fsFidState *, off_t); +extern int v9fs_co_futimens(V9fsPDU *, V9fsFidState *, struct timespec [2]); #endif