1 1.92 msaitoh /* $NetBSD: ops.c,v 1.92 2023/06/24 05:18:13 msaitoh Exp $ */ 2 1.1 manu 3 1.1 manu /*- 4 1.24 manu * Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved. 5 1.1 manu * 6 1.1 manu * Redistribution and use in source and binary forms, with or without 7 1.1 manu * modification, are permitted provided that the following conditions 8 1.1 manu * are met: 9 1.1 manu * 1. Redistributions of source code must retain the above copyright 10 1.1 manu * notice, this list of conditions and the following disclaimer. 11 1.1 manu * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 manu * notice, this list of conditions and the following disclaimer in the 13 1.1 manu * documentation and/or other materials provided with the distribution. 14 1.1 manu * 15 1.1 manu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 1.1 manu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 1.1 manu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 1.1 manu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 1.1 manu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 1.1 manu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 1.1 manu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 1.1 manu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 1.1 manu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 1.1 manu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 1.1 manu * POSSIBILITY OF SUCH DAMAGE. 26 1.1 manu */ 27 1.1 manu 28 1.1 manu #include <stdio.h> 29 1.1 manu #include <unistd.h> 30 1.1 manu #include <stdlib.h> 31 1.1 manu #include <libgen.h> 32 1.1 manu #include <errno.h> 33 1.1 manu #include <err.h> 34 1.1 manu #include <sysexits.h> 35 1.1 manu #include <syslog.h> 36 1.1 manu #include <puffs.h> 37 1.59 manu #include <sys/socket.h> 38 1.1 manu #include <sys/socket.h> 39 1.31 manu #include <sys/extattr.h> 40 1.49 manu #include <sys/time.h> 41 1.1 manu #include <machine/vmparam.h> 42 1.1 manu 43 1.1 manu #include "perfuse_priv.h" 44 1.1 manu #include "fuse.h" 45 1.1 manu 46 1.12 manu extern int perfuse_diagflags; 47 1.12 manu 48 1.47 manu #if 0 49 1.47 manu static void print_node(const char *, puffs_cookie_t); 50 1.47 manu #endif 51 1.54 manu #ifdef PUFFS_KFLAG_CACHE_FS_TTL 52 1.54 manu static void perfuse_newinfo_setttl(struct puffs_newinfo *, 53 1.59 manu struct puffs_node *, struct fuse_entry_out *, struct fuse_attr_out *); 54 1.53 manu #endif /* PUFFS_KFLAG_CACHE_FS_TTL */ 55 1.16 manu static int xchg_msg(struct puffs_usermount *, puffs_cookie_t, 56 1.16 manu perfuse_msg_t *, size_t, enum perfuse_xchg_pb_reply); 57 1.24 manu static int mode_access(puffs_cookie_t, const struct puffs_cred *, mode_t); 58 1.59 manu static int sticky_access(puffs_cookie_t, struct puffs_node *, 59 1.59 manu const struct puffs_cred *); 60 1.1 manu static void fuse_attr_to_vap(struct perfuse_state *, 61 1.1 manu struct vattr *, struct fuse_attr *); 62 1.1 manu static int node_lookup_common(struct puffs_usermount *, puffs_cookie_t, 63 1.54 manu struct puffs_newinfo *, const char *, const struct puffs_cred *, 64 1.54 manu struct puffs_node **); 65 1.1 manu static int node_mk_common(struct puffs_usermount *, puffs_cookie_t, 66 1.6 manu struct puffs_newinfo *, const struct puffs_cn *pcn, perfuse_msg_t *); 67 1.33 manu static uint64_t readdir_last_cookie(struct fuse_dirent *, size_t); 68 1.1 manu static ssize_t fuse_to_dirent(struct puffs_usermount *, puffs_cookie_t, 69 1.1 manu struct fuse_dirent *, size_t); 70 1.59 manu static void readdir_buffered(puffs_cookie_t, struct dirent *, off_t *, 71 1.33 manu size_t *); 72 1.59 manu static void node_ref(puffs_cookie_t); 73 1.59 manu static void node_rele(puffs_cookie_t); 74 1.1 manu static void requeue_request(struct puffs_usermount *, 75 1.1 manu puffs_cookie_t opc, enum perfuse_qtype); 76 1.59 manu static int dequeue_requests(puffs_cookie_t opc, enum perfuse_qtype, int); 77 1.1 manu #define DEQUEUE_ALL 0 78 1.1 manu 79 1.1 manu /* 80 1.1 manu * From <sys/vnode>, inside #ifdef _KERNEL section 81 1.1 manu */ 82 1.1 manu #define IO_SYNC (0x40|IO_DSYNC) 83 1.1 manu #define IO_DSYNC 0x00200 84 1.1 manu #define IO_DIRECT 0x02000 85 1.1 manu 86 1.1 manu /* 87 1.1 manu * From <fcntl>, inside #ifdef _KERNEL section 88 1.1 manu */ 89 1.1 manu #define F_WAIT 0x010 90 1.1 manu #define F_FLOCK 0x020 91 1.7 manu #define OFLAGS(fflags) ((fflags) - 1) 92 1.1 manu 93 1.1 manu /* 94 1.1 manu * Borrowed from src/sys/kern/vfs_subr.c and src/sys/sys/vnode.h 95 1.1 manu */ 96 1.1 manu const enum vtype iftovt_tab[16] = { 97 1.1 manu VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 98 1.1 manu VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 99 1.1 manu }; 100 1.1 manu const int vttoif_tab[9] = { 101 1.1 manu 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 102 1.1 manu S_IFSOCK, S_IFIFO, S_IFMT, 103 1.1 manu }; 104 1.1 manu 105 1.1 manu #define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12]) 106 1.1 manu #define VTTOIF(indx) (vttoif_tab[(int)(indx)]) 107 1.1 manu 108 1.86 manu #define PN_ISDIR(opc) \ 109 1.86 manu (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR) 110 1.86 manu 111 1.47 manu #if 0 112 1.47 manu static void 113 1.52 matt print_node(const char *func, puffs_cookie_t opc) 114 1.47 manu { 115 1.47 manu struct puffs_node *pn; 116 1.47 manu struct perfuse_node_data *pnd; 117 1.47 manu struct vattr *vap; 118 1.47 manu 119 1.47 manu pn = (struct puffs_node *)opc; 120 1.47 manu pnd = PERFUSE_NODE_DATA(opc); 121 1.47 manu vap = &pn->pn_va; 122 1.47 manu 123 1.47 manu printf("%s: \"%s\", opc = %p, nodeid = 0x%"PRIx64" ino = %"PRIu64"\n", 124 1.47 manu func, pnd->pnd_name, opc, pnd->pnd_nodeid, vap->va_fileid); 125 1.47 manu 126 1.47 manu return; 127 1.47 manu } 128 1.47 manu #endif /* PERFUSE_DEBUG */ 129 1.47 manu 130 1.16 manu int 131 1.52 matt perfuse_node_close_common(struct puffs_usermount *pu, puffs_cookie_t opc, 132 1.52 matt int mode) 133 1.7 manu { 134 1.7 manu struct perfuse_state *ps; 135 1.7 manu perfuse_msg_t *pm; 136 1.7 manu int op; 137 1.7 manu uint64_t fh; 138 1.7 manu struct fuse_release_in *fri; 139 1.7 manu struct perfuse_node_data *pnd; 140 1.7 manu struct puffs_node *pn; 141 1.7 manu int error; 142 1.7 manu 143 1.7 manu ps = puffs_getspecific(pu); 144 1.7 manu pn = (struct puffs_node *)opc; 145 1.7 manu pnd = PERFUSE_NODE_DATA(pn); 146 1.7 manu 147 1.86 manu if (PN_ISDIR(opc)) { 148 1.7 manu op = FUSE_RELEASEDIR; 149 1.7 manu mode = FREAD; 150 1.7 manu } else { 151 1.7 manu op = FUSE_RELEASE; 152 1.7 manu } 153 1.7 manu 154 1.7 manu /* 155 1.7 manu * Destroy the filehandle before sending the 156 1.7 manu * request to the FUSE filesystem, otherwise 157 1.7 manu * we may get a second close() while we wait 158 1.7 manu * for the reply, and we would end up closing 159 1.7 manu * the same fh twice instead of closng both. 160 1.7 manu */ 161 1.7 manu fh = perfuse_get_fh(opc, mode); 162 1.7 manu perfuse_destroy_fh(pn, fh); 163 1.7 manu 164 1.7 manu /* 165 1.7 manu * release_flags may be set to FUSE_RELEASE_FLUSH 166 1.7 manu * to flush locks. lock_owner must be set in that case 167 1.36 manu * 168 1.36 manu * ps_new_msg() is called with NULL creds, which will 169 1.36 manu * be interpreted as FUSE superuser. We come here from the 170 1.36 manu * inactive method, which provides no creds, but obviously 171 1.36 manu * runs with kernel privilege. 172 1.7 manu */ 173 1.7 manu pm = ps->ps_new_msg(pu, opc, op, sizeof(*fri), NULL); 174 1.7 manu fri = GET_INPAYLOAD(ps, pm, fuse_release_in); 175 1.7 manu fri->fh = fh; 176 1.7 manu fri->flags = 0; 177 1.7 manu fri->release_flags = 0; 178 1.7 manu fri->lock_owner = pnd->pnd_lock_owner; 179 1.7 manu fri->flags = (fri->lock_owner != 0) ? FUSE_RELEASE_FLUSH : 0; 180 1.7 manu 181 1.7 manu #ifdef PERFUSE_DEBUG 182 1.7 manu if (perfuse_diagflags & PDF_FH) 183 1.43 manu DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 184 1.43 manu __func__, (void *)opc, pnd->pnd_nodeid, fri->fh); 185 1.7 manu #endif 186 1.7 manu 187 1.16 manu if ((error = xchg_msg(pu, opc, pm, 188 1.16 manu NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0) 189 1.48 manu DERRX(EX_SOFTWARE, "%s: freed fh = 0x%"PRIx64" but filesystem " 190 1.48 manu "returned error = %d", __func__, fh, error); 191 1.7 manu 192 1.7 manu ps->ps_destroy_msg(pm); 193 1.7 manu 194 1.48 manu return 0; 195 1.7 manu } 196 1.1 manu 197 1.16 manu static int 198 1.52 matt xchg_msg(struct puffs_usermount *pu, puffs_cookie_t opc, perfuse_msg_t *pm, 199 1.52 matt size_t len, enum perfuse_xchg_pb_reply wait) 200 1.16 manu { 201 1.16 manu struct perfuse_state *ps; 202 1.18 manu struct perfuse_node_data *pnd; 203 1.49 manu struct perfuse_trace *pt = NULL; 204 1.16 manu int error; 205 1.16 manu 206 1.16 manu ps = puffs_getspecific(pu); 207 1.18 manu pnd = NULL; 208 1.18 manu if ((struct puffs_node *)opc != NULL) 209 1.18 manu pnd = PERFUSE_NODE_DATA(opc); 210 1.16 manu 211 1.16 manu #ifdef PERFUSE_DEBUG 212 1.17 manu if ((perfuse_diagflags & PDF_FILENAME) && (opc != 0)) 213 1.43 manu DPRINTF("file = \"%s\", ino = %"PRIu64" flags = 0x%x\n", 214 1.59 manu perfuse_node_path(ps, opc), 215 1.43 manu ((struct puffs_node *)opc)->pn_va.va_fileid, 216 1.17 manu PERFUSE_NODE_DATA(opc)->pnd_flags); 217 1.16 manu #endif 218 1.59 manu ps->ps_xchgcount++; 219 1.18 manu if (pnd) 220 1.59 manu pnd->pnd_inxchg++; 221 1.18 manu 222 1.49 manu /* 223 1.49 manu * Record FUSE call start if requested 224 1.49 manu */ 225 1.50 manu if (perfuse_diagflags & PDF_TRACE) 226 1.50 manu pt = perfuse_trace_begin(ps, opc, pm); 227 1.49 manu 228 1.49 manu /* 229 1.49 manu * Do actual FUSE exchange 230 1.49 manu */ 231 1.48 manu if ((error = ps->ps_xchg_msg(pu, pm, len, wait)) != 0) 232 1.48 manu ps->ps_destroy_msg(pm); 233 1.16 manu 234 1.49 manu /* 235 1.49 manu * Record FUSE call end if requested 236 1.49 manu */ 237 1.50 manu if (pt != NULL) 238 1.50 manu perfuse_trace_end(ps, pt, error); 239 1.49 manu 240 1.59 manu ps->ps_xchgcount--; 241 1.18 manu if (pnd) { 242 1.59 manu pnd->pnd_inxchg--; 243 1.59 manu (void)dequeue_requests(opc, PCQ_AFTERXCHG, DEQUEUE_ALL); 244 1.18 manu } 245 1.18 manu 246 1.16 manu return error; 247 1.16 manu } 248 1.16 manu 249 1.4 manu static int 250 1.52 matt mode_access(puffs_cookie_t opc, const struct puffs_cred *pcr, mode_t mode) 251 1.4 manu { 252 1.4 manu struct puffs_node *pn; 253 1.4 manu struct vattr *va; 254 1.4 manu 255 1.19 manu /* 256 1.19 manu * pcr is NULL for self open through fsync or readdir. 257 1.19 manu * In both case, access control is useless, as it was 258 1.19 manu * done before, at open time. 259 1.19 manu */ 260 1.19 manu if (pcr == NULL) 261 1.19 manu return 0; 262 1.19 manu 263 1.4 manu pn = (struct puffs_node *)opc; 264 1.4 manu va = puffs_pn_getvap(pn); 265 1.4 manu return puffs_access(va->va_type, va->va_mode, 266 1.4 manu va->va_uid, va->va_gid, 267 1.4 manu mode, pcr); 268 1.4 manu } 269 1.4 manu 270 1.24 manu static int 271 1.59 manu sticky_access(puffs_cookie_t opc, struct puffs_node *targ, 272 1.59 manu const struct puffs_cred *pcr) 273 1.24 manu { 274 1.24 manu uid_t uid; 275 1.71 manu int sticky, owner, parent_owner; 276 1.24 manu 277 1.36 manu /* 278 1.36 manu * This covers the case where the kernel requests a DELETE 279 1.36 manu * or RENAME on its own, and where puffs_cred_getuid would 280 1.36 manu * return -1. While such a situation should not happen, 281 1.36 manu * we allow it here. 282 1.36 manu * 283 1.36 manu * This also allows root to tamper with other users' files 284 1.36 manu * that have the sticky bit. 285 1.36 manu */ 286 1.36 manu if (puffs_cred_isjuggernaut(pcr)) 287 1.36 manu return 0; 288 1.36 manu 289 1.36 manu if (puffs_cred_getuid(pcr, &uid) != 0) 290 1.36 manu DERRX(EX_SOFTWARE, "puffs_cred_getuid fails in %s", __func__); 291 1.24 manu 292 1.59 manu sticky = puffs_pn_getvap(opc)->va_mode & S_ISTXT; 293 1.24 manu owner = puffs_pn_getvap(targ)->va_uid == uid; 294 1.71 manu parent_owner = puffs_pn_getvap(opc)->va_uid == uid; 295 1.24 manu 296 1.71 manu if (sticky && !owner && !parent_owner) 297 1.71 manu return EPERM; 298 1.24 manu 299 1.38 manu return 0; 300 1.24 manu } 301 1.24 manu 302 1.24 manu 303 1.1 manu static void 304 1.52 matt fuse_attr_to_vap(struct perfuse_state *ps, struct vattr *vap, 305 1.52 matt struct fuse_attr *fa) 306 1.1 manu { 307 1.1 manu vap->va_type = IFTOVT(fa->mode); 308 1.24 manu vap->va_mode = fa->mode & ALLPERMS; 309 1.1 manu vap->va_nlink = fa->nlink; 310 1.1 manu vap->va_uid = fa->uid; 311 1.1 manu vap->va_gid = fa->gid; 312 1.27 manu vap->va_fsid = (long)ps->ps_fsid; 313 1.1 manu vap->va_fileid = fa->ino; 314 1.1 manu vap->va_size = fa->size; 315 1.1 manu vap->va_blocksize = fa->blksize; 316 1.5 manu vap->va_atime.tv_sec = (time_t)fa->atime; 317 1.5 manu vap->va_atime.tv_nsec = (long) fa->atimensec; 318 1.5 manu vap->va_mtime.tv_sec = (time_t)fa->mtime; 319 1.5 manu vap->va_mtime.tv_nsec = (long)fa->mtimensec; 320 1.5 manu vap->va_ctime.tv_sec = (time_t)fa->ctime; 321 1.5 manu vap->va_ctime.tv_nsec = (long)fa->ctimensec; 322 1.1 manu vap->va_birthtime.tv_sec = 0; 323 1.1 manu vap->va_birthtime.tv_nsec = 0; 324 1.1 manu vap->va_gen = 0; 325 1.1 manu vap->va_flags = 0; 326 1.1 manu vap->va_rdev = fa->rdev; 327 1.76 manu vap->va_bytes = fa->blocks * S_BLKSIZE; 328 1.21 manu vap->va_filerev = (u_quad_t)PUFFS_VNOVAL; 329 1.1 manu vap->va_vaflags = 0; 330 1.1 manu 331 1.1 manu if (vap->va_blocksize == 0) 332 1.1 manu vap->va_blocksize = DEV_BSIZE; 333 1.1 manu 334 1.21 manu if (vap->va_size == (size_t)PUFFS_VNOVAL) /* XXX */ 335 1.1 manu vap->va_size = 0; 336 1.1 manu 337 1.1 manu return; 338 1.1 manu } 339 1.1 manu 340 1.54 manu #ifdef PUFFS_KFLAG_CACHE_FS_TTL 341 1.59 manu static void 342 1.59 manu perfuse_newinfo_setttl(struct puffs_newinfo *pni, 343 1.59 manu struct puffs_node *pn, struct fuse_entry_out *feo, 344 1.59 manu struct fuse_attr_out *fao) 345 1.54 manu { 346 1.54 manu #ifdef PERFUSE_DEBUG 347 1.54 manu if ((feo == NULL) && (fao == NULL)) 348 1.54 manu DERRX(EX_SOFTWARE, "%s: feo and fao NULL", __func__); 349 1.54 manu 350 1.54 manu if ((feo != NULL) && (fao != NULL)) 351 1.54 manu DERRX(EX_SOFTWARE, "%s: feo and fao != NULL", __func__); 352 1.54 manu #endif /* PERFUSE_DEBUG */ 353 1.54 manu 354 1.54 manu if (fao != NULL) { 355 1.54 manu struct timespec va_ttl; 356 1.54 manu 357 1.54 manu va_ttl.tv_sec = fao->attr_valid; 358 1.54 manu va_ttl.tv_nsec = fao->attr_valid_nsec; 359 1.54 manu 360 1.54 manu puffs_newinfo_setvattl(pni, &va_ttl); 361 1.54 manu } 362 1.54 manu 363 1.54 manu if (feo != NULL) { 364 1.54 manu struct timespec va_ttl; 365 1.54 manu struct timespec cn_ttl; 366 1.59 manu struct timespec now; 367 1.59 manu struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(pn); 368 1.54 manu 369 1.54 manu va_ttl.tv_sec = feo->attr_valid; 370 1.54 manu va_ttl.tv_nsec = feo->attr_valid_nsec; 371 1.54 manu cn_ttl.tv_sec = feo->entry_valid; 372 1.54 manu cn_ttl.tv_nsec = feo->entry_valid_nsec; 373 1.54 manu 374 1.54 manu puffs_newinfo_setvattl(pni, &va_ttl); 375 1.54 manu puffs_newinfo_setcnttl(pni, &cn_ttl); 376 1.59 manu 377 1.59 manu if (clock_gettime(CLOCK_REALTIME, &now) != 0) 378 1.59 manu DERR(EX_OSERR, "clock_gettime failed"); 379 1.59 manu 380 1.59 manu timespecadd(&now, &cn_ttl, &pnd->pnd_cn_expire); 381 1.54 manu } 382 1.54 manu 383 1.54 manu return; 384 1.54 manu } 385 1.53 manu #endif /* PUFFS_KFLAG_CACHE_FS_TTL */ 386 1.43 manu 387 1.1 manu static int 388 1.52 matt node_lookup_common(struct puffs_usermount *pu, puffs_cookie_t opc, 389 1.54 manu struct puffs_newinfo *pni, const char *path, 390 1.54 manu const struct puffs_cred *pcr, struct puffs_node **pnp) 391 1.1 manu { 392 1.1 manu struct perfuse_state *ps; 393 1.43 manu struct perfuse_node_data *oldpnd; 394 1.1 manu perfuse_msg_t *pm; 395 1.1 manu struct fuse_entry_out *feo; 396 1.1 manu struct puffs_node *pn; 397 1.1 manu size_t len; 398 1.1 manu int error; 399 1.1 manu 400 1.47 manu /* 401 1.47 manu * Prevent further lookups if the parent was removed 402 1.47 manu */ 403 1.47 manu if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 404 1.47 manu return ESTALE; 405 1.47 manu 406 1.43 manu if (pnp == NULL) 407 1.43 manu DERRX(EX_SOFTWARE, "pnp must be != NULL"); 408 1.43 manu 409 1.1 manu ps = puffs_getspecific(pu); 410 1.1 manu 411 1.19 manu #ifdef PERFUSE_DEBUG 412 1.19 manu if (perfuse_diagflags & PDF_FILENAME) 413 1.19 manu DPRINTF("%s: opc = %p, file = \"%s\" looking up \"%s\"\n", 414 1.59 manu __func__, (void *)opc, 415 1.59 manu perfuse_node_path(ps, opc), path); 416 1.59 manu 417 1.59 manu if (strcmp(path, ".") == 0) 418 1.59 manu DERRX(EX_SOFTWARE, "unexpected dot-lookup"); 419 1.19 manu 420 1.59 manu if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_RECLAIMED) 421 1.59 manu DERRX(EX_SOFTWARE, 422 1.59 manu "looking up reclaimed node opc = %p, name = \"%s\"", 423 1.59 manu opc, path); 424 1.59 manu 425 1.59 manu if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_INVALID) 426 1.59 manu DERRX(EX_SOFTWARE, 427 1.59 manu "looking up freed node opc = %p, name = \"%s\"", 428 1.59 manu opc, path); 429 1.59 manu #endif /* PERFUSE_DEBUG */ 430 1.19 manu 431 1.1 manu len = strlen(path) + 1; 432 1.36 manu pm = ps->ps_new_msg(pu, opc, FUSE_LOOKUP, len, pcr); 433 1.1 manu (void)strlcpy(_GET_INPAYLOAD(ps, pm, char *), path, len); 434 1.1 manu 435 1.59 manu if ((error = xchg_msg(pu, opc, pm, sizeof(*feo), wait_reply)) != 0) 436 1.48 manu return error; 437 1.1 manu 438 1.1 manu feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 439 1.1 manu 440 1.60 manu /* 441 1.60 manu * Starting with ABI 7.4, inode number 0 means ENOENT, 442 1.60 manu * with entry_valid / entry_valid_nsec giving negative 443 1.60 manu * cache timeout (which we do not implement yet). 444 1.60 manu */ 445 1.60 manu if (feo->attr.ino == 0) { 446 1.60 manu ps->ps_destroy_msg(pm); 447 1.60 manu return ENOENT; 448 1.60 manu } 449 1.60 manu 450 1.59 manu /* 451 1.59 manu * Check for a known node, not reclaimed, with another name. 452 1.59 manu * It may have been moved, or we can lookup ../ 453 1.59 manu */ 454 1.59 manu if (((oldpnd = perfuse_node_bynodeid(ps, feo->nodeid)) != NULL) && 455 1.59 manu !(oldpnd->pnd_flags & PND_RECLAIMED)) { 456 1.59 manu /* 457 1.59 manu * Save the new node name if not .. 458 1.59 manu */ 459 1.59 manu if (strncmp(path, "..", len) != 0) 460 1.59 manu (void)strlcpy(oldpnd->pnd_name, 461 1.59 manu path, MAXPATHLEN); 462 1.59 manu pn = oldpnd->pnd_pn; 463 1.43 manu 464 1.59 manu } else { 465 1.54 manu pn = perfuse_new_pn(pu, path, opc); 466 1.54 manu PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid; 467 1.59 manu perfuse_node_cache(ps, pn); 468 1.54 manu } 469 1.1 manu 470 1.59 manu #ifdef PERFUSE_DEBUG 471 1.59 manu if (PERFUSE_NODE_DATA(pn)->pnd_flags & PND_RECLAIMED) 472 1.59 manu DERRX(EX_SOFTWARE, 473 1.59 manu "reclaimed in lookup opc = %p, name = \"%s\", ck = %p", 474 1.59 manu opc, path, pn); 475 1.59 manu 476 1.59 manu if (PERFUSE_NODE_DATA(pn)->pnd_flags & PND_INVALID) 477 1.59 manu DERRX(EX_SOFTWARE, 478 1.59 manu "freed in lookup opc = %p, name = \"%s\", ck = %p", 479 1.59 manu opc, path, pn); 480 1.59 manu #endif /* PERFUSE_DEBUG */ 481 1.59 manu 482 1.1 manu fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 483 1.21 manu pn->pn_va.va_gen = (u_long)(feo->generation); 484 1.59 manu PERFUSE_NODE_DATA(pn)->pnd_fuse_nlookup++; 485 1.86 manu PERFUSE_NODE_DATA(pn)->pnd_puffs_nlookup++; 486 1.1 manu 487 1.43 manu *pnp = pn; 488 1.1 manu 489 1.17 manu #ifdef PERFUSE_DEBUG 490 1.17 manu if (perfuse_diagflags & PDF_FILENAME) 491 1.43 manu DPRINTF("%s: opc = %p, looked up opc = %p, " 492 1.86 manu "nodeid = 0x%"PRIx64" file = \"%s\"\n", __func__, 493 1.43 manu (void *)opc, pn, feo->nodeid, path); 494 1.17 manu #endif 495 1.59 manu 496 1.54 manu if (pni != NULL) { 497 1.54 manu #ifdef PUFFS_KFLAG_CACHE_FS_TTL 498 1.54 manu puffs_newinfo_setva(pni, &pn->pn_va); 499 1.59 manu perfuse_newinfo_setttl(pni, pn, feo, NULL); 500 1.54 manu #endif /* PUFFS_KFLAG_CACHE_FS_TTL */ 501 1.54 manu puffs_newinfo_setcookie(pni, pn); 502 1.54 manu puffs_newinfo_setvtype(pni, pn->pn_va.va_type); 503 1.54 manu puffs_newinfo_setsize(pni, (voff_t)pn->pn_va.va_size); 504 1.54 manu puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev); 505 1.54 manu } 506 1.54 manu 507 1.1 manu ps->ps_destroy_msg(pm); 508 1.1 manu 509 1.48 manu return 0; 510 1.1 manu } 511 1.1 manu 512 1.1 manu 513 1.1 manu /* 514 1.24 manu * Common code for methods that create objects: 515 1.1 manu * perfuse_node_mkdir 516 1.1 manu * perfuse_node_mknod 517 1.1 manu * perfuse_node_symlink 518 1.1 manu */ 519 1.1 manu static int 520 1.52 matt node_mk_common(struct puffs_usermount *pu, puffs_cookie_t opc, 521 1.52 matt struct puffs_newinfo *pni, const struct puffs_cn *pcn, 522 1.52 matt perfuse_msg_t *pm) 523 1.1 manu { 524 1.1 manu struct perfuse_state *ps; 525 1.1 manu struct puffs_node *pn; 526 1.1 manu struct fuse_entry_out *feo; 527 1.1 manu int error; 528 1.1 manu 529 1.1 manu ps = puffs_getspecific(pu); 530 1.1 manu 531 1.16 manu if ((error = xchg_msg(pu, opc, pm, sizeof(*feo), wait_reply)) != 0) 532 1.48 manu return error; 533 1.1 manu 534 1.1 manu feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 535 1.43 manu if (feo->nodeid == PERFUSE_UNKNOWN_NODEID) 536 1.43 manu DERRX(EX_SOFTWARE, "%s: no nodeid", __func__); 537 1.1 manu 538 1.19 manu pn = perfuse_new_pn(pu, pcn->pcn_name, opc); 539 1.43 manu PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid; 540 1.86 manu PERFUSE_NODE_DATA(pn)->pnd_fuse_nlookup++; 541 1.59 manu PERFUSE_NODE_DATA(pn)->pnd_puffs_nlookup++; 542 1.59 manu perfuse_node_cache(ps, pn); 543 1.1 manu 544 1.1 manu fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 545 1.21 manu pn->pn_va.va_gen = (u_long)(feo->generation); 546 1.54 manu 547 1.54 manu puffs_newinfo_setcookie(pni, pn); 548 1.54 manu #ifdef PUFFS_KFLAG_CACHE_FS_TTL 549 1.54 manu puffs_newinfo_setva(pni, &pn->pn_va); 550 1.59 manu perfuse_newinfo_setttl(pni, pn, feo, NULL); 551 1.59 manu #endif /* PUFFS_KFLAG_CACHE_FS_TTL */ 552 1.21 manu 553 1.19 manu 554 1.19 manu #ifdef PERFUSE_DEBUG 555 1.19 manu if (perfuse_diagflags & PDF_FILENAME) 556 1.19 manu DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x " 557 1.43 manu "nodeid = 0x%"PRIx64"\n", 558 1.19 manu __func__, (void *)pn, pcn->pcn_name, 559 1.19 manu PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid); 560 1.19 manu #endif 561 1.4 manu ps->ps_destroy_msg(pm); 562 1.54 manu 563 1.54 manu /* Parents is now dirty */ 564 1.14 manu PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 565 1.19 manu 566 1.54 manu return 0; 567 1.1 manu } 568 1.1 manu 569 1.33 manu static uint64_t 570 1.52 matt readdir_last_cookie(struct fuse_dirent *fd, size_t fd_len) 571 1.33 manu { 572 1.33 manu size_t len; 573 1.33 manu size_t seen = 0; 574 1.33 manu char *ndp; 575 1.33 manu 576 1.33 manu do { 577 1.33 manu len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen); 578 1.33 manu seen += len; 579 1.33 manu 580 1.33 manu if (seen >= fd_len) 581 1.33 manu break; 582 1.33 manu 583 1.33 manu ndp = (char *)(void *)fd + (size_t)len; 584 1.33 manu fd = (struct fuse_dirent *)(void *)ndp; 585 1.33 manu } while (1 /* CONSTCOND */); 586 1.33 manu 587 1.33 manu return fd->off; 588 1.33 manu } 589 1.24 manu 590 1.1 manu static ssize_t 591 1.52 matt fuse_to_dirent(struct puffs_usermount *pu, puffs_cookie_t opc, 592 1.52 matt struct fuse_dirent *fd, size_t fd_len) 593 1.1 manu { 594 1.1 manu struct dirent *dents; 595 1.1 manu size_t dents_len; 596 1.1 manu ssize_t written; 597 1.1 manu uint64_t fd_offset; 598 1.1 manu struct fuse_dirent *fd_base; 599 1.1 manu size_t len; 600 1.1 manu 601 1.1 manu fd_base = fd; 602 1.1 manu fd_offset = 0; 603 1.1 manu written = 0; 604 1.1 manu dents = PERFUSE_NODE_DATA(opc)->pnd_dirent; 605 1.10 manu dents_len = (size_t)PERFUSE_NODE_DATA(opc)->pnd_dirent_len; 606 1.1 manu 607 1.1 manu do { 608 1.1 manu char *ndp; 609 1.1 manu size_t reclen; 610 1.75 manu char name[MAXPATHLEN]; 611 1.1 manu 612 1.1 manu reclen = _DIRENT_RECLEN(dents, fd->namelen); 613 1.1 manu 614 1.1 manu /* 615 1.1 manu * Check we do not overflow the output buffer 616 1.1 manu * struct fuse_dirent is bigger than struct dirent, 617 1.1 manu * so we should always use fd_len and never reallocate 618 1.1 manu * later. 619 1.91 andvar * If we have to reallocate, try to double the buffer 620 1.1 manu * each time so that we do not have to do it too often. 621 1.1 manu */ 622 1.1 manu if (written + reclen > dents_len) { 623 1.1 manu if (dents_len == 0) 624 1.1 manu dents_len = fd_len; 625 1.1 manu else 626 1.1 manu dents_len = 627 1.1 manu MAX(2 * dents_len, written + reclen); 628 1.1 manu 629 1.1 manu dents = PERFUSE_NODE_DATA(opc)->pnd_dirent; 630 1.1 manu if ((dents = realloc(dents, dents_len)) == NULL) 631 1.39 christos DERR(EX_OSERR, "%s: malloc failed", __func__); 632 1.1 manu 633 1.1 manu PERFUSE_NODE_DATA(opc)->pnd_dirent = dents; 634 1.1 manu PERFUSE_NODE_DATA(opc)->pnd_dirent_len = dents_len; 635 1.1 manu 636 1.1 manu /* 637 1.1 manu * (void *) for delint 638 1.1 manu */ 639 1.1 manu ndp = (char *)(void *)dents + written; 640 1.1 manu dents = (struct dirent *)(void *)ndp; 641 1.1 manu } 642 1.1 manu 643 1.75 manu strncpy(name, fd->name, fd->namelen); 644 1.75 manu name[fd->namelen] = '\0'; 645 1.75 manu 646 1.1 manu /* 647 1.1 manu * Filesystem was mounted without -o use_ino 648 1.1 manu * Perform a lookup to find it. 649 1.1 manu */ 650 1.1 manu if (fd->ino == PERFUSE_UNKNOWN_INO) { 651 1.1 manu struct puffs_node *pn; 652 1.63 manu struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 653 1.1 manu 654 1.84 manu if (strcmp(name, "..") == 0) { 655 1.84 manu /* 656 1.84 manu * Avoid breaking out of fs 657 1.84 manu * by lookup to .. on root 658 1.84 manu */ 659 1.84 manu if (pnd->pnd_nodeid == FUSE_ROOT_ID) 660 1.84 manu fd->ino = FUSE_ROOT_ID; 661 1.84 manu else 662 1.84 manu fd->ino = pnd->pnd_parent_nodeid; 663 1.84 manu } else if (strcmp(name, ".") == 0 ) { 664 1.84 manu fd->ino = pnd->pnd_nodeid; 665 1.43 manu } else { 666 1.75 manu int error; 667 1.75 manu 668 1.75 manu error = node_lookup_common(pu, opc, NULL, 669 1.75 manu name, NULL, &pn); 670 1.75 manu if (error != 0) { 671 1.75 manu DWARNX("node_lookup_common %s " 672 1.75 manu "failed: %d", name, error); 673 1.63 manu } else { 674 1.63 manu fd->ino = pn->pn_va.va_fileid; 675 1.85 manu (void)perfuse_node_reclaim2(pu, pn, 1); 676 1.63 manu } 677 1.43 manu } 678 1.1 manu } 679 1.1 manu 680 1.1 manu dents->d_fileno = fd->ino; 681 1.5 manu dents->d_reclen = (unsigned short)reclen; 682 1.1 manu dents->d_namlen = fd->namelen; 683 1.1 manu dents->d_type = fd->type; 684 1.75 manu strlcpy(dents->d_name, name, fd->namelen + 1); 685 1.1 manu 686 1.1 manu #ifdef PERFUSE_DEBUG 687 1.1 manu if (perfuse_diagflags & PDF_READDIR) 688 1.43 manu DPRINTF("%s: translated \"%s\" ino = %"PRIu64"\n", 689 1.1 manu __func__, dents->d_name, dents->d_fileno); 690 1.1 manu #endif 691 1.1 manu 692 1.1 manu dents = _DIRENT_NEXT(dents); 693 1.1 manu written += reclen; 694 1.1 manu 695 1.1 manu /* 696 1.1 manu * Move to the next record. 697 1.33 manu * fd->off is not the offset, it is an opaque cookie 698 1.33 manu * given by the filesystem to keep state across multiple 699 1.33 manu * readdir() operation. 700 1.89 andvar * Use record alignment instead. 701 1.1 manu */ 702 1.1 manu len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen); 703 1.1 manu #ifdef PERFUSE_DEBUG 704 1.1 manu if (perfuse_diagflags & PDF_READDIR) 705 1.5 manu DPRINTF("%s: record at %"PRId64"/0x%"PRIx64" " 706 1.5 manu "length = %zd/0x%zx. " 707 1.5 manu "next record at %"PRId64"/0x%"PRIx64" " 708 1.5 manu "max %zd/0x%zx\n", 709 1.1 manu __func__, fd_offset, fd_offset, len, len, 710 1.1 manu fd_offset + len, fd_offset + len, 711 1.1 manu fd_len, fd_len); 712 1.1 manu #endif 713 1.1 manu fd_offset += len; 714 1.1 manu 715 1.1 manu /* 716 1.1 manu * Check if next record is still within the packet 717 1.1 manu * If it is not, we reached the end of the buffer. 718 1.1 manu */ 719 1.1 manu if (fd_offset >= fd_len) 720 1.1 manu break; 721 1.1 manu 722 1.1 manu /* 723 1.1 manu * (void *) for delint 724 1.1 manu */ 725 1.1 manu ndp = (char *)(void *)fd_base + (size_t)fd_offset; 726 1.1 manu fd = (struct fuse_dirent *)(void *)ndp; 727 1.1 manu 728 1.1 manu } while (1 /* CONSTCOND */); 729 1.1 manu 730 1.1 manu /* 731 1.1 manu * Adjust the dirent output length 732 1.1 manu */ 733 1.1 manu if (written != -1) 734 1.1 manu PERFUSE_NODE_DATA(opc)->pnd_dirent_len = written; 735 1.75 manu 736 1.1 manu return written; 737 1.1 manu } 738 1.1 manu 739 1.59 manu static void 740 1.52 matt readdir_buffered(puffs_cookie_t opc, struct dirent *dent, off_t *readoff, 741 1.52 matt size_t *reslen) 742 1.1 manu { 743 1.1 manu struct dirent *fromdent; 744 1.1 manu struct perfuse_node_data *pnd; 745 1.1 manu char *ndp; 746 1.1 manu 747 1.1 manu pnd = PERFUSE_NODE_DATA(opc); 748 1.1 manu 749 1.1 manu while (*readoff < pnd->pnd_dirent_len) { 750 1.1 manu /* 751 1.1 manu * (void *) for delint 752 1.1 manu */ 753 1.1 manu ndp = (char *)(void *)pnd->pnd_dirent + (size_t)*readoff; 754 1.1 manu fromdent = (struct dirent *)(void *)ndp; 755 1.1 manu 756 1.1 manu if (*reslen < _DIRENT_SIZE(fromdent)) 757 1.1 manu break; 758 1.1 manu 759 1.1 manu memcpy(dent, fromdent, _DIRENT_SIZE(fromdent)); 760 1.1 manu *readoff += _DIRENT_SIZE(fromdent); 761 1.1 manu *reslen -= _DIRENT_SIZE(fromdent); 762 1.1 manu 763 1.1 manu dent = _DIRENT_NEXT(dent); 764 1.1 manu } 765 1.1 manu 766 1.1 manu #ifdef PERFUSE_DEBUG 767 1.1 manu if (perfuse_diagflags & PDF_READDIR) 768 1.10 manu DPRINTF("%s: readoff = %"PRId64", " 769 1.10 manu "pnd->pnd_dirent_len = %"PRId64"\n", 770 1.1 manu __func__, *readoff, pnd->pnd_dirent_len); 771 1.1 manu #endif 772 1.1 manu if (*readoff >= pnd->pnd_dirent_len) { 773 1.1 manu free(pnd->pnd_dirent); 774 1.1 manu pnd->pnd_dirent = NULL; 775 1.1 manu pnd->pnd_dirent_len = 0; 776 1.1 manu } 777 1.1 manu 778 1.59 manu return; 779 1.59 manu } 780 1.59 manu 781 1.59 manu 782 1.59 manu static void 783 1.59 manu node_ref(puffs_cookie_t opc) 784 1.59 manu { 785 1.59 manu struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 786 1.59 manu 787 1.59 manu #ifdef PERFUSE_DEBUG 788 1.59 manu if (pnd->pnd_flags & PND_INVALID) 789 1.59 manu DERRX(EX_SOFTWARE, "Use of freed node opc = %p", opc); 790 1.59 manu #endif /* PERFUSE_DEBUG */ 791 1.59 manu 792 1.59 manu pnd->pnd_ref++; 793 1.59 manu return; 794 1.59 manu } 795 1.59 manu 796 1.59 manu static void 797 1.59 manu node_rele(puffs_cookie_t opc) 798 1.59 manu { 799 1.59 manu struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 800 1.59 manu 801 1.59 manu #ifdef PERFUSE_DEBUG 802 1.59 manu if (pnd->pnd_flags & PND_INVALID) 803 1.59 manu DERRX(EX_SOFTWARE, "Use of freed node opc = %p", opc); 804 1.59 manu #endif /* PERFUSE_DEBUG */ 805 1.59 manu 806 1.59 manu pnd->pnd_ref--; 807 1.59 manu 808 1.59 manu if (pnd->pnd_ref == 0) 809 1.59 manu (void)dequeue_requests(opc, PCQ_REF, DEQUEUE_ALL); 810 1.59 manu 811 1.59 manu return; 812 1.1 manu } 813 1.1 manu 814 1.1 manu static void 815 1.52 matt requeue_request(struct puffs_usermount *pu, puffs_cookie_t opc, 816 1.52 matt enum perfuse_qtype type) 817 1.1 manu { 818 1.1 manu struct perfuse_cc_queue pcq; 819 1.1 manu struct perfuse_node_data *pnd; 820 1.1 manu 821 1.1 manu pnd = PERFUSE_NODE_DATA(opc); 822 1.1 manu pcq.pcq_type = type; 823 1.1 manu pcq.pcq_cc = puffs_cc_getcc(pu); 824 1.1 manu TAILQ_INSERT_TAIL(&pnd->pnd_pcq, &pcq, pcq_next); 825 1.1 manu 826 1.1 manu #ifdef PERFUSE_DEBUG 827 1.1 manu if (perfuse_diagflags & PDF_REQUEUE) 828 1.15 manu DPRINTF("%s: REQUEUE opc = %p, pcc = %p (%s)\n", 829 1.15 manu __func__, (void *)opc, pcq.pcq_cc, 830 1.15 manu perfuse_qtypestr[type]); 831 1.1 manu #endif 832 1.1 manu 833 1.1 manu puffs_cc_yield(pcq.pcq_cc); 834 1.6 manu TAILQ_REMOVE(&pnd->pnd_pcq, &pcq, pcq_next); 835 1.1 manu 836 1.1 manu #ifdef PERFUSE_DEBUG 837 1.1 manu if (perfuse_diagflags & PDF_REQUEUE) 838 1.15 manu DPRINTF("%s: RESUME opc = %p, pcc = %p (%s)\n", 839 1.15 manu __func__, (void *)opc, pcq.pcq_cc, 840 1.15 manu perfuse_qtypestr[type]); 841 1.1 manu #endif 842 1.1 manu 843 1.1 manu return; 844 1.1 manu } 845 1.1 manu 846 1.9 manu static int 847 1.59 manu dequeue_requests(puffs_cookie_t opc, enum perfuse_qtype type, int max) 848 1.1 manu { 849 1.1 manu struct perfuse_cc_queue *pcq; 850 1.1 manu struct perfuse_node_data *pnd; 851 1.1 manu int dequeued; 852 1.1 manu 853 1.1 manu pnd = PERFUSE_NODE_DATA(opc); 854 1.1 manu dequeued = 0; 855 1.1 manu TAILQ_FOREACH(pcq, &pnd->pnd_pcq, pcq_next) { 856 1.1 manu if (pcq->pcq_type != type) 857 1.1 manu continue; 858 1.1 manu 859 1.1 manu #ifdef PERFUSE_DEBUG 860 1.1 manu if (perfuse_diagflags & PDF_REQUEUE) 861 1.15 manu DPRINTF("%s: SCHEDULE opc = %p, pcc = %p (%s)\n", 862 1.15 manu __func__, (void *)opc, pcq->pcq_cc, 863 1.15 manu perfuse_qtypestr[type]); 864 1.1 manu #endif 865 1.6 manu puffs_cc_schedule(pcq->pcq_cc); 866 1.1 manu 867 1.1 manu if (++dequeued == max) 868 1.1 manu break; 869 1.1 manu } 870 1.1 manu 871 1.1 manu #ifdef PERFUSE_DEBUG 872 1.1 manu if (perfuse_diagflags & PDF_REQUEUE) 873 1.1 manu DPRINTF("%s: DONE opc = %p\n", __func__, (void *)opc); 874 1.1 manu #endif 875 1.1 manu 876 1.9 manu return dequeued; 877 1.1 manu } 878 1.1 manu 879 1.1 manu void 880 1.52 matt perfuse_fs_init(struct puffs_usermount *pu) 881 1.1 manu { 882 1.1 manu struct perfuse_state *ps; 883 1.1 manu perfuse_msg_t *pm; 884 1.1 manu struct fuse_init_in *fii; 885 1.1 manu struct fuse_init_out *fio; 886 1.1 manu int error; 887 1.1 manu 888 1.1 manu ps = puffs_getspecific(pu); 889 1.16 manu 890 1.1 manu if (puffs_mount(pu, ps->ps_target, ps->ps_mountflags, ps->ps_root) != 0) 891 1.39 christos DERR(EX_OSERR, "%s: puffs_mount failed", __func__); 892 1.1 manu 893 1.1 manu /* 894 1.1 manu * Linux 2.6.34.1 sends theses flags: 895 1.1 manu * FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC 896 1.1 manu * FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK 897 1.1 manu * 898 1.1 manu * Linux also sets max_readahead at 32 pages (128 kB) 899 1.36 manu * 900 1.36 manu * ps_new_msg() is called with NULL creds, which will 901 1.36 manu * be interpreted as FUSE superuser. 902 1.1 manu */ 903 1.1 manu pm = ps->ps_new_msg(pu, 0, FUSE_INIT, sizeof(*fii), NULL); 904 1.1 manu fii = GET_INPAYLOAD(ps, pm, fuse_init_in); 905 1.1 manu fii->major = FUSE_KERNEL_VERSION; 906 1.1 manu fii->minor = FUSE_KERNEL_MINOR_VERSION; 907 1.41 christos fii->max_readahead = (unsigned int)(32 * sysconf(_SC_PAGESIZE)); 908 1.1 manu fii->flags = (FUSE_ASYNC_READ|FUSE_POSIX_LOCKS|FUSE_ATOMIC_O_TRUNC); 909 1.1 manu 910 1.16 manu if ((error = xchg_msg(pu, 0, pm, sizeof(*fio), wait_reply)) != 0) 911 1.1 manu DERRX(EX_SOFTWARE, "init message exchange failed (%d)", error); 912 1.1 manu 913 1.1 manu fio = GET_OUTPAYLOAD(ps, pm, fuse_init_out); 914 1.1 manu ps->ps_max_readahead = fio->max_readahead; 915 1.1 manu ps->ps_max_write = fio->max_write; 916 1.1 manu 917 1.1 manu ps->ps_destroy_msg(pm); 918 1.1 manu 919 1.1 manu return; 920 1.1 manu } 921 1.1 manu 922 1.1 manu int 923 1.52 matt perfuse_fs_unmount(struct puffs_usermount *pu, int flags) 924 1.1 manu { 925 1.1 manu perfuse_msg_t *pm; 926 1.1 manu struct perfuse_state *ps; 927 1.1 manu puffs_cookie_t opc; 928 1.1 manu int error; 929 1.1 manu 930 1.1 manu ps = puffs_getspecific(pu); 931 1.36 manu opc = (puffs_cookie_t)puffs_getroot(pu); 932 1.1 manu 933 1.36 manu /* 934 1.36 manu * ps_new_msg() is called with NULL creds, which will 935 1.36 manu * be interpreted as FUSE superuser. 936 1.36 manu */ 937 1.1 manu pm = ps->ps_new_msg(pu, opc, FUSE_DESTROY, 0, NULL); 938 1.1 manu 939 1.16 manu if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0){ 940 1.1 manu DWARN("unmount %s", ps->ps_target); 941 1.1 manu if (!(flags & MNT_FORCE)) 942 1.48 manu return error; 943 1.48 manu else 944 1.48 manu error = 0; 945 1.48 manu } else { 946 1.48 manu ps->ps_destroy_msg(pm); 947 1.1 manu } 948 1.1 manu 949 1.28 manu ps->ps_umount(pu); 950 1.1 manu 951 1.28 manu if (perfuse_diagflags & PDF_MISC) 952 1.28 manu DPRINTF("%s unmounted, exit\n", ps->ps_target); 953 1.28 manu 954 1.28 manu return 0; 955 1.1 manu } 956 1.1 manu 957 1.1 manu int 958 1.88 christos perfuse_fs_statvfs(struct puffs_usermount *pu, struct puffs_statvfs *svfsb) 959 1.1 manu { 960 1.1 manu struct perfuse_state *ps; 961 1.1 manu perfuse_msg_t *pm; 962 1.1 manu puffs_cookie_t opc; 963 1.1 manu struct fuse_statfs_out *fso; 964 1.1 manu int error; 965 1.1 manu 966 1.1 manu ps = puffs_getspecific(pu); 967 1.1 manu opc = (puffs_cookie_t)puffs_getroot(pu); 968 1.36 manu 969 1.36 manu /* 970 1.36 manu * ps_new_msg() is called with NULL creds, which will 971 1.36 manu * be interpreted as FUSE superuser. 972 1.36 manu */ 973 1.1 manu pm = ps->ps_new_msg(pu, opc, FUSE_STATFS, 0, NULL); 974 1.1 manu 975 1.16 manu if ((error = xchg_msg(pu, opc, pm, sizeof(*fso), wait_reply)) != 0) 976 1.48 manu return error; 977 1.1 manu 978 1.1 manu fso = GET_OUTPAYLOAD(ps, pm, fuse_statfs_out); 979 1.1 manu svfsb->f_flag = ps->ps_mountflags; 980 1.1 manu svfsb->f_bsize = fso->st.bsize; 981 1.1 manu svfsb->f_frsize = fso->st.frsize; 982 1.1 manu svfsb->f_iosize = ((struct puffs_node *)opc)->pn_va.va_blocksize; 983 1.1 manu svfsb->f_blocks = fso->st.blocks; 984 1.1 manu svfsb->f_bfree = fso->st.bfree; 985 1.1 manu svfsb->f_bavail = fso->st.bavail; 986 1.1 manu svfsb->f_bresvd = fso->st.bfree - fso->st.bavail; 987 1.1 manu svfsb->f_files = fso->st.files; 988 1.1 manu svfsb->f_ffree = fso->st.ffree; 989 1.1 manu svfsb->f_favail = fso->st.ffree;/* files not reserved for root */ 990 1.1 manu svfsb->f_fresvd = 0; /* files reserved for root */ 991 1.1 manu 992 1.1 manu svfsb->f_syncreads = ps->ps_syncreads; 993 1.1 manu svfsb->f_syncwrites = ps->ps_syncwrites; 994 1.1 manu 995 1.1 manu svfsb->f_asyncreads = ps->ps_asyncreads; 996 1.1 manu svfsb->f_asyncwrites = ps->ps_asyncwrites; 997 1.1 manu 998 1.24 manu (void)memcpy(&svfsb->f_fsidx, &ps->ps_fsid, sizeof(ps->ps_fsid)); 999 1.24 manu svfsb->f_fsid = (unsigned long)ps->ps_fsid; 1000 1.1 manu svfsb->f_namemax = MAXPATHLEN; /* XXX */ 1001 1.3 manu svfsb->f_owner = ps->ps_owner_uid; 1002 1.1 manu 1003 1.1 manu (void)strlcpy(svfsb->f_mntonname, ps->ps_target, _VFS_NAMELEN); 1004 1.1 manu 1005 1.1 manu if (ps->ps_filesystemtype != NULL) 1006 1.1 manu (void)strlcpy(svfsb->f_fstypename, 1007 1.1 manu ps->ps_filesystemtype, _VFS_NAMELEN); 1008 1.1 manu else 1009 1.1 manu (void)strlcpy(svfsb->f_fstypename, "fuse", _VFS_NAMELEN); 1010 1.1 manu 1011 1.1 manu if (ps->ps_source != NULL) 1012 1.1 manu strlcpy(svfsb->f_mntfromname, ps->ps_source, _VFS_NAMELEN); 1013 1.1 manu else 1014 1.1 manu strlcpy(svfsb->f_mntfromname, _PATH_FUSE, _VFS_NAMELEN); 1015 1.48 manu 1016 1.1 manu ps->ps_destroy_msg(pm); 1017 1.48 manu 1018 1.48 manu return 0; 1019 1.1 manu } 1020 1.1 manu 1021 1.1 manu int 1022 1.52 matt perfuse_fs_sync(struct puffs_usermount *pu, int waitfor, 1023 1.52 matt const struct puffs_cred *pcr) 1024 1.1 manu { 1025 1.1 manu /* 1026 1.1 manu * FUSE does not seem to have a FS sync callback. 1027 1.1 manu * Maybe do not even register this callback 1028 1.1 manu */ 1029 1.1 manu return puffs_fsnop_sync(pu, waitfor, pcr); 1030 1.1 manu } 1031 1.1 manu 1032 1.1 manu /* ARGSUSED0 */ 1033 1.1 manu int 1034 1.52 matt perfuse_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize, 1035 1.52 matt struct puffs_newinfo *pni) 1036 1.1 manu { 1037 1.1 manu DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 1038 1.1 manu return 0; 1039 1.1 manu } 1040 1.1 manu 1041 1.1 manu /* ARGSUSED0 */ 1042 1.1 manu int 1043 1.52 matt perfuse_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t cookie, 1044 1.52 matt void *fid, size_t *fidsize) 1045 1.1 manu { 1046 1.1 manu DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 1047 1.1 manu return 0; 1048 1.1 manu } 1049 1.1 manu 1050 1.1 manu #if 0 1051 1.1 manu /* ARGSUSED0 */ 1052 1.1 manu void 1053 1.52 matt perfuse_fs_extattrctl(struct puffs_usermount *pu, int cmd, 1054 1.52 matt puffs_cookie_t *cookie, int flags, int namespace, const char *attrname) 1055 1.1 manu { 1056 1.1 manu DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 1057 1.1 manu return 0; 1058 1.1 manu } 1059 1.1 manu #endif /* 0 */ 1060 1.1 manu 1061 1.1 manu /* ARGSUSED0 */ 1062 1.1 manu void 1063 1.52 matt perfuse_fs_suspend(struct puffs_usermount *pu, int status) 1064 1.1 manu { 1065 1.1 manu return; 1066 1.1 manu } 1067 1.1 manu 1068 1.1 manu 1069 1.1 manu int 1070 1.52 matt perfuse_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc, 1071 1.52 matt struct puffs_newinfo *pni, const struct puffs_cn *pcn) 1072 1.1 manu { 1073 1.59 manu struct perfuse_state *ps; 1074 1.1 manu struct puffs_node *pn; 1075 1.24 manu mode_t mode; 1076 1.1 manu int error; 1077 1.21 manu 1078 1.59 manu ps = puffs_getspecific(pu); 1079 1.59 manu node_ref(opc); 1080 1.59 manu 1081 1.24 manu /* 1082 1.24 manu * Check permissions 1083 1.24 manu */ 1084 1.24 manu switch(pcn->pcn_nameiop) { 1085 1.24 manu case NAMEI_DELETE: /* FALLTHROUGH */ 1086 1.24 manu case NAMEI_RENAME: /* FALLTHROUGH */ 1087 1.24 manu case NAMEI_CREATE: 1088 1.27 manu if (pcn->pcn_flags & NAMEI_ISLASTCN) 1089 1.27 manu mode = PUFFS_VEXEC|PUFFS_VWRITE; 1090 1.27 manu else 1091 1.27 manu mode = PUFFS_VEXEC; 1092 1.24 manu break; 1093 1.24 manu case NAMEI_LOOKUP: /* FALLTHROUGH */ 1094 1.24 manu default: 1095 1.24 manu mode = PUFFS_VEXEC; 1096 1.24 manu break; 1097 1.24 manu } 1098 1.24 manu 1099 1.24 manu if ((error = mode_access(opc, pcn->pcn_cred, mode)) != 0) 1100 1.59 manu goto out; 1101 1.59 manu 1102 1.59 manu error = node_lookup_common(pu, (puffs_cookie_t)opc, pni, 1103 1.59 manu pcn->pcn_name, pcn->pcn_cred, &pn); 1104 1.18 manu 1105 1.18 manu if (error != 0) 1106 1.59 manu goto out; 1107 1.7 manu 1108 1.24 manu /* 1109 1.47 manu * Kernel would kill us if the filesystem returned the parent 1110 1.47 manu * itself. If we want to live, hide that! 1111 1.47 manu */ 1112 1.47 manu if ((opc == (puffs_cookie_t)pn) && (strcmp(pcn->pcn_name, ".") != 0)) { 1113 1.53 manu DERRX(EX_SOFTWARE, "lookup \"%s\" in \"%s\" returned parent", 1114 1.59 manu pcn->pcn_name, perfuse_node_path(ps, opc)); 1115 1.53 manu /* NOTREACHED */ 1116 1.59 manu error = ESTALE; 1117 1.59 manu goto out; 1118 1.47 manu } 1119 1.47 manu 1120 1.47 manu /* 1121 1.24 manu * Removed node 1122 1.24 manu */ 1123 1.59 manu if (PERFUSE_NODE_DATA(pn)->pnd_flags & PND_REMOVED) { 1124 1.59 manu error = ENOENT; 1125 1.59 manu goto out; 1126 1.59 manu } 1127 1.1 manu 1128 1.1 manu /* 1129 1.24 manu * Check for sticky bit. Unfortunately there is no way to 1130 1.24 manu * do this before creating the puffs_node, since we require 1131 1.24 manu * this operation to get the node owner. 1132 1.24 manu */ 1133 1.24 manu switch (pcn->pcn_nameiop) { 1134 1.24 manu case NAMEI_DELETE: /* FALLTHROUGH */ 1135 1.24 manu case NAMEI_RENAME: 1136 1.59 manu error = sticky_access(opc, pn, pcn->pcn_cred); 1137 1.24 manu if (error != 0) { 1138 1.85 manu (void)perfuse_node_reclaim2(pu, pn, 1); 1139 1.59 manu goto out; 1140 1.24 manu } 1141 1.24 manu break; 1142 1.24 manu default: 1143 1.24 manu break; 1144 1.24 manu } 1145 1.24 manu 1146 1.86 manu PERFUSE_NODE_DATA(pn)->pnd_fuse_nlookup++; 1147 1.59 manu PERFUSE_NODE_DATA(pn)->pnd_puffs_nlookup++; 1148 1.59 manu 1149 1.59 manu error = 0; 1150 1.1 manu 1151 1.59 manu out: 1152 1.59 manu node_rele(opc); 1153 1.18 manu return error; 1154 1.1 manu } 1155 1.1 manu 1156 1.1 manu int 1157 1.52 matt perfuse_node_create(struct puffs_usermount *pu, puffs_cookie_t opc, 1158 1.52 matt struct puffs_newinfo *pni, const struct puffs_cn *pcn, 1159 1.52 matt const struct vattr *vap) 1160 1.1 manu { 1161 1.1 manu perfuse_msg_t *pm; 1162 1.1 manu struct perfuse_state *ps; 1163 1.1 manu struct fuse_create_in *fci; 1164 1.1 manu struct fuse_entry_out *feo; 1165 1.1 manu struct fuse_open_out *foo; 1166 1.1 manu struct puffs_node *pn; 1167 1.1 manu const char *name; 1168 1.1 manu size_t namelen; 1169 1.1 manu size_t len; 1170 1.1 manu int error; 1171 1.1 manu 1172 1.18 manu if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1173 1.18 manu return ENOENT; 1174 1.18 manu 1175 1.59 manu node_ref(opc); 1176 1.59 manu 1177 1.4 manu /* 1178 1.1 manu * If create is unimplemented: Check that it does not 1179 1.1 manu * already exists, and if not, do mknod and open 1180 1.1 manu */ 1181 1.1 manu ps = puffs_getspecific(pu); 1182 1.1 manu if (ps->ps_flags & PS_NO_CREAT) { 1183 1.54 manu error = node_lookup_common(pu, opc, NULL, pcn->pcn_name, 1184 1.36 manu pcn->pcn_cred, &pn); 1185 1.59 manu if (error == 0) { 1186 1.85 manu (void)perfuse_node_reclaim2(pu, pn, 1); 1187 1.59 manu error = EEXIST; 1188 1.59 manu goto out; 1189 1.59 manu } 1190 1.1 manu 1191 1.1 manu error = perfuse_node_mknod(pu, opc, pni, pcn, vap); 1192 1.59 manu if (error != 0) 1193 1.59 manu goto out; 1194 1.1 manu 1195 1.54 manu error = node_lookup_common(pu, opc, NULL, pcn->pcn_name, 1196 1.36 manu pcn->pcn_cred, &pn); 1197 1.59 manu if (error != 0) 1198 1.59 manu goto out; 1199 1.7 manu 1200 1.21 manu /* 1201 1.21 manu * FUSE does the open at create time, while 1202 1.21 manu * NetBSD will open in a subsequent operation. 1203 1.21 manu * We need to open now, in order to retain FUSE 1204 1.24 manu * semantics. The calling process will not get 1205 1.24 manu * a file descriptor before the kernel sends 1206 1.24 manu * the open operation. 1207 1.21 manu */ 1208 1.59 manu error = perfuse_node_open(pu, (puffs_cookie_t)pn, 1209 1.59 manu FWRITE, pcn->pcn_cred); 1210 1.59 manu goto out; 1211 1.1 manu } 1212 1.1 manu 1213 1.18 manu name = pcn->pcn_name; 1214 1.18 manu namelen = pcn->pcn_namelen + 1; 1215 1.1 manu len = sizeof(*fci) + namelen; 1216 1.1 manu 1217 1.9 manu /* 1218 1.9 manu * flags should use O_WRONLY instead of O_RDWR, but it 1219 1.9 manu * breaks when the caller tries to read from file. 1220 1.13 manu * 1221 1.13 manu * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type) 1222 1.9 manu */ 1223 1.36 manu pm = ps->ps_new_msg(pu, opc, FUSE_CREATE, len, pcn->pcn_cred); 1224 1.1 manu fci = GET_INPAYLOAD(ps, pm, fuse_create_in); 1225 1.9 manu fci->flags = O_CREAT | O_TRUNC | O_RDWR; 1226 1.13 manu fci->mode = vap->va_mode | VTTOIF(vap->va_type); 1227 1.9 manu fci->umask = 0; /* Seems unused by libfuse */ 1228 1.1 manu (void)strlcpy((char*)(void *)(fci + 1), name, namelen); 1229 1.1 manu 1230 1.1 manu len = sizeof(*feo) + sizeof(*foo); 1231 1.48 manu if ((error = xchg_msg(pu, opc, pm, len, wait_reply)) != 0) { 1232 1.48 manu /* 1233 1.92 msaitoh * create is unimplemented, remember it for later, 1234 1.48 manu * and start over using mknod and open instead. 1235 1.48 manu */ 1236 1.48 manu if (error == ENOSYS) { 1237 1.48 manu ps->ps_flags |= PS_NO_CREAT; 1238 1.59 manu error = perfuse_node_create(pu, opc, pni, pcn, vap); 1239 1.48 manu } 1240 1.48 manu 1241 1.59 manu goto out; 1242 1.48 manu } 1243 1.1 manu 1244 1.1 manu feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out); 1245 1.1 manu foo = (struct fuse_open_out *)(void *)(feo + 1); 1246 1.43 manu if (feo->nodeid == PERFUSE_UNKNOWN_NODEID) 1247 1.43 manu DERRX(EX_SOFTWARE, "%s: no nodeid", __func__); 1248 1.1 manu 1249 1.1 manu /* 1250 1.1 manu * Save the file handle and inode in node private data 1251 1.1 manu * so that we can reuse it later 1252 1.1 manu */ 1253 1.19 manu pn = perfuse_new_pn(pu, name, opc); 1254 1.17 manu perfuse_new_fh((puffs_cookie_t)pn, foo->fh, FWRITE); 1255 1.43 manu PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid; 1256 1.86 manu PERFUSE_NODE_DATA(pn)->pnd_fuse_nlookup++; 1257 1.59 manu PERFUSE_NODE_DATA(pn)->pnd_puffs_nlookup++; 1258 1.59 manu perfuse_node_cache(ps, pn); 1259 1.1 manu 1260 1.1 manu fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr); 1261 1.21 manu pn->pn_va.va_gen = (u_long)(feo->generation); 1262 1.54 manu 1263 1.54 manu puffs_newinfo_setcookie(pni, pn); 1264 1.54 manu #ifdef PUFFS_KFLAG_CACHE_FS_TTL 1265 1.54 manu puffs_newinfo_setva(pni, &pn->pn_va); 1266 1.59 manu perfuse_newinfo_setttl(pni, pn, feo, NULL); 1267 1.54 manu #endif /* PUFFS_KFLAG_CACHE_FS_TTL */ 1268 1.1 manu 1269 1.17 manu #ifdef PERFUSE_DEBUG 1270 1.17 manu if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) 1271 1.17 manu DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x " 1272 1.43 manu "nodeid = 0x%"PRIx64", wfh = 0x%"PRIx64"\n", 1273 1.18 manu __func__, (void *)pn, pcn->pcn_name, 1274 1.43 manu PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid, 1275 1.43 manu foo->fh); 1276 1.17 manu #endif 1277 1.16 manu 1278 1.24 manu ps->ps_destroy_msg(pm); 1279 1.59 manu error = 0; 1280 1.24 manu 1281 1.59 manu out: 1282 1.59 manu node_rele(opc); 1283 1.59 manu return error; 1284 1.1 manu } 1285 1.1 manu 1286 1.1 manu 1287 1.1 manu int 1288 1.52 matt perfuse_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc, 1289 1.52 matt struct puffs_newinfo *pni, const struct puffs_cn *pcn, 1290 1.52 matt const struct vattr *vap) 1291 1.1 manu { 1292 1.1 manu struct perfuse_state *ps; 1293 1.1 manu perfuse_msg_t *pm; 1294 1.1 manu struct fuse_mknod_in *fmi; 1295 1.1 manu const char* path; 1296 1.1 manu size_t len; 1297 1.59 manu int error; 1298 1.1 manu 1299 1.18 manu if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1300 1.18 manu return ENOENT; 1301 1.18 manu 1302 1.59 manu node_ref(opc); 1303 1.59 manu 1304 1.4 manu /* 1305 1.4 manu * Only superuser can mknod objects other than 1306 1.4 manu * directories, files, socks, fifo and links. 1307 1.4 manu * 1308 1.4 manu * Create an object require -WX permission in the parent directory 1309 1.4 manu */ 1310 1.4 manu switch (vap->va_type) { 1311 1.4 manu case VDIR: /* FALLTHROUGH */ 1312 1.4 manu case VREG: /* FALLTHROUGH */ 1313 1.4 manu case VFIFO: /* FALLTHROUGH */ 1314 1.24 manu case VSOCK: 1315 1.4 manu break; 1316 1.4 manu default: /* VNON, VBLK, VCHR, VBAD */ 1317 1.59 manu if (!puffs_cred_isjuggernaut(pcn->pcn_cred)) { 1318 1.71 manu error = EPERM; 1319 1.59 manu goto out; 1320 1.59 manu } 1321 1.4 manu break; 1322 1.4 manu } 1323 1.4 manu 1324 1.4 manu 1325 1.1 manu ps = puffs_getspecific(pu); 1326 1.18 manu path = pcn->pcn_name; 1327 1.18 manu len = sizeof(*fmi) + pcn->pcn_namelen + 1; 1328 1.1 manu 1329 1.9 manu /* 1330 1.13 manu * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type) 1331 1.9 manu */ 1332 1.36 manu pm = ps->ps_new_msg(pu, opc, FUSE_MKNOD, len, pcn->pcn_cred); 1333 1.1 manu fmi = GET_INPAYLOAD(ps, pm, fuse_mknod_in); 1334 1.1 manu fmi->mode = vap->va_mode | VTTOIF(vap->va_type); 1335 1.10 manu fmi->rdev = (uint32_t)vap->va_rdev; 1336 1.1 manu fmi->umask = 0; /* Seems unused bu libfuse */ 1337 1.1 manu (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi)); 1338 1.1 manu 1339 1.59 manu error = node_mk_common(pu, opc, pni, pcn, pm); 1340 1.59 manu 1341 1.59 manu out: 1342 1.59 manu node_rele(opc); 1343 1.59 manu return error; 1344 1.1 manu } 1345 1.1 manu 1346 1.1 manu 1347 1.1 manu int 1348 1.52 matt perfuse_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 1349 1.52 matt const struct puffs_cred *pcr) 1350 1.1 manu { 1351 1.67 manu return perfuse_node_open2(pu, opc, mode, pcr, NULL); 1352 1.67 manu } 1353 1.67 manu 1354 1.67 manu int 1355 1.67 manu perfuse_node_open2(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 1356 1.67 manu const struct puffs_cred *pcr, int *oflags) 1357 1.67 manu { 1358 1.1 manu struct perfuse_state *ps; 1359 1.7 manu struct perfuse_node_data *pnd; 1360 1.1 manu perfuse_msg_t *pm; 1361 1.7 manu mode_t fmode; 1362 1.1 manu int op; 1363 1.1 manu struct fuse_open_in *foi; 1364 1.1 manu struct fuse_open_out *foo; 1365 1.1 manu int error; 1366 1.1 manu 1367 1.1 manu ps = puffs_getspecific(pu); 1368 1.7 manu pnd = PERFUSE_NODE_DATA(opc); 1369 1.17 manu error = 0; 1370 1.17 manu 1371 1.18 manu if (pnd->pnd_flags & PND_REMOVED) 1372 1.18 manu return ENOENT; 1373 1.18 manu 1374 1.59 manu node_ref(opc); 1375 1.59 manu 1376 1.86 manu if (PN_ISDIR(opc)) 1377 1.1 manu op = FUSE_OPENDIR; 1378 1.24 manu else 1379 1.1 manu op = FUSE_OPEN; 1380 1.4 manu 1381 1.4 manu /* 1382 1.24 manu * libfuse docs says 1383 1.27 manu * - O_CREAT and O_EXCL should never be set. 1384 1.24 manu * - O_TRUNC may be used if mount option atomic_o_trunc is used XXX 1385 1.24 manu * 1386 1.24 manu * O_APPEND makes no sense since FUSE always sends 1387 1.24 manu * the file offset for write operations. If the 1388 1.24 manu * filesystem uses pwrite(), O_APPEND would cause 1389 1.24 manu * the offset to be ignored and cause file corruption. 1390 1.4 manu */ 1391 1.27 manu mode &= ~(O_CREAT|O_EXCL|O_APPEND); 1392 1.7 manu 1393 1.7 manu /* 1394 1.7 manu * Do not open twice, and do not reopen for reading 1395 1.20 manu * if we already have write handle. 1396 1.7 manu */ 1397 1.61 manu switch (mode & (FREAD|FWRITE)) { 1398 1.61 manu case FREAD: 1399 1.61 manu if (pnd->pnd_flags & (PND_RFH|PND_WFH)) 1400 1.61 manu goto out; 1401 1.61 manu break; 1402 1.61 manu case FWRITE: 1403 1.61 manu if (pnd->pnd_flags & PND_WFH) 1404 1.61 manu goto out; 1405 1.61 manu break; 1406 1.61 manu case FREAD|FWRITE: 1407 1.61 manu if (pnd->pnd_flags & PND_WFH) 1408 1.61 manu goto out; 1409 1.61 manu 1410 1.61 manu /* 1411 1.61 manu * Corner case: if already open for reading (PND_RFH) 1412 1.61 manu * and re-opening FREAD|FWRITE, we need to reopen, 1413 1.61 manu * but only for writing. Note the change on mode 1414 1.61 manu * will only affect perfuse_new_fh() 1415 1.61 manu */ 1416 1.61 manu if (pnd->pnd_flags & PND_RFH) 1417 1.61 manu mode &= ~FREAD; 1418 1.61 manu break; 1419 1.62 manu default: 1420 1.62 manu DWARNX("open without either FREAD nor FWRITE"); 1421 1.62 manu error = EPERM; 1422 1.62 manu goto out; 1423 1.61 manu } 1424 1.16 manu 1425 1.7 manu /* 1426 1.19 manu * Queue open on a node so that we do not open 1427 1.19 manu * twice. This would be better with read and 1428 1.19 manu * write distinguished. 1429 1.19 manu */ 1430 1.19 manu while (pnd->pnd_flags & PND_INOPEN) 1431 1.19 manu requeue_request(pu, opc, PCQ_OPEN); 1432 1.19 manu pnd->pnd_flags |= PND_INOPEN; 1433 1.19 manu 1434 1.19 manu /* 1435 1.7 manu * Convert PUFFS mode to FUSE mode: convert FREAD/FWRITE 1436 1.7 manu * to O_RDONLY/O_WRONLY while perserving the other options. 1437 1.7 manu */ 1438 1.7 manu fmode = mode & ~(FREAD|FWRITE); 1439 1.7 manu fmode |= (mode & FWRITE) ? O_RDWR : O_RDONLY; 1440 1.7 manu 1441 1.1 manu pm = ps->ps_new_msg(pu, opc, op, sizeof(*foi), pcr); 1442 1.1 manu foi = GET_INPAYLOAD(ps, pm, fuse_open_in); 1443 1.7 manu foi->flags = fmode; 1444 1.1 manu foi->unused = 0; 1445 1.1 manu 1446 1.16 manu if ((error = xchg_msg(pu, opc, pm, sizeof(*foo), wait_reply)) != 0) 1447 1.1 manu goto out; 1448 1.1 manu 1449 1.1 manu foo = GET_OUTPAYLOAD(ps, pm, fuse_open_out); 1450 1.16 manu 1451 1.1 manu /* 1452 1.1 manu * Save the file handle in node private data 1453 1.1 manu * so that we can reuse it later 1454 1.1 manu */ 1455 1.17 manu perfuse_new_fh(opc, foo->fh, mode); 1456 1.53 manu 1457 1.67 manu /* 1458 1.67 manu * Set direct I/O if the filesystems forces it 1459 1.67 manu */ 1460 1.67 manu if ((foo->open_flags & FUSE_FOPEN_DIRECT_IO) && (oflags != NULL)) 1461 1.67 manu *oflags |= PUFFS_OPEN_IO_DIRECT; 1462 1.67 manu 1463 1.1 manu #ifdef PERFUSE_DEBUG 1464 1.17 manu if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) 1465 1.2 manu DPRINTF("%s: opc = %p, file = \"%s\", " 1466 1.43 manu "nodeid = 0x%"PRIx64", %s%sfh = 0x%"PRIx64"\n", 1467 1.59 manu __func__, (void *)opc, perfuse_node_path(ps, opc), 1468 1.43 manu pnd->pnd_nodeid, mode & FREAD ? "r" : "", 1469 1.7 manu mode & FWRITE ? "w" : "", foo->fh); 1470 1.1 manu #endif 1471 1.16 manu 1472 1.48 manu ps->ps_destroy_msg(pm); 1473 1.1 manu out: 1474 1.17 manu 1475 1.17 manu pnd->pnd_flags &= ~PND_INOPEN; 1476 1.59 manu (void)dequeue_requests(opc, PCQ_OPEN, DEQUEUE_ALL); 1477 1.1 manu 1478 1.59 manu node_rele(opc); 1479 1.1 manu return error; 1480 1.1 manu } 1481 1.1 manu 1482 1.7 manu /* ARGSUSED0 */ 1483 1.1 manu int 1484 1.52 matt perfuse_node_close(struct puffs_usermount *pu, puffs_cookie_t opc, int flags, 1485 1.52 matt const struct puffs_cred *pcr) 1486 1.1 manu { 1487 1.2 manu struct perfuse_node_data *pnd; 1488 1.7 manu 1489 1.7 manu pnd = PERFUSE_NODE_DATA(opc); 1490 1.1 manu 1491 1.2 manu if (!(pnd->pnd_flags & PND_OPEN)) 1492 1.1 manu return EBADF; 1493 1.1 manu 1494 1.7 manu /* 1495 1.17 manu * Actual close is postponed at inactive time. 1496 1.1 manu */ 1497 1.7 manu return 0; 1498 1.1 manu } 1499 1.1 manu 1500 1.1 manu int 1501 1.52 matt perfuse_node_access(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 1502 1.52 matt const struct puffs_cred *pcr) 1503 1.1 manu { 1504 1.1 manu perfuse_msg_t *pm; 1505 1.1 manu struct perfuse_state *ps; 1506 1.1 manu struct fuse_access_in *fai; 1507 1.1 manu int error; 1508 1.1 manu 1509 1.9 manu if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 1510 1.9 manu return ENOENT; 1511 1.9 manu 1512 1.59 manu node_ref(opc); 1513 1.59 manu 1514 1.1 manu /* 1515 1.1 manu * If we previously detected the filesystem does not 1516 1.1 manu * implement access(), short-circuit the call and skip 1517 1.24 manu * to libpuffs access() emulation. 1518 1.1 manu */ 1519 1.1 manu ps = puffs_getspecific(pu); 1520 1.1 manu if (ps->ps_flags & PS_NO_ACCESS) { 1521 1.24 manu const struct vattr *vap; 1522 1.24 manu 1523 1.24 manu vap = puffs_pn_getvap((struct puffs_node *)opc); 1524 1.1 manu 1525 1.24 manu error = puffs_access(IFTOVT(vap->va_mode), 1526 1.24 manu vap->va_mode & ACCESSPERMS, 1527 1.24 manu vap->va_uid, vap->va_gid, 1528 1.24 manu (mode_t)mode, pcr); 1529 1.59 manu goto out; 1530 1.1 manu } 1531 1.1 manu 1532 1.24 manu /* 1533 1.24 manu * Plain access call 1534 1.24 manu */ 1535 1.24 manu pm = ps->ps_new_msg(pu, opc, FUSE_ACCESS, sizeof(*fai), pcr); 1536 1.24 manu fai = GET_INPAYLOAD(ps, pm, fuse_access_in); 1537 1.24 manu fai->mask = 0; 1538 1.24 manu fai->mask |= (mode & PUFFS_VREAD) ? R_OK : 0; 1539 1.24 manu fai->mask |= (mode & PUFFS_VWRITE) ? W_OK : 0; 1540 1.24 manu fai->mask |= (mode & PUFFS_VEXEC) ? X_OK : 0; 1541 1.1 manu 1542 1.24 manu error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply); 1543 1.1 manu 1544 1.24 manu ps->ps_destroy_msg(pm); 1545 1.1 manu 1546 1.24 manu /* 1547 1.24 manu * If unimplemented, start over with emulation 1548 1.24 manu */ 1549 1.24 manu if (error == ENOSYS) { 1550 1.24 manu ps->ps_flags |= PS_NO_ACCESS; 1551 1.59 manu error = perfuse_node_access(pu, opc, mode, pcr); 1552 1.1 manu } 1553 1.1 manu 1554 1.59 manu out: 1555 1.59 manu node_rele(opc); 1556 1.1 manu return error; 1557 1.1 manu } 1558 1.1 manu 1559 1.1 manu int 1560 1.52 matt perfuse_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc, 1561 1.52 matt struct vattr *vap, const struct puffs_cred *pcr) 1562 1.1 manu { 1563 1.54 manu return perfuse_node_getattr_ttl(pu, opc, vap, pcr, NULL); 1564 1.54 manu } 1565 1.54 manu 1566 1.54 manu int 1567 1.54 manu perfuse_node_getattr_ttl(struct puffs_usermount *pu, puffs_cookie_t opc, 1568 1.54 manu struct vattr *vap, const struct puffs_cred *pcr, 1569 1.54 manu struct timespec *va_ttl) 1570 1.54 manu { 1571 1.43 manu perfuse_msg_t *pm = NULL; 1572 1.1 manu struct perfuse_state *ps; 1573 1.40 manu struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc); 1574 1.1 manu struct fuse_getattr_in *fgi; 1575 1.1 manu struct fuse_attr_out *fao; 1576 1.43 manu int error = 0; 1577 1.1 manu 1578 1.64 manu if ((pnd->pnd_flags & PND_REMOVED) && !(pnd->pnd_flags & PND_OPEN)) 1579 1.9 manu return ENOENT; 1580 1.9 manu 1581 1.59 manu node_ref(opc); 1582 1.59 manu 1583 1.40 manu /* 1584 1.40 manu * Serialize size access, see comment in perfuse_node_setattr(). 1585 1.40 manu */ 1586 1.40 manu while (pnd->pnd_flags & PND_INRESIZE) 1587 1.40 manu requeue_request(pu, opc, PCQ_RESIZE); 1588 1.40 manu pnd->pnd_flags |= PND_INRESIZE; 1589 1.40 manu 1590 1.1 manu ps = puffs_getspecific(pu); 1591 1.43 manu 1592 1.1 manu /* 1593 1.1 manu * FUSE_GETATTR_FH must be set in fgi->flags 1594 1.17 manu * if we use for fgi->fh 1595 1.1 manu */ 1596 1.1 manu pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR, sizeof(*fgi), pcr); 1597 1.1 manu fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in); 1598 1.1 manu fgi->getattr_flags = 0; 1599 1.1 manu fgi->dummy = 0; 1600 1.86 manu fgi->fh = FUSE_UNKNOWN_FH; 1601 1.17 manu 1602 1.86 manu if (!PN_ISDIR(opc) && PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) { 1603 1.20 manu fgi->fh = perfuse_get_fh(opc, FREAD); 1604 1.17 manu fgi->getattr_flags |= FUSE_GETATTR_FH; 1605 1.20 manu } 1606 1.1 manu 1607 1.40 manu #ifdef PERFUSE_DEBUG 1608 1.40 manu if (perfuse_diagflags & PDF_RESIZE) 1609 1.41 christos DPRINTF(">> %s %p %" PRIu64 "\n", __func__, (void *)opc, 1610 1.41 christos vap->va_size); 1611 1.40 manu #endif 1612 1.40 manu 1613 1.16 manu if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0) 1614 1.1 manu goto out; 1615 1.1 manu 1616 1.1 manu fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 1617 1.1 manu 1618 1.40 manu #ifdef PERFUSE_DEBUG 1619 1.40 manu if (perfuse_diagflags & PDF_RESIZE) 1620 1.41 christos DPRINTF("<< %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__, 1621 1.41 christos (void *)opc, vap->va_size, fao->attr.size); 1622 1.40 manu #endif 1623 1.40 manu 1624 1.1 manu /* 1625 1.43 manu * We set birthtime, flags, filerev,vaflags to 0. 1626 1.1 manu * This seems the best bet, since the information is 1627 1.1 manu * not available from filesystem. 1628 1.1 manu */ 1629 1.1 manu fuse_attr_to_vap(ps, vap, &fao->attr); 1630 1.54 manu 1631 1.54 manu if (va_ttl != NULL) { 1632 1.54 manu va_ttl->tv_sec = fao->attr_valid; 1633 1.54 manu va_ttl->tv_nsec = fao->attr_valid_nsec; 1634 1.54 manu } 1635 1.1 manu 1636 1.48 manu ps->ps_destroy_msg(pm); 1637 1.59 manu error = 0; 1638 1.1 manu out: 1639 1.1 manu 1640 1.40 manu pnd->pnd_flags &= ~PND_INRESIZE; 1641 1.59 manu (void)dequeue_requests(opc, PCQ_RESIZE, DEQUEUE_ALL); 1642 1.40 manu 1643 1.59 manu node_rele(opc); 1644 1.1 manu return error; 1645 1.1 manu } 1646 1.1 manu 1647 1.1 manu int 1648 1.52 matt perfuse_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc, 1649 1.52 matt const struct vattr *vap, const struct puffs_cred *pcr) 1650 1.1 manu { 1651 1.54 manu return perfuse_node_setattr_ttl(pu, opc, 1652 1.58 abs __UNCONST(vap), pcr, NULL, 0); 1653 1.54 manu } 1654 1.54 manu 1655 1.54 manu int 1656 1.54 manu perfuse_node_setattr_ttl(struct puffs_usermount *pu, puffs_cookie_t opc, 1657 1.54 manu struct vattr *vap, const struct puffs_cred *pcr, 1658 1.59 manu struct timespec *va_ttl, int xflag) 1659 1.54 manu { 1660 1.1 manu perfuse_msg_t *pm; 1661 1.1 manu uint64_t fh; 1662 1.1 manu struct perfuse_state *ps; 1663 1.7 manu struct perfuse_node_data *pnd; 1664 1.1 manu struct fuse_setattr_in *fsi; 1665 1.24 manu struct fuse_attr_out *fao; 1666 1.17 manu struct vattr *old_va; 1667 1.59 manu enum perfuse_xchg_pb_reply reply; 1668 1.1 manu int error; 1669 1.40 manu #ifdef PERFUSE_DEBUG 1670 1.40 manu struct vattr *old_vap; 1671 1.40 manu int resize_debug = 0; 1672 1.40 manu #endif 1673 1.7 manu ps = puffs_getspecific(pu); 1674 1.7 manu pnd = PERFUSE_NODE_DATA(opc); 1675 1.7 manu 1676 1.4 manu /* 1677 1.9 manu * The only operation we can do once the file is removed 1678 1.9 manu * is to resize it, and we can do it only if it is open. 1679 1.17 manu * Do not even send the operation to the filesystem: the 1680 1.17 manu * file is not there anymore. 1681 1.9 manu */ 1682 1.9 manu if (pnd->pnd_flags & PND_REMOVED) { 1683 1.9 manu if (!(pnd->pnd_flags & PND_OPEN)) 1684 1.9 manu return ENOENT; 1685 1.9 manu 1686 1.59 manu return 0; 1687 1.9 manu } 1688 1.9 manu 1689 1.4 manu old_va = puffs_pn_getvap((struct puffs_node *)opc); 1690 1.4 manu 1691 1.4 manu /* 1692 1.4 manu * Check for permission to change size 1693 1.59 manu * It is always allowed if we already have a write file handle 1694 1.4 manu */ 1695 1.59 manu if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) && 1696 1.59 manu !(pnd->pnd_flags & PND_WFH) && 1697 1.59 manu (error = mode_access(opc, pcr, PUFFS_VWRITE)) != 0) 1698 1.59 manu return error; 1699 1.59 manu 1700 1.59 manu /* 1701 1.59 manu * Check for permission to change dates 1702 1.59 manu */ 1703 1.59 manu if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) || 1704 1.59 manu (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) && 1705 1.59 manu (puffs_access_times(old_va->va_uid, old_va->va_gid, 1706 1.59 manu old_va->va_mode, 0, pcr) != 0)) 1707 1.71 manu return EPERM; 1708 1.4 manu 1709 1.4 manu /* 1710 1.57 manu * Check for permission to change owner and group 1711 1.4 manu */ 1712 1.59 manu if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) || 1713 1.59 manu (vap->va_gid != (gid_t)PUFFS_VNOVAL)) && 1714 1.59 manu (puffs_access_chown(old_va->va_uid, old_va->va_gid, 1715 1.59 manu vap->va_uid, vap->va_gid, pcr)) != 0) 1716 1.71 manu return EPERM; 1717 1.71 manu 1718 1.71 manu /* 1719 1.71 manu * Check for sticky bit on non-directory by non root user 1720 1.71 manu */ 1721 1.71 manu if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) && 1722 1.71 manu (vap->va_mode & S_ISTXT) && (old_va->va_type != VDIR) && 1723 1.71 manu !puffs_cred_isjuggernaut(pcr)) 1724 1.71 manu return EFTYPE; 1725 1.4 manu 1726 1.4 manu /* 1727 1.57 manu * Check for permission to change permissions 1728 1.57 manu */ 1729 1.59 manu if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) && 1730 1.59 manu (puffs_access_chmod(old_va->va_uid, old_va->va_gid, 1731 1.59 manu old_va->va_type, vap->va_mode, pcr)) != 0) 1732 1.71 manu return EPERM; 1733 1.59 manu 1734 1.59 manu node_ref(opc); 1735 1.59 manu 1736 1.86 manu if (!PN_ISDIR(opc) && pnd->pnd_flags & PND_WFH) 1737 1.59 manu fh = perfuse_get_fh(opc, FWRITE); 1738 1.59 manu else 1739 1.59 manu fh = FUSE_UNKNOWN_FH; 1740 1.57 manu 1741 1.57 manu /* 1742 1.59 manu * fchmod() sets mode and fh, and it may carry 1743 1.59 manu * a resize as well. That may break if the 1744 1.59 manu * filesystem does chmod then resize, and fails 1745 1.59 manu * because it does not have permission anymore. 1746 1.59 manu * We work this around by splitting into two setattr. 1747 1.59 manu */ 1748 1.59 manu if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) && 1749 1.59 manu (vap->va_mode != (mode_t)PUFFS_VNOVAL) && 1750 1.59 manu (fh != FUSE_UNKNOWN_FH)) { 1751 1.59 manu struct vattr resize_va; 1752 1.59 manu 1753 1.59 manu (void)memcpy(&resize_va, vap, sizeof(resize_va)); 1754 1.59 manu resize_va.va_mode = (mode_t)PUFFS_VNOVAL; 1755 1.59 manu if ((error = perfuse_node_setattr_ttl(pu, opc, &resize_va, 1756 1.59 manu pcr, va_ttl, xflag)) != 0) 1757 1.59 manu goto out2; 1758 1.4 manu 1759 1.59 manu vap->va_size = (u_quad_t)PUFFS_VNOVAL; 1760 1.57 manu } 1761 1.57 manu 1762 1.1 manu pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr); 1763 1.1 manu fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in); 1764 1.1 manu fsi->valid = 0; 1765 1.1 manu 1766 1.17 manu /* 1767 1.17 manu * Get a fh if the node is open for writing 1768 1.17 manu */ 1769 1.59 manu if (fh != FUSE_UNKNOWN_FH) { 1770 1.1 manu fsi->fh = fh; 1771 1.7 manu fsi->valid |= FUSE_FATTR_FH; 1772 1.1 manu } 1773 1.1 manu 1774 1.59 manu 1775 1.59 manu if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) { 1776 1.40 manu fsi->size = vap->va_size; 1777 1.1 manu fsi->valid |= FUSE_FATTR_SIZE; 1778 1.40 manu 1779 1.40 manu /* 1780 1.40 manu * Serialize anything that can touch file size 1781 1.40 manu * to avoid reordered GETATTR and SETATTR. 1782 1.40 manu * Out of order SETATTR can report stale size, 1783 1.40 manu * which will cause the kernel to truncate the file. 1784 1.53 manu * XXX Probably useless now we have a lock on GETATTR 1785 1.40 manu */ 1786 1.40 manu while (pnd->pnd_flags & PND_INRESIZE) 1787 1.40 manu requeue_request(pu, opc, PCQ_RESIZE); 1788 1.40 manu pnd->pnd_flags |= PND_INRESIZE; 1789 1.1 manu } 1790 1.1 manu 1791 1.21 manu /* 1792 1.82 manu * When not sending a time field, still fill with 1793 1.82 manu * current value, as the filesystem may just reset 1794 1.82 manu * the field to Epoch even if fsi->valid bit is 1795 1.82 manu * not set (GlusterFS does that). 1796 1.21 manu */ 1797 1.82 manu if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) { 1798 1.82 manu fsi->atime = vap->va_atime.tv_sec; 1799 1.82 manu fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec; 1800 1.82 manu fsi->valid |= FUSE_FATTR_ATIME; 1801 1.82 manu } else { 1802 1.82 manu fsi->atime = old_va->va_atime.tv_sec; 1803 1.82 manu fsi->atimensec = (uint32_t)old_va->va_atime.tv_nsec; 1804 1.82 manu } 1805 1.21 manu 1806 1.82 manu if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) { 1807 1.82 manu fsi->mtime = vap->va_mtime.tv_sec; 1808 1.82 manu fsi->mtimensec = (uint32_t)vap->va_mtime.tv_nsec; 1809 1.82 manu fsi->valid |= FUSE_FATTR_MTIME; 1810 1.82 manu } else { 1811 1.82 manu fsi->mtime = old_va->va_mtime.tv_sec; 1812 1.82 manu fsi->mtimensec = (uint32_t)old_va->va_mtime.tv_nsec; 1813 1.1 manu } 1814 1.1 manu 1815 1.59 manu if (vap->va_mode != (mode_t)PUFFS_VNOVAL) { 1816 1.9 manu fsi->mode = vap->va_mode; 1817 1.1 manu fsi->valid |= FUSE_FATTR_MODE; 1818 1.1 manu } 1819 1.1 manu 1820 1.59 manu if (vap->va_uid != (uid_t)PUFFS_VNOVAL) { 1821 1.1 manu fsi->uid = vap->va_uid; 1822 1.1 manu fsi->valid |= FUSE_FATTR_UID; 1823 1.1 manu } 1824 1.1 manu 1825 1.59 manu if (vap->va_gid != (gid_t)PUFFS_VNOVAL) { 1826 1.1 manu fsi->gid = vap->va_gid; 1827 1.1 manu fsi->valid |= FUSE_FATTR_GID; 1828 1.1 manu } 1829 1.1 manu 1830 1.7 manu if (pnd->pnd_lock_owner != 0) { 1831 1.7 manu fsi->lock_owner = pnd->pnd_lock_owner; 1832 1.1 manu fsi->valid |= FUSE_FATTR_LOCKOWNER; 1833 1.1 manu } 1834 1.1 manu 1835 1.83 manu #ifndef PUFFS_KFLAG_NOFLUSH_META 1836 1.59 manu /* 1837 1.59 manu * ftruncate() sends only va_size, and metadata cache 1838 1.59 manu * flush adds va_atime and va_mtime. Some FUSE 1839 1.59 manu * filesystems will attempt to detect ftruncate by 1840 1.59 manu * checking for FATTR_SIZE being set without 1841 1.59 manu * FATTR_UID|FATTR_GID|FATTR_ATIME|FATTR_MTIME|FATTR_MODE 1842 1.59 manu * 1843 1.59 manu * Try to adapt and remove FATTR_ATIME|FATTR_MTIME 1844 1.59 manu * if we suspect a ftruncate(). 1845 1.59 manu */ 1846 1.59 manu if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) && 1847 1.59 manu ((vap->va_mode == (mode_t)PUFFS_VNOVAL) && 1848 1.59 manu (vap->va_uid == (uid_t)PUFFS_VNOVAL) && 1849 1.59 manu (vap->va_gid == (gid_t)PUFFS_VNOVAL))) { 1850 1.59 manu fsi->atime = 0; 1851 1.59 manu fsi->atimensec = 0; 1852 1.59 manu fsi->mtime = 0; 1853 1.59 manu fsi->mtimensec = 0; 1854 1.59 manu fsi->valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME); 1855 1.59 manu } 1856 1.82 manu 1857 1.82 manu /* 1858 1.82 manu * If only atime is changed, discard the operation: it 1859 1.82 manu * happens after read, and in that case the filesystem 1860 1.91 andvar * already updated atime. NB: utimes() also change mtime. 1861 1.82 manu */ 1862 1.82 manu if (fsi->valid == FUSE_FATTR_ATIME) 1863 1.82 manu fsi->valid &= ~FUSE_FATTR_ATIME; 1864 1.83 manu #endif /* PUFFS_KFLAG_NOFLUSH_META */ 1865 1.59 manu 1866 1.59 manu /* 1867 1.59 manu * If nothing remain, discard the operation. 1868 1.59 manu */ 1869 1.59 manu if (!(fsi->valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME| 1870 1.59 manu FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) { 1871 1.59 manu error = 0; 1872 1.59 manu ps->ps_destroy_msg(pm); 1873 1.59 manu goto out; 1874 1.59 manu } 1875 1.9 manu 1876 1.40 manu #ifdef PERFUSE_DEBUG 1877 1.40 manu old_vap = puffs_pn_getvap((struct puffs_node *)opc); 1878 1.40 manu 1879 1.40 manu if ((perfuse_diagflags & PDF_RESIZE) && 1880 1.40 manu (old_vap->va_size != (u_quad_t)PUFFS_VNOVAL)) { 1881 1.40 manu resize_debug = 1; 1882 1.40 manu 1883 1.41 christos DPRINTF(">> %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__, 1884 1.41 christos (void *)opc, 1885 1.41 christos puffs_pn_getvap((struct puffs_node *)opc)->va_size, 1886 1.41 christos fsi->size); 1887 1.40 manu } 1888 1.40 manu #endif 1889 1.40 manu 1890 1.59 manu /* 1891 1.59 manu * Do not honour FAF when changing size. How do 1892 1.59 manu * you want such a thing to work? 1893 1.59 manu */ 1894 1.59 manu reply = wait_reply; 1895 1.59 manu #ifdef PUFFS_SETATTR_FAF 1896 1.59 manu if ((xflag & PUFFS_SETATTR_FAF) && !(fsi->valid & FUSE_FATTR_SIZE)) 1897 1.59 manu reply = no_reply; 1898 1.59 manu #endif 1899 1.59 manu if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), reply)) != 0) 1900 1.59 manu goto out; 1901 1.59 manu 1902 1.59 manu if (reply == no_reply) 1903 1.24 manu goto out; 1904 1.24 manu 1905 1.9 manu /* 1906 1.24 manu * Copy back the new values 1907 1.1 manu */ 1908 1.24 manu fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out); 1909 1.40 manu 1910 1.40 manu #ifdef PERFUSE_DEBUG 1911 1.40 manu if (resize_debug) 1912 1.41 christos DPRINTF("<< %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__, 1913 1.41 christos (void *)opc, old_vap->va_size, fao->attr.size); 1914 1.40 manu #endif 1915 1.40 manu 1916 1.24 manu fuse_attr_to_vap(ps, old_va, &fao->attr); 1917 1.54 manu 1918 1.54 manu if (va_ttl != NULL) { 1919 1.54 manu va_ttl->tv_sec = fao->attr_valid; 1920 1.54 manu va_ttl->tv_nsec = fao->attr_valid_nsec; 1921 1.54 manu (void)memcpy(vap, old_va, sizeof(*vap)); 1922 1.54 manu } 1923 1.43 manu 1924 1.48 manu ps->ps_destroy_msg(pm); 1925 1.59 manu error = 0; 1926 1.48 manu 1927 1.17 manu out: 1928 1.40 manu if (pnd->pnd_flags & PND_INRESIZE) { 1929 1.40 manu pnd->pnd_flags &= ~PND_INRESIZE; 1930 1.59 manu (void)dequeue_requests(opc, PCQ_RESIZE, DEQUEUE_ALL); 1931 1.40 manu } 1932 1.40 manu 1933 1.59 manu out2: 1934 1.59 manu node_rele(opc); 1935 1.1 manu return error; 1936 1.1 manu } 1937 1.1 manu 1938 1.1 manu int 1939 1.52 matt perfuse_node_poll(struct puffs_usermount *pu, puffs_cookie_t opc, int *events) 1940 1.1 manu { 1941 1.1 manu struct perfuse_state *ps; 1942 1.1 manu perfuse_msg_t *pm; 1943 1.1 manu struct fuse_poll_in *fpi; 1944 1.1 manu struct fuse_poll_out *fpo; 1945 1.1 manu int error; 1946 1.1 manu 1947 1.59 manu node_ref(opc); 1948 1.1 manu ps = puffs_getspecific(pu); 1949 1.1 manu /* 1950 1.1 manu * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set. 1951 1.36 manu * 1952 1.36 manu * XXX ps_new_msg() is called with NULL creds, which will 1953 1.36 manu * be interpreted as FUSE superuser. We have no way to 1954 1.36 manu * know the requesting process' credential, but since poll 1955 1.36 manu * is supposed to operate on a file that has been open, 1956 1.36 manu * permission should have already been checked at open time. 1957 1.36 manu * That still may breaks on filesystems that provides odd 1958 1.36 manu * semantics. 1959 1.1 manu */ 1960 1.1 manu pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL); 1961 1.1 manu fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in); 1962 1.86 manu fpi->fh = PN_ISDIR(opc) ? FUSE_UNKNOWN_FH : perfuse_get_fh(opc, FREAD); 1963 1.1 manu fpi->kh = 0; 1964 1.1 manu fpi->flags = 0; 1965 1.1 manu 1966 1.2 manu #ifdef PERFUSE_DEBUG 1967 1.2 manu if (perfuse_diagflags & PDF_FH) 1968 1.48 manu DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", " 1969 1.48 manu "fh = 0x%"PRIx64"\n", __func__, (void *)opc, 1970 1.43 manu PERFUSE_NODE_DATA(opc)->pnd_nodeid, fpi->fh); 1971 1.2 manu #endif 1972 1.16 manu if ((error = xchg_msg(pu, opc, pm, sizeof(*fpo), wait_reply)) != 0) 1973 1.59 manu goto out; 1974 1.1 manu 1975 1.1 manu fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out); 1976 1.1 manu *events = fpo->revents; 1977 1.48 manu 1978 1.1 manu ps->ps_destroy_msg(pm); 1979 1.59 manu error = 0; 1980 1.1 manu 1981 1.59 manu out: 1982 1.59 manu node_rele(opc); 1983 1.59 manu return error; 1984 1.1 manu } 1985 1.1 manu 1986 1.1 manu /* ARGSUSED2 */ 1987 1.1 manu int 1988 1.52 matt perfuse_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc, 1989 1.52 matt const struct puffs_cred *pcr, int flags, off_t offlo, off_t offhi) 1990 1.1 manu { 1991 1.14 manu int op; 1992 1.1 manu perfuse_msg_t *pm; 1993 1.1 manu struct perfuse_state *ps; 1994 1.2 manu struct perfuse_node_data *pnd; 1995 1.1 manu struct fuse_fsync_in *ffi; 1996 1.2 manu uint64_t fh; 1997 1.59 manu int error = 0; 1998 1.1 manu 1999 1.2 manu pm = NULL; 2000 1.14 manu ps = puffs_getspecific(pu); 2001 1.17 manu pnd = PERFUSE_NODE_DATA(opc); 2002 1.17 manu 2003 1.17 manu /* 2004 1.17 manu * No need to sync a removed node 2005 1.17 manu */ 2006 1.17 manu if (pnd->pnd_flags & PND_REMOVED) 2007 1.17 manu return 0; 2008 1.17 manu 2009 1.17 manu /* 2010 1.17 manu * We do not sync closed files. They have been 2011 1.17 manu * sync at inactive time already. 2012 1.17 manu */ 2013 1.17 manu if (!(pnd->pnd_flags & PND_OPEN)) 2014 1.17 manu return 0; 2015 1.2 manu 2016 1.59 manu node_ref(opc); 2017 1.59 manu 2018 1.86 manu if (PN_ISDIR(opc)) 2019 1.14 manu op = FUSE_FSYNCDIR; 2020 1.14 manu else /* VREG but also other types such as VLNK */ 2021 1.14 manu op = FUSE_FSYNC; 2022 1.1 manu 2023 1.1 manu /* 2024 1.2 manu * Do not sync if there are no change to sync 2025 1.14 manu * XXX remove that test on files if we implement mmap 2026 1.2 manu */ 2027 1.2 manu #ifdef PERFUSE_DEBUG 2028 1.2 manu if (perfuse_diagflags & PDF_SYNC) 2029 1.2 manu DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n", 2030 1.59 manu __func__, (void*)opc, perfuse_node_path(ps, opc), 2031 1.2 manu pnd->pnd_flags & PND_DIRTY ? "" : "not "); 2032 1.2 manu #endif 2033 1.2 manu if (!(pnd->pnd_flags & PND_DIRTY)) 2034 1.59 manu goto out; 2035 1.2 manu 2036 1.18 manu /* 2037 1.18 manu * It seems NetBSD can call fsync without open first 2038 1.18 manu * glusterfs complain in such a situation: 2039 1.18 manu * "FSYNC() ERR => -1 (Invalid argument)" 2040 1.18 manu * The file will be closed at inactive time. 2041 1.18 manu * 2042 1.18 manu * We open the directory for reading in order to sync. 2043 1.18 manu * This sounds rather counterintuitive, but it works. 2044 1.18 manu */ 2045 1.18 manu if (!(pnd->pnd_flags & PND_WFH)) { 2046 1.18 manu if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0) 2047 1.18 manu goto out; 2048 1.18 manu } 2049 1.18 manu 2050 1.17 manu if (op == FUSE_FSYNCDIR) 2051 1.17 manu fh = perfuse_get_fh(opc, FREAD); 2052 1.17 manu else 2053 1.17 manu fh = perfuse_get_fh(opc, FWRITE); 2054 1.2 manu 2055 1.2 manu /* 2056 1.1 manu * If fsync_flags is set, meta data should not be flushed. 2057 1.1 manu */ 2058 1.36 manu pm = ps->ps_new_msg(pu, opc, op, sizeof(*ffi), pcr); 2059 1.1 manu ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in); 2060 1.2 manu ffi->fh = fh; 2061 1.1 manu ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1; 2062 1.1 manu 2063 1.2 manu #ifdef PERFUSE_DEBUG 2064 1.2 manu if (perfuse_diagflags & PDF_FH) 2065 1.43 manu DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 2066 1.2 manu __func__, (void *)opc, 2067 1.43 manu PERFUSE_NODE_DATA(opc)->pnd_nodeid, ffi->fh); 2068 1.2 manu #endif 2069 1.2 manu 2070 1.16 manu if ((error = xchg_msg(pu, opc, pm, 2071 1.16 manu NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0) 2072 1.1 manu goto out; 2073 1.1 manu 2074 1.1 manu /* 2075 1.2 manu * No reply beyond fuse_out_header: nothing to do on success 2076 1.2 manu * just clear the dirty flag 2077 1.1 manu */ 2078 1.2 manu pnd->pnd_flags &= ~PND_DIRTY; 2079 1.2 manu 2080 1.2 manu #ifdef PERFUSE_DEBUG 2081 1.2 manu if (perfuse_diagflags & PDF_SYNC) 2082 1.2 manu DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n", 2083 1.59 manu __func__, (void*)opc, perfuse_node_path(ps, opc)); 2084 1.2 manu #endif 2085 1.2 manu 2086 1.48 manu ps->ps_destroy_msg(pm); 2087 1.59 manu error = 0; 2088 1.48 manu 2089 1.1 manu out: 2090 1.14 manu /* 2091 1.14 manu * ENOSYS is not returned to kernel, 2092 1.14 manu */ 2093 1.1 manu if (error == ENOSYS) 2094 1.14 manu error = 0; 2095 1.1 manu 2096 1.59 manu node_rele(opc); 2097 1.1 manu return error; 2098 1.1 manu } 2099 1.1 manu 2100 1.1 manu int 2101 1.52 matt perfuse_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc, 2102 1.52 matt puffs_cookie_t targ, const struct puffs_cn *pcn) 2103 1.1 manu { 2104 1.1 manu struct perfuse_state *ps; 2105 1.7 manu struct perfuse_node_data *pnd; 2106 1.1 manu perfuse_msg_t *pm; 2107 1.1 manu char *path; 2108 1.1 manu const char *name; 2109 1.1 manu size_t len; 2110 1.1 manu int error; 2111 1.1 manu 2112 1.7 manu pnd = PERFUSE_NODE_DATA(opc); 2113 1.7 manu 2114 1.18 manu if ((pnd->pnd_flags & PND_REMOVED) || 2115 1.18 manu (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_REMOVED)) 2116 1.18 manu return ENOENT; 2117 1.18 manu 2118 1.17 manu #ifdef PERFUSE_DEBUG 2119 1.1 manu if (targ == NULL) 2120 1.1 manu DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__); 2121 1.1 manu 2122 1.17 manu if (perfuse_diagflags & (PDF_FH|PDF_FILENAME)) 2123 1.17 manu DPRINTF("%s: opc = %p, remove opc = %p, file = \"%s\"\n", 2124 1.18 manu __func__, (void *)opc, (void *)targ, pcn->pcn_name); 2125 1.17 manu #endif 2126 1.59 manu node_ref(opc); 2127 1.59 manu node_ref(targ); 2128 1.59 manu 2129 1.17 manu /* 2130 1.18 manu * Await for all operations on the deleted node to drain, 2131 1.18 manu * as the filesystem may be confused to have it deleted 2132 1.18 manu * during a getattr 2133 1.17 manu */ 2134 1.59 manu while (PERFUSE_NODE_DATA(targ)->pnd_inxchg) 2135 1.18 manu requeue_request(pu, targ, PCQ_AFTERXCHG); 2136 1.17 manu 2137 1.19 manu ps = puffs_getspecific(pu); 2138 1.19 manu pnd = PERFUSE_NODE_DATA(opc); 2139 1.19 manu name = pcn->pcn_name; 2140 1.19 manu len = pcn->pcn_namelen + 1; 2141 1.19 manu 2142 1.36 manu pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred); 2143 1.1 manu path = _GET_INPAYLOAD(ps, pm, char *); 2144 1.1 manu (void)strlcpy(path, name, len); 2145 1.1 manu 2146 1.16 manu if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2147 1.59 manu goto out; 2148 1.1 manu 2149 1.59 manu perfuse_cache_flush(targ); 2150 1.18 manu PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED; 2151 1.59 manu 2152 1.18 manu if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN)) 2153 1.18 manu puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 2154 1.14 manu 2155 1.14 manu /* 2156 1.14 manu * The parent directory needs a sync 2157 1.14 manu */ 2158 1.14 manu PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2159 1.17 manu 2160 1.17 manu #ifdef PERFUSE_DEBUG 2161 1.17 manu if (perfuse_diagflags & PDF_FILENAME) 2162 1.43 manu DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n", 2163 1.43 manu __func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid, 2164 1.18 manu pcn->pcn_name); 2165 1.17 manu #endif 2166 1.1 manu ps->ps_destroy_msg(pm); 2167 1.59 manu error = 0; 2168 1.1 manu 2169 1.59 manu out: 2170 1.59 manu node_rele(opc); 2171 1.59 manu node_rele(targ); 2172 1.59 manu return error; 2173 1.1 manu } 2174 1.1 manu 2175 1.1 manu int 2176 1.52 matt perfuse_node_link(struct puffs_usermount *pu, puffs_cookie_t opc, 2177 1.52 matt puffs_cookie_t targ, const struct puffs_cn *pcn) 2178 1.1 manu { 2179 1.1 manu struct perfuse_state *ps; 2180 1.1 manu perfuse_msg_t *pm; 2181 1.1 manu const char *name; 2182 1.1 manu size_t len; 2183 1.1 manu struct puffs_node *pn; 2184 1.1 manu struct fuse_link_in *fli; 2185 1.1 manu int error; 2186 1.18 manu 2187 1.18 manu if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2188 1.18 manu return ENOENT; 2189 1.1 manu 2190 1.59 manu node_ref(opc); 2191 1.59 manu node_ref(targ); 2192 1.1 manu ps = puffs_getspecific(pu); 2193 1.1 manu pn = (struct puffs_node *)targ; 2194 1.18 manu name = pcn->pcn_name; 2195 1.18 manu len = sizeof(*fli) + pcn->pcn_namelen + 1; 2196 1.1 manu 2197 1.36 manu pm = ps->ps_new_msg(pu, opc, FUSE_LINK, len, pcn->pcn_cred); 2198 1.1 manu fli = GET_INPAYLOAD(ps, pm, fuse_link_in); 2199 1.43 manu fli->oldnodeid = PERFUSE_NODE_DATA(pn)->pnd_nodeid; 2200 1.1 manu (void)strlcpy((char *)(void *)(fli + 1), name, len - sizeof(*fli)); 2201 1.1 manu 2202 1.48 manu if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2203 1.59 manu goto out; 2204 1.1 manu 2205 1.1 manu ps->ps_destroy_msg(pm); 2206 1.59 manu error = 0; 2207 1.1 manu 2208 1.59 manu out: 2209 1.59 manu node_rele(opc); 2210 1.59 manu node_rele(targ); 2211 1.59 manu return error; 2212 1.1 manu } 2213 1.1 manu 2214 1.1 manu int 2215 1.52 matt perfuse_node_rename(struct puffs_usermount *pu, puffs_cookie_t opc, 2216 1.52 matt puffs_cookie_t src, const struct puffs_cn *pcn_src, 2217 1.52 matt puffs_cookie_t targ_dir, puffs_cookie_t targ, 2218 1.52 matt const struct puffs_cn *pcn_targ) 2219 1.1 manu { 2220 1.1 manu struct perfuse_state *ps; 2221 1.59 manu struct perfuse_node_data *dstdir_pnd; 2222 1.1 manu perfuse_msg_t *pm; 2223 1.1 manu struct fuse_rename_in *fri; 2224 1.1 manu const char *newname; 2225 1.1 manu const char *oldname; 2226 1.1 manu char *np; 2227 1.1 manu int error; 2228 1.1 manu size_t len; 2229 1.1 manu size_t newname_len; 2230 1.1 manu size_t oldname_len; 2231 1.1 manu 2232 1.18 manu if ((PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) || 2233 1.18 manu (PERFUSE_NODE_DATA(src)->pnd_flags & PND_REMOVED) || 2234 1.18 manu (PERFUSE_NODE_DATA(targ_dir)->pnd_flags & PND_REMOVED)) 2235 1.18 manu return ENOENT; 2236 1.18 manu 2237 1.59 manu node_ref(opc); 2238 1.59 manu node_ref(src); 2239 1.59 manu 2240 1.18 manu /* 2241 1.18 manu * Await for all operations on the deleted node to drain, 2242 1.18 manu * as the filesystem may be confused to have it deleted 2243 1.18 manu * during a getattr 2244 1.18 manu */ 2245 1.18 manu if ((struct puffs_node *)targ != NULL) { 2246 1.59 manu node_ref(targ); 2247 1.59 manu while (PERFUSE_NODE_DATA(targ)->pnd_inxchg) 2248 1.18 manu requeue_request(pu, targ, PCQ_AFTERXCHG); 2249 1.18 manu } else { 2250 1.59 manu while (PERFUSE_NODE_DATA(src)->pnd_inxchg) 2251 1.18 manu requeue_request(pu, src, PCQ_AFTERXCHG); 2252 1.18 manu } 2253 1.18 manu 2254 1.1 manu ps = puffs_getspecific(pu); 2255 1.18 manu newname = pcn_targ->pcn_name; 2256 1.18 manu newname_len = pcn_targ->pcn_namelen + 1; 2257 1.18 manu oldname = pcn_src->pcn_name; 2258 1.18 manu oldname_len = pcn_src->pcn_namelen + 1; 2259 1.1 manu 2260 1.1 manu len = sizeof(*fri) + oldname_len + newname_len; 2261 1.36 manu pm = ps->ps_new_msg(pu, opc, FUSE_RENAME, len, pcn_targ->pcn_cred); 2262 1.1 manu fri = GET_INPAYLOAD(ps, pm, fuse_rename_in); 2263 1.43 manu fri->newdir = PERFUSE_NODE_DATA(targ_dir)->pnd_nodeid; 2264 1.1 manu np = (char *)(void *)(fri + 1); 2265 1.1 manu (void)strlcpy(np, oldname, oldname_len); 2266 1.1 manu np += oldname_len; 2267 1.1 manu (void)strlcpy(np, newname, newname_len); 2268 1.1 manu 2269 1.16 manu if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2270 1.59 manu goto out; 2271 1.1 manu 2272 1.19 manu 2273 1.59 manu /* 2274 1.59 manu * Record new parent nodeid 2275 1.59 manu */ 2276 1.59 manu dstdir_pnd = PERFUSE_NODE_DATA(targ_dir); 2277 1.59 manu PERFUSE_NODE_DATA(src)->pnd_parent_nodeid = dstdir_pnd->pnd_nodeid; 2278 1.19 manu 2279 1.59 manu if (opc != targ_dir) 2280 1.59 manu dstdir_pnd->pnd_flags |= PND_DIRTY; 2281 1.15 manu 2282 1.59 manu if (strcmp(newname, "..") != 0) 2283 1.59 manu (void)strlcpy(PERFUSE_NODE_DATA(src)->pnd_name, 2284 1.59 manu newname, MAXPATHLEN); 2285 1.59 manu else 2286 1.59 manu PERFUSE_NODE_DATA(src)->pnd_name[0] = 0; /* forget name */ 2287 1.18 manu 2288 1.19 manu PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2289 1.18 manu 2290 1.59 manu if ((struct puffs_node *)targ != NULL) { 2291 1.59 manu perfuse_cache_flush(targ); 2292 1.19 manu PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED; 2293 1.59 manu } 2294 1.17 manu 2295 1.17 manu #ifdef PERFUSE_DEBUG 2296 1.17 manu if (perfuse_diagflags & PDF_FILENAME) 2297 1.43 manu DPRINTF("%s: nodeid = 0x%"PRIx64" file = \"%s\" renamed \"%s\" " 2298 1.43 manu "nodeid = 0x%"PRIx64" -> nodeid = 0x%"PRIx64" \"%s\"\n", 2299 1.43 manu __func__, PERFUSE_NODE_DATA(src)->pnd_nodeid, 2300 1.19 manu pcn_src->pcn_name, pcn_targ->pcn_name, 2301 1.43 manu PERFUSE_NODE_DATA(opc)->pnd_nodeid, 2302 1.43 manu PERFUSE_NODE_DATA(targ_dir)->pnd_nodeid, 2303 1.59 manu perfuse_node_path(ps, targ_dir)); 2304 1.17 manu #endif 2305 1.17 manu 2306 1.48 manu ps->ps_destroy_msg(pm); 2307 1.59 manu error = 0; 2308 1.1 manu 2309 1.59 manu out: 2310 1.59 manu node_rele(opc); 2311 1.59 manu node_rele(src); 2312 1.59 manu if ((struct puffs_node *)targ != NULL) 2313 1.59 manu node_rele(targ); 2314 1.59 manu 2315 1.59 manu return error; 2316 1.1 manu } 2317 1.1 manu 2318 1.1 manu int 2319 1.52 matt perfuse_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc, 2320 1.52 matt struct puffs_newinfo *pni, const struct puffs_cn *pcn, 2321 1.52 matt const struct vattr *vap) 2322 1.1 manu { 2323 1.1 manu struct perfuse_state *ps; 2324 1.1 manu perfuse_msg_t *pm; 2325 1.1 manu struct fuse_mkdir_in *fmi; 2326 1.1 manu const char *path; 2327 1.1 manu size_t len; 2328 1.59 manu int error; 2329 1.1 manu 2330 1.18 manu if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2331 1.18 manu return ENOENT; 2332 1.18 manu 2333 1.59 manu node_ref(opc); 2334 1.1 manu ps = puffs_getspecific(pu); 2335 1.18 manu path = pcn->pcn_name; 2336 1.18 manu len = sizeof(*fmi) + pcn->pcn_namelen + 1; 2337 1.1 manu 2338 1.36 manu pm = ps->ps_new_msg(pu, opc, FUSE_MKDIR, len, pcn->pcn_cred); 2339 1.1 manu fmi = GET_INPAYLOAD(ps, pm, fuse_mkdir_in); 2340 1.9 manu fmi->mode = vap->va_mode; 2341 1.9 manu fmi->umask = 0; /* Seems unused by libfuse? */ 2342 1.1 manu (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi)); 2343 1.1 manu 2344 1.59 manu error = node_mk_common(pu, opc, pni, pcn, pm); 2345 1.59 manu 2346 1.59 manu node_rele(opc); 2347 1.59 manu return error; 2348 1.1 manu } 2349 1.1 manu 2350 1.1 manu 2351 1.1 manu int 2352 1.52 matt perfuse_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc, 2353 1.52 matt puffs_cookie_t targ, const struct puffs_cn *pcn) 2354 1.1 manu { 2355 1.1 manu struct perfuse_state *ps; 2356 1.7 manu struct perfuse_node_data *pnd; 2357 1.1 manu perfuse_msg_t *pm; 2358 1.1 manu char *path; 2359 1.1 manu const char *name; 2360 1.1 manu size_t len; 2361 1.1 manu int error; 2362 1.1 manu 2363 1.7 manu pnd = PERFUSE_NODE_DATA(opc); 2364 1.47 manu 2365 1.47 manu if ((pnd->pnd_flags & PND_REMOVED) || 2366 1.47 manu (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_REMOVED)) 2367 1.18 manu return ENOENT; 2368 1.18 manu 2369 1.73 manu /* 2370 1.90 andvar * Attempt to rmdir dir/.. should raise ENOTEMPTY 2371 1.73 manu */ 2372 1.73 manu if (PERFUSE_NODE_DATA(targ)->pnd_nodeid == pnd->pnd_parent_nodeid) 2373 1.73 manu return ENOTEMPTY; 2374 1.73 manu 2375 1.59 manu node_ref(opc); 2376 1.59 manu node_ref(targ); 2377 1.59 manu 2378 1.17 manu /* 2379 1.18 manu * Await for all operations on the deleted node to drain, 2380 1.18 manu * as the filesystem may be confused to have it deleted 2381 1.18 manu * during a getattr 2382 1.17 manu */ 2383 1.59 manu while (PERFUSE_NODE_DATA(targ)->pnd_inxchg) 2384 1.18 manu requeue_request(pu, targ, PCQ_AFTERXCHG); 2385 1.18 manu 2386 1.18 manu ps = puffs_getspecific(pu); 2387 1.18 manu name = pcn->pcn_name; 2388 1.18 manu len = pcn->pcn_namelen + 1; 2389 1.17 manu 2390 1.36 manu pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred); 2391 1.1 manu path = _GET_INPAYLOAD(ps, pm, char *); 2392 1.1 manu (void)strlcpy(path, name, len); 2393 1.1 manu 2394 1.16 manu if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2395 1.59 manu goto out; 2396 1.1 manu 2397 1.59 manu perfuse_cache_flush(targ); 2398 1.18 manu PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED; 2399 1.59 manu 2400 1.18 manu if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN)) 2401 1.18 manu puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 2402 1.2 manu 2403 1.14 manu /* 2404 1.14 manu * The parent directory needs a sync 2405 1.14 manu */ 2406 1.14 manu PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY; 2407 1.17 manu 2408 1.17 manu #ifdef PERFUSE_DEBUG 2409 1.17 manu if (perfuse_diagflags & PDF_FILENAME) 2410 1.43 manu DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n", 2411 1.43 manu __func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid, 2412 1.59 manu perfuse_node_path(ps, targ)); 2413 1.17 manu #endif 2414 1.1 manu ps->ps_destroy_msg(pm); 2415 1.59 manu error = 0; 2416 1.1 manu 2417 1.59 manu out: 2418 1.59 manu node_rele(opc); 2419 1.59 manu node_rele(targ); 2420 1.59 manu return error; 2421 1.1 manu } 2422 1.1 manu 2423 1.1 manu /* vap is unused */ 2424 1.1 manu /* ARGSUSED4 */ 2425 1.1 manu int 2426 1.52 matt perfuse_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc, 2427 1.52 matt struct puffs_newinfo *pni, const struct puffs_cn *pcn_src, 2428 1.52 matt const struct vattr *vap, const char *link_target) 2429 1.1 manu { 2430 1.1 manu struct perfuse_state *ps; 2431 1.1 manu perfuse_msg_t *pm; 2432 1.1 manu char *np; 2433 1.1 manu const char *path; 2434 1.1 manu size_t path_len; 2435 1.1 manu size_t linkname_len; 2436 1.1 manu size_t len; 2437 1.59 manu int error; 2438 1.1 manu 2439 1.18 manu if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2440 1.18 manu return ENOENT; 2441 1.18 manu 2442 1.59 manu node_ref(opc); 2443 1.1 manu ps = puffs_getspecific(pu); 2444 1.18 manu path = pcn_src->pcn_name; 2445 1.18 manu path_len = pcn_src->pcn_namelen + 1; 2446 1.1 manu linkname_len = strlen(link_target) + 1; 2447 1.1 manu len = path_len + linkname_len; 2448 1.1 manu 2449 1.36 manu pm = ps->ps_new_msg(pu, opc, FUSE_SYMLINK, len, pcn_src->pcn_cred); 2450 1.1 manu np = _GET_INPAYLOAD(ps, pm, char *); 2451 1.1 manu (void)strlcpy(np, path, path_len); 2452 1.1 manu np += path_len; 2453 1.1 manu (void)strlcpy(np, link_target, linkname_len); 2454 1.1 manu 2455 1.59 manu error = node_mk_common(pu, opc, pni, pcn_src, pm); 2456 1.59 manu 2457 1.59 manu node_rele(opc); 2458 1.59 manu return error; 2459 1.1 manu } 2460 1.1 manu 2461 1.33 manu /* ARGSUSED4 */ 2462 1.1 manu int 2463 1.52 matt perfuse_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc, 2464 1.52 matt struct dirent *dent, off_t *readoff, size_t *reslen, 2465 1.52 matt const struct puffs_cred *pcr, int *eofflag, off_t *cookies, 2466 1.52 matt size_t *ncookies) 2467 1.1 manu { 2468 1.1 manu perfuse_msg_t *pm; 2469 1.1 manu uint64_t fh; 2470 1.1 manu struct perfuse_state *ps; 2471 1.1 manu struct perfuse_node_data *pnd; 2472 1.1 manu struct fuse_read_in *fri; 2473 1.1 manu struct fuse_out_header *foh; 2474 1.1 manu struct fuse_dirent *fd; 2475 1.1 manu size_t foh_len; 2476 1.1 manu int error; 2477 1.16 manu size_t fd_maxlen; 2478 1.1 manu 2479 1.1 manu error = 0; 2480 1.59 manu node_ref(opc); 2481 1.1 manu ps = puffs_getspecific(pu); 2482 1.1 manu 2483 1.1 manu /* 2484 1.1 manu * readdir state is kept at node level, and several readdir 2485 1.1 manu * requests can be issued at the same time on the same node. 2486 1.1 manu * We need to queue requests so that only one is in readdir 2487 1.1 manu * code at the same time. 2488 1.1 manu */ 2489 1.1 manu pnd = PERFUSE_NODE_DATA(opc); 2490 1.1 manu while (pnd->pnd_flags & PND_INREADDIR) 2491 1.1 manu requeue_request(pu, opc, PCQ_READDIR); 2492 1.1 manu pnd->pnd_flags |= PND_INREADDIR; 2493 1.1 manu 2494 1.1 manu #ifdef PERFUSE_DEBUG 2495 1.1 manu if (perfuse_diagflags & PDF_READDIR) 2496 1.1 manu DPRINTF("%s: READDIR opc = %p enter critical section\n", 2497 1.1 manu __func__, (void *)opc); 2498 1.1 manu #endif 2499 1.1 manu /* 2500 1.33 manu * Re-initialize pnd->pnd_fd_cookie on the first readdir for a node 2501 1.33 manu */ 2502 1.33 manu if (*readoff == 0) 2503 1.33 manu pnd->pnd_fd_cookie = 0; 2504 1.33 manu 2505 1.33 manu /* 2506 1.91 andvar * Do we already have the data buffered? 2507 1.1 manu */ 2508 1.1 manu if (pnd->pnd_dirent != NULL) 2509 1.1 manu goto out; 2510 1.1 manu pnd->pnd_dirent_len = 0; 2511 1.1 manu 2512 1.18 manu /* 2513 1.18 manu * It seems NetBSD can call readdir without open first 2514 1.18 manu * libfuse will crash if it is done that way, hence open first. 2515 1.18 manu */ 2516 1.18 manu if (!(pnd->pnd_flags & PND_OPEN)) { 2517 1.18 manu if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0) 2518 1.18 manu goto out; 2519 1.18 manu } 2520 1.18 manu 2521 1.86 manu fh = perfuse_get_fh(opc, FREAD); 2522 1.2 manu 2523 1.2 manu #ifdef PERFUSE_DEBUG 2524 1.2 manu if (perfuse_diagflags & PDF_FH) 2525 1.48 manu DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", " 2526 1.48 manu "rfh = 0x%"PRIx64"\n", __func__, (void *)opc, 2527 1.43 manu PERFUSE_NODE_DATA(opc)->pnd_nodeid, fh); 2528 1.2 manu #endif 2529 1.2 manu 2530 1.1 manu pnd->pnd_all_fd = NULL; 2531 1.1 manu pnd->pnd_all_fd_len = 0; 2532 1.16 manu fd_maxlen = ps->ps_max_readahead - sizeof(*foh); 2533 1.33 manu 2534 1.1 manu do { 2535 1.1 manu size_t fd_len; 2536 1.1 manu char *afdp; 2537 1.1 manu 2538 1.1 manu pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr); 2539 1.1 manu 2540 1.1 manu /* 2541 1.1 manu * read_flags, lock_owner and flags are unused in libfuse 2542 1.1 manu */ 2543 1.1 manu fri = GET_INPAYLOAD(ps, pm, fuse_read_in); 2544 1.1 manu fri->fh = fh; 2545 1.33 manu fri->offset = pnd->pnd_fd_cookie; 2546 1.24 manu fri->size = (uint32_t)fd_maxlen; 2547 1.1 manu fri->read_flags = 0; 2548 1.1 manu fri->lock_owner = 0; 2549 1.1 manu fri->flags = 0; 2550 1.1 manu 2551 1.16 manu if ((error = xchg_msg(pu, opc, pm, 2552 1.16 manu UNSPEC_REPLY_LEN, wait_reply)) != 0) 2553 1.1 manu goto out; 2554 1.1 manu 2555 1.1 manu /* 2556 1.1 manu * There are many puffs_framebufs calls later, 2557 1.1 manu * therefore foh will not be valid for a long time. 2558 1.1 manu * Just get the length and forget it. 2559 1.1 manu */ 2560 1.1 manu foh = GET_OUTHDR(ps, pm); 2561 1.1 manu foh_len = foh->len; 2562 1.1 manu 2563 1.1 manu /* 2564 1.16 manu * Empty read: we reached the end of the buffer. 2565 1.1 manu */ 2566 1.33 manu if (foh_len == sizeof(*foh)) { 2567 1.48 manu ps->ps_destroy_msg(pm); 2568 1.33 manu *eofflag = 1; 2569 1.1 manu break; 2570 1.33 manu } 2571 1.1 manu 2572 1.1 manu /* 2573 1.33 manu * Check for corrupted message. 2574 1.1 manu */ 2575 1.1 manu if (foh_len < sizeof(*foh) + sizeof(*fd)) { 2576 1.48 manu ps->ps_destroy_msg(pm); 2577 1.1 manu DWARNX("readdir reply too short"); 2578 1.1 manu error = EIO; 2579 1.1 manu goto out; 2580 1.1 manu } 2581 1.1 manu 2582 1.1 manu 2583 1.1 manu fd = GET_OUTPAYLOAD(ps, pm, fuse_dirent); 2584 1.1 manu fd_len = foh_len - sizeof(*foh); 2585 1.1 manu 2586 1.1 manu pnd->pnd_all_fd = realloc(pnd->pnd_all_fd, 2587 1.1 manu pnd->pnd_all_fd_len + fd_len); 2588 1.1 manu if (pnd->pnd_all_fd == NULL) 2589 1.39 christos DERR(EX_OSERR, "%s: malloc failed", __func__); 2590 1.1 manu 2591 1.1 manu afdp = (char *)(void *)pnd->pnd_all_fd + pnd->pnd_all_fd_len; 2592 1.1 manu (void)memcpy(afdp, fd, fd_len); 2593 1.1 manu 2594 1.1 manu pnd->pnd_all_fd_len += fd_len; 2595 1.33 manu 2596 1.33 manu /* 2597 1.33 manu * The fd->off field is used as a cookie for 2598 1.33 manu * resuming the next readdir() where this one was left. 2599 1.33 manu */ 2600 1.33 manu pnd->pnd_fd_cookie = readdir_last_cookie(fd, fd_len); 2601 1.1 manu 2602 1.1 manu ps->ps_destroy_msg(pm); 2603 1.33 manu } while (1 /* CONSTCOND */); 2604 1.16 manu 2605 1.33 manu if (pnd->pnd_all_fd != NULL) { 2606 1.33 manu if (fuse_to_dirent(pu, opc, pnd->pnd_all_fd, 2607 1.33 manu pnd->pnd_all_fd_len) == -1) 2608 1.33 manu error = EIO; 2609 1.33 manu } 2610 1.1 manu 2611 1.1 manu out: 2612 1.1 manu if (pnd->pnd_all_fd != NULL) { 2613 1.1 manu free(pnd->pnd_all_fd); 2614 1.1 manu pnd->pnd_all_fd = NULL; 2615 1.1 manu pnd->pnd_all_fd_len = 0; 2616 1.1 manu } 2617 1.1 manu 2618 1.1 manu if (error == 0) 2619 1.59 manu readdir_buffered(opc, dent, readoff, reslen); 2620 1.1 manu 2621 1.1 manu /* 2622 1.1 manu * Schedule queued readdir requests 2623 1.1 manu */ 2624 1.1 manu pnd->pnd_flags &= ~PND_INREADDIR; 2625 1.59 manu (void)dequeue_requests(opc, PCQ_READDIR, DEQUEUE_ALL); 2626 1.1 manu 2627 1.1 manu #ifdef PERFUSE_DEBUG 2628 1.1 manu if (perfuse_diagflags & PDF_READDIR) 2629 1.1 manu DPRINTF("%s: READDIR opc = %p exit critical section\n", 2630 1.1 manu __func__, (void *)opc); 2631 1.1 manu #endif 2632 1.1 manu 2633 1.59 manu node_rele(opc); 2634 1.1 manu return error; 2635 1.1 manu } 2636 1.1 manu 2637 1.1 manu int 2638 1.52 matt perfuse_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc, 2639 1.52 matt const struct puffs_cred *pcr, char *linkname, size_t *linklen) 2640 1.1 manu { 2641 1.1 manu struct perfuse_state *ps; 2642 1.1 manu perfuse_msg_t *pm; 2643 1.1 manu int error; 2644 1.1 manu size_t len; 2645 1.1 manu struct fuse_out_header *foh; 2646 1.1 manu 2647 1.18 manu if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) 2648 1.18 manu return ENOENT; 2649 1.18 manu 2650 1.59 manu node_ref(opc); 2651 1.1 manu ps = puffs_getspecific(pu); 2652 1.1 manu 2653 1.1 manu pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr); 2654 1.1 manu 2655 1.16 manu if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 2656 1.59 manu goto out; 2657 1.1 manu 2658 1.1 manu foh = GET_OUTHDR(ps, pm); 2659 1.22 manu len = foh->len - sizeof(*foh); 2660 1.1 manu if (len > *linklen) 2661 1.5 manu DERRX(EX_PROTOCOL, "path len = %zd too long", len); 2662 1.22 manu if (len == 0) 2663 1.22 manu DERRX(EX_PROTOCOL, "path len = %zd too short", len); 2664 1.1 manu 2665 1.70 manu (void)memcpy(linkname, _GET_OUTPAYLOAD(ps, pm, char *), len); 2666 1.70 manu 2667 1.22 manu /* 2668 1.22 manu * FUSE filesystems return a NUL terminated string, we 2669 1.70 manu * do not want the trailing \0 2670 1.22 manu */ 2671 1.70 manu while (len > 0 && linkname[len - 1] == '\0') 2672 1.70 manu len--; 2673 1.70 manu 2674 1.70 manu *linklen = len; 2675 1.48 manu 2676 1.1 manu ps->ps_destroy_msg(pm); 2677 1.59 manu error = 0; 2678 1.1 manu 2679 1.59 manu out: 2680 1.59 manu node_rele(opc); 2681 1.59 manu return error; 2682 1.1 manu } 2683 1.1 manu 2684 1.1 manu int 2685 1.85 manu perfuse_node_reclaim2(struct puffs_usermount *pu, 2686 1.85 manu puffs_cookie_t opc, int nlookup) 2687 1.1 manu { 2688 1.1 manu struct perfuse_state *ps; 2689 1.1 manu perfuse_msg_t *pm; 2690 1.2 manu struct perfuse_node_data *pnd; 2691 1.1 manu struct fuse_forget_in *ffi; 2692 1.1 manu 2693 1.85 manu #ifdef PERFUSE_DEBUG 2694 1.85 manu if (perfuse_diagflags & PDF_RECLAIM) 2695 1.85 manu DPRINTF("%s called with opc = %p, nlookup = %d\n", 2696 1.85 manu __func__, (void *)opc, nlookup); 2697 1.85 manu #endif 2698 1.85 manu if (opc == 0 || nlookup == 0) { 2699 1.54 manu return 0; 2700 1.85 manu } 2701 1.54 manu 2702 1.1 manu ps = puffs_getspecific(pu); 2703 1.2 manu pnd = PERFUSE_NODE_DATA(opc); 2704 1.1 manu 2705 1.1 manu /* 2706 1.1 manu * Never forget the root. 2707 1.1 manu */ 2708 1.43 manu if (pnd->pnd_nodeid == FUSE_ROOT_ID) 2709 1.1 manu return 0; 2710 1.1 manu 2711 1.85 manu #ifdef PERFUSE_DEBUG 2712 1.85 manu if (perfuse_diagflags & PDF_RECLAIM) 2713 1.85 manu DPRINTF("%s (nodeid %"PRId64") reclaimed, nlookup = %d/%d\n", 2714 1.85 manu perfuse_node_path(ps, opc), pnd->pnd_nodeid, 2715 1.85 manu nlookup, pnd->pnd_puffs_nlookup); 2716 1.85 manu #endif 2717 1.59 manu /* 2718 1.85 manu * The kernel tells us how many lookups it made, which allows 2719 1.85 manu * us to detect that we have an uncompleted lookup and that the 2720 1.91 andvar * node should not disappear. 2721 1.85 manu */ 2722 1.85 manu pnd->pnd_puffs_nlookup -= nlookup; 2723 1.85 manu if (pnd->pnd_puffs_nlookup > 0) 2724 1.59 manu return 0; 2725 1.59 manu 2726 1.59 manu node_ref(opc); 2727 1.2 manu pnd->pnd_flags |= PND_RECLAIMED; 2728 1.1 manu 2729 1.1 manu #ifdef PERFUSE_DEBUG 2730 1.1 manu if (perfuse_diagflags & PDF_RECLAIM) 2731 1.51 manu DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, nlookup = %d " 2732 1.59 manu "%s%s%s%s, pending ops:%s%s%s\n", 2733 1.59 manu perfuse_node_path(ps, opc), pnd->pnd_nodeid, 2734 1.2 manu pnd->pnd_flags & PND_RECLAIMED ? "" : "not ", 2735 1.59 manu pnd->pnd_puffs_nlookup, 2736 1.7 manu pnd->pnd_flags & PND_OPEN ? "open " : "not open", 2737 1.7 manu pnd->pnd_flags & PND_RFH ? "r" : "", 2738 1.7 manu pnd->pnd_flags & PND_WFH ? "w" : "", 2739 1.85 manu pnd->pnd_flags & PND_BUSY ? " busy" : "", 2740 1.7 manu pnd->pnd_flags & PND_INREADDIR ? " readdir" : "", 2741 1.17 manu pnd->pnd_flags & PND_INWRITE ? " write" : "", 2742 1.17 manu pnd->pnd_flags & PND_INOPEN ? " open" : ""); 2743 1.1 manu #endif 2744 1.59 manu /* 2745 1.59 manu * Make sure it is not looked up again 2746 1.59 manu */ 2747 1.59 manu if (!(pnd->pnd_flags & PND_REMOVED)) 2748 1.59 manu perfuse_cache_flush(opc); 2749 1.59 manu 2750 1.59 manu /* 2751 1.59 manu * Purge any activity on the node, while checking 2752 1.59 manu * that it remains eligible for a reclaim. 2753 1.59 manu */ 2754 1.59 manu while (pnd->pnd_ref > 1) 2755 1.59 manu requeue_request(pu, opc, PCQ_REF); 2756 1.59 manu 2757 1.17 manu #ifdef PERFUSE_DEBUG 2758 1.59 manu if ((pnd->pnd_flags & PND_OPEN) || 2759 1.59 manu !TAILQ_EMPTY(&pnd->pnd_pcq)) 2760 1.61 manu DERRX(EX_SOFTWARE, "%s: opc = %p \"%s\": still open", 2761 1.61 manu __func__, opc, pnd->pnd_name); 2762 1.2 manu 2763 1.59 manu if ((pnd->pnd_flags & PND_BUSY) || 2764 1.59 manu !TAILQ_EMPTY(&pnd->pnd_pcq)) 2765 1.59 manu DERRX(EX_SOFTWARE, "%s: opc = %p: queued operations", 2766 1.59 manu __func__, opc); 2767 1.1 manu 2768 1.59 manu if (pnd->pnd_inxchg != 0) 2769 1.59 manu DERRX(EX_SOFTWARE, "%s: opc = %p: ongoing operations", 2770 1.59 manu __func__, opc); 2771 1.59 manu #endif 2772 1.1 manu 2773 1.59 manu /* 2774 1.59 manu * Send the FORGET message 2775 1.59 manu * 2776 1.59 manu * ps_new_msg() is called with NULL creds, which will 2777 1.59 manu * be interpreted as FUSE superuser. This is obviously 2778 1.59 manu * fine since we operate with kernel creds here. 2779 1.59 manu */ 2780 1.59 manu pm = ps->ps_new_msg(pu, opc, FUSE_FORGET, 2781 1.59 manu sizeof(*ffi), NULL); 2782 1.59 manu ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in); 2783 1.59 manu ffi->nlookup = pnd->pnd_fuse_nlookup; 2784 1.1 manu 2785 1.59 manu /* 2786 1.59 manu * No reply is expected, pm is freed in xchg_msg 2787 1.59 manu */ 2788 1.59 manu (void)xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, no_reply); 2789 1.1 manu 2790 1.59 manu perfuse_destroy_pn(pu, opc); 2791 1.1 manu 2792 1.1 manu return 0; 2793 1.1 manu } 2794 1.1 manu 2795 1.85 manu int 2796 1.85 manu perfuse_node_reclaim(struct puffs_usermount *pu, puffs_cookie_t opc) 2797 1.85 manu { 2798 1.85 manu #ifdef PERFUSE_DEBUG 2799 1.85 manu if (perfuse_diagflags & PDF_RECLAIM) 2800 1.85 manu DPRINTF("perfuse_node_reclaim called\n"); 2801 1.85 manu #endif 2802 1.85 manu return perfuse_node_reclaim2(pu, opc, 1); 2803 1.85 manu } 2804 1.85 manu 2805 1.1 manu int 2806 1.52 matt perfuse_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) 2807 1.1 manu { 2808 1.17 manu struct perfuse_node_data *pnd; 2809 1.53 manu int error; 2810 1.17 manu 2811 1.54 manu if (opc == 0) 2812 1.54 manu return 0; 2813 1.54 manu 2814 1.17 manu pnd = PERFUSE_NODE_DATA(opc); 2815 1.80 manu if (!(pnd->pnd_flags & (PND_OPEN|PND_REMOVED))) 2816 1.80 manu return 0; 2817 1.17 manu 2818 1.80 manu node_ref(opc); 2819 1.17 manu 2820 1.17 manu /* 2821 1.17 manu * Make sure all operation are finished 2822 1.17 manu * There can be an ongoing write. Other 2823 1.18 manu * operation wait for all data before 2824 1.17 manu * the close/inactive. 2825 1.17 manu */ 2826 1.17 manu while (pnd->pnd_flags & PND_INWRITE) 2827 1.17 manu requeue_request(pu, opc, PCQ_AFTERWRITE); 2828 1.17 manu 2829 1.17 manu /* 2830 1.53 manu * The inactive operation may be cancelled, 2831 1.17 manu * If no open is in progress, set PND_INOPEN 2832 1.17 manu * so that a new open will be queued. 2833 1.17 manu */ 2834 1.53 manu if (pnd->pnd_flags & PND_INOPEN) 2835 1.59 manu goto out; 2836 1.17 manu 2837 1.17 manu pnd->pnd_flags |= PND_INOPEN; 2838 1.17 manu 2839 1.17 manu /* 2840 1.17 manu * Sync data 2841 1.17 manu */ 2842 1.53 manu if (pnd->pnd_flags & PND_DIRTY) { 2843 1.53 manu if ((error = perfuse_node_fsync(pu, opc, NULL, 0, 0, 0)) != 0) 2844 1.53 manu DWARN("%s: perfuse_node_fsync failed error = %d", 2845 1.53 manu __func__, error); 2846 1.53 manu } 2847 1.53 manu 2848 1.17 manu 2849 1.17 manu /* 2850 1.17 manu * Close handles 2851 1.17 manu */ 2852 1.53 manu if (pnd->pnd_flags & PND_WFH) { 2853 1.53 manu if ((error = perfuse_node_close_common(pu, opc, FWRITE)) != 0) 2854 1.53 manu DWARN("%s: close write FH failed error = %d", 2855 1.53 manu __func__, error); 2856 1.53 manu } 2857 1.17 manu 2858 1.53 manu if (pnd->pnd_flags & PND_RFH) { 2859 1.53 manu if ((error = perfuse_node_close_common(pu, opc, FREAD)) != 0) 2860 1.53 manu DWARN("%s: close read FH failed error = %d", 2861 1.53 manu __func__, error); 2862 1.53 manu } 2863 1.17 manu 2864 1.19 manu /* 2865 1.19 manu * This will cause a reclaim to be sent 2866 1.19 manu */ 2867 1.18 manu if (pnd->pnd_flags & PND_REMOVED) 2868 1.18 manu puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); 2869 1.18 manu 2870 1.19 manu /* 2871 1.19 manu * Schedule awaiting operations 2872 1.19 manu */ 2873 1.19 manu pnd->pnd_flags &= ~PND_INOPEN; 2874 1.59 manu (void)dequeue_requests(opc, PCQ_OPEN, DEQUEUE_ALL); 2875 1.19 manu 2876 1.59 manu /* 2877 1.59 manu * errors are ignored, since the kernel ignores the return code. 2878 1.59 manu */ 2879 1.59 manu out: 2880 1.59 manu node_rele(opc); 2881 1.1 manu return 0; 2882 1.1 manu } 2883 1.1 manu 2884 1.1 manu 2885 1.1 manu /* ARGSUSED0 */ 2886 1.1 manu int 2887 1.52 matt perfuse_node_print(struct puffs_usermount *pu, puffs_cookie_t opc) 2888 1.1 manu { 2889 1.1 manu DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__); 2890 1.1 manu return 0; 2891 1.1 manu } 2892 1.1 manu 2893 1.1 manu int 2894 1.52 matt perfuse_node_pathconf(struct puffs_usermount *pu, puffs_cookie_t opc, 2895 1.72 enami int name, register_t *retval) 2896 1.1 manu { 2897 1.71 manu perfuse_msg_t *pm; 2898 1.71 manu struct perfuse_state *ps; 2899 1.71 manu struct fuse_statfs_out *fso; 2900 1.71 manu int error = 0; 2901 1.71 manu 2902 1.71 manu /* 2903 1.71 manu * Static values copied from UFS 2904 1.71 manu * in src/sys/ufs/ufs/ufs_vnops.c 2905 1.71 manu */ 2906 1.71 manu switch (name) { 2907 1.71 manu case _PC_LINK_MAX: 2908 1.71 manu *retval = LINK_MAX; 2909 1.71 manu break; 2910 1.71 manu case _PC_PATH_MAX: 2911 1.71 manu *retval = PATH_MAX; 2912 1.71 manu break; 2913 1.71 manu case _PC_PIPE_BUF: 2914 1.71 manu *retval = PIPE_BUF; 2915 1.71 manu break; 2916 1.71 manu case _PC_CHOWN_RESTRICTED: 2917 1.71 manu *retval = 1; 2918 1.71 manu break; 2919 1.71 manu case _PC_NO_TRUNC: 2920 1.71 manu *retval = 1; 2921 1.71 manu break; 2922 1.71 manu case _PC_SYNC_IO: 2923 1.71 manu *retval = 1; 2924 1.71 manu break; 2925 1.71 manu case _PC_FILESIZEBITS: 2926 1.71 manu *retval = 42; 2927 1.71 manu break; 2928 1.71 manu case _PC_SYMLINK_MAX: 2929 1.71 manu *retval = MAXPATHLEN; 2930 1.71 manu break; 2931 1.71 manu case _PC_2_SYMLINKS: 2932 1.71 manu *retval = 1; 2933 1.71 manu break; 2934 1.71 manu case _PC_NAME_MAX: 2935 1.71 manu ps = puffs_getspecific(pu); 2936 1.71 manu pm = ps->ps_new_msg(pu, opc, FUSE_STATFS, 0, NULL); 2937 1.71 manu 2938 1.71 manu error = xchg_msg(pu, opc, pm, sizeof(*fso), wait_reply); 2939 1.71 manu if (error != 0) 2940 1.71 manu return error; 2941 1.71 manu 2942 1.71 manu fso = GET_OUTPAYLOAD(ps, pm, fuse_statfs_out); 2943 1.71 manu *retval = fso->st.namelen; 2944 1.71 manu 2945 1.71 manu ps->ps_destroy_msg(pm); 2946 1.71 manu 2947 1.71 manu break; 2948 1.71 manu default: 2949 1.71 manu DWARN("Unimplemented pathconf for name = %d", name); 2950 1.71 manu error = ENOSYS; 2951 1.71 manu break; 2952 1.71 manu } 2953 1.71 manu 2954 1.71 manu return error; 2955 1.1 manu } 2956 1.1 manu 2957 1.1 manu int 2958 1.52 matt perfuse_node_advlock(struct puffs_usermount *pu, puffs_cookie_t opc, 2959 1.52 matt void *id, int op, struct flock *fl, int flags) 2960 1.1 manu { 2961 1.1 manu struct perfuse_state *ps; 2962 1.1 manu int fop; 2963 1.1 manu perfuse_msg_t *pm; 2964 1.45 manu uint64_t fh; 2965 1.1 manu struct fuse_lk_in *fli; 2966 1.25 manu struct fuse_out_header *foh; 2967 1.1 manu struct fuse_lk_out *flo; 2968 1.25 manu uint32_t owner; 2969 1.25 manu size_t len; 2970 1.1 manu int error; 2971 1.1 manu 2972 1.59 manu node_ref(opc); 2973 1.59 manu 2974 1.45 manu /* 2975 1.45 manu * Make sure we do have a filehandle, as the FUSE filesystem 2976 1.45 manu * expect one. E.g.: if we provide none, GlusterFS logs an error 2977 1.45 manu * "0-glusterfs-fuse: xl is NULL" 2978 1.45 manu * 2979 1.45 manu * We need the read file handle if the file is open read only, 2980 1.45 manu * in order to support shared locks on read-only files. 2981 1.45 manu * NB: The kernel always sends advlock for read-only 2982 1.45 manu * files at exit time when the process used lock, see 2983 1.45 manu * sys_exit -> exit1 -> fd_free -> fd_close -> VOP_ADVLOCK 2984 1.45 manu */ 2985 1.87 manu if ((fh = perfuse_get_fh(opc, FREAD)) == FUSE_UNKNOWN_FH) { 2986 1.87 manu error = EBADF; 2987 1.87 manu goto out; 2988 1.59 manu } 2989 1.45 manu 2990 1.1 manu ps = puffs_getspecific(pu); 2991 1.1 manu 2992 1.1 manu if (op == F_GETLK) 2993 1.1 manu fop = FUSE_GETLK; 2994 1.1 manu else 2995 1.1 manu fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK; 2996 1.1 manu 2997 1.36 manu /* 2998 1.36 manu * XXX ps_new_msg() is called with NULL creds, which will 2999 1.36 manu * be interpreted as FUSE superuser. We have no way to 3000 1.36 manu * know the requesting process' credential, but since advlock() 3001 1.36 manu * is supposed to operate on a file that has been open(), 3002 1.36 manu * permission should have already been checked at open() time. 3003 1.36 manu */ 3004 1.1 manu pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL); 3005 1.1 manu fli = GET_INPAYLOAD(ps, pm, fuse_lk_in); 3006 1.45 manu fli->fh = fh; 3007 1.45 manu fli->owner = (uint64_t)(vaddr_t)id; 3008 1.1 manu fli->lk.start = fl->l_start; 3009 1.1 manu fli->lk.end = fl->l_start + fl->l_len; 3010 1.1 manu fli->lk.type = fl->l_type; 3011 1.1 manu fli->lk.pid = fl->l_pid; 3012 1.1 manu fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0; 3013 1.1 manu 3014 1.47 manu owner = (uint32_t)(vaddr_t)id; 3015 1.25 manu 3016 1.2 manu #ifdef PERFUSE_DEBUG 3017 1.2 manu if (perfuse_diagflags & PDF_FH) 3018 1.43 manu DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 3019 1.2 manu __func__, (void *)opc, 3020 1.43 manu PERFUSE_NODE_DATA(opc)->pnd_nodeid, fli->fh); 3021 1.2 manu #endif 3022 1.2 manu 3023 1.25 manu if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 3024 1.59 manu goto out; 3025 1.1 manu 3026 1.25 manu foh = GET_OUTHDR(ps, pm); 3027 1.25 manu len = foh->len - sizeof(*foh); 3028 1.1 manu 3029 1.1 manu /* 3030 1.1 manu * Save or clear the lock 3031 1.1 manu */ 3032 1.1 manu switch (op) { 3033 1.25 manu case F_GETLK: 3034 1.25 manu if (len != sizeof(*flo)) 3035 1.25 manu DERRX(EX_SOFTWARE, 3036 1.25 manu "%s: Unexpected lock reply len %zd", 3037 1.25 manu __func__, len); 3038 1.25 manu 3039 1.25 manu flo = GET_OUTPAYLOAD(ps, pm, fuse_lk_out); 3040 1.25 manu fl->l_start = flo->lk.start; 3041 1.25 manu fl->l_len = flo->lk.end - flo->lk.start; 3042 1.25 manu fl->l_pid = flo->lk.pid; 3043 1.25 manu fl->l_type = flo->lk.type; 3044 1.25 manu fl->l_whence = SEEK_SET; /* libfuse hardcodes it */ 3045 1.25 manu 3046 1.1 manu PERFUSE_NODE_DATA(opc)->pnd_lock_owner = flo->lk.pid; 3047 1.1 manu break; 3048 1.1 manu case F_UNLCK: 3049 1.25 manu owner = 0; 3050 1.25 manu /* FALLTHROUGH */ 3051 1.25 manu case F_SETLK: 3052 1.25 manu /* FALLTHROUGH */ 3053 1.25 manu case F_SETLKW: 3054 1.25 manu if (error != 0) 3055 1.25 manu PERFUSE_NODE_DATA(opc)->pnd_lock_owner = owner; 3056 1.25 manu 3057 1.25 manu if (len != 0) 3058 1.25 manu DERRX(EX_SOFTWARE, 3059 1.25 manu "%s: Unexpected unlock reply len %zd", 3060 1.25 manu __func__, len); 3061 1.25 manu 3062 1.1 manu break; 3063 1.1 manu default: 3064 1.25 manu DERRX(EX_SOFTWARE, "%s: Unexpected op %d", __func__, op); 3065 1.1 manu break; 3066 1.1 manu } 3067 1.48 manu 3068 1.1 manu ps->ps_destroy_msg(pm); 3069 1.59 manu error = 0; 3070 1.1 manu 3071 1.59 manu out: 3072 1.59 manu node_rele(opc); 3073 1.59 manu return error; 3074 1.1 manu } 3075 1.1 manu 3076 1.1 manu int 3077 1.52 matt perfuse_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, uint8_t *buf, 3078 1.52 matt off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag) 3079 1.1 manu { 3080 1.1 manu struct perfuse_state *ps; 3081 1.7 manu struct perfuse_node_data *pnd; 3082 1.40 manu const struct vattr *vap; 3083 1.1 manu perfuse_msg_t *pm; 3084 1.86 manu uint64_t fh; 3085 1.1 manu struct fuse_read_in *fri; 3086 1.1 manu struct fuse_out_header *foh; 3087 1.1 manu size_t readen; 3088 1.1 manu int error; 3089 1.1 manu 3090 1.1 manu ps = puffs_getspecific(pu); 3091 1.7 manu pnd = PERFUSE_NODE_DATA(opc); 3092 1.40 manu vap = puffs_pn_getvap((struct puffs_node *)opc); 3093 1.1 manu 3094 1.44 manu /* 3095 1.44 manu * NetBSD turns that into a getdents(2) output 3096 1.44 manu * We just do a EISDIR as this feature is of little use. 3097 1.44 manu */ 3098 1.44 manu if (vap->va_type == VDIR) 3099 1.44 manu return EISDIR; 3100 1.44 manu 3101 1.86 manu fh = perfuse_get_fh(opc, FREAD); /* Cannot be VDIR */ 3102 1.86 manu 3103 1.1 manu do { 3104 1.16 manu size_t max_read; 3105 1.16 manu 3106 1.16 manu max_read = ps->ps_max_readahead - sizeof(*foh); 3107 1.1 manu /* 3108 1.1 manu * flags may be set to FUSE_READ_LOCKOWNER 3109 1.1 manu * if lock_owner is provided. 3110 1.1 manu */ 3111 1.1 manu pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr); 3112 1.1 manu fri = GET_INPAYLOAD(ps, pm, fuse_read_in); 3113 1.86 manu fri->fh = fh; 3114 1.1 manu fri->offset = offset; 3115 1.16 manu fri->size = (uint32_t)MIN(*resid, max_read); 3116 1.1 manu fri->read_flags = 0; /* XXX Unused by libfuse? */ 3117 1.7 manu fri->lock_owner = pnd->pnd_lock_owner; 3118 1.1 manu fri->flags = 0; 3119 1.1 manu fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0; 3120 1.1 manu 3121 1.2 manu #ifdef PERFUSE_DEBUG 3122 1.2 manu if (perfuse_diagflags & PDF_FH) 3123 1.43 manu DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n", 3124 1.43 manu __func__, (void *)opc, pnd->pnd_nodeid, fri->fh); 3125 1.2 manu #endif 3126 1.16 manu error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply); 3127 1.1 manu if (error != 0) 3128 1.48 manu return error; 3129 1.1 manu 3130 1.1 manu foh = GET_OUTHDR(ps, pm); 3131 1.1 manu readen = foh->len - sizeof(*foh); 3132 1.1 manu 3133 1.16 manu #ifdef PERFUSE_DEBUG 3134 1.16 manu if (readen > *resid) 3135 1.16 manu DERRX(EX_SOFTWARE, "%s: Unexpected big read %zd", 3136 1.16 manu __func__, readen); 3137 1.16 manu #endif 3138 1.16 manu 3139 1.1 manu (void)memcpy(buf, _GET_OUTPAYLOAD(ps, pm, char *), readen); 3140 1.1 manu 3141 1.1 manu buf += readen; 3142 1.1 manu offset += readen; 3143 1.1 manu *resid -= readen; 3144 1.1 manu 3145 1.1 manu ps->ps_destroy_msg(pm); 3146 1.1 manu } while ((*resid != 0) && (readen != 0)); 3147 1.1 manu 3148 1.1 manu if (ioflag & (IO_SYNC|IO_DSYNC)) 3149 1.1 manu ps->ps_syncreads++; 3150 1.1 manu else 3151 1.1 manu ps->ps_asyncreads++; 3152 1.1 manu 3153 1.48 manu return 0; 3154 1.1 manu } 3155 1.1 manu 3156 1.1 manu int 3157 1.59 manu perfuse_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, 3158 1.59 manu uint8_t *buf, off_t offset, size_t *resid, 3159 1.59 manu const struct puffs_cred *pcr, int ioflag) 3160 1.59 manu { 3161 1.59 manu return perfuse_node_write2(pu, opc, buf, offset, resid, pcr, ioflag, 0); 3162 1.59 manu } 3163 1.59 manu 3164 1.59 manu /* ARGSUSED7 */ 3165 1.59 manu int 3166 1.59 manu perfuse_node_write2(struct puffs_usermount *pu, puffs_cookie_t opc, 3167 1.59 manu uint8_t *buf, off_t offset, size_t *resid, 3168 1.59 manu const struct puffs_cred *pcr, int ioflag, int xflag) 3169 1.1 manu { 3170 1.1 manu struct perfuse_state *ps; 3171 1.7 manu struct perfuse_node_data *pnd; 3172 1.24 manu struct vattr *vap; 3173 1.1 manu perfuse_msg_t *pm; 3174 1.86 manu uint64_t fh; 3175 1.1 manu struct fuse_write_in *fwi; 3176 1.1 manu struct fuse_write_out *fwo; 3177 1.1 manu size_t data_len; 3178 1.1 manu size_t payload_len; 3179 1.1 manu size_t written; 3180 1.40 manu int inresize; 3181 1.1 manu int error; 3182 1.1 manu 3183 1.1 manu ps = puffs_getspecific(pu); 3184 1.7 manu pnd = PERFUSE_NODE_DATA(opc); 3185 1.24 manu vap = puffs_pn_getvap((struct puffs_node *)opc); 3186 1.1 manu written = 0; 3187 1.40 manu inresize = 0; 3188 1.48 manu error = 0; 3189 1.1 manu 3190 1.24 manu if (vap->va_type == VDIR) 3191 1.44 manu return EISDIR; 3192 1.7 manu 3193 1.59 manu node_ref(opc); 3194 1.59 manu 3195 1.16 manu /* 3196 1.16 manu * We need to queue write requests in order to avoid 3197 1.16 manu * dequeueing PCQ_AFTERWRITE when there are pending writes. 3198 1.16 manu */ 3199 1.9 manu while (pnd->pnd_flags & PND_INWRITE) 3200 1.9 manu requeue_request(pu, opc, PCQ_WRITE); 3201 1.7 manu pnd->pnd_flags |= PND_INWRITE; 3202 1.7 manu 3203 1.18 manu /* 3204 1.24 manu * append flag: re-read the file size so that 3205 1.24 manu * we get the latest value. 3206 1.18 manu */ 3207 1.24 manu if (ioflag & PUFFS_IO_APPEND) { 3208 1.24 manu if ((error = perfuse_node_getattr(pu, opc, vap, pcr)) != 0) 3209 1.24 manu goto out; 3210 1.24 manu 3211 1.24 manu offset = vap->va_size; 3212 1.24 manu } 3213 1.18 manu 3214 1.74 manu /* 3215 1.74 manu * Serialize size access, see comment in perfuse_node_setattr(). 3216 1.74 manu */ 3217 1.74 manu if ((u_quad_t)offset + *resid > vap->va_size) { 3218 1.74 manu while (pnd->pnd_flags & PND_INRESIZE) 3219 1.74 manu requeue_request(pu, opc, PCQ_RESIZE); 3220 1.74 manu pnd->pnd_flags |= PND_INRESIZE; 3221 1.74 manu inresize = 1; 3222 1.74 manu } 3223 1.74 manu 3224 1.40 manu #ifdef PERFUSE_DEBUG 3225 1.40 manu if (perfuse_diagflags & PDF_RESIZE) 3226 1.41 christos DPRINTF(">> %s %p %" PRIu64 "\n", __func__, 3227 1.40 manu (void *)opc, vap->va_size); 3228 1.40 manu #endif 3229 1.40 manu 3230 1.86 manu fh = perfuse_get_fh(opc, FWRITE); /* Cannot be VDIR */ 3231 1.86 manu 3232 1.1 manu do { 3233 1.16 manu size_t max_write; 3234 1.1 manu /* 3235 1.16 manu * There is a writepage flag when data 3236 1.26 jakllsch * is aligned to page size. Use it for 3237 1.16 manu * everything but the data after the last 3238 1.16 manu * page boundary. 3239 1.1 manu */ 3240 1.16 manu max_write = ps->ps_max_write - sizeof(*fwi); 3241 1.16 manu 3242 1.16 manu data_len = MIN(*resid, max_write); 3243 1.26 jakllsch if (data_len > (size_t)sysconf(_SC_PAGESIZE)) 3244 1.26 jakllsch data_len = data_len & ~(sysconf(_SC_PAGESIZE) - 1); 3245 1.16 manu 3246 1.1 manu payload_len = data_len + sizeof(*fwi); 3247 1.1 manu 3248 1.1 manu /* 3249 1.1 manu * flags may be set to FUSE_WRITE_CACHE (XXX usage?) 3250 1.1 manu * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided. 3251 1.1 manu * write_flags is set to 1 for writepage. 3252 1.1 manu */ 3253 1.1 manu pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr); 3254 1.1 manu fwi = GET_INPAYLOAD(ps, pm, fuse_write_in); 3255 1.86 manu fwi->fh = fh; 3256 1.1 manu fwi->offset = offset; 3257 1.5 manu fwi->size = (uint32_t)data_len; 3258 1.26 jakllsch fwi->write_flags = (fwi->size % sysconf(_SC_PAGESIZE)) ? 0 : 1; 3259 1.7 manu fwi->lock_owner = pnd->pnd_lock_owner; 3260 1.1 manu fwi->flags = 0; 3261 1.1 manu fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0; 3262 1.1 manu fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE; 3263 1.18 manu (void)memcpy((fwi + 1), buf, data_len); 3264 1.18 manu 3265 1.1 manu 3266 1.2 manu #ifdef PERFUSE_DEBUG 3267 1.24 manu if (perfuse_diagflags & PDF_FH) 3268 1.43 manu DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", " 3269 1.86 manu "fh = 0x%"PRIx64"\n", __func__, 3270 1.43 manu (void *)opc, pnd->pnd_nodeid, fwi->fh); 3271 1.2 manu #endif 3272 1.16 manu if ((error = xchg_msg(pu, opc, pm, 3273 1.16 manu sizeof(*fwo), wait_reply)) != 0) 3274 1.1 manu goto out; 3275 1.1 manu 3276 1.1 manu fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out); 3277 1.1 manu written = fwo->size; 3278 1.59 manu ps->ps_destroy_msg(pm); 3279 1.59 manu 3280 1.16 manu #ifdef PERFUSE_DEBUG 3281 1.16 manu if (written > *resid) 3282 1.16 manu DERRX(EX_SOFTWARE, "%s: Unexpected big write %zd", 3283 1.16 manu __func__, written); 3284 1.16 manu #endif 3285 1.1 manu *resid -= written; 3286 1.1 manu offset += written; 3287 1.1 manu buf += written; 3288 1.1 manu 3289 1.1 manu } while (*resid != 0); 3290 1.1 manu 3291 1.1 manu /* 3292 1.1 manu * puffs_ops(3) says 3293 1.1 manu * "everything must be written or an error will be generated" 3294 1.1 manu */ 3295 1.1 manu if (*resid != 0) 3296 1.1 manu error = EFBIG; 3297 1.1 manu 3298 1.79 manu out: 3299 1.40 manu #ifdef PERFUSE_DEBUG 3300 1.40 manu if (perfuse_diagflags & PDF_RESIZE) { 3301 1.40 manu if (offset > (off_t)vap->va_size) 3302 1.86 manu DPRINTF("<< %s %p %" PRIu64 " -> %lld\n", __func__, 3303 1.41 christos (void *)opc, vap->va_size, (long long)offset); 3304 1.40 manu else 3305 1.40 manu DPRINTF("<< %s %p \n", __func__, (void *)opc); 3306 1.40 manu } 3307 1.40 manu #endif 3308 1.40 manu 3309 1.24 manu /* 3310 1.24 manu * Update file size if we wrote beyond the end 3311 1.24 manu */ 3312 1.24 manu if (offset > (off_t)vap->va_size) 3313 1.24 manu vap->va_size = offset; 3314 1.24 manu 3315 1.24 manu /* 3316 1.24 manu * Statistics 3317 1.24 manu */ 3318 1.1 manu if (ioflag & (IO_SYNC|IO_DSYNC)) 3319 1.1 manu ps->ps_syncwrites++; 3320 1.1 manu else 3321 1.1 manu ps->ps_asyncwrites++; 3322 1.1 manu 3323 1.2 manu /* 3324 1.2 manu * Remember to sync the file 3325 1.2 manu */ 3326 1.7 manu pnd->pnd_flags |= PND_DIRTY; 3327 1.2 manu 3328 1.2 manu #ifdef PERFUSE_DEBUG 3329 1.2 manu if (perfuse_diagflags & PDF_SYNC) 3330 1.2 manu DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n", 3331 1.59 manu __func__, (void*)opc, perfuse_node_path(ps, opc)); 3332 1.2 manu #endif 3333 1.48 manu 3334 1.79 manu if (inresize) { 3335 1.79 manu #ifdef PERFUSE_DEBUG 3336 1.79 manu if (!(pnd->pnd_flags & PND_INRESIZE)) 3337 1.79 manu DERRX(EX_SOFTWARE, "file write grow without resize"); 3338 1.79 manu #endif 3339 1.79 manu pnd->pnd_flags &= ~PND_INRESIZE; 3340 1.79 manu (void)dequeue_requests(opc, PCQ_RESIZE, DEQUEUE_ALL); 3341 1.79 manu } 3342 1.79 manu 3343 1.7 manu /* 3344 1.59 manu * VOP_PUTPAGE causes FAF write where kernel does not 3345 1.59 manu * check operation result. At least warn if it failed. 3346 1.59 manu */ 3347 1.59 manu #ifdef PUFFS_WRITE_FAF 3348 1.59 manu if (error && (xflag & PUFFS_WRITE_FAF)) 3349 1.59 manu DWARN("Data loss caused by FAF write failed on \"%s\"", 3350 1.59 manu pnd->pnd_name); 3351 1.59 manu #endif /* PUFFS_WRITE_FAF */ 3352 1.59 manu 3353 1.59 manu /* 3354 1.9 manu * If there are no more queued write, we can resume 3355 1.9 manu * an operation awaiting write completion. 3356 1.7 manu */ 3357 1.9 manu pnd->pnd_flags &= ~PND_INWRITE; 3358 1.59 manu if (dequeue_requests(opc, PCQ_WRITE, 1) == 0) 3359 1.59 manu (void)dequeue_requests(opc, PCQ_AFTERWRITE, DEQUEUE_ALL); 3360 1.7 manu 3361 1.59 manu node_rele(opc); 3362 1.1 manu return error; 3363 1.1 manu } 3364 1.1 manu 3365 1.1 manu /* ARGSUSED0 */ 3366 1.1 manu void 3367 1.52 matt perfuse_cache_write(struct puffs_usermount *pu, puffs_cookie_t opc, size_t size, 3368 1.52 matt struct puffs_cacherun *runs) 3369 1.1 manu { 3370 1.1 manu return; 3371 1.1 manu } 3372 1.1 manu 3373 1.31 manu /* ARGSUSED4 */ 3374 1.31 manu int 3375 1.52 matt perfuse_node_getextattr(struct puffs_usermount *pu, puffs_cookie_t opc, 3376 1.52 matt int attrns, const char *attrname, size_t *attrsize, uint8_t *attr, 3377 1.52 matt size_t *resid, const struct puffs_cred *pcr) 3378 1.31 manu { 3379 1.31 manu struct perfuse_state *ps; 3380 1.31 manu char fuse_attrname[LINUX_XATTR_NAME_MAX + 1]; 3381 1.31 manu perfuse_msg_t *pm; 3382 1.31 manu struct fuse_getxattr_in *fgi; 3383 1.31 manu struct fuse_getxattr_out *fgo; 3384 1.31 manu struct fuse_out_header *foh; 3385 1.31 manu size_t attrnamelen; 3386 1.31 manu size_t len; 3387 1.31 manu char *np; 3388 1.31 manu int error; 3389 1.31 manu 3390 1.66 manu /* system namespace attrs are not accessible to non root users */ 3391 1.66 manu if (attrns == EXTATTR_NAMESPACE_SYSTEM && !puffs_cred_isjuggernaut(pcr)) 3392 1.66 manu return EPERM; 3393 1.66 manu 3394 1.59 manu node_ref(opc); 3395 1.31 manu ps = puffs_getspecific(pu); 3396 1.31 manu attrname = perfuse_native_ns(attrns, attrname, fuse_attrname); 3397 1.31 manu attrnamelen = strlen(attrname) + 1; 3398 1.31 manu len = sizeof(*fgi) + attrnamelen; 3399 1.31 manu 3400 1.31 manu pm = ps->ps_new_msg(pu, opc, FUSE_GETXATTR, len, pcr); 3401 1.31 manu fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in); 3402 1.41 christos fgi->size = (unsigned int)((resid != NULL) ? *resid : 0); 3403 1.31 manu np = (char *)(void *)(fgi + 1); 3404 1.31 manu (void)strlcpy(np, attrname, attrnamelen); 3405 1.31 manu 3406 1.31 manu if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 3407 1.59 manu goto out; 3408 1.31 manu 3409 1.31 manu /* 3410 1.31 manu * We just get fuse_getattr_out with list size if we requested 3411 1.31 manu * a null size. 3412 1.31 manu */ 3413 1.31 manu if (resid == NULL) { 3414 1.31 manu fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out); 3415 1.31 manu 3416 1.31 manu if (attrsize != NULL) 3417 1.31 manu *attrsize = fgo->size; 3418 1.31 manu 3419 1.48 manu ps->ps_destroy_msg(pm); 3420 1.59 manu error = 0; 3421 1.59 manu goto out; 3422 1.31 manu } 3423 1.31 manu 3424 1.31 manu /* 3425 1.31 manu * And with a non null requested size, we get the list just 3426 1.31 manu * after the header 3427 1.31 manu */ 3428 1.31 manu foh = GET_OUTHDR(ps, pm); 3429 1.31 manu np = (char *)(void *)(foh + 1); 3430 1.65 manu len = foh->len - sizeof(*foh); 3431 1.65 manu 3432 1.65 manu if (attrsize != NULL) 3433 1.65 manu *attrsize = len; 3434 1.31 manu 3435 1.31 manu if (resid != NULL) { 3436 1.65 manu if (*resid < len) { 3437 1.65 manu error = ERANGE; 3438 1.66 manu ps->ps_destroy_msg(pm); 3439 1.65 manu goto out; 3440 1.65 manu } 3441 1.65 manu 3442 1.31 manu (void)memcpy(attr, np, len); 3443 1.31 manu *resid -= len; 3444 1.31 manu } 3445 1.31 manu 3446 1.31 manu ps->ps_destroy_msg(pm); 3447 1.59 manu error = 0; 3448 1.31 manu 3449 1.59 manu out: 3450 1.59 manu node_rele(opc); 3451 1.59 manu return error; 3452 1.31 manu } 3453 1.31 manu 3454 1.31 manu int 3455 1.52 matt perfuse_node_setextattr(struct puffs_usermount *pu, puffs_cookie_t opc, 3456 1.52 matt int attrns, const char *attrname, uint8_t *attr, size_t *resid, 3457 1.52 matt const struct puffs_cred *pcr) 3458 1.31 manu { 3459 1.31 manu struct perfuse_state *ps; 3460 1.31 manu char fuse_attrname[LINUX_XATTR_NAME_MAX + 1]; 3461 1.31 manu perfuse_msg_t *pm; 3462 1.31 manu struct fuse_setxattr_in *fsi; 3463 1.31 manu size_t attrnamelen; 3464 1.81 manu size_t datalen; 3465 1.31 manu size_t len; 3466 1.31 manu char *np; 3467 1.31 manu int error; 3468 1.31 manu 3469 1.66 manu /* system namespace attrs are not accessible to non root users */ 3470 1.66 manu if (attrns == EXTATTR_NAMESPACE_SYSTEM && !puffs_cred_isjuggernaut(pcr)) 3471 1.66 manu return EPERM; 3472 1.66 manu 3473 1.59 manu node_ref(opc); 3474 1.31 manu ps = puffs_getspecific(pu); 3475 1.31 manu attrname = perfuse_native_ns(attrns, attrname, fuse_attrname); 3476 1.31 manu attrnamelen = strlen(attrname) + 1; 3477 1.81 manu 3478 1.81 manu datalen = (resid != NULL) ? *resid : 0; 3479 1.81 manu len = sizeof(*fsi) + attrnamelen + datalen; 3480 1.31 manu 3481 1.31 manu pm = ps->ps_new_msg(pu, opc, FUSE_SETXATTR, len, pcr); 3482 1.31 manu fsi = GET_INPAYLOAD(ps, pm, fuse_setxattr_in); 3483 1.81 manu fsi->size = (unsigned int)datalen; 3484 1.31 manu fsi->flags = 0; 3485 1.31 manu np = (char *)(void *)(fsi + 1); 3486 1.31 manu (void)strlcpy(np, attrname, attrnamelen); 3487 1.31 manu np += attrnamelen; 3488 1.81 manu if (datalen) 3489 1.81 manu (void)memcpy(np, (char *)attr, datalen); 3490 1.31 manu 3491 1.31 manu if ((error = xchg_msg(pu, opc, pm, 3492 1.31 manu NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0) 3493 1.59 manu goto out; 3494 1.31 manu 3495 1.59 manu ps->ps_destroy_msg(pm); 3496 1.81 manu if (resid) 3497 1.81 manu *resid = 0; 3498 1.59 manu error = 0; 3499 1.31 manu 3500 1.59 manu out: 3501 1.59 manu node_rele(opc); 3502 1.59 manu return error; 3503 1.31 manu } 3504 1.31 manu 3505 1.31 manu /* ARGSUSED2 */ 3506 1.31 manu int 3507 1.52 matt perfuse_node_listextattr(struct puffs_usermount *pu, puffs_cookie_t opc, 3508 1.52 matt int attrns, size_t *attrsize, uint8_t *attrs, size_t *resid, int flag, 3509 1.52 matt const struct puffs_cred *pcr) 3510 1.31 manu { 3511 1.31 manu struct perfuse_state *ps; 3512 1.31 manu perfuse_msg_t *pm; 3513 1.31 manu struct fuse_getxattr_in *fgi; 3514 1.31 manu struct fuse_getxattr_out *fgo; 3515 1.31 manu struct fuse_out_header *foh; 3516 1.31 manu char *np; 3517 1.66 manu size_t len, puffs_len, i, attrlen, outlen; 3518 1.31 manu int error; 3519 1.31 manu 3520 1.66 manu /* system namespace attrs are not accessible to non root users */ 3521 1.66 manu if (attrns == EXTATTR_NAMESPACE_SYSTEM && !puffs_cred_isjuggernaut(pcr)) 3522 1.66 manu return EPERM; 3523 1.66 manu 3524 1.59 manu node_ref(opc); 3525 1.59 manu 3526 1.31 manu ps = puffs_getspecific(pu); 3527 1.31 manu len = sizeof(*fgi); 3528 1.31 manu 3529 1.31 manu pm = ps->ps_new_msg(pu, opc, FUSE_LISTXATTR, len, pcr); 3530 1.31 manu fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in); 3531 1.31 manu if (resid != NULL) 3532 1.41 christos fgi->size = (unsigned int)*resid; 3533 1.31 manu else 3534 1.31 manu fgi->size = 0; 3535 1.31 manu 3536 1.31 manu if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0) 3537 1.59 manu goto out; 3538 1.31 manu 3539 1.31 manu /* 3540 1.31 manu * We just get fuse_getattr_out with list size if we requested 3541 1.31 manu * a null size. 3542 1.31 manu */ 3543 1.31 manu if (resid == NULL) { 3544 1.31 manu fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out); 3545 1.31 manu 3546 1.31 manu if (attrsize != NULL) 3547 1.31 manu *attrsize = fgo->size; 3548 1.31 manu 3549 1.48 manu ps->ps_destroy_msg(pm); 3550 1.48 manu 3551 1.59 manu error = 0; 3552 1.59 manu goto out; 3553 1.31 manu } 3554 1.31 manu 3555 1.31 manu /* 3556 1.31 manu * And with a non null requested size, we get the list just 3557 1.31 manu * after the header 3558 1.31 manu */ 3559 1.31 manu foh = GET_OUTHDR(ps, pm); 3560 1.31 manu np = (char *)(void *)(foh + 1); 3561 1.31 manu puffs_len = foh->len - sizeof(*foh); 3562 1.31 manu 3563 1.66 manu if (attrsize != NULL) 3564 1.66 manu *attrsize = puffs_len; 3565 1.66 manu 3566 1.31 manu if (attrs != NULL) { 3567 1.66 manu if (*resid < puffs_len) { 3568 1.66 manu error = ERANGE; 3569 1.66 manu ps->ps_destroy_msg(pm); 3570 1.66 manu goto out; 3571 1.66 manu } 3572 1.66 manu 3573 1.66 manu outlen = 0; 3574 1.66 manu 3575 1.66 manu for (i = 0; i < puffs_len; i += attrlen + 1) { 3576 1.66 manu attrlen = strlen(np + i); 3577 1.66 manu 3578 1.66 manu /* 3579 1.66 manu * Filter attributes per namespace 3580 1.66 manu */ 3581 1.66 manu if (!perfuse_ns_match(attrns, np + i)) 3582 1.66 manu continue; 3583 1.66 manu 3584 1.35 manu #ifdef PUFFS_EXTATTR_LIST_LENPREFIX 3585 1.66 manu /* 3586 1.66 manu * Convert the FUSE reply to length prefixed strings 3587 1.66 manu * if this is what the kernel wants. 3588 1.66 manu */ 3589 1.66 manu if (flag & PUFFS_EXTATTR_LIST_LENPREFIX) { 3590 1.66 manu (void)memcpy(attrs + outlen + 1, 3591 1.66 manu np + i, attrlen); 3592 1.66 manu *(attrs + outlen) = (uint8_t)attrlen; 3593 1.66 manu } else 3594 1.66 manu #endif /* PUFFS_EXTATTR_LIST_LENPREFIX */ 3595 1.66 manu (void)memcpy(attrs + outlen, np + i, attrlen + 1); 3596 1.66 manu outlen += attrlen + 1; 3597 1.66 manu } 3598 1.32 manu 3599 1.66 manu *resid -= outlen; 3600 1.31 manu } 3601 1.31 manu 3602 1.31 manu ps->ps_destroy_msg(pm); 3603 1.59 manu error = 0; 3604 1.31 manu 3605 1.59 manu out: 3606 1.59 manu node_rele(opc); 3607 1.59 manu return error; 3608 1.31 manu } 3609 1.31 manu 3610 1.31 manu int 3611 1.52 matt perfuse_node_deleteextattr(struct puffs_usermount *pu, puffs_cookie_t opc, 3612 1.52 matt int attrns, const char *attrname, const struct puffs_cred *pcr) 3613 1.31 manu { 3614 1.31 manu struct perfuse_state *ps; 3615 1.31 manu char fuse_attrname[LINUX_XATTR_NAME_MAX + 1]; 3616 1.31 manu perfuse_msg_t *pm; 3617 1.31 manu size_t attrnamelen; 3618 1.31 manu char *np; 3619 1.31 manu int error; 3620 1.31 manu 3621 1.66 manu /* system namespace attrs are not accessible to non root users */ 3622 1.66 manu if (attrns == EXTATTR_NAMESPACE_SYSTEM && !puffs_cred_isjuggernaut(pcr)) 3623 1.66 manu return EPERM; 3624 1.66 manu 3625 1.59 manu node_ref(opc); 3626 1.59 manu 3627 1.31 manu ps = puffs_getspecific(pu); 3628 1.31 manu attrname = perfuse_native_ns(attrns, attrname, fuse_attrname); 3629 1.31 manu attrnamelen = strlen(attrname) + 1; 3630 1.31 manu 3631 1.31 manu pm = ps->ps_new_msg(pu, opc, FUSE_REMOVEXATTR, attrnamelen, pcr); 3632 1.31 manu np = _GET_INPAYLOAD(ps, pm, char *); 3633 1.31 manu (void)strlcpy(np, attrname, attrnamelen); 3634 1.31 manu 3635 1.31 manu error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply); 3636 1.77 manu if (error != 0) 3637 1.77 manu goto out; 3638 1.78 manu 3639 1.78 manu ps->ps_destroy_msg(pm); 3640 1.78 manu 3641 1.78 manu out: 3642 1.78 manu node_rele(opc); 3643 1.78 manu return error; 3644 1.78 manu } 3645 1.78 manu 3646 1.78 manu int 3647 1.78 manu perfuse_node_fallocate(struct puffs_usermount *pu, puffs_cookie_t opc, 3648 1.78 manu off_t off, off_t len) 3649 1.78 manu { 3650 1.78 manu struct perfuse_state *ps; 3651 1.78 manu perfuse_msg_t *pm; 3652 1.78 manu struct fuse_fallocate_in *fai; 3653 1.78 manu int error; 3654 1.31 manu 3655 1.78 manu ps = puffs_getspecific(pu); 3656 1.78 manu if (ps->ps_flags & PS_NO_FALLOCATE) 3657 1.78 manu return EOPNOTSUPP; 3658 1.78 manu 3659 1.78 manu node_ref(opc); 3660 1.78 manu 3661 1.78 manu pm = ps->ps_new_msg(pu, opc, FUSE_FALLOCATE, sizeof(*fai), NULL); 3662 1.78 manu 3663 1.78 manu fai = GET_INPAYLOAD(ps, pm, fuse_fallocate_in); 3664 1.86 manu fai->fh = PN_ISDIR(opc) ? FUSE_UNKNOWN_FH : perfuse_get_fh(opc, FWRITE); 3665 1.78 manu fai->offset = off; 3666 1.78 manu fai->length = len; 3667 1.78 manu fai->mode = 0; 3668 1.78 manu 3669 1.78 manu error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply); 3670 1.78 manu if (error == EOPNOTSUPP || error == ENOSYS) { 3671 1.78 manu ps->ps_flags |= PS_NO_FALLOCATE; 3672 1.78 manu error = EOPNOTSUPP; 3673 1.78 manu } 3674 1.78 manu if (error != 0) 3675 1.78 manu goto out; 3676 1.78 manu 3677 1.31 manu ps->ps_destroy_msg(pm); 3678 1.78 manu 3679 1.77 manu out: 3680 1.59 manu node_rele(opc); 3681 1.31 manu return error; 3682 1.31 manu } 3683