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