hammer2 - more indirect block work, add advlock
[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>
703720e4
MD
46
47#include "hammer2.h"
48
db71f61f
MD
49#define ZFOFFSET (-2LL)
50
703720e4
MD
51/*
52 * Last reference to a vnode is going away but it is still cached.
53 */
e118c14f 54static
703720e4 55int
e118c14f 56hammer2_vop_inactive(struct vop_inactive_args *ap)
703720e4
MD
57{
58 struct vnode *vp;
59 struct hammer2_inode *ip;
e118c14f 60#if 0
703720e4 61 struct hammer2_mount *hmp;
e118c14f 62#endif
703720e4 63
703720e4
MD
64 vp = ap->a_vp;
65 ip = VTOI(vp);
703720e4 66
df9ea374
MD
67 /*
68 * Degenerate case
69 */
70 if (ip == NULL) {
71 vrecycle(vp);
72 return (0);
73 }
74
703720e4
MD
75 return (0);
76}
77
78/*
79 * Reclaim a vnode so that it can be reused; after the inode is
80 * disassociated, the filesystem must manage it alone.
81 */
e118c14f 82static
703720e4 83int
e118c14f 84hammer2_vop_reclaim(struct vop_reclaim_args *ap)
703720e4 85{
703720e4
MD
86 struct hammer2_inode *ip;
87 struct hammer2_mount *hmp;
b7926f31 88 struct vnode *vp;
703720e4 89
703720e4
MD
90 vp = ap->a_vp;
91 ip = VTOI(vp);
9c2e0de0
MD
92 if (ip == NULL)
93 return(0);
9c2e0de0 94 hmp = ip->hmp;
b7926f31 95
54eb943b 96 hammer2_inode_lock_ex(ip);
703720e4 97 vp->v_data = NULL;
0e92b724 98 ip->vp = NULL;
b7926f31 99 hammer2_chain_flush(hmp, &ip->chain, NULL);
54eb943b 100 hammer2_inode_unlock_ex(ip);
9c2e0de0 101 hammer2_chain_drop(hmp, &ip->chain); /* vp ref removed */
54eb943b
MD
102
103 /*
104 * XXX handle background sync when ip dirty, kernel will no longer
105 * notify us regarding this inode because there is no longer a
106 * vnode attached to it.
107 */
703720e4
MD
108
109 return (0);
110}
111
e118c14f 112static
703720e4 113int
e118c14f 114hammer2_vop_fsync(struct vop_fsync_args *ap)
703720e4 115{
b7926f31
MD
116 struct hammer2_inode *ip;
117 struct hammer2_mount *hmp;
118 struct vnode *vp;
119
120 vp = ap->a_vp;
121 ip = VTOI(vp);
122 hmp = ip->hmp;
123
124 hammer2_inode_lock_ex(ip);
125 vfsync(vp, ap->a_waitfor, 1, NULL, NULL);
126 hammer2_chain_flush(hmp, &ip->chain, NULL);
127 hammer2_inode_unlock_ex(ip);
128 return (0);
703720e4
MD
129}
130
e118c14f 131static
703720e4 132int
e118c14f 133hammer2_vop_access(struct vop_access_args *ap)
703720e4 134{
37494cab
MD
135 hammer2_inode_t *ip = VTOI(ap->a_vp);
136 uid_t uid;
137 gid_t gid;
138 int error;
139
140 uid = hammer2_to_unix_xid(&ip->ip_data.uid);
141 gid = hammer2_to_unix_xid(&ip->ip_data.gid);
142
143 error = vop_helper_access(ap, uid, gid, ip->ip_data.mode,
144 ip->ip_data.uflags);
145 return (error);
703720e4
MD
146}
147
e118c14f 148static
703720e4 149int
e118c14f 150hammer2_vop_getattr(struct vop_getattr_args *ap)
703720e4 151{
cd4b3d92
MD
152 hammer2_mount_t *hmp;
153 hammer2_inode_t *ip;
703720e4
MD
154 struct vnode *vp;
155 struct vattr *vap;
703720e4
MD
156
157 vp = ap->a_vp;
158 vap = ap->a_vap;
159
cd4b3d92
MD
160 ip = VTOI(vp);
161 hmp = ip->hmp;
162
703720e4
MD
163 hammer2_inode_lock_sh(ip);
164
cd4b3d92
MD
165 vap->va_fsid = hmp->mp->mnt_stat.f_fsid.val[0];
166 vap->va_fileid = ip->ip_data.inum;
167 vap->va_mode = ip->ip_data.mode;
168 vap->va_nlink = ip->ip_data.nlinks;
703720e4
MD
169 vap->va_uid = 0;
170 vap->va_gid = 0;
cd4b3d92
MD
171 vap->va_rmajor = 0;
172 vap->va_rminor = 0;
173 vap->va_size = ip->ip_data.size;
df9ea374 174 vap->va_blocksize = HAMMER2_PBUFSIZE;
cd4b3d92
MD
175 vap->va_flags = ip->ip_data.uflags;
176 hammer2_time_to_timespec(ip->ip_data.ctime, &vap->va_ctime);
177 hammer2_time_to_timespec(ip->ip_data.mtime, &vap->va_mtime);
178 hammer2_time_to_timespec(ip->ip_data.mtime, &vap->va_atime);
179 vap->va_gen = 1;
180 vap->va_bytes = vap->va_size;
181 vap->va_type = hammer2_get_vtype(ip);
182 vap->va_filerev = 0;
183 vap->va_uid_uuid = ip->ip_data.uid;
184 vap->va_gid_uuid = ip->ip_data.gid;
185 vap->va_vaflags = VA_UID_UUID_VALID | VA_GID_UUID_VALID |
186 VA_FSID_UUID_VALID;
703720e4
MD
187
188 hammer2_inode_unlock_sh(ip);
189
190 return (0);
191}
192
e118c14f 193static
703720e4 194int
e118c14f 195hammer2_vop_readdir(struct vop_readdir_args *ap)
703720e4 196{
e028fa74
MD
197 hammer2_mount_t *hmp;
198 hammer2_inode_t *ip;
199 hammer2_inode_t *xip;
200 hammer2_chain_t *parent;
201 hammer2_chain_t *chain;
202 hammer2_key_t lkey;
203 struct uio *uio;
204 off_t *cookies;
205 off_t saveoff;
206 int cookie_index;
207 int ncookies;
208 int error;
209 int dtype;
210 int r;
211
212 ip = VTOI(ap->a_vp);
213 hmp = ip->hmp;
214 uio = ap->a_uio;
215 saveoff = uio->uio_offset;
216
217 /*
218 * Setup cookies directory entry cookies if requested
219 */
220 if (ap->a_ncookies) {
221 ncookies = uio->uio_resid / 16 + 1;
222 if (ncookies > 1024)
223 ncookies = 1024;
224 cookies = kmalloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
225 } else {
226 ncookies = -1;
227 cookies = NULL;
228 }
229 cookie_index = 0;
230
231 /*
232 * Handle artificial entries. To ensure that only positive 64 bit
233 * quantities are returned to userland we always strip off bit 63.
234 * The hash code is designed such that codes 0x0000-0x7FFF are not
235 * used, allowing us to use these codes for articial entries.
236 *
237 * Entry 0 is used for '.' and entry 1 is used for '..'. Do not
238 * allow '..' to cross the mount point into (e.g.) the super-root.
239 */
240 error = 0;
37aa19df 241 chain = (void *)(intptr_t)-1; /* non-NULL for early goto done case */
e028fa74
MD
242
243 if (saveoff == 0) {
244 r = vop_write_dirent(&error, uio,
245 ip->ip_data.inum &
246 HAMMER2_DIRHASH_USERMSK,
247 DT_DIR, 1, ".");
248 if (r)
249 goto done;
250 if (cookies)
251 cookies[cookie_index] = saveoff;
252 ++saveoff;
253 ++cookie_index;
254 if (cookie_index == ncookies)
255 goto done;
256 }
257 if (saveoff == 1) {
258 if (ip->pip == NULL || ip == hmp->iroot)
259 xip = ip;
260 else
261 xip = ip->pip;
262
263 r = vop_write_dirent(&error, uio,
264 xip->ip_data.inum &
265 HAMMER2_DIRHASH_USERMSK,
266 DT_DIR, 2, "..");
267 if (r)
268 goto done;
269 if (cookies)
270 cookies[cookie_index] = saveoff;
271 ++saveoff;
272 ++cookie_index;
273 if (cookie_index == ncookies)
274 goto done;
275 }
276
277 lkey = saveoff | HAMMER2_DIRHASH_VISIBLE;
278
279 parent = &ip->chain;
280 hammer2_chain_ref(hmp, parent);
281 error = hammer2_chain_lock(hmp, parent);
282 if (error) {
283 hammer2_chain_put(hmp, parent);
284 goto done;
285 }
37aa19df
MD
286 chain = hammer2_chain_lookup(hmp, &parent, lkey, lkey, 0);
287 if (chain == NULL) {
288 chain = hammer2_chain_lookup(hmp, &parent,
289 lkey, (hammer2_key_t)-1, 0);
290 }
e028fa74 291 while (chain) {
c667909f
MD
292 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
293 dtype = hammer2_get_dtype(chain->u.ip);
294 saveoff = chain->bref.key & HAMMER2_DIRHASH_USERMSK;
295 r = vop_write_dirent(&error, uio,
296 chain->u.ip->ip_data.inum &
297 HAMMER2_DIRHASH_USERMSK,
298 dtype, chain->u.ip->ip_data.name_len,
299 chain->u.ip->ip_data.filename);
300 if (r)
301 break;
302 if (cookies)
303 cookies[cookie_index] = saveoff;
304 ++cookie_index;
305 } else {
306 /* XXX chain error */
307 kprintf("bad chain type readdir %d\n",
308 chain->bref.type);
309 }
995e78dc
MD
310
311 /*
312 * Keys may not be returned in order so once we have a
313 * placemarker (chain) the scan must allow the full range
314 * or some entries will be missed.
315 */
e028fa74 316 chain = hammer2_chain_next(hmp, &parent, chain,
995e78dc 317 0, (hammer2_key_t)-1, 0);
028a55bb
MD
318 if (chain) {
319 saveoff = (chain->bref.key &
320 HAMMER2_DIRHASH_USERMSK) + 1;
321 } else {
322 saveoff = (hammer2_key_t)-1;
323 }
324 if (cookie_index == ncookies)
325 break;
e028fa74
MD
326 }
327 hammer2_chain_put(hmp, parent);
028a55bb
MD
328 if (chain)
329 hammer2_chain_put(hmp, chain);
e028fa74
MD
330done:
331 if (ap->a_eofflag)
332 *ap->a_eofflag = (chain == NULL);
37aa19df 333 uio->uio_offset = saveoff & ~HAMMER2_DIRHASH_VISIBLE;
e028fa74
MD
334 if (error && cookie_index == 0) {
335 if (cookies) {
336 kfree(cookies, M_TEMP);
337 *ap->a_ncookies = 0;
338 *ap->a_cookies = NULL;
339 }
340 } else {
341 if (cookies) {
342 *ap->a_ncookies = cookie_index;
343 *ap->a_cookies = cookies;
344 }
345 }
346 return (error);
703720e4
MD
347}
348
e118c14f 349static
703720e4 350int
e118c14f 351hammer2_vop_read(struct vop_read_args *ap)
703720e4 352{
db71f61f
MD
353 struct vnode *vp;
354 hammer2_mount_t *hmp;
355 hammer2_inode_t *ip;
356 struct buf *bp;
357 struct uio *uio;
358 int error;
359 int seqcount;
360 int bigread;
361
362 /*
363 * Read operations supported on this vnode?
364 */
365 vp = ap->a_vp;
366 if (vp->v_type != VREG)
367 return (EINVAL);
368
369 /*
370 * Misc
371 */
372 ip = VTOI(vp);
373 hmp = ip->hmp;
374 uio = ap->a_uio;
375 error = 0;
376
377 seqcount = ap->a_ioflag >> 16;
378 bigread = (uio->uio_resid > 100 * 1024 * 1024);
379
380 /*
381 * UIO read loop
382 */
383 while (uio->uio_resid > 0 && uio->uio_offset < ip->ip_data.size) {
384 hammer2_key_t off_hi;
385 int off_lo;
386 int n;
387
388 off_hi = uio->uio_offset & ~HAMMER2_LBUFMASK64;
389 off_lo = (int)(uio->uio_offset & HAMMER2_LBUFMASK64);
390
391 /* XXX bigread & signal check test */
392
393 error = cluster_read(vp, ip->ip_data.size, off_hi,
394 HAMMER2_LBUFSIZE, HAMMER2_PBUFSIZE,
395 seqcount * BKVASIZE, &bp);
396 if (error)
397 break;
398 n = HAMMER2_LBUFSIZE - off_lo;
399 if (n > uio->uio_resid)
400 n = uio->uio_resid;
401 if (n > ip->ip_data.size - uio->uio_offset)
402 n = (int)(ip->ip_data.size - uio->uio_offset);
403 bp->b_flags |= B_AGE;
404 uiomove((char *)bp->b_data + off_lo, n, uio);
c667909f 405 bqrelse(bp);
db71f61f
MD
406 }
407 return (error);
47902fef 408}
703720e4 409
e118c14f 410static
47902fef 411int
e118c14f 412hammer2_vop_write(struct vop_write_args *ap)
47902fef 413{
db71f61f
MD
414 thread_t td;
415 struct vnode *vp;
416 hammer2_mount_t *hmp;
417 hammer2_inode_t *ip;
418 struct buf *bp;
419 struct uio *uio;
420 int error;
421 int kflags;
422 int seqcount;
423 int bigwrite;
424
425 /*
426 * Read operations supported on this vnode?
427 */
428 vp = ap->a_vp;
429 if (vp->v_type != VREG)
430 return (EINVAL);
431
432 /*
433 * Misc
434 */
435 ip = VTOI(vp);
436 hmp = ip->hmp;
437 uio = ap->a_uio;
438 error = 0;
439 kflags = 0;
440 if (hmp->ronly)
441 return (EROFS);
442
443 seqcount = ap->a_ioflag >> 16;
444 bigwrite = (uio->uio_resid > 100 * 1024 * 1024);
445
446 /*
447 * Check resource limit
448 */
449 if (uio->uio_resid > 0 && (td = uio->uio_td) != NULL && td->td_proc &&
450 uio->uio_offset + uio->uio_resid >
451 td->td_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
452 lwpsignal(td->td_proc, td->td_lwp, SIGXFSZ);
453 return (EFBIG);
454 }
455
456 bigwrite = (uio->uio_resid > 100 * 1024 * 1024);
457
458 /*
459 * UIO read loop
460 */
461 while (uio->uio_resid > 0) {
462 hammer2_key_t nsize;
463 hammer2_key_t off_hi;
464 int fixsize;
465 int off_lo;
466 int n;
467 int trivial;
468 int endofblk;
469
470 off_hi = uio->uio_offset & ~HAMMER2_LBUFMASK64;
471 off_lo = (int)(uio->uio_offset & HAMMER2_LBUFMASK64);
472
473 n = HAMMER2_LBUFSIZE - off_lo;
474 if (n > uio->uio_resid) {
475 n = uio->uio_resid;
476 endofblk = 0;
477 } else {
478 endofblk = 1;
479 }
480 nsize = uio->uio_offset + n;
481
482 /* XXX bigwrite & signal check test */
483
484 /*
485 * Don't allow the buffer build to blow out the buffer
486 * cache.
487 */
488 if ((ap->a_ioflag & IO_RECURSE) == 0)
489 bwillwrite(HAMMER2_LBUFSIZE);
490
491 /*
492 * Extend the size of the file as needed
493 * XXX lock.
494 */
495 if (nsize > ip->ip_data.size) {
496 if (uio->uio_offset > ip->ip_data.size)
497 trivial = 0;
498 else
499 trivial = 1;
500 nvextendbuf(vp, ip->ip_data.size, nsize,
501 HAMMER2_LBUFSIZE, HAMMER2_LBUFSIZE,
502 (int)(ip->ip_data.size & HAMMER2_LBUFMASK),
503 (int)(nsize),
504 trivial);
505 kflags |= NOTE_EXTEND;
506 fixsize = 1;
507 } else {
508 fixsize = 0;
509 }
510
511 if (uio->uio_segflg == UIO_NOCOPY) {
512 /*
513 * Issuing a write with the same data backing the
514 * buffer. Instantiate the buffer to collect the
515 * backing vm pages, then read-in any missing bits.
516 *
517 * This case is used by vop_stdputpages().
518 */
519 bp = getblk(vp, off_hi,
520 HAMMER2_LBUFSIZE, GETBLK_BHEAVY, 0);
521 if ((bp->b_flags & B_CACHE) == 0) {
522 bqrelse(bp);
523 error = bread(ap->a_vp,
524 off_hi, HAMMER2_LBUFSIZE, &bp);
525 }
526 } else if (off_lo == 0 && uio->uio_resid >= HAMMER2_LBUFSIZE) {
527 /*
528 * Even though we are entirely overwriting the buffer
529 * we may still have to zero it out to avoid a
530 * mmap/write visibility issue.
531 */
532 bp = getblk(vp, off_hi,
533 HAMMER2_LBUFSIZE, GETBLK_BHEAVY, 0);
534 if ((bp->b_flags & B_CACHE) == 0)
535 vfs_bio_clrbuf(bp);
536 } else if (off_hi >= ip->ip_data.size) {
537 /*
538 * If the base offset of the buffer is beyond the
539 * file EOF, we don't have to issue a read.
540 */
541 bp = getblk(vp, off_hi,
542 HAMMER2_LBUFSIZE, GETBLK_BHEAVY, 0);
543 vfs_bio_clrbuf(bp);
544 } else {
545 /*
546 * Partial overwrite, read in any missing bits then
547 * replace the portion being written.
548 */
549 error = bread(vp, off_hi, HAMMER2_LBUFSIZE, &bp);
550 if (error == 0)
551 bheavy(bp);
552 }
553
554 if (error == 0) {
555 /* release lock */
556 error = uiomove(bp->b_data + off_lo, n, uio);
557 /* acquire lock */
558 }
559
560 if (error) {
561 brelse(bp);
562 if (fixsize) {
563 nvtruncbuf(vp, ip->ip_data.size,
564 HAMMER2_LBUFSIZE, HAMMER2_LBUFSIZE);
565 }
566 break;
567 }
568 kflags |= NOTE_WRITE;
569 if (ip->ip_data.size < uio->uio_offset)
570 ip->ip_data.size = uio->uio_offset;
571 /* XXX update ino_data.mtime */
572
573 /*
574 * Once we dirty a buffer any cached offset becomes invalid.
575 */
576 bp->b_bio2.bio_offset = NOOFFSET;
577 bp->b_flags |= B_AGE;
578 if (ap->a_ioflag & IO_SYNC) {
579 bwrite(bp);
580 } else if ((ap->a_ioflag & IO_DIRECT) && endofblk) {
581 bawrite(bp);
582 } else if (ap->a_ioflag & IO_ASYNC) {
583 bawrite(bp);
584 } else {
585 bdwrite(bp);
586 }
587 }
588 /* hammer2_knote(vp, kflags); */
589 return (error);
703720e4
MD
590}
591
e118c14f 592static
703720e4 593int
e118c14f 594hammer2_vop_nresolve(struct vop_nresolve_args *ap)
703720e4 595{
37494cab
MD
596 hammer2_inode_t *dip;
597 hammer2_mount_t *hmp;
598 hammer2_chain_t *parent;
599 hammer2_chain_t *chain;
600 struct namecache *ncp;
601 const uint8_t *name;
602 size_t name_len;
603 hammer2_key_t lhc;
604 int error = 0;
605 struct vnode *vp;
606
607 dip = VTOI(ap->a_dvp);
608 hmp = dip->hmp;
609 ncp = ap->a_nch->ncp;
610 name = ncp->nc_name;
611 name_len = ncp->nc_nlen;
612 lhc = hammer2_dirhash(name, name_len);
613
614 /*
615 * Note: In DragonFly the kernel handles '.' and '..'.
616 */
617 parent = &dip->chain;
618 hammer2_chain_ref(hmp, parent);
619 hammer2_chain_lock(hmp, parent);
620 chain = hammer2_chain_lookup(hmp, &parent,
c667909f
MD
621 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
622 0);
37494cab
MD
623 while (chain) {
624 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
625 chain->u.ip &&
626 name_len == chain->data->ipdata.name_len &&
627 bcmp(name, chain->data->ipdata.filename, name_len) == 0) {
628 break;
629 }
630 chain = hammer2_chain_next(hmp, &parent, chain,
c667909f
MD
631 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
632 0);
37494cab
MD
633 }
634 hammer2_chain_put(hmp, parent);
635
636 if (chain) {
637 vp = hammer2_igetv(chain->u.ip, &error);
638 if (error == 0) {
639 vn_unlock(vp);
640 cache_setvp(ap->a_nch, vp);
641 vrele(vp);
642 }
643 hammer2_chain_put(hmp, chain);
644 } else {
645 error = ENOENT;
646 cache_setvp(ap->a_nch, NULL);
647 }
648 return error;
649}
650
651static
652int
653hammer2_vop_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
654{
655 hammer2_inode_t *dip;
656 hammer2_inode_t *ip;
657 hammer2_mount_t *hmp;
658 int error;
659
660 dip = VTOI(ap->a_dvp);
661 hmp = dip->hmp;
662
663 if ((ip = dip->pip) == NULL) {
664 *ap->a_vpp = NULL;
665 return ENOENT;
666 }
667 hammer2_chain_ref(hmp, &ip->chain);
668 hammer2_chain_lock(hmp, &ip->chain);
669 *ap->a_vpp = hammer2_igetv(ip, &error);
670 hammer2_chain_put(hmp, &ip->chain);
671
672 return error;
673}
674
675static
676int
677hammer2_vop_nmkdir(struct vop_nmkdir_args *ap)
678{
679 hammer2_mount_t *hmp;
680 hammer2_inode_t *dip;
681 hammer2_inode_t *nip;
682 struct namecache *ncp;
683 const uint8_t *name;
684 size_t name_len;
685 int error;
686
687 dip = VTOI(ap->a_dvp);
688 hmp = dip->hmp;
db71f61f
MD
689 if (hmp->ronly)
690 return (EROFS);
691
37494cab
MD
692 ncp = ap->a_nch->ncp;
693 name = ncp->nc_name;
694 name_len = ncp->nc_nlen;
695
696 error = hammer2_create_inode(hmp, ap->a_vap, ap->a_cred,
697 dip, name, name_len, &nip);
698 if (error) {
699 KKASSERT(nip == NULL);
700 *ap->a_vpp = NULL;
701 return error;
702 }
703 *ap->a_vpp = hammer2_igetv(nip, &error);
704 hammer2_chain_put(hmp, &nip->chain);
705
706 if (error == 0) {
707 cache_setunresolved(ap->a_nch);
708 cache_setvp(ap->a_nch, *ap->a_vpp);
709 }
710 return error;
703720e4
MD
711}
712
db71f61f
MD
713/*
714 * Return the largest contiguous physical disk range for the logical
715 * request.
716 *
717 * (struct vnode *vp, off_t loffset, off_t *doffsetp, int *runp, int *runb)
718 */
e118c14f 719static
703720e4 720int
e118c14f 721hammer2_vop_bmap(struct vop_bmap_args *ap)
703720e4 722{
db71f61f
MD
723 struct vnode *vp;
724 hammer2_mount_t *hmp;
725 hammer2_inode_t *ip;
726 hammer2_chain_t *parent;
727 hammer2_chain_t *chain;
5b4a2132
MD
728 hammer2_key_t loff;
729 hammer2_off_t poff;
db71f61f
MD
730
731 /*
732 * Only supported on regular files
733 *
734 * Only supported for read operations (required for cluster_read).
735 * The block allocation is delayed for write operations.
736 */
737 vp = ap->a_vp;
738 if (vp->v_type != VREG)
739 return (EOPNOTSUPP);
740 if (ap->a_cmd != BUF_CMD_READ)
741 return (EOPNOTSUPP);
742
743 ip = VTOI(vp);
744 hmp = ip->hmp;
5b4a2132
MD
745
746 loff = ap->a_loffset;
747 KKASSERT((loff & HAMMER2_LBUFMASK64) == 0);
db71f61f
MD
748
749 parent = &ip->chain;
750 hammer2_chain_ref(hmp, parent);
751 hammer2_chain_lock(hmp, parent);
5b4a2132 752 chain = hammer2_chain_lookup(hmp, &parent, loff, loff, 0);
db71f61f 753 if (chain) {
5b4a2132
MD
754 poff = loff - chain->bref.key +
755 (chain->bref.data_off & HAMMER2_OFF_MASK);
756 *ap->a_doffsetp = poff;
db71f61f
MD
757 hammer2_chain_put(hmp, chain);
758 } else {
759 *ap->a_doffsetp = ZFOFFSET; /* zero-fill hole */
760 }
761 hammer2_chain_put(hmp, parent);
762 return (0);
703720e4
MD
763}
764
e118c14f 765static
703720e4 766int
e118c14f 767hammer2_vop_open(struct vop_open_args *ap)
703720e4 768{
703720e4
MD
769 return vop_stdopen(ap);
770}
771
37aa19df
MD
772/*
773 * hammer_vop_advlock { vp, id, op, fl, flags }
774 *
775 * MPSAFE - does not require fs_token
776 */
777static
778int
779hammer2_vop_advlock(struct vop_advlock_args *ap)
780{
781 hammer2_inode_t *ip = VTOI(ap->a_vp);
782
783 return (lf_advlock(ap, &ip->advlock, ip->ip_data.size));
784}
785
786
c667909f
MD
787static
788int
789hammer2_vop_close(struct vop_close_args *ap)
790{
791 return vop_stdclose(ap);
792}
793
794/*
795 * hammer_vop_ncreate { nch, dvp, vpp, cred, vap }
796 *
797 * The operating system has already ensured that the directory entry
798 * does not exist and done all appropriate namespace locking.
799 */
800static
801int
802hammer2_vop_ncreate(struct vop_ncreate_args *ap)
803{
804 hammer2_mount_t *hmp;
805 hammer2_inode_t *dip;
806 hammer2_inode_t *nip;
807 struct namecache *ncp;
808 const uint8_t *name;
809 size_t name_len;
810 int error;
811
812 dip = VTOI(ap->a_dvp);
813 hmp = dip->hmp;
814 if (hmp->ronly)
815 return (EROFS);
816
817 ncp = ap->a_nch->ncp;
818 name = ncp->nc_name;
819 name_len = ncp->nc_nlen;
820
821 error = hammer2_create_inode(hmp, ap->a_vap, ap->a_cred,
822 dip, name, name_len, &nip);
823 if (error) {
824 KKASSERT(nip == NULL);
825 *ap->a_vpp = NULL;
826 return error;
827 }
828 *ap->a_vpp = hammer2_igetv(nip, &error);
829 hammer2_chain_put(hmp, &nip->chain);
830
831 if (error == 0) {
832 cache_setunresolved(ap->a_nch);
833 cache_setvp(ap->a_nch, *ap->a_vpp);
834 }
835 return error;
836}
837
db71f61f
MD
838static int hammer2_strategy_read(struct vop_strategy_args *ap);
839static int hammer2_strategy_write(struct vop_strategy_args *ap);
840
e118c14f 841static
703720e4 842int
e118c14f 843hammer2_vop_strategy(struct vop_strategy_args *ap)
703720e4 844{
703720e4
MD
845 struct bio *biop;
846 struct buf *bp;
703720e4
MD
847 int error;
848
703720e4
MD
849 biop = ap->a_bio;
850 bp = biop->bio_buf;
703720e4
MD
851
852 switch(bp->b_cmd) {
9c2e0de0 853 case BUF_CMD_READ:
db71f61f
MD
854 error = hammer2_strategy_read(ap);
855 break;
9c2e0de0 856 case BUF_CMD_WRITE:
db71f61f
MD
857 error = hammer2_strategy_write(ap);
858 break;
703720e4
MD
859 default:
860 bp->b_error = error = EINVAL;
861 bp->b_flags |= B_ERROR;
862 biodone(biop);
863 break;
864 }
865
866 return (error);
867}
868
e118c14f 869static
db71f61f
MD
870int
871hammer2_strategy_read(struct vop_strategy_args *ap)
872{
873 struct buf *bp;
874 struct bio *bio;
875 struct bio *nbio;
876 hammer2_mount_t *hmp;
877 hammer2_inode_t *ip;
878 hammer2_chain_t *parent;
879 hammer2_chain_t *chain;
5b4a2132
MD
880 hammer2_key_t loff;
881 hammer2_off_t poff;
db71f61f
MD
882
883 bio = ap->a_bio;
884 bp = bio->bio_buf;
885 ip = VTOI(ap->a_vp);
886 hmp = ip->hmp;
887 nbio = push_bio(bio);
888
889 if (nbio->bio_offset == NOOFFSET) {
5b4a2132
MD
890 loff = bio->bio_offset;
891 KKASSERT((loff & HAMMER2_LBUFMASK64) == 0);
db71f61f
MD
892
893 parent = &ip->chain;
894 hammer2_chain_ref(hmp, parent);
895 hammer2_chain_lock(hmp, parent);
c667909f
MD
896
897 /*
898 * Specifying NOLOCK avoids unnecessary bread()s of the
899 * chain element's content. We just need the block device
900 * offset.
901 */
5b4a2132 902 chain = hammer2_chain_lookup(hmp, &parent, loff, loff,
c667909f 903 HAMMER2_LOOKUP_NOLOCK);
db71f61f 904 if (chain) {
5b4a2132
MD
905 poff = loff - chain->bref.key +
906 (chain->bref.data_off & HAMMER2_OFF_MASK);
907 nbio->bio_offset = poff;
c667909f 908 hammer2_chain_drop(hmp, chain);
db71f61f
MD
909 } else {
910 nbio->bio_offset = ZFOFFSET;
911 }
912 hammer2_chain_put(hmp, parent);
913 }
914 if (nbio->bio_offset == ZFOFFSET) {
915 bp->b_resid = 0;
916 bp->b_error = 0;
917 vfs_bio_clrbuf(bp);
918 biodone(nbio);
919 } else {
920 vn_strategy(hmp->devvp, nbio);
921 }
922 return (0);
923}
924
925static
926int
927hammer2_strategy_write(struct vop_strategy_args *ap)
928{
929 struct buf *bp;
930 struct bio *bio;
931 struct bio *nbio;
932 hammer2_mount_t *hmp;
933 hammer2_inode_t *ip;
934 hammer2_chain_t *parent;
935 hammer2_chain_t *chain;
936 hammer2_key_t off_hi;
937 int off_lo;
938
939 bio = ap->a_bio;
940 bp = bio->bio_buf;
941 ip = VTOI(ap->a_vp);
942 hmp = ip->hmp;
943 nbio = push_bio(bio);
944
945 /*
946 * Our bmap doesn't support writes atm, and a vop_write should
947 * clear the physical disk offset cache for the copy-on-write
948 * operation.
949 */
950 KKASSERT(nbio->bio_offset == NOOFFSET);
951
952 off_hi = bio->bio_offset & HAMMER2_OFF_MASK_HI;
953 off_lo = bio->bio_offset & HAMMER2_OFF_MASK_LO;
954 KKASSERT((bio->bio_offset & HAMMER2_LBUFMASK64) == 0);
955
956 parent = &ip->chain;
957 hammer2_chain_ref(hmp, parent);
958 hammer2_chain_lock(hmp, parent);
c667909f 959 chain = hammer2_chain_lookup(hmp, &parent, off_hi, off_hi, 0);
db71f61f
MD
960 if (chain) {
961 hammer2_chain_modify(hmp, chain);
962 bcopy(bp->b_data, chain->data->buf + off_lo, bp->b_bcount);
db71f61f
MD
963 } else {
964 chain = hammer2_chain_create(hmp, parent,
965 off_hi, HAMMER2_PBUFRADIX,
966 HAMMER2_BREF_TYPE_DATA,
967 HAMMER2_PBUFSIZE);
968 bcopy(bp->b_data, chain->data->buf + off_lo, bp->b_bcount);
db71f61f 969 }
37aa19df
MD
970 if (off_lo + bp->b_bcount == HAMMER2_PBUFSIZE)
971 atomic_set_int(&chain->flags, HAMMER2_CHAIN_IOFLUSH);
972 hammer2_chain_put(hmp, chain);
db71f61f
MD
973 hammer2_chain_put(hmp, parent);
974
975 bp->b_resid = 0;
976 bp->b_error = 0;
977 biodone(nbio);
978
979 return (0);
980}
981
982static
f0206a67 983int
e118c14f 984hammer2_vop_mountctl(struct vop_mountctl_args *ap)
f0206a67
VS
985{
986 struct mount *mp;
987 struct hammer2_mount *hmp;
988 int rc;
989
990 switch (ap->a_op) {
991 case (MOUNTCTL_SET_EXPORT):
992 mp = ap->a_head.a_ops->head.vv_mount;
993 hmp = MPTOH2(mp);
994
995 if (ap->a_ctllen != sizeof(struct export_args))
996 rc = (EINVAL);
997 else
10c5dee0
MD
998 rc = vfs_export(mp, &hmp->export,
999 (const struct export_args *)ap->a_ctl);
f0206a67
VS
1000 break;
1001 default:
1002 rc = vop_stdmountctl(ap);
1003 break;
1004 }
1005 return (rc);
1006}
1007
703720e4
MD
1008struct vop_ops hammer2_vnode_vops = {
1009 .vop_default = vop_defaultop,
e118c14f 1010 .vop_fsync = hammer2_vop_fsync,
703720e4
MD
1011 .vop_getpages = vop_stdgetpages,
1012 .vop_putpages = vop_stdputpages,
e118c14f 1013 .vop_access = hammer2_vop_access,
37aa19df 1014 .vop_advlock = hammer2_vop_advlock,
c667909f
MD
1015 .vop_close = hammer2_vop_close,
1016 .vop_ncreate = hammer2_vop_ncreate,
e118c14f
MD
1017 .vop_getattr = hammer2_vop_getattr,
1018 .vop_readdir = hammer2_vop_readdir,
5b4a2132
MD
1019 .vop_getpages = vop_stdgetpages,
1020 .vop_putpages = vop_stdputpages,
e118c14f
MD
1021 .vop_read = hammer2_vop_read,
1022 .vop_write = hammer2_vop_write,
1023 .vop_open = hammer2_vop_open,
1024 .vop_inactive = hammer2_vop_inactive,
1025 .vop_reclaim = hammer2_vop_reclaim,
1026 .vop_nresolve = hammer2_vop_nresolve,
37494cab
MD
1027 .vop_nlookupdotdot = hammer2_vop_nlookupdotdot,
1028 .vop_nmkdir = hammer2_vop_nmkdir,
e118c14f
MD
1029 .vop_mountctl = hammer2_vop_mountctl,
1030 .vop_bmap = hammer2_vop_bmap,
1031 .vop_strategy = hammer2_vop_strategy,
703720e4
MD
1032};
1033
1034struct vop_ops hammer2_spec_vops = {
1035
1036};
1037
1038struct vop_ops hammer2_fifo_vops = {
1039
1040};