tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[RFC] pass FAF flag to perfuse



Hi

PUFFS sometimes uses Fire-And-Forget (FAF) operation, where the
request is sent to userland but the result is not awaited. This
always happens for close, inactive and reclaim, and optionnaly
happens for fsync, setattr (during fsync), and write (during putpages).

There is a ressource leak when the filesystem is getting unresponsive
and the kernel keeps sending requests. perfuse and puffs hold buffer 
in userspace related to the requests, and this may last for a while.

Attached patch makes sure a puffs filesystem can be informed that 
a fsync, setattr or write is in FAF mode. libperfuse use it to avoid
awaiting for the reply of theses operations. Of course, we still
get FUSE replies, but we ignore them except if there is an error. In
that later case, we abort.

Opinions?

-- 
Emmanuel Dreyfus
manu%netbsd.org@localhost
Index: sys/sys/vnode.h
===================================================================
RCS file: /cvsroot/src/sys/sys/vnode.h,v
retrieving revision 1.236
diff -U4 -r1.236 vnode.h
--- sys/sys/vnode.h     24 Nov 2011 15:51:30 -0000      1.236
+++ sys/sys/vnode.h     5 Jun 2012 12:35:23 -0000
@@ -289,8 +289,9 @@
 #define        IO_NORMAL       0x00800         /* operate on regular data */
 #define        IO_EXT          0x01000         /* operate on extended 
attributes */
 #define        IO_DIRECT       0x02000         /* direct I/O hint */
 #define        IO_JOURNALLOCKED 0x04000        /* journal is already locked */
+#define        IO_FAF          0x08000         /* FAF bit for PUFFS (userland 
only) */
 #define        IO_ADV_MASK     0x00003         /* access pattern hint */
 
 #define        IO_ADV_SHIFT    0
 #define        IO_ADV_ENCODE(adv)      (((adv) << IO_ADV_SHIFT) & IO_ADV_MASK)
Index: lib/libperfuse/debug.c
===================================================================
RCS file: /cvsroot/src/lib/libperfuse/debug.c,v
retrieving revision 1.11
diff -U4 -r1.11 debug.c
--- lib/libperfuse/debug.c      21 Mar 2012 10:10:36 -0000      1.11
+++ lib/libperfuse/debug.c      5 Jun 2012 12:35:23 -0000
@@ -197,9 +197,9 @@
 
        ps = puffs_getspecific(pu);
 
        (void)ftruncate(fileno(fp), 0);
-       (void)fseek(fp, 0, SEEK_SET);
+       (void)fseek(fp, (long int)0, SEEK_SET);
 
        (void)memset(&ts_min, 0, sizeof(ts_min));
        (void)memset(&ts_max, 0, sizeof(ts_max));
        (void)memset(&ts_total, 0, sizeof(ts_total));
Index: lib/libperfuse/ops.c
===================================================================
RCS file: /cvsroot/src/lib/libperfuse/ops.c,v
retrieving revision 1.55
diff -U4 -r1.55 ops.c
--- lib/libperfuse/ops.c        28 May 2012 02:13:32 -0000      1.55
+++ lib/libperfuse/ops.c        5 Jun 2012 12:35:23 -0000
@@ -1679,17 +1679,19 @@
 perfuse_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc,
        const struct vattr *vap, const struct puffs_cred *pcr)
 {
        return perfuse_node_setattr_ttl(pu, opc, 
-                                       __UNCONST(vap), pcr, NULL);
+                                       __UNCONST(vap), pcr, NULL, 
+                                       PUFFS_FSYNC_WAIT);
 }
 
 int
 perfuse_node_setattr_ttl(struct puffs_usermount *pu, puffs_cookie_t opc,
        struct vattr *vap, const struct puffs_cred *pcr,
-       struct timespec *va_ttl)
+       struct timespec *va_ttl, int flags)
 {
        perfuse_msg_t *pm;
+       enum perfuse_xchg_pb_reply reply;
        uint64_t fh;
        struct perfuse_state *ps;
        struct perfuse_node_data *pnd;
        struct fuse_setattr_in *fsi;
@@ -1702,8 +1704,9 @@
 #endif
 
        ps = puffs_getspecific(pu);
        pnd = PERFUSE_NODE_DATA(opc);
+       reply = (flags & PUFFS_FSYNC_WAIT) ? wait_reply : no_reply;
 
        /*
         * The only operation we can do once the file is removed 
         * is to resize it, and we can do it only if it is open.
@@ -1885,9 +1888,12 @@
                    fsi->size);
        }
 #endif
 
-       if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0)
+       if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), reply)) != 0)
+               goto out;
+
+       if (reply == no_reply)
                goto out;
 
        /*
         * Copy back the new values 
@@ -1984,8 +1990,9 @@
        const struct puffs_cred *pcr, int flags, off_t offlo, off_t offhi)
 {
        int op;
        perfuse_msg_t *pm;
+       enum perfuse_xchg_pb_reply reply;
        struct perfuse_state *ps;
        struct perfuse_node_data *pnd;
        struct fuse_fsync_in *ffi;
        uint64_t fh;
@@ -1993,8 +2000,9 @@
        
        pm = NULL;
        ps = puffs_getspecific(pu);
        pnd = PERFUSE_NODE_DATA(opc);
+       reply = (flags & PUFFS_FSYNC_WAIT) ? wait_reply : no_reply;
 
        /*
         * No need to sync a removed node
         */
@@ -2060,9 +2068,9 @@
                        PERFUSE_NODE_DATA(opc)->pnd_nodeid, ffi->fh);
 #endif
 
        if ((error = xchg_msg(pu, opc, pm, 
-                             NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0)
+                             NO_PAYLOAD_REPLY_LEN, reply)) != 0)
                goto out;       
 
        /*
         * No reply beyond fuse_out_header: nothing to do on success
@@ -2075,9 +2083,10 @@
                DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n", 
                        __func__, (void*)opc, perfuse_node_path(opc));
 #endif
 
-       ps->ps_destroy_msg(pm);
+       if (reply != no_reply)
+               ps->ps_destroy_msg(pm);
 
 out:
        /*
         * ENOSYS is not returned to kernel,
@@ -3029,8 +3038,9 @@
        struct perfuse_state *ps;
        struct perfuse_node_data *pnd;
        struct vattr *vap;
        perfuse_msg_t *pm;
+       enum perfuse_xchg_pb_reply reply;
        struct fuse_write_in *fwi;
        struct fuse_write_out *fwo;
        size_t data_len;
        size_t payload_len;
@@ -3039,8 +3049,9 @@
        int error;
        
        ps = puffs_getspecific(pu);
        pnd = PERFUSE_NODE_DATA(opc);
+       reply = (ioflag & PUFFS_IO_FAF) ? no_reply : wait_reply;
        vap = puffs_pn_getvap((struct puffs_node *)opc);
        written = 0;
        inresize = 0;
        error = 0;
@@ -3125,9 +3136,9 @@
                                "fh = 0x%"PRIx64"\n", __func__, 
                                (void *)opc, pnd->pnd_nodeid, fwi->fh);
 #endif
                if ((error = xchg_msg(pu, opc, pm, 
-                                     sizeof(*fwo), wait_reply)) != 0)
+                                     sizeof(*fwo), reply)) != 0)
                        goto out;
 
                fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out);
                written = fwo->size;
@@ -3139,9 +3150,10 @@
                *resid -= written;
                offset += written;
                buf += written;
 
-               ps->ps_destroy_msg(pm);
+               if (reply != no_reply)
+                       ps->ps_destroy_msg(pm);
        } while (*resid != 0);
 
        /* 
         * puffs_ops(3) says
Index: lib/libperfuse/perfuse.c
===================================================================
RCS file: /cvsroot/src/lib/libperfuse/perfuse.c,v
retrieving revision 1.28
diff -U4 -r1.28 perfuse.c
--- lib/libperfuse/perfuse.c    18 Apr 2012 00:57:22 -0000      1.28
+++ lib/libperfuse/perfuse.c    5 Jun 2012 12:35:23 -0000
@@ -557,8 +557,10 @@
        ps->ps_get_outhdr = pc->pc_get_outhdr;
        ps->ps_get_outpayload = pc->pc_get_outpayload;
        ps->ps_umount = pc->pc_umount;
 
+       pc->pc_fsreq = *perfuse_fsreq;
+
        return pu;
 } 
 
 void
@@ -626,4 +628,31 @@
        ps = puffs_getspecific(pu);
 
        return unmount(ps->ps_target, MNT_FORCE);
 }
+
+
+void
+perfuse_fsreq(struct puffs_usermount *pu, perfuse_msg_t *pm)
+{
+       struct perfuse_state *ps;
+       struct fuse_out_header *foh;
+
+       ps = puffs_getspecific(pu);
+       foh = GET_OUTHDR(ps, pm);
+
+       /*
+        * There are some operations we may use in a  Fire and Forget wey,
+        * because the kernel does not await a reply, but FUSE still 
+        * sends a reply. This happens for fsyc, setattr (for metadata
+        * associated with a fsync) and write (for VOP_PUTPAGES). Ignore 
+        * if it was fine, abort otherwise.
+        */
+       if (foh->error != 0)
+               DERRX(EX_SOFTWARE,
+                     "Unexpected frame: unique = %"PRId64", error = %d", 
+                     foh->unique, foh->error);
+
+       ps->ps_destroy_msg(pm);
+
+       return; 
+}
Index: lib/libperfuse/perfuse_if.h
===================================================================
RCS file: /cvsroot/src/lib/libperfuse/perfuse_if.h,v
retrieving revision 1.18
diff -U4 -r1.18 perfuse_if.h
--- lib/libperfuse/perfuse_if.h 28 Dec 2011 17:33:53 -0000      1.18
+++ lib/libperfuse/perfuse_if.h 5 Jun 2012 12:35:23 -0000
@@ -113,9 +113,9 @@
 /*
  * frame handling callbacks
  */
 #ifndef PEFUSE_MSG_T
-#define PEFUSE_MSG_T struct perfuse_framebuf
+#define PEFUSE_MSG_T struct puffs_framebuf
 #endif
 typedef PEFUSE_MSG_T perfuse_msg_t;
 
 #define PERFUSE_UNSPEC_REPLY_LEN (size_t)-1
@@ -130,8 +130,9 @@
 typedef struct fuse_in_header *(*perfuse_get_inhdr_fn)(perfuse_msg_t *);
 typedef char *(*perfuse_get_inpayload_fn)(perfuse_msg_t *);
 typedef char *(*perfuse_get_outpayload_fn)(perfuse_msg_t *);
 typedef void (*perfuse_umount_fn)(struct puffs_usermount *);
+typedef void (*perfuse_fsreq_fn)(struct puffs_usermount *, perfuse_msg_t *);
 
 struct perfuse_callbacks {
        perfuse_new_msg_fn pc_new_msg;
        perfuse_xchg_msg_fn pc_xchg_msg;
@@ -140,8 +141,10 @@
        perfuse_get_inpayload_fn pc_get_inpayload;
        perfuse_get_outhdr_fn pc_get_outhdr;
        perfuse_get_outpayload_fn pc_get_outpayload;
        perfuse_umount_fn pc_umount;
+       perfuse_fsreq_fn pc_fsreq;
+       void *pc_reserved[16];
 };
 
 /* 
  * mount request
@@ -207,6 +210,7 @@
 void perfuse_fs_init(struct puffs_usermount *);
 int perfuse_mainloop(struct puffs_usermount *);
 int perfuse_unmount(struct puffs_usermount *);
 void perfuse_trace_dump(struct puffs_usermount *, FILE *);
+void perfuse_fsreq(struct puffs_usermount *, perfuse_msg_t *);
 
 #endif /* _PERFUSE_IF_H */
Index: lib/libperfuse/perfuse_priv.h
===================================================================
RCS file: /cvsroot/src/lib/libperfuse/perfuse_priv.h,v
retrieving revision 1.29
diff -U4 -r1.29 perfuse_priv.h
--- lib/libperfuse/perfuse_priv.h       18 Apr 2012 00:57:22 -0000      1.29
+++ lib/libperfuse/perfuse_priv.h       5 Jun 2012 12:35:23 -0000
@@ -258,9 +258,9 @@
     puffs_cookie_t, struct vattr *, const struct puffs_cred *,
     struct timespec *);
 int perfuse_node_setattr_ttl(struct puffs_usermount *,
     puffs_cookie_t, struct vattr *, const struct puffs_cred *,
-    struct timespec *);
+    struct timespec *, int);
 
 struct perfuse_trace *perfuse_trace_begin(struct perfuse_state *, 
     puffs_cookie_t, perfuse_msg_t *);
 void perfuse_trace_end(struct perfuse_state *, struct perfuse_trace *, int);
Index: lib/libpuffs/dispatcher.c
===================================================================
RCS file: /cvsroot/src/lib/libpuffs/dispatcher.c,v
retrieving revision 1.40
diff -U4 -r1.40 dispatcher.c
--- lib/libpuffs/dispatcher.c   18 Apr 2012 00:57:22 -0000      1.40
+++ lib/libpuffs/dispatcher.c   5 Jun 2012 12:35:23 -0000
@@ -466,16 +466,21 @@
                        struct puffs_vnmsg_setattr *auxt = auxbuf;
                        PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
 
                        if (PUFFS_USE_FS_TTL(pu)) {
+                               int flag = 0;
+
                                if (pops->puffs_node_setattr_ttl == NULL) {
                                        error = EOPNOTSUPP;
                                        break;
                                }
 
+                               if (PUFFSOP_WANTREPLY(preq->preq_opclass))
+                                       flag |= PUFFS_FSYNC_WAIT;
+
                                error = pops->puffs_node_setattr_ttl(pu,
                                    opcookie, &auxt->pvnr_va, pcr,
-                                   &auxt->pvnr_va_ttl);
+                                   &auxt->pvnr_va_ttl, flag);
                        } else {
                                if (pops->puffs_node_setattr == NULL) {
                                        error = EOPNOTSUPP;
                                        break;
@@ -910,19 +915,23 @@
 
                case PUFFS_VN_WRITE:
                {
                        struct puffs_vnmsg_write *auxt = auxbuf;
+                       int ioflag = auxt->pvnr_ioflag;
                        PUFFS_MAKECRED(pcr, &auxt->pvnr_cred);
 
                        if (pops->puffs_node_write == NULL) {
                                error = EIO;
                                break;
                        }
 
+                       if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
+                               ioflag |= PUFFS_IO_FAF;
+
                        error = pops->puffs_node_write(pu,
                            opcookie, auxt->pvnr_data,
                            auxt->pvnr_offset, &auxt->pvnr_resid,
-                           pcr, auxt->pvnr_ioflag);
+                           pcr, ioflag);
 
                        /* don't need to move data back to the kernel */
                        preq->preq_buflen = sizeof(struct puffs_vnmsg_write);
                        break;
Index: lib/libpuffs/puffs.h
===================================================================
RCS file: /cvsroot/src/lib/libpuffs/puffs.h,v
retrieving revision 1.121
diff -U4 -r1.121 puffs.h
--- lib/libpuffs/puffs.h        18 Apr 2012 00:57:22 -0000      1.121
+++ lib/libpuffs/puffs.h        5 Jun 2012 12:35:23 -0000
@@ -102,13 +102,15 @@
 #define PUFFS_VNOVAL (-1)
 
 #define PUFFS_IO_APPEND 0x020
 #define PUFFS_IO_NDELAY        0x100
+#define PUFFS_IO_FAF    0x08000
 
 #define PUFFS_VEXEC    01
 #define PUFFS_VWRITE   02
 #define PUFFS_VREAD    04
 
+#define PUFFS_FSYNC_WAIT     0x0001
 #define PUFFS_FSYNC_DATAONLY 0x0002
 #define PUFFS_FSYNC_CACHE    0x0100
 
 #define PUFFS_EXTATTR_LIST_LENPREFIX 1
@@ -237,9 +239,9 @@
            puffs_cookie_t, struct vattr *, const struct puffs_cred *,
            struct timespec *);
        int (*puffs_node_setattr_ttl)(struct puffs_usermount *,
            puffs_cookie_t, struct vattr *, const struct puffs_cred *,
-           struct timespec *);
+           struct timespec *, int flags);
 
        void *puffs_ops_spare[30];
 };
 
@@ -392,9 +394,9 @@
            puffs_cookie_t, struct vattr *, const struct puffs_cred *,  \
            struct timespec *);                                         \
        int fsname##_node_setattr_ttl(struct puffs_usermount *,         \
            puffs_cookie_t, struct vattr *, const struct puffs_cred *,  \
-           struct timespec *);
+           struct timespec *, int flags);
 
 
 #define PUFFSOP_INIT(ops)                                              \
     ops = malloc(sizeof(struct puffs_ops));                            \
Index: usr.sbin/perfused/perfused.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/perfused/perfused.c,v
retrieving revision 1.22
diff -U4 -r1.22 perfused.c
--- usr.sbin/perfused/perfused.c        4 Feb 2012 18:36:30 -0000       1.22
+++ usr.sbin/perfused/perfused.c        5 Jun 2012 12:35:23 -0000
@@ -244,21 +244,23 @@
 
        /*
         * Initialize libperfuse, which will initialize libpuffs
         */
+       (void)memset(&pc, 0, sizeof(pc));
        pc.pc_new_msg = perfused_new_pb;
        pc.pc_xchg_msg = perfused_xchg_pb;
        pc.pc_destroy_msg = (perfuse_destroy_msg_fn)puffs_framebuf_destroy;
        pc.pc_get_inhdr = perfused_get_inhdr;
        pc.pc_get_inpayload = perfused_get_inpayload;
        pc.pc_get_outhdr = perfused_get_outhdr;
        pc.pc_get_outpayload = perfused_get_outpayload;
        pc.pc_umount = perfused_umount;
+       pc.pc_fsreq = perfused_gotframe;
 
        pu = perfuse_init(&pc, &pmi);
-       
+
        puffs_framev_init(pu, perfused_readframe, perfused_writeframe, 
-                         perfused_cmpframe, perfused_gotframe, 
perfused_fdnotify);
+                         perfused_cmpframe, pc.pc_fsreq, perfused_fdnotify);
 
        if (puffs_framev_addfd(pu, fd, PUFFS_FBIO_READ|PUFFS_FBIO_WRITE) == -1)
                DERR(EX_SOFTWARE, "puffs_framev_addfd failed");
 


Home | Main Index | Thread Index | Old Index