Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 03 Sep 2019 14:06:02 -0000
From:      Alan Somers <asomers@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r345742 - projects/fuse2/sys/fs/fuse
Message-ID:  <201903310319.x2V3JAGH038626@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: asomers
Date: Sun Mar 31 03:19:10 2019
New Revision: 345742
URL: https://svnweb.freebsd.org/changeset/base/345742

Log:
  fusefs: replace the fufh table with a linked list
  
  The FUSE protocol allows each open file descriptor to have a unique file
  handle.  On FreeBSD, these file handles must all be stored in the vnode.
  The old method (also used by OSX and OpenBSD) is to store them all in a
  small array.  But that limits the total number that can be stored.  This
  commit replaces the array with a linked list (a technique also used by
  Illumos).  There is not yet any change in functionality, but this is the
  first step to fixing several bugs.
  
  PR:		236329, 236340, 236381, 236560, 236844
  Discussed with:	cem
  Sponsored by:	The FreeBSD Foundation

Modified:
  projects/fuse2/sys/fs/fuse/fuse_file.c
  projects/fuse2/sys/fs/fuse/fuse_file.h
  projects/fuse2/sys/fs/fuse/fuse_internal.c
  projects/fuse2/sys/fs/fuse/fuse_node.c
  projects/fuse2/sys/fs/fuse/fuse_node.h
  projects/fuse2/sys/fs/fuse/fuse_vnops.c

Modified: projects/fuse2/sys/fs/fuse/fuse_file.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_file.c	Sat Mar 30 23:43:58 2019	(r345741)
+++ projects/fuse2/sys/fs/fuse/fuse_file.c	Sun Mar 31 03:19:10 2019	(r345742)
@@ -82,6 +82,8 @@ __FBSDID("$FreeBSD$");
 #include "fuse_ipc.h"
 #include "fuse_node.h"
 
+MALLOC_DEFINE(M_FUSE_FILEHANDLE, "fuse_filefilehandle", "FUSE file handle");
+
 SDT_PROVIDER_DECLARE(fuse);
 /* 
  * Fuse trace probe:
@@ -157,16 +159,14 @@ fuse_filehandle_close(struct vnode *vp, fufh_type_t fu
 {
 	struct fuse_dispatcher fdi;
 	struct fuse_release_in *fri;
-	struct fuse_vnode_data *fvdat = VTOFUD(vp);
 	struct fuse_filehandle *fufh = NULL;
 
 	int err = 0;
 	int op = FUSE_RELEASE;
 
-	fufh = &(fvdat->fufh[fufh_type]);
-	if (!FUFH_IS_VALID(fufh)) {
-		panic("FUSE: filehandle_put called on invalid fufh (type=%d)",
-		    fufh_type);
+	if (fuse_filehandle_get(vp, fufh_type, &fufh)) {
+		panic("FUSE: fuse_filehandle_close called on invalid fufh "
+		    "(type=%d)", fufh_type);
 		/* NOTREACHED */
 	}
 	if (fuse_isdeadfs(vp)) {
@@ -185,8 +185,8 @@ fuse_filehandle_close(struct vnode *vp, fufh_type_t fu
 
 out:
 	atomic_subtract_acq_int(&fuse_fh_count, 1);
-	fufh->fh_id = (uint64_t)-1;
-	fufh->fh_type = FUFH_INVALID;
+	LIST_REMOVE(fufh, next);
+	free(fufh, M_FUSE_FILEHANDLE);
 
 	return err;
 }
@@ -194,31 +194,22 @@ out:
 int
 fuse_filehandle_valid(struct vnode *vp, fufh_type_t fufh_type)
 {
-	struct fuse_vnode_data *fvdat = VTOFUD(vp);
-	struct fuse_filehandle *fufh;
-
-	fufh = &(fvdat->fufh[fufh_type]);
-	return FUFH_IS_VALID(fufh);
+	return (0 == fuse_filehandle_get(vp, fufh_type, NULL));
 }
 
 /*
  * Check for a valid file handle, first the type requested, but if that
  * isn't valid, try for FUFH_RDWR.
  * Return the FUFH type that is valid or FUFH_INVALID if there are none.
- * This is a variant of fuse_filehandle_vaild() analogous to
+ * This is a variant of fuse_filehandle_valid() analogous to
  * fuse_filehandle_getrw().
  */
 fufh_type_t
 fuse_filehandle_validrw(struct vnode *vp, fufh_type_t fufh_type)
 {
-	struct fuse_vnode_data *fvdat = VTOFUD(vp);
-	struct fuse_filehandle *fufh;
-
-	fufh = &fvdat->fufh[fufh_type];
-	if (FUFH_IS_VALID(fufh) != 0)
+	if (fuse_filehandle_get(vp, fufh_type, NULL) == 0)
 		return (fufh_type);
-	fufh = &fvdat->fufh[FUFH_RDWR];
-	if (FUFH_IS_VALID(fufh) != 0)
+	if (fuse_filehandle_get(vp, FUFH_RDWR, NULL) == 0)
 		return (FUFH_RDWR);
 	return (FUFH_INVALID);
 }
@@ -230,8 +221,14 @@ fuse_filehandle_get(struct vnode *vp, fufh_type_t fufh
 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
 	struct fuse_filehandle *fufh;
 
-	fufh = &(fvdat->fufh[fufh_type]);
-	if (!FUFH_IS_VALID(fufh))
+	/* TODO: Find a list entry with the same mode, pid, gid, and uid */
+	/* Fallback: find a list entry with the right mode */
+	LIST_FOREACH(fufh, &fvdat->handles, next) {
+		if (fufh->mode == fufh_type)
+			break;
+	}
+
+	if (fufh == NULL)
 		return EBADF;
 	if (fufhp != NULL)
 		*fufhp = fufh;
@@ -242,14 +239,12 @@ int
 fuse_filehandle_getrw(struct vnode *vp, fufh_type_t fufh_type,
     struct fuse_filehandle **fufhp)
 {
-	struct fuse_vnode_data *fvdat = VTOFUD(vp);
-	struct fuse_filehandle *fufh;
+	int err;
 
-	fufh = &(fvdat->fufh[fufh_type]);
-	if (!FUFH_IS_VALID(fufh)) {
-		fufh_type = FUFH_RDWR;
-	}
-	return fuse_filehandle_get(vp, fufh_type, fufhp);
+	err = fuse_filehandle_get(vp, fufh_type, fufhp);
+	if (err)
+		err = fuse_filehandle_get(vp, FUFH_RDWR, fufhp);
+	return err;
 }
 
 void
@@ -259,13 +254,16 @@ fuse_filehandle_init(struct vnode *vp, fufh_type_t fuf
 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
 	struct fuse_filehandle *fufh;
 
-	fufh = &(fvdat->fufh[fufh_type]);
-	MPASS(!FUFH_IS_VALID(fufh));
+	fufh = malloc(sizeof(struct fuse_filehandle), M_FUSE_FILEHANDLE,
+		M_WAITOK);
+	MPASS(fufh != NULL);
 	fufh->fh_id = fh_id;
-	fufh->fh_type = fufh_type;
+	fufh->mode = fufh_type;
+	/* TODO: initialize fufh credentials and open flags */
 	if (!FUFH_IS_VALID(fufh)) {
 		panic("FUSE: init: invalid filehandle id (type=%d)", fufh_type);
 	}
+	LIST_INSERT_HEAD(&fvdat->handles, fufh, next);
 	if (fufhp != NULL)
 		*fufhp = fufh;
 

Modified: projects/fuse2/sys/fs/fuse/fuse_file.h
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_file.h	Sat Mar 30 23:43:58 2019	(r345741)
+++ projects/fuse2/sys/fs/fuse/fuse_file.h	Sun Mar 31 03:19:10 2019	(r345742)
@@ -78,11 +78,24 @@ _Static_assert(FUFH_WRONLY == O_WRONLY, "WRONLY");
 _Static_assert(FUFH_RDWR == O_RDWR, "RDWR");
 
 struct fuse_filehandle {
+	LIST_ENTRY(fuse_filehandle) next;
+
+	/* The filehandle returned by FUSE_OPEN */
 	uint64_t fh_id;
-	fufh_type_t fh_type;
+
+	/* flags returned by FUSE_OPEN */
+	uint32_t fuse_open_flags;
+
+	/* The mode used to open(2) the file (using O_RDONLY, not FREAD) */
+	uint32_t mode;
+
+	/* Credentials used to open the file */
+	gid_t gid;
+	pid_t pid;
+	uid_t uid;
 };
 
-#define FUFH_IS_VALID(f)  ((f)->fh_type != FUFH_INVALID)
+#define FUFH_IS_VALID(f)  ((f)->mode != FUFH_INVALID)
 
 static inline fufh_type_t
 fuse_filehandle_xlate_from_fflags(int fflags)

Modified: projects/fuse2/sys/fs/fuse/fuse_internal.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_internal.c	Sat Mar 30 23:43:58 2019	(r345741)
+++ projects/fuse2/sys/fs/fuse/fuse_internal.c	Sun Mar 31 03:19:10 2019	(r345742)
@@ -285,7 +285,6 @@ fuse_internal_fsync(struct vnode *vp,
 	struct fuse_fsync_in *ffsi;
 	struct fuse_dispatcher fdi;
 	struct fuse_filehandle *fufh;
-	struct fuse_vnode_data *fvdat = VTOFUD(vp);
 	int op = FUSE_FSYNC;
 	int type = 0;
 	int err = 0;
@@ -295,8 +294,7 @@ fuse_internal_fsync(struct vnode *vp,
 		return 0;
 	}
 	for (type = 0; type < FUFH_MAXTYPE; type++) {
-		fufh = &(fvdat->fufh[type]);
-		if (FUFH_IS_VALID(fufh)) {
+		if (fuse_filehandle_get(vp, type, &fufh) == 0) {
 			if (vnode_isdir(vp)) {
 				op = FUSE_FSYNCDIR;
 			}
@@ -454,11 +452,7 @@ fuse_internal_remove(struct vnode *dvp,
     enum fuse_opcode op)
 {
 	struct fuse_dispatcher fdi;
-	struct fuse_vnode_data *fvdat;
-	int err;
-
-	err = 0;
-	fvdat = VTOFUD(vp);
+	int err = 0;
 
 	fdisp_init(&fdi, cnp->cn_namelen + 1);
 	fdisp_make_vp(&fdi, op, dvp, cnp->cn_thread, cnp->cn_cred);

Modified: projects/fuse2/sys/fs/fuse/fuse_node.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_node.c	Sat Mar 30 23:43:58 2019	(r345741)
+++ projects/fuse2/sys/fs/fuse/fuse_node.c	Sun Mar 31 03:19:10 2019	(r345742)
@@ -174,9 +174,8 @@ static void
 fuse_vnode_init(struct vnode *vp, struct fuse_vnode_data *fvdat,
     uint64_t nodeid, enum vtype vtyp)
 {
-	int i;
-
 	fvdat->nid = nodeid;
+	LIST_INIT(&fvdat->handles);
 	vattr_null(&fvdat->cached_attrs);
 	if (nodeid == FUSE_ROOT_ID) {
 		vp->v_vflag |= VV_ROOT;
@@ -184,9 +183,6 @@ fuse_vnode_init(struct vnode *vp, struct fuse_vnode_da
 	vp->v_type = vtyp;
 	vp->v_data = fvdat;
 
-	for (i = 0; i < FUFH_MAXTYPE; i++)
-		fvdat->fufh[i].fh_type = FUFH_INVALID;
-
 	atomic_add_acq_int(&fuse_node_count, 1);
 }
 
@@ -196,6 +192,8 @@ fuse_vnode_destroy(struct vnode *vp)
 	struct fuse_vnode_data *fvdat = vp->v_data;
 
 	vp->v_data = NULL;
+	KASSERT(LIST_EMPTY(&fvdat->handles),
+		("Destroying fuse vnode with open files!"));
 	free(fvdat, M_FUSEVN);
 
 	atomic_subtract_acq_int(&fuse_node_count, 1);
@@ -314,7 +312,7 @@ void
 fuse_vnode_open(struct vnode *vp, int32_t fuse_open_flags, struct thread *td)
 {
 	/*
-	 * Funcation is called for every vnode open.
+	 * Function is called for every vnode open.
 	 * Merge fuse_open_flags it may be 0
 	 */
 	/*

Modified: projects/fuse2/sys/fs/fuse/fuse_node.h
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_node.h	Sat Mar 30 23:43:58 2019	(r345741)
+++ projects/fuse2/sys/fs/fuse/fuse_node.h	Sun Mar 31 03:19:10 2019	(r345742)
@@ -80,7 +80,8 @@ struct fuse_vnode_data {
 	uint64_t	parent_nid;
 
 	/** I/O **/
-	struct		fuse_filehandle fufh[FUFH_MAXTYPE];
+	/* List of file data for each of the vnode's open file descriptors */
+	LIST_HEAD(, fuse_filehandle)	handles;
 
 	/** flags **/
 	uint32_t	flag;

Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_vnops.c	Sat Mar 30 23:43:58 2019	(r345741)
+++ projects/fuse2/sys/fs/fuse/fuse_vnops.c	Sun Mar 31 03:19:10 2019	(r345742)
@@ -606,8 +606,7 @@ fuse_vnop_inactive(struct vop_inactive_args *ap)
 	int type, need_flush = 1;
 
 	for (type = 0; type < FUFH_MAXTYPE; type++) {
-		fufh = &(fvdat->fufh[type]);
-		if (FUFH_IS_VALID(fufh)) {
+		if (!fuse_filehandle_get(vp, type, &fufh)) {
 			if (need_flush && vp->v_type == VREG) {
 				if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
 					fuse_vnode_savesize(vp, NULL);
@@ -1396,7 +1395,6 @@ fuse_vnop_reclaim(struct vop_reclaim_args *ap)
 	struct thread *td = ap->a_td;
 
 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
-	struct fuse_filehandle *fufh = NULL;
 
 	int type;
 
@@ -1404,8 +1402,7 @@ fuse_vnop_reclaim(struct vop_reclaim_args *ap)
 		panic("FUSE: no vnode data during recycling");
 	}
 	for (type = 0; type < FUFH_MAXTYPE; type++) {
-		fufh = &(fvdat->fufh[type]);
-		if (FUFH_IS_VALID(fufh)) {
+		if (fuse_filehandle_get(vp, type, NULL) == 0) {
 			printf("FUSE: vnode being reclaimed but fufh (type=%d) is valid",
 			    type);
 			fuse_filehandle_close(vp, type, td, NULL);





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903310319.x2V3JAGH038626>