tech-kern archive

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

[PATCH] GOP_ALLOC and fallocate for PUFFS



Hello

When a PUFFS filesystem uses the page cache, data enters the
cache with no guarantee it will be flushed. If it cannot be flushed
(bcause PUFFS write requests get EDQUOT or ENOSPC), then the
kernel will loop forever trying to flush data from the cache,
and the filesystem cannot be unmounted without -f (and data loss).

In the attached patch, I add in PUFFS:
- support for the fallocate operation 
- a puffs_gop_alloe() function that use fallocate
- when writing through the page cache we call first GOP_ALLOC to make
  sure backend storage is allocated for the data we cache. debug printf
  show a sane behavior, GOP_ALLOC calling puffs_gop_alloc only when required.

If the filesystem does not implement fallocate, we keep the current 
behavior of filling the page cache with data we are not sure we can flush. 
Perhaps we can improve further: missing fallocate can be emulated by 
writing zeroed chuncks. I have implemented that in libperfuse, but 
we may want to have this in libpuffs, enabled by a mount option. Input
welcome.

-- 
Emmanuel Dreyfus
manu%netbsd.org@localhost
Index: lib/libpuffs/dispatcher.c
===================================================================
RCS file: /cvsroot/src/lib/libpuffs/dispatcher.c,v
retrieving revision 1.46.4.1
diff -U4 -r1.46.4.1 dispatcher.c
--- lib/libpuffs/dispatcher.c	24 Aug 2014 08:42:06 -0000	1.46.4.1
+++ lib/libpuffs/dispatcher.c	30 Sep 2014 09:40:28 -0000
@@ -1139,8 +1139,22 @@
 			    auxt->pvnr_attrname, pcr);
 			break;
 		}
 
+		case PUFFS_VN_FALLOCATE:
+		{
+			struct puffs_vnmsg_fallocate *auxt = auxbuf;
+
+			if (pops->puffs_node_fallocate == NULL) {
+				error = EOPNOTSUPP;
+				break;
+			}
+
+			error = pops->puffs_node_fallocate(pu,
+			    opcookie, auxt->pvnr_off, auxt->pvnr_len);
+			break;
+		}
+
 		default:
 			printf("inval op %d\n", preq->preq_optype);
 			error = EINVAL;
 			break;
Index: lib/libpuffs/opdump.c
===================================================================
RCS file: /cvsroot/src/lib/libpuffs/opdump.c,v
retrieving revision 1.36
diff -U4 -r1.36 opdump.c
--- lib/libpuffs/opdump.c	15 Mar 2012 02:02:21 -0000	1.36
+++ lib/libpuffs/opdump.c	30 Sep 2014 09:40:28 -0000
@@ -116,8 +116,9 @@
 	"PUFFS_VN_OPENEXTATTR",
 	"PUFFS_VN_DELETEEXTATTR",
 	"PUFFS_VN_SETEXTATTR",
 	"PUFFS_VN_CLOSEEXTATTR",
+	"PUFFS_VN_FALLOCATE",
 };
 size_t puffsdump_vnop_count = __arraycount(puffsdump_vnop_revmap);
 
 /* XXX! */
Index: lib/libpuffs/puffs.c
===================================================================
RCS file: /cvsroot/src/lib/libpuffs/puffs.c,v
retrieving revision 1.117
diff -U4 -r1.117 puffs.c
--- lib/libpuffs/puffs.c	14 Nov 2011 01:27:42 -0000	1.117
+++ lib/libpuffs/puffs.c	30 Sep 2014 09:40:28 -0000
@@ -105,8 +105,9 @@
 	FILLOP(getextattr,  GETEXTATTR);
 	FILLOP(setextattr,  SETEXTATTR);
 	FILLOP(listextattr, LISTEXTATTR);
 	FILLOP(deleteextattr, DELETEEXTATTR);
+	FILLOP(fallocate, FALLOCATE);
 }
 #undef FILLOP
 
 /*
Index: lib/libpuffs/puffs.h
===================================================================
RCS file: /cvsroot/src/lib/libpuffs/puffs.h,v
retrieving revision 1.124.10.1
diff -U4 -r1.124.10.1 puffs.h
--- lib/libpuffs/puffs.h	24 Aug 2014 08:42:06 -0000	1.124.10.1
+++ lib/libpuffs/puffs.h	30 Sep 2014 09:40:28 -0000
@@ -251,10 +251,12 @@
 	int (*puffs_node_reclaim2)(struct puffs_usermount *,
 	    puffs_cookie_t, int);
 	int (*puffs_node_open2)(struct puffs_usermount *,
 	    puffs_cookie_t, int, const struct puffs_cred *, int *);
+	int (*puffs_node_fallocate)(struct puffs_usermount *,
+	    puffs_cookie_t, off_t, off_t);
 
-	void *puffs_ops_spare[28];
+	void *puffs_ops_spare[27];
 };
 
 typedef	int (*pu_pathbuild_fn)(struct puffs_usermount *,
 			       const struct puffs_pathobj *,
@@ -413,9 +415,11 @@
 	    const struct puffs_cred *, int, int);			\
 	int fsname##_node_reclaim2(struct puffs_usermount *,		\
 	    puffs_cookie_t, int);					\
 	int fsname##_node_open2(struct puffs_usermount *,		\
-	    puffs_cookie_t, int, const struct puffs_cred *, int *);
+	    puffs_cookie_t, int, const struct puffs_cred *, int *);	\
+	int fsname##_node_fallocate(struct puffs_usermount *,		\
+	    puffs_cookie_t, int, off_t, off_t);
 
 
 #define PUFFSOP_INIT(ops)						\
     ops = malloc(sizeof(struct puffs_ops));				\
? sys/fs/puffs/diff
? sys/fs/puffs/ndiff
? sys/fs/puffs/out
Index: sys/fs/puffs/puffs_msgif.h
===================================================================
RCS file: /cvsroot/src/sys/fs/puffs/puffs_msgif.h,v
retrieving revision 1.80.14.1
diff -U 4 -r1.80.14.1 puffs_msgif.h
--- sys/fs/puffs/puffs_msgif.h	26 Aug 2014 23:15:12 -0000	1.80.14.1
+++ sys/fs/puffs/puffs_msgif.h	30 Sep 2014 13:36:52 -0000
@@ -85,13 +85,13 @@
 	PUFFS_VN_PRINT,		PUFFS_VN_ISLOCKED,	PUFFS_VN_PATHCONF,
 	PUFFS_VN_ADVLOCK,	PUFFS_VN_LEASE,		PUFFS_VN_WHITEOUT,
 	PUFFS_VN_GETPAGES,	PUFFS_VN_PUTPAGES,	PUFFS_VN_GETEXTATTR,
 	PUFFS_VN_LISTEXTATTR,	PUFFS_VN_OPENEXTATTR,	PUFFS_VN_DELETEEXTATTR,
-	PUFFS_VN_SETEXTATTR,	PUFFS_VN_CLOSEEXTATTR
+	PUFFS_VN_SETEXTATTR,	PUFFS_VN_CLOSEEXTATTR,	PUFFS_VN_FALLOCATE,
 	/* NOTE: If you add an op, decrement PUFFS_VN_SPARE accordingly */
 };
 #define PUFFS_VN_MAX PUFFS_VN_CLOSEEXTATTR
-#define PUFFS_VN_SPARE 32
+#define PUFFS_VN_SPARE 31
 
 /*
  * These signal invalid parameters the file system returned.
  */
@@ -665,8 +665,14 @@
 
 	struct puffs_kcred	pvnr_cred;			/* OUT	*/
 };
 
+struct puffs_vnmsg_fallocate {
+	struct puffs_req	pvn_pr;
+	off_t			pvnr_off;			/* OUT    */
+	off_t			pvnr_len;			/* OUT    */
+};
+
 /*
  * For cache reports.  Everything is always out-out-out, no replies
  */
 
Index: sys/fs/puffs/puffs_subr.c
===================================================================
RCS file: /cvsroot/src/sys/fs/puffs/puffs_subr.c,v
retrieving revision 1.66
diff -U 4 -r1.66 puffs_subr.c
--- sys/fs/puffs/puffs_subr.c	16 Nov 2008 19:34:30 -0000	1.66
+++ sys/fs/puffs/puffs_subr.c	30 Sep 2014 13:36:52 -0000
@@ -197,8 +197,15 @@
 
 	puffs_updatenode(VPTOPP(vp), uflags, 0);
 }
 
+int
+puffs_gop_alloc(struct vnode *vp, off_t off, off_t len,
+		int flags, kauth_cred_t cred)
+{
+	return _puffs_vnop_fallocate(vp, off, len);
+}
+
 void
 puffs_senderr(struct puffs_mount *pmp, int type, int error,
 	const char *str, puffs_cookie_t ck)
 {
Index: sys/fs/puffs/puffs_sys.h
===================================================================
RCS file: /cvsroot/src/sys/fs/puffs/puffs_sys.h,v
retrieving revision 1.84.4.2
diff -U 4 -r1.84.4.2 puffs_sys.h
--- sys/fs/puffs/puffs_sys.h	29 Aug 2014 11:55:34 -0000	1.84.4.2
+++ sys/fs/puffs/puffs_sys.h	30 Sep 2014 13:36:52 -0000
@@ -279,8 +279,10 @@
 void	puffs_mp_release(struct puffs_mount *);
 
 void	puffs_gop_size(struct vnode *, off_t, off_t *, int); 
 void	puffs_gop_markupdate(struct vnode *, int);
+int	puffs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t);
+int	_puffs_vnop_fallocate(struct vnode *, off_t, off_t);
 
 void	puffs_senderr(struct puffs_mount *, int, int, const char *,
 		      puffs_cookie_t);
 
Index: sys/fs/puffs/puffs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/puffs/puffs_vfsops.c,v
retrieving revision 1.113.2.1
diff -U 4 -r1.113.2.1 puffs_vfsops.c
--- sys/fs/puffs/puffs_vfsops.c	29 Aug 2014 11:55:34 -0000	1.113.2.1
+++ sys/fs/puffs/puffs_vfsops.c	30 Sep 2014 13:36:52 -0000
@@ -73,11 +73,9 @@
 static const struct genfs_ops puffs_genfsops = {
         .gop_size = puffs_gop_size,
 	.gop_write = genfs_gop_write,
 	.gop_markupdate = puffs_gop_markupdate,
-#if 0
-	.gop_alloc, should ask userspace
-#endif
+	.gop_alloc = puffs_gop_alloc,
 };
 
 /*
  * Try to ensure data structures used by the puffs protocol
Index: sys/fs/puffs/puffs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/puffs/puffs_vnops.c,v
retrieving revision 1.182.2.4
diff -U 4 -r1.182.2.4 puffs_vnops.c
--- sys/fs/puffs/puffs_vnops.c	11 Sep 2014 14:00:54 -0000	1.182.2.4
+++ sys/fs/puffs/puffs_vnops.c	30 Sep 2014 13:36:53 -0000
@@ -72,8 +72,9 @@
 int	puffs_vnop_symlink(void *);
 int	puffs_vnop_rename(void *);
 int	puffs_vnop_read(void *);
 int	puffs_vnop_write(void *);
+int	puffs_vnop_fallocate(void *);
 int	puffs_vnop_fcntl(void *);
 int	puffs_vnop_ioctl(void *);
 int	puffs_vnop_inactive(void *);
 int	puffs_vnop_print(void *);
@@ -112,9 +113,9 @@
         { &vop_getattr_desc, puffs_vnop_checkop },	/* getattr */
         { &vop_setattr_desc, puffs_vnop_checkop },	/* setattr */
         { &vop_read_desc, puffs_vnop_checkop },		/* read */
         { &vop_write_desc, puffs_vnop_checkop },	/* write */
-	{ &vop_fallocate_desc, genfs_eopnotsupp },	/* fallocate */
+	{ &vop_fallocate_desc, puffs_vnop_fallocate },	/* fallocate */
 	{ &vop_fdiscard_desc, genfs_eopnotsupp },	/* fdiscard */
         { &vop_fsync_desc, puffs_vnop_fsync },		/* REAL fsync */
         { &vop_seek_desc, puffs_vnop_checkop },		/* seek */
         { &vop_remove_desc, puffs_vnop_checkop },	/* remove */
@@ -2330,8 +2331,24 @@
 		if (ap->a_ioflag & IO_APPEND)
 			uio->uio_offset = vp->v_size;
 
 		origoff = uio->uio_offset;
+
+		/*
+		 * Attempt to allocate storage so that we do not
+		 * feed the page cache with data we cannot flush 
+		 * later. If we get EOPNOTSUPP it means FALLOCATE
+		 * is unimplemented in the filesystem: in that 
+		 * case we cary on without any guarantee that the
+		 * data we cache will be flushable
+		 */
+		error = GOP_ALLOC(vp, origoff, uio->uio_resid,
+				  0, curlwp->l_cred);
+		if (error == EOPNOTSUPP)
+			error = 0;
+		else
+			goto out;
+
 		while (uio->uio_resid > 0) {
 			oldoff = uio->uio_offset;
 			bytelen = uio->uio_resid;
 
@@ -2444,9 +2461,62 @@
 	uflags |= PUFFS_UPDATECTIME;
 	uflags |= PUFFS_UPDATEMTIME;
 	puffs_updatenode(VPTOPP(vp), uflags, vp->v_size);
 
+out:
+	mutex_exit(&pn->pn_sizemtx);
+	return error;
+}
+
+int
+_puffs_vnop_fallocate(struct vnode *vp, off_t pos, off_t len)
+{
+	PUFFS_MSG_VARS(vn, fallocate);
+	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
+	int error;
+
+	PUFFS_MSG_ALLOC(vn, fallocate);
+	fallocate_msg->pvnr_off = pos;
+	fallocate_msg->pvnr_len = len;
+	puffs_msg_setinfo(park_fallocate, PUFFSOP_VN,
+	    PUFFS_VN_FALLOCATE, VPTOPNC(vp));
+
+	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fallocate, vp->v_data,
+	    NULL, error);
+	error = checkerr(pmp, error, __func__);
+	PUFFS_MSG_RELEASE(fallocate);
+
+	return error;
+}
+
+int
+puffs_vnop_fallocate(void *v)
+{
+	struct vop_fallocate_args /* {
+		const struct vnodeop_desc *a_desc;
+		struct vnode *a_vp;
+		off_t a_pos;
+		off_t a_len;
+	} */ *ap = v;
+	struct vnode *vp = ap->a_vp;
+	struct puffs_node *pn = VPTOPP(vp);
+	int error;
+
+	mutex_enter(&pn->pn_sizemtx);
+	error = _puffs_vnop_fallocate(v, ap->a_pos, ap->a_len);
+	if (error) {
+		if (error == EAGAIN)
+			error = EIO;
+		goto out;
+	}
+
+	if (ap->a_pos + ap->a_len > vp->v_size) {
+		uvm_vnp_setsize(vp, ap->a_pos + ap->a_len);
+		puffs_updatenode(pn, PUFFS_UPDATESIZE, vp->v_size);
+	}
+out:
 	mutex_exit(&pn->pn_sizemtx);
+
 	return error;
 }
 
 int


Home | Main Index | Thread Index | Old Index