9ns: Implement fsync with chan_ctl
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 6 Apr 2018 18:27:02 +0000 (14:27 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 30 Apr 2018 18:37:05 +0000 (14:37 -0400)
If you fsync on a directory, we'll sync the entire FS for the given device.
You can use the sync helper to cause fsyncs.

Note your bind order matters.  If you mount or bind with "-a", it'll be at
the bottom of the union mount list.  You probably want -b.  For example:

$ mount -a -c -C /srv/some_chan /mnt
$ sync /mnt  # this calls #kfs.chan_ctl

That will sync kfs's /mnt, not gtfs's, since both kfs and gtfs have a chan
at /mnt/ that can be opened.

$ mount -b -c -C /srv/some_chan /mnt
$ sync /mnt  # this calls #gtfs.chan_ctl

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/drivers/dev/gtfs.c
kern/drivers/dev/kfs.c
kern/drivers/dev/tmpfs.c
kern/include/ns.h
kern/src/ns/sysfile.c
kern/src/syscall.c
tests/sync.c [new file with mode: 0644]

index 2fc6337..1983a57 100644 (file)
@@ -810,6 +810,22 @@ static void gtfs_sync_chans_fs(struct chan *any_c)
        gtfs_sync_gtfs(chan_to_gtfs(any_c));
 }
 
+static unsigned long gtfs_chan_ctl(struct chan *c, int op, unsigned long a1,
+                                   unsigned long a2, unsigned long a3,
+                                   unsigned long a4)
+{
+       switch (op) {
+       case CCTL_SYNC:
+               if (tree_file_is_dir(chan_to_tree_file(c)))
+                       gtfs_sync_chans_fs(c);
+               else
+                       gtfs_sync_chan(c);
+               return 0;
+       default:
+               error(EINVAL, "%s does not support %d", __func__, op);
+       }
+}
+
 struct dev gtfs_devtab __devtab = {
        .name = "gtfs",
 
@@ -831,4 +847,5 @@ struct dev gtfs_devtab __devtab = {
        .power = devpower,
        .chaninfo = devchaninfo,
        .mmap = tree_chan_mmap,
+       .chan_ctl = gtfs_chan_ctl,
 };
index 5c07115..b701a1d 100644 (file)
@@ -302,6 +302,18 @@ static struct chan *kfs_attach(char *spec)
        return tree_file_alloc_chan(kfs.tfs.root, &kfs_devtab, "#kfs");
 }
 
+static unsigned long kfs_chan_ctl(struct chan *c, int op, unsigned long a1,
+                                  unsigned long a2, unsigned long a3,
+                                  unsigned long a4)
+{
+       switch (op) {
+       case CCTL_SYNC:
+               return 0;
+       default:
+               error(EINVAL, "%s does not support %d", __func__, op);
+       }
+}
+
 struct dev kfs_devtab __devtab = {
        .name = "kfs",
        .reset = devreset,
@@ -323,4 +335,5 @@ struct dev kfs_devtab __devtab = {
        .power = devpower,
        .chaninfo = devchaninfo,
        .mmap = tree_chan_mmap,
+       .chan_ctl = kfs_chan_ctl,
 };
index f4e6389..7a55da6 100644 (file)
@@ -246,6 +246,18 @@ void tmpfs_rename(struct chan *c, struct chan *new_p_c, const char *name,
        tree_chan_rename(c, new_p_c, name, flags);
 }
 
+static unsigned long tmpfs_chan_ctl(struct chan *c, int op, unsigned long a1,
+                                    unsigned long a2, unsigned long a3,
+                                    unsigned long a4)
+{
+       switch (op) {
+       case CCTL_SYNC:
+               return 0;
+       default:
+               error(EINVAL, "%s does not support %d", __func__, op);
+       }
+}
+
 struct dev tmpfs_devtab __devtab = {
        .name = "tmpfs",
        .reset = devreset,
@@ -267,4 +279,5 @@ struct dev tmpfs_devtab __devtab = {
        .power = devpower,
        .chaninfo = devchaninfo,
        .mmap = tree_chan_mmap,
+       .chan_ctl = tmpfs_chan_ctl,
 };
index 47cf9f4..68985ac 100644 (file)
@@ -134,6 +134,7 @@ extern int parseether(uint8_t * unused_uint8_p_t, char *unused_char_p_t);
  * chan, you already have the flags.  It's not like when you have an FD and
  * don't (yet) have the Unix struct file. */
 #define CCTL_SET_FL                            1
+#define CCTL_SYNC                              2
 
 struct qid {
        uint64_t path;
@@ -1124,6 +1125,7 @@ int plan9setup(struct proc *new_proc, struct proc *parent, int flags);
 int iseve(void);
 int fd_getfl(int fd);
 int fd_setfl(int fd, int flags);
+int fd_sync(int fd);
 
 /* kern/drivers/dev/srv.c */
 char *srvname(struct chan *c);
index c0e44aa..9ad7d46 100644 (file)
@@ -1521,6 +1521,30 @@ int fd_setfl(int fd, int flags)
        return ret;
 }
 
+int fd_sync(int fd)
+{
+       ERRSTACK(2);
+       struct chan *c;
+       int ret = 0;
+
+       if (waserror()) {
+               poperror();
+               return -1;
+       }
+       c = fdtochan(&current->open_files, fd, -1, 0, 1);
+       if (waserror()) {
+               cclose(c);
+               nexterror();
+       }
+       if (!devtab[c->type].chan_ctl)
+               error(EINVAL, "can't fsync, %s has no chan_ctl", chan_dev_name(c));
+       ret = devtab[c->type].chan_ctl(c, CCTL_SYNC, 0, 0, 0, 0);
+       poperror();
+       cclose(c);
+       poperror();
+       return ret;
+}
+
 ssize_t kread_file(struct file_or_chan *file, void *buf, size_t sz)
 {
        /* TODO: (KFOP) (VFS kernel read/writes need to be from a ktask) */
index 00a6286..95eaee3 100644 (file)
@@ -1895,10 +1895,11 @@ intreg_t sys_fcntl(struct proc *p, int fd, int cmd, unsigned long arg1,
                return sysdup(fd, newfd, FALSE);
        case (F_GETFD):
        case (F_SETFD):
-       case (F_SYNC):
        case (F_ADVISE):
                /* TODO: 9ns versions */
                return 0;
+       case (F_SYNC):
+               return fd_sync(fd);
        case (F_GETFL):
                return fd_getfl(fd);
        case (F_SETFL):
diff --git a/tests/sync.c b/tests/sync.c
new file mode 100644 (file)
index 0000000..4f0c1e4
--- /dev/null
@@ -0,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+int main(int argc, char **argv)
+{
+       int fd, ret;
+       char *path = ".";
+
+       if (argc > 2) {
+               fprintf(stderr, "Usage: %s [PATH]\n", argv[0]);
+               exit(-1);
+       }
+       if (argc == 2)
+               path = argv[1];
+       fd = open(path, O_READ);
+       if (fd < 0) {
+               perror("open");
+               exit(-1);
+       }
+       ret = fsync(fd);
+       if (ret)
+               perror("fsync");
+       close(fd);
+       return ret;
+}