Fri Sep 3 07:15:18 2010 UTC ()
- Postpone file close at reclaim time, since NetBSD sends fsync and
setattr(mtime, ctime) after close, while FUSE expects the file
to be open for these operations

- remove unused argument to node_mk_common()

- remove requeued requests when they are executed, not when they
are tagged for schedule

- try to make filehandle management simplier, by keeping track of only
one read and one write filehandle (the latter being really read/write).

- when CREATE is not available, we use the MKNOD/OPEN path. Fix a
bug here where we opened the parent directory instead of the node:
add the missing lookup of the mknod'ed node.

- lookup file we just created: glusterfs does not really see them
otherwise.

- open file when doing setattr(mtime, ctime) on non open files, as
some filesystems seems to require it.

- Do not flush pagecache for removed nodes

- Keep track of read/write operations in progress, and at reclaim
time, make sure they are over before closing and forgeting the file.


(manu)
diff -r1.6 -r1.7 src/lib/libperfuse/ops.c
diff -r1.4 -r1.5 src/lib/libperfuse/perfuse_priv.h
diff -r1.3 -r1.4 src/lib/libperfuse/subr.c

cvs diff -r1.6 -r1.7 src/lib/libperfuse/ops.c (expand / switch to unified diff)

--- src/lib/libperfuse/ops.c 2010/09/02 08:58:06 1.6
+++ src/lib/libperfuse/ops.c 2010/09/03 07:15:18 1.7
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ops.c,v 1.6 2010/09/02 08:58:06 manu Exp $ */ 1/* $NetBSD: ops.c,v 1.7 2010/09/03 07:15:18 manu Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved. 4 * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
5 *  5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 *  14 *
@@ -31,26 +31,27 @@ @@ -31,26 +31,27 @@
31#include <libgen.h> 31#include <libgen.h>
32#include <errno.h> 32#include <errno.h>
33#include <err.h> 33#include <err.h>
34#include <sysexits.h> 34#include <sysexits.h>
35#include <syslog.h> 35#include <syslog.h>
36#include <puffs.h> 36#include <puffs.h>
37#include <sys/vnode.h> 37#include <sys/vnode.h>
38#include <sys/socket.h> 38#include <sys/socket.h>
39#include <machine/vmparam.h> 39#include <machine/vmparam.h>
40 40
41#include "perfuse_priv.h" 41#include "perfuse_priv.h"
42#include "fuse.h" 42#include "fuse.h"
43 43
 44static int node_close_common(struct puffs_usermount *, puffs_cookie_t, int);
44static int no_access(puffs_cookie_t, const struct puffs_cred *, mode_t); 45static int no_access(puffs_cookie_t, const struct puffs_cred *, mode_t);
45static void fuse_attr_to_vap(struct perfuse_state *, 46static void fuse_attr_to_vap(struct perfuse_state *,
46 struct vattr *, struct fuse_attr *); 47 struct vattr *, struct fuse_attr *);
47static int node_lookup_dir_nodot(struct puffs_usermount *, 48static int node_lookup_dir_nodot(struct puffs_usermount *,
48 puffs_cookie_t, char *, size_t, struct puffs_node **); 49 puffs_cookie_t, char *, size_t, struct puffs_node **);
49static int node_lookup_common(struct puffs_usermount *, puffs_cookie_t,  50static int node_lookup_common(struct puffs_usermount *, puffs_cookie_t,
50 const char*, struct puffs_node **); 51 const char*, struct puffs_node **);
51static int node_mk_common(struct puffs_usermount *, puffs_cookie_t, 52static int node_mk_common(struct puffs_usermount *, puffs_cookie_t,
52 struct puffs_newinfo *, const struct puffs_cn *pcn, perfuse_msg_t *); 53 struct puffs_newinfo *, const struct puffs_cn *pcn, perfuse_msg_t *);
53static const char *basename_r(const char *); 54static const char *basename_r(const char *);
54static ssize_t fuse_to_dirent(struct puffs_usermount *, puffs_cookie_t, 55static ssize_t fuse_to_dirent(struct puffs_usermount *, puffs_cookie_t,
55 struct fuse_dirent *, size_t); 56 struct fuse_dirent *, size_t);
56static int readdir_buffered(struct perfuse_state *, puffs_cookie_t, 57static int readdir_buffered(struct perfuse_state *, puffs_cookie_t,
@@ -64,42 +65,111 @@ static void dequeue_requests(struct perf @@ -64,42 +65,111 @@ static void dequeue_requests(struct perf
64 65
65/*  66/*
66 * From <sys/vnode>, inside #ifdef _KERNEL section 67 * From <sys/vnode>, inside #ifdef _KERNEL section
67 */ 68 */
68#define IO_SYNC (0x40|IO_DSYNC)  69#define IO_SYNC (0x40|IO_DSYNC)
69#define IO_DSYNC 0x00200  70#define IO_DSYNC 0x00200
70#define IO_DIRECT 0x02000 71#define IO_DIRECT 0x02000
71 72
72/*  73/*
73 * From <fcntl>, inside #ifdef _KERNEL section 74 * From <fcntl>, inside #ifdef _KERNEL section
74 */ 75 */
75#define F_WAIT 0x010 76#define F_WAIT 0x010
76#define F_FLOCK 0x020 77#define F_FLOCK 0x020
 78#define OFLAGS(fflags) ((fflags) - 1)
77 79
78/*  80/*
79 * Borrowed from src/sys/kern/vfs_subr.c and src/sys/sys/vnode.h  81 * Borrowed from src/sys/kern/vfs_subr.c and src/sys/sys/vnode.h
80 */ 82 */
81const enum vtype iftovt_tab[16] = {  83const enum vtype iftovt_tab[16] = {
82 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 84 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
83 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 85 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
84}; 86};
85const int vttoif_tab[9] = {  87const int vttoif_tab[9] = {
86 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 88 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK,
87 S_IFSOCK, S_IFIFO, S_IFMT, 89 S_IFSOCK, S_IFIFO, S_IFMT,
88};  90};
89 91
90#define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12]) 92#define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12])
91#define VTTOIF(indx) (vttoif_tab[(int)(indx)]) 93#define VTTOIF(indx) (vttoif_tab[(int)(indx)])
92 94
 95static int
 96node_close_common(pu, opc, mode)
 97 struct puffs_usermount *pu;
 98 puffs_cookie_t opc;
 99 int mode;
 100{
 101 struct perfuse_state *ps;
 102 perfuse_msg_t *pm;
 103 int op;
 104 uint64_t fh;
 105 struct fuse_release_in *fri;
 106 struct perfuse_node_data *pnd;
 107 struct puffs_node *pn;
 108 int error;
 109
 110 ps = puffs_getspecific(pu);
 111 pn = (struct puffs_node *)opc;
 112 pnd = PERFUSE_NODE_DATA(pn);
 113
 114 if (puffs_pn_getvap(pn)->va_type == VDIR) {
 115 op = FUSE_RELEASEDIR;
 116 mode = FREAD;
 117 } else {
 118 op = FUSE_RELEASE;
 119 }
 120
 121 /*
 122 * Destroy the filehandle before sending the
 123 * request to the FUSE filesystem, otherwise
 124 * we may get a second close() while we wait
 125 * for the reply, and we would end up closing
 126 * the same fh twice instead of closng both.
 127 */
 128 fh = perfuse_get_fh(opc, mode);
 129 perfuse_destroy_fh(pn, fh);
 130
 131 /*
 132 * release_flags may be set to FUSE_RELEASE_FLUSH
 133 * to flush locks. lock_owner must be set in that case
 134 */
 135 pm = ps->ps_new_msg(pu, opc, op, sizeof(*fri), NULL);
 136 fri = GET_INPAYLOAD(ps, pm, fuse_release_in);
 137 fri->fh = fh;
 138 fri->flags = 0;
 139 fri->release_flags = 0;
 140 fri->lock_owner = pnd->pnd_lock_owner;
 141 fri->flags = (fri->lock_owner != 0) ? FUSE_RELEASE_FLUSH : 0;
 142
 143#ifdef PERFUSE_DEBUG
 144 if (perfuse_diagflags & PDF_FH)
 145 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
 146 __func__, (void *)opc, pnd->pnd_ino, fri->fh);
 147#endif
 148
 149 if ((error = XCHG_MSG(ps, pu, pm, NO_PAYLOAD_REPLY_LEN)) != 0)
 150 goto out;
 151
 152 ps->ps_destroy_msg(pm);
 153
 154 error = 0;
 155
 156out:
 157 if (error != 0)
 158 DERRX(EX_SOFTWARE, "%s: freed fh = 0x%"PRIx64" but filesystem "
 159 "returned error = %d", __func__, fh, error);
 160
 161 return error;
 162}
93 163
94static int 164static int
95no_access(opc, pcr, mode) 165no_access(opc, pcr, mode)
96 puffs_cookie_t opc; 166 puffs_cookie_t opc;
97 const struct puffs_cred *pcr; 167 const struct puffs_cred *pcr;
98 mode_t mode; 168 mode_t mode;
99{ 169{
100 struct puffs_node *pn; 170 struct puffs_node *pn;
101 struct vattr *va; 171 struct vattr *va;
102 172
103 pn = (struct puffs_node *)opc; 173 pn = (struct puffs_node *)opc;
104 va = puffs_pn_getvap(pn); 174 va = puffs_pn_getvap(pn);
105 175
@@ -792,26 +862,39 @@ perfuse_fs_suspend(pu, status) @@ -792,26 +862,39 @@ perfuse_fs_suspend(pu, status)
792 862
793 863
794int 864int
795perfuse_node_lookup(pu, opc, pni, pcn) 865perfuse_node_lookup(pu, opc, pni, pcn)
796 struct puffs_usermount *pu; 866 struct puffs_usermount *pu;
797 puffs_cookie_t opc; 867 puffs_cookie_t opc;
798 struct puffs_newinfo *pni; 868 struct puffs_newinfo *pni;
799 const struct puffs_cn *pcn; 869 const struct puffs_cn *pcn;
800{ 870{
801 struct puffs_node *pn; 871 struct puffs_node *pn;
802 int error; 872 int error;
803  873
804 /* 874 /*
 875 * Special case for ..
 876 */
 877 if (PCNISDOTDOT(pcn)) {
 878 pn = PERFUSE_NODE_DATA(opc)->pnd_parent;
 879 PERFUSE_NODE_DATA(pn)->pnd_flags &= ~PND_RECLAIMED;
 880
 881 puffs_newinfo_setcookie(pni, pn);
 882 puffs_newinfo_setvtype(pni, VDIR);
 883
 884 return 0;
 885 }
 886
 887 /*
805 * XXX This is borrowed from librefuse,  888 * XXX This is borrowed from librefuse,
806 * and __UNCONST is said to be fixed. 889 * and __UNCONST is said to be fixed.
807 */ 890 */
808 pn = puffs_pn_nodewalk(pu, puffs_path_walkcmp, 891 pn = puffs_pn_nodewalk(pu, puffs_path_walkcmp,
809 __UNCONST(&pcn->pcn_po_full)); 892 __UNCONST(&pcn->pcn_po_full));
810 893
811 if (pn == NULL) { 894 if (pn == NULL) {
812 error = node_lookup_common(pu, opc, (char *)PCNPATH(pcn), &pn); 895 error = node_lookup_common(pu, opc, (char *)PCNPATH(pcn), &pn);
813 if (error != 0) 896 if (error != 0)
814 return error; 897 return error;
815 } 898 }
816 899
817 /* 900 /*
@@ -856,26 +939,32 @@ perfuse_node_create(pu, opc, pni, pcn, v @@ -856,26 +939,32 @@ perfuse_node_create(pu, opc, pni, pcn, v
856 * If create is unimplemented: Check that it does not 939 * If create is unimplemented: Check that it does not
857 * already exists, and if not, do mknod and open 940 * already exists, and if not, do mknod and open
858 */ 941 */
859 ps = puffs_getspecific(pu); 942 ps = puffs_getspecific(pu);
860 if (ps->ps_flags & PS_NO_CREAT) { 943 if (ps->ps_flags & PS_NO_CREAT) {
861 error = node_lookup_common(pu, opc, (char*)PCNPATH(pcn), &pn); 944 error = node_lookup_common(pu, opc, (char*)PCNPATH(pcn), &pn);
862 if (error == 0)  945 if (error == 0)
863 return EEXIST; 946 return EEXIST;
864 947
865 error = perfuse_node_mknod(pu, opc, pni, pcn, vap); 948 error = perfuse_node_mknod(pu, opc, pni, pcn, vap);
866 if (error != 0) 949 if (error != 0)
867 return error; 950 return error;
868 951
 952 error = node_lookup_common(pu, opc, (char*)PCNPATH(pcn), &pn);
 953 if (error != 0)
 954 return error;
 955
 956 opc = (puffs_cookie_t)pn;
 957
869 error = perfuse_node_open(pu, opc, FREAD|FWRITE, pcn->pcn_cred); 958 error = perfuse_node_open(pu, opc, FREAD|FWRITE, pcn->pcn_cred);
870 if (error != 0)  959 if (error != 0)
871 return error; 960 return error;
872 961
873 return 0; 962 return 0;
874 } 963 }
875 964
876 name = basename_r((char *)PCNPATH(pcn)); 965 name = basename_r((char *)PCNPATH(pcn));
877 namelen = strlen(name) + 1; 966 namelen = strlen(name) + 1;
878 len = sizeof(*fci) + namelen; 967 len = sizeof(*fci) + namelen;
879 968
880 pm = ps->ps_new_msg(pu, opc, FUSE_CREATE, len, pcn->pcn_cred); 969 pm = ps->ps_new_msg(pu, opc, FUSE_CREATE, len, pcn->pcn_cred);
881 fci = GET_INPAYLOAD(ps, pm, fuse_create_in); 970 fci = GET_INPAYLOAD(ps, pm, fuse_create_in);
@@ -888,32 +977,46 @@ perfuse_node_create(pu, opc, pni, pcn, v @@ -888,32 +977,46 @@ perfuse_node_create(pu, opc, pni, pcn, v
888 if ((error = XCHG_MSG(ps, pu, pm, len)) != 0) 977 if ((error = XCHG_MSG(ps, pu, pm, len)) != 0)
889 goto out; 978 goto out;
890 979
891 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 980 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
892 foo = (struct fuse_open_out *)(void *)(feo + 1); 981 foo = (struct fuse_open_out *)(void *)(feo + 1);
893 if (feo->nodeid == PERFUSE_UNKNOWN_INO) 982 if (feo->nodeid == PERFUSE_UNKNOWN_INO)
894 DERRX(EX_SOFTWARE, "%s: no ino", __func__); 983 DERRX(EX_SOFTWARE, "%s: no ino", __func__);
895  984
896 /* 985 /*
897 * Save the file handle and inode in node private data  986 * Save the file handle and inode in node private data
898 * so that we can reuse it later 987 * so that we can reuse it later
899 */ 988 */
900 pn = perfuse_new_pn(pu, opc); 989 pn = perfuse_new_pn(pu, opc);
901 perfuse_new_fh((puffs_cookie_t)pn, foo->fh); 990 perfuse_new_fh((puffs_cookie_t)pn, foo->fh, FWRITE);
902 PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid; 991 PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid;
903 992
 993#ifdef PERFUSE_DEBUG
 994 if (perfuse_diagflags & PDF_FH)
 995 DPRINTF("%s: opc = %p, file = \"%s\", "
 996 "ino = %"PRId64", rfh = 0x%"PRIx64"\n",
 997 __func__, (void *)pn, (char *)PCNPATH(pcn),
 998 feo->nodeid, foo->fh);
 999#endif
 1000
904 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 1001 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
905 puffs_newinfo_setcookie(pni, pn); 1002 puffs_newinfo_setcookie(pni, pn);
906 1003
 1004 /*
 1005 * It seems we need to do this so that glusterfs gets fully
 1006 * aware that the file was created. If we do not do it, we
 1007 * get "SETATTR (null) (fuse_loc_fill() failed)"
 1008 */
 1009 (void)node_lookup_common(pu, opc, (char*)PCNPATH(pcn), NULL);
907out:  1010out:
908 ps->ps_destroy_msg(pm); 1011 ps->ps_destroy_msg(pm);
909 1012
910 /* 1013 /*
911 * create is unimplmented, remember it for later, 1014 * create is unimplmented, remember it for later,
912 * and start over using mknod and open instead. 1015 * and start over using mknod and open instead.
913 */ 1016 */
914 if (error == ENOSYS) { 1017 if (error == ENOSYS) {
915 ps->ps_flags |= PS_NO_CREAT; 1018 ps->ps_flags |= PS_NO_CREAT;
916 return perfuse_node_create(pu, opc, pni, pcn, vap); 1019 return perfuse_node_create(pu, opc, pni, pcn, vap);
917 } 1020 }
918 1021
919 return error; 1022 return error;
@@ -969,205 +1072,154 @@ perfuse_node_mknod(pu, opc, pni, pcn, va @@ -969,205 +1072,154 @@ perfuse_node_mknod(pu, opc, pni, pcn, va
969 1072
970 return node_mk_common(pu, opc, pni, pcn, pm); 1073 return node_mk_common(pu, opc, pni, pcn, pm);
971} 1074}
972 1075
973 1076
974int 1077int
975perfuse_node_open(pu, opc, mode, pcr) 1078perfuse_node_open(pu, opc, mode, pcr)
976 struct puffs_usermount *pu; 1079 struct puffs_usermount *pu;
977 puffs_cookie_t opc; 1080 puffs_cookie_t opc;
978 int mode; 1081 int mode;
979 const struct puffs_cred *pcr; 1082 const struct puffs_cred *pcr;
980{ 1083{
981 struct perfuse_state *ps; 1084 struct perfuse_state *ps;
 1085 struct perfuse_node_data *pnd;
982 perfuse_msg_t *pm; 1086 perfuse_msg_t *pm;
983 mode_t pmode; 1087 mode_t pmode;
 1088 mode_t fmode;
984 int op; 1089 int op;
985 struct fuse_open_in *foi; 1090 struct fuse_open_in *foi;
986 struct fuse_open_out *foo; 1091 struct fuse_open_out *foo;
987 struct puffs_node *pn; 1092 struct puffs_node *pn;
988 int error; 1093 int error;
989  1094
990 ps = puffs_getspecific(pu); 1095 ps = puffs_getspecific(pu);
 1096 pnd = PERFUSE_NODE_DATA(opc);
991 1097
992 pn = (struct puffs_node *)opc; 1098 pn = (struct puffs_node *)opc;
993 if (puffs_pn_getvap(pn)->va_type == VDIR) { 1099 if (puffs_pn_getvap(pn)->va_type == VDIR) {
994 op = FUSE_OPENDIR; 1100 op = FUSE_OPENDIR;
995 pmode = PUFFS_VREAD|PUFFS_VEXEC; 1101 pmode = PUFFS_VREAD|PUFFS_VEXEC;
996 } else { 1102 } else {
997 op = FUSE_OPEN; 1103 op = FUSE_OPEN;
998 if (mode & (O_RDWR|O_WRONLY)) 1104 if (mode & FWRITE)
999 pmode = PUFFS_VWRITE; 1105 pmode = PUFFS_VWRITE|PUFFS_VREAD;
1000 else 1106 else
1001 pmode = PUFFS_VREAD; 1107 pmode = PUFFS_VREAD;
1002 } 1108 }
1003 1109
1004 /* 1110 /*
1005 * Opening a directory require R-X on the directory 1111 * Opening a directory require R-X on the directory
1006 * Opening a file requires R-- for reading, -W- for writing 1112 * Opening a file requires R-- for reading, -W- for writing
1007 * In both cases, --X is required on the parent. 1113 * In both cases, --X is required on the parent.
1008 */ 1114 */
1009 if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent, 1115 if (no_access((puffs_cookie_t)pnd->pnd_parent, pcr, PUFFS_VEXEC))
1010 pcr, PUFFS_VEXEC)) 
1011 return EACCES; 1116 return EACCES;
1012 1117
1013 if (no_access(opc, pcr, pmode)) 1118 if (no_access(opc, pcr, pmode))
1014 return EACCES; 1119 return EACCES;
1015 1120
1016 /* 1121 /*
1017 * libfuse docs say O_CREAT should not be set. 1122 * libfuse docs say O_CREAT should not be set.
1018 */ 1123 */
1019 mode &= ~O_CREAT; 1124 mode &= ~O_CREAT;
1020  1125
 1126 /*
 1127 * Do not open twice, and do not reopen for reading
 1128 * if we already have write handle.
 1129 * Directories are always open with read access only,
 1130 * whatever flags we get.
 1131 */
 1132 if (op == FUSE_OPENDIR)
 1133 mode = (mode & ~(FREAD|FWRITE)) | FREAD;
 1134 if ((mode & FREAD) && (pnd->pnd_flags & PND_RFH))
 1135 return 0;
 1136 if ((mode & FWRITE) && (pnd->pnd_flags & PND_WFH))
 1137 return 0;
 1138
 1139 /*
 1140 * Convert PUFFS mode to FUSE mode: convert FREAD/FWRITE
 1141 * to O_RDONLY/O_WRONLY while perserving the other options.
 1142 */
 1143 fmode = mode & ~(FREAD|FWRITE);
 1144 fmode |= (mode & FWRITE) ? O_RDWR : O_RDONLY;
 1145
1021 pm = ps->ps_new_msg(pu, opc, op, sizeof(*foi), pcr); 1146 pm = ps->ps_new_msg(pu, opc, op, sizeof(*foi), pcr);
1022 foi = GET_INPAYLOAD(ps, pm, fuse_open_in); 1147 foi = GET_INPAYLOAD(ps, pm, fuse_open_in);
1023 foi->flags = mode & ~O_ACCMODE;  1148 foi->flags = fmode;
1024 switch (mode & (FREAD|FWRITE)) { 
1025 case FREAD|FWRITE: 
1026 foi->flags |= O_RDWR; 
1027 break; 
1028 case FREAD: 
1029 foi->flags |= O_RDONLY; 
1030 break; 
1031 case FWRITE: 
1032 foi->flags |= O_WRONLY; 
1033 break; 
1034 default: 
1035 break; 
1036 } 
1037 foi->unused = 0; 1149 foi->unused = 0;
1038 1150
1039 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*foo))) != 0) 1151 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*foo))) != 0)
1040 goto out; 1152 goto out;
1041 1153
1042 foo = GET_OUTPAYLOAD(ps, pm, fuse_open_out); 1154 foo = GET_OUTPAYLOAD(ps, pm, fuse_open_out);
1043  1155
1044 /* 1156 /*
1045 * Save the file handle in node private data  1157 * Save the file handle in node private data
1046 * so that we can reuse it later 1158 * so that we can reuse it later
1047 */ 1159 */
1048 perfuse_new_fh((puffs_cookie_t)pn, foo->fh); 1160 perfuse_new_fh((puffs_cookie_t)pn, foo->fh, mode);
1049 1161
1050#ifdef PERFUSE_DEBUG 1162#ifdef PERFUSE_DEBUG
1051 if (perfuse_diagflags & PDF_FH) 1163 if (perfuse_diagflags & PDF_FH)
1052 DPRINTF("%s: opc = %p, file = \"%s\", " 1164 DPRINTF("%s: opc = %p, file = \"%s\", "
1053 "ino = %"PRId64", fh = 0x%"PRIx64"\n", 1165 "ino = %"PRId64", %s%sfh = 0x%"PRIx64"\n",
1054 __func__, (void *)opc,  1166 __func__, (void *)opc,
1055 (char *)PNPATH((struct puffs_node *)opc), 1167 (char *)PNPATH((struct puffs_node *)opc),
1056 PERFUSE_NODE_DATA(opc)->pnd_ino, foo->fh); 1168 pnd->pnd_ino, mode & FREAD ? "r" : "",
 1169 mode & FWRITE ? "w" : "", foo->fh);
1057#endif 1170#endif
1058out: 1171out:
1059 ps->ps_destroy_msg(pm); 1172 ps->ps_destroy_msg(pm);
1060 1173
1061 return error; 1174 return error;
1062} 1175}
1063 1176
1064/* ARGSUSED2 */ 1177/* ARGSUSED0 */
1065int 1178int
1066perfuse_node_close(pu, opc, flags, pcr) 1179perfuse_node_close(pu, opc, flags, pcr)
1067 struct puffs_usermount *pu; 1180 struct puffs_usermount *pu;
1068 puffs_cookie_t opc; 1181 puffs_cookie_t opc;
1069 int flags; 1182 int flags;
1070 const struct puffs_cred *pcr; 1183 const struct puffs_cred *pcr;
1071{ 1184{
1072 struct perfuse_state *ps; 
1073 perfuse_msg_t *pm; 
1074 int op; 
1075 uint64_t fh; 
1076 struct perfuse_node_data *pnd; 
1077 struct fuse_release_in *fri; 
1078 struct puffs_node *pn; 1185 struct puffs_node *pn;
1079 int error; 1186 struct perfuse_node_data *pnd;
1080  
1081 ps = puffs_getspecific(pu); 
1082 pn = (struct puffs_node *)opc; 
1083 pnd = PERFUSE_NODE_DATA(pn); 
1084 1187
1085 if (puffs_pn_getvap(pn)->va_type == VDIR) 1188 pn = (struct puffs_node *)opc;
1086 op = FUSE_RELEASEDIR; 1189 pnd = PERFUSE_NODE_DATA(opc);
1087 else 
1088 op = FUSE_RELEASE; 
1089 1190
1090 if (!(pnd->pnd_flags & PND_OPEN)) 1191 if (!(pnd->pnd_flags & PND_OPEN))
1091 return EBADF; 1192 return EBADF;
1092 1193
1093 fh = perfuse_get_fh(opc); 
1094 
1095 /* 1194 /*
1096 * Sync before close for files 1195 * Make sure all operation are finished
1097 */ 1196 * There can be an ongoing write, or queued operations
1098 if ((op == FUSE_RELEASE) && (pnd->pnd_flags & PND_DIRTY)) { 1197 * XXX perhaps deadlock. Use requeue_request
1099#ifdef PERFUSE_DEBUG 1198 */
1100 if (perfuse_diagflags & PDF_SYNC) 1199 while ((pnd->pnd_flags & PND_BUSY) ||
1101 DPRINTF("%s: SYNC opc = %p, file = \"%s\"\n",  1200 !TAILQ_EMPTY(&pnd->pnd_pcq))
1102 __func__, (void*)opc, (char *)PNPATH(pn)); 1201 puffs_cc_yield(puffs_cc_getcc(pu));
1103#endif 
1104 if ((error = perfuse_node_fsync(pu, opc, pcr, 0, 0, 0)) != 0) 
1105 return error; 
1106 
1107 pnd->pnd_flags &= ~PND_DIRTY; 
1108 
1109#ifdef PERFUSE_DEBUG 
1110 if (perfuse_diagflags & PDF_SYNC) 
1111 DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n",  
1112 __func__, (void*)opc, (char *)PNPATH((pn))); 
1113#endif 
1114 } 
1115 
1116 /* 
1117 * Destroy the filehandle before sending the  
1118 * request to the FUSE filesystem, otherwise  
1119 * we may get a second close() while we wait 
1120 * for the reply, and we would end up closing 
1121 * the same fh twice instead of closng both. 
1122 */ 
1123 perfuse_destroy_fh(pn, fh); 
1124 
1125#ifdef PERFUSE_DEBUG 
1126 if (perfuse_diagflags & PDF_FH) 
1127 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n", 
1128 __func__, (void *)opc, pnd->pnd_ino, fh); 
1129#endif 
1130 1202
1131 /* 1203 /*
1132 * release_flags may be set to FUSE_RELEASE_FLUSH 1204 * The NetBSD kernel will send sync and setattr(mtime, ctime)
1133 * to flush locks. lock_owner must be set in that case 1205 * afer a close on a regular file. Some FUSE filesystem will
 1206 * assume theses operations are performed on open files. We
 1207 * therefore postpone the close operation at reclaim time.
1134 */ 1208 */
1135 pm = ps->ps_new_msg(pu, opc, op, sizeof(*fri), NULL); 1209 if (puffs_pn_getvap(pn)->va_type != VREG)
1136 fri = GET_INPAYLOAD(ps, pm, fuse_release_in); 1210 return node_close_common(pu, opc, flags);
1137 fri->fh = fh; 
1138 fri->flags = 0; 
1139 fri->release_flags = 0; 
1140 fri->lock_owner = PERFUSE_NODE_DATA(pn)->pnd_lock_owner; 
1141 fri->flags = (fri->lock_owner != 0) ? FUSE_RELEASE_FLUSH : 0; 
1142 
1143#ifdef PERFUSE_DEBUG 
1144 if (perfuse_diagflags & PDF_FH) 
1145 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n", 
1146 __func__, (void *)opc, pnd->pnd_ino, fri->fh); 
1147#endif 
1148 
1149 if ((error = XCHG_MSG(ps, pu, pm, NO_PAYLOAD_REPLY_LEN)) != 0) 
1150 goto out; 
1151 
1152out: 
1153 if (error != 0) 
1154 DWARNX("%s: freed fh = 0x%"PRIx64" but filesystem " 
1155 "returned error = %d", 
1156 __func__, fh, error); 
1157 1211
1158 ps->ps_destroy_msg(pm); 1212 return 0;
1159 
1160 return error; 
1161} 1213}
1162 1214
1163int 1215int
1164perfuse_node_access(pu, opc, mode, pcr) 1216perfuse_node_access(pu, opc, mode, pcr)
1165 struct puffs_usermount *pu; 1217 struct puffs_usermount *pu;
1166 puffs_cookie_t opc; 1218 puffs_cookie_t opc;
1167 int mode; 1219 int mode;
1168 const struct puffs_cred *pcr; 1220 const struct puffs_cred *pcr;
1169{ 1221{
1170 perfuse_msg_t *pm; 1222 perfuse_msg_t *pm;
1171 struct perfuse_state *ps; 1223 struct perfuse_state *ps;
1172 struct fuse_access_in *fai; 1224 struct fuse_access_in *fai;
1173 int error; 1225 int error;
@@ -1190,27 +1242,27 @@ perfuse_node_access(pu, opc, mode, pcr) @@ -1190,27 +1242,27 @@ perfuse_node_access(pu, opc, mode, pcr)
1190 } 1242 }
1191 1243
1192 if (error == ENOSYS) { 1244 if (error == ENOSYS) {
1193 struct fuse_getattr_in *fgi; 1245 struct fuse_getattr_in *fgi;
1194 struct fuse_attr_out *fao; 1246 struct fuse_attr_out *fao;
1195 1247
1196 ps->ps_flags |= PS_NO_ACCESS; 1248 ps->ps_flags |= PS_NO_ACCESS;
1197 1249
1198 pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR,  1250 pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR,
1199 sizeof(*fgi), NULL); 1251 sizeof(*fgi), NULL);
1200 fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in); 1252 fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in);
1201 fgi->getattr_flags = 0;  1253 fgi->getattr_flags = 0;
1202 fgi->dummy = 0; 1254 fgi->dummy = 0;
1203 fgi->fh = perfuse_get_fh(opc); 1255 fgi->fh = perfuse_get_fh(opc, FREAD);
1204 1256
1205#ifdef PERFUSE_DEBUG 1257#ifdef PERFUSE_DEBUG
1206 if (perfuse_diagflags & PDF_FH) 1258 if (perfuse_diagflags & PDF_FH)
1207 DPRINTF("%s: opc = %p, ino = %"PRId64", " 1259 DPRINTF("%s: opc = %p, ino = %"PRId64", "
1208 "fh = 0x%"PRIx64"\n", __func__, (void *)opc, 1260 "fh = 0x%"PRIx64"\n", __func__, (void *)opc,
1209 PERFUSE_NODE_DATA(opc)->pnd_ino, fgi->fh); 1261 PERFUSE_NODE_DATA(opc)->pnd_ino, fgi->fh);
1210#endif 1262#endif
1211 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fao))) != 0) { 1263 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fao))) != 0) {
1212 ps->ps_destroy_msg(pm); 1264 ps->ps_destroy_msg(pm);
1213 goto out; 1265 goto out;
1214 } 1266 }
1215 1267
1216 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 1268 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
@@ -1278,35 +1330,40 @@ out: @@ -1278,35 +1330,40 @@ out:
1278 return error; 1330 return error;
1279} 1331}
1280 1332
1281int 1333int
1282perfuse_node_setattr(pu, opc, vap, pcr) 1334perfuse_node_setattr(pu, opc, vap, pcr)
1283 struct puffs_usermount *pu; 1335 struct puffs_usermount *pu;
1284 puffs_cookie_t opc; 1336 puffs_cookie_t opc;
1285 const struct vattr *vap; 1337 const struct vattr *vap;
1286 const struct puffs_cred *pcr; 1338 const struct puffs_cred *pcr;
1287{ 1339{
1288 perfuse_msg_t *pm; 1340 perfuse_msg_t *pm;
1289 uint64_t fh; 1341 uint64_t fh;
1290 struct perfuse_state *ps; 1342 struct perfuse_state *ps;
 1343 struct perfuse_node_data *pnd;
1291 struct fuse_setattr_in *fsi; 1344 struct fuse_setattr_in *fsi;
1292 int error; 1345 int error;
 1346 int open_self;
1293 struct vattr *old_va; 1347 struct vattr *old_va;
1294 1348
 1349 open_self = 0;
 1350 ps = puffs_getspecific(pu);
 1351 pnd = PERFUSE_NODE_DATA(opc);
 1352
1295 /* 1353 /*
1296 * setattr requires --X on the parent directory 1354 * setattr requires --X on the parent directory
1297 */ 1355 */
1298 if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent, 1356 if (no_access((puffs_cookie_t)pnd->pnd_parent, pcr, PUFFS_VEXEC))
1299 pcr, PUFFS_VEXEC)) 
1300 return EACCES; 1357 return EACCES;
1301 1358
1302 old_va = puffs_pn_getvap((struct puffs_node *)opc); 1359 old_va = puffs_pn_getvap((struct puffs_node *)opc);
1303 1360
1304 /* 1361 /*
1305 * Check for permission to change size 1362 * Check for permission to change size
1306 */ 1363 */
1307 if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) && 1364 if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) &&
1308 no_access(opc, pcr, PUFFS_VWRITE)) 1365 no_access(opc, pcr, PUFFS_VWRITE))
1309 return EACCES; 1366 return EACCES;
1310 1367
1311 /* 1368 /*
1312 * Check for permission to change dates 1369 * Check for permission to change dates
@@ -1321,41 +1378,58 @@ perfuse_node_setattr(pu, opc, vap, pcr) @@ -1321,41 +1378,58 @@ perfuse_node_setattr(pu, opc, vap, pcr)
1321 * Check for permission to change owner and group 1378 * Check for permission to change owner and group
1322 */ 1379 */
1323 if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) || 1380 if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) ||
1324 (vap->va_gid != (gid_t)PUFFS_VNOVAL)) && 1381 (vap->va_gid != (gid_t)PUFFS_VNOVAL)) &&
1325 (puffs_access_chown(old_va->va_uid, old_va->va_gid, 1382 (puffs_access_chown(old_va->va_uid, old_va->va_gid,
1326 vap->va_uid, vap->va_gid, pcr)) != 0) 1383 vap->va_uid, vap->va_gid, pcr)) != 0)
1327 return EACCES; 1384 return EACCES;
1328 1385
1329 /* 1386 /*
1330 * Check for permission to change permissions 1387 * Check for permission to change permissions
1331 */ 1388 */
1332 if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) && 1389 if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) &&
1333 (puffs_access_chmod(old_va->va_uid, old_va->va_gid, 1390 (puffs_access_chmod(old_va->va_uid, old_va->va_gid,
1334 old_va->va_type, vap->va_mode, pcr)) != 0) 1391 old_va->va_type, vap->va_mode, pcr)) != 0)
1335 return EACCES; 1392 return EACCES;
1336  1393
 1394 /*
 1395 * setattr(mtime, ctime) require an open file,
 1396 * at least for glusterfs.
 1397 */
 1398 if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) ||
 1399 (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) &&
 1400 !(pnd->pnd_flags & PND_WFH)) {
 1401 if ((error = perfuse_node_open(pu, opc, FWRITE, pcr)) != 0)
 1402 return error;
 1403 open_self = 1;
 1404 }
 1405 /*
 1406 * It seems troublesome to resize a file while
 1407 * a write is just beeing done. Wait for
 1408 * it to finish.
 1409 */
 1410 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL)
 1411 while (pnd->pnd_flags & PND_INWRITE)
 1412 requeue_request(pu, opc, PCQ_AFTERWRITE);
1337 1413
1338 ps = puffs_getspecific(pu); 
1339 1414
1340 pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr); 1415 pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr);
1341 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in); 1416 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
1342 fsi->valid = 0; 1417 fsi->valid = 0;
1343 1418
1344 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) { 1419 if (pnd->pnd_flags & PND_WFH) {
1345 fh = perfuse_get_fh(opc); 1420 fh = perfuse_get_fh(opc, FWRITE);
1346 fsi->fh = fh; 1421 fsi->fh = fh;
1347 if (fh != FUSE_UNKNOWN_FH) 1422 fsi->valid |= FUSE_FATTR_FH;
1348 fsi->valid |= FUSE_FATTR_FH; 
1349 } 1423 }
1350 1424
1351 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) { 1425 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) {
1352 fsi->size = vap->va_size; 1426 fsi->size = vap->va_size;
1353 fsi->valid |= FUSE_FATTR_SIZE; 1427 fsi->valid |= FUSE_FATTR_SIZE;
1354 } 1428 }
1355 1429
1356 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) { 1430 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) {
1357 fsi->atime = vap->va_atime.tv_sec;; 1431 fsi->atime = vap->va_atime.tv_sec;;
1358 fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec;; 1432 fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec;;
1359 fsi->valid |= (FUSE_FATTR_ATIME|FUSE_FATTR_ATIME_NOW); 1433 fsi->valid |= (FUSE_FATTR_ATIME|FUSE_FATTR_ATIME_NOW);
1360 } 1434 }
1361 1435
@@ -1370,60 +1444,63 @@ perfuse_node_setattr(pu, opc, vap, pcr) @@ -1370,60 +1444,63 @@ perfuse_node_setattr(pu, opc, vap, pcr)
1370 fsi->valid |= FUSE_FATTR_MODE; 1444 fsi->valid |= FUSE_FATTR_MODE;
1371 } 1445 }
1372  1446
1373 if (vap->va_uid != (uid_t)PUFFS_VNOVAL) { 1447 if (vap->va_uid != (uid_t)PUFFS_VNOVAL) {
1374 fsi->uid = vap->va_uid; 1448 fsi->uid = vap->va_uid;
1375 fsi->valid |= FUSE_FATTR_UID; 1449 fsi->valid |= FUSE_FATTR_UID;
1376 } 1450 }
1377 1451
1378 if (vap->va_gid != (gid_t)PUFFS_VNOVAL) { 1452 if (vap->va_gid != (gid_t)PUFFS_VNOVAL) {
1379 fsi->gid = vap->va_gid; 1453 fsi->gid = vap->va_gid;
1380 fsi->valid |= FUSE_FATTR_GID; 1454 fsi->valid |= FUSE_FATTR_GID;
1381 } 1455 }
1382 1456
1383 if (PERFUSE_NODE_DATA(opc)->pnd_lock_owner != 0) { 1457 if (pnd->pnd_lock_owner != 0) {
1384 fsi->lock_owner = PERFUSE_NODE_DATA(opc)->pnd_lock_owner; 1458 fsi->lock_owner = pnd->pnd_lock_owner;
1385 fsi->valid |= FUSE_FATTR_LOCKOWNER; 1459 fsi->valid |= FUSE_FATTR_LOCKOWNER;
1386 } 1460 }
1387 1461
1388 /* 1462 /*
1389 * A fuse_attr_out is returned, but we ignore it. 1463 * A fuse_attr_out is returned, but we ignore it.
1390 */ 1464 */
1391 error = XCHG_MSG(ps, pu, pm, sizeof(struct fuse_attr_out)); 1465 error = XCHG_MSG(ps, pu, pm, sizeof(struct fuse_attr_out));
1392 1466
1393 ps->ps_destroy_msg(pm); 1467 ps->ps_destroy_msg(pm);
1394 1468
 1469 if (open_self)
 1470 (void)perfuse_node_close(pu, opc, FWRITE, pcr);
 1471
1395 return error; 1472 return error;
1396} 1473}
1397 1474
1398int 1475int
1399perfuse_node_poll(pu, opc, events) 1476perfuse_node_poll(pu, opc, events)
1400 struct puffs_usermount *pu; 1477 struct puffs_usermount *pu;
1401 puffs_cookie_t opc; 1478 puffs_cookie_t opc;
1402 int *events; 1479 int *events;
1403{ 1480{
1404 struct perfuse_state *ps; 1481 struct perfuse_state *ps;
1405 perfuse_msg_t *pm; 1482 perfuse_msg_t *pm;
1406 struct fuse_poll_in *fpi; 1483 struct fuse_poll_in *fpi;
1407 struct fuse_poll_out *fpo; 1484 struct fuse_poll_out *fpo;
1408 int error; 1485 int error;
1409 1486
1410 ps = puffs_getspecific(pu); 1487 ps = puffs_getspecific(pu);
1411 /* 1488 /*
1412 * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set. 1489 * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set.
1413 */ 1490 */
1414 pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL); 1491 pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL);
1415 fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in); 1492 fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in);
1416 fpi->fh = perfuse_get_fh(opc); 1493 fpi->fh = perfuse_get_fh(opc, FREAD);
1417 fpi->kh = 0; 1494 fpi->kh = 0;
1418 fpi->flags = 0; 1495 fpi->flags = 0;
1419 1496
1420#ifdef PERFUSE_DEBUG 1497#ifdef PERFUSE_DEBUG
1421 if (perfuse_diagflags & PDF_FH) 1498 if (perfuse_diagflags & PDF_FH)
1422 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n", 1499 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
1423 __func__, (void *)opc,  1500 __func__, (void *)opc,
1424 PERFUSE_NODE_DATA(opc)->pnd_ino, fpi->fh); 1501 PERFUSE_NODE_DATA(opc)->pnd_ino, fpi->fh);
1425#endif 1502#endif
1426 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fpo))) != 0) 1503 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fpo))) != 0)
1427 goto out; 1504 goto out;
1428 1505
1429 fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out); 1506 fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out);
@@ -1469,51 +1546,51 @@ perfuse_node_fsync(pu, opc, pcr, flags,  @@ -1469,51 +1546,51 @@ perfuse_node_fsync(pu, opc, pcr, flags,
1469 pm = NULL; 1546 pm = NULL;
1470 open_self = 0;  1547 open_self = 0;
1471 1548
1472 /*  1549 /*
1473 * If we previously detected it as unimplemented, 1550 * If we previously detected it as unimplemented,
1474 * skip the call to the filesystem. 1551 * skip the call to the filesystem.
1475 */ 1552 */
1476 ps = puffs_getspecific(pu); 1553 ps = puffs_getspecific(pu);
1477 if (ps->ps_flags == PS_NO_FSYNC) 1554 if (ps->ps_flags == PS_NO_FSYNC)
1478 return ENOSYS; 1555 return ENOSYS;
1479 1556
1480 /* 1557 /*
1481 * Do not sync if there are no change to sync 1558 * Do not sync if there are no change to sync
1482 * XXX remove that testif we implement mmap 1559 * XXX remove that test if we implement mmap
1483 */ 1560 */
1484 pnd = PERFUSE_NODE_DATA(opc); 1561 pnd = PERFUSE_NODE_DATA(opc);
1485#ifdef PERFUSE_DEBUG 1562#ifdef PERFUSE_DEBUG
1486 if (perfuse_diagflags & PDF_SYNC) 1563 if (perfuse_diagflags & PDF_SYNC)
1487 DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n",  1564 DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n",
1488 __func__, (void*)opc, 1565 __func__, (void*)opc,
1489 (char *)PNPATH((struct puffs_node *)opc), 1566 (char *)PNPATH((struct puffs_node *)opc),
1490 pnd->pnd_flags & PND_DIRTY ? "" : "not "); 1567 pnd->pnd_flags & PND_DIRTY ? "" : "not ");
1491#endif 1568#endif
1492 if (!(pnd->pnd_flags & PND_DIRTY)) 1569 if (!(pnd->pnd_flags & PND_DIRTY))
1493 return 0; 1570 return 0;
1494 1571
1495 /* 1572 /*
1496 * It seems NetBSD can call fsync without open first 1573 * It seems NetBSD can call fsync without open first
1497 * glusterfs complain in such a situation: 1574 * glusterfs complain in such a situation:
1498 * "FSYNC() ERR => -1 (Invalid argument)" 1575 * "FSYNC() ERR => -1 (Invalid argument)"
1499 */ 1576 */
1500 if (!(pnd->pnd_flags & PND_OPEN)) { 1577 if (!(pnd->pnd_flags & PND_OPEN)) {
1501 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0) 1578 if ((error = perfuse_node_open(pu, opc, FWRITE, pcr)) != 0)
1502 goto out; 1579 goto out;
1503 open_self = 1; 1580 open_self = 1;
1504 } 1581 }
1505 1582
1506 fh = perfuse_get_fh(opc); 1583 fh = perfuse_get_fh(opc, FWRITE);
1507  1584
1508 /* 1585 /*
1509 * If fsync_flags is set, meta data should not be flushed. 1586 * If fsync_flags is set, meta data should not be flushed.
1510 */ 1587 */
1511 pm = ps->ps_new_msg(pu, opc, FUSE_FSYNC, sizeof(*ffi), NULL); 1588 pm = ps->ps_new_msg(pu, opc, FUSE_FSYNC, sizeof(*ffi), NULL);
1512 ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in); 1589 ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in);
1513 ffi->fh = fh; 1590 ffi->fh = fh;
1514 ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1; 1591 ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1;
1515 1592
1516#ifdef PERFUSE_DEBUG 1593#ifdef PERFUSE_DEBUG
1517 if (perfuse_diagflags & PDF_FH) 1594 if (perfuse_diagflags & PDF_FH)
1518 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n", 1595 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
1519 __func__, (void *)opc, 1596 __func__, (void *)opc,
@@ -1533,28 +1610,28 @@ perfuse_node_fsync(pu, opc, pcr, flags,  @@ -1533,28 +1610,28 @@ perfuse_node_fsync(pu, opc, pcr, flags,
1533 if (perfuse_diagflags & PDF_SYNC) 1610 if (perfuse_diagflags & PDF_SYNC)
1534 DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n",  1611 DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n",
1535 __func__, (void*)opc, 1612 __func__, (void*)opc,
1536 (char *)PNPATH((struct puffs_node *)opc)); 1613 (char *)PNPATH((struct puffs_node *)opc));
1537#endif 1614#endif
1538 1615
1539out: 1616out:
1540 if (error == ENOSYS) 1617 if (error == ENOSYS)
1541 ps->ps_flags |= PS_NO_FSYNC; 1618 ps->ps_flags |= PS_NO_FSYNC;
1542 1619
1543 if (pm != NULL) 1620 if (pm != NULL)
1544 ps->ps_destroy_msg(pm); 1621 ps->ps_destroy_msg(pm);
1545 1622
1546 if (open_self) 1623 if (open_self)
1547 (void)perfuse_node_close(pu, opc, 0, pcr); 1624 (void)node_close_common(pu, opc, FWRITE);
1548 1625
1549 return error; 1626 return error;
1550} 1627}
1551 1628
1552/* ARGSUSED0 */ 1629/* ARGSUSED0 */
1553int 1630int
1554perfuse_node_seek(pu, opc, oldoff, newoff, pcr) 1631perfuse_node_seek(pu, opc, oldoff, newoff, pcr)
1555 struct puffs_usermount *pu; 1632 struct puffs_usermount *pu;
1556 puffs_cookie_t opc; 1633 puffs_cookie_t opc;
1557 off_t oldoff; 1634 off_t oldoff;
1558 off_t newoff; 1635 off_t newoff;
1559 const struct puffs_cred *pcr; 1636 const struct puffs_cred *pcr;
1560{ 1637{
@@ -1566,63 +1643,62 @@ perfuse_node_seek(pu, opc, oldoff, newof @@ -1566,63 +1643,62 @@ perfuse_node_seek(pu, opc, oldoff, newof
1566 PERFUSE_NODE_DATA(opc)->pnd_offset = newoff; 1643 PERFUSE_NODE_DATA(opc)->pnd_offset = newoff;
1567 1644
1568 return 0; 1645 return 0;
1569} 1646}
1570 1647
1571int 1648int
1572perfuse_node_remove(pu, opc, targ, pcn) 1649perfuse_node_remove(pu, opc, targ, pcn)
1573 struct puffs_usermount *pu; 1650 struct puffs_usermount *pu;
1574 puffs_cookie_t opc; 1651 puffs_cookie_t opc;
1575 puffs_cookie_t targ; 1652 puffs_cookie_t targ;
1576 const struct puffs_cn *pcn; 1653 const struct puffs_cn *pcn;
1577{ 1654{
1578 struct perfuse_state *ps; 1655 struct perfuse_state *ps;
1579 perfuse_msg_t *pm; 
1580 struct puffs_node *pn; 1656 struct puffs_node *pn;
 1657 struct perfuse_node_data *pnd;
 1658 perfuse_msg_t *pm;
1581 char *path; 1659 char *path;
1582 const char *name; 1660 const char *name;
1583 size_t len; 1661 size_t len;
1584 int error; 1662 int error;
1585  1663
 1664 pnd = PERFUSE_NODE_DATA(opc);
 1665
1586 /* 1666 /*
1587 * remove requires -WX on the parent directory  1667 * remove requires -WX on the parent directory
1588 * no right required on the object. 1668 * no right required on the object.
1589 */ 1669 */
1590 if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent, 1670 if (no_access((puffs_cookie_t)pnd->pnd_parent,
1591 pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC)) 1671 pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
1592 return EACCES; 1672 return EACCES;
1593 1673
1594 ps = puffs_getspecific(pu); 
1595 
1596 if (targ == NULL) 1674 if (targ == NULL)
1597 DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__); 1675 DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__);
1598 1676
 1677 ps = puffs_getspecific(pu);
1599 pn = (struct puffs_node *)targ; 1678 pn = (struct puffs_node *)targ;
1600 name = basename_r((char *)PNPATH(pn)); 1679 name = basename_r((char *)PNPATH(pn));
1601 len = strlen(name) + 1; 1680 len = strlen(name) + 1;
1602 1681
1603 pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred); 1682 pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred);
1604 path = _GET_INPAYLOAD(ps, pm, char *); 1683 path = _GET_INPAYLOAD(ps, pm, char *);
1605 (void)strlcpy(path, name, len); 1684 (void)strlcpy(path, name, len);
1606 1685
1607 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0) 1686 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0)
1608 goto out; 1687 goto out;
1609 1688
1610 if (puffs_inval_namecache_dir(pu, opc) != 0) 1689 if (puffs_inval_namecache_dir(pu, opc) != 0)
1611 DERR(EX_OSERR, "puffs_inval_namecache_dir failed"); 1690 DERR(EX_OSERR, "puffs_inval_namecache_dir failed");
1612 1691
1613 if (puffs_inval_pagecache_node(pu, (puffs_cookie_t)pn) != 0) 
1614 DERR(EX_OSERR, "puffs_inval_namecache_node failed"); 
1615 
1616 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 1692 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
1617 1693
1618 /* 1694 /*
1619 * Reclaim should take care of decreasing pnd_childcount 1695 * Reclaim should take care of decreasing pnd_childcount
1620 */ 1696 */
1621out: 1697out:
1622 ps->ps_destroy_msg(pm); 1698 ps->ps_destroy_msg(pm);
1623 1699
1624 return error; 1700 return error;
1625} 1701}
1626 1702
1627int 1703int
1628perfuse_node_link(pu, opc, targ, pcn) 1704perfuse_node_link(pu, opc, targ, pcn)
@@ -1757,59 +1833,59 @@ perfuse_node_mkdir(pu, opc, pni, pcn, va @@ -1757,59 +1833,59 @@ perfuse_node_mkdir(pu, opc, pni, pcn, va
1757 1833
1758 return node_mk_common(pu, opc, pni, pcn, pm); 1834 return node_mk_common(pu, opc, pni, pcn, pm);
1759} 1835}
1760 1836
1761 1837
1762int 1838int
1763perfuse_node_rmdir(pu, opc, targ, pcn) 1839perfuse_node_rmdir(pu, opc, targ, pcn)
1764 struct puffs_usermount *pu; 1840 struct puffs_usermount *pu;
1765 puffs_cookie_t opc; 1841 puffs_cookie_t opc;
1766 puffs_cookie_t targ; 1842 puffs_cookie_t targ;
1767 const struct puffs_cn *pcn; 1843 const struct puffs_cn *pcn;
1768{ 1844{
1769 struct perfuse_state *ps; 1845 struct perfuse_state *ps;
 1846 struct perfuse_node_data *pnd;
1770 perfuse_msg_t *pm; 1847 perfuse_msg_t *pm;
1771 struct puffs_node *pn; 1848 struct puffs_node *pn;
1772 char *path; 1849 char *path;
1773 const char *name; 1850 const char *name;
1774 size_t len; 1851 size_t len;
1775 int error; 1852 int error;
1776  1853
 1854 pnd = PERFUSE_NODE_DATA(opc);
 1855
1777 /* 1856 /*
1778 * remove requires -WX on the parent directory  1857 * remove requires -WX on the parent directory
1779 * no right required on the object. 1858 * no right required on the object.
1780 */ 1859 */
1781 if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent, 1860 if (no_access((puffs_cookie_t)pnd->pnd_parent,
1782 pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC)) 1861 pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
1783 return EACCES; 1862 return EACCES;
1784 1863
1785 ps = puffs_getspecific(pu); 1864 ps = puffs_getspecific(pu);
1786 pn = (struct puffs_node *)targ; 1865 pn = (struct puffs_node *)targ;
1787 name = basename_r((char *)PNPATH(pn)); 1866 name = basename_r((char *)PNPATH(pn));
1788 len = strlen(name) + 1; 1867 len = strlen(name) + 1;
1789 1868
1790 pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred); 1869 pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred);
1791 path = _GET_INPAYLOAD(ps, pm, char *); 1870 path = _GET_INPAYLOAD(ps, pm, char *);
1792 (void)strlcpy(path, name, len); 1871 (void)strlcpy(path, name, len);
1793 1872
1794 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0) 1873 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0)
1795 goto out; 1874 goto out;
1796 1875
1797 if (puffs_inval_namecache_dir(pu, opc) != 0) 1876 if (puffs_inval_namecache_dir(pu, opc) != 0)
1798 DERR(EX_OSERR, "puffs_inval_namecache_dir failed"); 1877 DERR(EX_OSERR, "puffs_inval_namecache_dir failed");
1799 1878
1800 if (puffs_inval_pagecache_node(pu, (puffs_cookie_t)pn) != 0) 
1801 DERR(EX_OSERR, "puffs_inval_namecache_node failed"); 
1802 
1803 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 1879 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
1804 1880
1805out: 1881out:
1806 ps->ps_destroy_msg(pm); 1882 ps->ps_destroy_msg(pm);
1807 1883
1808 return error; 1884 return error;
1809} 1885}
1810 1886
1811/* vap is unused */ 1887/* vap is unused */
1812/* ARGSUSED4 */ 1888/* ARGSUSED4 */
1813int 1889int
1814perfuse_node_symlink(pu, opc, pni, pcn_src, vap, link_target) 1890perfuse_node_symlink(pu, opc, pni, pcn_src, vap, link_target)
1815 struct puffs_usermount *pu; 1891 struct puffs_usermount *pu;
@@ -1895,37 +1971,37 @@ perfuse_node_readdir(pu, opc, dent, read @@ -1895,37 +1971,37 @@ perfuse_node_readdir(pu, opc, dent, read
1895 __func__, (void *)opc); 1971 __func__, (void *)opc);
1896#endif 1972#endif
1897 /* 1973 /*
1898 * Do we already have the data bufered? 1974 * Do we already have the data bufered?
1899 */ 1975 */
1900 if (pnd->pnd_dirent != NULL) 1976 if (pnd->pnd_dirent != NULL)
1901 goto out; 1977 goto out;
1902 pnd->pnd_dirent_len = 0; 1978 pnd->pnd_dirent_len = 0;
1903  1979
1904 /* 1980 /*
1905 * It seems NetBSD can call readdir without open first 1981 * It seems NetBSD can call readdir without open first
1906 * libfuse will crash if it is done that way, hence open first. 1982 * libfuse will crash if it is done that way, hence open first.
1907 */ 1983 */
1908 if (!(PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN)) { 1984 if (!(pnd->pnd_flags & PND_OPEN)) {
1909 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0) 1985 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
1910 goto out; 1986 goto out;
1911 open_self = 1; 1987 open_self = 1;
1912 } 1988 }
1913 1989
1914 fh = perfuse_get_fh(opc); 1990 fh = perfuse_get_fh(opc, FREAD);
1915 1991
1916#ifdef PERFUSE_DEBUG 1992#ifdef PERFUSE_DEBUG
1917 if (perfuse_diagflags & PDF_FH) 1993 if (perfuse_diagflags & PDF_FH)
1918 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n", 1994 DPRINTF("%s: opc = %p, ino = %"PRId64", rfh = 0x%"PRIx64"\n",
1919 __func__, (void *)opc, 1995 __func__, (void *)opc,
1920 PERFUSE_NODE_DATA(opc)->pnd_ino, fh); 1996 PERFUSE_NODE_DATA(opc)->pnd_ino, fh);
1921#endif 1997#endif
1922 1998
1923 pnd->pnd_all_fd = NULL; 1999 pnd->pnd_all_fd = NULL;
1924 pnd->pnd_all_fd_len = 0; 2000 pnd->pnd_all_fd_len = 0;
1925 fd_offset = 0; 2001 fd_offset = 0;
1926  2002
1927 do { 2003 do {
1928 size_t fd_len; 2004 size_t fd_len;
1929 char *afdp; 2005 char *afdp;
1930  2006
1931 pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr); 2007 pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr);
@@ -2003,27 +2079,27 @@ out: @@ -2003,27 +2079,27 @@ out:
2003 free(pnd->pnd_all_fd); 2079 free(pnd->pnd_all_fd);
2004 pnd->pnd_all_fd = NULL; 2080 pnd->pnd_all_fd = NULL;
2005 pnd->pnd_all_fd_len = 0; 2081 pnd->pnd_all_fd_len = 0;
2006 } 2082 }
2007 2083
2008 if (pm != NULL) 2084 if (pm != NULL)
2009 ps->ps_destroy_msg(pm); 2085 ps->ps_destroy_msg(pm);
2010 2086
2011 /* 2087 /*
2012 * If we opened the directory ourselves, close now 2088 * If we opened the directory ourselves, close now
2013 * errors are ignored. 2089 * errors are ignored.
2014 */ 2090 */
2015 if (open_self) 2091 if (open_self)
2016 (void)perfuse_node_close(pu, opc, 0, pcr); 2092 (void)perfuse_node_close(pu, opc, FWRITE, pcr);
2017 2093
2018 if (error == 0) 2094 if (error == 0)
2019 error = readdir_buffered(ps, opc, dent, readoff, 2095 error = readdir_buffered(ps, opc, dent, readoff,
2020 reslen, pcr, eofflag, cookies, ncookies); 2096 reslen, pcr, eofflag, cookies, ncookies);
2021 2097
2022 /* 2098 /*
2023 * Schedule queued readdir requests 2099 * Schedule queued readdir requests
2024 */ 2100 */
2025 dequeue_requests(ps, opc, PCQ_READDIR, DEQUEUE_ALL); 2101 dequeue_requests(ps, opc, PCQ_READDIR, DEQUEUE_ALL);
2026 pnd->pnd_flags &= ~PND_INREADDIR; 2102 pnd->pnd_flags &= ~PND_INREADDIR;
2027 2103
2028#ifdef PERFUSE_DEBUG 2104#ifdef PERFUSE_DEBUG
2029 if (perfuse_diagflags & PDF_READDIR) 2105 if (perfuse_diagflags & PDF_READDIR)
@@ -2082,77 +2158,99 @@ perfuse_node_reclaim(pu, opc) @@ -2082,77 +2158,99 @@ perfuse_node_reclaim(pu, opc)
2082 puffs_cookie_t opc; 2158 puffs_cookie_t opc;
2083{ 2159{
2084 struct perfuse_state *ps; 2160 struct perfuse_state *ps;
2085 perfuse_msg_t *pm; 2161 perfuse_msg_t *pm;
2086 struct perfuse_node_data *pnd; 2162 struct perfuse_node_data *pnd;
2087 struct fuse_forget_in *ffi; 2163 struct fuse_forget_in *ffi;
2088 struct puffs_node *pn; 2164 struct puffs_node *pn;
2089 struct puffs_node *pn_root; 2165 struct puffs_node *pn_root;
2090  2166
2091 ps = puffs_getspecific(pu); 2167 ps = puffs_getspecific(pu);
2092 pnd = PERFUSE_NODE_DATA(opc); 2168 pnd = PERFUSE_NODE_DATA(opc);
2093 2169
2094 /* 2170 /*
2095 * Make sure open files are properly closed when reclaimed. 
2096 */ 
2097 while (pnd->pnd_flags & PND_OPEN) 
2098 (void)perfuse_node_close(pu, opc, 0, NULL); 
2099  
2100 /* 
2101 * Never forget the root. 2171 * Never forget the root.
2102 */ 2172 */
2103 if (pnd->pnd_ino == FUSE_ROOT_ID) 2173 if (pnd->pnd_ino == FUSE_ROOT_ID)
2104 return 0; 2174 return 0;
2105 2175
2106 pnd->pnd_flags |= PND_RECLAIMED; 2176 pnd->pnd_flags |= PND_RECLAIMED;
2107 2177
2108#ifdef PERFUSE_DEBUG 2178#ifdef PERFUSE_DEBUG
2109 if (perfuse_diagflags & PDF_RECLAIM) 2179 if (perfuse_diagflags & PDF_RECLAIM)
2110 DPRINTF("%s (nodeid %"PRId64") reclaimed\n",  2180 DPRINTF("%s (nodeid %"PRId64") reclaimed\n",
2111 (char *)PNPATH((struct puffs_node *)opc), pnd->pnd_ino); 2181 (char *)PNPATH((struct puffs_node *)opc), pnd->pnd_ino);
2112#endif 2182#endif
2113 2183
2114 pn_root = puffs_getroot(pu); 2184 pn_root = puffs_getroot(pu);
2115 pn = (struct puffs_node *)opc; 2185 pn = (struct puffs_node *)opc;
2116 while (pn != pn_root) { 2186 while (pn != pn_root) {
2117 struct puffs_node *parent_pn; 2187 struct puffs_node *parent_pn;
2118  2188
2119 pnd = PERFUSE_NODE_DATA(pn); 2189 pnd = PERFUSE_NODE_DATA(pn);
2120 2190
2121#ifdef PERFUSE_DEBUG 2191#ifdef PERFUSE_DEBUG
2122 if (perfuse_diagflags & PDF_RECLAIM) 2192 if (perfuse_diagflags & PDF_RECLAIM)
2123 DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, " 2193 DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, "
2124 "has childcount %d, %sopen\n",  2194 "has childcount %d %s%s%s, pending ops:%s%s%s%s\n",
2125 (char *)PNPATH(pn), pnd->pnd_ino, 2195 (char *)PNPATH(pn), pnd->pnd_ino,
2126 pnd->pnd_flags & PND_RECLAIMED ? "" : "not ", 2196 pnd->pnd_flags & PND_RECLAIMED ? "" : "not ",
2127 pnd->pnd_childcount, 2197 pnd->pnd_childcount,
2128 pnd->pnd_flags & PND_OPEN ? "" : "not "); 2198 pnd->pnd_flags & PND_OPEN ? "open " : "not open",
2129 2199 pnd->pnd_flags & PND_RFH ? "r" : "",
2130 if (pnd->pnd_flags & PND_OPEN) 2200 pnd->pnd_flags & PND_WFH ? "w" : "",
2131 DWARNX("%s: (nodeid %"PRId64") %s is still open", 2201 pnd->pnd_flags & PND_INREADDIR ? " readdir" : "",
2132 __func__, pnd->pnd_ino, (char *)PNPATH(pn)); 2202 pnd->pnd_flags & PND_INREAD ? " read" : "",
 2203 pnd->pnd_flags & PND_INWRITE ? " write" : "",
 2204 pnd->pnd_flags & PND_BUSY ? "" : " none");
2133#endif 2205#endif
2134 2206
2135 if (!(pnd->pnd_flags & PND_RECLAIMED) || 2207 if (!(pnd->pnd_flags & PND_RECLAIMED) ||
2136 (pnd->pnd_childcount != 0)) 2208 (pnd->pnd_childcount != 0))
2137 return 0; 2209 return 0;
2138 2210
2139 /* 2211 /*
2140 * If the file is still open, close all file handles 2212 * Make sure all operation are finished
2141 * XXX no pcr arguement to send. 2213 * There can be an ongoing write, or queued operations
2142 */ 2214 */
2143 while(pnd->pnd_flags & PND_OPEN) 2215 while (pnd->pnd_flags & PND_INWRITE) {
2144 (void)perfuse_node_close(pu, opc, 0, NULL); 2216 requeue_request(pu, opc, PCQ_AFTERWRITE);
 2217
 2218 /*
 2219 * It may have been cancelled in the meantime
 2220 */
 2221 if (!(pnd->pnd_flags & PND_RECLAIMED))
 2222 return 0;
 2223 }
 2224
 2225#ifdef PERFUSE_DEBUG
 2226 if ((pnd->pnd_flags & PND_BUSY) ||
 2227 !TAILQ_EMPTY(&pnd->pnd_pcq))
 2228 DERRX(EX_SOFTWARE, "%s: opc = %p: ongoing operations",
 2229 __func__, (void *)opc);
 2230#endif
2145 2231
 2232 /*
 2233 * Close open files
 2234 */
 2235 if (pnd->pnd_flags & PND_WFH)
 2236 (void)node_close_common(pu, opc, FREAD);
 2237
 2238 if (pnd->pnd_flags & PND_RFH)
 2239 (void)node_close_common(pu, opc, FWRITE);
 2240
 2241 /*
 2242 * And send the FORGET message
 2243 */
2146 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET,  2244 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET,
2147 sizeof(*ffi), NULL); 2245 sizeof(*ffi), NULL);
2148 ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in); 2246 ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in);
2149 ffi->nlookup = pnd->pnd_nlookup; 2247 ffi->nlookup = pnd->pnd_nlookup;
2150 2248
2151 /* 2249 /*
2152 * No reply is expected, pm is freed in XCHG_MSG 2250 * No reply is expected, pm is freed in XCHG_MSG
2153 */ 2251 */
2154 (void)XCHG_MSG_NOREPLY(ps, pu, pm, UNSPEC_REPLY_LEN); 2252 (void)XCHG_MSG_NOREPLY(ps, pu, pm, UNSPEC_REPLY_LEN);
2155 2253
2156 parent_pn = pnd->pnd_parent; 2254 parent_pn = pnd->pnd_parent;
2157 2255
2158 perfuse_destroy_pn(pn); 2256 perfuse_destroy_pn(pn);
@@ -2213,27 +2311,27 @@ perfuse_node_advlock(pu, opc, id, op, fl @@ -2213,27 +2311,27 @@ perfuse_node_advlock(pu, opc, id, op, fl
2213 struct fuse_lk_in *fli; 2311 struct fuse_lk_in *fli;
2214 struct fuse_lk_out *flo; 2312 struct fuse_lk_out *flo;
2215 int error; 2313 int error;
2216  2314
2217 ps = puffs_getspecific(pu); 2315 ps = puffs_getspecific(pu);
2218 2316
2219 if (op == F_GETLK) 2317 if (op == F_GETLK)
2220 fop = FUSE_GETLK; 2318 fop = FUSE_GETLK;
2221 else 2319 else
2222 fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK; 2320 fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK;
2223  2321
2224 pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL); 2322 pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL);
2225 fli = GET_INPAYLOAD(ps, pm, fuse_lk_in); 2323 fli = GET_INPAYLOAD(ps, pm, fuse_lk_in);
2226 fli->fh = perfuse_get_fh(opc); 2324 fli->fh = perfuse_get_fh(opc, FWRITE);
2227 fli->owner = fl->l_pid; 2325 fli->owner = fl->l_pid;
2228 fli->lk.start = fl->l_start; 2326 fli->lk.start = fl->l_start;
2229 fli->lk.end = fl->l_start + fl->l_len; 2327 fli->lk.end = fl->l_start + fl->l_len;
2230 fli->lk.type = fl->l_type; 2328 fli->lk.type = fl->l_type;
2231 fli->lk.pid = fl->l_pid; 2329 fli->lk.pid = fl->l_pid;
2232 fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0; 2330 fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0;
2233 2331
2234#ifdef PERFUSE_DEBUG 2332#ifdef PERFUSE_DEBUG
2235 if (perfuse_diagflags & PDF_FH) 2333 if (perfuse_diagflags & PDF_FH)
2236 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n", 2334 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
2237 __func__, (void *)opc, 2335 __func__, (void *)opc,
2238 PERFUSE_NODE_DATA(opc)->pnd_ino, fli->fh); 2336 PERFUSE_NODE_DATA(opc)->pnd_ino, fli->fh);
2239#endif 2337#endif
@@ -2269,67 +2367,73 @@ out: @@ -2269,67 +2367,73 @@ out:
2269} 2367}
2270 2368
2271int 2369int
2272perfuse_node_read(pu, opc, buf, offset, resid, pcr, ioflag) 2370perfuse_node_read(pu, opc, buf, offset, resid, pcr, ioflag)
2273 struct puffs_usermount *pu; 2371 struct puffs_usermount *pu;
2274 puffs_cookie_t opc; 2372 puffs_cookie_t opc;
2275 uint8_t *buf; 2373 uint8_t *buf;
2276 off_t offset; 2374 off_t offset;
2277 size_t *resid; 2375 size_t *resid;
2278 const struct puffs_cred *pcr; 2376 const struct puffs_cred *pcr;
2279 int ioflag; 2377 int ioflag;
2280{ 2378{
2281 struct perfuse_state *ps; 2379 struct perfuse_state *ps;
 2380 struct perfuse_node_data *pnd;
2282 perfuse_msg_t *pm; 2381 perfuse_msg_t *pm;
2283 struct fuse_read_in *fri; 2382 struct fuse_read_in *fri;
2284 struct fuse_out_header *foh; 2383 struct fuse_out_header *foh;
2285 size_t readen; 2384 size_t readen;
2286 size_t requested; 2385 size_t requested;
2287 int error; 2386 int error;
2288  2387
2289 ps = puffs_getspecific(pu); 2388 ps = puffs_getspecific(pu);
 2389 pnd = PERFUSE_NODE_DATA(opc);
2290 pm = NULL; 2390 pm = NULL;
2291 2391
 2392 if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR)
 2393 return EBADF;
 2394
 2395 pnd->pnd_flags |= PND_INREAD;
 2396
2292 requested = *resid; 2397 requested = *resid;
2293 if ((ps->ps_readahead + requested) > ps->ps_max_readahead) { 2398 if ((ps->ps_readahead + requested) > ps->ps_max_readahead) {
2294 if (perfuse_diagflags & PDF_REQUEUE) 2399 if (perfuse_diagflags & PDF_REQUEUE)
2295 DPRINTF("readahead = %zd\n", ps->ps_readahead); 2400 DPRINTF("readahead = %zd\n", ps->ps_readahead);
2296 requeue_request(pu, opc, PCQ_READ); 2401 requeue_request(pu, opc, PCQ_READ);
2297 } 2402 }
2298 ps->ps_readahead += requested; 2403 ps->ps_readahead += requested;
2299  2404
2300 do { 2405 do {
2301 /* 2406 /*
2302 * flags may be set to FUSE_READ_LOCKOWNER  2407 * flags may be set to FUSE_READ_LOCKOWNER
2303 * if lock_owner is provided. 2408 * if lock_owner is provided.
2304 * 2409 *
2305 * XXX See comment about fri->size in perfuse_node_readdir 2410 * XXX See comment about fri->size in perfuse_node_readdir
2306 * We encounter the same bug here. 2411 * We encounter the same bug here.
2307 */ 2412 */
2308 pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr); 2413 pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr);
2309 fri = GET_INPAYLOAD(ps, pm, fuse_read_in); 2414 fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
2310 fri->fh = perfuse_get_fh(opc); 2415 fri->fh = perfuse_get_fh(opc, FREAD);
2311 fri->offset = offset; 2416 fri->offset = offset;
2312 fri->size = (uint32_t)MIN(*resid, PAGE_SIZE - sizeof(*foh)); 2417 fri->size = (uint32_t)MIN(*resid, PAGE_SIZE - sizeof(*foh));
2313 fri->read_flags = 0; /* XXX Unused by libfuse? */ 2418 fri->read_flags = 0; /* XXX Unused by libfuse? */
2314 fri->lock_owner = PERFUSE_NODE_DATA(opc)->pnd_lock_owner; 2419 fri->lock_owner = pnd->pnd_lock_owner;
2315 fri->flags = 0; 2420 fri->flags = 0;
2316 fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0; 2421 fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0;
2317 2422
2318#ifdef PERFUSE_DEBUG 2423#ifdef PERFUSE_DEBUG
2319 if (perfuse_diagflags & PDF_FH) 2424 if (perfuse_diagflags & PDF_FH)
2320 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n", 2425 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
2321 __func__, (void *)opc, 2426 __func__, (void *)opc, pnd->pnd_ino, fri->fh);
2322 PERFUSE_NODE_DATA(opc)->pnd_ino, fri->fh); 
2323#endif 2427#endif
2324 error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN); 2428 error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN);
2325 2429
2326 if (error != 0) 2430 if (error != 0)
2327 goto out; 2431 goto out;
2328 2432
2329 foh = GET_OUTHDR(ps, pm); 2433 foh = GET_OUTHDR(ps, pm);
2330 readen = foh->len - sizeof(*foh); 2434 readen = foh->len - sizeof(*foh);
2331 2435
2332 (void)memcpy(buf, _GET_OUTPAYLOAD(ps, pm, char *), readen); 2436 (void)memcpy(buf, _GET_OUTPAYLOAD(ps, pm, char *), readen);
2333 2437
2334 buf += readen; 2438 buf += readen;
2335 offset += readen; 2439 offset += readen;
@@ -2341,93 +2445,102 @@ perfuse_node_read(pu, opc, buf, offset,  @@ -2341,93 +2445,102 @@ perfuse_node_read(pu, opc, buf, offset,
2341 2445
2342 if (ioflag & (IO_SYNC|IO_DSYNC)) 2446 if (ioflag & (IO_SYNC|IO_DSYNC))
2343 ps->ps_syncreads++; 2447 ps->ps_syncreads++;
2344 else 2448 else
2345 ps->ps_asyncreads++; 2449 ps->ps_asyncreads++;
2346 2450
2347out: 2451out:
2348 if (pm != NULL) 2452 if (pm != NULL)
2349 ps->ps_destroy_msg(pm); 2453 ps->ps_destroy_msg(pm);
2350 2454
2351 ps->ps_readahead -= requested; 2455 ps->ps_readahead -= requested;
2352 dequeue_requests(ps, opc, PCQ_READ, 1); 2456 dequeue_requests(ps, opc, PCQ_READ, 1);
2353 2457
 2458 pnd->pnd_flags &= ~PND_INREAD;
 2459
2354 return error; 2460 return error;
2355} 2461}
2356 2462
2357int 2463int
2358perfuse_node_write(pu, opc, buf, offset, resid, pcr, ioflag) 2464perfuse_node_write(pu, opc, buf, offset, resid, pcr, ioflag)
2359 struct puffs_usermount *pu; 2465 struct puffs_usermount *pu;
2360 puffs_cookie_t opc; 2466 puffs_cookie_t opc;
2361 uint8_t *buf; 2467 uint8_t *buf;
2362 off_t offset; 2468 off_t offset;
2363 size_t *resid; 2469 size_t *resid;
2364 const struct puffs_cred *pcr; 2470 const struct puffs_cred *pcr;
2365 int ioflag; 2471 int ioflag;
2366{ 2472{
2367 struct perfuse_state *ps; 2473 struct perfuse_state *ps;
 2474 struct perfuse_node_data *pnd;
2368 perfuse_msg_t *pm; 2475 perfuse_msg_t *pm;
2369 struct fuse_write_in *fwi; 2476 struct fuse_write_in *fwi;
2370 struct fuse_write_out *fwo; 2477 struct fuse_write_out *fwo;
2371 size_t data_len; 2478 size_t data_len;
2372 size_t payload_len; 2479 size_t payload_len;
2373 size_t written; 2480 size_t written;
2374 size_t requested; 2481 size_t requested;
2375 int error; 2482 int error;
2376  2483
2377 ps = puffs_getspecific(pu); 2484 ps = puffs_getspecific(pu);
 2485 pnd = PERFUSE_NODE_DATA(opc);
2378 pm = NULL; 2486 pm = NULL;
2379 written = 0; 2487 written = 0;
2380 2488
 2489 if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR)
 2490 return EBADF;
 2491
 2492DPRINTF("%s ENTER\n", __func__);
 2493 pnd->pnd_flags |= PND_INWRITE;
 2494
2381 requested = *resid; 2495 requested = *resid;
2382 if ((ps->ps_write + requested) > ps->ps_max_write) { 2496 if ((ps->ps_write + requested) > ps->ps_max_write) {
2383 if (perfuse_diagflags & PDF_REQUEUE) 2497 if (perfuse_diagflags & PDF_REQUEUE)
2384 DPRINTF("write = %zd\n", ps->ps_write); 2498 DPRINTF("write = %zd\n", ps->ps_write);
2385 requeue_request(pu, opc, PCQ_WRITE); 2499 requeue_request(pu, opc, PCQ_WRITE);
2386 } 2500 }
2387 ps->ps_write += requested; 2501 ps->ps_write += requested;
2388  2502
2389 do { 2503 do {
2390 /* 2504 /*
2391 * It seems libfuse does not expects big chunks, so  2505 * It seems libfuse does not expects big chunks, so
2392 * send it page per page. The writepage feature is 2506 * send it page per page. The writepage feature is
2393 * probably there to minmize data movement. 2507 * probably there to minmize data movement.
2394 * XXX use ps->ps_maxwrite? 2508 * XXX use ps->ps_maxwrite?
2395 */ 2509 */
2396 data_len = MIN(*resid, PAGE_SIZE); 2510 data_len = MIN(*resid, PAGE_SIZE);
2397 payload_len = data_len + sizeof(*fwi); 2511 payload_len = data_len + sizeof(*fwi);
2398 2512
2399 /* 2513 /*
2400 * flags may be set to FUSE_WRITE_CACHE (XXX usage?) 2514 * flags may be set to FUSE_WRITE_CACHE (XXX usage?)
2401 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided. 2515 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided.
2402 * write_flags is set to 1 for writepage. 2516 * write_flags is set to 1 for writepage.
2403 */ 2517 */
2404 pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr); 2518 pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr);
2405 fwi = GET_INPAYLOAD(ps, pm, fuse_write_in); 2519 fwi = GET_INPAYLOAD(ps, pm, fuse_write_in);
2406 fwi->fh = perfuse_get_fh(opc); 2520 fwi->fh = perfuse_get_fh(opc, FWRITE);
2407 fwi->offset = offset; 2521 fwi->offset = offset;
2408 fwi->size = (uint32_t)data_len; 2522 fwi->size = (uint32_t)data_len;
2409 fwi->write_flags = (fwi->size % PAGE_SIZE) ? 0 : 1; 2523 fwi->write_flags = (fwi->size % PAGE_SIZE) ? 0 : 1;
2410 fwi->lock_owner = PERFUSE_NODE_DATA(opc)->pnd_lock_owner; 2524 fwi->lock_owner = pnd->pnd_lock_owner;
2411 fwi->flags = 0; 2525 fwi->flags = 0;
2412 fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0; 2526 fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0;
2413 fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE;  2527 fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE;
2414 (void)memcpy((fwi + 1), buf + written, data_len); 2528 (void)memcpy((fwi + 1), buf + written, data_len);
2415 2529
2416#ifdef PERFUSE_DEBUG 2530#ifdef PERFUSE_DEBUG
2417 if (perfuse_diagflags & PDF_FH) 2531 if (perfuse_diagflags & PDF_FH)
2418 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n", 2532 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
2419 __func__, (void *)opc, 2533 __func__, (void *)opc, pnd->pnd_ino, fwi->fh);
2420 PERFUSE_NODE_DATA(opc)->pnd_ino, fwi->fh); 
2421#endif 2534#endif
2422 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fwo))) != 0) 2535 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fwo))) != 0)
2423 goto out; 2536 goto out;
2424 2537
2425 fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out); 2538 fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out);
2426 written = fwo->size; 2539 written = fwo->size;
2427 *resid -= written; 2540 *resid -= written;
2428 offset += written; 2541 offset += written;
2429 buf += written; 2542 buf += written;
2430 2543
2431 ps->ps_destroy_msg(pm); 2544 ps->ps_destroy_msg(pm);
2432 pm = NULL; 2545 pm = NULL;
2433 } while (*resid != 0); 2546 } while (*resid != 0);
@@ -2437,41 +2550,48 @@ perfuse_node_write(pu, opc, buf, offset, @@ -2437,41 +2550,48 @@ perfuse_node_write(pu, opc, buf, offset,
2437 * "everything must be written or an error will be generated"  2550 * "everything must be written or an error will be generated"
2438 */ 2551 */
2439 if (*resid != 0) 2552 if (*resid != 0)
2440 error = EFBIG; 2553 error = EFBIG;
2441 2554
2442 if (ioflag & (IO_SYNC|IO_DSYNC)) 2555 if (ioflag & (IO_SYNC|IO_DSYNC))
2443 ps->ps_syncwrites++; 2556 ps->ps_syncwrites++;
2444 else 2557 else
2445 ps->ps_asyncwrites++; 2558 ps->ps_asyncwrites++;
2446 2559
2447 /* 2560 /*
2448 * Remember to sync the file 2561 * Remember to sync the file
2449 */ 2562 */
2450 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2563 pnd->pnd_flags |= PND_DIRTY;
2451 2564
2452#ifdef PERFUSE_DEBUG 2565#ifdef PERFUSE_DEBUG
2453 if (perfuse_diagflags & PDF_SYNC) 2566 if (perfuse_diagflags & PDF_SYNC)
2454 DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n",  2567 DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n",
2455 __func__, (void*)opc, 2568 __func__, (void*)opc,
2456 (char *)PNPATH((struct puffs_node *)opc)); 2569 (char *)PNPATH((struct puffs_node *)opc));
2457#endif 2570#endif
2458out: 2571out:
2459 if (pm != NULL) 2572 if (pm != NULL)
2460 ps->ps_destroy_msg(pm); 2573 ps->ps_destroy_msg(pm);
2461 2574
2462 ps->ps_write -= requested; 2575 ps->ps_write -= requested;
2463 dequeue_requests(ps, opc, PCQ_WRITE, 1); 2576 dequeue_requests(ps, opc, PCQ_WRITE, 1);
2464 2577
 2578 pnd->pnd_flags &= ~PND_INWRITE;
 2579
 2580 /*
 2581 * Dequeue operation that were waiting for write to complete
 2582 */
 2583 dequeue_requests(ps, opc, PCQ_AFTERWRITE, DEQUEUE_ALL);
 2584
2465 return error; 2585 return error;
2466} 2586}
2467 2587
2468/* ARGSUSED0 */ 2588/* ARGSUSED0 */
2469void 2589void
2470perfuse_cache_write(pu, opc, size, runs) 2590perfuse_cache_write(pu, opc, size, runs)
2471 struct puffs_usermount *pu; 2591 struct puffs_usermount *pu;
2472 puffs_cookie_t opc; 2592 puffs_cookie_t opc;
2473 size_t size; 2593 size_t size;
2474 struct puffs_cacherun *runs; 2594 struct puffs_cacherun *runs;
2475{ 2595{
2476 return; 2596 return;
2477} 2597}

cvs diff -r1.4 -r1.5 src/lib/libperfuse/perfuse_priv.h (expand / switch to unified diff)

--- src/lib/libperfuse/perfuse_priv.h 2010/09/01 14:57:24 1.4
+++ src/lib/libperfuse/perfuse_priv.h 2010/09/03 07:15:18 1.5
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: perfuse_priv.h,v 1.4 2010/09/01 14:57:24 manu Exp $ */ 1/* $NetBSD: perfuse_priv.h,v 1.5 2010/09/03 07:15:18 manu Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved. 4 * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
5 *  5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 *  14 *
@@ -61,57 +61,58 @@ struct perfuse_state { @@ -61,57 +61,58 @@ struct perfuse_state {
61 uint64_t ps_unique; 61 uint64_t ps_unique;
62 size_t ps_readahead; 62 size_t ps_readahead;
63 size_t ps_write; 63 size_t ps_write;
64 perfuse_new_msg_fn ps_new_msg; 64 perfuse_new_msg_fn ps_new_msg;
65 perfuse_xchg_msg_fn ps_xchg_msg; 65 perfuse_xchg_msg_fn ps_xchg_msg;
66 perfuse_destroy_msg_fn ps_destroy_msg; 66 perfuse_destroy_msg_fn ps_destroy_msg;
67 perfuse_get_inhdr_fn ps_get_inhdr; 67 perfuse_get_inhdr_fn ps_get_inhdr;
68 perfuse_get_inpayload_fn ps_get_inpayload; 68 perfuse_get_inpayload_fn ps_get_inpayload;
69 perfuse_get_outhdr_fn ps_get_outhdr; 69 perfuse_get_outhdr_fn ps_get_outhdr;
70 perfuse_get_outpayload_fn ps_get_outpayload; 70 perfuse_get_outpayload_fn ps_get_outpayload;
71}; 71};
72 72
73 73
74struct perfuse_file_handle { 74enum perfuse_qtype { PCQ_READDIR, PCQ_READ, PCQ_WRITE, PCQ_AFTERWRITE };
75 uint64_t pfh_fh; 
76 TAILQ_ENTRY(perfuse_file_handle) pfh_entries; 
77}; 
78 
79 
80enum perfuse_qtype { PCQ_READDIR, PCQ_READ, PCQ_WRITE }; 
81 75
82struct perfuse_cc_queue { 76struct perfuse_cc_queue {
83 enum perfuse_qtype pcq_type; 77 enum perfuse_qtype pcq_type;
84 struct puffs_cc *pcq_cc; 78 struct puffs_cc *pcq_cc;
85 TAILQ_ENTRY(perfuse_cc_queue) pcq_next; 79 TAILQ_ENTRY(perfuse_cc_queue) pcq_next;
86}; 80};
87 81
88 82
89struct perfuse_node_data { 83struct perfuse_node_data {
90 TAILQ_HEAD(,perfuse_file_handle) pnd_fh; 84 uint64_t pnd_rfh;
 85 uint64_t pnd_wfh;
91 uint64_t pnd_ino; /* inode */ 86 uint64_t pnd_ino; /* inode */
92 uint64_t pnd_nlookup; /* vnode refcount */ 87 uint64_t pnd_nlookup; /* vnode refcount */
93 uint64_t pnd_offset; /* seek state */ 88 uint64_t pnd_offset; /* seek state */
94 uint64_t pnd_lock_owner; 89 uint64_t pnd_lock_owner;
95 struct dirent *pnd_dirent; /* native buffer for readdir */ 90 struct dirent *pnd_dirent; /* native buffer for readdir */
96 size_t pnd_dirent_len; 91 size_t pnd_dirent_len;
97 struct fuse_dirent *pnd_all_fd; /* FUSE buffer for readdir */ 92 struct fuse_dirent *pnd_all_fd; /* FUSE buffer for readdir */
98 size_t pnd_all_fd_len; 93 size_t pnd_all_fd_len;
99 TAILQ_HEAD(,perfuse_cc_queue) pnd_pcq; /* queued requests */ 94 TAILQ_HEAD(,perfuse_cc_queue) pnd_pcq; /* queued requests */
100 int pnd_flags; 95 int pnd_flags;
101#define PND_RECLAIMED 0x1 /* reclaim pending */ 96#define PND_RECLAIMED 0x01 /* reclaim pending */
102#define PND_INREADDIR 0x2 /* readdir in progress */ 97#define PND_INREADDIR 0x02 /* readdir in progress */
103#define PND_OPEN 0x4 /* At least one fh is allocated */ 98#define PND_DIRTY 0x04 /* There is some data to sync */
104#define PND_DIRTY 0x8 /* There is some data to sync */ 99#define PND_RFH 0x08 /* Read FH allocated */
 100#define PND_WFH 0x10 /* Write FH allocated */
 101#define PND_INREAD 0x20 /* read in progress */
 102#define PND_INWRITE 0x40 /* write in progress */
 103
 104#define PND_OPEN (PND_RFH|PND_WFH) /* File is open */
 105#define PND_BUSY (PND_INREADDIR|PND_INREAD|PND_INWRITE)
105 puffs_cookie_t pnd_parent; 106 puffs_cookie_t pnd_parent;
106 int pnd_childcount; 107 int pnd_childcount;
107}; 108};
108 109
109#define PERFUSE_NODE_DATA(opc) \ 110#define PERFUSE_NODE_DATA(opc) \
110 ((struct perfuse_node_data *)puffs_pn_getpriv((struct puffs_node *)opc)) 111 ((struct perfuse_node_data *)puffs_pn_getpriv((struct puffs_node *)opc))
111 112
112 113
113#define UNSPEC_REPLY_LEN PERFUSE_UNSPEC_REPLY_LEN /* shorter! */ 114#define UNSPEC_REPLY_LEN PERFUSE_UNSPEC_REPLY_LEN /* shorter! */
114#define NO_PAYLOAD_REPLY_LEN 0 115#define NO_PAYLOAD_REPLY_LEN 0
115 116
116#define GET_INHDR(ps, pm) ps->ps_get_inhdr(pm) 117#define GET_INHDR(ps, pm) ps->ps_get_inhdr(pm)
117#define GET_INPAYLOAD(ps, pm, type) \ 118#define GET_INPAYLOAD(ps, pm, type) \
@@ -121,29 +122,29 @@ struct perfuse_node_data { @@ -121,29 +122,29 @@ struct perfuse_node_data {
121#define GET_OUTPAYLOAD(ps, pm, type) \ 122#define GET_OUTPAYLOAD(ps, pm, type) \
122 (struct type *)(void *)ps->ps_get_outpayload(pm) 123 (struct type *)(void *)ps->ps_get_outpayload(pm)
123#define _GET_OUTPAYLOAD(ps, pm, type) (type)ps->ps_get_outpayload(pm) 124#define _GET_OUTPAYLOAD(ps, pm, type) (type)ps->ps_get_outpayload(pm)
124 125
125#define XCHG_MSG(ps, pu, opc, len) ps->ps_xchg_msg(pu, opc, len, wait_reply) 126#define XCHG_MSG(ps, pu, opc, len) ps->ps_xchg_msg(pu, opc, len, wait_reply)
126#define XCHG_MSG_NOREPLY(ps, pu, opc, len) \ 127#define XCHG_MSG_NOREPLY(ps, pu, opc, len) \
127 ps->ps_xchg_msg(pu, opc, len, no_reply) 128 ps->ps_xchg_msg(pu, opc, len, no_reply)
128 129
129__BEGIN_DECLS 130__BEGIN_DECLS
130 131
131struct puffs_node *perfuse_new_pn(struct puffs_usermount *,  132struct puffs_node *perfuse_new_pn(struct puffs_usermount *,
132 struct puffs_node *); 133 struct puffs_node *);
133void perfuse_destroy_pn(struct puffs_node *); 134void perfuse_destroy_pn(struct puffs_node *);
134void perfuse_new_fh(puffs_cookie_t, uint64_t); 135void perfuse_new_fh(puffs_cookie_t, uint64_t, int);
135void perfuse_destroy_fh(puffs_cookie_t, uint64_t); 136void perfuse_destroy_fh(puffs_cookie_t, uint64_t);
136uint64_t perfuse_get_fh(puffs_cookie_t); 137uint64_t perfuse_get_fh(puffs_cookie_t, int);
137uint64_t perfuse_next_unique(struct puffs_usermount *); 138uint64_t perfuse_next_unique(struct puffs_usermount *);
138 139
139char *perfuse_fs_mount(int, ssize_t); 140char *perfuse_fs_mount(int, ssize_t);
140 141
141 142
142/* 143/*
143 * opc.c - filesystem operations 144 * opc.c - filesystem operations
144 */ 145 */
145int perfuse_fs_unmount(struct puffs_usermount *, int); 146int perfuse_fs_unmount(struct puffs_usermount *, int);
146int perfuse_fs_statvfs(struct puffs_usermount *, struct statvfs *); 147int perfuse_fs_statvfs(struct puffs_usermount *, struct statvfs *);
147int perfuse_fs_sync(struct puffs_usermount *, int, 148int perfuse_fs_sync(struct puffs_usermount *, int,
148 const struct puffs_cred *); 149 const struct puffs_cred *);
149int perfuse_fs_fhtonode(struct puffs_usermount *, void *, size_t, 150int perfuse_fs_fhtonode(struct puffs_usermount *, void *, size_t,

cvs diff -r1.3 -r1.4 src/lib/libperfuse/subr.c (expand / switch to unified diff)

--- src/lib/libperfuse/subr.c 2010/09/01 14:57:24 1.3
+++ src/lib/libperfuse/subr.c 2010/09/03 07:15:18 1.4
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: subr.c,v 1.3 2010/09/01 14:57:24 manu Exp $ */ 1/* $NetBSD: subr.c,v 1.4 2010/09/03 07:15:18 manu Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved. 4 * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
5 *  5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 *  14 *
@@ -41,27 +41,28 @@ perfuse_new_pn(pu, parent) @@ -41,27 +41,28 @@ perfuse_new_pn(pu, parent)
41 struct puffs_usermount *pu; 41 struct puffs_usermount *pu;
42 struct puffs_node *parent; 42 struct puffs_node *parent;
43{ 43{
44 struct puffs_node *pn; 44 struct puffs_node *pn;
45 struct perfuse_node_data *pnd; 45 struct perfuse_node_data *pnd;
46 46
47 if ((pnd = malloc(sizeof(*pnd))) == NULL) 47 if ((pnd = malloc(sizeof(*pnd))) == NULL)
48 DERR(EX_OSERR, "malloc failed"); 48 DERR(EX_OSERR, "malloc failed");
49 49
50 if ((pn = puffs_pn_new(pu, pnd)) == NULL) 50 if ((pn = puffs_pn_new(pu, pnd)) == NULL)
51 DERR(EX_SOFTWARE, "puffs_pn_new failed"); 51 DERR(EX_SOFTWARE, "puffs_pn_new failed");
52 52
53 (void)memset(pnd, 0, sizeof(*pnd)); 53 (void)memset(pnd, 0, sizeof(*pnd));
54 TAILQ_INIT(&pnd->pnd_fh); 54 pnd->pnd_rfh = FUSE_UNKNOWN_FH;
 55 pnd->pnd_wfh = FUSE_UNKNOWN_FH;
55 pnd->pnd_ino = PERFUSE_UNKNOWN_INO; 56 pnd->pnd_ino = PERFUSE_UNKNOWN_INO;
56 pnd->pnd_nlookup = 1; 57 pnd->pnd_nlookup = 1;
57 pnd->pnd_parent = parent; 58 pnd->pnd_parent = parent;
58 TAILQ_INIT(&pnd->pnd_pcq); 59 TAILQ_INIT(&pnd->pnd_pcq);
59 60
60 if (parent != NULL) 61 if (parent != NULL)
61 PERFUSE_NODE_DATA(parent)->pnd_childcount++; 62 PERFUSE_NODE_DATA(parent)->pnd_childcount++;
62 63
63 return pn; 64 return pn;
64} 65}
65 66
66void 67void
67perfuse_destroy_pn(pn) 68perfuse_destroy_pn(pn)
@@ -69,98 +70,112 @@ perfuse_destroy_pn(pn) @@ -69,98 +70,112 @@ perfuse_destroy_pn(pn)
69{ 70{
70 struct perfuse_node_data *pnd; 71 struct perfuse_node_data *pnd;
71 72
72 if ((pnd = puffs_pn_getpriv(pn)) != NULL) { 73 if ((pnd = puffs_pn_getpriv(pn)) != NULL) {
73 if (pnd->pnd_parent != NULL) 74 if (pnd->pnd_parent != NULL)
74 PERFUSE_NODE_DATA(pnd->pnd_parent)->pnd_childcount--; 75 PERFUSE_NODE_DATA(pnd->pnd_parent)->pnd_childcount--;
75 76
76 if (pnd->pnd_dirent != NULL) 77 if (pnd->pnd_dirent != NULL)
77 free(pnd->pnd_dirent); 78 free(pnd->pnd_dirent);
78 79
79 if (pnd->pnd_all_fd != NULL) 80 if (pnd->pnd_all_fd != NULL)
80 free(pnd->pnd_all_fd); 81 free(pnd->pnd_all_fd);
81#ifdef PERFUSE_DEBUG 82#ifdef PERFUSE_DEBUG
82 if (!TAILQ_EMPTY(&pnd->pnd_fh)) 83 if (pnd->pnd_flags & PND_OPEN)
83 DERRX(EX_SOFTWARE, "%s: non empty pnd_fh", __func__); 84 DERRX(EX_SOFTWARE, "%s: file open", __func__);
84 85
85 if (!TAILQ_EMPTY(&pnd->pnd_pcq)) 86 if (!TAILQ_EMPTY(&pnd->pnd_pcq))
86 DERRX(EX_SOFTWARE, "%s: non empty pnd_pcq", __func__); 87 DERRX(EX_SOFTWARE, "%s: non empty pnd_pcq", __func__);
87#endif /* PERFUSE_DEBUG */ 88#endif /* PERFUSE_DEBUG */
88 89
89 free(pnd); 90 free(pnd);
90 } 91 }
91 92
92 puffs_pn_remove(pn); 93 puffs_pn_remove(pn);
93 94
94 return; 95 return;
95} 96}
96 97
97 98
98void 99void
99perfuse_new_fh(opc, fh) 100perfuse_new_fh(opc, fh, mode)
100 puffs_cookie_t opc; 101 puffs_cookie_t opc;
101 uint64_t fh; 102 uint64_t fh;
 103 int mode;
102{ 104{
103 struct perfuse_node_data *pnd; 105 struct perfuse_node_data *pnd;
104 struct perfuse_file_handle *pfh; 
105 
106 if (fh == FUSE_UNKNOWN_FH) 
107 return; 
108 106
109 pnd = PERFUSE_NODE_DATA(opc); 107 pnd = PERFUSE_NODE_DATA(opc);
110 pnd->pnd_flags |= PND_OPEN; 
111 
112 if ((pfh = malloc(sizeof(*pfh))) == NULL) 
113 DERR(EX_OSERR, "malloc failed"); 
114 
115 pfh->pfh_fh = fh; 
116 108
117 TAILQ_INSERT_TAIL(&pnd->pnd_fh, pfh, pfh_entries); 109 if (mode & FWRITE) {
 110 if (pnd->pnd_flags & PND_WFH)
 111 DERRX(EX_SOFTWARE, "%s: opc = %p, write fh already set",
 112 __func__, (void *)opc);
 113 pnd->pnd_wfh = fh;
 114 pnd->pnd_flags |= PND_WFH;
 115 }
 116
 117 if (mode & FREAD) {
 118 if (pnd->pnd_flags & PND_RFH)
 119 DERRX(EX_SOFTWARE, "%s: opc = %p, read fh already set",
 120 __func__, (void *)opc);
 121 pnd->pnd_rfh = fh;
 122 pnd->pnd_flags |= PND_RFH;
 123 }
118 124
119 return; 125 return;
120} 126}
121 127
122void 128void
123perfuse_destroy_fh(opc, fh) 129perfuse_destroy_fh(opc, fh)
124 puffs_cookie_t opc; 130 puffs_cookie_t opc;
125 uint64_t fh;  131 uint64_t fh;
126{ 132{
127 struct perfuse_node_data *pnd; 133 struct perfuse_node_data *pnd;
128 struct perfuse_file_handle *pfh; 
129 134
130 pnd = PERFUSE_NODE_DATA(opc); 135 pnd = PERFUSE_NODE_DATA(opc);
131 136
132 TAILQ_FOREACH(pfh, &pnd->pnd_fh, pfh_entries) { 137 if (fh == pnd->pnd_rfh) {
133 if (pfh->pfh_fh == fh) { 138 if (!(pnd->pnd_flags & PND_RFH) && (fh != FUSE_UNKNOWN_FH))
134 TAILQ_REMOVE(&pnd->pnd_fh, pfh, pfh_entries); 139 DERRX(EX_SOFTWARE,
135 free(pfh); 140 "%s: opc = %p, unset rfh = %"PRIx64"",
136 break; 141 __func__, (void *)opc, fh);
137 } 142 pnd->pnd_rfh = FUSE_UNKNOWN_FH;
 143 pnd->pnd_flags &= ~PND_RFH;
138 } 144 }
139 145
140 if (TAILQ_EMPTY(&pnd->pnd_fh)) 146 if (fh == pnd->pnd_wfh) {
141 pnd->pnd_flags &= ~PND_OPEN; 147 if (!(pnd->pnd_flags & PND_WFH) && (fh != FUSE_UNKNOWN_FH))
 148 DERRX(EX_SOFTWARE,
 149 "%s: opc = %p, unset wfh = %"PRIx64"",
 150 __func__, (void *)opc, fh);
 151 pnd->pnd_wfh = FUSE_UNKNOWN_FH;
 152 pnd->pnd_flags &= ~PND_WFH;
 153 }
142 154
143 if (pfh == NULL) 
144 DERRX(EX_SOFTWARE,  
145 "%s: unexistant fh = %"PRId64" (double close?)", 
146 __func__, fh); 
147  
148 return; 155 return;
149} 156}
150 157
151uint64_t 158uint64_t
152perfuse_get_fh(opc) 159perfuse_get_fh(opc, mode)
153 puffs_cookie_t opc; 160 puffs_cookie_t opc;
 161 int mode;
154{ 162{
155 struct perfuse_node_data *pnd; 163 struct perfuse_node_data *pnd;
156 struct perfuse_file_handle *pfh; 
157 uint64_t fh = FUSE_UNKNOWN_FH; 
158 164
159 pnd = PERFUSE_NODE_DATA(opc); 165 pnd = PERFUSE_NODE_DATA(opc);
160 166
161 if ((pfh = TAILQ_FIRST(&pnd->pnd_fh)) != NULL) 167 if (mode & FWRITE)
162 fh = pfh->pfh_fh;; 168 if (pnd->pnd_flags & PND_WFH)
 169 return pnd->pnd_wfh;
 170
 171 if (mode & FREAD) {
 172 if (pnd->pnd_flags & PND_RFH)
 173 return pnd->pnd_rfh;
 174
 175 if (pnd->pnd_flags & PND_WFH)
 176 return pnd->pnd_wfh;
 177 }
163 178
164 return fh; 179 return FUSE_UNKNOWN_FH;
165} 180}
166 181