1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2022 Tomohiro Kusumi <tkusumi@netbsd.org>
5 * Copyright (c) 2011-2022 The DragonFly Project. All rights reserved.
6 *
7 * This code is derived from software contributed to The DragonFly Project
8 * by Matthew Dillon <dillon@dragonflybsd.org>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 * 3. Neither the name of The DragonFly Project nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific, prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37 /*
38 * Kernel Filesystem interface
39 *
40 * NOTE! local ipdata pointers must be reloaded on any modifying operation
41 * to the inode as its underlying chain may have changed.
42 */
43
44 /*
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/fcntl.h>
49 #include <sys/buf.h>
50 #include <sys/proc.h>
51 #include <sys/mount.h>
52 #include <sys/vnode.h>
53 #include <sys/mountctl.h>
54 */
55 #include <sys/dirent.h>
56 /*
57 #include <sys/uio.h>
58 #include <sys/objcache.h>
59 #include <sys/event.h>
60 #include <sys/file.h>
61 #include <vfs/fifofs/fifo.h>
62 */
63
64 #include "hammer2.h"
65
66 static int hammer2_read_file(hammer2_inode_t *ip, struct uio *uio,
67 int seqcount);
68 static int hammer2_write_file(hammer2_inode_t *ip, struct uio *uio,
69 int ioflag, int seqcount);
70 static void hammer2_extend_file(hammer2_inode_t *ip, hammer2_key_t nsize);
71 static void hammer2_truncate_file(hammer2_inode_t *ip, hammer2_key_t nsize);
72
73 /*
74 * Last reference to a vnode is going away but it is still cached.
75 */
76 static
77 int
hammer2_vop_inactive(struct vop_inactive_args * ap)78 hammer2_vop_inactive(struct vop_inactive_args *ap)
79 {
80 #if 0
81 hammer2_inode_t *ip;
82 struct m_vnode *vp;
83
84 vp = ap->a_vp;
85 ip = VTOI(vp);
86
87 /*
88 * Degenerate case
89 */
90 if (ip == NULL) {
91 vrecycle(vp);
92 return (0);
93 }
94
95 /*
96 * Aquire the inode lock to interlock against vp updates via
97 * the inode path and file deletions and such (which can be
98 * namespace-only operations that might not hold the vnode).
99 */
100 hammer2_inode_lock(ip, 0);
101 if (ip->flags & HAMMER2_INODE_ISUNLINKED) {
102 int nblksize;
103
104 /*
105 * If the inode has been unlinked we can throw away all
106 * buffers (dirty or not) and clean the file out.
107 *
108 * Because vrecycle() calls are not guaranteed, try to
109 * dispose of the inode as much as possible right here.
110 */
111 nblksize = hammer2_calc_logical(ip, 0, NULL, NULL);
112 nvtruncbuf(vp, 0, nblksize, 0, 0);
113
114 /*
115 * Delete the file on-media.
116 */
117 if ((ip->flags & HAMMER2_INODE_DELETING) == 0) {
118 atomic_set_int(&ip->flags, HAMMER2_INODE_DELETING);
119 hammer2_inode_delayed_sideq(ip);
120 }
121 hammer2_inode_unlock(ip);
122
123 /*
124 * Recycle immediately if possible
125 */
126 vrecycle(vp);
127 } else {
128 hammer2_inode_unlock(ip);
129 }
130 return (0);
131 #endif
132 return (EOPNOTSUPP);
133 }
134
135 /*
136 * Reclaim a vnode so that it can be reused; after the inode is
137 * disassociated, the filesystem must manage it alone.
138 */
139 static
140 int
hammer2_vop_reclaim(struct vop_reclaim_args * ap)141 hammer2_vop_reclaim(struct vop_reclaim_args *ap)
142 {
143 hammer2_inode_t *ip;
144 struct m_vnode *vp;
145
146 vp = ap->a_vp;
147 ip = VTOI(vp);
148 if (ip == NULL)
149 return(0);
150
151 /*
152 * NOTE! We do not attempt to flush chains here, flushing is
153 * really fragile and could also deadlock.
154 */
155 vclrisdirty(vp);
156
157 /*
158 * The inode lock is required to disconnect it.
159 */
160 hammer2_inode_lock(ip, 0);
161 vp->v_data = NULL;
162 ip->vp = NULL;
163
164 /*
165 * Delete the file on-media. This should have been handled by the
166 * inactivation. The operation is likely still queued on the inode
167 * though so only complain if the stars don't align.
168 */
169 if ((ip->flags & (HAMMER2_INODE_ISUNLINKED | HAMMER2_INODE_DELETING)) ==
170 HAMMER2_INODE_ISUNLINKED)
171 {
172 assert(0);
173 atomic_set_int(&ip->flags, HAMMER2_INODE_DELETING);
174 hammer2_inode_delayed_sideq(ip);
175 kprintf("hammer2: vp=%p ip=%p unlinked but not disposed\n",
176 vp, ip);
177 }
178 hammer2_inode_unlock(ip);
179
180 /*
181 * Modified inodes will already be on SIDEQ or SYNCQ, no further
182 * action is needed.
183 *
184 * We cannot safely synchronize the inode from inside the reclaim
185 * due to potentially deep locks held as-of when the reclaim occurs.
186 * Interactions and potential deadlocks abound. We also can't do it
187 * here without desynchronizing from the related directory entrie(s).
188 */
189 hammer2_inode_drop(ip); /* vp ref */
190
191 /*
192 * XXX handle background sync when ip dirty, kernel will no longer
193 * notify us regarding this inode because there is no longer a
194 * vnode attached to it.
195 */
196
197 return (0);
198 }
199
200 int
hammer2_reclaim(struct m_vnode * vp)201 hammer2_reclaim(struct m_vnode *vp)
202 {
203 struct vop_reclaim_args ap = {
204 .a_vp = vp,
205 };
206
207 return hammer2_vop_reclaim(&ap);
208 }
209
210 /*
211 * Currently this function synchronizes the front-end inode state to the
212 * backend chain topology, then flushes the inode's chain and sub-topology
213 * to backend media. This function does not flush the root topology down to
214 * the inode.
215 */
216 static
217 int
hammer2_vop_fsync(struct vop_fsync_args * ap)218 hammer2_vop_fsync(struct vop_fsync_args *ap)
219 {
220 #if 0
221 hammer2_inode_t *ip;
222 struct m_vnode *vp;
223 int error1;
224 int error2;
225
226 vp = ap->a_vp;
227 ip = VTOI(vp);
228 error1 = 0;
229
230 hammer2_trans_init(ip->pmp, 0);
231
232 /*
233 * Flush dirty buffers in the file's logical buffer cache.
234 * It is best to wait for the strategy code to commit the
235 * buffers to the device's backing buffer cache before
236 * then trying to flush the inode.
237 *
238 * This should be quick, but certain inode modifications cached
239 * entirely in the hammer2_inode structure may not trigger a
240 * buffer read until the flush so the fsync can wind up also
241 * doing scattered reads.
242 */
243 vfsync(vp, ap->a_waitfor, 1, NULL, NULL);
244 bio_track_wait(&vp->v_track_write, 0, 0);
245
246 /*
247 * Flush any inode changes
248 */
249 hammer2_inode_lock(ip, 0);
250 if (ip->flags & (HAMMER2_INODE_RESIZED|HAMMER2_INODE_MODIFIED))
251 error1 = hammer2_inode_chain_sync(ip);
252
253 /*
254 * Flush dirty chains related to the inode.
255 *
256 * NOTE! We are not in a flush transaction. The inode remains on
257 * the sideq so the filesystem syncer can synchronize it to
258 * the volume root.
259 */
260 error2 = hammer2_inode_chain_flush(ip, HAMMER2_XOP_INODE_STOP);
261 if (error2)
262 error1 = error2;
263
264 /*
265 * We may be able to clear the vnode dirty flag.
266 */
267 if ((ip->flags & (HAMMER2_INODE_MODIFIED |
268 HAMMER2_INODE_RESIZED |
269 HAMMER2_INODE_DIRTYDATA)) == 0 &&
270 RB_EMPTY(&vp->v_rbdirty_tree) &&
271 !bio_track_active(&vp->v_track_write)) {
272 vclrisdirty(vp);
273 }
274 hammer2_inode_unlock(ip);
275 hammer2_trans_done(ip->pmp, 0);
276
277 return (error1);
278 #endif
279 return (EOPNOTSUPP);
280 }
281
282 /*
283 * No lock needed, just handle ip->update
284 */
285 static
286 int
hammer2_vop_access(struct vop_access_args * ap)287 hammer2_vop_access(struct vop_access_args *ap)
288 {
289 #if 0
290 hammer2_inode_t *ip = VTOI(ap->a_vp);
291 uid_t uid;
292 gid_t gid;
293 mode_t mode;
294 uint32_t uflags;
295 int error;
296 int update;
297
298 retry:
299 update = spin_access_start(&ip->cluster_spin);
300
301 /*hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED);*/
302 uid = hammer2_to_unix_xid(&ip->meta.uid);
303 gid = hammer2_to_unix_xid(&ip->meta.gid);
304 mode = ip->meta.mode;
305 uflags = ip->meta.uflags;
306 /*hammer2_inode_unlock(ip);*/
307
308 if (__predict_false(spin_access_end(&ip->cluster_spin, update)))
309 goto retry;
310
311 error = vop_helper_access(ap, uid, gid, mode, uflags);
312
313 return (error);
314 #endif
315 return (EOPNOTSUPP);
316 }
317
318 static
319 int
hammer2_vop_getattr(struct vop_getattr_args * ap)320 hammer2_vop_getattr(struct vop_getattr_args *ap)
321 {
322 #if 0
323 hammer2_pfs_t *pmp;
324 hammer2_inode_t *ip;
325 struct m_vnode *vp;
326 struct vattr *vap;
327 int update;
328
329 vp = ap->a_vp;
330 vap = ap->a_vap;
331
332 ip = VTOI(vp);
333 pmp = ip->pmp;
334
335 retry:
336 update = spin_access_start(&ip->cluster_spin);
337
338 vap->va_fsid = pmp->mp->mnt_stat.f_fsid.val[0];
339 vap->va_fileid = ip->meta.inum;
340 vap->va_mode = ip->meta.mode;
341 vap->va_nlink = ip->meta.nlinks;
342 vap->va_uid = hammer2_to_unix_xid(&ip->meta.uid);
343 vap->va_gid = hammer2_to_unix_xid(&ip->meta.gid);
344 vap->va_rmajor = 0;
345 vap->va_rminor = 0;
346 vap->va_size = ip->meta.size; /* protected by shared lock */
347 vap->va_blocksize = HAMMER2_PBUFSIZE;
348 vap->va_flags = ip->meta.uflags;
349 hammer2_time_to_timespec(ip->meta.ctime, &vap->va_ctime);
350 hammer2_time_to_timespec(ip->meta.mtime, &vap->va_mtime);
351 hammer2_time_to_timespec(ip->meta.mtime, &vap->va_atime);
352 vap->va_gen = 1;
353 vap->va_bytes = 0;
354 if (ip->meta.type == HAMMER2_OBJTYPE_DIRECTORY) {
355 /*
356 * Can't really calculate directory use sans the files under
357 * it, just assume one block for now.
358 */
359 vap->va_bytes += HAMMER2_INODE_BYTES;
360 } else {
361 vap->va_bytes = hammer2_inode_data_count(ip);
362 }
363 vap->va_type = hammer2_get_vtype(ip->meta.type);
364 vap->va_filerev = 0;
365 vap->va_uid_uuid = ip->meta.uid;
366 vap->va_gid_uuid = ip->meta.gid;
367 vap->va_vaflags = VA_UID_UUID_VALID | VA_GID_UUID_VALID |
368 VA_FSID_UUID_VALID;
369
370 if (__predict_false(spin_access_end(&ip->cluster_spin, update)))
371 goto retry;
372
373 return (0);
374 #endif
375 return (EOPNOTSUPP);
376 }
377
378 static
379 int
hammer2_vop_getattr_lite(struct vop_getattr_lite_args * ap)380 hammer2_vop_getattr_lite(struct vop_getattr_lite_args *ap)
381 {
382 #if 0
383 hammer2_pfs_t *pmp;
384 hammer2_inode_t *ip;
385 struct m_vnode *vp;
386 struct vattr_lite *lvap;
387 int update;
388
389 vp = ap->a_vp;
390 lvap = ap->a_lvap;
391
392 ip = VTOI(vp);
393 pmp = ip->pmp;
394
395 retry:
396 update = spin_access_start(&ip->cluster_spin);
397
398 #if 0
399 vap->va_fsid = pmp->mp->mnt_stat.f_fsid.val[0];
400 vap->va_fileid = ip->meta.inum;
401 #endif
402 lvap->va_mode = ip->meta.mode;
403 lvap->va_nlink = ip->meta.nlinks;
404 lvap->va_uid = hammer2_to_unix_xid(&ip->meta.uid);
405 lvap->va_gid = hammer2_to_unix_xid(&ip->meta.gid);
406 #if 0
407 vap->va_rmajor = 0;
408 vap->va_rminor = 0;
409 #endif
410 lvap->va_size = ip->meta.size;
411 #if 0
412 vap->va_blocksize = HAMMER2_PBUFSIZE;
413 #endif
414 lvap->va_flags = ip->meta.uflags;
415 lvap->va_type = hammer2_get_vtype(ip->meta.type);
416 #if 0
417 vap->va_filerev = 0;
418 vap->va_uid_uuid = ip->meta.uid;
419 vap->va_gid_uuid = ip->meta.gid;
420 vap->va_vaflags = VA_UID_UUID_VALID | VA_GID_UUID_VALID |
421 VA_FSID_UUID_VALID;
422 #endif
423
424 if (__predict_false(spin_access_end(&ip->cluster_spin, update)))
425 goto retry;
426
427 return (0);
428 #endif
429 return (EOPNOTSUPP);
430 }
431
432 static
433 int
hammer2_vop_setattr(struct vop_setattr_args * ap)434 hammer2_vop_setattr(struct vop_setattr_args *ap)
435 {
436 #if 0
437 hammer2_inode_t *ip;
438 struct m_vnode *vp;
439 struct vattr *vap;
440 int error;
441 int kflags = 0;
442 uint64_t ctime;
443
444 vp = ap->a_vp;
445 vap = ap->a_vap;
446 hammer2_update_time(&ctime);
447
448 ip = VTOI(vp);
449
450 if (ip->pmp->ronly)
451 return (EROFS);
452
453 /*
454 * Normally disallow setattr if there is no space, unless we
455 * are in emergency mode (might be needed to chflags -R noschg
456 * files prior to removal).
457 */
458 if ((ip->pmp->flags & HAMMER2_PMPF_EMERG) == 0 &&
459 hammer2_vfs_enospace(ip, 0, ap->a_cred) > 1) {
460 return (ENOSPC);
461 }
462
463 hammer2_trans_init(ip->pmp, 0);
464 hammer2_inode_lock(ip, 0);
465 error = 0;
466
467 if (vap->va_flags != VNOVAL) {
468 uint32_t flags;
469
470 flags = ip->meta.uflags;
471 error = vop_helper_setattr_flags(&flags, vap->va_flags,
472 hammer2_to_unix_xid(&ip->meta.uid),
473 ap->a_cred);
474 if (error == 0) {
475 if (ip->meta.uflags != flags) {
476 hammer2_inode_modify(ip);
477 hammer2_spin_lock_update(&ip->cluster_spin);
478 ip->meta.uflags = flags;
479 ip->meta.ctime = ctime;
480 hammer2_spin_unlock_update(&ip->cluster_spin);
481 kflags |= NOTE_ATTRIB;
482 }
483 if (ip->meta.uflags & (IMMUTABLE | APPEND)) {
484 error = 0;
485 goto done;
486 }
487 }
488 goto done;
489 }
490 if (ip->meta.uflags & (IMMUTABLE | APPEND)) {
491 error = EPERM;
492 goto done;
493 }
494 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
495 mode_t cur_mode = ip->meta.mode;
496 uid_t cur_uid = hammer2_to_unix_xid(&ip->meta.uid);
497 gid_t cur_gid = hammer2_to_unix_xid(&ip->meta.gid);
498 uuid_t uuid_uid;
499 uuid_t uuid_gid;
500
501 error = vop_helper_chown(ap->a_vp, vap->va_uid, vap->va_gid,
502 ap->a_cred,
503 &cur_uid, &cur_gid, &cur_mode);
504 if (error == 0) {
505 hammer2_guid_to_uuid(&uuid_uid, cur_uid);
506 hammer2_guid_to_uuid(&uuid_gid, cur_gid);
507 if (bcmp(&uuid_uid, &ip->meta.uid, sizeof(uuid_uid)) ||
508 bcmp(&uuid_gid, &ip->meta.gid, sizeof(uuid_gid)) ||
509 ip->meta.mode != cur_mode
510 ) {
511 hammer2_inode_modify(ip);
512 hammer2_spin_lock_update(&ip->cluster_spin);
513 ip->meta.uid = uuid_uid;
514 ip->meta.gid = uuid_gid;
515 ip->meta.mode = cur_mode;
516 ip->meta.ctime = ctime;
517 hammer2_spin_unlock_update(&ip->cluster_spin);
518 }
519 kflags |= NOTE_ATTRIB;
520 }
521 }
522
523 /*
524 * Resize the file
525 */
526 if (vap->va_size != VNOVAL && ip->meta.size != vap->va_size) {
527 switch(vp->v_type) {
528 case VREG:
529 if (vap->va_size == ip->meta.size)
530 break;
531 if (vap->va_size < ip->meta.size) {
532 hammer2_mtx_ex(&ip->truncate_lock);
533 hammer2_truncate_file(ip, vap->va_size);
534 hammer2_mtx_unlock(&ip->truncate_lock);
535 kflags |= NOTE_WRITE;
536 } else {
537 hammer2_extend_file(ip, vap->va_size);
538 kflags |= NOTE_WRITE | NOTE_EXTEND;
539 }
540 hammer2_inode_modify(ip);
541 ip->meta.mtime = ctime;
542 vclrflags(vp, VLASTWRITETS);
543 break;
544 default:
545 error = EINVAL;
546 goto done;
547 }
548 }
549 #if 0
550 /* atime not supported */
551 if (vap->va_atime.tv_sec != VNOVAL) {
552 hammer2_inode_modify(ip);
553 ip->meta.atime = hammer2_timespec_to_time(&vap->va_atime);
554 kflags |= NOTE_ATTRIB;
555 }
556 #endif
557 if (vap->va_mode != (mode_t)VNOVAL) {
558 mode_t cur_mode = ip->meta.mode;
559 uid_t cur_uid = hammer2_to_unix_xid(&ip->meta.uid);
560 gid_t cur_gid = hammer2_to_unix_xid(&ip->meta.gid);
561
562 error = vop_helper_chmod(ap->a_vp, vap->va_mode, ap->a_cred,
563 cur_uid, cur_gid, &cur_mode);
564 if (error == 0) {
565 hammer2_inode_modify(ip);
566 hammer2_spin_lock_update(&ip->cluster_spin);
567 ip->meta.mode = cur_mode;
568 ip->meta.ctime = ctime;
569 hammer2_spin_unlock_update(&ip->cluster_spin);
570 kflags |= NOTE_ATTRIB;
571 }
572 }
573
574 if (vap->va_mtime.tv_sec != VNOVAL) {
575 hammer2_inode_modify(ip);
576 ip->meta.mtime = hammer2_timespec_to_time(&vap->va_mtime);
577 kflags |= NOTE_ATTRIB;
578 vclrflags(vp, VLASTWRITETS);
579 }
580
581 done:
582 /*
583 * If a truncation occurred we must call chain_sync() now in order
584 * to trim the related data chains, otherwise a later expansion can
585 * cause havoc.
586 *
587 * If an extend occured that changed the DIRECTDATA state, we must
588 * call inode_chain_sync now in order to prepare the inode's indirect
589 * block table.
590 *
591 * WARNING! This means we are making an adjustment to the inode's
592 * chain outside of sync/fsync, and not just to inode->meta, which
593 * may result in some consistency issues if a crash were to occur
594 * at just the wrong time.
595 */
596 if (ip->flags & HAMMER2_INODE_RESIZED)
597 hammer2_inode_chain_sync(ip);
598
599 /*
600 * Cleanup.
601 */
602 hammer2_inode_unlock(ip);
603 hammer2_trans_done(ip->pmp, HAMMER2_TRANS_SIDEQ);
604 hammer2_knote(ip->vp, kflags);
605
606 return (error);
607 #endif
608 return (EOPNOTSUPP);
609 }
610
611 static int
vop_write_dirent(int * error,struct uio * uio,ino_t d_ino,uint8_t d_type,uint16_t d_namlen,const char * d_name)612 vop_write_dirent(int *error, struct uio *uio, ino_t d_ino, uint8_t d_type,
613 uint16_t d_namlen, const char *d_name)
614 {
615 struct dirent *dp;
616 size_t len;
617
618 len = _DIRENT_RECLEN(d_namlen);
619 if (len > uio->uio_resid)
620 return(1);
621
622 dp = kmalloc(len, M_TEMP, M_WAITOK | M_ZERO);
623
624 dp->d_ino = d_ino;
625 dp->d_namlen = d_namlen;
626 dp->d_type = d_type;
627 bcopy(d_name, dp->d_name, d_namlen);
628
629 *error = uiomove((caddr_t)dp, len, uio);
630
631 kfree(dp, M_TEMP);
632
633 return(0);
634 }
635
636 static
637 int
hammer2_vop_readdir(struct vop_readdir_args * ap)638 hammer2_vop_readdir(struct vop_readdir_args *ap)
639 {
640 hammer2_xop_readdir_t *xop;
641 hammer2_blockref_t bref;
642 hammer2_inode_t *ip;
643 hammer2_tid_t inum;
644 hammer2_key_t lkey;
645 struct uio *uio;
646 off_t *cookies;
647 off_t saveoff;
648 int cookie_index;
649 int ncookies;
650 int error;
651 int ndirent;
652 int eofflag;
653 int r;
654
655 ip = VTOI(ap->a_vp);
656 uio = ap->a_uio;
657 saveoff = uio->uio_offset;
658 ndirent = 0;
659 eofflag = 0;
660 error = 0;
661
662 /*
663 * Setup cookies directory entry cookies if requested
664 */
665 if (ap->a_ncookies) {
666 ncookies = uio->uio_resid / 16 + 1;
667 if (ncookies > 1024)
668 ncookies = 1024;
669 cookies = kmalloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
670 } else {
671 ncookies = -1;
672 cookies = NULL;
673 }
674 cookie_index = 0;
675
676 hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED);
677
678 /*
679 * Handle artificial entries. To ensure that only positive 64 bit
680 * quantities are returned to userland we always strip off bit 63.
681 * The hash code is designed such that codes 0x0000-0x7FFF are not
682 * used, allowing us to use these codes for articial entries.
683 *
684 * Entry 0 is used for '.' and entry 1 is used for '..'. Do not
685 * allow '..' to cross the mount point into (e.g.) the super-root.
686 */
687 if (saveoff == 0) {
688 inum = ip->meta.inum & HAMMER2_DIRHASH_USERMSK;
689 r = vop_write_dirent(&error, uio, inum, DT_DIR, 1, ".");
690 if (r)
691 goto done;
692 if (cookies)
693 cookies[cookie_index] = saveoff;
694 ++saveoff;
695 ++cookie_index;
696 ++ndirent;
697 if (cookie_index == ncookies)
698 goto done;
699 }
700
701 if (saveoff == 1) {
702 inum = ip->meta.inum & HAMMER2_DIRHASH_USERMSK;
703 if (ip != ip->pmp->iroot)
704 inum = ip->meta.iparent & HAMMER2_DIRHASH_USERMSK;
705 r = vop_write_dirent(&error, uio, inum, DT_DIR, 2, "..");
706 if (r)
707 goto done;
708 if (cookies)
709 cookies[cookie_index] = saveoff;
710 ++saveoff;
711 ++cookie_index;
712 ++ndirent;
713 if (cookie_index == ncookies)
714 goto done;
715 }
716
717 lkey = saveoff | HAMMER2_DIRHASH_VISIBLE;
718 if (hammer2_debug & 0x0020)
719 kprintf("readdir: lkey %016jx\n", lkey);
720 if (error)
721 goto done;
722
723 xop = hammer2_xop_alloc(ip, 0);
724 xop->lkey = lkey;
725 hammer2_xop_start(&xop->head, &hammer2_readdir_desc);
726
727 for (;;) {
728 const hammer2_inode_data_t *ripdata;
729 const char *dname;
730 int dtype;
731
732 error = hammer2_xop_collect(&xop->head, 0);
733 error = hammer2_error_to_errno(error);
734 if (error) {
735 break;
736 }
737 if (cookie_index == ncookies)
738 break;
739 if (hammer2_debug & 0x0020)
740 kprintf("cluster chain %p %p\n",
741 xop->head.cluster.focus,
742 (xop->head.cluster.focus ?
743 xop->head.cluster.focus->data : (void *)-1));
744 hammer2_cluster_bref(&xop->head.cluster, &bref);
745
746 if (bref.type == HAMMER2_BREF_TYPE_INODE) {
747 ripdata = &hammer2_xop_gdata(&xop->head)->ipdata;
748 dtype = hammer2_get_dtype(ripdata->meta.type);
749 saveoff = bref.key & HAMMER2_DIRHASH_USERMSK;
750 r = vop_write_dirent(&error, uio,
751 ripdata->meta.inum &
752 HAMMER2_DIRHASH_USERMSK,
753 dtype,
754 ripdata->meta.name_len,
755 ripdata->filename);
756 hammer2_xop_pdata(&xop->head);
757 if (r)
758 break;
759 if (cookies)
760 cookies[cookie_index] = saveoff;
761 ++cookie_index;
762 ++ndirent;
763 } else if (bref.type == HAMMER2_BREF_TYPE_DIRENT) {
764 uint16_t namlen;
765
766 dtype = hammer2_get_dtype(bref.embed.dirent.type);
767 saveoff = bref.key & HAMMER2_DIRHASH_USERMSK;
768 namlen = bref.embed.dirent.namlen;
769 if (namlen <= sizeof(bref.check.buf)) {
770 dname = bref.check.buf;
771 } else {
772 dname = hammer2_xop_gdata(&xop->head)->buf;
773 }
774 r = vop_write_dirent(&error, uio,
775 bref.embed.dirent.inum, dtype,
776 namlen, dname);
777 if (namlen > sizeof(bref.check.buf))
778 hammer2_xop_pdata(&xop->head);
779 if (r)
780 break;
781 if (cookies)
782 cookies[cookie_index] = saveoff;
783 ++cookie_index;
784 ++ndirent;
785 } else {
786 /* XXX chain error */
787 kprintf("bad chain type readdir %d\n", bref.type);
788 }
789 }
790 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
791 if (error == ENOENT) {
792 error = 0;
793 eofflag = 1;
794 saveoff = (hammer2_key_t)-1;
795 } else {
796 saveoff = bref.key & HAMMER2_DIRHASH_USERMSK;
797 }
798 done:
799 hammer2_inode_unlock(ip);
800 if (ap->a_eofflag)
801 *ap->a_eofflag = eofflag;
802 if (hammer2_debug & 0x0020)
803 kprintf("readdir: done at %016jx\n", saveoff);
804 uio->uio_offset = saveoff & ~HAMMER2_DIRHASH_VISIBLE;
805 if (error && cookie_index == 0) {
806 if (cookies) {
807 kfree(cookies, M_TEMP);
808 *ap->a_ncookies = 0;
809 *ap->a_cookies = NULL;
810 }
811 } else {
812 if (cookies) {
813 *ap->a_ncookies = cookie_index;
814 *ap->a_cookies = cookies;
815 }
816 }
817 *ap->a_ndirent = ndirent;
818
819 return (error);
820 }
821
822 int
hammer2_readdir(struct m_vnode * vp,void * buf,size_t size,off_t * offsetp,int * ndirentp,int * eofflagp)823 hammer2_readdir(struct m_vnode *vp, void *buf, size_t size, off_t *offsetp,
824 int *ndirentp, int *eofflagp)
825 {
826 int error;
827
828 assert(buf);
829 assert(size > 0);
830 assert(size <= HAMMER2_PBUFSIZE);
831
832 struct iovec iov = {
833 .iov_base = buf,
834 .iov_len = size,
835 };
836 struct uio uio = {
837 .uio_iov = &iov,
838 .uio_iovcnt = 1,
839 .uio_offset = *offsetp,
840 .uio_resid = size,
841 .uio_segflg = UIO_USERSPACE,
842 .uio_rw = UIO_READ,
843 .uio_td = NULL,
844 };
845 struct vop_readdir_args ap = {
846 .a_vp = vp,
847 .a_uio = &uio,
848 .a_cred = NULL,
849 .a_eofflag = eofflagp,
850 .a_ncookies = NULL,
851 .a_cookies = NULL,
852 .a_ndirent = ndirentp,
853 };
854
855 error = hammer2_vop_readdir(&ap);
856 *offsetp = uio.uio_offset;
857
858 return (error);
859 }
860
861 /*
862 * hammer2_vop_readlink { vp, uio, cred }
863 */
864 static
865 int
hammer2_vop_readlink(struct vop_readlink_args * ap)866 hammer2_vop_readlink(struct vop_readlink_args *ap)
867 {
868 struct m_vnode *vp;
869 hammer2_inode_t *ip;
870 int error;
871
872 vp = ap->a_vp;
873 if (vp->v_type != VLNK)
874 return (EINVAL);
875 ip = VTOI(vp);
876
877 error = hammer2_read_file(ip, ap->a_uio, 0);
878 return (error);
879 }
880
881 int
hammer2_readlink(struct m_vnode * vp,void * buf,size_t size)882 hammer2_readlink(struct m_vnode *vp, void *buf, size_t size)
883 {
884 assert(buf);
885 assert(size > 0);
886 assert(size <= HAMMER2_PBUFSIZE);
887
888 struct iovec iov = {
889 .iov_base = buf,
890 .iov_len = size,
891 };
892 struct uio uio = {
893 .uio_iov = &iov,
894 .uio_iovcnt = 1,
895 .uio_offset = 0,
896 .uio_resid = size,
897 .uio_segflg = UIO_USERSPACE,
898 .uio_rw = UIO_READ,
899 .uio_td = NULL,
900 };
901 struct vop_readlink_args ap = {
902 .a_vp = vp,
903 .a_uio = &uio,
904 .a_cred = NULL,
905 };
906
907 return hammer2_vop_readlink(&ap);
908 }
909
910 static
911 int
hammer2_vop_read(struct vop_read_args * ap)912 hammer2_vop_read(struct vop_read_args *ap)
913 {
914 struct m_vnode *vp;
915 hammer2_inode_t *ip;
916 struct uio *uio;
917 int error;
918 int seqcount;
919
920 /*
921 * Read operations supported on this vnode?
922 */
923 vp = ap->a_vp;
924 if (vp->v_type == VDIR)
925 return (EISDIR);
926 if (vp->v_type != VREG)
927 return (EINVAL);
928
929 /*
930 * Misc
931 */
932 ip = VTOI(vp);
933 uio = ap->a_uio;
934 error = 0;
935
936 seqcount = ap->a_ioflag >> IO_SEQSHIFT;
937
938 error = hammer2_read_file(ip, uio, seqcount);
939 return (error);
940 }
941
942 int
hammer2_read(struct m_vnode * vp,void * buf,size_t size,off_t offset)943 hammer2_read(struct m_vnode *vp, void *buf, size_t size, off_t offset)
944 {
945 assert(buf);
946 assert(size > 0);
947 assert(size <= HAMMER2_PBUFSIZE);
948
949 struct iovec iov = {
950 .iov_base = buf,
951 .iov_len = size,
952 };
953 struct uio uio = {
954 .uio_iov = &iov,
955 .uio_iovcnt = 1,
956 .uio_offset = offset,
957 .uio_resid = size,
958 .uio_segflg = UIO_USERSPACE,
959 .uio_rw = UIO_READ,
960 .uio_td = NULL,
961 };
962 struct vop_read_args ap = {
963 .a_vp = vp,
964 .a_uio = &uio,
965 .a_ioflag = 0,
966 .a_cred = NULL,
967 };
968
969 return hammer2_vop_read(&ap);
970 }
971
972 static
973 int
hammer2_vop_write(struct vop_write_args * ap)974 hammer2_vop_write(struct vop_write_args *ap)
975 {
976 hammer2_inode_t *ip;
977 //thread_t td;
978 struct m_vnode *vp;
979 struct uio *uio;
980 int error;
981 int seqcount;
982 int ioflag;
983
984 /*
985 * Read operations supported on this vnode?
986 */
987 vp = ap->a_vp;
988 if (vp->v_type != VREG)
989 return (EINVAL);
990
991 /*
992 * Misc
993 */
994 ip = VTOI(vp);
995 ioflag = ap->a_ioflag;
996 uio = ap->a_uio;
997 error = 0;
998 if (ip->pmp->ronly || (ip->pmp->flags & HAMMER2_PMPF_EMERG))
999 return (EROFS);
1000 switch (hammer2_vfs_enospace(ip, uio->uio_resid, ap->a_cred)) {
1001 case 2:
1002 return (ENOSPC);
1003 case 1:
1004 ioflag |= IO_DIRECT; /* semi-synchronous */
1005 /* fall through */
1006 default:
1007 break;
1008 }
1009
1010 seqcount = ioflag >> IO_SEQSHIFT;
1011
1012 /*
1013 * Check resource limit
1014 */
1015 /*
1016 if (uio->uio_resid > 0 && (td = uio->uio_td) != NULL && td->td_proc &&
1017 uio->uio_offset + uio->uio_resid >
1018 td->td_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
1019 lwpsignal(td->td_proc, td->td_lwp, SIGXFSZ);
1020 return (EFBIG);
1021 }
1022 */
1023
1024 /*
1025 * The transaction interlocks against flush initiations
1026 * (note: but will run concurrently with the actual flush).
1027 *
1028 * To avoid deadlocking against the VM system, we must flag any
1029 * transaction related to the buffer cache or other direct
1030 * VM page manipulation.
1031 */
1032 if (uio->uio_segflg == UIO_NOCOPY) {
1033 assert(0); /* no UIO_NOCOPY in makefs */
1034 hammer2_trans_init(ip->pmp, HAMMER2_TRANS_BUFCACHE);
1035 } else {
1036 hammer2_trans_init(ip->pmp, 0);
1037 }
1038 error = hammer2_write_file(ip, uio, ioflag, seqcount);
1039 if (uio->uio_segflg == UIO_NOCOPY) {
1040 assert(0); /* no UIO_NOCOPY in makefs */
1041 hammer2_trans_done(ip->pmp, HAMMER2_TRANS_BUFCACHE |
1042 HAMMER2_TRANS_SIDEQ);
1043 } else
1044 hammer2_trans_done(ip->pmp, HAMMER2_TRANS_SIDEQ);
1045
1046 return (error);
1047 }
1048
1049 int
hammer2_write(struct m_vnode * vp,void * buf,size_t size,off_t offset)1050 hammer2_write(struct m_vnode *vp, void *buf, size_t size, off_t offset)
1051 {
1052 assert(buf);
1053 assert(size > 0);
1054 assert(size <= HAMMER2_PBUFSIZE);
1055
1056 struct iovec iov = {
1057 .iov_base = buf,
1058 .iov_len = size,
1059 };
1060 struct uio uio = {
1061 .uio_iov = &iov,
1062 .uio_iovcnt = 1,
1063 .uio_offset = offset,
1064 .uio_resid = size,
1065 .uio_segflg = UIO_USERSPACE,
1066 .uio_rw = UIO_WRITE,
1067 .uio_td = NULL,
1068 };
1069 struct vop_write_args ap = {
1070 .a_vp = vp,
1071 .a_uio = &uio,
1072 .a_ioflag = 0,
1073 .a_cred = NULL,
1074 };
1075
1076 return hammer2_vop_write(&ap);
1077 }
1078
1079 /*
1080 * Perform read operations on a file or symlink given an UNLOCKED
1081 * inode and uio.
1082 *
1083 * The passed ip is not locked.
1084 */
1085 static
1086 int
hammer2_read_file(hammer2_inode_t * ip,struct uio * uio,int seqcount)1087 hammer2_read_file(hammer2_inode_t *ip, struct uio *uio, int seqcount)
1088 {
1089 hammer2_off_t size;
1090 struct m_buf *bp;
1091 int error;
1092
1093 error = 0;
1094
1095 /*
1096 * UIO read loop.
1097 *
1098 * WARNING! Assumes that the kernel interlocks size changes at the
1099 * vnode level.
1100 */
1101 hammer2_mtx_sh(&ip->lock);
1102 hammer2_mtx_sh(&ip->truncate_lock);
1103 size = ip->meta.size;
1104 hammer2_mtx_unlock(&ip->lock);
1105
1106 while (uio->uio_resid > 0 && uio->uio_offset < size) {
1107 hammer2_key_t lbase;
1108 hammer2_key_t leof;
1109 int lblksize;
1110 int loff;
1111 int n;
1112
1113 lblksize = hammer2_calc_logical(ip, uio->uio_offset,
1114 &lbase, &leof);
1115 #if 0
1116 #if 1
1117 bp = NULL;
1118 error = cluster_readx(ip->vp, leof, lbase, lblksize,
1119 B_NOTMETA | B_KVABIO,
1120 uio->uio_resid,
1121 seqcount * MAXBSIZE,
1122 &bp);
1123 #else
1124 if (uio->uio_segflg == UIO_NOCOPY) {
1125 bp = getblk(ip->vp, lbase, lblksize,
1126 GETBLK_BHEAVY | GETBLK_KVABIO, 0);
1127 if (bp->b_flags & B_CACHE) {
1128 int i;
1129 int j = 0;
1130 if (bp->b_xio.xio_npages != 16)
1131 kprintf("NPAGES BAD\n");
1132 for (i = 0; i < bp->b_xio.xio_npages; ++i) {
1133 vm_page_t m;
1134 m = bp->b_xio.xio_pages[i];
1135 if (m == NULL || m->valid == 0) {
1136 kprintf("bp %016jx %016jx pg %d inv",
1137 lbase, leof, i);
1138 if (m)
1139 kprintf("m->object %p/%p", m->object, ip->vp->v_object);
1140 kprintf("\n");
1141 j = 1;
1142 }
1143 }
1144 if (j)
1145 kprintf("b_flags %08x, b_error %d\n", bp->b_flags, bp->b_error);
1146 }
1147 bqrelse(bp);
1148 }
1149 error = bread_kvabio(ip->vp, lbase, lblksize, &bp);
1150 #endif
1151 #else
1152 bp = getblkx(ip->vp, lbase, lblksize,
1153 GETBLK_BHEAVY | GETBLK_KVABIO, 0);
1154 bp->b_cmd = BUF_CMD_READ;
1155
1156 struct bio bio;
1157 bio.bio_buf = bp;
1158 bio.bio_offset = lbase;
1159
1160 struct vop_strategy_args ap;
1161 ap.a_vp = ip->vp;
1162 ap.a_bio = &bio;
1163
1164 error = hammer2_vop_strategy(&ap);
1165 assert(!error);
1166 #endif
1167 if (error) {
1168 brelse(bp);
1169 break;
1170 }
1171 bkvasync(bp);
1172 loff = (int)(uio->uio_offset - lbase);
1173 n = lblksize - loff;
1174 if (n > uio->uio_resid)
1175 n = uio->uio_resid;
1176 if (n > size - uio->uio_offset)
1177 n = (int)(size - uio->uio_offset);
1178 //bp->b_flags |= B_AGE;
1179 uiomovebp(bp, bp->b_data + loff, n, uio);
1180 bqrelse(bp);
1181 }
1182 hammer2_mtx_unlock(&ip->truncate_lock);
1183
1184 return (error);
1185 }
1186
1187 /*
1188 * Write to the file represented by the inode via the logical buffer cache.
1189 * The inode may represent a regular file or a symlink.
1190 *
1191 * The inode must not be locked.
1192 */
1193 static
1194 int
hammer2_write_file(hammer2_inode_t * ip,struct uio * uio,int ioflag,int seqcount)1195 hammer2_write_file(hammer2_inode_t *ip, struct uio *uio,
1196 int ioflag, int seqcount)
1197 {
1198 hammer2_key_t old_eof;
1199 hammer2_key_t new_eof;
1200 struct m_buf *bp;
1201 int kflags;
1202 int error;
1203 int modified;
1204
1205 /*
1206 * Setup if append
1207 *
1208 * WARNING! Assumes that the kernel interlocks size changes at the
1209 * vnode level.
1210 */
1211 hammer2_mtx_ex(&ip->lock);
1212 hammer2_mtx_sh(&ip->truncate_lock);
1213 if (ioflag & IO_APPEND)
1214 uio->uio_offset = ip->meta.size;
1215 old_eof = ip->meta.size;
1216
1217 /*
1218 * Extend the file if necessary. If the write fails at some point
1219 * we will truncate it back down to cover as much as we were able
1220 * to write.
1221 *
1222 * Doing this now makes it easier to calculate buffer sizes in
1223 * the loop.
1224 */
1225 kflags = 0;
1226 error = 0;
1227 modified = 0;
1228
1229 if (uio->uio_offset + uio->uio_resid > old_eof) {
1230 new_eof = uio->uio_offset + uio->uio_resid;
1231 modified = 1;
1232 hammer2_extend_file(ip, new_eof);
1233 kflags |= NOTE_EXTEND;
1234 } else {
1235 new_eof = old_eof;
1236 }
1237 hammer2_mtx_unlock(&ip->lock);
1238
1239 /*
1240 * UIO write loop
1241 */
1242 while (uio->uio_resid > 0) {
1243 hammer2_key_t lbase;
1244 int trivial;
1245 int endofblk;
1246 int lblksize;
1247 int loff;
1248 int n;
1249
1250 /*
1251 * Don't allow the buffer build to blow out the buffer
1252 * cache.
1253 */
1254 if ((ioflag & IO_RECURSE) == 0)
1255 bwillwrite(HAMMER2_PBUFSIZE);
1256
1257 /*
1258 * This nominally tells us how much we can cluster and
1259 * what the logical buffer size needs to be. Currently
1260 * we don't try to cluster the write and just handle one
1261 * block at a time.
1262 */
1263 lblksize = hammer2_calc_logical(ip, uio->uio_offset,
1264 &lbase, NULL);
1265 loff = (int)(uio->uio_offset - lbase);
1266
1267 KKASSERT(lblksize <= MAXBSIZE);
1268
1269 /*
1270 * Calculate bytes to copy this transfer and whether the
1271 * copy completely covers the buffer or not.
1272 */
1273 trivial = 0;
1274 n = lblksize - loff;
1275 if (n > uio->uio_resid) {
1276 n = uio->uio_resid;
1277 if (loff == lbase && uio->uio_offset + n == new_eof)
1278 trivial = 1;
1279 endofblk = 0;
1280 } else {
1281 if (loff == 0)
1282 trivial = 1;
1283 endofblk = 1;
1284 }
1285 if (lbase >= new_eof)
1286 trivial = 1;
1287 trivial = 1; /* force trivial for makefs */
1288
1289 /*
1290 * Get the buffer
1291 */
1292 if (uio->uio_segflg == UIO_NOCOPY) {
1293 assert(0); /* no UIO_NOCOPY in makefs */
1294 /*
1295 * Issuing a write with the same data backing the
1296 * buffer. Instantiate the buffer to collect the
1297 * backing vm pages, then read-in any missing bits.
1298 *
1299 * This case is used by vop_stdputpages().
1300 */
1301 bp = getblkx(ip->vp, lbase, lblksize,
1302 GETBLK_BHEAVY | GETBLK_KVABIO, 0);
1303 /*
1304 if ((bp->b_flags & B_CACHE) == 0) {
1305 bqrelse(bp);
1306 error = bread_kvabio(ip->vp, lbase,
1307 lblksize, &bp);
1308 }
1309 */
1310 } else if (trivial) {
1311 /*
1312 * Even though we are entirely overwriting the buffer
1313 * we may still have to zero it out to avoid a
1314 * mmap/write visibility issue.
1315 */
1316 bp = getblkx(ip->vp, lbase, lblksize,
1317 GETBLK_BHEAVY | GETBLK_KVABIO, 0);
1318 /*
1319 if ((bp->b_flags & B_CACHE) == 0)
1320 vfs_bio_clrbuf(bp);
1321 */
1322 } else {
1323 assert(0); /* no partial write in makefs */
1324 /*
1325 * Partial overwrite, read in any missing bits then
1326 * replace the portion being written.
1327 *
1328 * (The strategy code will detect zero-fill physical
1329 * blocks for this case).
1330 */
1331 error = bread_kvabio(ip->vp, lbase, lblksize, &bp);
1332 if (error == 0)
1333 bheavy(bp);
1334 }
1335
1336 if (error) {
1337 brelse(bp);
1338 break;
1339 }
1340
1341 /*
1342 * Ok, copy the data in
1343 */
1344 bkvasync(bp);
1345 error = uiomovebp(bp, bp->b_data + loff, n, uio);
1346 kflags |= NOTE_WRITE;
1347 modified = 1;
1348 if (error) {
1349 brelse(bp);
1350 break;
1351 }
1352
1353 /*
1354 * WARNING: Pageout daemon will issue UIO_NOCOPY writes
1355 * with IO_SYNC or IO_ASYNC set. These writes
1356 * must be handled as the pageout daemon expects.
1357 *
1358 * NOTE! H2 relies on cluster_write() here because it
1359 * cannot preallocate disk blocks at the logical
1360 * level due to not knowing what the compression
1361 * size will be at this time.
1362 *
1363 * We must use cluster_write() here and we depend
1364 * on the write-behind feature to flush buffers
1365 * appropriately. If we let the buffer daemons do
1366 * it the block allocations will be all over the
1367 * map.
1368 */
1369 if (1) {
1370 bp->b_cmd = BUF_CMD_WRITE;
1371
1372 struct bio bio;
1373 bio.bio_buf = bp;
1374 bio.bio_offset = lbase;
1375
1376 struct vop_strategy_args ap;
1377 ap.a_vp = ip->vp;
1378 ap.a_bio = &bio;
1379
1380 error = hammer2_vop_strategy(&ap);
1381 assert(!error);
1382
1383 brelse(bp);
1384 } else if (ioflag & IO_SYNC) {
1385 assert(0);
1386 bwrite(bp);
1387 } else if ((ioflag & IO_DIRECT) && endofblk) {
1388 assert(0);
1389 bawrite(bp);
1390 } else if (ioflag & IO_ASYNC) {
1391 assert(0);
1392 bawrite(bp);
1393 } else if (0 /*ip->vp->v_mount->mnt_flag & MNT_NOCLUSTERW*/) {
1394 assert(0);
1395 bdwrite(bp);
1396 } else {
1397 assert(0);
1398 #if 0
1399 #if 1
1400 bp->b_flags |= B_CLUSTEROK;
1401 cluster_write(bp, new_eof, lblksize, seqcount);
1402 #else
1403 bp->b_flags |= B_CLUSTEROK;
1404 bdwrite(bp);
1405 #endif
1406 #endif
1407 }
1408 }
1409
1410 /*
1411 * Cleanup. If we extended the file EOF but failed to write through
1412 * the entire write is a failure and we have to back-up.
1413 */
1414 if (error && new_eof != old_eof) {
1415 hammer2_mtx_unlock(&ip->truncate_lock);
1416 hammer2_mtx_ex(&ip->lock); /* note lock order */
1417 hammer2_mtx_ex(&ip->truncate_lock); /* note lock order */
1418 hammer2_truncate_file(ip, old_eof);
1419 if (ip->flags & HAMMER2_INODE_MODIFIED)
1420 hammer2_inode_chain_sync(ip);
1421 hammer2_mtx_unlock(&ip->lock);
1422 } else if (modified) {
1423 struct m_vnode *vp = ip->vp;
1424
1425 hammer2_mtx_ex(&ip->lock);
1426 hammer2_inode_modify(ip);
1427 if (uio->uio_segflg == UIO_NOCOPY) {
1428 assert(0); /* no UIO_NOCOPY in makefs */
1429 /*
1430 if (vp->v_flag & VLASTWRITETS) {
1431 ip->meta.mtime =
1432 (unsigned long)vp->v_lastwrite_ts.tv_sec *
1433 1000000 +
1434 vp->v_lastwrite_ts.tv_nsec / 1000;
1435 }
1436 */
1437 } else {
1438 hammer2_update_time(&ip->meta.mtime, true);
1439 vclrflags(vp, VLASTWRITETS);
1440 }
1441
1442 #if 0
1443 /*
1444 * REMOVED - handled by hammer2_extend_file(). Do not issue
1445 * a chain_sync() outside of a sync/fsync except for DIRECTDATA
1446 * state changes.
1447 *
1448 * Under normal conditions we only issue a chain_sync if
1449 * the inode's DIRECTDATA state changed.
1450 */
1451 if (ip->flags & HAMMER2_INODE_RESIZED)
1452 hammer2_inode_chain_sync(ip);
1453 #endif
1454 hammer2_mtx_unlock(&ip->lock);
1455 hammer2_knote(ip->vp, kflags);
1456 }
1457 hammer2_trans_assert_strategy(ip->pmp);
1458 hammer2_mtx_unlock(&ip->truncate_lock);
1459
1460 return error;
1461 }
1462
1463 /*
1464 * Truncate the size of a file. The inode must be locked.
1465 *
1466 * We must unconditionally set HAMMER2_INODE_RESIZED to properly
1467 * ensure that any on-media data beyond the new file EOF has been destroyed.
1468 *
1469 * WARNING: nvtruncbuf() can only be safely called without the inode lock
1470 * held due to the way our write thread works. If the truncation
1471 * occurs in the middle of a buffer, nvtruncbuf() is responsible
1472 * for dirtying that buffer and zeroing out trailing bytes.
1473 *
1474 * WARNING! Assumes that the kernel interlocks size changes at the
1475 * vnode level.
1476 *
1477 * WARNING! Caller assumes responsibility for removing dead blocks
1478 * if INODE_RESIZED is set.
1479 */
1480 static
1481 void
hammer2_truncate_file(hammer2_inode_t * ip,hammer2_key_t nsize)1482 hammer2_truncate_file(hammer2_inode_t *ip, hammer2_key_t nsize)
1483 {
1484 int nblksize;
1485
1486 hammer2_mtx_unlock(&ip->lock);
1487 if (ip->vp) {
1488 nblksize = hammer2_calc_logical(ip, 0, NULL, NULL);
1489 nvtruncbuf(ip->vp, nsize,
1490 nblksize, (int)nsize & (nblksize - 1),
1491 0);
1492 }
1493 hammer2_mtx_ex(&ip->lock);
1494 KKASSERT((ip->flags & HAMMER2_INODE_RESIZED) == 0);
1495 ip->osize = ip->meta.size;
1496 ip->meta.size = nsize;
1497 atomic_set_int(&ip->flags, HAMMER2_INODE_RESIZED);
1498 hammer2_inode_modify(ip);
1499 }
1500
1501 /*
1502 * Extend the size of a file. The inode must be locked.
1503 *
1504 * Even though the file size is changing, we do not have to set the
1505 * INODE_RESIZED bit unless the file size crosses the EMBEDDED_BYTES
1506 * boundary. When this occurs a hammer2_inode_chain_sync() is required
1507 * to prepare the inode cluster's indirect block table, otherwise
1508 * async execution of the strategy code will implode on us.
1509 *
1510 * WARNING! Assumes that the kernel interlocks size changes at the
1511 * vnode level.
1512 *
1513 * WARNING! Caller assumes responsibility for transitioning out
1514 * of the inode DIRECTDATA mode if INODE_RESIZED is set.
1515 */
1516 static
1517 void
hammer2_extend_file(hammer2_inode_t * ip,hammer2_key_t nsize)1518 hammer2_extend_file(hammer2_inode_t *ip, hammer2_key_t nsize)
1519 {
1520 hammer2_key_t osize;
1521 int oblksize;
1522 int nblksize;
1523 int error;
1524
1525 KKASSERT((ip->flags & HAMMER2_INODE_RESIZED) == 0);
1526 hammer2_inode_modify(ip);
1527 osize = ip->meta.size;
1528 ip->osize = osize;
1529 ip->meta.size = nsize;
1530
1531 /*
1532 * We must issue a chain_sync() when the DIRECTDATA state changes
1533 * to prevent confusion between the flush code and the in-memory
1534 * state. This is not perfect because we are doing it outside of
1535 * a sync/fsync operation, so it might not be fully synchronized
1536 * with the meta-data topology flush.
1537 *
1538 * We must retain and re-dirty the buffer cache buffer containing
1539 * the direct data so it can be written to a real block. It should
1540 * not be possible for a bread error to occur since the original data
1541 * is extracted from the inode structure directly.
1542 */
1543 if (osize <= HAMMER2_EMBEDDED_BYTES && nsize > HAMMER2_EMBEDDED_BYTES) {
1544 if (osize) {
1545 assert(0); /* no such transition in makefs */
1546 struct m_buf *bp;
1547
1548 oblksize = hammer2_calc_logical(ip, 0, NULL, NULL);
1549 error = bread_kvabio(ip->vp, 0, oblksize, &bp);
1550 atomic_set_int(&ip->flags, HAMMER2_INODE_RESIZED);
1551 hammer2_inode_chain_sync(ip);
1552 if (error == 0) {
1553 bheavy(bp);
1554 bdwrite(bp);
1555 } else {
1556 brelse(bp);
1557 }
1558 } else {
1559 atomic_set_int(&ip->flags, HAMMER2_INODE_RESIZED);
1560 hammer2_inode_chain_sync(ip);
1561 }
1562 }
1563 hammer2_mtx_unlock(&ip->lock);
1564 if (ip->vp) {
1565 oblksize = hammer2_calc_logical(ip, 0, NULL, NULL);
1566 nblksize = hammer2_calc_logical(ip, 0, NULL, NULL);
1567 nvextendbuf(ip->vp,
1568 osize, nsize,
1569 oblksize, nblksize,
1570 -1, -1, 0);
1571 }
1572 hammer2_mtx_ex(&ip->lock);
1573 }
1574
1575 static
1576 int
hammer2_vop_nresolve(struct vop_nresolve_args * ap)1577 hammer2_vop_nresolve(struct vop_nresolve_args *ap)
1578 {
1579 hammer2_xop_nresolve_t *xop;
1580 hammer2_inode_t *ip;
1581 hammer2_inode_t *dip;
1582 struct namecache *ncp;
1583 struct m_vnode *vp;
1584 int error;
1585
1586 dip = VTOI(ap->a_dvp);
1587 xop = hammer2_xop_alloc(dip, 0);
1588
1589 ncp = ap->a_nch->ncp;
1590 hammer2_xop_setname(&xop->head, ncp->nc_name, ncp->nc_nlen);
1591
1592 /*
1593 * Note: In DragonFly the kernel handles '.' and '..'.
1594 */
1595 hammer2_inode_lock(dip, HAMMER2_RESOLVE_SHARED);
1596 hammer2_xop_start(&xop->head, &hammer2_nresolve_desc);
1597
1598 error = hammer2_xop_collect(&xop->head, 0);
1599 error = hammer2_error_to_errno(error);
1600 if (error) {
1601 ip = NULL;
1602 } else {
1603 ip = hammer2_inode_get(dip->pmp, &xop->head, -1, -1);
1604 }
1605 hammer2_inode_unlock(dip);
1606
1607 /*
1608 * Acquire the related vnode
1609 *
1610 * NOTE: For error processing, only ENOENT resolves the namecache
1611 * entry to NULL, otherwise we just return the error and
1612 * leave the namecache unresolved.
1613 *
1614 * WARNING: inode structure is locked exclusively via inode_get
1615 * but chain was locked shared. inode_unlock()
1616 * will handle it properly.
1617 */
1618 if (ip) {
1619 vp = hammer2_igetv(ip, &error); /* error set to UNIX error */
1620 if (error == 0) {
1621 vn_unlock(vp);
1622 cache_setvp(ap->a_nch, vp);
1623 *ap->a_vpp = vp;
1624 } else if (error == ENOENT) {
1625 cache_setvp(ap->a_nch, NULL);
1626 }
1627 hammer2_inode_unlock(ip);
1628
1629 /*
1630 * The vp should not be released until after we've disposed
1631 * of our locks, because it might cause vop_inactive() to
1632 * be called.
1633 */
1634 if (vp)
1635 vrele(vp);
1636 } else {
1637 error = ENOENT;
1638 cache_setvp(ap->a_nch, NULL);
1639 }
1640 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
1641 /*
1642 KASSERT(error || ap->a_nch->ncp->nc_vp != NULL,
1643 ("resolve error %d/%p ap %p\n",
1644 error, ap->a_nch->ncp->nc_vp, ap));
1645 */
1646
1647 return error;
1648 }
1649
1650 int
hammer2_nresolve(struct m_vnode * dvp,struct m_vnode ** vpp,char * name,int nlen)1651 hammer2_nresolve(struct m_vnode *dvp, struct m_vnode **vpp, char *name, int nlen)
1652 {
1653 *vpp = NULL;
1654 struct namecache nc = {
1655 .nc_name = name,
1656 .nc_nlen = nlen,
1657 };
1658 struct nchandle nch = {
1659 .ncp = &nc,
1660 };
1661 struct vop_nresolve_args ap = {
1662 .a_nch = &nch,
1663 .a_dvp = dvp,
1664 .a_vpp = vpp,
1665 };
1666
1667 return hammer2_vop_nresolve(&ap);
1668 }
1669
1670 static
1671 int
hammer2_vop_nlookupdotdot(struct vop_nlookupdotdot_args * ap)1672 hammer2_vop_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
1673 {
1674 #if 0
1675 hammer2_inode_t *dip;
1676 hammer2_tid_t inum;
1677 int error;
1678
1679 dip = VTOI(ap->a_dvp);
1680 inum = dip->meta.iparent;
1681 *ap->a_vpp = NULL;
1682
1683 if (inum) {
1684 error = hammer2_vfs_vget(ap->a_dvp->v_mount, NULL,
1685 inum, ap->a_vpp);
1686 } else {
1687 error = ENOENT;
1688 }
1689 return error;
1690 #endif
1691 return (EOPNOTSUPP);
1692 }
1693
1694 static
1695 int
hammer2_vop_nmkdir(struct vop_nmkdir_args * ap)1696 hammer2_vop_nmkdir(struct vop_nmkdir_args *ap)
1697 {
1698 hammer2_inode_t *dip;
1699 hammer2_inode_t *nip;
1700 struct namecache *ncp;
1701 const char *name;
1702 size_t name_len;
1703 hammer2_tid_t inum;
1704 int error;
1705
1706 dip = VTOI(ap->a_dvp);
1707 if (dip->pmp->ronly || (dip->pmp->flags & HAMMER2_PMPF_EMERG))
1708 return (EROFS);
1709 if (hammer2_vfs_enospace(dip, 0, ap->a_cred) > 1)
1710 return (ENOSPC);
1711
1712 ncp = ap->a_nch->ncp;
1713 name = ncp->nc_name;
1714 name_len = ncp->nc_nlen;
1715
1716 hammer2_trans_init(dip->pmp, 0);
1717
1718 inum = hammer2_trans_newinum(dip->pmp);
1719
1720 /*
1721 * Create the directory as an inode and then create the directory
1722 * entry.
1723 *
1724 * dip must be locked before nip to avoid deadlock.
1725 */
1726 hammer2_inode_lock(dip, 0);
1727 nip = hammer2_inode_create_normal(dip, ap->a_vap, ap->a_cred,
1728 inum, &error);
1729 if (error) {
1730 error = hammer2_error_to_errno(error);
1731 } else {
1732 error = hammer2_dirent_create(dip, name, name_len,
1733 nip->meta.inum, nip->meta.type);
1734 /* returns UNIX error code */
1735 }
1736 if (error) {
1737 if (nip) {
1738 hammer2_inode_unlink_finisher(nip, NULL);
1739 hammer2_inode_unlock(nip);
1740 nip = NULL;
1741 }
1742 *ap->a_vpp = NULL;
1743 } else {
1744 /*
1745 * inode_depend() must occur before the igetv() because
1746 * the igetv() can temporarily release the inode lock.
1747 */
1748 hammer2_inode_depend(dip, nip); /* before igetv */
1749 *ap->a_vpp = hammer2_igetv(nip, &error);
1750 hammer2_inode_unlock(nip);
1751 }
1752
1753 /*
1754 * Update dip's mtime
1755 *
1756 * We can use a shared inode lock and allow the meta.mtime update
1757 * SMP race. hammer2_inode_modify() is MPSAFE w/a shared lock.
1758 */
1759 if (error == 0) {
1760 uint64_t mtime;
1761
1762 /*hammer2_inode_lock(dip, HAMMER2_RESOLVE_SHARED);*/
1763 hammer2_update_time(&mtime, true);
1764 hammer2_inode_modify(dip);
1765 dip->meta.mtime = mtime;
1766 /*hammer2_inode_unlock(dip);*/
1767 }
1768 hammer2_inode_unlock(dip);
1769
1770 hammer2_trans_done(dip->pmp, HAMMER2_TRANS_SIDEQ);
1771
1772 if (error == 0) {
1773 cache_setunresolved(ap->a_nch);
1774 cache_setvp(ap->a_nch, *ap->a_vpp);
1775 hammer2_knote(ap->a_dvp, NOTE_WRITE | NOTE_LINK);
1776 }
1777 return error;
1778 }
1779
1780 int
hammer2_nmkdir(struct m_vnode * dvp,struct m_vnode ** vpp,char * name,int nlen,mode_t mode)1781 hammer2_nmkdir(struct m_vnode *dvp, struct m_vnode **vpp, char *name, int nlen,
1782 mode_t mode)
1783 {
1784 struct namecache nc = {
1785 .nc_name = name,
1786 .nc_nlen = nlen,
1787 };
1788 struct nchandle nch = {
1789 .ncp = &nc,
1790 };
1791 uid_t va_uid = VNOVAL; //getuid();
1792 uid_t va_gid = VNOVAL; //getgid();
1793 struct vattr va = {
1794 .va_type = VDIR,
1795 .va_mode = mode & ~S_IFMT,
1796 .va_uid = va_uid,
1797 .va_gid = va_gid,
1798 };
1799 struct vop_nmkdir_args ap = {
1800 .a_nch = &nch,
1801 .a_dvp = dvp,
1802 .a_vpp = vpp,
1803 .a_vap = &va,
1804 };
1805
1806 return hammer2_vop_nmkdir(&ap);
1807 }
1808
1809 static
1810 int
hammer2_vop_open(struct vop_open_args * ap)1811 hammer2_vop_open(struct vop_open_args *ap)
1812 {
1813 #if 0
1814 return vop_stdopen(ap);
1815 #endif
1816 return (EOPNOTSUPP);
1817 }
1818
1819 /*
1820 * hammer2_vop_advlock { vp, id, op, fl, flags }
1821 */
1822 static
1823 int
hammer2_vop_advlock(struct vop_advlock_args * ap)1824 hammer2_vop_advlock(struct vop_advlock_args *ap)
1825 {
1826 #if 0
1827 hammer2_inode_t *ip = VTOI(ap->a_vp);
1828 hammer2_off_t size;
1829
1830 size = ip->meta.size;
1831 return (lf_advlock(ap, &ip->advlock, size));
1832 #endif
1833 return (EOPNOTSUPP);
1834 }
1835
1836 static
1837 int
hammer2_vop_close(struct vop_close_args * ap)1838 hammer2_vop_close(struct vop_close_args *ap)
1839 {
1840 #if 0
1841 return vop_stdclose(ap);
1842 #endif
1843 return (EOPNOTSUPP);
1844 }
1845
1846 /*
1847 * hammer2_vop_nlink { nch, dvp, vp, cred }
1848 *
1849 * Create a hardlink from (vp) to {dvp, nch}.
1850 */
1851 static
1852 int
hammer2_vop_nlink(struct vop_nlink_args * ap)1853 hammer2_vop_nlink(struct vop_nlink_args *ap)
1854 {
1855 hammer2_inode_t *tdip; /* target directory to create link in */
1856 hammer2_inode_t *ip; /* inode we are hardlinking to */
1857 struct namecache *ncp;
1858 const char *name;
1859 size_t name_len;
1860 int error;
1861 uint64_t cmtime;
1862
1863 /* We know it's the same in makefs */
1864 /*
1865 if (ap->a_dvp->v_mount != ap->a_vp->v_mount)
1866 return(EXDEV);
1867 */
1868
1869 tdip = VTOI(ap->a_dvp);
1870 if (tdip->pmp->ronly || (tdip->pmp->flags & HAMMER2_PMPF_EMERG))
1871 return (EROFS);
1872 if (hammer2_vfs_enospace(tdip, 0, ap->a_cred) > 1)
1873 return (ENOSPC);
1874
1875 ncp = ap->a_nch->ncp;
1876 name = ncp->nc_name;
1877 name_len = ncp->nc_nlen;
1878
1879 /*
1880 * ip represents the file being hardlinked. The file could be a
1881 * normal file or a hardlink target if it has already been hardlinked.
1882 * (with the new semantics, it will almost always be a hardlink
1883 * target).
1884 *
1885 * Bump nlinks and potentially also create or move the hardlink
1886 * target in the parent directory common to (ip) and (tdip). The
1887 * consolidation code can modify ip->cluster. The returned cluster
1888 * is locked.
1889 */
1890 ip = VTOI(ap->a_vp);
1891 KASSERT(ip->pmp, ("ip->pmp is NULL %p %p", ip, ip->pmp));
1892 hammer2_trans_init(ip->pmp, 0);
1893
1894 /*
1895 * Target should be an indexed inode or there's no way we will ever
1896 * be able to find it!
1897 */
1898 KKASSERT((ip->meta.name_key & HAMMER2_DIRHASH_VISIBLE) == 0);
1899
1900 hammer2_inode_lock4(tdip, ip, NULL, NULL);
1901
1902 hammer2_update_time(&cmtime, true);
1903
1904 /*
1905 * Create the directory entry and bump nlinks.
1906 * Also update ip's ctime.
1907 */
1908 error = hammer2_dirent_create(tdip, name, name_len,
1909 ip->meta.inum, ip->meta.type);
1910 hammer2_inode_modify(ip);
1911 ++ip->meta.nlinks;
1912 ip->meta.ctime = cmtime;
1913 if (error == 0) {
1914 /*
1915 * Update dip's [cm]time
1916 */
1917 hammer2_inode_modify(tdip);
1918 tdip->meta.mtime = cmtime;
1919 tdip->meta.ctime = cmtime;
1920
1921 cache_setunresolved(ap->a_nch);
1922 cache_setvp(ap->a_nch, ap->a_vp);
1923 }
1924 hammer2_inode_unlock(ip);
1925 hammer2_inode_unlock(tdip);
1926
1927 hammer2_trans_done(ip->pmp, HAMMER2_TRANS_SIDEQ);
1928 hammer2_knote(ap->a_vp, NOTE_LINK);
1929 hammer2_knote(ap->a_dvp, NOTE_WRITE);
1930
1931 return error;
1932 }
1933
1934 int
hammer2_nlink(struct m_vnode * dvp,struct m_vnode * vp,char * name,int nlen)1935 hammer2_nlink(struct m_vnode *dvp, struct m_vnode *vp, char *name, int nlen)
1936 {
1937 struct namecache nc = {
1938 .nc_name = name,
1939 .nc_nlen = nlen,
1940 };
1941 struct nchandle nch = {
1942 .ncp = &nc,
1943 };
1944 struct vop_nlink_args ap = {
1945 .a_nch = &nch,
1946 .a_dvp = dvp,
1947 .a_vp = vp,
1948 };
1949
1950 return hammer2_vop_nlink(&ap);
1951 }
1952
1953 /*
1954 * hammer2_vop_ncreate { nch, dvp, vpp, cred, vap }
1955 *
1956 * The operating system has already ensured that the directory entry
1957 * does not exist and done all appropriate namespace locking.
1958 */
1959 static
1960 int
hammer2_vop_ncreate(struct vop_ncreate_args * ap)1961 hammer2_vop_ncreate(struct vop_ncreate_args *ap)
1962 {
1963 hammer2_inode_t *dip;
1964 hammer2_inode_t *nip;
1965 struct namecache *ncp;
1966 const char *name;
1967 size_t name_len;
1968 hammer2_tid_t inum;
1969 int error;
1970
1971 dip = VTOI(ap->a_dvp);
1972 if (dip->pmp->ronly || (dip->pmp->flags & HAMMER2_PMPF_EMERG))
1973 return (EROFS);
1974 if (hammer2_vfs_enospace(dip, 0, ap->a_cred) > 1)
1975 return (ENOSPC);
1976
1977 ncp = ap->a_nch->ncp;
1978 name = ncp->nc_name;
1979 name_len = ncp->nc_nlen;
1980 hammer2_trans_init(dip->pmp, 0);
1981
1982 inum = hammer2_trans_newinum(dip->pmp);
1983
1984 /*
1985 * Create the regular file as an inode and then create the directory
1986 * entry.
1987 *
1988 * dip must be locked before nip to avoid deadlock.
1989 */
1990 hammer2_inode_lock(dip, 0);
1991 nip = hammer2_inode_create_normal(dip, ap->a_vap, ap->a_cred,
1992 inum, &error);
1993 if (error) {
1994 error = hammer2_error_to_errno(error);
1995 } else {
1996 error = hammer2_dirent_create(dip, name, name_len,
1997 nip->meta.inum, nip->meta.type);
1998 }
1999 if (error) {
2000 if (nip) {
2001 hammer2_inode_unlink_finisher(nip, NULL);
2002 hammer2_inode_unlock(nip);
2003 nip = NULL;
2004 }
2005 *ap->a_vpp = NULL;
2006 } else {
2007 hammer2_inode_depend(dip, nip); /* before igetv */
2008 *ap->a_vpp = hammer2_igetv(nip, &error);
2009 hammer2_inode_unlock(nip);
2010 }
2011
2012 /*
2013 * Update dip's mtime
2014 */
2015 if (error == 0) {
2016 uint64_t mtime;
2017
2018 /*hammer2_inode_lock(dip, HAMMER2_RESOLVE_SHARED);*/
2019 hammer2_update_time(&mtime, true);
2020 hammer2_inode_modify(dip);
2021 dip->meta.mtime = mtime;
2022 /*hammer2_inode_unlock(dip);*/
2023 }
2024 hammer2_inode_unlock(dip);
2025
2026 hammer2_trans_done(dip->pmp, HAMMER2_TRANS_SIDEQ);
2027
2028 if (error == 0) {
2029 cache_setunresolved(ap->a_nch);
2030 cache_setvp(ap->a_nch, *ap->a_vpp);
2031 hammer2_knote(ap->a_dvp, NOTE_WRITE);
2032 }
2033 return error;
2034 }
2035
2036 int
hammer2_ncreate(struct m_vnode * dvp,struct m_vnode ** vpp,char * name,int nlen,mode_t mode)2037 hammer2_ncreate(struct m_vnode *dvp, struct m_vnode **vpp, char *name, int nlen,
2038 mode_t mode)
2039 {
2040 struct namecache nc = {
2041 .nc_name = name,
2042 .nc_nlen = nlen,
2043 };
2044 struct nchandle nch = {
2045 .ncp = &nc,
2046 };
2047 uid_t va_uid = VNOVAL; //getuid();
2048 uid_t va_gid = VNOVAL; //getgid();
2049 struct vattr va = {
2050 .va_type = VREG,
2051 .va_mode = mode & ~S_IFMT,
2052 .va_uid = va_uid,
2053 .va_gid = va_gid,
2054 };
2055 struct vop_ncreate_args ap = {
2056 .a_nch = &nch,
2057 .a_dvp = dvp,
2058 .a_vpp = vpp,
2059 .a_vap = &va,
2060 };
2061
2062 return hammer2_vop_ncreate(&ap);
2063 }
2064
2065 /*
2066 * Make a device node (typically a fifo)
2067 */
2068 static
2069 int
hammer2_vop_nmknod(struct vop_nmknod_args * ap)2070 hammer2_vop_nmknod(struct vop_nmknod_args *ap)
2071 {
2072 hammer2_inode_t *dip;
2073 hammer2_inode_t *nip;
2074 struct namecache *ncp;
2075 const char *name;
2076 size_t name_len;
2077 hammer2_tid_t inum;
2078 int error;
2079
2080 dip = VTOI(ap->a_dvp);
2081 if (dip->pmp->ronly || (dip->pmp->flags & HAMMER2_PMPF_EMERG))
2082 return (EROFS);
2083 if (hammer2_vfs_enospace(dip, 0, ap->a_cred) > 1)
2084 return (ENOSPC);
2085
2086 ncp = ap->a_nch->ncp;
2087 name = ncp->nc_name;
2088 name_len = ncp->nc_nlen;
2089 hammer2_trans_init(dip->pmp, 0);
2090
2091 /*
2092 * Create the device inode and then create the directory entry.
2093 *
2094 * dip must be locked before nip to avoid deadlock.
2095 */
2096 inum = hammer2_trans_newinum(dip->pmp);
2097
2098 hammer2_inode_lock(dip, 0);
2099 nip = hammer2_inode_create_normal(dip, ap->a_vap, ap->a_cred,
2100 inum, &error);
2101 if (error) {
2102 error = hammer2_error_to_errno(error);
2103 } else {
2104 error = hammer2_dirent_create(dip, name, name_len,
2105 nip->meta.inum, nip->meta.type);
2106 }
2107 if (error) {
2108 if (nip) {
2109 hammer2_inode_unlink_finisher(nip, NULL);
2110 hammer2_inode_unlock(nip);
2111 nip = NULL;
2112 }
2113 *ap->a_vpp = NULL;
2114 } else {
2115 hammer2_inode_depend(dip, nip); /* before igetv */
2116 *ap->a_vpp = hammer2_igetv(nip, &error);
2117 hammer2_inode_unlock(nip);
2118 }
2119
2120 /*
2121 * Update dip's mtime
2122 */
2123 if (error == 0) {
2124 uint64_t mtime;
2125
2126 /*hammer2_inode_lock(dip, HAMMER2_RESOLVE_SHARED);*/
2127 hammer2_update_time(&mtime, true);
2128 hammer2_inode_modify(dip);
2129 dip->meta.mtime = mtime;
2130 /*hammer2_inode_unlock(dip);*/
2131 }
2132 hammer2_inode_unlock(dip);
2133
2134 hammer2_trans_done(dip->pmp, HAMMER2_TRANS_SIDEQ);
2135
2136 if (error == 0) {
2137 cache_setunresolved(ap->a_nch);
2138 cache_setvp(ap->a_nch, *ap->a_vpp);
2139 hammer2_knote(ap->a_dvp, NOTE_WRITE);
2140 }
2141 return error;
2142 }
2143
2144 int
hammer2_nmknod(struct m_vnode * dvp,struct m_vnode ** vpp,char * name,int nlen,int type,mode_t mode)2145 hammer2_nmknod(struct m_vnode *dvp, struct m_vnode **vpp, char *name, int nlen,
2146 int type, mode_t mode)
2147 {
2148 struct namecache nc = {
2149 .nc_name = name,
2150 .nc_nlen = nlen,
2151 };
2152 struct nchandle nch = {
2153 .ncp = &nc,
2154 };
2155 uid_t va_uid = VNOVAL; //getuid();
2156 uid_t va_gid = VNOVAL; //getgid();
2157 struct vattr va = {
2158 .va_type = type,
2159 .va_mode = mode & ~S_IFMT,
2160 .va_uid = va_uid,
2161 .va_gid = va_gid,
2162 };
2163 struct vop_nmknod_args ap = {
2164 .a_nch = &nch,
2165 .a_dvp = dvp,
2166 .a_vpp = vpp,
2167 .a_vap = &va,
2168 };
2169
2170 return hammer2_vop_nmknod(&ap);
2171 }
2172
2173 /*
2174 * hammer2_vop_nsymlink { nch, dvp, vpp, cred, vap, target }
2175 */
2176 static
2177 int
hammer2_vop_nsymlink(struct vop_nsymlink_args * ap)2178 hammer2_vop_nsymlink(struct vop_nsymlink_args *ap)
2179 {
2180 hammer2_inode_t *dip;
2181 hammer2_inode_t *nip;
2182 struct namecache *ncp;
2183 const char *name;
2184 size_t name_len;
2185 hammer2_tid_t inum;
2186 int error;
2187
2188 dip = VTOI(ap->a_dvp);
2189 if (dip->pmp->ronly || (dip->pmp->flags & HAMMER2_PMPF_EMERG))
2190 return (EROFS);
2191 if (hammer2_vfs_enospace(dip, 0, ap->a_cred) > 1)
2192 return (ENOSPC);
2193
2194 ncp = ap->a_nch->ncp;
2195 name = ncp->nc_name;
2196 name_len = ncp->nc_nlen;
2197 hammer2_trans_init(dip->pmp, 0);
2198
2199 ap->a_vap->va_type = VLNK; /* enforce type */
2200
2201 /*
2202 * Create the softlink as an inode and then create the directory
2203 * entry.
2204 *
2205 * dip must be locked before nip to avoid deadlock.
2206 */
2207 inum = hammer2_trans_newinum(dip->pmp);
2208
2209 hammer2_inode_lock(dip, 0);
2210 nip = hammer2_inode_create_normal(dip, ap->a_vap, ap->a_cred,
2211 inum, &error);
2212 if (error) {
2213 error = hammer2_error_to_errno(error);
2214 } else {
2215 error = hammer2_dirent_create(dip, name, name_len,
2216 nip->meta.inum, nip->meta.type);
2217 }
2218 if (error) {
2219 if (nip) {
2220 hammer2_inode_unlink_finisher(nip, NULL);
2221 hammer2_inode_unlock(nip);
2222 nip = NULL;
2223 }
2224 *ap->a_vpp = NULL;
2225 hammer2_inode_unlock(dip);
2226 hammer2_trans_done(dip->pmp, HAMMER2_TRANS_SIDEQ);
2227 return error;
2228 }
2229 hammer2_inode_depend(dip, nip); /* before igetv */
2230 *ap->a_vpp = hammer2_igetv(nip, &error);
2231
2232 /*
2233 * Build the softlink (~like file data) and finalize the namecache.
2234 */
2235 if (error == 0) {
2236 size_t bytes;
2237 struct uio auio;
2238 struct iovec aiov;
2239
2240 bytes = strlen(ap->a_target);
2241
2242 hammer2_inode_unlock(nip);
2243 bzero(&auio, sizeof(auio));
2244 bzero(&aiov, sizeof(aiov));
2245 auio.uio_iov = &aiov;
2246 auio.uio_segflg = UIO_SYSSPACE;
2247 auio.uio_rw = UIO_WRITE;
2248 auio.uio_resid = bytes;
2249 auio.uio_iovcnt = 1;
2250 auio.uio_td = curthread;
2251 aiov.iov_base = ap->a_target;
2252 aiov.iov_len = bytes;
2253 error = hammer2_write_file(nip, &auio, IO_APPEND, 0);
2254 /* XXX handle error */
2255 error = 0;
2256 } else {
2257 hammer2_inode_unlock(nip);
2258 }
2259
2260 /*
2261 * Update dip's mtime
2262 */
2263 if (error == 0) {
2264 uint64_t mtime;
2265
2266 /*hammer2_inode_lock(dip, HAMMER2_RESOLVE_SHARED);*/
2267 hammer2_update_time(&mtime, true);
2268 hammer2_inode_modify(dip);
2269 dip->meta.mtime = mtime;
2270 /*hammer2_inode_unlock(dip);*/
2271 }
2272 hammer2_inode_unlock(dip);
2273
2274 hammer2_trans_done(dip->pmp, HAMMER2_TRANS_SIDEQ);
2275
2276 /*
2277 * Finalize namecache
2278 */
2279 if (error == 0) {
2280 cache_setunresolved(ap->a_nch);
2281 cache_setvp(ap->a_nch, *ap->a_vpp);
2282 hammer2_knote(ap->a_dvp, NOTE_WRITE);
2283 }
2284 return error;
2285 }
2286
2287 int
hammer2_nsymlink(struct m_vnode * dvp,struct m_vnode ** vpp,char * name,int nlen,char * target,mode_t mode)2288 hammer2_nsymlink(struct m_vnode *dvp, struct m_vnode **vpp, char *name, int nlen,
2289 char *target, mode_t mode)
2290 {
2291 struct namecache nc = {
2292 .nc_name = name,
2293 .nc_nlen = nlen,
2294 };
2295 struct nchandle nch = {
2296 .ncp = &nc,
2297 };
2298 uid_t va_uid = VNOVAL; //getuid();
2299 uid_t va_gid = VNOVAL; //getgid();
2300 struct vattr va = {
2301 .va_type = VDIR,
2302 .va_mode = mode & ~S_IFMT,
2303 .va_uid = va_uid,
2304 .va_gid = va_gid,
2305 };
2306 struct vop_nsymlink_args ap = {
2307 .a_nch = &nch,
2308 .a_dvp = dvp,
2309 .a_vpp = vpp,
2310 .a_vap = &va,
2311 .a_target = target,
2312 };
2313
2314 return hammer2_vop_nsymlink(&ap);
2315 }
2316
2317 /*
2318 * hammer2_vop_nremove { nch, dvp, cred }
2319 */
2320 static
2321 int
hammer2_vop_nremove(struct vop_nremove_args * ap)2322 hammer2_vop_nremove(struct vop_nremove_args *ap)
2323 {
2324 #if 0
2325 hammer2_xop_unlink_t *xop;
2326 hammer2_inode_t *dip;
2327 hammer2_inode_t *ip;
2328 struct m_vnode *vprecycle;
2329 struct namecache *ncp;
2330 int error;
2331
2332 dip = VTOI(ap->a_dvp);
2333 if (dip->pmp->ronly)
2334 return (EROFS);
2335 #if 0
2336 /* allow removals, except user to also bulkfree */
2337 if (hammer2_vfs_enospace(dip, 0, ap->a_cred) > 1)
2338 return (ENOSPC);
2339 #endif
2340
2341 ncp = ap->a_nch->ncp;
2342
2343 if (hammer2_debug_inode && dip->meta.inum == hammer2_debug_inode) {
2344 kprintf("hammer2: attempt to delete inside debug inode: %s\n",
2345 ncp->nc_name);
2346 while (hammer2_debug_inode &&
2347 dip->meta.inum == hammer2_debug_inode) {
2348 tsleep(&hammer2_debug_inode, 0, "h2debug", hz*5);
2349 }
2350 }
2351
2352 hammer2_trans_init(dip->pmp, 0);
2353 hammer2_inode_lock(dip, 0);
2354
2355 /*
2356 * The unlink XOP unlinks the path from the directory and
2357 * locates and returns the cluster associated with the real inode.
2358 * We have to handle nlinks here on the frontend.
2359 */
2360 xop = hammer2_xop_alloc(dip, HAMMER2_XOP_MODIFYING);
2361 hammer2_xop_setname(&xop->head, ncp->nc_name, ncp->nc_nlen);
2362
2363 xop->isdir = 0;
2364 xop->dopermanent = 0;
2365 hammer2_xop_start(&xop->head, &hammer2_unlink_desc);
2366
2367 /*
2368 * Collect the real inode and adjust nlinks, destroy the real
2369 * inode if nlinks transitions to 0 and it was the real inode
2370 * (else it has already been removed).
2371 */
2372 error = hammer2_xop_collect(&xop->head, 0);
2373 error = hammer2_error_to_errno(error);
2374 vprecycle = NULL;
2375
2376 if (error == 0) {
2377 ip = hammer2_inode_get(dip->pmp, &xop->head, -1, -1);
2378 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
2379 if (ip) {
2380 if (hammer2_debug_inode &&
2381 ip->meta.inum == hammer2_debug_inode) {
2382 kprintf("hammer2: attempt to delete debug "
2383 "inode!\n");
2384 while (hammer2_debug_inode &&
2385 ip->meta.inum == hammer2_debug_inode) {
2386 tsleep(&hammer2_debug_inode, 0,
2387 "h2debug", hz*5);
2388 }
2389 }
2390 hammer2_inode_unlink_finisher(ip, &vprecycle);
2391 hammer2_inode_depend(dip, ip); /* after modified */
2392 hammer2_inode_unlock(ip);
2393 }
2394 } else {
2395 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
2396 }
2397
2398 /*
2399 * Update dip's mtime
2400 */
2401 if (error == 0) {
2402 uint64_t mtime;
2403
2404 /*hammer2_inode_lock(dip, HAMMER2_RESOLVE_SHARED);*/
2405 hammer2_update_time(&mtime);
2406 hammer2_inode_modify(dip);
2407 dip->meta.mtime = mtime;
2408 /*hammer2_inode_unlock(dip);*/
2409 }
2410 hammer2_inode_unlock(dip);
2411
2412 hammer2_trans_done(dip->pmp, HAMMER2_TRANS_SIDEQ);
2413 if (error == 0) {
2414 cache_unlink(ap->a_nch);
2415 hammer2_knote(ap->a_dvp, NOTE_WRITE);
2416 }
2417 if (vprecycle)
2418 hammer2_inode_vprecycle(vprecycle);
2419
2420 return (error);
2421 #endif
2422 return (EOPNOTSUPP);
2423 }
2424
2425 /*
2426 * hammer2_vop_nrmdir { nch, dvp, cred }
2427 */
2428 static
2429 int
hammer2_vop_nrmdir(struct vop_nrmdir_args * ap)2430 hammer2_vop_nrmdir(struct vop_nrmdir_args *ap)
2431 {
2432 #if 0
2433 hammer2_xop_unlink_t *xop;
2434 hammer2_inode_t *dip;
2435 hammer2_inode_t *ip;
2436 struct namecache *ncp;
2437 struct m_vnode *vprecycle;
2438 int error;
2439
2440 dip = VTOI(ap->a_dvp);
2441 if (dip->pmp->ronly)
2442 return (EROFS);
2443 #if 0
2444 /* allow removals, except user to also bulkfree */
2445 if (hammer2_vfs_enospace(dip, 0, ap->a_cred) > 1)
2446 return (ENOSPC);
2447 #endif
2448
2449 hammer2_trans_init(dip->pmp, 0);
2450 hammer2_inode_lock(dip, 0);
2451
2452 xop = hammer2_xop_alloc(dip, HAMMER2_XOP_MODIFYING);
2453
2454 ncp = ap->a_nch->ncp;
2455 hammer2_xop_setname(&xop->head, ncp->nc_name, ncp->nc_nlen);
2456 xop->isdir = 1;
2457 xop->dopermanent = 0;
2458 hammer2_xop_start(&xop->head, &hammer2_unlink_desc);
2459
2460 /*
2461 * Collect the real inode and adjust nlinks, destroy the real
2462 * inode if nlinks transitions to 0 and it was the real inode
2463 * (else it has already been removed).
2464 */
2465 error = hammer2_xop_collect(&xop->head, 0);
2466 error = hammer2_error_to_errno(error);
2467 vprecycle = NULL;
2468
2469 if (error == 0) {
2470 ip = hammer2_inode_get(dip->pmp, &xop->head, -1, -1);
2471 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
2472 if (ip) {
2473 hammer2_inode_unlink_finisher(ip, &vprecycle);
2474 hammer2_inode_depend(dip, ip); /* after modified */
2475 hammer2_inode_unlock(ip);
2476 }
2477 } else {
2478 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
2479 }
2480
2481 /*
2482 * Update dip's mtime
2483 */
2484 if (error == 0) {
2485 uint64_t mtime;
2486
2487 /*hammer2_inode_lock(dip, HAMMER2_RESOLVE_SHARED);*/
2488 hammer2_update_time(&mtime);
2489 hammer2_inode_modify(dip);
2490 dip->meta.mtime = mtime;
2491 /*hammer2_inode_unlock(dip);*/
2492 }
2493 hammer2_inode_unlock(dip);
2494
2495 hammer2_trans_done(dip->pmp, HAMMER2_TRANS_SIDEQ);
2496 if (error == 0) {
2497 cache_unlink(ap->a_nch);
2498 hammer2_knote(ap->a_dvp, NOTE_WRITE | NOTE_LINK);
2499 }
2500 if (vprecycle)
2501 hammer2_inode_vprecycle(vprecycle);
2502 return (error);
2503 #endif
2504 return (EOPNOTSUPP);
2505 }
2506
2507 /*
2508 * hammer2_vop_nrename { fnch, tnch, fdvp, tdvp, cred }
2509 */
2510 static
2511 int
hammer2_vop_nrename(struct vop_nrename_args * ap)2512 hammer2_vop_nrename(struct vop_nrename_args *ap)
2513 {
2514 #if 0
2515 struct namecache *fncp;
2516 struct namecache *tncp;
2517 hammer2_inode_t *fdip; /* source directory */
2518 hammer2_inode_t *tdip; /* target directory */
2519 hammer2_inode_t *ip; /* file being renamed */
2520 hammer2_inode_t *tip; /* replaced target during rename or NULL */
2521 struct m_vnode *vprecycle;
2522 const char *fname;
2523 size_t fname_len;
2524 const char *tname;
2525 size_t tname_len;
2526 int error;
2527 int update_tdip;
2528 int update_fdip;
2529 hammer2_key_t tlhc;
2530
2531 if (ap->a_fdvp->v_mount != ap->a_tdvp->v_mount)
2532 return(EXDEV);
2533 if (ap->a_fdvp->v_mount != ap->a_fnch->ncp->nc_vp->v_mount)
2534 return(EXDEV);
2535
2536 fdip = VTOI(ap->a_fdvp); /* source directory */
2537 tdip = VTOI(ap->a_tdvp); /* target directory */
2538
2539 if (fdip->pmp->ronly || (fdip->pmp->flags & HAMMER2_PMPF_EMERG))
2540 return (EROFS);
2541 if (hammer2_vfs_enospace(fdip, 0, ap->a_cred) > 1)
2542 return (ENOSPC);
2543
2544 fncp = ap->a_fnch->ncp; /* entry name in source */
2545 fname = fncp->nc_name;
2546 fname_len = fncp->nc_nlen;
2547
2548 tncp = ap->a_tnch->ncp; /* entry name in target */
2549 tname = tncp->nc_name;
2550 tname_len = tncp->nc_nlen;
2551
2552 hammer2_trans_init(tdip->pmp, 0);
2553
2554 update_tdip = 0;
2555 update_fdip = 0;
2556
2557 ip = VTOI(fncp->nc_vp);
2558 hammer2_inode_ref(ip); /* extra ref */
2559
2560 /*
2561 * Lookup the target name to determine if a directory entry
2562 * is being overwritten. We only hold related inode locks
2563 * temporarily, the operating system is expected to protect
2564 * against rename races.
2565 */
2566 tip = tncp->nc_vp ? VTOI(tncp->nc_vp) : NULL;
2567 if (tip)
2568 hammer2_inode_ref(tip); /* extra ref */
2569
2570 /*
2571 * For now try to avoid deadlocks with a simple pointer address
2572 * test. (tip) can be NULL.
2573 */
2574 error = 0;
2575 {
2576 hammer2_inode_t *ip1 = fdip;
2577 hammer2_inode_t *ip2 = tdip;
2578 hammer2_inode_t *ip3 = ip;
2579 hammer2_inode_t *ip4 = tip; /* may be NULL */
2580
2581 if (fdip > tdip) {
2582 ip1 = tdip;
2583 ip2 = fdip;
2584 }
2585 if (tip && ip > tip) {
2586 ip3 = tip;
2587 ip4 = ip;
2588 }
2589 hammer2_inode_lock4(ip1, ip2, ip3, ip4);
2590 }
2591
2592 /*
2593 * Resolve the collision space for (tdip, tname, tname_len)
2594 *
2595 * tdip must be held exclusively locked to prevent races since
2596 * multiple filenames can end up in the same collision space.
2597 */
2598 {
2599 hammer2_xop_scanlhc_t *sxop;
2600 hammer2_key_t lhcbase;
2601
2602 tlhc = hammer2_dirhash(tname, tname_len);
2603 lhcbase = tlhc;
2604 sxop = hammer2_xop_alloc(tdip, HAMMER2_XOP_MODIFYING);
2605 sxop->lhc = tlhc;
2606 hammer2_xop_start(&sxop->head, &hammer2_scanlhc_desc);
2607 while ((error = hammer2_xop_collect(&sxop->head, 0)) == 0) {
2608 if (tlhc != sxop->head.cluster.focus->bref.key)
2609 break;
2610 ++tlhc;
2611 }
2612 error = hammer2_error_to_errno(error);
2613 hammer2_xop_retire(&sxop->head, HAMMER2_XOPMASK_VOP);
2614
2615 if (error) {
2616 if (error != ENOENT)
2617 goto done2;
2618 ++tlhc;
2619 error = 0;
2620 }
2621 if ((lhcbase ^ tlhc) & ~HAMMER2_DIRHASH_LOMASK) {
2622 error = ENOSPC;
2623 goto done2;
2624 }
2625 }
2626
2627 /*
2628 * Ready to go, issue the rename to the backend. Note that meta-data
2629 * updates to the related inodes occur separately from the rename
2630 * operation.
2631 *
2632 * NOTE: While it is not necessary to update ip->meta.name*, doing
2633 * so aids catastrophic recovery and debugging.
2634 */
2635 if (error == 0) {
2636 hammer2_xop_nrename_t *xop4;
2637
2638 xop4 = hammer2_xop_alloc(fdip, HAMMER2_XOP_MODIFYING);
2639 xop4->lhc = tlhc;
2640 xop4->ip_key = ip->meta.name_key;
2641 hammer2_xop_setip2(&xop4->head, ip);
2642 hammer2_xop_setip3(&xop4->head, tdip);
2643 if (tip && tip->meta.type == HAMMER2_OBJTYPE_DIRECTORY)
2644 hammer2_xop_setip4(&xop4->head, tip);
2645 hammer2_xop_setname(&xop4->head, fname, fname_len);
2646 hammer2_xop_setname2(&xop4->head, tname, tname_len);
2647 hammer2_xop_start(&xop4->head, &hammer2_nrename_desc);
2648
2649 error = hammer2_xop_collect(&xop4->head, 0);
2650 error = hammer2_error_to_errno(error);
2651 hammer2_xop_retire(&xop4->head, HAMMER2_XOPMASK_VOP);
2652
2653 if (error == ENOENT)
2654 error = 0;
2655
2656 /*
2657 * Update inode meta-data.
2658 *
2659 * WARNING! The in-memory inode (ip) structure does not
2660 * maintain a copy of the inode's filename buffer.
2661 */
2662 if (error == 0 &&
2663 (ip->meta.name_key & HAMMER2_DIRHASH_VISIBLE)) {
2664 hammer2_inode_modify(ip);
2665 ip->meta.name_len = tname_len;
2666 ip->meta.name_key = tlhc;
2667 }
2668 if (error == 0) {
2669 hammer2_inode_modify(ip);
2670 ip->meta.iparent = tdip->meta.inum;
2671 }
2672 update_fdip = 1;
2673 update_tdip = 1;
2674 }
2675
2676 done2:
2677 /*
2678 * If no error, the backend has replaced the target directory entry.
2679 * We must adjust nlinks on the original replace target if it exists.
2680 */
2681 vprecycle = NULL;
2682 if (error == 0 && tip) {
2683 hammer2_inode_unlink_finisher(tip, &vprecycle);
2684 }
2685
2686 /*
2687 * Update directory mtimes to represent the something changed.
2688 */
2689 if (update_fdip || update_tdip) {
2690 uint64_t mtime;
2691
2692 hammer2_update_time(&mtime);
2693 if (update_fdip) {
2694 hammer2_inode_modify(fdip);
2695 fdip->meta.mtime = mtime;
2696 }
2697 if (update_tdip) {
2698 hammer2_inode_modify(tdip);
2699 tdip->meta.mtime = mtime;
2700 }
2701 }
2702 if (tip) {
2703 hammer2_inode_unlock(tip);
2704 hammer2_inode_drop(tip);
2705 }
2706 hammer2_inode_unlock(ip);
2707 hammer2_inode_unlock(tdip);
2708 hammer2_inode_unlock(fdip);
2709 hammer2_inode_drop(ip);
2710 hammer2_trans_done(tdip->pmp, HAMMER2_TRANS_SIDEQ);
2711
2712 /*
2713 * Issue the namecache update after unlocking all the internal
2714 * hammer2 structures, otherwise we might deadlock.
2715 *
2716 * WARNING! The target namespace must be updated atomically,
2717 * and we depend on cache_rename() to handle that for
2718 * us. Do not do a separate cache_unlink() because
2719 * that leaves a small window of opportunity for other
2720 * threads to allocate the target namespace before we
2721 * manage to complete our rename.
2722 *
2723 * WARNING! cache_rename() (and cache_unlink()) will properly
2724 * set VREF_FINALIZE on any attached vnode. Do not
2725 * call cache_setunresolved() manually before-hand as
2726 * this will prevent the flag from being set later via
2727 * cache_rename(). If VREF_FINALIZE is not properly set
2728 * and the inode is no longer in the topology, related
2729 * chains can remain dirty indefinitely.
2730 */
2731 if (error == 0 && tip) {
2732 /*cache_unlink(ap->a_tnch); see above */
2733 /*cache_setunresolved(ap->a_tnch); see above */
2734 }
2735 if (error == 0) {
2736 cache_rename(ap->a_fnch, ap->a_tnch);
2737 hammer2_knote(ap->a_fdvp, NOTE_WRITE);
2738 hammer2_knote(ap->a_tdvp, NOTE_WRITE);
2739 hammer2_knote(fncp->nc_vp, NOTE_RENAME);
2740 }
2741 if (vprecycle)
2742 hammer2_inode_vprecycle(vprecycle);
2743
2744 return (error);
2745 #endif
2746 return (EOPNOTSUPP);
2747 }
2748
2749 /*
2750 * hammer2_vop_ioctl { vp, command, data, fflag, cred }
2751 */
2752 static
2753 int
hammer2_vop_ioctl(struct vop_ioctl_args * ap)2754 hammer2_vop_ioctl(struct vop_ioctl_args *ap)
2755 {
2756 #if 0
2757 hammer2_inode_t *ip;
2758 int error;
2759
2760 ip = VTOI(ap->a_vp);
2761
2762 error = hammer2_ioctl(ip, ap->a_command, (void *)ap->a_data,
2763 ap->a_fflag, ap->a_cred);
2764 return (error);
2765 #endif
2766 return (EOPNOTSUPP);
2767 }
2768
2769 static
2770 int
hammer2_vop_mountctl(struct vop_mountctl_args * ap)2771 hammer2_vop_mountctl(struct vop_mountctl_args *ap)
2772 {
2773 #if 0
2774 struct mount *mp;
2775 hammer2_pfs_t *pmp;
2776 int rc;
2777
2778 switch (ap->a_op) {
2779 case (MOUNTCTL_SET_EXPORT):
2780 mp = ap->a_head.a_ops->head.vv_mount;
2781 pmp = MPTOPMP(mp);
2782
2783 if (ap->a_ctllen != sizeof(struct export_args))
2784 rc = (EINVAL);
2785 else
2786 rc = vfs_export(mp, &pmp->export,
2787 (const struct export_args *)ap->a_ctl);
2788 break;
2789 default:
2790 rc = vop_stdmountctl(ap);
2791 break;
2792 }
2793 return (rc);
2794 #endif
2795 return (EOPNOTSUPP);
2796 }
2797
2798 /*
2799 * KQFILTER
2800 */
2801 /*
2802 static void filt_hammer2detach(struct knote *kn);
2803 static int filt_hammer2read(struct knote *kn, long hint);
2804 static int filt_hammer2write(struct knote *kn, long hint);
2805 static int filt_hammer2vnode(struct knote *kn, long hint);
2806
2807 static struct filterops hammer2read_filtops =
2808 { FILTEROP_ISFD | FILTEROP_MPSAFE,
2809 NULL, filt_hammer2detach, filt_hammer2read };
2810 static struct filterops hammer2write_filtops =
2811 { FILTEROP_ISFD | FILTEROP_MPSAFE,
2812 NULL, filt_hammer2detach, filt_hammer2write };
2813 static struct filterops hammer2vnode_filtops =
2814 { FILTEROP_ISFD | FILTEROP_MPSAFE,
2815 NULL, filt_hammer2detach, filt_hammer2vnode };
2816 */
2817
2818 static
2819 int
hammer2_vop_kqfilter(struct vop_kqfilter_args * ap)2820 hammer2_vop_kqfilter(struct vop_kqfilter_args *ap)
2821 {
2822 #if 0
2823 struct m_vnode *vp = ap->a_vp;
2824 struct knote *kn = ap->a_kn;
2825
2826 switch (kn->kn_filter) {
2827 case EVFILT_READ:
2828 kn->kn_fop = &hammer2read_filtops;
2829 break;
2830 case EVFILT_WRITE:
2831 kn->kn_fop = &hammer2write_filtops;
2832 break;
2833 case EVFILT_VNODE:
2834 kn->kn_fop = &hammer2vnode_filtops;
2835 break;
2836 default:
2837 return (EOPNOTSUPP);
2838 }
2839
2840 kn->kn_hook = (caddr_t)vp;
2841
2842 knote_insert(&vp->v_pollinfo.vpi_kqinfo.ki_note, kn);
2843
2844 return(0);
2845 #endif
2846 return (EOPNOTSUPP);
2847 }
2848
2849 #if 0
2850 static void
2851 filt_hammer2detach(struct knote *kn)
2852 {
2853 struct m_vnode *vp = (void *)kn->kn_hook;
2854
2855 knote_remove(&vp->v_pollinfo.vpi_kqinfo.ki_note, kn);
2856 }
2857
2858 static int
2859 filt_hammer2read(struct knote *kn, long hint)
2860 {
2861 struct m_vnode *vp = (void *)kn->kn_hook;
2862 hammer2_inode_t *ip = VTOI(vp);
2863 off_t off;
2864
2865 if (hint == NOTE_REVOKE) {
2866 kn->kn_flags |= (EV_EOF | EV_NODATA | EV_ONESHOT);
2867 return(1);
2868 }
2869 off = ip->meta.size - kn->kn_fp->f_offset;
2870 kn->kn_data = (off < INTPTR_MAX) ? off : INTPTR_MAX;
2871 if (kn->kn_sfflags & NOTE_OLDAPI)
2872 return(1);
2873 return (kn->kn_data != 0);
2874 }
2875
2876
2877 static int
2878 filt_hammer2write(struct knote *kn, long hint)
2879 {
2880 if (hint == NOTE_REVOKE)
2881 kn->kn_flags |= (EV_EOF | EV_NODATA | EV_ONESHOT);
2882 kn->kn_data = 0;
2883 return (1);
2884 }
2885
2886 static int
2887 filt_hammer2vnode(struct knote *kn, long hint)
2888 {
2889 if (kn->kn_sfflags & hint)
2890 kn->kn_fflags |= hint;
2891 if (hint == NOTE_REVOKE) {
2892 kn->kn_flags |= (EV_EOF | EV_NODATA);
2893 return (1);
2894 }
2895 return (kn->kn_fflags != 0);
2896 }
2897 #endif
2898
2899 /*
2900 * FIFO VOPS
2901 */
2902 static
2903 int
hammer2_vop_markatime(struct vop_markatime_args * ap)2904 hammer2_vop_markatime(struct vop_markatime_args *ap)
2905 {
2906 #if 0
2907 hammer2_inode_t *ip;
2908 struct m_vnode *vp;
2909
2910 vp = ap->a_vp;
2911 ip = VTOI(vp);
2912
2913 if (ip->pmp->ronly || (ip->pmp->flags & HAMMER2_PMPF_EMERG))
2914 return (EROFS);
2915 return(0);
2916 #endif
2917 return (EOPNOTSUPP);
2918 }
2919
2920 static
2921 int
hammer2_vop_fifokqfilter(struct vop_kqfilter_args * ap)2922 hammer2_vop_fifokqfilter(struct vop_kqfilter_args *ap)
2923 {
2924 #if 0
2925 int error;
2926
2927 error = VOCALL(&fifo_vnode_vops, &ap->a_head);
2928 if (error)
2929 error = hammer2_vop_kqfilter(ap);
2930 return(error);
2931 #endif
2932 return (EOPNOTSUPP);
2933 }
2934
2935 /*
2936 * VOPS vector
2937 */
2938 struct vop_ops hammer2_vnode_vops = {
2939 .vop_default = vop_defaultop,
2940 .vop_fsync = hammer2_vop_fsync,
2941 .vop_getpages = vop_stdgetpages,
2942 .vop_putpages = vop_stdputpages,
2943 .vop_access = hammer2_vop_access,
2944 .vop_advlock = hammer2_vop_advlock,
2945 .vop_close = hammer2_vop_close,
2946 .vop_nlink = hammer2_vop_nlink,
2947 .vop_ncreate = hammer2_vop_ncreate,
2948 .vop_nsymlink = hammer2_vop_nsymlink,
2949 .vop_nremove = hammer2_vop_nremove,
2950 .vop_nrmdir = hammer2_vop_nrmdir,
2951 .vop_nrename = hammer2_vop_nrename,
2952 .vop_getattr = hammer2_vop_getattr,
2953 .vop_getattr_lite = hammer2_vop_getattr_lite,
2954 .vop_setattr = hammer2_vop_setattr,
2955 .vop_readdir = hammer2_vop_readdir,
2956 .vop_readlink = hammer2_vop_readlink,
2957 .vop_read = hammer2_vop_read,
2958 .vop_write = hammer2_vop_write,
2959 .vop_open = hammer2_vop_open,
2960 .vop_inactive = hammer2_vop_inactive,
2961 .vop_reclaim = hammer2_vop_reclaim,
2962 .vop_nresolve = hammer2_vop_nresolve,
2963 .vop_nlookupdotdot = hammer2_vop_nlookupdotdot,
2964 .vop_nmkdir = hammer2_vop_nmkdir,
2965 .vop_nmknod = hammer2_vop_nmknod,
2966 .vop_ioctl = hammer2_vop_ioctl,
2967 .vop_mountctl = hammer2_vop_mountctl,
2968 .vop_bmap = hammer2_vop_bmap,
2969 .vop_strategy = hammer2_vop_strategy,
2970 .vop_kqfilter = hammer2_vop_kqfilter
2971 };
2972
2973 struct vop_ops hammer2_spec_vops = {
2974 .vop_default = vop_defaultop,
2975 .vop_fsync = hammer2_vop_fsync,
2976 .vop_read = vop_stdnoread,
2977 .vop_write = vop_stdnowrite,
2978 .vop_access = hammer2_vop_access,
2979 .vop_close = hammer2_vop_close,
2980 .vop_markatime = hammer2_vop_markatime,
2981 .vop_getattr = hammer2_vop_getattr,
2982 .vop_inactive = hammer2_vop_inactive,
2983 .vop_reclaim = hammer2_vop_reclaim,
2984 .vop_setattr = hammer2_vop_setattr
2985 };
2986
2987 struct vop_ops hammer2_fifo_vops = {
2988 .vop_default = fifo_vnoperate,
2989 .vop_fsync = hammer2_vop_fsync,
2990 #if 0
2991 .vop_read = hammer2_vop_fiforead,
2992 .vop_write = hammer2_vop_fifowrite,
2993 #endif
2994 .vop_access = hammer2_vop_access,
2995 #if 0
2996 .vop_close = hammer2_vop_fifoclose,
2997 #endif
2998 .vop_markatime = hammer2_vop_markatime,
2999 .vop_getattr = hammer2_vop_getattr,
3000 .vop_inactive = hammer2_vop_inactive,
3001 .vop_reclaim = hammer2_vop_reclaim,
3002 .vop_setattr = hammer2_vop_setattr,
3003 .vop_kqfilter = hammer2_vop_fifokqfilter
3004 };
3005
3006