| Commit | Line | Data |
|---|---|---|
| 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 | 54 | static |
| 703720e4 | 55 | int |
| e118c14f | 56 | hammer2_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 | 82 | static |
| 703720e4 | 83 | int |
| e118c14f | 84 | hammer2_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 | 112 | static |
| 703720e4 | 113 | int |
| e118c14f | 114 | hammer2_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 | 131 | static |
| 703720e4 | 132 | int |
| e118c14f | 133 | hammer2_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 | 148 | static |
| 703720e4 | 149 | int |
| e118c14f | 150 | hammer2_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 | 193 | static |
| 703720e4 | 194 | int |
| e118c14f | 195 | hammer2_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 |
330 | done: |
| 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 | 349 | static |
| 703720e4 | 350 | int |
| e118c14f | 351 | hammer2_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 | 410 | static |
| 47902fef | 411 | int |
| e118c14f | 412 | hammer2_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 | 592 | static |
| 703720e4 | 593 | int |
| e118c14f | 594 | hammer2_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 | ||
| 651 | static | |
| 652 | int | |
| 653 | hammer2_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 | ||
| 675 | static | |
| 676 | int | |
| 677 | hammer2_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 | 719 | static |
| 703720e4 | 720 | int |
| e118c14f | 721 | hammer2_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 | 765 | static |
| 703720e4 | 766 | int |
| e118c14f | 767 | hammer2_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 | */ | |
| 777 | static | |
| 778 | int | |
| 779 | hammer2_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 |
787 | static |
| 788 | int | |
| 789 | hammer2_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 | */ | |
| 800 | static | |
| 801 | int | |
| 802 | hammer2_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 |
838 | static int hammer2_strategy_read(struct vop_strategy_args *ap); |
| 839 | static int hammer2_strategy_write(struct vop_strategy_args *ap); | |
| 840 | ||
| e118c14f | 841 | static |
| 703720e4 | 842 | int |
| e118c14f | 843 | hammer2_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 | 869 | static |
| db71f61f MD |
870 | int |
| 871 | hammer2_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 | ||
| 925 | static | |
| 926 | int | |
| 927 | hammer2_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 | ||
| 982 | static | |
| f0206a67 | 983 | int |
| e118c14f | 984 | hammer2_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 |
1008 | struct 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 | ||
| 1034 | struct vop_ops hammer2_spec_vops = { | |
| 1035 | ||
| 1036 | }; | |
| 1037 | ||
| 1038 | struct vop_ops hammer2_fifo_vops = { | |
| 1039 | ||
| 1040 | }; |