svn commit: r345742 - projects/fuse2/sys/fs/fuse
Alan Somers
asomers at FreeBSD.org
Sun Mar 31 03:19:12 UTC 2019
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);
More information about the svn-src-projects
mailing list