hammer2 - small-embedded-data fixes, syncer fixes
[dragonfly.git] / sys / vfs / hammer2 / hammer2_vnops.c
CommitLineData
e118c14f
MD
1/*
2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@dragonflybsd.org>
6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
703720e4
MD
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/fcntl.h>
39#include <sys/buf.h>
40#include <sys/proc.h>
41#include <sys/namei.h>
42#include <sys/mount.h>
43#include <sys/vnode.h>
f0206a67 44#include <sys/mountctl.h>
e028fa74 45#include <sys/dirent.h>
4e2004ea 46#include <sys/uio.h>
703720e4
MD
47
48#include "hammer2.h"
49
db71f61f
MD
50#define ZFOFFSET (-2LL)
51
4e2004ea
MD
52static int hammer2_read_file(hammer2_inode_t *ip, struct uio *uio,
53 int seqcount);
54static int hammer2_write_file(hammer2_inode_t *ip, struct uio *uio, int ioflag);
8cce658d
MD
55static hammer2_off_t hammer2_assign_physical(hammer2_inode_t *ip,
56 hammer2_key_t lbase, int lblksize, int *errorp);
57static void hammer2_extend_file(hammer2_inode_t *ip, hammer2_key_t nsize);
3ac6a319 58static void hammer2_truncate_file(hammer2_inode_t *ip, hammer2_key_t nsize);
4e2004ea
MD
59static int hammer2_unlink_file(hammer2_inode_t *dip,
60 const uint8_t *name, size_t name_len,
db0c2eb3 61 int isdir, int adjlinks);
3ac6a319 62
703720e4
MD
63/*
64 * Last reference to a vnode is going away but it is still cached.
65 */
e118c14f 66static
703720e4 67int
e118c14f 68hammer2_vop_inactive(struct vop_inactive_args *ap)
703720e4
MD
69{
70 struct vnode *vp;
71 struct hammer2_inode *ip;
e118c14f 72#if 0
703720e4 73 struct hammer2_mount *hmp;
e118c14f 74#endif
703720e4 75
703720e4
MD
76 vp = ap->a_vp;
77 ip = VTOI(vp);
703720e4 78
df9ea374
MD
79 /*
80 * Degenerate case
81 */
82 if (ip == NULL) {
83 vrecycle(vp);
84 return (0);
85 }
86
214f4a77
MD
87 /*
88 * Detect updates to the embedded data which may be synchronized by
89 * the strategy code. Simply mark the inode modified so it gets
90 * picked up by our normal flush.
91 */
92 if (ip->chain.flags & HAMMER2_CHAIN_DIRTYEMBED) {
93 hammer2_inode_lock_ex(ip);
94 atomic_clear_int(&ip->chain.flags, HAMMER2_CHAIN_DIRTYEMBED);
95 hammer2_chain_modify(ip->hmp, &ip->chain, 1);
96 hammer2_inode_unlock_ex(ip);
97 }
98
99 /*
100 * Check for deleted inodes and recycle immediately.
101 */
102 if (ip->chain.flags & HAMMER2_CHAIN_DELETED) {
103 vrecycle(vp);
104 }
703720e4
MD
105 return (0);
106}
107
108/*
109 * Reclaim a vnode so that it can be reused; after the inode is
110 * disassociated, the filesystem must manage it alone.
111 */
e118c14f 112static
703720e4 113int
e118c14f 114hammer2_vop_reclaim(struct vop_reclaim_args *ap)
703720e4 115{
703720e4
MD
116 struct hammer2_inode *ip;
117 struct hammer2_mount *hmp;
b7926f31 118 struct vnode *vp;
703720e4 119
703720e4
MD
120 vp = ap->a_vp;
121 ip = VTOI(vp);
9c2e0de0
MD
122 if (ip == NULL)
123 return(0);
9c2e0de0 124 hmp = ip->hmp;
b7926f31 125
54eb943b 126 hammer2_inode_lock_ex(ip);
703720e4 127 vp->v_data = NULL;
0e92b724 128 ip->vp = NULL;
222d9e22
MD
129 if (ip->chain.flags & HAMMER2_CHAIN_DELETED)
130 atomic_set_int(&ip->chain.flags, HAMMER2_CHAIN_DESTROYED);
73e441b9 131 hammer2_chain_flush(hmp, &ip->chain);
54eb943b 132 hammer2_inode_unlock_ex(ip);
222d9e22 133 hammer2_chain_drop(hmp, &ip->chain); /* vp ref */
54eb943b
MD
134
135 /*
136 * XXX handle background sync when ip dirty, kernel will no longer
137 * notify us regarding this inode because there is no longer a
138 * vnode attached to it.
139 */
703720e4
MD
140
141 return (0);
142}
143
e118c14f 144static
703720e4 145int
e118c14f 146hammer2_vop_fsync(struct vop_fsync_args *ap)
703720e4 147{
b7926f31
MD
148 struct hammer2_inode *ip;
149 struct hammer2_mount *hmp;
150 struct vnode *vp;
151
152 vp = ap->a_vp;
153 ip = VTOI(vp);
154 hmp = ip->hmp;
155
156 hammer2_inode_lock_ex(ip);
157 vfsync(vp, ap->a_waitfor, 1, NULL, NULL);
6ba3b984 158
214f4a77
MD
159 /*
160 * Detect updates to the embedded data which may be synchronized by
161 * the strategy code. Simply mark the inode modified so it gets
162 * picked up by our normal flush.
163 */
164 if (ip->chain.flags & HAMMER2_CHAIN_DIRTYEMBED) {
165 atomic_clear_int(&ip->chain.flags, HAMMER2_CHAIN_DIRTYEMBED);
166 hammer2_chain_modify(hmp, &ip->chain, 1);
167 }
168
6ba3b984
MD
169 /*
170 * Calling chain_flush here creates a lot of duplicative
171 * COW operations due to non-optimal vnode ordering.
172 *
173 * Only do it for an actual fsync() syscall. The other forms
174 * which call this function will eventually call chain_flush
175 * on the volume root as a catch-all, which is far more optimal.
176 */
177 if (ap->a_flags & VOP_FSYNC_SYSCALL)
178 hammer2_chain_flush(hmp, &ip->chain);
b7926f31
MD
179 hammer2_inode_unlock_ex(ip);
180 return (0);
703720e4
MD
181}
182
e118c14f 183static
703720e4 184int
e118c14f 185hammer2_vop_access(struct vop_access_args *ap)
703720e4 186{
37494cab
MD
187 hammer2_inode_t *ip = VTOI(ap->a_vp);
188 uid_t uid;
189 gid_t gid;
190 int error;
191
192 uid = hammer2_to_unix_xid(&ip->ip_data.uid);
193 gid = hammer2_to_unix_xid(&ip->ip_data.gid);
194
195 error = vop_helper_access(ap, uid, gid, ip->ip_data.mode,
196 ip->ip_data.uflags);
197 return (error);
703720e4
MD
198}
199
e118c14f 200static
703720e4 201int
e118c14f 202hammer2_vop_getattr(struct vop_getattr_args *ap)
703720e4 203{
cd4b3d92
MD
204 hammer2_mount_t *hmp;
205 hammer2_inode_t *ip;
703720e4
MD
206 struct vnode *vp;
207 struct vattr *vap;
703720e4
MD
208
209 vp = ap->a_vp;
210 vap = ap->a_vap;
211
cd4b3d92
MD
212 ip = VTOI(vp);
213 hmp = ip->hmp;
214
703720e4
MD
215 hammer2_inode_lock_sh(ip);
216
cd4b3d92
MD
217 vap->va_fsid = hmp->mp->mnt_stat.f_fsid.val[0];
218 vap->va_fileid = ip->ip_data.inum;
219 vap->va_mode = ip->ip_data.mode;
220 vap->va_nlink = ip->ip_data.nlinks;
703720e4
MD
221 vap->va_uid = 0;
222 vap->va_gid = 0;
cd4b3d92
MD
223 vap->va_rmajor = 0;
224 vap->va_rminor = 0;
225 vap->va_size = ip->ip_data.size;
df9ea374 226 vap->va_blocksize = HAMMER2_PBUFSIZE;
cd4b3d92
MD
227 vap->va_flags = ip->ip_data.uflags;
228 hammer2_time_to_timespec(ip->ip_data.ctime, &vap->va_ctime);
229 hammer2_time_to_timespec(ip->ip_data.mtime, &vap->va_mtime);
230 hammer2_time_to_timespec(ip->ip_data.mtime, &vap->va_atime);
231 vap->va_gen = 1;
866d5273 232 vap->va_bytes = vap->va_size; /* XXX */
cd4b3d92
MD
233 vap->va_type = hammer2_get_vtype(ip);
234 vap->va_filerev = 0;
235 vap->va_uid_uuid = ip->ip_data.uid;
236 vap->va_gid_uuid = ip->ip_data.gid;
237 vap->va_vaflags = VA_UID_UUID_VALID | VA_GID_UUID_VALID |
238 VA_FSID_UUID_VALID;
703720e4
MD
239
240 hammer2_inode_unlock_sh(ip);
241
242 return (0);
243}
244
3ac6a319
MD
245static
246int
247hammer2_vop_setattr(struct vop_setattr_args *ap)
248{
249 hammer2_mount_t *hmp;
250 hammer2_inode_t *ip;
251 struct vnode *vp;
252 struct vattr *vap;
253 int error;
254 int kflags = 0;
255 int doctime = 0;
256 int domtime = 0;
257
258 vp = ap->a_vp;
259 vap = ap->a_vap;
260
261 ip = VTOI(vp);
262 hmp = ip->hmp;
263
264 if (hmp->ronly)
265 return(EROFS);
266
267 hammer2_inode_lock_ex(ip);
268 error = 0;
269
270 if (vap->va_flags != VNOVAL) {
271 u_int32_t flags;
272
273 flags = ip->ip_data.uflags;
274 error = vop_helper_setattr_flags(&flags, vap->va_flags,
275 hammer2_to_unix_xid(&ip->ip_data.uid),
276 ap->a_cred);
277 if (error == 0) {
278 if (ip->ip_data.uflags != flags) {
214f4a77 279 hammer2_chain_modify(hmp, &ip->chain, 1);
3ac6a319
MD
280 ip->ip_data.uflags = flags;
281 doctime = 1;
282 kflags |= NOTE_ATTRIB;
283 }
284 if (ip->ip_data.uflags & (IMMUTABLE | APPEND)) {
285 error = 0;
286 goto done;
287 }
288 }
289 }
290
291 if (ip->ip_data.uflags & (IMMUTABLE | APPEND)) {
292 error = EPERM;
293 goto done;
294 }
295 /* uid, gid */
296
297 /*
298 * Resize the file
299 */
300 if (vap->va_size != VNOVAL && ip->ip_data.size != vap->va_size) {
301 switch(vp->v_type) {
302 case VREG:
303 if (vap->va_size == ip->ip_data.size)
304 break;
305 if (vap->va_size < ip->ip_data.size) {
3ac6a319 306 hammer2_truncate_file(ip, vap->va_size);
3ac6a319 307 } else {
8cce658d 308 hammer2_extend_file(ip, vap->va_size);
3ac6a319
MD
309 }
310 domtime = 1;
311 break;
312 default:
313 error = EINVAL;
314 goto done;
315 }
316 }
317done:
318 hammer2_inode_unlock_ex(ip);
319 return (error);
320}
321
e118c14f 322static
703720e4 323int
e118c14f 324hammer2_vop_readdir(struct vop_readdir_args *ap)
703720e4 325{
e028fa74
MD
326 hammer2_mount_t *hmp;
327 hammer2_inode_t *ip;
328 hammer2_inode_t *xip;
329 hammer2_chain_t *parent;
330 hammer2_chain_t *chain;
331 hammer2_key_t lkey;
332 struct uio *uio;
333 off_t *cookies;
334 off_t saveoff;
335 int cookie_index;
336 int ncookies;
337 int error;
338 int dtype;
339 int r;
340
341 ip = VTOI(ap->a_vp);
342 hmp = ip->hmp;
343 uio = ap->a_uio;
344 saveoff = uio->uio_offset;
345
346 /*
347 * Setup cookies directory entry cookies if requested
348 */
349 if (ap->a_ncookies) {
350 ncookies = uio->uio_resid / 16 + 1;
351 if (ncookies > 1024)
352 ncookies = 1024;
353 cookies = kmalloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
354 } else {
355 ncookies = -1;
356 cookies = NULL;
357 }
358 cookie_index = 0;
359
360 /*
361 * Handle artificial entries. To ensure that only positive 64 bit
362 * quantities are returned to userland we always strip off bit 63.
363 * The hash code is designed such that codes 0x0000-0x7FFF are not
364 * used, allowing us to use these codes for articial entries.
365 *
366 * Entry 0 is used for '.' and entry 1 is used for '..'. Do not
367 * allow '..' to cross the mount point into (e.g.) the super-root.
368 */
369 error = 0;
37aa19df 370 chain = (void *)(intptr_t)-1; /* non-NULL for early goto done case */
e028fa74
MD
371
372 if (saveoff == 0) {
373 r = vop_write_dirent(&error, uio,
374 ip->ip_data.inum &
375 HAMMER2_DIRHASH_USERMSK,
376 DT_DIR, 1, ".");
377 if (r)
378 goto done;
379 if (cookies)
380 cookies[cookie_index] = saveoff;
381 ++saveoff;
382 ++cookie_index;
383 if (cookie_index == ncookies)
384 goto done;
385 }
386 if (saveoff == 1) {
387 if (ip->pip == NULL || ip == hmp->iroot)
388 xip = ip;
389 else
390 xip = ip->pip;
391
392 r = vop_write_dirent(&error, uio,
393 xip->ip_data.inum &
394 HAMMER2_DIRHASH_USERMSK,
395 DT_DIR, 2, "..");
396 if (r)
397 goto done;
398 if (cookies)
399 cookies[cookie_index] = saveoff;
400 ++saveoff;
401 ++cookie_index;
402 if (cookie_index == ncookies)
403 goto done;
404 }
405
406 lkey = saveoff | HAMMER2_DIRHASH_VISIBLE;
407
408 parent = &ip->chain;
409 hammer2_chain_ref(hmp, parent);
410 error = hammer2_chain_lock(hmp, parent);
411 if (error) {
412 hammer2_chain_put(hmp, parent);
413 goto done;
414 }
37aa19df
MD
415 chain = hammer2_chain_lookup(hmp, &parent, lkey, lkey, 0);
416 if (chain == NULL) {
417 chain = hammer2_chain_lookup(hmp, &parent,
418 lkey, (hammer2_key_t)-1, 0);
419 }
e028fa74 420 while (chain) {
c667909f
MD
421 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
422 dtype = hammer2_get_dtype(chain->u.ip);
423 saveoff = chain->bref.key & HAMMER2_DIRHASH_USERMSK;
424 r = vop_write_dirent(&error, uio,
425 chain->u.ip->ip_data.inum &
426 HAMMER2_DIRHASH_USERMSK,
427 dtype, chain->u.ip->ip_data.name_len,
428 chain->u.ip->ip_data.filename);
429 if (r)
430 break;
431 if (cookies)
432 cookies[cookie_index] = saveoff;
433 ++cookie_index;
434 } else {
435 /* XXX chain error */
436 kprintf("bad chain type readdir %d\n",
437 chain->bref.type);
438 }
995e78dc
MD
439
440 /*
441 * Keys may not be returned in order so once we have a
442 * placemarker (chain) the scan must allow the full range
443 * or some entries will be missed.
444 */
e028fa74 445 chain = hammer2_chain_next(hmp, &parent, chain,
995e78dc 446 0, (hammer2_key_t)-1, 0);
028a55bb
MD
447 if (chain) {
448 saveoff = (chain->bref.key &
449 HAMMER2_DIRHASH_USERMSK) + 1;
450 } else {
451 saveoff = (hammer2_key_t)-1;
452 }
453 if (cookie_index == ncookies)
454 break;
e028fa74
MD
455 }
456 hammer2_chain_put(hmp, parent);
028a55bb
MD
457 if (chain)
458 hammer2_chain_put(hmp, chain);
e028fa74
MD
459done:
460 if (ap->a_eofflag)
461 *ap->a_eofflag = (chain == NULL);
37aa19df 462 uio->uio_offset = saveoff & ~HAMMER2_DIRHASH_VISIBLE;
e028fa74
MD
463 if (error && cookie_index == 0) {
464 if (cookies) {
465 kfree(cookies, M_TEMP);
466 *ap->a_ncookies = 0;
467 *ap->a_cookies = NULL;
468 }
469 } else {
470 if (cookies) {
471 *ap->a_ncookies = cookie_index;
472 *ap->a_cookies = cookies;
473 }
474 }
475 return (error);
703720e4
MD
476}
477
4e2004ea
MD
478/*
479 * hammer2_vop_readlink { vp, uio, cred }
480 */
481static
482int
483hammer2_vop_readlink(struct vop_readlink_args *ap)
484{
485 struct vnode *vp;
486 hammer2_mount_t *hmp;
487 hammer2_inode_t *ip;
488 int error;
489
490 vp = ap->a_vp;
491 if (vp->v_type != VLNK)
492 return (EINVAL);
493 ip = VTOI(vp);
494 hmp = ip->hmp;
495
496 error = hammer2_read_file(ip, ap->a_uio, 0);
497 return (error);
498}
499
e118c14f 500static
703720e4 501int
e118c14f 502hammer2_vop_read(struct vop_read_args *ap)
703720e4 503{
db71f61f
MD
504 struct vnode *vp;
505 hammer2_mount_t *hmp;
506 hammer2_inode_t *ip;
db71f61f
MD
507 struct uio *uio;
508 int error;
509 int seqcount;
510 int bigread;
511
512 /*
513 * Read operations supported on this vnode?
514 */
515 vp = ap->a_vp;
516 if (vp->v_type != VREG)
517 return (EINVAL);
518
519 /*
520 * Misc
521 */
522 ip = VTOI(vp);
523 hmp = ip->hmp;
524 uio = ap->a_uio;
525 error = 0;
526
527 seqcount = ap->a_ioflag >> 16;
528 bigread = (uio->uio_resid > 100 * 1024 * 1024);
529
4e2004ea 530 error = hammer2_read_file(ip, uio, seqcount);
db71f61f 531 return (error);
47902fef 532}
703720e4 533
e118c14f 534static
47902fef 535int
e118c14f 536hammer2_vop_write(struct vop_write_args *ap)
47902fef 537{
db71f61f
MD
538 thread_t td;
539 struct vnode *vp;
540 hammer2_mount_t *hmp;
541 hammer2_inode_t *ip;
db71f61f
MD
542 struct uio *uio;
543 int error;
db71f61f
MD
544 int seqcount;
545 int bigwrite;
546
547 /*
548 * Read operations supported on this vnode?
549 */
550 vp = ap->a_vp;
551 if (vp->v_type != VREG)
552 return (EINVAL);
553
554 /*
555 * Misc
556 */
557 ip = VTOI(vp);
558 hmp = ip->hmp;
559 uio = ap->a_uio;
560 error = 0;
db71f61f
MD
561 if (hmp->ronly)
562 return (EROFS);
563
564 seqcount = ap->a_ioflag >> 16;
565 bigwrite = (uio->uio_resid > 100 * 1024 * 1024);
566
567 /*
568 * Check resource limit
569 */
570 if (uio->uio_resid > 0 && (td = uio->uio_td) != NULL && td->td_proc &&
571 uio->uio_offset + uio->uio_resid >
572 td->td_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
573 lwpsignal(td->td_proc, td->td_lwp, SIGXFSZ);
574 return (EFBIG);
575 }
576
577 bigwrite = (uio->uio_resid > 100 * 1024 * 1024);
578
579 /*
3ac6a319
MD
580 * ip must be locked if extending the file.
581 * ip must be locked to avoid racing a truncation.
8cce658d
MD
582 *
583 * ip must be marked modified, particularly because the write
584 * might wind up being copied into the embedded data area.
3ac6a319
MD
585 */
586 hammer2_inode_lock_ex(ip);
214f4a77 587 hammer2_chain_modify(hmp, &ip->chain, 1);
4e2004ea
MD
588 error = hammer2_write_file(ip, uio, ap->a_ioflag);
589
590 hammer2_inode_unlock_ex(ip);
591 return (error);
592}
593
594/*
595 * Perform read operations on a file or symlink given an UNLOCKED
596 * inode and uio.
597 */
598static
599int
600hammer2_read_file(hammer2_inode_t *ip, struct uio *uio, int seqcount)
601{
602 struct buf *bp;
603 int error;
604
605 error = 0;
606
607 /*
608 * UIO read loop
609 */
610 while (uio->uio_resid > 0 && uio->uio_offset < ip->ip_data.size) {
8cce658d
MD
611 hammer2_key_t lbase;
612 hammer2_key_t leof;
613 int lblksize;
614 int loff;
4e2004ea
MD
615 int n;
616
8cce658d
MD
617 lblksize = hammer2_calc_logical(ip, uio->uio_offset,
618 &lbase, &leof);
4e2004ea 619
8cce658d 620 error = cluster_read(ip->vp, leof, lbase, lblksize,
6ba3b984
MD
621 uio->uio_resid, seqcount * BKVASIZE,
622 &bp);
8cce658d 623
4e2004ea
MD
624 if (error)
625 break;
8cce658d
MD
626 loff = (int)(uio->uio_offset - lbase);
627 n = lblksize - loff;
4e2004ea
MD
628 if (n > uio->uio_resid)
629 n = uio->uio_resid;
630 if (n > ip->ip_data.size - uio->uio_offset)
631 n = (int)(ip->ip_data.size - uio->uio_offset);
632 bp->b_flags |= B_AGE;
8cce658d 633 uiomove((char *)bp->b_data + loff, n, uio);
4e2004ea
MD
634 bqrelse(bp);
635 }
636 return (error);
637}
638
639/*
640 * Called with a locked (ip) to do the underlying write to a file or
641 * to build the symlink target.
642 */
643static
644int
645hammer2_write_file(hammer2_inode_t *ip, struct uio *uio, int ioflag)
646{
8cce658d 647 hammer2_key_t old_eof;
4e2004ea
MD
648 struct buf *bp;
649 int kflags;
650 int error;
3ac6a319 651
4e2004ea
MD
652 /*
653 * Setup if append
654 */
655 if (ioflag & IO_APPEND)
3ac6a319 656 uio->uio_offset = ip->ip_data.size;
4e2004ea
MD
657 kflags = 0;
658 error = 0;
3ac6a319 659
8cce658d
MD
660 /*
661 * Extend the file if necessary. If the write fails at some point
662 * we will truncate it back down to cover as much as we were able
663 * to write.
664 *
665 * Doing this now makes it easier to calculate buffer sizes in
666 * the loop.
667 */
668 old_eof = ip->ip_data.size;
669 if (uio->uio_offset + uio->uio_resid > ip->ip_data.size) {
670 hammer2_extend_file(ip, uio->uio_offset + uio->uio_resid);
671 kflags |= NOTE_EXTEND;
672 }
673
3ac6a319
MD
674 /*
675 * UIO write loop
db71f61f
MD
676 */
677 while (uio->uio_resid > 0) {
8cce658d
MD
678 hammer2_key_t lbase;
679 hammer2_key_t leof;
db71f61f 680 int trivial;
8cce658d
MD
681 int lblksize;
682 int loff;
683 int n;
db71f61f
MD
684
685 /*
686 * Don't allow the buffer build to blow out the buffer
687 * cache.
688 */
a92f82c4
MD
689 if ((ioflag & IO_RECURSE) == 0) {
690 /*
691 * XXX should try to leave this unlocked through
692 * the whole loop
693 */
694 hammer2_chain_unlock(ip->hmp, &ip->chain);
db71f61f 695 bwillwrite(HAMMER2_LBUFSIZE);
a92f82c4
MD
696 hammer2_chain_lock(ip->hmp, &ip->chain);
697 }
db71f61f 698
8cce658d
MD
699 /* XXX bigwrite & signal check test */
700
db71f61f 701 /*
8cce658d
MD
702 * This nominally tells us how much we can cluster and
703 * what the logical buffer size needs to be. Currently
704 * we don't try to cluster the write and just handle one
705 * block at a time.
db71f61f 706 */
8cce658d
MD
707 lblksize = hammer2_calc_logical(ip, uio->uio_offset,
708 &lbase, &leof);
709 loff = (int)(uio->uio_offset - lbase);
710
711 /*
712 * Calculate bytes to copy this transfer and whether the
713 * copy completely covers the buffer or not.
714 */
715 trivial = 0;
716 n = lblksize - loff;
717 if (n > uio->uio_resid) {
718 n = uio->uio_resid;
719 if (uio->uio_offset + n == ip->ip_data.size)
db71f61f 720 trivial = 1;
8cce658d
MD
721 } else if (loff == 0) {
722 trivial = 1;
db71f61f
MD
723 }
724
8cce658d
MD
725 /*
726 * Get the buffer
727 */
db71f61f
MD
728 if (uio->uio_segflg == UIO_NOCOPY) {
729 /*
730 * Issuing a write with the same data backing the
731 * buffer. Instantiate the buffer to collect the
732 * backing vm pages, then read-in any missing bits.
733 *
734 * This case is used by vop_stdputpages().
735 */
8cce658d 736 bp = getblk(ip->vp, lbase, lblksize, GETBLK_BHEAVY, 0);
db71f61f
MD
737 if ((bp->b_flags & B_CACHE) == 0) {
738 bqrelse(bp);
8cce658d 739 error = bread(ip->vp, lbase, lblksize, &bp);
db71f61f 740 }
8cce658d 741 } else if (trivial) {
db71f61f
MD
742 /*
743 * Even though we are entirely overwriting the buffer
744 * we may still have to zero it out to avoid a
745 * mmap/write visibility issue.
746 */
8cce658d 747 bp = getblk(ip->vp, lbase, lblksize, GETBLK_BHEAVY, 0);
db71f61f
MD
748 if ((bp->b_flags & B_CACHE) == 0)
749 vfs_bio_clrbuf(bp);
db71f61f
MD
750 } else {
751 /*
752 * Partial overwrite, read in any missing bits then
753 * replace the portion being written.
8cce658d
MD
754 *
755 * (The strategy code will detect zero-fill physical
756 * blocks for this case).
db71f61f 757 */
8cce658d 758 error = bread(ip->vp, lbase, lblksize, &bp);
db71f61f
MD
759 if (error == 0)
760 bheavy(bp);
761 }
762
8cce658d
MD
763 if (error) {
764 brelse(bp);
765 break;
db71f61f
MD
766 }
767
8cce658d
MD
768 /*
769 * We have to assign physical storage to the buffer we intend
770 * to dirty or write now to avoid deadlocks in the strategy
771 * code later.
772 *
773 * This can return NOOFFSET for inode-embedded data. The
774 * strategy code will take care of it in that case.
775 */
776 bp->b_bio2.bio_offset =
777 hammer2_assign_physical(ip, lbase, lblksize, &error);
db71f61f
MD
778 if (error) {
779 brelse(bp);
db71f61f
MD
780 break;
781 }
8cce658d
MD
782
783 /*
784 * Ok, copy the data in
785 */
786 hammer2_chain_unlock(ip->hmp, &ip->chain);
787 error = uiomove(bp->b_data + loff, n, uio);
788 hammer2_chain_lock(ip->hmp, &ip->chain);
db71f61f 789 kflags |= NOTE_WRITE;
8cce658d
MD
790
791 if (error) {
792 brelse(bp);
793 break;
794 }
795
db71f61f
MD
796 /* XXX update ino_data.mtime */
797
798 /*
799 * Once we dirty a buffer any cached offset becomes invalid.
800 */
db71f61f 801 bp->b_flags |= B_AGE;
4e2004ea 802 if (ioflag & IO_SYNC) {
db71f61f 803 bwrite(bp);
8cce658d
MD
804 } else if ((ioflag & IO_DIRECT) && loff + n == lblksize) {
805 bdwrite(bp);
4e2004ea 806 } else if (ioflag & IO_ASYNC) {
db71f61f
MD
807 bawrite(bp);
808 } else {
809 bdwrite(bp);
810 }
811 }
8cce658d
MD
812
813 /*
814 * Cleanup. If we extended the file EOF but failed to write through
815 * the entire write is a failure and we have to back-up.
816 */
817 if (error && ip->ip_data.size != old_eof)
818 hammer2_truncate_file(ip, old_eof);
4e2004ea
MD
819 /* hammer2_knote(ip->vp, kflags); */
820 return error;
703720e4
MD
821}
822
3ac6a319 823/*
8cce658d
MD
824 * Assign physical storage to a logical block.
825 *
826 * NOOFFSET is returned if the data is inode-embedded. In this case the
827 * strategy code will simply bcopy() the data into the inode.
828 */
829static
830hammer2_off_t
831hammer2_assign_physical(hammer2_inode_t *ip, hammer2_key_t lbase,
832 int lblksize, int *errorp)
833{
834 hammer2_mount_t *hmp;
835 hammer2_chain_t *parent;
836 hammer2_chain_t *chain;
837 hammer2_off_t pbase;
838
839 *errorp = 0;
840 hmp = ip->hmp;
841
842 /*
843 * Locate the chain associated with lbase, return a locked chain.
844 * However, do not instantiate any data reference (which utilizes a
845 * device buffer) because we will be using direct IO via the
846 * logical buffer cache buffer.
847 */
848 parent = &ip->chain;
849 hammer2_chain_ref(hmp, parent);
850 hammer2_chain_lock(hmp, parent);
851
852 chain = hammer2_chain_lookup(hmp, &parent,
853 lbase, lbase,
854 HAMMER2_LOOKUP_NODATA);
855
856 if (chain == NULL) {
857 /*
858 * We found a hole, create a new chain entry. No meta-data
859 * buffer or data pointer will be assigned (indicating
860 * new, unwritten storage).
861 */
862 chain = hammer2_chain_create(hmp, parent, NULL,
863 lbase, HAMMER2_PBUFRADIX,
864 HAMMER2_BREF_TYPE_DATA,
865 lblksize);
866 pbase = chain->bref.data_off & ~HAMMER2_OFF_MASK_RADIX;
867 } else {
868 switch (chain->bref.type) {
869 case HAMMER2_BREF_TYPE_INODE:
870 /*
214f4a77
MD
871 * The data is embedded in the inode. The
872 * caller is responsible for marking the inode
873 * modified and copying the data to the embedded
874 * area.
8cce658d 875 */
8cce658d
MD
876 pbase = NOOFFSET;
877 break;
878 case HAMMER2_BREF_TYPE_DATA:
879 if (chain->bytes != lblksize) {
880 panic("hammer2_assign_physical: "
881 "size mismatch %d/%d\n",
882 lblksize, chain->bytes);
883 }
884 hammer2_chain_modify_quick(hmp, chain);
885 pbase = chain->bref.data_off & ~HAMMER2_OFF_MASK_RADIX;
886 break;
887 default:
888 panic("hammer2_assign_physical: bad type");
889 /* NOT REACHED */
890 pbase = NOOFFSET;
891 break;
892 }
893 }
894
895 if (chain)
896 hammer2_chain_put(hmp, chain);
897 hammer2_chain_put(hmp, parent);
898
899 return (pbase);
900}
901
902/*
903 * Truncate the size of a file.
904 *
905 * This routine adjusts ip->ip_data.size smaller, destroying any related
906 * data beyond the new EOF and potentially resizing the block straddling
907 * the EOF.
908 *
909 * The inode must be locked.
3ac6a319
MD
910 */
911static
912void
913hammer2_truncate_file(hammer2_inode_t *ip, hammer2_key_t nsize)
914{
915 hammer2_chain_t *parent;
916 hammer2_chain_t *chain;
917 hammer2_mount_t *hmp = ip->hmp;
8cce658d
MD
918 hammer2_key_t lbase;
919 hammer2_key_t leof;
920 struct buf *bp;
921 int loff;
3ac6a319 922 int error;
8cce658d
MD
923 int oblksize;
924 int nblksize;
925
214f4a77 926 hammer2_chain_modify(hmp, &ip->chain, 1);
8cce658d 927 bp = NULL;
3ac6a319
MD
928
929 /*
8cce658d
MD
930 * Destroy any logical buffer cache buffers beyond the file EOF.
931 *
932 * We call nvtruncbuf() w/ trivial == 1 to prevent it from messing
933 * around with the buffer straddling EOF, because we need to assign
934 * a new physical offset to it.
3ac6a319
MD
935 */
936 if (ip->vp) {
937 nvtruncbuf(ip->vp, nsize,
8cce658d
MD
938 HAMMER2_PBUFSIZE, (int)nsize & HAMMER2_PBUFMASK,
939 1);
3ac6a319 940 }
3ac6a319
MD
941
942 /*
8cce658d 943 * Setup for lookup/search
3ac6a319
MD
944 */
945 parent = &ip->chain;
946 hammer2_chain_ref(hmp, parent);
947 error = hammer2_chain_lock(hmp, parent);
948 if (error) {
949 hammer2_chain_put(hmp, parent);
950 /* XXX error reporting */
951 return;
952 }
953
954 /*
8cce658d
MD
955 * Handle the case where a chain/logical-buffer straddles the new
956 * EOF. We told nvtruncbuf() above not to mess with the logical
957 * buffer straddling the EOF because we need to reassign its storage
958 * and can't let the strategy code do it for us.
3ac6a319 959 */
8cce658d
MD
960 loff = (int)nsize & HAMMER2_PBUFMASK;
961 if (loff && ip->vp) {
962 oblksize = hammer2_calc_logical(ip, nsize, &lbase, &leof);
963 error = bread(ip->vp, lbase, oblksize, &bp);
964 KKASSERT(error == 0);
965 }
966 ip->ip_data.size = nsize;
967 nblksize = hammer2_calc_logical(ip, nsize, &lbase, &leof);
3ac6a319 968
866d5273 969 /*
8cce658d
MD
970 * Fixup the chain element. If we have a logical buffer in-hand
971 * we don't want to create a conflicting device buffer.
866d5273 972 */
8cce658d
MD
973 if (loff && bp) {
974 chain = hammer2_chain_lookup(hmp, &parent, lbase, lbase,
866d5273 975 HAMMER2_LOOKUP_NOLOCK);
8cce658d
MD
976 if (chain) {
977 allocbuf(bp, nblksize);
978 switch(chain->bref.type) {
979 case HAMMER2_BREF_TYPE_DATA:
980 hammer2_chain_resize_quick(hmp, chain,
981 hammer2_bytes_to_radix(nblksize));
982 hammer2_chain_modify_quick(hmp, chain);
983 bzero(bp->b_data + loff, nblksize - loff);
984 bp->b_bio2.bio_offset = chain->bref.data_off &
985 HAMMER2_OFF_MASK;
986 break;
987 case HAMMER2_BREF_TYPE_INODE:
988 bzero(bp->b_data + loff, nblksize - loff);
989 bp->b_bio2.bio_offset = NOOFFSET;
990 break;
991 default:
992 panic("hammer2_truncate_file: bad type");
993 break;
994 }
995 hammer2_chain_drop(hmp, chain);
996 bdwrite(bp);
997 } else {
998 /*
999 * Destroy clean buffer w/ wrong buffer size. Retain
1000 * backing store.
1001 */
1002 bp->b_flags |= B_RELBUF;
1003 KKASSERT(bp->b_bio2.bio_offset == NOOFFSET);
1004 KKASSERT((bp->b_flags & B_DIRTY) == 0);
1005 bqrelse(bp);
1006 }
1007 } else if (loff) {
1008 chain = hammer2_chain_lookup(hmp, &parent, lbase, lbase, 0);
1009 if (chain) {
1010 switch(chain->bref.type) {
1011 case HAMMER2_BREF_TYPE_DATA:
1012 hammer2_chain_resize(hmp, chain,
1013 hammer2_bytes_to_radix(nblksize));
214f4a77 1014 hammer2_chain_modify(hmp, chain, 1);
8cce658d
MD
1015 bzero(chain->data->buf + loff, nblksize - loff);
1016 break;
1017 case HAMMER2_BREF_TYPE_INODE:
1018 if (loff < HAMMER2_EMBEDDED_BYTES) {
214f4a77 1019 hammer2_chain_modify(hmp, chain, 1);
8cce658d
MD
1020 bzero(chain->data->ipdata.u.data + loff,
1021 HAMMER2_EMBEDDED_BYTES - loff);
1022 }
1023 break;
1024 }
1025 hammer2_chain_put(hmp, chain);
3ac6a319
MD
1026 }
1027 }
1028
866d5273 1029 /*
8cce658d
MD
1030 * Clean up any fragmentory VM pages now that we have properly
1031 * resized the straddling buffer. These pages are no longer
1032 * part of the buffer.
866d5273 1033 */
8cce658d
MD
1034 if (ip->vp) {
1035 nvtruncbuf(ip->vp, nsize,
1036 nblksize, (int)nsize & (nblksize - 1),
1037 1);
1038 }
866d5273 1039
8cce658d
MD
1040 /*
1041 * Destroy any physical blocks after the new EOF point.
1042 */
1043 lbase = (nsize + HAMMER2_PBUFMASK64) & ~HAMMER2_PBUFMASK64;
3ac6a319 1044 chain = hammer2_chain_lookup(hmp, &parent,
8cce658d 1045 lbase, (hammer2_key_t)-1,
3ac6a319
MD
1046 HAMMER2_LOOKUP_NOLOCK);
1047 while (chain) {
1048 /*
1049 * Degenerate embedded data case, nothing to loop on.
1050 */
1051 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE)
1052 break;
1053
1054 /*
1055 * Delete physical data blocks past the file EOF.
1056 */
1057 if (chain->bref.type == HAMMER2_BREF_TYPE_DATA) {
1058 hammer2_chain_delete(hmp, parent, chain);
1059 }
db0c2eb3 1060 /* XXX check parent if empty indirect block & delete */
3ac6a319 1061 chain = hammer2_chain_next(hmp, &parent, chain,
8cce658d 1062 lbase, (hammer2_key_t)-1,
3ac6a319
MD
1063 HAMMER2_LOOKUP_NOLOCK);
1064 }
1065 hammer2_chain_put(hmp, parent);
1066}
1067
1068/*
8cce658d 1069 * Extend the size of a file. The inode must be locked.
866d5273 1070 *
8cce658d 1071 * We may have to resize the block straddling the old EOF.
3ac6a319
MD
1072 */
1073static
1074void
8cce658d 1075hammer2_extend_file(hammer2_inode_t *ip, hammer2_key_t nsize)
3ac6a319 1076{
8cce658d
MD
1077 hammer2_mount_t *hmp;
1078 hammer2_chain_t *parent;
1079 hammer2_chain_t *chain;
3ac6a319 1080 struct buf *bp;
8cce658d
MD
1081 hammer2_key_t osize;
1082 hammer2_key_t obase;
1083 hammer2_key_t nbase;
1084 hammer2_key_t leof;
1085 int oblksize;
1086 int nblksize;
1087 int nradix;
3ac6a319
MD
1088 int error;
1089
8cce658d
MD
1090 KKASSERT(ip->vp);
1091 hmp = ip->hmp;
1092
214f4a77 1093 hammer2_chain_modify(hmp, &ip->chain, 1);
8cce658d 1094
3ac6a319 1095 /*
8cce658d 1096 * Nothing to do if the direct-data case is still intact
3ac6a319
MD
1097 */
1098 if ((ip->ip_data.op_flags & HAMMER2_OPFLAG_DIRECTDATA) &&
8cce658d
MD
1099 nsize <= HAMMER2_EMBEDDED_BYTES) {
1100 ip->ip_data.size = nsize;
1101 return;
1102 }
1103
1104 /*
1105 * Calculate the blocksize at the original EOF and resize the block
1106 * if necessary. Adjust the file size in the inode.
1107 */
1108 osize = ip->ip_data.size;
1109 oblksize = hammer2_calc_logical(ip, osize, &obase, &leof);
1110 ip->ip_data.size = nsize;
1111 nblksize = hammer2_calc_logical(ip, osize, &nbase, &leof);
1112
1113 /*
1114 * Do all required vnode operations, but do not mess with the
1115 * buffer straddling the orignal EOF.
1116 */
1117 nvextendbuf(ip->vp,
1118 ip->ip_data.size, nsize,
1119 0, nblksize,
1120 0, (int)nsize & HAMMER2_PBUFMASK,
1121 1);
1122
1123 /*
1124 * Early return if we have no more work to do.
1125 */
1126 if (obase == nbase && oblksize == nblksize &&
1127 (ip->ip_data.op_flags & HAMMER2_OPFLAG_DIRECTDATA) == 0) {
1128 return;
1129 }
1130
1131 /*
1132 * We have work to do, including possibly resizing the buffer
1133 * at the EOF point and turning off DIRECTDATA mode.
1134 */
1135 bp = NULL;
1136 if (((int)osize & HAMMER2_PBUFMASK)) {
1137 error = bread(ip->vp, obase, oblksize, &bp);
3ac6a319 1138 KKASSERT(error == 0);
8cce658d
MD
1139
1140 if (obase != nbase) {
1141 allocbuf(bp, HAMMER2_PBUFSIZE);
1142 } else {
1143 allocbuf(bp, nblksize);
1144 }
1145 vfs_bio_clrbuf(bp);
1146 }
1147
1148 /*
1149 * Disable direct-data mode by loading up a buffer cache buffer
1150 * with the data, then converting the inode data area into the
1151 * inode indirect block array area.
1152 */
1153 if (ip->ip_data.op_flags & HAMMER2_OPFLAG_DIRECTDATA) {
3ac6a319 1154 ip->ip_data.op_flags &= ~HAMMER2_OPFLAG_DIRECTDATA;
8cce658d 1155 bzero(&ip->ip_data.u.blockset, sizeof(ip->ip_data.u.blockset));
3ac6a319 1156 }
866d5273
MD
1157
1158 /*
8cce658d 1159 * Resize the chain element at the old EOF.
866d5273 1160 */
8cce658d
MD
1161 if (((int)osize & HAMMER2_PBUFMASK)) {
1162 parent = &ip->chain;
1163 hammer2_chain_ref(hmp, parent);
1164 error = hammer2_chain_lock(hmp, parent);
1165 KKASSERT(error == 0);
1166
1167 nradix = hammer2_bytes_to_radix(nblksize);
1168
1169 chain = hammer2_chain_lookup(hmp, &parent,
1170 obase, obase,
1171 HAMMER2_LOOKUP_NOLOCK);
1172 if (chain == NULL) {
1173 chain = hammer2_chain_create(hmp, parent, NULL,
1174 obase, nblksize,
1175 HAMMER2_BREF_TYPE_DATA,
1176 nradix);
1177 } else {
1178 KKASSERT(chain->bref.type == HAMMER2_BREF_TYPE_DATA);
1179 hammer2_chain_resize_quick(hmp, chain, nradix);
1180 hammer2_chain_modify_quick(hmp, chain);
1181 }
1182 bp->b_bio2.bio_offset = chain->bref.data_off &
1183 HAMMER2_OFF_MASK;
1184 hammer2_chain_drop(hmp, chain);
1185 bdwrite(bp);
1186 hammer2_chain_put(hmp, parent);
3ac6a319
MD
1187 }
1188}
1189
e118c14f 1190static
703720e4 1191int
e118c14f 1192hammer2_vop_nresolve(struct vop_nresolve_args *ap)
703720e4 1193{
37494cab
MD
1194 hammer2_inode_t *dip;
1195 hammer2_mount_t *hmp;
1196 hammer2_chain_t *parent;
1197 hammer2_chain_t *chain;
1198 struct namecache *ncp;
1199 const uint8_t *name;
1200 size_t name_len;
1201 hammer2_key_t lhc;
1202 int error = 0;
1203 struct vnode *vp;
1204
1205 dip = VTOI(ap->a_dvp);
1206 hmp = dip->hmp;
1207 ncp = ap->a_nch->ncp;
1208 name = ncp->nc_name;
1209 name_len = ncp->nc_nlen;
1210 lhc = hammer2_dirhash(name, name_len);
1211
1212 /*
1213 * Note: In DragonFly the kernel handles '.' and '..'.
1214 */
1215 parent = &dip->chain;
1216 hammer2_chain_ref(hmp, parent);
1217 hammer2_chain_lock(hmp, parent);
1218 chain = hammer2_chain_lookup(hmp, &parent,
c667909f
MD
1219 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
1220 0);
37494cab
MD
1221 while (chain) {
1222 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
1223 chain->u.ip &&
1224 name_len == chain->data->ipdata.name_len &&
1225 bcmp(name, chain->data->ipdata.filename, name_len) == 0) {
1226 break;
1227 }
1228 chain = hammer2_chain_next(hmp, &parent, chain,
c667909f
MD
1229 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
1230 0);
37494cab
MD
1231 }
1232 hammer2_chain_put(hmp, parent);
1233
1234 if (chain) {
1235 vp = hammer2_igetv(chain->u.ip, &error);
1236 if (error == 0) {
1237 vn_unlock(vp);
1238 cache_setvp(ap->a_nch, vp);
1239 vrele(vp);
1240 }
1241 hammer2_chain_put(hmp, chain);
1242 } else {
1243 error = ENOENT;
1244 cache_setvp(ap->a_nch, NULL);
1245 }
1246 return error;
1247}
1248
1249static
1250int
1251hammer2_vop_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
1252{
1253 hammer2_inode_t *dip;
1254 hammer2_inode_t *ip;
1255 hammer2_mount_t *hmp;
1256 int error;
1257
1258 dip = VTOI(ap->a_dvp);
1259 hmp = dip->hmp;
1260
1261 if ((ip = dip->pip) == NULL) {
1262 *ap->a_vpp = NULL;
1263 return ENOENT;
1264 }
1265 hammer2_chain_ref(hmp, &ip->chain);
1266 hammer2_chain_lock(hmp, &ip->chain);
1267 *ap->a_vpp = hammer2_igetv(ip, &error);
1268 hammer2_chain_put(hmp, &ip->chain);
1269
1270 return error;
1271}
1272
1273static
1274int
1275hammer2_vop_nmkdir(struct vop_nmkdir_args *ap)
1276{
1277 hammer2_mount_t *hmp;
1278 hammer2_inode_t *dip;
1279 hammer2_inode_t *nip;
1280 struct namecache *ncp;
1281 const uint8_t *name;
1282 size_t name_len;
1283 int error;
1284
1285 dip = VTOI(ap->a_dvp);
1286 hmp = dip->hmp;
db71f61f
MD
1287 if (hmp->ronly)
1288 return (EROFS);
1289
37494cab
MD
1290 ncp = ap->a_nch->ncp;
1291 name = ncp->nc_name;
1292 name_len = ncp->nc_nlen;
1293
db0c2eb3 1294 error = hammer2_inode_create(hmp, ap->a_vap, ap->a_cred,
37494cab
MD
1295 dip, name, name_len, &nip);
1296 if (error) {
1297 KKASSERT(nip == NULL);
1298 *ap->a_vpp = NULL;
1299 return error;
1300 }
1301 *ap->a_vpp = hammer2_igetv(nip, &error);
1302 hammer2_chain_put(hmp, &nip->chain);
1303
1304 if (error == 0) {
1305 cache_setunresolved(ap->a_nch);
1306 cache_setvp(ap->a_nch, *ap->a_vpp);
1307 }
1308 return error;
703720e4
MD
1309}
1310
db71f61f
MD
1311/*
1312 * Return the largest contiguous physical disk range for the logical
1313 * request.
1314 *
1315 * (struct vnode *vp, off_t loffset, off_t *doffsetp, int *runp, int *runb)
1316 */
e118c14f 1317static
703720e4 1318int
e118c14f 1319hammer2_vop_bmap(struct vop_bmap_args *ap)
703720e4 1320{
db71f61f
MD
1321 struct vnode *vp;
1322 hammer2_mount_t *hmp;
1323 hammer2_inode_t *ip;
1324 hammer2_chain_t *parent;
1325 hammer2_chain_t *chain;
6ba3b984
MD
1326 hammer2_key_t lbeg;
1327 hammer2_key_t lend;
1328 hammer2_off_t pbeg;
1329 hammer2_off_t pbytes;
1330 hammer2_off_t array[HAMMER2_BMAP_COUNT][2];
1331 int loff;
1332 int ai;
db71f61f
MD
1333
1334 /*
1335 * Only supported on regular files
1336 *
1337 * Only supported for read operations (required for cluster_read).
1338 * The block allocation is delayed for write operations.
1339 */
1340 vp = ap->a_vp;
1341 if (vp->v_type != VREG)
1342 return (EOPNOTSUPP);
1343 if (ap->a_cmd != BUF_CMD_READ)
1344 return (EOPNOTSUPP);
1345
1346 ip = VTOI(vp);
1347 hmp = ip->hmp;
6ba3b984 1348 bzero(array, sizeof(array));
5b4a2132 1349
6ba3b984
MD
1350 /*
1351 * Calculate logical range
1352 */
1353 KKASSERT((ap->a_loffset & HAMMER2_LBUFMASK64) == 0);
1354 lbeg = ap->a_loffset & HAMMER2_OFF_MASK_HI;
1355 lend = lbeg + HAMMER2_BMAP_COUNT * HAMMER2_PBUFSIZE - 1;
1356 if (lend < lbeg)
1357 lend = lbeg;
1358 loff = ap->a_loffset & HAMMER2_OFF_MASK_LO;
db71f61f
MD
1359
1360 parent = &ip->chain;
1361 hammer2_chain_ref(hmp, parent);
1362 hammer2_chain_lock(hmp, parent);
6ba3b984
MD
1363 chain = hammer2_chain_lookup(hmp, &parent,
1364 lbeg, lend,
1365 HAMMER2_LOOKUP_NOLOCK);
3ac6a319 1366 if (chain == NULL) {
3ac6a319 1367 *ap->a_doffsetp = ZFOFFSET;
6ba3b984
MD
1368 hammer2_chain_put(hmp, parent);
1369 return (0);
1370 }
1371
1372 while (chain) {
1373 if (chain->bref.type == HAMMER2_BREF_TYPE_DATA) {
1374 ai = (chain->bref.key - lbeg) / HAMMER2_PBUFSIZE;
1375 KKASSERT(ai >= 0 && ai < HAMMER2_BMAP_COUNT);
1376 array[ai][0] = chain->bref.data_off & HAMMER2_OFF_MASK;
1377 array[ai][1] = chain->bytes;
1378 }
1379 chain = hammer2_chain_next(hmp, &parent, chain,
1380 lbeg, lend,
1381 HAMMER2_LOOKUP_NOLOCK);
db71f61f
MD
1382 }
1383 hammer2_chain_put(hmp, parent);
6ba3b984
MD
1384
1385 /*
1386 * If the requested loffset is not mappable physically we can't
1387 * bmap. The caller will have to access the file data via a
1388 * device buffer.
1389 */
1390 if (array[0][0] == 0 || array[0][1] < loff + HAMMER2_LBUFSIZE) {
1391 *ap->a_doffsetp = NOOFFSET;
1392 return (0);
1393 }
1394
1395 /*
1396 * Calculate the physical disk offset range for array[0]
1397 */
1398 pbeg = array[0][0] + loff;
1399 pbytes = array[0][1] - loff;
1400
1401 for (ai = 1; ai < HAMMER2_BMAP_COUNT; ++ai) {
1402 if (array[ai][0] != pbeg + pbytes)
1403 break;
1404 pbytes += array[ai][1];
1405 }
1406
1407 *ap->a_doffsetp = pbeg;
1408 if (ap->a_runp)
1409 *ap->a_runp = pbytes;
db71f61f 1410 return (0);
703720e4
MD
1411}
1412
e118c14f 1413static
703720e4 1414int
e118c14f 1415hammer2_vop_open(struct vop_open_args *ap)
703720e4 1416{
703720e4
MD
1417 return vop_stdopen(ap);
1418}
1419
37aa19df 1420/*
db0c2eb3 1421 * hammer2_vop_advlock { vp, id, op, fl, flags }
37aa19df
MD
1422 */
1423static
1424int
1425hammer2_vop_advlock(struct vop_advlock_args *ap)
1426{
1427 hammer2_inode_t *ip = VTOI(ap->a_vp);
1428
1429 return (lf_advlock(ap, &ip->advlock, ip->ip_data.size));
1430}
1431
1432
c667909f
MD
1433static
1434int
1435hammer2_vop_close(struct vop_close_args *ap)
1436{
1437 return vop_stdclose(ap);
1438}
1439
1440/*
db0c2eb3
MD
1441 * hammer2_vop_nlink { nch, dvp, vp, cred }
1442 *
1443 * Create a hardlink to vp.
1444 */
1445static
1446int
1447hammer2_vop_nlink(struct vop_nlink_args *ap)
1448{
1449 hammer2_inode_t *dip;
1450 hammer2_inode_t *ip; /* inode we are hardlinking to */
1451 hammer2_mount_t *hmp;
1452 struct namecache *ncp;
1453 const uint8_t *name;
1454 size_t name_len;
1455 int error;
1456
1457 dip = VTOI(ap->a_dvp);
1458 hmp = dip->hmp;
1459 if (hmp->ronly)
1460 return (EROFS);
1461
1462 ip = VTOI(ap->a_vp);
1463
1464 ncp = ap->a_nch->ncp;
1465 name = ncp->nc_name;
1466 name_len = ncp->nc_nlen;
1467
1468 error = hammer2_hardlink_create(ip, dip, name, name_len);
1469 if (error == 0) {
1470 cache_setunresolved(ap->a_nch);
1471 cache_setvp(ap->a_nch, ap->a_vp);
1472 }
1473 return error;
1474}
1475
1476/*
1477 * hammer2_vop_ncreate { nch, dvp, vpp, cred, vap }
c667909f
MD
1478 *
1479 * The operating system has already ensured that the directory entry
1480 * does not exist and done all appropriate namespace locking.
1481 */
1482static
1483int
1484hammer2_vop_ncreate(struct vop_ncreate_args *ap)
1485{
1486 hammer2_mount_t *hmp;
1487 hammer2_inode_t *dip;
1488 hammer2_inode_t *nip;
1489 struct namecache *ncp;
1490 const uint8_t *name;
1491 size_t name_len;
1492 int error;
1493
1494 dip = VTOI(ap->a_dvp);
1495 hmp = dip->hmp;
1496 if (hmp->ronly)
1497 return (EROFS);
1498
1499 ncp = ap->a_nch->ncp;
1500 name = ncp->nc_name;
1501 name_len = ncp->nc_nlen;
1502
db0c2eb3 1503 error = hammer2_inode_create(hmp, ap->a_vap, ap->a_cred,
c667909f
MD
1504 dip, name, name_len, &nip);
1505 if (error) {
1506 KKASSERT(nip == NULL);
1507 *ap->a_vpp = NULL;
1508 return error;
1509 }
1510 *ap->a_vpp = hammer2_igetv(nip, &error);
1511 hammer2_chain_put(hmp, &nip->chain);
1512
1513 if (error == 0) {
1514 cache_setunresolved(ap->a_nch);
1515 cache_setvp(ap->a_nch, *ap->a_vpp);
1516 }
1517 return error;
1518}
1519
4e2004ea
MD
1520/*
1521 * hammer2_vop_nsymlink { nch, dvp, vpp, cred, vap, target }
1522 */
1523static
1524int
1525hammer2_vop_nsymlink(struct vop_nsymlink_args *ap)
1526{
1527 hammer2_mount_t *hmp;
1528 hammer2_inode_t *dip;
1529 hammer2_inode_t *nip;
1530 struct namecache *ncp;
1531 const uint8_t *name;
1532 size_t name_len;
1533 int error;
1534
1535 dip = VTOI(ap->a_dvp);
1536 hmp = dip->hmp;
1537 if (hmp->ronly)
1538 return (EROFS);
1539
1540 ncp = ap->a_nch->ncp;
1541 name = ncp->nc_name;
1542 name_len = ncp->nc_nlen;
1543
1544 ap->a_vap->va_type = VLNK; /* enforce type */
1545
db0c2eb3 1546 error = hammer2_inode_create(hmp, ap->a_vap, ap->a_cred,
4e2004ea
MD
1547 dip, name, name_len, &nip);
1548 if (error) {
1549 KKASSERT(nip == NULL);
1550 *ap->a_vpp = NULL;
1551 return error;
1552 }
1553 *ap->a_vpp = hammer2_igetv(nip, &error);
1554
1555 /*
1556 * Build the softlink (~like file data) and finalize the namecache.
1557 */
1558 if (error == 0) {
1559 size_t bytes;
1560 struct uio auio;
1561 struct iovec aiov;
1562
1563 bytes = strlen(ap->a_target);
1564
1565 if (bytes <= HAMMER2_EMBEDDED_BYTES) {
1566 KKASSERT(nip->ip_data.op_flags &
1567 HAMMER2_OPFLAG_DIRECTDATA);
1568 bcopy(ap->a_target, nip->ip_data.u.data, bytes);
1569 nip->ip_data.size = bytes;
1570 } else {
1571 bzero(&auio, sizeof(auio));
1572 bzero(&aiov, sizeof(aiov));
1573 auio.uio_iov = &aiov;
1574 auio.uio_segflg = UIO_SYSSPACE;
1575 auio.uio_rw = UIO_WRITE;
1576 auio.uio_resid = bytes;
1577 auio.uio_iovcnt = 1;
1578 auio.uio_td = curthread;
1579 aiov.iov_base = ap->a_target;
1580 aiov.iov_len = bytes;
1581 error = hammer2_write_file(nip, &auio, IO_APPEND);
1582 /* XXX handle error */
1583 error = 0;
1584 }
1585 }
1586 hammer2_chain_put(hmp, &nip->chain);
1587
1588 /*
1589 * Finalize namecache
1590 */
1591 if (error == 0) {
1592 cache_setunresolved(ap->a_nch);
1593 cache_setvp(ap->a_nch, *ap->a_vpp);
1594 /* hammer2_knote(ap->a_dvp, NOTE_WRITE); */
1595 }
1596 return error;
1597}
1598
1599/*
1600 * hammer2_vop_nremove { nch, dvp, cred }
1601 */
1602static
1603int
1604hammer2_vop_nremove(struct vop_nremove_args *ap)
1605{
1606 hammer2_inode_t *dip;
1607 hammer2_mount_t *hmp;
1608 struct namecache *ncp;
1609 const uint8_t *name;
1610 size_t name_len;
1611 int error;
1612
1613 dip = VTOI(ap->a_dvp);
1614 hmp = dip->hmp;
1615 if (hmp->ronly)
1616 return(EROFS);
1617
1618 ncp = ap->a_nch->ncp;
1619 name = ncp->nc_name;
1620 name_len = ncp->nc_nlen;
1621
db0c2eb3 1622 error = hammer2_unlink_file(dip, name, name_len, 0, 1);
4e2004ea
MD
1623
1624 if (error == 0) {
1625 cache_setunresolved(ap->a_nch);
1626 cache_setvp(ap->a_nch, NULL);
1627 }
1628 return (error);
1629}
1630
1631/*
1632 * hammer2_vop_nrmdir { nch, dvp, cred }
1633 */
1634static
1635int
1636hammer2_vop_nrmdir(struct vop_nrmdir_args *ap)
1637{
1638 hammer2_inode_t *dip;
1639 hammer2_mount_t *hmp;
1640 struct namecache *ncp;
1641 const uint8_t *name;
1642 size_t name_len;
1643 int error;
1644
1645 dip = VTOI(ap->a_dvp);
1646 hmp = dip->hmp;
1647 if (hmp->ronly)
1648 return(EROFS);
1649
1650 ncp = ap->a_nch->ncp;
1651 name = ncp->nc_name;
1652 name_len = ncp->nc_nlen;
1653
db0c2eb3 1654 error = hammer2_unlink_file(dip, name, name_len, 1, 1);
4e2004ea
MD
1655
1656 if (error == 0) {
1657 cache_setunresolved(ap->a_nch);
1658 cache_setvp(ap->a_nch, NULL);
1659 }
1660 return (error);
1661}
1662
6934ae32
MD
1663/*
1664 * hammer2_vop_nrename { fnch, tnch, fdvp, tdvp, cred }
1665 */
4e2004ea
MD
1666static
1667int
1668hammer2_vop_nrename(struct vop_nrename_args *ap)
1669{
6934ae32
MD
1670 struct namecache *fncp;
1671 struct namecache *tncp;
1672 hammer2_inode_t *fdip;
1673 hammer2_inode_t *tdip;
1674 hammer2_inode_t *ip;
1675 hammer2_mount_t *hmp;
1676 const uint8_t *fname;
1677 size_t fname_len;
1678 const uint8_t *tname;
1679 size_t tname_len;
1680 int error;
1681
1682 if (ap->a_fdvp->v_mount != ap->a_tdvp->v_mount)
1683 return(EXDEV);
1684 if (ap->a_fdvp->v_mount != ap->a_fnch->ncp->nc_vp->v_mount)
1685 return(EXDEV);
1686
1687 fdip = VTOI(ap->a_fdvp); /* source directory */
1688 tdip = VTOI(ap->a_tdvp); /* target directory */
1689
1690 hmp = fdip->hmp; /* check read-only filesystem */
1691 if (hmp->ronly)
1692 return(EROFS);
1693
1694 fncp = ap->a_fnch->ncp; /* entry name in source */
1695 fname = fncp->nc_name;
1696 fname_len = fncp->nc_nlen;
1697
1698 tncp = ap->a_tnch->ncp; /* entry name in target */
1699 tname = tncp->nc_name;
1700 tname_len = tncp->nc_nlen;
1701
1702 ip = VTOI(fncp->nc_vp); /* inode being moved */
1703
1704 /*
1705 * Keep a tight grip on the inode as removing it should disconnect
1706 * it and we don't want to destroy it.
222d9e22
MD
1707 *
1708 * NOTE: To avoid deadlocks we cannot lock (ip) while we are
1709 * unlinking elements from their directories.
6934ae32
MD
1710 */
1711 hammer2_chain_ref(hmp, &ip->chain);
6934ae32
MD
1712
1713 /*
1714 * Remove target if it exists
1715 */
db0c2eb3 1716 error = hammer2_unlink_file(tdip, tname, tname_len, -1, 1);
6934ae32
MD
1717 if (error && error != ENOENT)
1718 goto done;
1719 cache_setunresolved(ap->a_tnch);
1720 cache_setvp(ap->a_tnch, NULL);
1721
1722 /*
db0c2eb3
MD
1723 * Disconnect ip from the source directory, do not adjust
1724 * the link count. Note that rename doesn't need to understand
1725 * whether this is a hardlink or not, we can just rename the
1726 * forwarding entry and don't even have to adjust the related
1727 * hardlink's link count.
6934ae32 1728 */
db0c2eb3 1729 error = hammer2_unlink_file(fdip, fname, fname_len, -1, 0);
6934ae32
MD
1730 if (error)
1731 goto done;
1732
1733 if (ip->chain.parent != NULL)
1734 panic("hammer2_vop_nrename(): rename source != ip!");
1735
1736 /*
1737 * Reconnect ip to target directory.
1738 */
222d9e22 1739 hammer2_chain_lock(hmp, &ip->chain);
db0c2eb3 1740 error = hammer2_inode_connect(tdip, ip, tname, tname_len);
6934ae32
MD
1741
1742 if (error == 0) {
1743 cache_rename(ap->a_fnch, ap->a_tnch);
1744 }
6934ae32 1745 hammer2_chain_unlock(hmp, &ip->chain);
222d9e22 1746done:
6934ae32
MD
1747 hammer2_chain_drop(hmp, &ip->chain);
1748
1749 return (error);
4e2004ea
MD
1750}
1751
6934ae32
MD
1752/*
1753 * Unlink the file from the specified directory inode. The directory inode
1754 * does not need to be locked.
db0c2eb3
MD
1755 *
1756 * isdir determines whether a directory/non-directory check should be made.
1757 * No check is made if isdir is set to -1.
1758 *
1759 * adjlinks tells unlink that we want to adjust the nlinks count of the
1760 * inode. When removing the last link for a NON forwarding entry we can
1761 * just ignore the link count... no point updating the inode that we are
1762 * about to dereference, it would just result in a lot of wasted I/O.
1763 *
1764 * However, if the entry is a forwarding entry (aka a hardlink), and adjlinks
1765 * is non-zero, we have to locate the hardlink and adjust its nlinks field.
6934ae32 1766 */
4e2004ea
MD
1767static
1768int
1769hammer2_unlink_file(hammer2_inode_t *dip, const uint8_t *name, size_t name_len,
db0c2eb3 1770 int isdir, int adjlinks)
4e2004ea
MD
1771{
1772 hammer2_mount_t *hmp;
1773 hammer2_chain_t *parent;
1774 hammer2_chain_t *chain;
1775 hammer2_chain_t *dparent;
1776 hammer2_chain_t *dchain;
1777 hammer2_key_t lhc;
4e2004ea
MD
1778 int error;
1779
1780 error = 0;
4e2004ea
MD
1781
1782 hmp = dip->hmp;
1783 lhc = hammer2_dirhash(name, name_len);
1784
1785 /*
1786 * Search for the filename in the directory
1787 */
1788 parent = &dip->chain;
1789 hammer2_chain_ref(hmp, parent);
1790 hammer2_chain_lock(hmp, parent);
1791 chain = hammer2_chain_lookup(hmp, &parent,
1792 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
1793 0);
1794 while (chain) {
1795 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
1796 chain->u.ip &&
1797 name_len == chain->data->ipdata.name_len &&
1798 bcmp(name, chain->data->ipdata.filename, name_len) == 0) {
1799 break;
1800 }
1801 chain = hammer2_chain_next(hmp, &parent, chain,
1802 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
1803 0);
1804 }
1805
1806 /*
6934ae32 1807 * Not found or wrong type (isdir < 0 disables the type check).
4e2004ea
MD
1808 */
1809 if (chain == NULL) {
1810 hammer2_chain_put(hmp, parent);
1811 return ENOENT;
1812 }
6934ae32
MD
1813 if (chain->data->ipdata.type == HAMMER2_OBJTYPE_DIRECTORY &&
1814 isdir == 0) {
4e2004ea
MD
1815 error = ENOTDIR;
1816 goto done;
1817 }
6934ae32
MD
1818 if (chain->data->ipdata.type != HAMMER2_OBJTYPE_DIRECTORY &&
1819 isdir == 1) {
4e2004ea
MD
1820 error = EISDIR;
1821 goto done;
1822 }
1823
1824 /*
6934ae32
MD
1825 * If this is a directory the directory must be empty. However, if
1826 * isdir < 0 we are doing a rename and the directory does not have
1827 * to be empty.
4e2004ea 1828 */
6934ae32
MD
1829 if (chain->data->ipdata.type == HAMMER2_OBJTYPE_DIRECTORY &&
1830 isdir >= 0) {
4e2004ea
MD
1831 dparent = chain;
1832 hammer2_chain_ref(hmp, dparent);
1833 hammer2_chain_lock(hmp, dparent);
1834 dchain = hammer2_chain_lookup(hmp, &dparent,
1835 0, (hammer2_key_t)-1,
1836 HAMMER2_LOOKUP_NOLOCK);
1837 if (dchain) {
1838 hammer2_chain_drop(hmp, dchain);
1839 hammer2_chain_put(hmp, dparent);
1840 error = ENOTEMPTY;
1841 goto done;
1842 }
1843 hammer2_chain_put(hmp, dparent);
1844 dparent = NULL;
1845 /* dchain NULL */
1846 }
1847
db0c2eb3
MD
1848#if 0
1849 /*
1850 * If adjlinks is non-zero this is a real deletion (otherwise it is
1851 * probably a rename). XXX
1852 */
1853 if (adjlinks) {
1854 if (chain->data->ipdata.type == HAMMER2_OBJTYPE_HARDLINK) {
1855 /*hammer2_adjust_hardlink(chain->u.ip, -1);*/
1856 /* error handling */
1857 } else {
1858 waslastlink = 1;
1859 }
1860 } else {
1861 waslastlink = 0;
1862 }
1863#endif
1864
4e2004ea
MD
1865 /*
1866 * Found, the chain represents the inode. Remove the parent reference
1867 * to the chain. The chain itself is no longer referenced and will
1868 * be marked unmodified by hammer2_chain_delete(), avoiding unnecessary
1869 * I/O.
1870 */
1871 hammer2_chain_delete(hmp, parent, chain);
1872 /* XXX nlinks (hardlink special case) */
1873 /* XXX nlinks (parent directory) */
1874
db0c2eb3
MD
1875#if 0
1876 /*
1877 * Destroy any associated vnode, but only if this was the last
1878 * link. XXX this might not be needed.
1879 */
6934ae32 1880 if (chain->u.ip->vp) {
db0c2eb3 1881 struct vnode *vp;
6934ae32
MD
1882 vp = hammer2_igetv(chain->u.ip, &error);
1883 if (error == 0) {
1884 vn_unlock(vp);
1885 /* hammer2_knote(vp, NOTE_DELETE); */
1886 cache_inval_vp(vp, CINV_DESTROY);
1887 vrele(vp);
1888 }
4e2004ea 1889 }
db0c2eb3 1890#endif
4e2004ea
MD
1891 error = 0;
1892
1893done:
1894 hammer2_chain_put(hmp, chain);
1895 hammer2_chain_put(hmp, parent);
1896
1897 return error;
1898}
1899
1900
db71f61f
MD
1901static int hammer2_strategy_read(struct vop_strategy_args *ap);
1902static int hammer2_strategy_write(struct vop_strategy_args *ap);
1903
e118c14f 1904static
703720e4 1905int
e118c14f 1906hammer2_vop_strategy(struct vop_strategy_args *ap)
703720e4 1907{
703720e4
MD
1908 struct bio *biop;
1909 struct buf *bp;
703720e4
MD
1910 int error;
1911
703720e4
MD
1912 biop = ap->a_bio;
1913 bp = biop->bio_buf;
703720e4
MD
1914
1915 switch(bp->b_cmd) {
9c2e0de0 1916 case BUF_CMD_READ:
db71f61f
MD
1917 error = hammer2_strategy_read(ap);
1918 break;
9c2e0de0 1919 case BUF_CMD_WRITE:
db71f61f
MD
1920 error = hammer2_strategy_write(ap);
1921 break;
703720e4
MD
1922 default:
1923 bp->b_error = error = EINVAL;
1924 bp->b_flags |= B_ERROR;
1925 biodone(biop);
1926 break;
1927 }
1928
1929 return (error);
1930}
1931
db71f61f
MD
1932static
1933int
1934hammer2_strategy_read(struct vop_strategy_args *ap)
1935{
1936 struct buf *bp;
1937 struct bio *bio;
1938 struct bio *nbio;
1939 hammer2_mount_t *hmp;
1940 hammer2_inode_t *ip;
1941 hammer2_chain_t *parent;
1942 hammer2_chain_t *chain;
8cce658d 1943 hammer2_key_t lbase;
db71f61f
MD
1944
1945 bio = ap->a_bio;
1946 bp = bio->bio_buf;
1947 ip = VTOI(ap->a_vp);
1948 hmp = ip->hmp;
1949 nbio = push_bio(bio);
1950
8cce658d 1951 lbase = bio->bio_offset;
866d5273 1952 chain = NULL;
8cce658d 1953 KKASSERT(((int)lbase & HAMMER2_PBUFMASK) == 0);
db71f61f 1954
866d5273
MD
1955 /*
1956 * We must characterize the logical->physical translation if it
1957 * has not already been cached.
1958 *
1959 * Physical data references < LBUFSIZE are never cached. This
1960 * includes both small-block allocations and inode-embedded data.
1961 */
1962 if (nbio->bio_offset == NOOFFSET) {
db71f61f
MD
1963 parent = &ip->chain;
1964 hammer2_chain_ref(hmp, parent);
1965 hammer2_chain_lock(hmp, parent);
c667909f
MD
1966
1967 /*
1968 * Specifying NOLOCK avoids unnecessary bread()s of the
1969 * chain element's content. We just need the block device
1970 * offset.
1971 */
8cce658d 1972 chain = hammer2_chain_lookup(hmp, &parent, lbase, lbase,
c667909f 1973 HAMMER2_LOOKUP_NOLOCK);
3ac6a319
MD
1974 if (chain == NULL) {
1975 /*
1976 * Data is zero-fill
1977 */
1978 nbio->bio_offset = ZFOFFSET;
3ac6a319
MD
1979 } else if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
1980 /*
8cce658d 1981 * Data is embedded in the inode (do nothing)
3ac6a319 1982 */
3ac6a319 1983 KKASSERT(chain == parent);
8cce658d 1984 hammer2_chain_drop(hmp, chain);
866d5273
MD
1985 } else if (chain->bref.type == HAMMER2_BREF_TYPE_DATA) {
1986 /*
1987 * Data is on-media
866d5273 1988 */
8cce658d
MD
1989 KKASSERT(bp->b_bcount == chain->bytes);
1990 nbio->bio_offset = chain->bref.data_off &
1991 HAMMER2_OFF_MASK;
1992 hammer2_chain_drop(hmp, chain);
1993 KKASSERT(nbio->bio_offset != 0);
db71f61f 1994 } else {
3ac6a319 1995 panic("hammer2_strategy_read: unknown bref type");
db71f61f
MD
1996 }
1997 hammer2_chain_put(hmp, parent);
1998 }
866d5273
MD
1999
2000 if (nbio->bio_offset == ZFOFFSET) {
3ac6a319 2001 /*
866d5273 2002 * Data is zero-fill
3ac6a319
MD
2003 */
2004 bp->b_resid = 0;
2005 bp->b_error = 0;
8cce658d 2006 bzero(bp->b_data, bp->b_bcount);
3ac6a319 2007 biodone(nbio);
866d5273 2008 } else if (nbio->bio_offset != NOOFFSET) {
3ac6a319 2009 /*
8cce658d 2010 * Forward direct IO to the device
3ac6a319 2011 */
866d5273 2012 vn_strategy(hmp->devvp, nbio);
8cce658d 2013 } else {
866d5273 2014 /*
8cce658d 2015 * Data is embedded in inode.
866d5273 2016 */
8cce658d
MD
2017 bcopy(chain->data->ipdata.u.data, bp->b_data,
2018 HAMMER2_EMBEDDED_BYTES);
2019 bzero(bp->b_data + HAMMER2_EMBEDDED_BYTES,
2020 bp->b_bcount - HAMMER2_EMBEDDED_BYTES);
db71f61f
MD
2021 bp->b_resid = 0;
2022 bp->b_error = 0;
db71f61f 2023 biodone(nbio);
db71f61f
MD
2024 }
2025 return (0);
2026}
2027
2028static
2029int
2030hammer2_strategy_write(struct vop_strategy_args *ap)
2031{
2032 struct buf *bp;
2033 struct bio *bio;
2034 struct bio *nbio;
2035 hammer2_mount_t *hmp;
2036 hammer2_inode_t *ip;
db71f61f
MD
2037
2038 bio = ap->a_bio;
2039 bp = bio->bio_buf;
2040 ip = VTOI(ap->a_vp);
2041 hmp = ip->hmp;
2042 nbio = push_bio(bio);
2043
8cce658d
MD
2044 KKASSERT((bio->bio_offset & HAMMER2_PBUFMASK64) == 0);
2045 KKASSERT(nbio->bio_offset != 0 && nbio->bio_offset != ZFOFFSET);
db71f61f 2046
8cce658d 2047 if (nbio->bio_offset == NOOFFSET) {
3ac6a319 2048 /*
8cce658d 2049 * Must be embedded in the inode.
3ac6a319 2050 */
8cce658d
MD
2051 KKASSERT(bio->bio_offset == 0);
2052 bcopy(bp->b_data, ip->ip_data.u.data, HAMMER2_EMBEDDED_BYTES);
2053 bp->b_resid = 0;
2054 bp->b_error = 0;
2055 biodone(nbio);
214f4a77
MD
2056
2057 /*
2058 * This special flag does not follow the normal MODIFY1 rules
2059 * because we might deadlock on ip. Instead we depend on
2060 * VOP_FSYNC() to detect the case.
2061 */
2062 atomic_set_int(&ip->chain.flags, HAMMER2_CHAIN_DIRTYEMBED);
8cce658d 2063 } else {
3ac6a319 2064 /*
8cce658d 2065 * Forward direct IO to the device
3ac6a319 2066 */
8cce658d 2067 vn_strategy(hmp->devvp, nbio);
a92f82c4 2068 }
db71f61f
MD
2069 return (0);
2070}
2071
e118c14f 2072static
f0206a67 2073int
e118c14f 2074hammer2_vop_mountctl(struct vop_mountctl_args *ap)
f0206a67
VS
2075{
2076 struct mount *mp;
2077 struct hammer2_mount *hmp;
2078 int rc;
2079
2080 switch (ap->a_op) {
2081 case (MOUNTCTL_SET_EXPORT):
2082 mp = ap->a_head.a_ops->head.vv_mount;
2083 hmp = MPTOH2(mp);
2084
2085 if (ap->a_ctllen != sizeof(struct export_args))
2086 rc = (EINVAL);
2087 else
10c5dee0
MD
2088 rc = vfs_export(mp, &hmp->export,
2089 (const struct export_args *)ap->a_ctl);
f0206a67
VS
2090 break;
2091 default:
2092 rc = vop_stdmountctl(ap);
2093 break;
2094 }
2095 return (rc);
2096}
2097
703720e4
MD
2098struct vop_ops hammer2_vnode_vops = {
2099 .vop_default = vop_defaultop,
e118c14f 2100 .vop_fsync = hammer2_vop_fsync,
703720e4
MD
2101 .vop_getpages = vop_stdgetpages,
2102 .vop_putpages = vop_stdputpages,
e118c14f 2103 .vop_access = hammer2_vop_access,
37aa19df 2104 .vop_advlock = hammer2_vop_advlock,
c667909f 2105 .vop_close = hammer2_vop_close,
db0c2eb3 2106 .vop_nlink = hammer2_vop_nlink,
c667909f 2107 .vop_ncreate = hammer2_vop_ncreate,
4e2004ea
MD
2108 .vop_nsymlink = hammer2_vop_nsymlink,
2109 .vop_nremove = hammer2_vop_nremove,
2110 .vop_nrmdir = hammer2_vop_nrmdir,
2111 .vop_nrename = hammer2_vop_nrename,
e118c14f 2112 .vop_getattr = hammer2_vop_getattr,
3ac6a319 2113 .vop_setattr = hammer2_vop_setattr,
e118c14f 2114 .vop_readdir = hammer2_vop_readdir,
4e2004ea 2115 .vop_readlink = hammer2_vop_readlink,
5b4a2132
MD
2116 .vop_getpages = vop_stdgetpages,
2117 .vop_putpages = vop_stdputpages,
e118c14f
MD
2118 .vop_read = hammer2_vop_read,
2119 .vop_write = hammer2_vop_write,
2120 .vop_open = hammer2_vop_open,
2121 .vop_inactive = hammer2_vop_inactive,
2122 .vop_reclaim = hammer2_vop_reclaim,
2123 .vop_nresolve = hammer2_vop_nresolve,
37494cab
MD
2124 .vop_nlookupdotdot = hammer2_vop_nlookupdotdot,
2125 .vop_nmkdir = hammer2_vop_nmkdir,
e118c14f
MD
2126 .vop_mountctl = hammer2_vop_mountctl,
2127 .vop_bmap = hammer2_vop_bmap,
2128 .vop_strategy = hammer2_vop_strategy,
703720e4
MD
2129};
2130
2131struct vop_ops hammer2_spec_vops = {
2132
2133};
2134
2135struct vop_ops hammer2_fifo_vops = {
2136
2137};