Merge from vendor branch LESS:
[dragonfly.git] / sys / vfs / hammer / hammer_vnops.c
1 /*
2  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/sys/vfs/hammer/hammer_vnops.c,v 1.2 2007/11/07 00:43:24 dillon Exp $
35  */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/fcntl.h>
41 #include <sys/namecache.h>
42 #include <sys/vnode.h>
43 #include <sys/lockf.h>
44 #include <sys/event.h>
45 #include <sys/stat.h>
46 #include "hammer.h"
47
48 /*
49  * USERFS VNOPS
50  */
51 /*static int hammer_vop_vnoperate(struct vop_generic_args *);*/
52 static int hammer_vop_fsync(struct vop_fsync_args *);
53 static int hammer_vop_read(struct vop_read_args *);
54 static int hammer_vop_write(struct vop_write_args *);
55 static int hammer_vop_access(struct vop_access_args *);
56 static int hammer_vop_advlock(struct vop_advlock_args *);
57 static int hammer_vop_close(struct vop_close_args *);
58 static int hammer_vop_ncreate(struct vop_ncreate_args *);
59 static int hammer_vop_getattr(struct vop_getattr_args *);
60 static int hammer_vop_nresolve(struct vop_nresolve_args *);
61 static int hammer_vop_nlookupdotdot(struct vop_nlookupdotdot_args *);
62 static int hammer_vop_nlink(struct vop_nlink_args *);
63 static int hammer_vop_nmkdir(struct vop_nmkdir_args *);
64 static int hammer_vop_nmknod(struct vop_nmknod_args *);
65 static int hammer_vop_open(struct vop_open_args *);
66 static int hammer_vop_pathconf(struct vop_pathconf_args *);
67 static int hammer_vop_print(struct vop_print_args *);
68 static int hammer_vop_readdir(struct vop_readdir_args *);
69 static int hammer_vop_readlink(struct vop_readlink_args *);
70 static int hammer_vop_nremove(struct vop_nremove_args *);
71 static int hammer_vop_nrename(struct vop_nrename_args *);
72 static int hammer_vop_nrmdir(struct vop_nrmdir_args *);
73 static int hammer_vop_setattr(struct vop_setattr_args *);
74 static int hammer_vop_strategy(struct vop_strategy_args *);
75 static int hammer_vop_nsymlink(struct vop_nsymlink_args *);
76 static int hammer_vop_nwhiteout(struct vop_nwhiteout_args *);
77
78 struct vop_ops hammer_vnode_vops = {
79         .vop_default =          vop_defaultop,
80         .vop_fsync =            hammer_vop_fsync,
81         .vop_read =             hammer_vop_read,
82         .vop_write =            hammer_vop_write,
83         .vop_access =           hammer_vop_access,
84         .vop_advlock =          hammer_vop_advlock,
85         .vop_close =            hammer_vop_close,
86         .vop_ncreate =          hammer_vop_ncreate,
87         .vop_getattr =          hammer_vop_getattr,
88         .vop_inactive =         hammer_vop_inactive,
89         .vop_reclaim =          hammer_vop_reclaim,
90         .vop_nresolve =         hammer_vop_nresolve,
91         .vop_nlookupdotdot =    hammer_vop_nlookupdotdot,
92         .vop_nlink =            hammer_vop_nlink,
93         .vop_nmkdir =           hammer_vop_nmkdir,
94         .vop_nmknod =           hammer_vop_nmknod,
95         .vop_open =             hammer_vop_open,
96         .vop_pathconf =         hammer_vop_pathconf,
97         .vop_print =            hammer_vop_print,
98         .vop_readdir =          hammer_vop_readdir,
99         .vop_readlink =         hammer_vop_readlink,
100         .vop_nremove =          hammer_vop_nremove,
101         .vop_nrename =          hammer_vop_nrename,
102         .vop_nrmdir =           hammer_vop_nrmdir,
103         .vop_setattr =          hammer_vop_setattr,
104         .vop_strategy =         hammer_vop_strategy,
105         .vop_nsymlink =         hammer_vop_nsymlink,
106         .vop_nwhiteout =        hammer_vop_nwhiteout
107 };
108
109 #if 0
110 static
111 int
112 hammer_vop_vnoperate(struct vop_generic_args *)
113 {
114         return (VOCALL(&hammer_vnode_vops, ap));
115 }
116 #endif
117
118 /*
119  * hammer_vop_fsync { vp, waitfor }
120  */
121 static
122 int
123 hammer_vop_fsync(struct vop_fsync_args *ap)
124 {
125         return EOPNOTSUPP;
126 }
127
128 /*
129  * hammer_vop_read { vp, uio, ioflag, cred }
130  */
131 static
132 int
133 hammer_vop_read(struct vop_read_args *ap)
134 {
135         struct hammer_transaction trans;
136         struct hammer_inode *ip;
137         off_t offset;
138         struct buf *bp;
139         struct uio *uio;
140         int error;
141         int n;
142
143         if (ap->a_vp->v_type != VREG)
144                 return (EINVAL);
145         ip = VTOI(ap->a_vp);
146         error = 0;
147
148         hammer_start_transaction(ip->hmp, &trans);
149
150         /*
151          * Access the data in HAMMER_BUFSIZE blocks via the buffer cache.
152          */
153         uio = ap->a_uio;
154         while (uio->uio_resid > 0 && uio->uio_offset < ip->ino_rec.ino_size) {
155                 offset = uio->uio_offset & HAMMER_BUFMASK;
156                 error = bread(ap->a_vp, uio->uio_offset - offset,
157                               HAMMER_BUFSIZE, &bp);
158                 if (error) {
159                         brelse(bp);
160                         break;
161                 }
162                 n = HAMMER_BUFSIZE - offset;
163                 if (n > uio->uio_resid)
164                         n = uio->uio_resid;
165                 if (n > ip->ino_rec.ino_size - uio->uio_offset)
166                         n = (int)(ip->ino_rec.ino_size - uio->uio_offset);
167                 error = uiomove((char *)bp->b_data + offset, n, uio);
168                 if (error) {
169                         brelse(bp);
170                         break;
171                 }
172                 ip->ino_rec.ino_atime = trans.tid;
173                 hammer_modify_inode(&trans, ip, HAMMER_INODE_ITIMES);
174                 bqrelse(bp);
175         }
176         hammer_commit_transaction(&trans);
177         return (error);
178 }
179
180 /*
181  * hammer_vop_write { vp, uio, ioflag, cred }
182  */
183 static
184 int
185 hammer_vop_write(struct vop_write_args *ap)
186 {
187         struct hammer_transaction trans;
188         struct hammer_inode *ip;
189         struct uio *uio;
190         off_t offset;
191         struct buf *bp;
192         int error;
193         int n;
194
195         if (ap->a_vp->v_type != VREG)
196                 return (EINVAL);
197         ip = VTOI(ap->a_vp);
198         error = 0;
199
200         /*
201          * Create a transaction to cover the operations we perform.
202          */
203         hammer_start_transaction(ip->hmp, &trans);
204         uio = ap->a_uio;
205
206         /*
207          * Check append mode
208          */
209         if (ap->a_ioflag & IO_APPEND)
210                 uio->uio_offset = ip->ino_rec.ino_size;
211
212         /*
213          * Check for illegal write offsets.  Valid range is 0...2^63-1
214          */
215         if (uio->uio_offset < 0 || uio->uio_offset + uio->uio_resid <= 0)
216                 return (EFBIG);
217
218         /*
219          * Access the data in HAMMER_BUFSIZE blocks via the buffer cache.
220          */
221         while (uio->uio_resid > 0) {
222                 offset = uio->uio_offset & HAMMER_BUFMASK;
223                 if (offset == 0 && uio->uio_resid >= HAMMER_BUFSIZE) {
224                         bp = getblk(ap->a_vp, uio->uio_offset, HAMMER_BUFSIZE,
225                                     0, 0);
226                 } else if (offset == 0 && uio->uio_offset >= ip->ino_rec.ino_size) {
227                         bp = getblk(ap->a_vp, uio->uio_offset, HAMMER_BUFSIZE,
228                                     0, 0);
229                         vfs_bio_clrbuf(bp);
230                 } else {
231                         error = bread(ap->a_vp, uio->uio_offset - offset,
232                                       HAMMER_BUFSIZE, &bp);
233                         if (error) {
234                                 brelse(bp);
235                                 break;
236                         }
237                 }
238                 n = HAMMER_BUFSIZE - offset;
239                 if (n > uio->uio_resid)
240                         n = uio->uio_resid;
241                 error = uiomove((char *)bp->b_data + offset, n, uio);
242                 if (error) {
243                         brelse(bp);
244                         break;
245                 }
246                 if (ip->ino_rec.ino_size < uio->uio_offset) {
247                         ip->ino_rec.ino_size = uio->uio_offset;
248                         ip->ino_rec.ino_mtime = trans.tid;
249                         hammer_modify_inode(&trans, ip,
250                                 HAMMER_INODE_RDIRTY | HAMMER_INODE_ITIMES);
251                 }
252                 if (ap->a_ioflag & IO_SYNC) {
253                         bwrite(bp);
254                 } else if (ap->a_ioflag & IO_DIRECT) {
255                         /* XXX B_CLUSTEROK SUPPORT */
256                         bawrite(bp);
257                 } else {
258                         /* XXX B_CLUSTEROK SUPPORT */
259                         bdwrite(bp);
260                 }
261         }
262         if (error)
263                 hammer_abort_transaction(&trans);
264         else
265                 hammer_commit_transaction(&trans);
266         return (error);
267 }
268
269 /*
270  * hammer_vop_access { vp, mode, cred }
271  */
272 static
273 int
274 hammer_vop_access(struct vop_access_args *ap)
275 {
276         struct hammer_inode *ip = VTOI(ap->a_vp);
277         uid_t uid;
278         gid_t gid;
279         int error;
280
281         uid = hammer_to_unix_xid(&ip->ino_data.uid);
282         gid = hammer_to_unix_xid(&ip->ino_data.gid);
283
284         error = vop_helper_access(ap, uid, gid, ip->ino_data.mode,
285                                   ip->ino_data.uflags);
286         return (error);
287 }
288
289 /*
290  * hammer_vop_advlock { vp, id, op, fl, flags }
291  */
292 static
293 int
294 hammer_vop_advlock(struct vop_advlock_args *ap)
295 {
296         struct hammer_inode *ip = VTOI(ap->a_vp);
297
298         return (lf_advlock(ap, &ip->advlock, ip->ino_rec.ino_size));
299 }
300
301 /*
302  * hammer_vop_close { vp, fflag }
303  */
304 static
305 int
306 hammer_vop_close(struct vop_close_args *ap)
307 {
308         return EOPNOTSUPP;
309 }
310
311 /*
312  * hammer_vop_ncreate { nch, dvp, vpp, cred, vap }
313  *
314  * The operating system has already ensured that the directory entry
315  * does not exist and done all appropriate namespace locking.
316  */
317 static
318 int
319 hammer_vop_ncreate(struct vop_ncreate_args *ap)
320 {
321         struct hammer_transaction trans;
322         struct hammer_inode *dip;
323         struct hammer_inode *nip;
324         struct nchandle *nch;
325         int error;
326
327         nch = ap->a_nch;
328         dip = VTOI(ap->a_dvp);
329
330         /*
331          * Create a transaction to cover the operations we perform.
332          */
333         hammer_start_transaction(dip->hmp, &trans);
334
335         /*
336          * Create a new filesystem object of the requested type.  The
337          * returned inode will be locked.  We cannot hold the new
338          * inode locked while doing other manipulations.
339          */
340         error = hammer_alloc_inode(&trans, ap->a_vap, ap->a_cred, &nip);
341         if (error) {
342                 hammer_abort_transaction(&trans);
343                 *ap->a_vpp = NULL;
344                 return (error);
345         }
346         hammer_lock_to_ref(&nip->lock);
347
348         /*
349          * Add the new filesystem object to the directory.  This will also
350          * bump the inode's link count.
351          */
352         error = hammer_add_directory(&trans, dip, nch->ncp, nip);
353
354         /*
355          * Finish up.
356          */
357         if (error) {
358                 hammer_put_inode_ref(nip);
359                 hammer_abort_transaction(&trans);
360                 *ap->a_vpp = NULL;
361         } else {
362                 hammer_commit_transaction(&trans);
363                 error = hammer_get_vnode(nip, LK_EXCLUSIVE, ap->a_vpp);
364                 hammer_put_inode_ref(nip);
365         }
366         return (error);
367 }
368
369 /*
370  * hammer_vop_getattr { vp, vap }
371  */
372 static
373 int
374 hammer_vop_getattr(struct vop_getattr_args *ap)
375 {
376         struct hammer_inode *ip = VTOI(ap->a_vp);
377         struct vattr *vap = ap->a_vap;
378
379 #if 0
380         if (cache_check_fsmid_vp(ap->a_vp, &ip->fsmid) &&
381             (vp->v_mount->mnt_flag & MNT_RDONLY) == 0 &&
382             ip->obj_asof == 0
383         ) {
384                 /* LAZYMOD XXX */
385         }
386         hammer_itimes(ap->a_vp);
387 #endif
388
389         vap->va_fsid = ip->hmp->fsid_udev;
390         vap->va_fileid = ip->ino_rec.base.base.obj_id;
391         vap->va_mode = ip->ino_data.mode;
392         vap->va_nlink = ip->ino_rec.ino_nlinks;
393         vap->va_uid = hammer_to_unix_xid(&ip->ino_data.uid);
394         vap->va_gid = hammer_to_unix_xid(&ip->ino_data.gid);
395         vap->va_rmajor = 0;
396         vap->va_rminor = 0;
397         vap->va_size = ip->ino_rec.ino_size;
398         hammer_to_timespec(ip->ino_rec.ino_atime, &vap->va_atime);
399         hammer_to_timespec(ip->ino_rec.ino_mtime, &vap->va_mtime);
400         hammer_to_timespec(ip->ino_data.ctime, &vap->va_ctime);
401         vap->va_flags = ip->ino_data.uflags;
402         vap->va_gen = 1;        /* hammer inums are unique for all time */
403         vap->va_blocksize = 32768; /* XXX - extract from root volume */
404         vap->va_bytes = ip->ino_rec.ino_size;
405         vap->va_type = hammer_get_vnode_type(ip->ino_rec.base.base.obj_type);
406         vap->va_filerev = 0;    /* XXX */
407         /* mtime uniquely identifies any adjustments made to the file */
408         vap->va_fsmid = ip->ino_rec.ino_mtime;
409         vap->va_uid_uuid = ip->ino_data.uid;
410         vap->va_gid_uuid = ip->ino_data.gid;
411         vap->va_fsid_uuid = ip->hmp->fsid;
412         vap->va_vaflags = VA_UID_UUID_VALID | VA_GID_UUID_VALID |
413                           VA_FSID_UUID_VALID;
414         return(0);
415 }
416
417 /*
418  * hammer_vop_nresolve { nch, dvp, cred }
419  *
420  * Locate the requested directory entry.
421  */
422 static
423 int
424 hammer_vop_nresolve(struct vop_nresolve_args *ap)
425 {
426         struct hammer_base_elm key;
427         struct namecache *ncp;
428         struct hammer_inode *dip;
429         struct hammer_btree_info info;
430         struct vnode *vp;
431         int64_t namekey;
432         int error;
433         const int flags = HAMMER_BTREE_GET_RECORD | HAMMER_BTREE_GET_DATA;
434
435         dip = VTOI(ap->a_dvp);
436         ncp = ap->a_nch->ncp;
437         namekey = hammer_directory_namekey(ncp->nc_name, ncp->nc_nlen);
438
439         hammer_btree_info_init(&info, dip->hmp->rootcl);
440         key.obj_id = dip->obj_id;
441         key.key = namekey;
442         key.create_tid = dip->obj_asof;
443         key.delete_tid = 0;
444         key.rec_type = HAMMER_RECTYPE_DIRENTRY;
445         key.obj_type = 0;
446
447         /*
448          * Issue a lookup on the namekey.  The entry should not be found
449          * since the low bits of the key are 0.  This positions our cursor
450          * properly for the iteration.
451          */
452         error = hammer_btree_lookup(&info, &key, 0);
453         if (error != ENOENT) {
454                 if (error == 0)
455                         error = EIO;
456                 goto done;
457         }
458
459         /*
460          * Iterate through the keys as long as the upper 32 bits are
461          * the same.
462          */
463         while ((error = hammer_btree_iterate(&info.cursor, &key)) == 0) {
464                 if ((error = hammer_btree_extract(&info, flags)) != 0)
465                         break;
466                 if ((namekey ^ info.rec->base.base.key) &
467                     (int64_t)0xFFFFFFFF00000000ULL) {
468                         error = ENOENT;
469                         break;
470                 }
471                 if (ncp->nc_nlen == info.rec->base.data_len &&
472                     bcmp(ncp->nc_name, (void *)info.data, ncp->nc_nlen) == 0) {
473                         break;
474                 }
475         }
476         if (error == 0) {
477                 error = hammer_vfs_vget(dip->hmp->mp, info.rec->entry.obj_id, &vp);
478                 if (error == 0) {
479                         vn_unlock(vp);
480                         cache_setvp(ap->a_nch, vp);
481                         vrele(vp);
482                 }
483         } else if (error == ENOENT) {
484                 cache_setvp(ap->a_nch, NULL);
485         }
486 done:
487         hammer_btree_info_done(&info);
488         return (error);
489 }
490
491 /*
492  * hammer_vop_nlookupdotdot { dvp, vpp, cred }
493  *
494  * Locate the parent directory of a directory vnode.
495  *
496  * dvp is referenced but not locked.  *vpp must be returned referenced and
497  * locked.  A parent_obj_id of 0 does not necessarily indicate that we are
498  * at the root, instead it could indicate that the directory we were in was
499  * removed.
500  */
501 static
502 int
503 hammer_vop_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
504 {
505         struct hammer_inode *dip;
506         u_int64_t parent_obj_id;
507
508         dip = VTOI(ap->a_dvp);
509         if ((parent_obj_id = dip->ino_data.parent_obj_id) == 0) {
510                 *ap->a_vpp = NULL;
511                 return ENOENT;
512         }
513         return(hammer_vfs_vget(dip->hmp->mp, parent_obj_id, ap->a_vpp));
514 }
515
516 /*
517  * hammer_vop_nlink { nch, dvp, vp, cred }
518  */
519 static
520 int
521 hammer_vop_nlink(struct vop_nlink_args *ap)
522 {
523         struct hammer_transaction trans;
524         struct hammer_inode *dip;
525         struct hammer_inode *ip;
526         struct nchandle *nch;
527         int error;
528
529         nch = ap->a_nch;
530         dip = VTOI(ap->a_dvp);
531         ip = VTOI(ap->a_vp);
532
533         /*
534          * Create a transaction to cover the operations we perform.
535          */
536         hammer_start_transaction(dip->hmp, &trans);
537
538         /*
539          * Add the filesystem object to the directory.  Note that neither
540          * dip nor ip are referenced or locked, but their vnodes are
541          * referenced.  This function will bump the inode's link count.
542          */
543         error = hammer_add_directory(&trans, dip, nch->ncp, ip);
544
545         /*
546          * Finish up.
547          */
548         if (error) {
549                 hammer_abort_transaction(&trans);
550         } else {
551                 hammer_commit_transaction(&trans);
552         }
553         return (error);
554 }
555
556 /*
557  * hammer_vop_nmkdir { nch, dvp, vpp, cred, vap }
558  *
559  * The operating system has already ensured that the directory entry
560  * does not exist and done all appropriate namespace locking.
561  */
562 static
563 int
564 hammer_vop_nmkdir(struct vop_nmkdir_args *ap)
565 {
566         struct hammer_transaction trans;
567         struct hammer_inode *dip;
568         struct hammer_inode *nip;
569         struct nchandle *nch;
570         int error;
571
572         nch = ap->a_nch;
573         dip = VTOI(ap->a_dvp);
574
575         /*
576          * Create a transaction to cover the operations we perform.
577          */
578         hammer_start_transaction(dip->hmp, &trans);
579
580         /*
581          * Create a new filesystem object of the requested type.  The
582          * returned inode will be locked.  We cannot hold the new
583          * inode locked while doing other manipulations.
584          */
585         error = hammer_alloc_inode(&trans, ap->a_vap, ap->a_cred, &nip);
586         if (error) {
587                 hammer_abort_transaction(&trans);
588                 *ap->a_vpp = NULL;
589                 return (error);
590         }
591         hammer_lock_to_ref(&nip->lock);
592
593         /*
594          * Add the new filesystem object to the directory.  This will also
595          * bump the inode's link count.
596          */
597         error = hammer_add_directory(&trans, dip, nch->ncp, nip);
598
599         /*
600          * Finish up.
601          */
602         if (error) {
603                 hammer_put_inode_ref(nip);
604                 hammer_abort_transaction(&trans);
605                 *ap->a_vpp = NULL;
606         } else {
607                 hammer_commit_transaction(&trans);
608                 error = hammer_get_vnode(nip, LK_EXCLUSIVE, ap->a_vpp);
609                 hammer_put_inode_ref(nip);
610         }
611         return (error);
612 }
613
614 /*
615  * hammer_vop_nmknod { nch, dvp, vpp, cred, vap }
616  *
617  * The operating system has already ensured that the directory entry
618  * does not exist and done all appropriate namespace locking.
619  */
620 static
621 int
622 hammer_vop_nmknod(struct vop_nmknod_args *ap)
623 {
624         struct hammer_transaction trans;
625         struct hammer_inode *dip;
626         struct hammer_inode *nip;
627         struct nchandle *nch;
628         int error;
629
630         nch = ap->a_nch;
631         dip = VTOI(ap->a_dvp);
632
633         /*
634          * Create a transaction to cover the operations we perform.
635          */
636         hammer_start_transaction(dip->hmp, &trans);
637
638         /*
639          * Create a new filesystem object of the requested type.  The
640          * returned inode will be locked.  We cannot hold the new
641          * inode locked while doing other manipulations.
642          */
643         error = hammer_alloc_inode(&trans, ap->a_vap, ap->a_cred, &nip);
644         if (error) {
645                 hammer_abort_transaction(&trans);
646                 *ap->a_vpp = NULL;
647                 return (error);
648         }
649         hammer_lock_to_ref(&nip->lock);
650
651         /*
652          * Add the new filesystem object to the directory.  This will also
653          * bump the inode's link count.
654          */
655         error = hammer_add_directory(&trans, dip, nch->ncp, nip);
656
657         /*
658          * Finish up.
659          */
660         if (error) {
661                 hammer_put_inode_ref(nip);
662                 hammer_abort_transaction(&trans);
663                 *ap->a_vpp = NULL;
664         } else {
665                 hammer_commit_transaction(&trans);
666                 error = hammer_get_vnode(nip, LK_EXCLUSIVE, ap->a_vpp);
667                 hammer_put_inode_ref(nip);
668         }
669         return (error);
670 }
671
672 /*
673  * hammer_vop_open { vp, mode, cred, fp }
674  */
675 static
676 int
677 hammer_vop_open(struct vop_open_args *ap)
678 {
679         return EOPNOTSUPP;
680 }
681
682 /*
683  * hammer_vop_pathconf { vp, name, retval }
684  */
685 static
686 int
687 hammer_vop_pathconf(struct vop_pathconf_args *ap)
688 {
689         return EOPNOTSUPP;
690 }
691
692 /*
693  * hammer_vop_print { vp }
694  */
695 static
696 int
697 hammer_vop_print(struct vop_print_args *ap)
698 {
699         return EOPNOTSUPP;
700 }
701
702 /*
703  * hammer_vop_readdir { vp, uio, cred, *eofflag }
704  */
705 static
706 int
707 hammer_vop_readdir(struct vop_readdir_args *ap)
708 {
709         return EOPNOTSUPP;
710 }
711
712 /*
713  * hammer_vop_readlink { vp, uio, cred }
714  */
715 static
716 int
717 hammer_vop_readlink(struct vop_readlink_args *ap)
718 {
719         return EOPNOTSUPP;
720 }
721
722 /*
723  * hammer_vop_nremove { nch, dvp, cred }
724  */
725 static
726 int
727 hammer_vop_nremove(struct vop_nremove_args *ap)
728 {
729         return EOPNOTSUPP;
730 }
731
732 /*
733  * hammer_vop_nrename { fnch, tnch, fdvp, tdvp, cred }
734  */
735 static
736 int
737 hammer_vop_nrename(struct vop_nrename_args *ap)
738 {
739         return EOPNOTSUPP;
740 }
741
742 /*
743  * hammer_vop_nrmdir { nch, dvp, cred }
744  */
745 static
746 int
747 hammer_vop_nrmdir(struct vop_nrmdir_args *ap)
748 {
749         return EOPNOTSUPP;
750 }
751
752 /*
753  * hammer_vop_setattr { vp, vap, cred }
754  */
755 static
756 int
757 hammer_vop_setattr(struct vop_setattr_args *ap)
758 {
759         return EOPNOTSUPP;
760 }
761
762 /*
763  * hammer_vop_nsymlink { nch, dvp, vpp, cred, vap, target }
764  */
765 static
766 int
767 hammer_vop_nsymlink(struct vop_nsymlink_args *ap)
768 {
769         return EOPNOTSUPP;
770 }
771
772 /*
773  * hammer_vop_nwhiteout { nch, dvp, cred, flags }
774  */
775 static
776 int
777 hammer_vop_nwhiteout(struct vop_nwhiteout_args *ap)
778 {
779         return EOPNOTSUPP;
780 }
781
782 /*
783  * hammer_vop_strategy { vp, bio }
784  */
785 static
786 int
787 hammer_vop_strategy(struct vop_strategy_args *ap)
788 {
789         return EOPNOTSUPP;
790 }
791
792 #if 0
793         struct hammer_data_record *data;
794         struct hammer_base_elm_t key;
795         hammer_btree_info info;
796         const int flags = HAMMER_BTREE_GET_RECORD | HAMMER_BTREE_GET_DATA;
797         int64_t base_offset;
798         int didinit;
799         int o;
800
801         hammer_btree_info_init(&info, ip->hmp->rootcl);
802         key.obj_id = ip->obj_id;
803         key.create_tid = ip->obj_asof;
804         key.delete_tid = 0;
805         key.rec_type = HAMMER_RECTYPE_DATA;
806         key.obj_type = 0;
807         key.key = uio->uio_offset;
808
809         /*
810          * Iterate through matching records.  Note that for data records
811          * the base offset is the key - data_len, NOT the key.  This way
812          * we don't have to special case a ranged search.
813          */
814         error = hammer_btree_lookup(&info, &key, 0);
815         if (error && error != ENOENT)
816                 goto done;
817         while (uio->uio_resid > 0 && uio->uio_offset < ip->ino_rec.ino_size) {
818                 if ((error = hammer_btree_iterate(&info.cursor, &key)) != 0)
819                         break;
820                 /*
821                  * XXX - possible to optimize the extract
822                  */
823                 if ((error = hammer_btree_extract(&info, flags)) != 0)
824                         break;
825                 data = &info.rec->data;
826                 base_offset = data->base.key - data->base.data_len;
827                 if (uio->uio_offset < base_offset) {
828                         if (base_offset - uio->uio_offset > HAMMER_BUFSIZE)
829                                 n = HAMMER_BUFSIZE;
830                         else
831                                 n = (int)(base_offset - uio->uio_offset);
832                         error = uiomove(ip->hmp->zbuf, n, uio);
833                 } else {
834                         o = (int)uio->uio_offset - base_offset;
835                         if (o < data->base.data_len) {
836                                 n = data->base.data_len - o;
837                                 if (n > uio->uio_resid)
838                                         n = uio->uio_resid;
839                                 error = uiomove((char *)info.data + o, n, uio);
840                         }
841                 }
842                 if (error)
843                         break;
844         }
845
846         /*
847          * Issue a lookup on the namekey.  The entry should not be found
848          * since the low bits of the key are 0.  This positions our cursor
849          * properly for the iteration.
850          */
851         if (error != ENOENT) {
852                 if (error == 0)
853                         error = EIO;
854                 goto done;
855         }
856
857         /*
858          * Iterate through the keys as long as the upper 32 bits are
859          * the same.
860          */
861         while ((error = hammer_btree_iterate(&info, &key, flags)) == 0) {
862                 if ((namekey ^ info.rec->base.base.key) &
863                     (int64_t)0xFFFFFFFF00000000ULL) {
864                         error = ENOENT;
865                         break;
866                 }
867                 if (ncp->nc_nlen == info.rec->base.data_len &&
868                     bcmp(ncp->nc_name, (void *)info->data, ncp->nc_nlen) == 0) {
869                         break;
870                 }
871         }
872         if (error == 0) {
873                 error = hammer_vfs_vget(dip->hmp->mp, info->rec->entry.obj_id, &vp);
874                 if (error == 0) {
875                         vn_unlock(vp);
876                         cache_setvp(nch, vp);
877                         vrele(vp);
878                 }
879         } else if (error == ENOENT) {
880                 cache_setvp(nch, NULL);
881         }
882 done:
883         hammer_btree_info_done(&info);
884         return (error);
885
886
887         return EOPNOTSUPP;
888 }
889
890 #endif