1dd058f666bc6ec8a486e273035355a54d7cb462
[dragonfly.git] / sys / vfs / hammer / hammer_vnops.c
1 /*
2  * Copyright (c) 2007-2008 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.102 2008/10/16 17:24:16 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 <sys/dirent.h>
47 #include <sys/file.h>
48 #include <vm/vm_extern.h>
49 #include <vfs/fifofs/fifo.h>
50 #include "hammer.h"
51
52 /*
53  * USERFS VNOPS
54  */
55 /*static int hammer_vop_vnoperate(struct vop_generic_args *);*/
56 static int hammer_vop_fsync(struct vop_fsync_args *);
57 static int hammer_vop_read(struct vop_read_args *);
58 static int hammer_vop_write(struct vop_write_args *);
59 static int hammer_vop_access(struct vop_access_args *);
60 static int hammer_vop_advlock(struct vop_advlock_args *);
61 static int hammer_vop_close(struct vop_close_args *);
62 static int hammer_vop_ncreate(struct vop_ncreate_args *);
63 static int hammer_vop_getattr(struct vop_getattr_args *);
64 static int hammer_vop_nresolve(struct vop_nresolve_args *);
65 static int hammer_vop_nlookupdotdot(struct vop_nlookupdotdot_args *);
66 static int hammer_vop_nlink(struct vop_nlink_args *);
67 static int hammer_vop_nmkdir(struct vop_nmkdir_args *);
68 static int hammer_vop_nmknod(struct vop_nmknod_args *);
69 static int hammer_vop_open(struct vop_open_args *);
70 static int hammer_vop_print(struct vop_print_args *);
71 static int hammer_vop_readdir(struct vop_readdir_args *);
72 static int hammer_vop_readlink(struct vop_readlink_args *);
73 static int hammer_vop_nremove(struct vop_nremove_args *);
74 static int hammer_vop_nrename(struct vop_nrename_args *);
75 static int hammer_vop_nrmdir(struct vop_nrmdir_args *);
76 static int hammer_vop_markatime(struct vop_markatime_args *);
77 static int hammer_vop_setattr(struct vop_setattr_args *);
78 static int hammer_vop_strategy(struct vop_strategy_args *);
79 static int hammer_vop_bmap(struct vop_bmap_args *ap);
80 static int hammer_vop_nsymlink(struct vop_nsymlink_args *);
81 static int hammer_vop_nwhiteout(struct vop_nwhiteout_args *);
82 static int hammer_vop_ioctl(struct vop_ioctl_args *);
83 static int hammer_vop_mountctl(struct vop_mountctl_args *);
84 static int hammer_vop_kqfilter (struct vop_kqfilter_args *);
85
86 static int hammer_vop_fifoclose (struct vop_close_args *);
87 static int hammer_vop_fiforead (struct vop_read_args *);
88 static int hammer_vop_fifowrite (struct vop_write_args *);
89 static int hammer_vop_fifokqfilter (struct vop_kqfilter_args *);
90
91 struct vop_ops hammer_vnode_vops = {
92         .vop_default =          vop_defaultop,
93         .vop_fsync =            hammer_vop_fsync,
94         .vop_getpages =         vop_stdgetpages,
95         .vop_putpages =         vop_stdputpages,
96         .vop_read =             hammer_vop_read,
97         .vop_write =            hammer_vop_write,
98         .vop_access =           hammer_vop_access,
99         .vop_advlock =          hammer_vop_advlock,
100         .vop_close =            hammer_vop_close,
101         .vop_ncreate =          hammer_vop_ncreate,
102         .vop_getattr =          hammer_vop_getattr,
103         .vop_inactive =         hammer_vop_inactive,
104         .vop_reclaim =          hammer_vop_reclaim,
105         .vop_nresolve =         hammer_vop_nresolve,
106         .vop_nlookupdotdot =    hammer_vop_nlookupdotdot,
107         .vop_nlink =            hammer_vop_nlink,
108         .vop_nmkdir =           hammer_vop_nmkdir,
109         .vop_nmknod =           hammer_vop_nmknod,
110         .vop_open =             hammer_vop_open,
111         .vop_pathconf =         vop_stdpathconf,
112         .vop_print =            hammer_vop_print,
113         .vop_readdir =          hammer_vop_readdir,
114         .vop_readlink =         hammer_vop_readlink,
115         .vop_nremove =          hammer_vop_nremove,
116         .vop_nrename =          hammer_vop_nrename,
117         .vop_nrmdir =           hammer_vop_nrmdir,
118         .vop_markatime =        hammer_vop_markatime,
119         .vop_setattr =          hammer_vop_setattr,
120         .vop_bmap =             hammer_vop_bmap,
121         .vop_strategy =         hammer_vop_strategy,
122         .vop_nsymlink =         hammer_vop_nsymlink,
123         .vop_nwhiteout =        hammer_vop_nwhiteout,
124         .vop_ioctl =            hammer_vop_ioctl,
125         .vop_mountctl =         hammer_vop_mountctl,
126         .vop_kqfilter =         hammer_vop_kqfilter
127 };
128
129 struct vop_ops hammer_spec_vops = {
130         .vop_default =          vop_defaultop,
131         .vop_fsync =            hammer_vop_fsync,
132         .vop_read =             vop_stdnoread,
133         .vop_write =            vop_stdnowrite,
134         .vop_access =           hammer_vop_access,
135         .vop_close =            hammer_vop_close,
136         .vop_markatime =        hammer_vop_markatime,
137         .vop_getattr =          hammer_vop_getattr,
138         .vop_inactive =         hammer_vop_inactive,
139         .vop_reclaim =          hammer_vop_reclaim,
140         .vop_setattr =          hammer_vop_setattr
141 };
142
143 struct vop_ops hammer_fifo_vops = {
144         .vop_default =          fifo_vnoperate,
145         .vop_fsync =            hammer_vop_fsync,
146         .vop_read =             hammer_vop_fiforead,
147         .vop_write =            hammer_vop_fifowrite,
148         .vop_access =           hammer_vop_access,
149         .vop_close =            hammer_vop_fifoclose,
150         .vop_markatime =        hammer_vop_markatime,
151         .vop_getattr =          hammer_vop_getattr,
152         .vop_inactive =         hammer_vop_inactive,
153         .vop_reclaim =          hammer_vop_reclaim,
154         .vop_setattr =          hammer_vop_setattr,
155         .vop_kqfilter =         hammer_vop_fifokqfilter
156 };
157
158 static __inline
159 void
160 hammer_knote(struct vnode *vp, int flags)
161 {
162         if (flags)
163                 KNOTE(&vp->v_pollinfo.vpi_selinfo.si_note, flags);
164 }
165
166 #ifdef DEBUG_TRUNCATE
167 struct hammer_inode *HammerTruncIp;
168 #endif
169
170 static int hammer_dounlink(hammer_transaction_t trans, struct nchandle *nch,
171                            struct vnode *dvp, struct ucred *cred,
172                            int flags, int isdir);
173 static int hammer_vop_strategy_read(struct vop_strategy_args *ap);
174 static int hammer_vop_strategy_write(struct vop_strategy_args *ap);
175
176 #if 0
177 static
178 int
179 hammer_vop_vnoperate(struct vop_generic_args *)
180 {
181         return (VOCALL(&hammer_vnode_vops, ap));
182 }
183 #endif
184
185 /*
186  * hammer_vop_fsync { vp, waitfor }
187  *
188  * fsync() an inode to disk and wait for it to be completely committed
189  * such that the information would not be undone if a crash occured after
190  * return.
191  */
192 static
193 int
194 hammer_vop_fsync(struct vop_fsync_args *ap)
195 {
196         hammer_inode_t ip = VTOI(ap->a_vp);
197
198         ++hammer_count_fsyncs;
199         vfsync(ap->a_vp, ap->a_waitfor, 1, NULL, NULL);
200         hammer_flush_inode(ip, HAMMER_FLUSH_SIGNAL);
201         if (ap->a_waitfor == MNT_WAIT) {
202                 vn_unlock(ap->a_vp);
203                 hammer_wait_inode(ip);
204                 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
205         }
206         return (ip->error);
207 }
208
209 /*
210  * hammer_vop_read { vp, uio, ioflag, cred }
211  *
212  * MPALMOSTSAFE
213  */
214 static
215 int
216 hammer_vop_read(struct vop_read_args *ap)
217 {
218         struct hammer_transaction trans;
219         hammer_inode_t ip;
220         off_t offset;
221         struct buf *bp;
222         struct uio *uio;
223         int error;
224         int n;
225         int seqcount;
226         int ioseqcount;
227         int blksize;
228         int got_mplock;
229
230         if (ap->a_vp->v_type != VREG)
231                 return (EINVAL);
232         ip = VTOI(ap->a_vp);
233         error = 0;
234         uio = ap->a_uio;
235
236         /*
237          * Allow the UIO's size to override the sequential heuristic.
238          */
239         blksize = hammer_blocksize(uio->uio_offset);
240         seqcount = (uio->uio_resid + (blksize - 1)) / blksize;
241         ioseqcount = ap->a_ioflag >> 16;
242         if (seqcount < ioseqcount)
243                 seqcount = ioseqcount;
244
245         /*
246          * Temporary hack until more of HAMMER can be made MPSAFE.
247          */
248 #ifdef SMP
249         if (curthread->td_mpcount) {
250                 got_mplock = -1;
251                 hammer_start_transaction(&trans, ip->hmp);
252         } else {
253                 got_mplock = 0;
254         }
255 #else
256         hammer_start_transaction(&trans, ip->hmp);
257         got_mplock = -1;
258 #endif
259
260         /*
261          * Access the data typically in HAMMER_BUFSIZE blocks via the
262          * buffer cache, but HAMMER may use a variable block size based
263          * on the offset.
264          *
265          * XXX Temporary hack, delay the start transaction while we remain
266          *     MPSAFE.  NOTE: ino_data.size cannot change while vnode is
267          *     locked-shared.
268          */
269         while (uio->uio_resid > 0 && uio->uio_offset < ip->ino_data.size) {
270                 int64_t base_offset;
271                 int64_t file_limit;
272
273                 blksize = hammer_blocksize(uio->uio_offset);
274                 offset = (int)uio->uio_offset & (blksize - 1);
275                 base_offset = uio->uio_offset - offset;
276
277                 /*
278                  * MPSAFE
279                  */
280                 bp = getcacheblk(ap->a_vp, base_offset);
281                 if (bp) {
282                         error = 0;
283                         goto skip;
284                 }
285
286                 /*
287                  * MPUNSAFE
288                  */
289                 if (got_mplock == 0) {
290                         got_mplock = 1;
291                         get_mplock();
292                         hammer_start_transaction(&trans, ip->hmp);
293                 }
294
295                 if (hammer_cluster_enable) {
296                         /*
297                          * Use file_limit to prevent cluster_read() from
298                          * creating buffers of the wrong block size past
299                          * the demarc.
300                          */
301                         file_limit = ip->ino_data.size;
302                         if (base_offset < HAMMER_XDEMARC &&
303                             file_limit > HAMMER_XDEMARC) {
304                                 file_limit = HAMMER_XDEMARC;
305                         }
306                         error = cluster_read(ap->a_vp,
307                                              file_limit, base_offset,
308                                              blksize, MAXPHYS,
309                                              seqcount, &bp);
310                 } else {
311                         error = bread(ap->a_vp, base_offset, blksize, &bp);
312                 }
313                 if (error) {
314                         kprintf("error %d\n", error);
315                         brelse(bp);
316                         break;
317                 }
318 skip:
319
320                 /* bp->b_flags |= B_CLUSTEROK; temporarily disabled */
321                 n = blksize - offset;
322                 if (n > uio->uio_resid)
323                         n = uio->uio_resid;
324                 if (n > ip->ino_data.size - uio->uio_offset)
325                         n = (int)(ip->ino_data.size - uio->uio_offset);
326                 error = uiomove((char *)bp->b_data + offset, n, uio);
327
328                 /* data has a lower priority then meta-data */
329                 bp->b_flags |= B_AGE;
330                 bqrelse(bp);
331                 if (error)
332                         break;
333                 hammer_stats_file_read += n;
334         }
335
336         /*
337          * XXX only update the atime if we had to get the MP lock.
338          * XXX hack hack hack, fixme.
339          */
340         if (got_mplock) {
341                 if ((ip->flags & HAMMER_INODE_RO) == 0 &&
342                     (ip->hmp->mp->mnt_flag & MNT_NOATIME) == 0) {
343                         ip->ino_data.atime = trans.time;
344                         hammer_modify_inode(ip, HAMMER_INODE_ATIME);
345                 }
346                 hammer_done_transaction(&trans);
347                 if (got_mplock > 0)
348                         rel_mplock();
349         }
350         return (error);
351 }
352
353 /*
354  * hammer_vop_write { vp, uio, ioflag, cred }
355  */
356 static
357 int
358 hammer_vop_write(struct vop_write_args *ap)
359 {
360         struct hammer_transaction trans;
361         struct hammer_inode *ip;
362         hammer_mount_t hmp;
363         struct uio *uio;
364         int offset;
365         off_t base_offset;
366         struct buf *bp;
367         int kflags;
368         int error;
369         int n;
370         int flags;
371         int delta;
372         int seqcount;
373
374         if (ap->a_vp->v_type != VREG)
375                 return (EINVAL);
376         ip = VTOI(ap->a_vp);
377         hmp = ip->hmp;
378         error = 0;
379         kflags = 0;
380         seqcount = ap->a_ioflag >> 16;
381
382         if (ip->flags & HAMMER_INODE_RO)
383                 return (EROFS);
384
385         /*
386          * Create a transaction to cover the operations we perform.
387          */
388         hammer_start_transaction(&trans, hmp);
389         uio = ap->a_uio;
390
391         /*
392          * Check append mode
393          */
394         if (ap->a_ioflag & IO_APPEND)
395                 uio->uio_offset = ip->ino_data.size;
396
397         /*
398          * Check for illegal write offsets.  Valid range is 0...2^63-1.
399          *
400          * NOTE: the base_off assignment is required to work around what
401          * I consider to be a GCC-4 optimization bug.
402          */
403         if (uio->uio_offset < 0) {
404                 hammer_done_transaction(&trans);
405                 return (EFBIG);
406         }
407         base_offset = uio->uio_offset + uio->uio_resid; /* work around gcc-4 */
408         if (uio->uio_resid > 0 && base_offset <= 0) {
409                 hammer_done_transaction(&trans);
410                 return (EFBIG);
411         }
412
413         /*
414          * Access the data typically in HAMMER_BUFSIZE blocks via the
415          * buffer cache, but HAMMER may use a variable block size based
416          * on the offset.
417          */
418         while (uio->uio_resid > 0) {
419                 int fixsize = 0;
420                 int blksize;
421                 int blkmask;
422
423                 if ((error = hammer_checkspace(hmp, HAMMER_CHKSPC_WRITE)) != 0)
424                         break;
425
426                 blksize = hammer_blocksize(uio->uio_offset);
427
428                 /*
429                  * Do not allow HAMMER to blow out the buffer cache.  Very
430                  * large UIOs can lockout other processes due to bwillwrite()
431                  * mechanics.
432                  *
433                  * The hammer inode is not locked during these operations.
434                  * The vnode is locked which can interfere with the pageout
435                  * daemon for non-UIO_NOCOPY writes but should not interfere
436                  * with the buffer cache.  Even so, we cannot afford to
437                  * allow the pageout daemon to build up too many dirty buffer
438                  * cache buffers.
439                  *
440                  * Only call this if we aren't being recursively called from
441                  * a virtual disk device (vn), else we may deadlock.
442                  */
443                 if ((ap->a_ioflag & IO_RECURSE) == 0)
444                         bwillwrite(blksize);
445
446                 /*
447                  * Do not allow HAMMER to blow out system memory by
448                  * accumulating too many records.   Records are so well
449                  * decoupled from the buffer cache that it is possible
450                  * for userland to push data out to the media via
451                  * direct-write, but build up the records queued to the
452                  * backend faster then the backend can flush them out.
453                  * HAMMER has hit its write limit but the frontend has
454                  * no pushback to slow it down.
455                  */
456                 if (hmp->rsv_recs > hammer_limit_recs / 2) {
457                         /*
458                          * Get the inode on the flush list
459                          */
460                         if (ip->rsv_recs >= 64)
461                                 hammer_flush_inode(ip, HAMMER_FLUSH_SIGNAL);
462                         else if (ip->rsv_recs >= 16)
463                                 hammer_flush_inode(ip, 0);
464
465                         /*
466                          * Keep the flusher going if the system keeps
467                          * queueing records.
468                          */
469                         delta = hmp->count_newrecords -
470                                 hmp->last_newrecords;
471                         if (delta < 0 || delta > hammer_limit_recs / 2) {
472                                 hmp->last_newrecords = hmp->count_newrecords;
473                                 hammer_sync_hmp(hmp, MNT_NOWAIT);
474                         }
475
476                         /*
477                          * If we have gotten behind start slowing
478                          * down the writers.
479                          */
480                         delta = (hmp->rsv_recs - hammer_limit_recs) *
481                                 hz / hammer_limit_recs;
482                         if (delta > 0)
483                                 tsleep(&trans, 0, "hmrslo", delta);
484                 }
485
486                 /*
487                  * Calculate the blocksize at the current offset and figure
488                  * out how much we can actually write.
489                  */
490                 blkmask = blksize - 1;
491                 offset = (int)uio->uio_offset & blkmask;
492                 base_offset = uio->uio_offset & ~(int64_t)blkmask;
493                 n = blksize - offset;
494                 if (n > uio->uio_resid)
495                         n = uio->uio_resid;
496                 if (uio->uio_offset + n > ip->ino_data.size) {
497                         vnode_pager_setsize(ap->a_vp, uio->uio_offset + n);
498                         fixsize = 1;
499                         kflags |= NOTE_EXTEND;
500                 }
501
502                 if (uio->uio_segflg == UIO_NOCOPY) {
503                         /*
504                          * Issuing a write with the same data backing the
505                          * buffer.  Instantiate the buffer to collect the
506                          * backing vm pages, then read-in any missing bits.
507                          *
508                          * This case is used by vop_stdputpages().
509                          */
510                         bp = getblk(ap->a_vp, base_offset,
511                                     blksize, GETBLK_BHEAVY, 0);
512                         if ((bp->b_flags & B_CACHE) == 0) {
513                                 bqrelse(bp);
514                                 error = bread(ap->a_vp, base_offset,
515                                               blksize, &bp);
516                         }
517                 } else if (offset == 0 && uio->uio_resid >= blksize) {
518                         /*
519                          * Even though we are entirely overwriting the buffer
520                          * we may still have to zero it out to avoid a 
521                          * mmap/write visibility issue.
522                          */
523                         bp = getblk(ap->a_vp, base_offset, blksize, GETBLK_BHEAVY, 0);
524                         if ((bp->b_flags & B_CACHE) == 0)
525                                 vfs_bio_clrbuf(bp);
526                 } else if (base_offset >= ip->ino_data.size) {
527                         /*
528                          * If the base offset of the buffer is beyond the
529                          * file EOF, we don't have to issue a read.
530                          */
531                         bp = getblk(ap->a_vp, base_offset,
532                                     blksize, GETBLK_BHEAVY, 0);
533                         vfs_bio_clrbuf(bp);
534                 } else {
535                         /*
536                          * Partial overwrite, read in any missing bits then
537                          * replace the portion being written.
538                          */
539                         error = bread(ap->a_vp, base_offset, blksize, &bp);
540                         if (error == 0)
541                                 bheavy(bp);
542                 }
543                 if (error == 0) {
544                         error = uiomove((char *)bp->b_data + offset,
545                                         n, uio);
546                 }
547
548                 /*
549                  * If we screwed up we have to undo any VM size changes we
550                  * made.
551                  */
552                 if (error) {
553                         brelse(bp);
554                         if (fixsize) {
555                                 vtruncbuf(ap->a_vp, ip->ino_data.size,
556                                           hammer_blocksize(ip->ino_data.size));
557                         }
558                         break;
559                 }
560                 kflags |= NOTE_WRITE;
561                 hammer_stats_file_write += n;
562                 /* bp->b_flags |= B_CLUSTEROK; temporarily disabled */
563                 if (ip->ino_data.size < uio->uio_offset) {
564                         ip->ino_data.size = uio->uio_offset;
565                         flags = HAMMER_INODE_DDIRTY;
566                         vnode_pager_setsize(ap->a_vp, ip->ino_data.size);
567                 } else {
568                         flags = 0;
569                 }
570                 ip->ino_data.mtime = trans.time;
571                 flags |= HAMMER_INODE_MTIME | HAMMER_INODE_BUFS;
572                 hammer_modify_inode(ip, flags);
573
574                 /*
575                  * Once we dirty the buffer any cached zone-X offset
576                  * becomes invalid.  HAMMER NOTE: no-history mode cannot 
577                  * allow overwriting over the same data sector unless
578                  * we provide UNDOs for the old data, which we don't.
579                  */
580                 bp->b_bio2.bio_offset = NOOFFSET;
581
582                 /*
583                  * Final buffer disposition.
584                  */
585                 bp->b_flags |= B_AGE;
586                 if (ap->a_ioflag & IO_SYNC) {
587                         bwrite(bp);
588                 } else if (ap->a_ioflag & IO_DIRECT) {
589                         bawrite(bp);
590                 } else {
591                         bdwrite(bp);
592                 }
593         }
594         hammer_done_transaction(&trans);
595         hammer_knote(ap->a_vp, kflags);
596         return (error);
597 }
598
599 /*
600  * hammer_vop_access { vp, mode, cred }
601  */
602 static
603 int
604 hammer_vop_access(struct vop_access_args *ap)
605 {
606         struct hammer_inode *ip = VTOI(ap->a_vp);
607         uid_t uid;
608         gid_t gid;
609         int error;
610
611         ++hammer_stats_file_iopsr;
612         uid = hammer_to_unix_xid(&ip->ino_data.uid);
613         gid = hammer_to_unix_xid(&ip->ino_data.gid);
614
615         error = vop_helper_access(ap, uid, gid, ip->ino_data.mode,
616                                   ip->ino_data.uflags);
617         return (error);
618 }
619
620 /*
621  * hammer_vop_advlock { vp, id, op, fl, flags }
622  */
623 static
624 int
625 hammer_vop_advlock(struct vop_advlock_args *ap)
626 {
627         hammer_inode_t ip = VTOI(ap->a_vp);
628
629         return (lf_advlock(ap, &ip->advlock, ip->ino_data.size));
630 }
631
632 /*
633  * hammer_vop_close { vp, fflag }
634  */
635 static
636 int
637 hammer_vop_close(struct vop_close_args *ap)
638 {
639         /*hammer_inode_t ip = VTOI(ap->a_vp);*/
640         return (vop_stdclose(ap));
641 }
642
643 /*
644  * hammer_vop_ncreate { nch, dvp, vpp, cred, vap }
645  *
646  * The operating system has already ensured that the directory entry
647  * does not exist and done all appropriate namespace locking.
648  */
649 static
650 int
651 hammer_vop_ncreate(struct vop_ncreate_args *ap)
652 {
653         struct hammer_transaction trans;
654         struct hammer_inode *dip;
655         struct hammer_inode *nip;
656         struct nchandle *nch;
657         int error;
658
659         nch = ap->a_nch;
660         dip = VTOI(ap->a_dvp);
661
662         if (dip->flags & HAMMER_INODE_RO)
663                 return (EROFS);
664         if ((error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_CREATE)) != 0)
665                 return (error);
666
667         /*
668          * Create a transaction to cover the operations we perform.
669          */
670         hammer_start_transaction(&trans, dip->hmp);
671         ++hammer_stats_file_iopsw;
672
673         /*
674          * Create a new filesystem object of the requested type.  The
675          * returned inode will be referenced and shared-locked to prevent
676          * it from being moved to the flusher.
677          */
678         error = hammer_create_inode(&trans, ap->a_vap, ap->a_cred,
679                                     dip, nch->ncp->nc_name, nch->ncp->nc_nlen,
680                                     NULL, &nip);
681         if (error) {
682                 hkprintf("hammer_create_inode error %d\n", error);
683                 hammer_done_transaction(&trans);
684                 *ap->a_vpp = NULL;
685                 return (error);
686         }
687
688         /*
689          * Add the new filesystem object to the directory.  This will also
690          * bump the inode's link count.
691          */
692         error = hammer_ip_add_directory(&trans, dip,
693                                         nch->ncp->nc_name, nch->ncp->nc_nlen,
694                                         nip);
695         if (error)
696                 hkprintf("hammer_ip_add_directory error %d\n", error);
697
698         /*
699          * Finish up.
700          */
701         if (error) {
702                 hammer_rel_inode(nip, 0);
703                 hammer_done_transaction(&trans);
704                 *ap->a_vpp = NULL;
705         } else {
706                 error = hammer_get_vnode(nip, ap->a_vpp);
707                 hammer_done_transaction(&trans);
708                 hammer_rel_inode(nip, 0);
709                 if (error == 0) {
710                         cache_setunresolved(ap->a_nch);
711                         cache_setvp(ap->a_nch, *ap->a_vpp);
712                 }
713                 hammer_knote(ap->a_dvp, NOTE_WRITE);
714         }
715         return (error);
716 }
717
718 /*
719  * hammer_vop_getattr { vp, vap }
720  *
721  * Retrieve an inode's attribute information.  When accessing inodes
722  * historically we fake the atime field to ensure consistent results.
723  * The atime field is stored in the B-Tree element and allowed to be
724  * updated without cycling the element.
725  *
726  * MPSAFE
727  */
728 static
729 int
730 hammer_vop_getattr(struct vop_getattr_args *ap)
731 {
732         struct hammer_inode *ip = VTOI(ap->a_vp);
733         struct vattr *vap = ap->a_vap;
734
735         /*
736          * We want the fsid to be different when accessing a filesystem
737          * with different as-of's so programs like diff don't think
738          * the files are the same.
739          *
740          * We also want the fsid to be the same when comparing snapshots,
741          * or when comparing mirrors (which might be backed by different
742          * physical devices).  HAMMER fsids are based on the PFS's
743          * shared_uuid field.
744          *
745          * XXX there is a chance of collision here.  The va_fsid reported
746          * by stat is different from the more involved fsid used in the
747          * mount structure.
748          */
749         ++hammer_stats_file_iopsr;
750         hammer_lock_sh(&ip->lock);
751         vap->va_fsid = ip->pfsm->fsid_udev ^ (u_int32_t)ip->obj_asof ^
752                        (u_int32_t)(ip->obj_asof >> 32);
753
754         vap->va_fileid = ip->ino_leaf.base.obj_id;
755         vap->va_mode = ip->ino_data.mode;
756         vap->va_nlink = ip->ino_data.nlinks;
757         vap->va_uid = hammer_to_unix_xid(&ip->ino_data.uid);
758         vap->va_gid = hammer_to_unix_xid(&ip->ino_data.gid);
759         vap->va_rmajor = 0;
760         vap->va_rminor = 0;
761         vap->va_size = ip->ino_data.size;
762
763         /*
764          * Special case for @@PFS softlinks.  The actual size of the
765          * expanded softlink is "@@0x%016llx:%05d" == 26 bytes.
766          * or for MAX_TID is    "@@-1:%05d" == 10 bytes.
767          */
768         if (ip->ino_data.obj_type == HAMMER_OBJTYPE_SOFTLINK &&
769             ip->ino_data.size == 10 &&
770             ip->obj_asof == HAMMER_MAX_TID &&
771             ip->obj_localization == 0 &&
772             strncmp(ip->ino_data.ext.symlink, "@@PFS", 5) == 0) {
773                     if (ip->pfsm->pfsd.mirror_flags & HAMMER_PFSD_SLAVE)
774                             vap->va_size = 26;
775                     else
776                             vap->va_size = 10;
777         }
778
779         /*
780          * We must provide a consistent atime and mtime for snapshots
781          * so people can do a 'tar cf - ... | md5' on them and get
782          * consistent results.
783          */
784         if (ip->flags & HAMMER_INODE_RO) {
785                 hammer_time_to_timespec(ip->ino_data.ctime, &vap->va_atime);
786                 hammer_time_to_timespec(ip->ino_data.ctime, &vap->va_mtime);
787         } else {
788                 hammer_time_to_timespec(ip->ino_data.atime, &vap->va_atime);
789                 hammer_time_to_timespec(ip->ino_data.mtime, &vap->va_mtime);
790         }
791         hammer_time_to_timespec(ip->ino_data.ctime, &vap->va_ctime);
792         vap->va_flags = ip->ino_data.uflags;
793         vap->va_gen = 1;        /* hammer inums are unique for all time */
794         vap->va_blocksize = HAMMER_BUFSIZE;
795         if (ip->ino_data.size >= HAMMER_XDEMARC) {
796                 vap->va_bytes = (ip->ino_data.size + HAMMER_XBUFMASK64) &
797                                 ~HAMMER_XBUFMASK64;
798         } else if (ip->ino_data.size > HAMMER_BUFSIZE / 2) {
799                 vap->va_bytes = (ip->ino_data.size + HAMMER_BUFMASK64) &
800                                 ~HAMMER_BUFMASK64;
801         } else {
802                 vap->va_bytes = (ip->ino_data.size + 15) & ~15;
803         }
804
805         vap->va_type = hammer_get_vnode_type(ip->ino_data.obj_type);
806         vap->va_filerev = 0;    /* XXX */
807         /* mtime uniquely identifies any adjustments made to the file XXX */
808         vap->va_fsmid = ip->ino_data.mtime;
809         vap->va_uid_uuid = ip->ino_data.uid;
810         vap->va_gid_uuid = ip->ino_data.gid;
811         vap->va_fsid_uuid = ip->hmp->fsid;
812         vap->va_vaflags = VA_UID_UUID_VALID | VA_GID_UUID_VALID |
813                           VA_FSID_UUID_VALID;
814
815         switch (ip->ino_data.obj_type) {
816         case HAMMER_OBJTYPE_CDEV:
817         case HAMMER_OBJTYPE_BDEV:
818                 vap->va_rmajor = ip->ino_data.rmajor;
819                 vap->va_rminor = ip->ino_data.rminor;
820                 break;
821         default:
822                 break;
823         }
824         hammer_unlock(&ip->lock);
825         return(0);
826 }
827
828 /*
829  * hammer_vop_nresolve { nch, dvp, cred }
830  *
831  * Locate the requested directory entry.
832  */
833 static
834 int
835 hammer_vop_nresolve(struct vop_nresolve_args *ap)
836 {
837         struct hammer_transaction trans;
838         struct namecache *ncp;
839         hammer_inode_t dip;
840         hammer_inode_t ip;
841         hammer_tid_t asof;
842         struct hammer_cursor cursor;
843         struct vnode *vp;
844         int64_t namekey;
845         int error;
846         int i;
847         int nlen;
848         int flags;
849         int ispfs;
850         int64_t obj_id;
851         u_int32_t localization;
852         u_int32_t max_iterations;
853
854         /*
855          * Misc initialization, plus handle as-of name extensions.  Look for
856          * the '@@' extension.  Note that as-of files and directories cannot
857          * be modified.
858          */
859         dip = VTOI(ap->a_dvp);
860         ncp = ap->a_nch->ncp;
861         asof = dip->obj_asof;
862         localization = dip->obj_localization;   /* for code consistency */
863         nlen = ncp->nc_nlen;
864         flags = dip->flags & HAMMER_INODE_RO;
865         ispfs = 0;
866
867         hammer_simple_transaction(&trans, dip->hmp);
868         ++hammer_stats_file_iopsr;
869
870         for (i = 0; i < nlen; ++i) {
871                 if (ncp->nc_name[i] == '@' && ncp->nc_name[i+1] == '@') {
872                         error = hammer_str_to_tid(ncp->nc_name + i + 2,
873                                                   &ispfs, &asof, &localization);
874                         if (error != 0) {
875                                 i = nlen;
876                                 break;
877                         }
878                         if (asof != HAMMER_MAX_TID)
879                                 flags |= HAMMER_INODE_RO;
880                         break;
881                 }
882         }
883         nlen = i;
884
885         /*
886          * If this is a PFS softlink we dive into the PFS
887          */
888         if (ispfs && nlen == 0) {
889                 ip = hammer_get_inode(&trans, dip, HAMMER_OBJID_ROOT,
890                                       asof, localization,
891                                       flags, &error);
892                 if (error == 0) {
893                         error = hammer_get_vnode(ip, &vp);
894                         hammer_rel_inode(ip, 0);
895                 } else {
896                         vp = NULL;
897                 }
898                 if (error == 0) {
899                         vn_unlock(vp);
900                         cache_setvp(ap->a_nch, vp);
901                         vrele(vp);
902                 }
903                 goto done;
904         }
905
906         /*
907          * If there is no path component the time extension is relative to dip.
908          * e.g. "fubar/@@<snapshot>"
909          *
910          * "." is handled by the kernel, but ".@@<snapshot>" is not.
911          * e.g. "fubar/.@@<snapshot>"
912          *
913          * ".." is handled by the kernel.  We do not currently handle
914          * "..@<snapshot>".
915          */
916         if (nlen == 0 || (nlen == 1 && ncp->nc_name[0] == '.')) {
917                 ip = hammer_get_inode(&trans, dip, dip->obj_id,
918                                       asof, dip->obj_localization,
919                                       flags, &error);
920                 if (error == 0) {
921                         error = hammer_get_vnode(ip, &vp);
922                         hammer_rel_inode(ip, 0);
923                 } else {
924                         vp = NULL;
925                 }
926                 if (error == 0) {
927                         vn_unlock(vp);
928                         cache_setvp(ap->a_nch, vp);
929                         vrele(vp);
930                 }
931                 goto done;
932         }
933
934         /*
935          * Calculate the namekey and setup the key range for the scan.  This
936          * works kinda like a chained hash table where the lower 32 bits
937          * of the namekey synthesize the chain.
938          *
939          * The key range is inclusive of both key_beg and key_end.
940          */
941         namekey = hammer_directory_namekey(dip, ncp->nc_name, nlen,
942                                            &max_iterations);
943
944         error = hammer_init_cursor(&trans, &cursor, &dip->cache[1], dip);
945         cursor.key_beg.localization = dip->obj_localization +
946                                       hammer_dir_localization(dip);
947         cursor.key_beg.obj_id = dip->obj_id;
948         cursor.key_beg.key = namekey;
949         cursor.key_beg.create_tid = 0;
950         cursor.key_beg.delete_tid = 0;
951         cursor.key_beg.rec_type = HAMMER_RECTYPE_DIRENTRY;
952         cursor.key_beg.obj_type = 0;
953
954         cursor.key_end = cursor.key_beg;
955         cursor.key_end.key += max_iterations;
956         cursor.asof = asof;
957         cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE | HAMMER_CURSOR_ASOF;
958
959         /*
960          * Scan all matching records (the chain), locate the one matching
961          * the requested path component.
962          *
963          * The hammer_ip_*() functions merge in-memory records with on-disk
964          * records for the purposes of the search.
965          */
966         obj_id = 0;
967         localization = HAMMER_DEF_LOCALIZATION;
968
969         if (error == 0) {
970                 error = hammer_ip_first(&cursor);
971                 while (error == 0) {
972                         error = hammer_ip_resolve_data(&cursor);
973                         if (error)
974                                 break;
975                         if (nlen == cursor.leaf->data_len - HAMMER_ENTRY_NAME_OFF &&
976                             bcmp(ncp->nc_name, cursor.data->entry.name, nlen) == 0) {
977                                 obj_id = cursor.data->entry.obj_id;
978                                 localization = cursor.data->entry.localization;
979                                 break;
980                         }
981                         error = hammer_ip_next(&cursor);
982                 }
983         }
984         hammer_done_cursor(&cursor);
985
986         /*
987          * Lookup the obj_id.  This should always succeed.  If it does not
988          * the filesystem may be damaged and we return a dummy inode.
989          */
990         if (error == 0) {
991                 ip = hammer_get_inode(&trans, dip, obj_id,
992                                       asof, localization,
993                                       flags, &error);
994                 if (error == ENOENT) {
995                         kprintf("HAMMER: WARNING: Missing "
996                                 "inode for dirent \"%s\"\n"
997                                 "\tobj_id = %016llx, asof=%016llx, lo=%08x\n",
998                                 ncp->nc_name,
999                                 (long long)obj_id, (long long)asof,
1000                                 localization);
1001                         error = 0;
1002                         ip = hammer_get_dummy_inode(&trans, dip, obj_id,
1003                                                     asof, localization,
1004                                                     flags, &error);
1005                 }
1006                 if (error == 0) {
1007                         error = hammer_get_vnode(ip, &vp);
1008                         hammer_rel_inode(ip, 0);
1009                 } else {
1010                         vp = NULL;
1011                 }
1012                 if (error == 0) {
1013                         vn_unlock(vp);
1014                         cache_setvp(ap->a_nch, vp);
1015                         vrele(vp);
1016                 }
1017         } else if (error == ENOENT) {
1018                 cache_setvp(ap->a_nch, NULL);
1019         }
1020 done:
1021         hammer_done_transaction(&trans);
1022         return (error);
1023 }
1024
1025 /*
1026  * hammer_vop_nlookupdotdot { dvp, vpp, cred }
1027  *
1028  * Locate the parent directory of a directory vnode.
1029  *
1030  * dvp is referenced but not locked.  *vpp must be returned referenced and
1031  * locked.  A parent_obj_id of 0 does not necessarily indicate that we are
1032  * at the root, instead it could indicate that the directory we were in was
1033  * removed.
1034  *
1035  * NOTE: as-of sequences are not linked into the directory structure.  If
1036  * we are at the root with a different asof then the mount point, reload
1037  * the same directory with the mount point's asof.   I'm not sure what this
1038  * will do to NFS.  We encode ASOF stamps in NFS file handles so it might not
1039  * get confused, but it hasn't been tested.
1040  */
1041 static
1042 int
1043 hammer_vop_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
1044 {
1045         struct hammer_transaction trans;
1046         struct hammer_inode *dip;
1047         struct hammer_inode *ip;
1048         int64_t parent_obj_id;
1049         u_int32_t parent_obj_localization;
1050         hammer_tid_t asof;
1051         int error;
1052
1053         dip = VTOI(ap->a_dvp);
1054         asof = dip->obj_asof;
1055
1056         /*
1057          * Whos are parent?  This could be the root of a pseudo-filesystem
1058          * whos parent is in another localization domain.
1059          */
1060         parent_obj_id = dip->ino_data.parent_obj_id;
1061         if (dip->obj_id == HAMMER_OBJID_ROOT)
1062                 parent_obj_localization = dip->ino_data.ext.obj.parent_obj_localization;
1063         else
1064                 parent_obj_localization = dip->obj_localization;
1065
1066         if (parent_obj_id == 0) {
1067                 if (dip->obj_id == HAMMER_OBJID_ROOT &&
1068                    asof != dip->hmp->asof) {
1069                         parent_obj_id = dip->obj_id;
1070                         asof = dip->hmp->asof;
1071                         *ap->a_fakename = kmalloc(19, M_TEMP, M_WAITOK);
1072                         ksnprintf(*ap->a_fakename, 19, "0x%016llx",
1073                                   (long long)dip->obj_asof);
1074                 } else {
1075                         *ap->a_vpp = NULL;
1076                         return ENOENT;
1077                 }
1078         }
1079
1080         hammer_simple_transaction(&trans, dip->hmp);
1081         ++hammer_stats_file_iopsr;
1082
1083         ip = hammer_get_inode(&trans, dip, parent_obj_id,
1084                               asof, parent_obj_localization,
1085                               dip->flags, &error);
1086         if (ip) {
1087                 error = hammer_get_vnode(ip, ap->a_vpp);
1088                 hammer_rel_inode(ip, 0);
1089         } else {
1090                 *ap->a_vpp = NULL;
1091         }
1092         hammer_done_transaction(&trans);
1093         return (error);
1094 }
1095
1096 /*
1097  * hammer_vop_nlink { nch, dvp, vp, cred }
1098  */
1099 static
1100 int
1101 hammer_vop_nlink(struct vop_nlink_args *ap)
1102 {
1103         struct hammer_transaction trans;
1104         struct hammer_inode *dip;
1105         struct hammer_inode *ip;
1106         struct nchandle *nch;
1107         int error;
1108
1109         if (ap->a_dvp->v_mount != ap->a_vp->v_mount)    
1110                 return(EXDEV);
1111
1112         nch = ap->a_nch;
1113         dip = VTOI(ap->a_dvp);
1114         ip = VTOI(ap->a_vp);
1115
1116         if (dip->obj_localization != ip->obj_localization)
1117                 return(EXDEV);
1118
1119         if (dip->flags & HAMMER_INODE_RO)
1120                 return (EROFS);
1121         if (ip->flags & HAMMER_INODE_RO)
1122                 return (EROFS);
1123         if ((error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_CREATE)) != 0)
1124                 return (error);
1125
1126         /*
1127          * Create a transaction to cover the operations we perform.
1128          */
1129         hammer_start_transaction(&trans, dip->hmp);
1130         ++hammer_stats_file_iopsw;
1131
1132         /*
1133          * Add the filesystem object to the directory.  Note that neither
1134          * dip nor ip are referenced or locked, but their vnodes are
1135          * referenced.  This function will bump the inode's link count.
1136          */
1137         error = hammer_ip_add_directory(&trans, dip,
1138                                         nch->ncp->nc_name, nch->ncp->nc_nlen,
1139                                         ip);
1140
1141         /*
1142          * Finish up.
1143          */
1144         if (error == 0) {
1145                 cache_setunresolved(nch);
1146                 cache_setvp(nch, ap->a_vp);
1147         }
1148         hammer_done_transaction(&trans);
1149         hammer_knote(ap->a_vp, NOTE_LINK);
1150         hammer_knote(ap->a_dvp, NOTE_WRITE);
1151         return (error);
1152 }
1153
1154 /*
1155  * hammer_vop_nmkdir { nch, dvp, vpp, cred, vap }
1156  *
1157  * The operating system has already ensured that the directory entry
1158  * does not exist and done all appropriate namespace locking.
1159  */
1160 static
1161 int
1162 hammer_vop_nmkdir(struct vop_nmkdir_args *ap)
1163 {
1164         struct hammer_transaction trans;
1165         struct hammer_inode *dip;
1166         struct hammer_inode *nip;
1167         struct nchandle *nch;
1168         int error;
1169
1170         nch = ap->a_nch;
1171         dip = VTOI(ap->a_dvp);
1172
1173         if (dip->flags & HAMMER_INODE_RO)
1174                 return (EROFS);
1175         if ((error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_CREATE)) != 0)
1176                 return (error);
1177
1178         /*
1179          * Create a transaction to cover the operations we perform.
1180          */
1181         hammer_start_transaction(&trans, dip->hmp);
1182         ++hammer_stats_file_iopsw;
1183
1184         /*
1185          * Create a new filesystem object of the requested type.  The
1186          * returned inode will be referenced but not locked.
1187          */
1188         error = hammer_create_inode(&trans, ap->a_vap, ap->a_cred,
1189                                     dip, nch->ncp->nc_name, nch->ncp->nc_nlen,
1190                                     NULL, &nip);
1191         if (error) {
1192                 hkprintf("hammer_mkdir error %d\n", error);
1193                 hammer_done_transaction(&trans);
1194                 *ap->a_vpp = NULL;
1195                 return (error);
1196         }
1197         /*
1198          * Add the new filesystem object to the directory.  This will also
1199          * bump the inode's link count.
1200          */
1201         error = hammer_ip_add_directory(&trans, dip,
1202                                         nch->ncp->nc_name, nch->ncp->nc_nlen,
1203                                         nip);
1204         if (error)
1205                 hkprintf("hammer_mkdir (add) error %d\n", error);
1206
1207         /*
1208          * Finish up.
1209          */
1210         if (error) {
1211                 hammer_rel_inode(nip, 0);
1212                 *ap->a_vpp = NULL;
1213         } else {
1214                 error = hammer_get_vnode(nip, ap->a_vpp);
1215                 hammer_rel_inode(nip, 0);
1216                 if (error == 0) {
1217                         cache_setunresolved(ap->a_nch);
1218                         cache_setvp(ap->a_nch, *ap->a_vpp);
1219                 }
1220         }
1221         hammer_done_transaction(&trans);
1222         if (error == 0)
1223                 hammer_knote(ap->a_dvp, NOTE_WRITE | NOTE_LINK);
1224         return (error);
1225 }
1226
1227 /*
1228  * hammer_vop_nmknod { nch, dvp, vpp, cred, vap }
1229  *
1230  * The operating system has already ensured that the directory entry
1231  * does not exist and done all appropriate namespace locking.
1232  */
1233 static
1234 int
1235 hammer_vop_nmknod(struct vop_nmknod_args *ap)
1236 {
1237         struct hammer_transaction trans;
1238         struct hammer_inode *dip;
1239         struct hammer_inode *nip;
1240         struct nchandle *nch;
1241         int error;
1242
1243         nch = ap->a_nch;
1244         dip = VTOI(ap->a_dvp);
1245
1246         if (dip->flags & HAMMER_INODE_RO)
1247                 return (EROFS);
1248         if ((error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_CREATE)) != 0)
1249                 return (error);
1250
1251         /*
1252          * Create a transaction to cover the operations we perform.
1253          */
1254         hammer_start_transaction(&trans, dip->hmp);
1255         ++hammer_stats_file_iopsw;
1256
1257         /*
1258          * Create a new filesystem object of the requested type.  The
1259          * returned inode will be referenced but not locked.
1260          *
1261          * If mknod specifies a directory a pseudo-fs is created.
1262          */
1263         error = hammer_create_inode(&trans, ap->a_vap, ap->a_cred,
1264                                     dip, nch->ncp->nc_name, nch->ncp->nc_nlen,
1265                                     NULL, &nip);
1266         if (error) {
1267                 hammer_done_transaction(&trans);
1268                 *ap->a_vpp = NULL;
1269                 return (error);
1270         }
1271
1272         /*
1273          * Add the new filesystem object to the directory.  This will also
1274          * bump the inode's link count.
1275          */
1276         error = hammer_ip_add_directory(&trans, dip,
1277                                         nch->ncp->nc_name, nch->ncp->nc_nlen,
1278                                         nip);
1279
1280         /*
1281          * Finish up.
1282          */
1283         if (error) {
1284                 hammer_rel_inode(nip, 0);
1285                 *ap->a_vpp = NULL;
1286         } else {
1287                 error = hammer_get_vnode(nip, ap->a_vpp);
1288                 hammer_rel_inode(nip, 0);
1289                 if (error == 0) {
1290                         cache_setunresolved(ap->a_nch);
1291                         cache_setvp(ap->a_nch, *ap->a_vpp);
1292                 }
1293         }
1294         hammer_done_transaction(&trans);
1295         if (error == 0)
1296                 hammer_knote(ap->a_dvp, NOTE_WRITE);
1297         return (error);
1298 }
1299
1300 /*
1301  * hammer_vop_open { vp, mode, cred, fp }
1302  */
1303 static
1304 int
1305 hammer_vop_open(struct vop_open_args *ap)
1306 {
1307         hammer_inode_t ip;
1308
1309         ++hammer_stats_file_iopsr;
1310         ip = VTOI(ap->a_vp);
1311
1312         if ((ap->a_mode & FWRITE) && (ip->flags & HAMMER_INODE_RO))
1313                 return (EROFS);
1314         return(vop_stdopen(ap));
1315 }
1316
1317 /*
1318  * hammer_vop_print { vp }
1319  */
1320 static
1321 int
1322 hammer_vop_print(struct vop_print_args *ap)
1323 {
1324         return EOPNOTSUPP;
1325 }
1326
1327 /*
1328  * hammer_vop_readdir { vp, uio, cred, *eofflag, *ncookies, off_t **cookies }
1329  */
1330 static
1331 int
1332 hammer_vop_readdir(struct vop_readdir_args *ap)
1333 {
1334         struct hammer_transaction trans;
1335         struct hammer_cursor cursor;
1336         struct hammer_inode *ip;
1337         struct uio *uio;
1338         hammer_base_elm_t base;
1339         int error;
1340         int cookie_index;
1341         int ncookies;
1342         off_t *cookies;
1343         off_t saveoff;
1344         int r;
1345         int dtype;
1346
1347         ++hammer_stats_file_iopsr;
1348         ip = VTOI(ap->a_vp);
1349         uio = ap->a_uio;
1350         saveoff = uio->uio_offset;
1351
1352         if (ap->a_ncookies) {
1353                 ncookies = uio->uio_resid / 16 + 1;
1354                 if (ncookies > 1024)
1355                         ncookies = 1024;
1356                 cookies = kmalloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
1357                 cookie_index = 0;
1358         } else {
1359                 ncookies = -1;
1360                 cookies = NULL;
1361                 cookie_index = 0;
1362         }
1363
1364         hammer_simple_transaction(&trans, ip->hmp);
1365
1366         /*
1367          * Handle artificial entries
1368          *
1369          * It should be noted that the minimum value for a directory
1370          * hash key on-media is 0x0000000100000000, so we can use anything
1371          * less then that to represent our 'special' key space.
1372          */
1373         error = 0;
1374         if (saveoff == 0) {
1375                 r = vop_write_dirent(&error, uio, ip->obj_id, DT_DIR, 1, ".");
1376                 if (r)
1377                         goto done;
1378                 if (cookies)
1379                         cookies[cookie_index] = saveoff;
1380                 ++saveoff;
1381                 ++cookie_index;
1382                 if (cookie_index == ncookies)
1383                         goto done;
1384         }
1385         if (saveoff == 1) {
1386                 if (ip->ino_data.parent_obj_id) {
1387                         r = vop_write_dirent(&error, uio,
1388                                              ip->ino_data.parent_obj_id,
1389                                              DT_DIR, 2, "..");
1390                 } else {
1391                         r = vop_write_dirent(&error, uio,
1392                                              ip->obj_id, DT_DIR, 2, "..");
1393                 }
1394                 if (r)
1395                         goto done;
1396                 if (cookies)
1397                         cookies[cookie_index] = saveoff;
1398                 ++saveoff;
1399                 ++cookie_index;
1400                 if (cookie_index == ncookies)
1401                         goto done;
1402         }
1403
1404         /*
1405          * Key range (begin and end inclusive) to scan.  Directory keys
1406          * directly translate to a 64 bit 'seek' position.
1407          */
1408         hammer_init_cursor(&trans, &cursor, &ip->cache[1], ip);
1409         cursor.key_beg.localization = ip->obj_localization +
1410                                       hammer_dir_localization(ip);
1411         cursor.key_beg.obj_id = ip->obj_id;
1412         cursor.key_beg.create_tid = 0;
1413         cursor.key_beg.delete_tid = 0;
1414         cursor.key_beg.rec_type = HAMMER_RECTYPE_DIRENTRY;
1415         cursor.key_beg.obj_type = 0;
1416         cursor.key_beg.key = saveoff;
1417
1418         cursor.key_end = cursor.key_beg;
1419         cursor.key_end.key = HAMMER_MAX_KEY;
1420         cursor.asof = ip->obj_asof;
1421         cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE | HAMMER_CURSOR_ASOF;
1422
1423         error = hammer_ip_first(&cursor);
1424
1425         while (error == 0) {
1426                 error = hammer_ip_resolve_data(&cursor);
1427                 if (error)
1428                         break;
1429                 base = &cursor.leaf->base;
1430                 saveoff = base->key;
1431                 KKASSERT(cursor.leaf->data_len > HAMMER_ENTRY_NAME_OFF);
1432
1433                 if (base->obj_id != ip->obj_id)
1434                         panic("readdir: bad record at %p", cursor.node);
1435
1436                 /*
1437                  * Convert pseudo-filesystems into softlinks
1438                  */
1439                 dtype = hammer_get_dtype(cursor.leaf->base.obj_type);
1440                 r = vop_write_dirent(
1441                              &error, uio, cursor.data->entry.obj_id,
1442                              dtype,
1443                              cursor.leaf->data_len - HAMMER_ENTRY_NAME_OFF ,
1444                              (void *)cursor.data->entry.name);
1445                 if (r)
1446                         break;
1447                 ++saveoff;
1448                 if (cookies)
1449                         cookies[cookie_index] = base->key;
1450                 ++cookie_index;
1451                 if (cookie_index == ncookies)
1452                         break;
1453                 error = hammer_ip_next(&cursor);
1454         }
1455         hammer_done_cursor(&cursor);
1456
1457 done:
1458         hammer_done_transaction(&trans);
1459
1460         if (ap->a_eofflag)
1461                 *ap->a_eofflag = (error == ENOENT);
1462         uio->uio_offset = saveoff;
1463         if (error && cookie_index == 0) {
1464                 if (error == ENOENT)
1465                         error = 0;
1466                 if (cookies) {
1467                         kfree(cookies, M_TEMP);
1468                         *ap->a_ncookies = 0;
1469                         *ap->a_cookies = NULL;
1470                 }
1471         } else {
1472                 if (error == ENOENT)
1473                         error = 0;
1474                 if (cookies) {
1475                         *ap->a_ncookies = cookie_index;
1476                         *ap->a_cookies = cookies;
1477                 }
1478         }
1479         return(error);
1480 }
1481
1482 /*
1483  * hammer_vop_readlink { vp, uio, cred }
1484  */
1485 static
1486 int
1487 hammer_vop_readlink(struct vop_readlink_args *ap)
1488 {
1489         struct hammer_transaction trans;
1490         struct hammer_cursor cursor;
1491         struct hammer_inode *ip;
1492         char buf[32];
1493         u_int32_t localization;
1494         hammer_pseudofs_inmem_t pfsm;
1495         int error;
1496
1497         ip = VTOI(ap->a_vp);
1498
1499         /*
1500          * Shortcut if the symlink data was stuffed into ino_data.
1501          *
1502          * Also expand special "@@PFS%05d" softlinks (expansion only
1503          * occurs for non-historical (current) accesses made from the
1504          * primary filesystem).
1505          */
1506         if (ip->ino_data.size <= HAMMER_INODE_BASESYMLEN) {
1507                 char *ptr;
1508                 int bytes;
1509
1510                 ptr = ip->ino_data.ext.symlink;
1511                 bytes = (int)ip->ino_data.size;
1512                 if (bytes == 10 &&
1513                     ip->obj_asof == HAMMER_MAX_TID &&
1514                     ip->obj_localization == 0 &&
1515                     strncmp(ptr, "@@PFS", 5) == 0) {
1516                         hammer_simple_transaction(&trans, ip->hmp);
1517                         bcopy(ptr + 5, buf, 5);
1518                         buf[5] = 0;
1519                         localization = strtoul(buf, NULL, 10) << 16;
1520                         pfsm = hammer_load_pseudofs(&trans, localization,
1521                                                     &error);
1522                         if (error == 0) {
1523                                 if (pfsm->pfsd.mirror_flags &
1524                                     HAMMER_PFSD_SLAVE) {
1525                                         /* vap->va_size == 26 */
1526                                         ksnprintf(buf, sizeof(buf),
1527                                                   "@@0x%016llx:%05d",
1528                                                   (long long)pfsm->pfsd.sync_end_tid,
1529                                                   localization >> 16);
1530                                 } else {
1531                                         /* vap->va_size == 10 */
1532                                         ksnprintf(buf, sizeof(buf),
1533                                                   "@@-1:%05d",
1534                                                   localization >> 16);
1535 #if 0
1536                                         ksnprintf(buf, sizeof(buf),
1537                                                   "@@0x%016llx:%05d",
1538                                                   (long long)HAMMER_MAX_TID,
1539                                                   localization >> 16);
1540 #endif
1541                                 }
1542                                 ptr = buf;
1543                                 bytes = strlen(buf);
1544                         }
1545                         if (pfsm)
1546                                 hammer_rel_pseudofs(trans.hmp, pfsm);
1547                         hammer_done_transaction(&trans);
1548                 }
1549                 error = uiomove(ptr, bytes, ap->a_uio);
1550                 return(error);
1551         }
1552
1553         /*
1554          * Long version
1555          */
1556         hammer_simple_transaction(&trans, ip->hmp);
1557         ++hammer_stats_file_iopsr;
1558         hammer_init_cursor(&trans, &cursor, &ip->cache[1], ip);
1559
1560         /*
1561          * Key range (begin and end inclusive) to scan.  Directory keys
1562          * directly translate to a 64 bit 'seek' position.
1563          */
1564         cursor.key_beg.localization = ip->obj_localization +
1565                                       HAMMER_LOCALIZE_MISC;
1566         cursor.key_beg.obj_id = ip->obj_id;
1567         cursor.key_beg.create_tid = 0;
1568         cursor.key_beg.delete_tid = 0;
1569         cursor.key_beg.rec_type = HAMMER_RECTYPE_FIX;
1570         cursor.key_beg.obj_type = 0;
1571         cursor.key_beg.key = HAMMER_FIXKEY_SYMLINK;
1572         cursor.asof = ip->obj_asof;
1573         cursor.flags |= HAMMER_CURSOR_ASOF;
1574
1575         error = hammer_ip_lookup(&cursor);
1576         if (error == 0) {
1577                 error = hammer_ip_resolve_data(&cursor);
1578                 if (error == 0) {
1579                         KKASSERT(cursor.leaf->data_len >=
1580                                  HAMMER_SYMLINK_NAME_OFF);
1581                         error = uiomove(cursor.data->symlink.name,
1582                                         cursor.leaf->data_len -
1583                                                 HAMMER_SYMLINK_NAME_OFF,
1584                                         ap->a_uio);
1585                 }
1586         }
1587         hammer_done_cursor(&cursor);
1588         hammer_done_transaction(&trans);
1589         return(error);
1590 }
1591
1592 /*
1593  * hammer_vop_nremove { nch, dvp, cred }
1594  */
1595 static
1596 int
1597 hammer_vop_nremove(struct vop_nremove_args *ap)
1598 {
1599         struct hammer_transaction trans;
1600         struct hammer_inode *dip;
1601         int error;
1602
1603         dip = VTOI(ap->a_dvp);
1604
1605         if (hammer_nohistory(dip) == 0 &&
1606             (error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_REMOVE)) != 0) {
1607                 return (error);
1608         }
1609
1610         hammer_start_transaction(&trans, dip->hmp);
1611         ++hammer_stats_file_iopsw;
1612         error = hammer_dounlink(&trans, ap->a_nch, ap->a_dvp, ap->a_cred, 0, 0);
1613         hammer_done_transaction(&trans);
1614         if (error == 0)
1615                 hammer_knote(ap->a_dvp, NOTE_WRITE);
1616         return (error);
1617 }
1618
1619 /*
1620  * hammer_vop_nrename { fnch, tnch, fdvp, tdvp, cred }
1621  */
1622 static
1623 int
1624 hammer_vop_nrename(struct vop_nrename_args *ap)
1625 {
1626         struct hammer_transaction trans;
1627         struct namecache *fncp;
1628         struct namecache *tncp;
1629         struct hammer_inode *fdip;
1630         struct hammer_inode *tdip;
1631         struct hammer_inode *ip;
1632         struct hammer_cursor cursor;
1633         int64_t namekey;
1634         u_int32_t max_iterations;
1635         int nlen, error;
1636
1637         if (ap->a_fdvp->v_mount != ap->a_tdvp->v_mount) 
1638                 return(EXDEV);
1639         if (ap->a_fdvp->v_mount != ap->a_fnch->ncp->nc_vp->v_mount)
1640                 return(EXDEV);
1641
1642         fdip = VTOI(ap->a_fdvp);
1643         tdip = VTOI(ap->a_tdvp);
1644         fncp = ap->a_fnch->ncp;
1645         tncp = ap->a_tnch->ncp;
1646         ip = VTOI(fncp->nc_vp);
1647         KKASSERT(ip != NULL);
1648
1649         if (fdip->obj_localization != tdip->obj_localization)
1650                 return(EXDEV);
1651         if (fdip->obj_localization != ip->obj_localization)
1652                 return(EXDEV);
1653
1654         if (fdip->flags & HAMMER_INODE_RO)
1655                 return (EROFS);
1656         if (tdip->flags & HAMMER_INODE_RO)
1657                 return (EROFS);
1658         if (ip->flags & HAMMER_INODE_RO)
1659                 return (EROFS);
1660         if ((error = hammer_checkspace(fdip->hmp, HAMMER_CHKSPC_CREATE)) != 0)
1661                 return (error);
1662
1663         hammer_start_transaction(&trans, fdip->hmp);
1664         ++hammer_stats_file_iopsw;
1665
1666         /*
1667          * Remove tncp from the target directory and then link ip as
1668          * tncp. XXX pass trans to dounlink
1669          *
1670          * Force the inode sync-time to match the transaction so it is
1671          * in-sync with the creation of the target directory entry.
1672          */
1673         error = hammer_dounlink(&trans, ap->a_tnch, ap->a_tdvp,
1674                                 ap->a_cred, 0, -1);
1675         if (error == 0 || error == ENOENT) {
1676                 error = hammer_ip_add_directory(&trans, tdip,
1677                                                 tncp->nc_name, tncp->nc_nlen,
1678                                                 ip);
1679                 if (error == 0) {
1680                         ip->ino_data.parent_obj_id = tdip->obj_id;
1681                         ip->ino_data.ctime = trans.time;
1682                         hammer_modify_inode(ip, HAMMER_INODE_DDIRTY);
1683                 }
1684         }
1685         if (error)
1686                 goto failed; /* XXX */
1687
1688         /*
1689          * Locate the record in the originating directory and remove it.
1690          *
1691          * Calculate the namekey and setup the key range for the scan.  This
1692          * works kinda like a chained hash table where the lower 32 bits
1693          * of the namekey synthesize the chain.
1694          *
1695          * The key range is inclusive of both key_beg and key_end.
1696          */
1697         namekey = hammer_directory_namekey(fdip, fncp->nc_name, fncp->nc_nlen,
1698                                            &max_iterations);
1699 retry:
1700         hammer_init_cursor(&trans, &cursor, &fdip->cache[1], fdip);
1701         cursor.key_beg.localization = fdip->obj_localization +
1702                                       hammer_dir_localization(fdip);
1703         cursor.key_beg.obj_id = fdip->obj_id;
1704         cursor.key_beg.key = namekey;
1705         cursor.key_beg.create_tid = 0;
1706         cursor.key_beg.delete_tid = 0;
1707         cursor.key_beg.rec_type = HAMMER_RECTYPE_DIRENTRY;
1708         cursor.key_beg.obj_type = 0;
1709
1710         cursor.key_end = cursor.key_beg;
1711         cursor.key_end.key += max_iterations;
1712         cursor.asof = fdip->obj_asof;
1713         cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE | HAMMER_CURSOR_ASOF;
1714
1715         /*
1716          * Scan all matching records (the chain), locate the one matching
1717          * the requested path component.
1718          *
1719          * The hammer_ip_*() functions merge in-memory records with on-disk
1720          * records for the purposes of the search.
1721          */
1722         error = hammer_ip_first(&cursor);
1723         while (error == 0) {
1724                 if (hammer_ip_resolve_data(&cursor) != 0)
1725                         break;
1726                 nlen = cursor.leaf->data_len - HAMMER_ENTRY_NAME_OFF;
1727                 KKASSERT(nlen > 0);
1728                 if (fncp->nc_nlen == nlen &&
1729                     bcmp(fncp->nc_name, cursor.data->entry.name, nlen) == 0) {
1730                         break;
1731                 }
1732                 error = hammer_ip_next(&cursor);
1733         }
1734
1735         /*
1736          * If all is ok we have to get the inode so we can adjust nlinks.
1737          *
1738          * WARNING: hammer_ip_del_directory() may have to terminate the
1739          * cursor to avoid a recursion.  It's ok to call hammer_done_cursor()
1740          * twice.
1741          */
1742         if (error == 0)
1743                 error = hammer_ip_del_directory(&trans, &cursor, fdip, ip);
1744
1745         /*
1746          * XXX A deadlock here will break rename's atomicy for the purposes
1747          * of crash recovery.
1748          */
1749         if (error == EDEADLK) {
1750                 hammer_done_cursor(&cursor);
1751                 goto retry;
1752         }
1753
1754         /*
1755          * Cleanup and tell the kernel that the rename succeeded.
1756          */
1757         hammer_done_cursor(&cursor);
1758         if (error == 0) {
1759                 cache_rename(ap->a_fnch, ap->a_tnch);
1760                 hammer_knote(ap->a_fdvp, NOTE_WRITE);
1761                 hammer_knote(ap->a_tdvp, NOTE_WRITE);
1762                 if (ip->vp)
1763                         hammer_knote(ip->vp, NOTE_RENAME);
1764         }
1765
1766 failed:
1767         hammer_done_transaction(&trans);
1768         return (error);
1769 }
1770
1771 /*
1772  * hammer_vop_nrmdir { nch, dvp, cred }
1773  */
1774 static
1775 int
1776 hammer_vop_nrmdir(struct vop_nrmdir_args *ap)
1777 {
1778         struct hammer_transaction trans;
1779         struct hammer_inode *dip;
1780         int error;
1781
1782         dip = VTOI(ap->a_dvp);
1783
1784         if (hammer_nohistory(dip) == 0 &&
1785             (error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_REMOVE)) != 0) {
1786                 return (error);
1787         }
1788
1789         hammer_start_transaction(&trans, dip->hmp);
1790         ++hammer_stats_file_iopsw;
1791         error = hammer_dounlink(&trans, ap->a_nch, ap->a_dvp, ap->a_cred, 0, 1);
1792         hammer_done_transaction(&trans);
1793         if (error == 0)
1794                 hammer_knote(ap->a_dvp, NOTE_WRITE | NOTE_LINK);
1795         return (error);
1796 }
1797
1798 /*
1799  * hammer_vop_markatime { vp, cred }
1800  */
1801 static
1802 int
1803 hammer_vop_markatime(struct vop_markatime_args *ap)
1804 {
1805         struct hammer_transaction trans;
1806         struct hammer_inode *ip;
1807
1808         ip = VTOI(ap->a_vp);
1809         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
1810                 return (EROFS);
1811         if (ip->flags & HAMMER_INODE_RO)
1812                 return (EROFS);
1813         if (ip->hmp->mp->mnt_flag & MNT_NOATIME)
1814                 return (0);
1815         hammer_start_transaction(&trans, ip->hmp);
1816         ++hammer_stats_file_iopsw;
1817
1818         ip->ino_data.atime = trans.time;
1819         hammer_modify_inode(ip, HAMMER_INODE_ATIME);
1820         hammer_done_transaction(&trans);
1821         hammer_knote(ap->a_vp, NOTE_ATTRIB);
1822         return (0);
1823 }
1824
1825 /*
1826  * hammer_vop_setattr { vp, vap, cred }
1827  */
1828 static
1829 int
1830 hammer_vop_setattr(struct vop_setattr_args *ap)
1831 {
1832         struct hammer_transaction trans;
1833         struct vattr *vap;
1834         struct hammer_inode *ip;
1835         int modflags;
1836         int error;
1837         int truncating;
1838         int blksize;
1839         int kflags;
1840         int64_t aligned_size;
1841         u_int32_t flags;
1842
1843         vap = ap->a_vap;
1844         ip = ap->a_vp->v_data;
1845         modflags = 0;
1846         kflags = 0;
1847
1848         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
1849                 return(EROFS);
1850         if (ip->flags & HAMMER_INODE_RO)
1851                 return (EROFS);
1852         if (hammer_nohistory(ip) == 0 &&
1853             (error = hammer_checkspace(ip->hmp, HAMMER_CHKSPC_REMOVE)) != 0) {
1854                 return (error);
1855         }
1856
1857         hammer_start_transaction(&trans, ip->hmp);
1858         ++hammer_stats_file_iopsw;
1859         error = 0;
1860
1861         if (vap->va_flags != VNOVAL) {
1862                 flags = ip->ino_data.uflags;
1863                 error = vop_helper_setattr_flags(&flags, vap->va_flags,
1864                                          hammer_to_unix_xid(&ip->ino_data.uid),
1865                                          ap->a_cred);
1866                 if (error == 0) {
1867                         if (ip->ino_data.uflags != flags) {
1868                                 ip->ino_data.uflags = flags;
1869                                 ip->ino_data.ctime = trans.time;
1870                                 modflags |= HAMMER_INODE_DDIRTY;
1871                                 kflags |= NOTE_ATTRIB;
1872                         }
1873                         if (ip->ino_data.uflags & (IMMUTABLE | APPEND)) {
1874                                 error = 0;
1875                                 goto done;
1876                         }
1877                 }
1878                 goto done;
1879         }
1880         if (ip->ino_data.uflags & (IMMUTABLE | APPEND)) {
1881                 error = EPERM;
1882                 goto done;
1883         }
1884         if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
1885                 mode_t cur_mode = ip->ino_data.mode;
1886                 uid_t cur_uid = hammer_to_unix_xid(&ip->ino_data.uid);
1887                 gid_t cur_gid = hammer_to_unix_xid(&ip->ino_data.gid);
1888                 uuid_t uuid_uid;
1889                 uuid_t uuid_gid;
1890
1891                 error = vop_helper_chown(ap->a_vp, vap->va_uid, vap->va_gid,
1892                                          ap->a_cred,
1893                                          &cur_uid, &cur_gid, &cur_mode);
1894                 if (error == 0) {
1895                         hammer_guid_to_uuid(&uuid_uid, cur_uid);
1896                         hammer_guid_to_uuid(&uuid_gid, cur_gid);
1897                         if (bcmp(&uuid_uid, &ip->ino_data.uid,
1898                                  sizeof(uuid_uid)) ||
1899                             bcmp(&uuid_gid, &ip->ino_data.gid,
1900                                  sizeof(uuid_gid)) ||
1901                             ip->ino_data.mode != cur_mode
1902                         ) {
1903                                 ip->ino_data.uid = uuid_uid;
1904                                 ip->ino_data.gid = uuid_gid;
1905                                 ip->ino_data.mode = cur_mode;
1906                                 ip->ino_data.ctime = trans.time;
1907                                 modflags |= HAMMER_INODE_DDIRTY;
1908                         }
1909                         kflags |= NOTE_ATTRIB;
1910                 }
1911         }
1912         while (vap->va_size != VNOVAL && ip->ino_data.size != vap->va_size) {
1913                 switch(ap->a_vp->v_type) {
1914                 case VREG:
1915                         if (vap->va_size == ip->ino_data.size)
1916                                 break;
1917                         /*
1918                          * XXX break atomicy, we can deadlock the backend
1919                          * if we do not release the lock.  Probably not a
1920                          * big deal here.
1921                          */
1922                         blksize = hammer_blocksize(vap->va_size);
1923                         if (vap->va_size < ip->ino_data.size) {
1924                                 vtruncbuf(ap->a_vp, vap->va_size, blksize);
1925                                 truncating = 1;
1926                                 kflags |= NOTE_WRITE;
1927                         } else {
1928                                 vnode_pager_setsize(ap->a_vp, vap->va_size);
1929                                 truncating = 0;
1930                                 kflags |= NOTE_WRITE | NOTE_EXTEND;
1931                         }
1932                         ip->ino_data.size = vap->va_size;
1933                         ip->ino_data.mtime = trans.time;
1934                         modflags |= HAMMER_INODE_MTIME | HAMMER_INODE_DDIRTY;
1935
1936                         /*
1937                          * on-media truncation is cached in the inode until
1938                          * the inode is synchronized.
1939                          */
1940                         if (truncating) {
1941                                 hammer_ip_frontend_trunc(ip, vap->va_size);
1942 #ifdef DEBUG_TRUNCATE
1943                                 if (HammerTruncIp == NULL)
1944                                         HammerTruncIp = ip;
1945 #endif
1946                                 if ((ip->flags & HAMMER_INODE_TRUNCATED) == 0) {
1947                                         ip->flags |= HAMMER_INODE_TRUNCATED;
1948                                         ip->trunc_off = vap->va_size;
1949 #ifdef DEBUG_TRUNCATE
1950                                         if (ip == HammerTruncIp)
1951                                         kprintf("truncate1 %016llx\n",
1952                                                 (long long)ip->trunc_off);
1953 #endif
1954                                 } else if (ip->trunc_off > vap->va_size) {
1955                                         ip->trunc_off = vap->va_size;
1956 #ifdef DEBUG_TRUNCATE
1957                                         if (ip == HammerTruncIp)
1958                                         kprintf("truncate2 %016llx\n",
1959                                                 (long long)ip->trunc_off);
1960 #endif
1961                                 } else {
1962 #ifdef DEBUG_TRUNCATE
1963                                         if (ip == HammerTruncIp)
1964                                         kprintf("truncate3 %016llx (ignored)\n",
1965                                                 (long long)vap->va_size);
1966 #endif
1967                                 }
1968                         }
1969
1970                         /*
1971                          * If truncating we have to clean out a portion of
1972                          * the last block on-disk.  We do this in the
1973                          * front-end buffer cache.
1974                          */
1975                         aligned_size = (vap->va_size + (blksize - 1)) &
1976                                        ~(int64_t)(blksize - 1);
1977                         if (truncating && vap->va_size < aligned_size) {
1978                                 struct buf *bp;
1979                                 int offset;
1980
1981                                 aligned_size -= blksize;
1982
1983                                 offset = (int)vap->va_size & (blksize - 1);
1984                                 error = bread(ap->a_vp, aligned_size,
1985                                               blksize, &bp);
1986                                 hammer_ip_frontend_trunc(ip, aligned_size);
1987                                 if (error == 0) {
1988                                         bzero(bp->b_data + offset,
1989                                               blksize - offset);
1990                                         /* must de-cache direct-io offset */
1991                                         bp->b_bio2.bio_offset = NOOFFSET;
1992                                         bdwrite(bp);
1993                                 } else {
1994                                         kprintf("ERROR %d\n", error);
1995                                         brelse(bp);
1996                                 }
1997                         }
1998                         break;
1999                 case VDATABASE:
2000                         if ((ip->flags & HAMMER_INODE_TRUNCATED) == 0) {
2001                                 ip->flags |= HAMMER_INODE_TRUNCATED;
2002                                 ip->trunc_off = vap->va_size;
2003                         } else if (ip->trunc_off > vap->va_size) {
2004                                 ip->trunc_off = vap->va_size;
2005                         }
2006                         hammer_ip_frontend_trunc(ip, vap->va_size);
2007                         ip->ino_data.size = vap->va_size;
2008                         ip->ino_data.mtime = trans.time;
2009                         modflags |= HAMMER_INODE_MTIME | HAMMER_INODE_DDIRTY;
2010                         kflags |= NOTE_ATTRIB;
2011                         break;
2012                 default:
2013                         error = EINVAL;
2014                         goto done;
2015                 }
2016                 break;
2017         }
2018         if (vap->va_atime.tv_sec != VNOVAL) {
2019                 ip->ino_data.atime = hammer_timespec_to_time(&vap->va_atime);
2020                 modflags |= HAMMER_INODE_ATIME;
2021                 kflags |= NOTE_ATTRIB;
2022         }
2023         if (vap->va_mtime.tv_sec != VNOVAL) {
2024                 ip->ino_data.mtime = hammer_timespec_to_time(&vap->va_mtime);
2025                 modflags |= HAMMER_INODE_MTIME;
2026                 kflags |= NOTE_ATTRIB;
2027         }
2028         if (vap->va_mode != (mode_t)VNOVAL) {
2029                 mode_t   cur_mode = ip->ino_data.mode;
2030                 uid_t cur_uid = hammer_to_unix_xid(&ip->ino_data.uid);
2031                 gid_t cur_gid = hammer_to_unix_xid(&ip->ino_data.gid);
2032
2033                 error = vop_helper_chmod(ap->a_vp, vap->va_mode, ap->a_cred,
2034                                          cur_uid, cur_gid, &cur_mode);
2035                 if (error == 0 && ip->ino_data.mode != cur_mode) {
2036                         ip->ino_data.mode = cur_mode;
2037                         ip->ino_data.ctime = trans.time;
2038                         modflags |= HAMMER_INODE_DDIRTY;
2039                         kflags |= NOTE_ATTRIB;
2040                 }
2041         }
2042 done:
2043         if (error == 0)
2044                 hammer_modify_inode(ip, modflags);
2045         hammer_done_transaction(&trans);
2046         hammer_knote(ap->a_vp, kflags);
2047         return (error);
2048 }
2049
2050 /*
2051  * hammer_vop_nsymlink { nch, dvp, vpp, cred, vap, target }
2052  */
2053 static
2054 int
2055 hammer_vop_nsymlink(struct vop_nsymlink_args *ap)
2056 {
2057         struct hammer_transaction trans;
2058         struct hammer_inode *dip;
2059         struct hammer_inode *nip;
2060         struct nchandle *nch;
2061         hammer_record_t record;
2062         int error;
2063         int bytes;
2064
2065         ap->a_vap->va_type = VLNK;
2066
2067         nch = ap->a_nch;
2068         dip = VTOI(ap->a_dvp);
2069
2070         if (dip->flags & HAMMER_INODE_RO)
2071                 return (EROFS);
2072         if ((error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_CREATE)) != 0)
2073                 return (error);
2074
2075         /*
2076          * Create a transaction to cover the operations we perform.
2077          */
2078         hammer_start_transaction(&trans, dip->hmp);
2079         ++hammer_stats_file_iopsw;
2080
2081         /*
2082          * Create a new filesystem object of the requested type.  The
2083          * returned inode will be referenced but not locked.
2084          */
2085
2086         error = hammer_create_inode(&trans, ap->a_vap, ap->a_cred,
2087                                     dip, nch->ncp->nc_name, nch->ncp->nc_nlen,
2088                                     NULL, &nip);
2089         if (error) {
2090                 hammer_done_transaction(&trans);
2091                 *ap->a_vpp = NULL;
2092                 return (error);
2093         }
2094
2095         /*
2096          * Add a record representing the symlink.  symlink stores the link
2097          * as pure data, not a string, and is no \0 terminated.
2098          */
2099         if (error == 0) {
2100                 bytes = strlen(ap->a_target);
2101
2102                 if (bytes <= HAMMER_INODE_BASESYMLEN) {
2103                         bcopy(ap->a_target, nip->ino_data.ext.symlink, bytes);
2104                 } else {
2105                         record = hammer_alloc_mem_record(nip, bytes);
2106                         record->type = HAMMER_MEM_RECORD_GENERAL;
2107
2108                         record->leaf.base.localization = nip->obj_localization +
2109                                                          HAMMER_LOCALIZE_MISC;
2110                         record->leaf.base.key = HAMMER_FIXKEY_SYMLINK;
2111                         record->leaf.base.rec_type = HAMMER_RECTYPE_FIX;
2112                         record->leaf.data_len = bytes;
2113                         KKASSERT(HAMMER_SYMLINK_NAME_OFF == 0);
2114                         bcopy(ap->a_target, record->data->symlink.name, bytes);
2115                         error = hammer_ip_add_record(&trans, record);
2116                 }
2117
2118                 /*
2119                  * Set the file size to the length of the link.
2120                  */
2121                 if (error == 0) {
2122                         nip->ino_data.size = bytes;
2123                         hammer_modify_inode(nip, HAMMER_INODE_DDIRTY);
2124                 }
2125         }
2126         if (error == 0)
2127                 error = hammer_ip_add_directory(&trans, dip, nch->ncp->nc_name,
2128                                                 nch->ncp->nc_nlen, nip);
2129
2130         /*
2131          * Finish up.
2132          */
2133         if (error) {
2134                 hammer_rel_inode(nip, 0);
2135                 *ap->a_vpp = NULL;
2136         } else {
2137                 error = hammer_get_vnode(nip, ap->a_vpp);
2138                 hammer_rel_inode(nip, 0);
2139                 if (error == 0) {
2140                         cache_setunresolved(ap->a_nch);
2141                         cache_setvp(ap->a_nch, *ap->a_vpp);
2142                         hammer_knote(ap->a_dvp, NOTE_WRITE);
2143                 }
2144         }
2145         hammer_done_transaction(&trans);
2146         return (error);
2147 }
2148
2149 /*
2150  * hammer_vop_nwhiteout { nch, dvp, cred, flags }
2151  */
2152 static
2153 int
2154 hammer_vop_nwhiteout(struct vop_nwhiteout_args *ap)
2155 {
2156         struct hammer_transaction trans;
2157         struct hammer_inode *dip;
2158         int error;
2159
2160         dip = VTOI(ap->a_dvp);
2161
2162         if (hammer_nohistory(dip) == 0 &&
2163             (error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_CREATE)) != 0) {
2164                 return (error);
2165         }
2166
2167         hammer_start_transaction(&trans, dip->hmp);
2168         ++hammer_stats_file_iopsw;
2169         error = hammer_dounlink(&trans, ap->a_nch, ap->a_dvp,
2170                                 ap->a_cred, ap->a_flags, -1);
2171         hammer_done_transaction(&trans);
2172
2173         return (error);
2174 }
2175
2176 /*
2177  * hammer_vop_ioctl { vp, command, data, fflag, cred }
2178  */
2179 static
2180 int
2181 hammer_vop_ioctl(struct vop_ioctl_args *ap)
2182 {
2183         struct hammer_inode *ip = ap->a_vp->v_data;
2184
2185         ++hammer_stats_file_iopsr;
2186         return(hammer_ioctl(ip, ap->a_command, ap->a_data,
2187                             ap->a_fflag, ap->a_cred));
2188 }
2189
2190 static
2191 int
2192 hammer_vop_mountctl(struct vop_mountctl_args *ap)
2193 {
2194         static const struct mountctl_opt extraopt[] = {
2195                 { HMNT_NOHISTORY,       "nohistory" },
2196                 { HMNT_MASTERID,        "master" },
2197                 { 0, NULL}
2198
2199         };
2200         struct hammer_mount *hmp;
2201         struct mount *mp;
2202         int usedbytes;
2203         int error;
2204         char *pos;
2205
2206         error = 0;
2207         usedbytes = 0;
2208         mp = ap->a_head.a_ops->head.vv_mount;
2209         KKASSERT(mp->mnt_data != NULL);
2210         hmp = (struct hammer_mount *)mp->mnt_data;
2211
2212         switch(ap->a_op) {
2213
2214         case MOUNTCTL_SET_EXPORT:
2215                 if (ap->a_ctllen != sizeof(struct export_args))
2216                         error = EINVAL;
2217                 else
2218                         error = hammer_vfs_export(mp, ap->a_op,
2219                                       (const struct export_args *)ap->a_ctl);
2220                 break;
2221         case MOUNTCTL_MOUNTFLAGS:
2222         {
2223                 /*
2224                  * Call standard mountctl VOP function
2225                  * so we get user mount flags.
2226                  */
2227                 error = vop_stdmountctl(ap);
2228                 if (error)
2229                         break;
2230
2231                 usedbytes = *ap->a_res;
2232
2233                 if (usedbytes && usedbytes < ap->a_buflen) {
2234                         pos = (char *)ap->a_buf + usedbytes;
2235                         *pos++ = ','; /* Overwrite trailing \0 */
2236                         usedbytes++;
2237
2238                         usedbytes += vfs_flagstostr(hmp->hflags, extraopt, ap->a_buf,
2239                                                     ap->a_buflen - usedbytes,
2240                                                     &error);
2241
2242                         /* Remove trailing comma if  no HAMMER flags returned */
2243                         if (usedbytes == *ap->a_res) {
2244                                 *pos-- = 0;
2245                                 usedbytes--;
2246                         }
2247
2248                 }
2249
2250                 *ap->a_res += usedbytes;
2251                 break;
2252         }
2253         default:
2254                 error = vop_stdmountctl(ap);
2255                 break;
2256         }
2257         return(error);
2258 }
2259
2260 /*
2261  * hammer_vop_strategy { vp, bio }
2262  *
2263  * Strategy call, used for regular file read & write only.  Note that the
2264  * bp may represent a cluster.
2265  *
2266  * To simplify operation and allow better optimizations in the future,
2267  * this code does not make any assumptions with regards to buffer alignment
2268  * or size.
2269  */
2270 static
2271 int
2272 hammer_vop_strategy(struct vop_strategy_args *ap)
2273 {
2274         struct buf *bp;
2275         int error;
2276
2277         bp = ap->a_bio->bio_buf;
2278
2279         switch(bp->b_cmd) {
2280         case BUF_CMD_READ:
2281                 error = hammer_vop_strategy_read(ap);
2282                 break;
2283         case BUF_CMD_WRITE:
2284                 error = hammer_vop_strategy_write(ap);
2285                 break;
2286         default:
2287                 bp->b_error = error = EINVAL;
2288                 bp->b_flags |= B_ERROR;
2289                 biodone(ap->a_bio);
2290                 break;
2291         }
2292         return (error);
2293 }
2294
2295 /*
2296  * Read from a regular file.  Iterate the related records and fill in the
2297  * BIO/BUF.  Gaps are zero-filled.
2298  *
2299  * The support code in hammer_object.c should be used to deal with mixed
2300  * in-memory and on-disk records.
2301  *
2302  * NOTE: Can be called from the cluster code with an oversized buf.
2303  *
2304  * XXX atime update
2305  */
2306 static
2307 int
2308 hammer_vop_strategy_read(struct vop_strategy_args *ap)
2309 {
2310         struct hammer_transaction trans;
2311         struct hammer_inode *ip;
2312         struct hammer_inode *dip;
2313         struct hammer_cursor cursor;
2314         hammer_base_elm_t base;
2315         hammer_off_t disk_offset;
2316         struct bio *bio;
2317         struct bio *nbio;
2318         struct buf *bp;
2319         int64_t rec_offset;
2320         int64_t ran_end;
2321         int64_t tmp64;
2322         int error;
2323         int boff;
2324         int roff;
2325         int n;
2326
2327         bio = ap->a_bio;
2328         bp = bio->bio_buf;
2329         ip = ap->a_vp->v_data;
2330
2331         /*
2332          * The zone-2 disk offset may have been set by the cluster code via
2333          * a BMAP operation, or else should be NOOFFSET.
2334          *
2335          * Checking the high bits for a match against zone-2 should suffice.
2336          */
2337         nbio = push_bio(bio);
2338         if ((nbio->bio_offset & HAMMER_OFF_ZONE_MASK) ==
2339             HAMMER_ZONE_LARGE_DATA) {
2340                 error = hammer_io_direct_read(ip->hmp, nbio, NULL);
2341                 return (error);
2342         }
2343
2344         /*
2345          * Well, that sucked.  Do it the hard way.  If all the stars are
2346          * aligned we may still be able to issue a direct-read.
2347          */
2348         hammer_simple_transaction(&trans, ip->hmp);
2349         hammer_init_cursor(&trans, &cursor, &ip->cache[1], ip);
2350
2351         /*
2352          * Key range (begin and end inclusive) to scan.  Note that the key's
2353          * stored in the actual records represent BASE+LEN, not BASE.  The
2354          * first record containing bio_offset will have a key > bio_offset.
2355          */
2356         cursor.key_beg.localization = ip->obj_localization +
2357                                       HAMMER_LOCALIZE_MISC;
2358         cursor.key_beg.obj_id = ip->obj_id;
2359         cursor.key_beg.create_tid = 0;
2360         cursor.key_beg.delete_tid = 0;
2361         cursor.key_beg.obj_type = 0;
2362         cursor.key_beg.key = bio->bio_offset + 1;
2363         cursor.asof = ip->obj_asof;
2364         cursor.flags |= HAMMER_CURSOR_ASOF;
2365
2366         cursor.key_end = cursor.key_beg;
2367         KKASSERT(ip->ino_data.obj_type == HAMMER_OBJTYPE_REGFILE);
2368 #if 0
2369         if (ip->ino_data.obj_type == HAMMER_OBJTYPE_DBFILE) {
2370                 cursor.key_beg.rec_type = HAMMER_RECTYPE_DB;
2371                 cursor.key_end.rec_type = HAMMER_RECTYPE_DB;
2372                 cursor.key_end.key = 0x7FFFFFFFFFFFFFFFLL;
2373         } else
2374 #endif
2375         {
2376                 ran_end = bio->bio_offset + bp->b_bufsize;
2377                 cursor.key_beg.rec_type = HAMMER_RECTYPE_DATA;
2378                 cursor.key_end.rec_type = HAMMER_RECTYPE_DATA;
2379                 tmp64 = ran_end + MAXPHYS + 1;  /* work-around GCC-4 bug */
2380                 if (tmp64 < ran_end)
2381                         cursor.key_end.key = 0x7FFFFFFFFFFFFFFFLL;
2382                 else
2383                         cursor.key_end.key = ran_end + MAXPHYS + 1;
2384         }
2385         cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
2386
2387         error = hammer_ip_first(&cursor);
2388         boff = 0;
2389
2390         while (error == 0) {
2391                 /*
2392                  * Get the base file offset of the record.  The key for
2393                  * data records is (base + bytes) rather then (base).
2394                  */
2395                 base = &cursor.leaf->base;
2396                 rec_offset = base->key - cursor.leaf->data_len;
2397
2398                 /*
2399                  * Calculate the gap, if any, and zero-fill it.
2400                  *
2401                  * n is the offset of the start of the record verses our
2402                  * current seek offset in the bio.
2403                  */
2404                 n = (int)(rec_offset - (bio->bio_offset + boff));
2405                 if (n > 0) {
2406                         if (n > bp->b_bufsize - boff)
2407                                 n = bp->b_bufsize - boff;
2408                         bzero((char *)bp->b_data + boff, n);
2409                         boff += n;
2410                         n = 0;
2411                 }
2412
2413                 /*
2414                  * Calculate the data offset in the record and the number
2415                  * of bytes we can copy.
2416                  *
2417                  * There are two degenerate cases.  First, boff may already
2418                  * be at bp->b_bufsize.  Secondly, the data offset within
2419                  * the record may exceed the record's size.
2420                  */
2421                 roff = -n;
2422                 rec_offset += roff;
2423                 n = cursor.leaf->data_len - roff;
2424                 if (n <= 0) {
2425                         kprintf("strategy_read: bad n=%d roff=%d\n", n, roff);
2426                         n = 0;
2427                 } else if (n > bp->b_bufsize - boff) {
2428                         n = bp->b_bufsize - boff;
2429                 }
2430
2431                 /*
2432                  * Deal with cached truncations.  This cool bit of code
2433                  * allows truncate()/ftruncate() to avoid having to sync
2434                  * the file.
2435                  *
2436                  * If the frontend is truncated then all backend records are
2437                  * subject to the frontend's truncation.
2438                  *
2439                  * If the backend is truncated then backend records on-disk
2440                  * (but not in-memory) are subject to the backend's
2441                  * truncation.  In-memory records owned by the backend
2442                  * represent data written after the truncation point on the
2443                  * backend and must not be truncated.
2444                  *
2445                  * Truncate operations deal with frontend buffer cache
2446                  * buffers and frontend-owned in-memory records synchronously.
2447                  */
2448                 if (ip->flags & HAMMER_INODE_TRUNCATED) {
2449                         if (hammer_cursor_ondisk(&cursor) ||
2450                             cursor.iprec->flush_state == HAMMER_FST_FLUSH) {
2451                                 if (ip->trunc_off <= rec_offset)
2452                                         n = 0;
2453                                 else if (ip->trunc_off < rec_offset + n)
2454                                         n = (int)(ip->trunc_off - rec_offset);
2455                         }
2456                 }
2457                 if (ip->sync_flags & HAMMER_INODE_TRUNCATED) {
2458                         if (hammer_cursor_ondisk(&cursor)) {
2459                                 if (ip->sync_trunc_off <= rec_offset)
2460                                         n = 0;
2461                                 else if (ip->sync_trunc_off < rec_offset + n)
2462                                         n = (int)(ip->sync_trunc_off - rec_offset);
2463                         }
2464                 }
2465
2466                 /*
2467                  * Try to issue a direct read into our bio if possible,
2468                  * otherwise resolve the element data into a hammer_buffer
2469                  * and copy.
2470                  *
2471                  * The buffer on-disk should be zerod past any real
2472                  * truncation point, but may not be for any synthesized
2473                  * truncation point from above.
2474                  */
2475                 disk_offset = cursor.leaf->data_offset + roff;
2476                 if (boff == 0 && n == bp->b_bufsize &&
2477                     hammer_cursor_ondisk(&cursor) &&
2478                     (disk_offset & HAMMER_BUFMASK) == 0) {
2479                         KKASSERT((disk_offset & HAMMER_OFF_ZONE_MASK) ==
2480                                  HAMMER_ZONE_LARGE_DATA);
2481                         nbio->bio_offset = disk_offset;
2482                         error = hammer_io_direct_read(trans.hmp, nbio,
2483                                                       cursor.leaf);
2484                         goto done;
2485                 } else if (n) {
2486                         error = hammer_ip_resolve_data(&cursor);
2487                         if (error == 0) {
2488                                 bcopy((char *)cursor.data + roff,
2489                                       (char *)bp->b_data + boff, n);
2490                         }
2491                 }
2492                 if (error)
2493                         break;
2494
2495                 /*
2496                  * Iterate until we have filled the request.
2497                  */
2498                 boff += n;
2499                 if (boff == bp->b_bufsize)
2500                         break;
2501                 error = hammer_ip_next(&cursor);
2502         }
2503
2504         /*
2505          * There may have been a gap after the last record
2506          */
2507         if (error == ENOENT)
2508                 error = 0;
2509         if (error == 0 && boff != bp->b_bufsize) {
2510                 KKASSERT(boff < bp->b_bufsize);
2511                 bzero((char *)bp->b_data + boff, bp->b_bufsize - boff);
2512                 /* boff = bp->b_bufsize; */
2513         }
2514         bp->b_resid = 0;
2515         bp->b_error = error;
2516         if (error)
2517                 bp->b_flags |= B_ERROR;
2518         biodone(ap->a_bio);
2519
2520 done:
2521         /*
2522          * Cache the b-tree node for the last data read in cache[1].
2523          *
2524          * If we hit the file EOF then also cache the node in the
2525          * governing director's cache[3], it will be used to initialize
2526          * the inode's cache[1] for any inodes looked up via the directory.
2527          *
2528          * This doesn't reduce disk accesses since the B-Tree chain is
2529          * likely cached, but it does reduce cpu overhead when looking
2530          * up file offsets for cpdup/tar/cpio style iterations.
2531          */
2532         if (cursor.node)
2533                 hammer_cache_node(&ip->cache[1], cursor.node);
2534         if (ran_end >= ip->ino_data.size) {
2535                 dip = hammer_find_inode(&trans, ip->ino_data.parent_obj_id,
2536                                         ip->obj_asof, ip->obj_localization);
2537                 if (dip) {
2538                         hammer_cache_node(&dip->cache[3], cursor.node);
2539                         hammer_rel_inode(dip, 0);
2540                 }
2541         }
2542         hammer_done_cursor(&cursor);
2543         hammer_done_transaction(&trans);
2544         return(error);
2545 }
2546
2547 /*
2548  * BMAP operation - used to support cluster_read() only.
2549  *
2550  * (struct vnode *vp, off_t loffset, off_t *doffsetp, int *runp, int *runb)
2551  *
2552  * This routine may return EOPNOTSUPP if the opration is not supported for
2553  * the specified offset.  The contents of the pointer arguments do not
2554  * need to be initialized in that case. 
2555  *
2556  * If a disk address is available and properly aligned return 0 with 
2557  * *doffsetp set to the zone-2 address, and *runp / *runb set appropriately
2558  * to the run-length relative to that offset.  Callers may assume that
2559  * *doffsetp is valid if 0 is returned, even if *runp is not sufficiently
2560  * large, so return EOPNOTSUPP if it is not sufficiently large.
2561  */
2562 static
2563 int
2564 hammer_vop_bmap(struct vop_bmap_args *ap)
2565 {
2566         struct hammer_transaction trans;
2567         struct hammer_inode *ip;
2568         struct hammer_cursor cursor;
2569         hammer_base_elm_t base;
2570         int64_t rec_offset;
2571         int64_t ran_end;
2572         int64_t tmp64;
2573         int64_t base_offset;
2574         int64_t base_disk_offset;
2575         int64_t last_offset;
2576         hammer_off_t last_disk_offset;
2577         hammer_off_t disk_offset;
2578         int     rec_len;
2579         int     error;
2580         int     blksize;
2581
2582         ++hammer_stats_file_iopsr;
2583         ip = ap->a_vp->v_data;
2584
2585         /*
2586          * We can only BMAP regular files.  We can't BMAP database files,
2587          * directories, etc.
2588          */
2589         if (ip->ino_data.obj_type != HAMMER_OBJTYPE_REGFILE)
2590                 return(EOPNOTSUPP);
2591
2592         /*
2593          * bmap is typically called with runp/runb both NULL when used
2594          * for writing.  We do not support BMAP for writing atm.
2595          */
2596         if (ap->a_cmd != BUF_CMD_READ)
2597                 return(EOPNOTSUPP);
2598
2599         /*
2600          * Scan the B-Tree to acquire blockmap addresses, then translate
2601          * to raw addresses.
2602          */
2603         hammer_simple_transaction(&trans, ip->hmp);
2604 #if 0
2605         kprintf("bmap_beg %016llx ip->cache %p\n",
2606                 (long long)ap->a_loffset, ip->cache[1]);
2607 #endif
2608         hammer_init_cursor(&trans, &cursor, &ip->cache[1], ip);
2609
2610         /*
2611          * Key range (begin and end inclusive) to scan.  Note that the key's
2612          * stored in the actual records represent BASE+LEN, not BASE.  The
2613          * first record containing bio_offset will have a key > bio_offset.
2614          */
2615         cursor.key_beg.localization = ip->obj_localization +
2616                                       HAMMER_LOCALIZE_MISC;
2617         cursor.key_beg.obj_id = ip->obj_id;
2618         cursor.key_beg.create_tid = 0;
2619         cursor.key_beg.delete_tid = 0;
2620         cursor.key_beg.obj_type = 0;
2621         if (ap->a_runb)
2622                 cursor.key_beg.key = ap->a_loffset - MAXPHYS + 1;
2623         else
2624                 cursor.key_beg.key = ap->a_loffset + 1;
2625         if (cursor.key_beg.key < 0)
2626                 cursor.key_beg.key = 0;
2627         cursor.asof = ip->obj_asof;
2628         cursor.flags |= HAMMER_CURSOR_ASOF;
2629
2630         cursor.key_end = cursor.key_beg;
2631         KKASSERT(ip->ino_data.obj_type == HAMMER_OBJTYPE_REGFILE);
2632
2633         ran_end = ap->a_loffset + MAXPHYS;
2634         cursor.key_beg.rec_type = HAMMER_RECTYPE_DATA;
2635         cursor.key_end.rec_type = HAMMER_RECTYPE_DATA;
2636         tmp64 = ran_end + MAXPHYS + 1;  /* work-around GCC-4 bug */
2637         if (tmp64 < ran_end)
2638                 cursor.key_end.key = 0x7FFFFFFFFFFFFFFFLL;
2639         else
2640                 cursor.key_end.key = ran_end + MAXPHYS + 1;
2641
2642         cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
2643
2644         error = hammer_ip_first(&cursor);
2645         base_offset = last_offset = 0;
2646         base_disk_offset = last_disk_offset = 0;
2647
2648         while (error == 0) {
2649                 /*
2650                  * Get the base file offset of the record.  The key for
2651                  * data records is (base + bytes) rather then (base).
2652                  *
2653                  * NOTE: rec_offset + rec_len may exceed the end-of-file.
2654                  * The extra bytes should be zero on-disk and the BMAP op
2655                  * should still be ok.
2656                  */
2657                 base = &cursor.leaf->base;
2658                 rec_offset = base->key - cursor.leaf->data_len;
2659                 rec_len    = cursor.leaf->data_len;
2660
2661                 /*
2662                  * Incorporate any cached truncation.
2663                  *
2664                  * NOTE: Modifications to rec_len based on synthesized
2665                  * truncation points remove the guarantee that any extended
2666                  * data on disk is zero (since the truncations may not have
2667                  * taken place on-media yet).
2668                  */
2669                 if (ip->flags & HAMMER_INODE_TRUNCATED) {
2670                         if (hammer_cursor_ondisk(&cursor) ||
2671                             cursor.iprec->flush_state == HAMMER_FST_FLUSH) {
2672                                 if (ip->trunc_off <= rec_offset)
2673                                         rec_len = 0;
2674                                 else if (ip->trunc_off < rec_offset + rec_len)
2675                                         rec_len = (int)(ip->trunc_off - rec_offset);
2676                         }
2677                 }
2678                 if (ip->sync_flags & HAMMER_INODE_TRUNCATED) {
2679                         if (hammer_cursor_ondisk(&cursor)) {
2680                                 if (ip->sync_trunc_off <= rec_offset)
2681                                         rec_len = 0;
2682                                 else if (ip->sync_trunc_off < rec_offset + rec_len)
2683                                         rec_len = (int)(ip->sync_trunc_off - rec_offset);
2684                         }
2685                 }
2686
2687                 /*
2688                  * Accumulate information.  If we have hit a discontiguous
2689                  * block reset base_offset unless we are already beyond the
2690                  * requested offset.  If we are, that's it, we stop.
2691                  */
2692                 if (error)
2693                         break;
2694                 if (hammer_cursor_ondisk(&cursor)) {
2695                         disk_offset = cursor.leaf->data_offset;
2696                         if (rec_offset != last_offset ||
2697                             disk_offset != last_disk_offset) {
2698                                 if (rec_offset > ap->a_loffset)
2699                                         break;
2700                                 base_offset = rec_offset;
2701                                 base_disk_offset = disk_offset;
2702                         }
2703                         last_offset = rec_offset + rec_len;
2704                         last_disk_offset = disk_offset + rec_len;
2705                 }
2706                 error = hammer_ip_next(&cursor);
2707         }
2708
2709 #if 0
2710         kprintf("BMAP %016llx:  %016llx - %016llx\n",
2711                 (long long)ap->a_loffset,
2712                 (long long)base_offset,
2713                 (long long)last_offset);
2714         kprintf("BMAP %16s:  %016llx - %016llx\n", "",
2715                 (long long)base_disk_offset,
2716                 (long long)last_disk_offset);
2717 #endif
2718
2719         if (cursor.node) {
2720                 hammer_cache_node(&ip->cache[1], cursor.node);
2721 #if 0
2722                 kprintf("bmap_end2 %016llx ip->cache %p\n",
2723                         (long long)ap->a_loffset, ip->cache[1]);
2724 #endif
2725         }
2726         hammer_done_cursor(&cursor);
2727         hammer_done_transaction(&trans);
2728
2729         /*
2730          * If we couldn't find any records or the records we did find were
2731          * all behind the requested offset, return failure.  A forward
2732          * truncation can leave a hole w/ no on-disk records.
2733          */
2734         if (last_offset == 0 || last_offset < ap->a_loffset)
2735                 return (EOPNOTSUPP);
2736
2737         /*
2738          * Figure out the block size at the requested offset and adjust
2739          * our limits so the cluster_read() does not create inappropriately
2740          * sized buffer cache buffers.
2741          */
2742         blksize = hammer_blocksize(ap->a_loffset);
2743         if (hammer_blocksize(base_offset) != blksize) {
2744                 base_offset = hammer_blockdemarc(base_offset, ap->a_loffset);
2745         }
2746         if (last_offset != ap->a_loffset &&
2747             hammer_blocksize(last_offset - 1) != blksize) {
2748                 last_offset = hammer_blockdemarc(ap->a_loffset,
2749                                                  last_offset - 1);
2750         }
2751
2752         /*
2753          * Returning EOPNOTSUPP simply prevents the direct-IO optimization
2754          * from occuring.
2755          */
2756         disk_offset = base_disk_offset + (ap->a_loffset - base_offset);
2757
2758         if ((disk_offset & HAMMER_OFF_ZONE_MASK) != HAMMER_ZONE_LARGE_DATA) {
2759                 /*
2760                  * Only large-data zones can be direct-IOd
2761                  */
2762                 error = EOPNOTSUPP;
2763         } else if ((disk_offset & HAMMER_BUFMASK) ||
2764                    (last_offset - ap->a_loffset) < blksize) {
2765                 /*
2766                  * doffsetp is not aligned or the forward run size does
2767                  * not cover a whole buffer, disallow the direct I/O.
2768                  */
2769                 error = EOPNOTSUPP;
2770         } else {
2771                 /*
2772                  * We're good.
2773                  */
2774                 *ap->a_doffsetp = disk_offset;
2775                 if (ap->a_runb) {
2776                         *ap->a_runb = ap->a_loffset - base_offset;
2777                         KKASSERT(*ap->a_runb >= 0);
2778                 }
2779                 if (ap->a_runp) {
2780                         *ap->a_runp = last_offset - ap->a_loffset;
2781                         KKASSERT(*ap->a_runp >= 0);
2782                 }
2783                 error = 0;
2784         }
2785         return(error);
2786 }
2787
2788 /*
2789  * Write to a regular file.   Because this is a strategy call the OS is
2790  * trying to actually get data onto the media.
2791  */
2792 static
2793 int
2794 hammer_vop_strategy_write(struct vop_strategy_args *ap)
2795 {
2796         hammer_record_t record;
2797         hammer_mount_t hmp;
2798         hammer_inode_t ip;
2799         struct bio *bio;
2800         struct buf *bp;
2801         int blksize;
2802         int bytes;
2803         int error;
2804
2805         bio = ap->a_bio;
2806         bp = bio->bio_buf;
2807         ip = ap->a_vp->v_data;
2808         hmp = ip->hmp;
2809
2810         blksize = hammer_blocksize(bio->bio_offset);
2811         KKASSERT(bp->b_bufsize == blksize);
2812
2813         if (ip->flags & HAMMER_INODE_RO) {
2814                 bp->b_error = EROFS;
2815                 bp->b_flags |= B_ERROR;
2816                 biodone(ap->a_bio);
2817                 return(EROFS);
2818         }
2819
2820         /*
2821          * Interlock with inode destruction (no in-kernel or directory
2822          * topology visibility).  If we queue new IO while trying to
2823          * destroy the inode we can deadlock the vtrunc call in
2824          * hammer_inode_unloadable_check().
2825          *
2826          * Besides, there's no point flushing a bp associated with an
2827          * inode that is being destroyed on-media and has no kernel
2828          * references.
2829          */
2830         if ((ip->flags | ip->sync_flags) &
2831             (HAMMER_INODE_DELETING|HAMMER_INODE_DELETED)) {
2832                 bp->b_resid = 0;
2833                 biodone(ap->a_bio);
2834                 return(0);
2835         }
2836
2837         /*
2838          * Reserve space and issue a direct-write from the front-end. 
2839          * NOTE: The direct_io code will hammer_bread/bcopy smaller
2840          * allocations.
2841          *
2842          * An in-memory record will be installed to reference the storage
2843          * until the flusher can get to it.
2844          *
2845          * Since we own the high level bio the front-end will not try to
2846          * do a direct-read until the write completes.
2847          *
2848          * NOTE: The only time we do not reserve a full-sized buffers
2849          * worth of data is if the file is small.  We do not try to
2850          * allocate a fragment (from the small-data zone) at the end of
2851          * an otherwise large file as this can lead to wildly separated
2852          * data.
2853          */
2854         KKASSERT((bio->bio_offset & HAMMER_BUFMASK) == 0);
2855         KKASSERT(bio->bio_offset < ip->ino_data.size);
2856         if (bio->bio_offset || ip->ino_data.size > HAMMER_BUFSIZE / 2)
2857                 bytes = bp->b_bufsize;
2858         else
2859                 bytes = ((int)ip->ino_data.size + 15) & ~15;
2860
2861         record = hammer_ip_add_bulk(ip, bio->bio_offset, bp->b_data,
2862                                     bytes, &error);
2863         if (record) {
2864                 hammer_io_direct_write(hmp, record, bio);
2865                 if (ip->rsv_recs > 1 && hmp->rsv_recs > hammer_limit_recs)
2866                         hammer_flush_inode(ip, 0);
2867         } else {
2868                 bp->b_bio2.bio_offset = NOOFFSET;
2869                 bp->b_error = error;
2870                 bp->b_flags |= B_ERROR;
2871                 biodone(ap->a_bio);
2872         }
2873         return(error);
2874 }
2875
2876 /*
2877  * dounlink - disconnect a directory entry
2878  *
2879  * XXX whiteout support not really in yet
2880  */
2881 static int
2882 hammer_dounlink(hammer_transaction_t trans, struct nchandle *nch,
2883                 struct vnode *dvp, struct ucred *cred, 
2884                 int flags, int isdir)
2885 {
2886         struct namecache *ncp;
2887         hammer_inode_t dip;
2888         hammer_inode_t ip;
2889         struct hammer_cursor cursor;
2890         int64_t namekey;
2891         u_int32_t max_iterations;
2892         int nlen, error;
2893
2894         /*
2895          * Calculate the namekey and setup the key range for the scan.  This
2896          * works kinda like a chained hash table where the lower 32 bits
2897          * of the namekey synthesize the chain.
2898          *
2899          * The key range is inclusive of both key_beg and key_end.
2900          */
2901         dip = VTOI(dvp);
2902         ncp = nch->ncp;
2903
2904         if (dip->flags & HAMMER_INODE_RO)
2905                 return (EROFS);
2906
2907         namekey = hammer_directory_namekey(dip, ncp->nc_name, ncp->nc_nlen,
2908                                            &max_iterations);
2909 retry:
2910         hammer_init_cursor(trans, &cursor, &dip->cache[1], dip);
2911         cursor.key_beg.localization = dip->obj_localization +
2912                                       hammer_dir_localization(dip);
2913         cursor.key_beg.obj_id = dip->obj_id;
2914         cursor.key_beg.key = namekey;
2915         cursor.key_beg.create_tid = 0;
2916         cursor.key_beg.delete_tid = 0;
2917         cursor.key_beg.rec_type = HAMMER_RECTYPE_DIRENTRY;
2918         cursor.key_beg.obj_type = 0;
2919
2920         cursor.key_end = cursor.key_beg;
2921         cursor.key_end.key += max_iterations;
2922         cursor.asof = dip->obj_asof;
2923         cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE | HAMMER_CURSOR_ASOF;
2924
2925         /*
2926          * Scan all matching records (the chain), locate the one matching
2927          * the requested path component.  info->last_error contains the
2928          * error code on search termination and could be 0, ENOENT, or
2929          * something else.
2930          *
2931          * The hammer_ip_*() functions merge in-memory records with on-disk
2932          * records for the purposes of the search.
2933          */
2934         error = hammer_ip_first(&cursor);
2935
2936         while (error == 0) {
2937                 error = hammer_ip_resolve_data(&cursor);
2938                 if (error)
2939                         break;
2940                 nlen = cursor.leaf->data_len - HAMMER_ENTRY_NAME_OFF;
2941                 KKASSERT(nlen > 0);
2942                 if (ncp->nc_nlen == nlen &&
2943                     bcmp(ncp->nc_name, cursor.data->entry.name, nlen) == 0) {
2944                         break;
2945                 }
2946                 error = hammer_ip_next(&cursor);
2947         }
2948
2949         /*
2950          * If all is ok we have to get the inode so we can adjust nlinks.
2951          * To avoid a deadlock with the flusher we must release the inode
2952          * lock on the directory when acquiring the inode for the entry.
2953          *
2954          * If the target is a directory, it must be empty.
2955          */
2956         if (error == 0) {
2957                 hammer_unlock(&cursor.ip->lock);
2958                 ip = hammer_get_inode(trans, dip, cursor.data->entry.obj_id,
2959                                       dip->hmp->asof,
2960                                       cursor.data->entry.localization,
2961                                       0, &error);
2962                 hammer_lock_sh(&cursor.ip->lock);
2963                 if (error == ENOENT) {
2964                         kprintf("HAMMER: WARNING: Removing "
2965                                 "dirent w/missing inode \"%s\"\n"
2966                                 "\tobj_id = %016llx\n",
2967                                 ncp->nc_name,
2968                                 (long long)cursor.data->entry.obj_id);
2969                         error = 0;
2970                 }
2971
2972                 /*
2973                  * If isdir >= 0 we validate that the entry is or is not a
2974                  * directory.  If isdir < 0 we don't care.
2975                  */
2976                 if (error == 0 && isdir >= 0 && ip) {
2977                         if (isdir &&
2978                             ip->ino_data.obj_type != HAMMER_OBJTYPE_DIRECTORY) {
2979                                 error = ENOTDIR;
2980                         } else if (isdir == 0 &&
2981                             ip->ino_data.obj_type == HAMMER_OBJTYPE_DIRECTORY) {
2982                                 error = EISDIR;
2983                         }
2984                 }
2985
2986                 /*
2987                  * If we are trying to remove a directory the directory must
2988                  * be empty.
2989                  *
2990                  * The check directory code can loop and deadlock/retry.  Our
2991                  * own cursor's node locks must be released to avoid a 3-way
2992                  * deadlock with the flusher if the check directory code
2993                  * blocks.
2994                  *
2995                  * If any changes whatsoever have been made to the cursor
2996                  * set EDEADLK and retry.
2997                  */
2998                 if (error == 0 && ip && ip->ino_data.obj_type ==
2999                                         HAMMER_OBJTYPE_DIRECTORY) {
3000                         hammer_unlock_cursor(&cursor);
3001                         error = hammer_ip_check_directory_empty(trans, ip);
3002                         hammer_lock_cursor(&cursor);
3003                         if (cursor.flags & HAMMER_CURSOR_RETEST) {
3004                                 kprintf("HAMMER: Warning: avoided deadlock "
3005                                         "on rmdir '%s'\n",
3006                                         ncp->nc_name);
3007                                 error = EDEADLK;
3008                         }
3009                 }
3010
3011                 /*
3012                  * Delete the directory entry.
3013                  *
3014                  * WARNING: hammer_ip_del_directory() may have to terminate
3015                  * the cursor to avoid a deadlock.  It is ok to call
3016                  * hammer_done_cursor() twice.
3017                  */
3018                 if (error == 0) {
3019                         error = hammer_ip_del_directory(trans, &cursor,
3020                                                         dip, ip);
3021                 }
3022                 hammer_done_cursor(&cursor);
3023                 if (error == 0) {
3024                         cache_setunresolved(nch);
3025                         cache_setvp(nch, NULL);
3026                         /* XXX locking */
3027                         if (ip && ip->vp) {
3028                                 hammer_knote(ip->vp, NOTE_DELETE);
3029                                 cache_inval_vp(ip->vp, CINV_DESTROY);
3030                         }
3031                 }
3032                 if (ip)
3033                         hammer_rel_inode(ip, 0);
3034         } else {
3035                 hammer_done_cursor(&cursor);
3036         }
3037         if (error == EDEADLK)
3038                 goto retry;
3039
3040         return (error);
3041 }
3042
3043 /************************************************************************
3044  *                          FIFO AND SPECFS OPS                         *
3045  ************************************************************************
3046  *
3047  */
3048
3049 static int
3050 hammer_vop_fifoclose (struct vop_close_args *ap)
3051 {
3052         /* XXX update itimes */
3053         return (VOCALL(&fifo_vnode_vops, &ap->a_head));
3054 }
3055
3056 static int
3057 hammer_vop_fiforead (struct vop_read_args *ap)
3058 {
3059         int error;
3060
3061         error = VOCALL(&fifo_vnode_vops, &ap->a_head);
3062         /* XXX update access time */
3063         return (error);
3064 }
3065
3066 static int
3067 hammer_vop_fifowrite (struct vop_write_args *ap)
3068 {
3069         int error;
3070
3071         error = VOCALL(&fifo_vnode_vops, &ap->a_head);
3072         /* XXX update access time */
3073         return (error);
3074 }
3075
3076 static
3077 int
3078 hammer_vop_fifokqfilter(struct vop_kqfilter_args *ap)
3079 {
3080         int error;
3081
3082         error = VOCALL(&fifo_vnode_vops, &ap->a_head);
3083         if (error)
3084                 error = hammer_vop_kqfilter(ap);
3085         return(error);
3086 }
3087
3088 /************************************************************************
3089  *                          KQFILTER OPS                                *
3090  ************************************************************************
3091  *
3092  */
3093 static void filt_hammerdetach(struct knote *kn);
3094 static int filt_hammerread(struct knote *kn, long hint);
3095 static int filt_hammerwrite(struct knote *kn, long hint);
3096 static int filt_hammervnode(struct knote *kn, long hint);
3097
3098 static struct filterops hammerread_filtops =
3099         { 1, NULL, filt_hammerdetach, filt_hammerread };
3100 static struct filterops hammerwrite_filtops =
3101         { 1, NULL, filt_hammerdetach, filt_hammerwrite };
3102 static struct filterops hammervnode_filtops =
3103         { 1, NULL, filt_hammerdetach, filt_hammervnode };
3104
3105 static
3106 int
3107 hammer_vop_kqfilter(struct vop_kqfilter_args *ap)
3108 {
3109         struct vnode *vp = ap->a_vp;
3110         struct knote *kn = ap->a_kn;
3111         lwkt_tokref vlock;
3112
3113         switch (kn->kn_filter) {
3114         case EVFILT_READ:
3115                 kn->kn_fop = &hammerread_filtops;
3116                 break;
3117         case EVFILT_WRITE:
3118                 kn->kn_fop = &hammerwrite_filtops;
3119                 break;
3120         case EVFILT_VNODE:
3121                 kn->kn_fop = &hammervnode_filtops;
3122                 break;
3123         default:
3124                 return (1);
3125         }
3126
3127         kn->kn_hook = (caddr_t)vp;
3128
3129         lwkt_gettoken(&vlock, &vp->v_token);
3130         SLIST_INSERT_HEAD(&vp->v_pollinfo.vpi_selinfo.si_note, kn, kn_selnext);
3131         lwkt_reltoken(&vlock);
3132
3133         return(0);
3134 }
3135
3136 static void
3137 filt_hammerdetach(struct knote *kn)
3138 {
3139         struct vnode *vp = (void *)kn->kn_hook;
3140         lwkt_tokref vlock;
3141
3142         lwkt_gettoken(&vlock, &vp->v_token);
3143         SLIST_REMOVE(&vp->v_pollinfo.vpi_selinfo.si_note,
3144                      kn, knote, kn_selnext);
3145         lwkt_reltoken(&vlock);
3146 }
3147
3148 static int
3149 filt_hammerread(struct knote *kn, long hint)
3150 {
3151         struct vnode *vp = (void *)kn->kn_hook;
3152         hammer_inode_t ip = VTOI(vp);
3153
3154         if (hint == NOTE_REVOKE) {
3155                 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
3156                 return(1);
3157         }
3158         kn->kn_data = ip->ino_data.size - kn->kn_fp->f_offset;
3159         return (kn->kn_data != 0);
3160 }
3161
3162 static int
3163 filt_hammerwrite(struct knote *kn, long hint)
3164 {
3165         if (hint == NOTE_REVOKE)
3166                 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
3167         kn->kn_data = 0;
3168         return (1);
3169 }
3170
3171 static int
3172 filt_hammervnode(struct knote *kn, long hint)
3173 {
3174         if (kn->kn_sfflags & hint)
3175                 kn->kn_fflags |= hint;
3176         if (hint == NOTE_REVOKE) {
3177                 kn->kn_flags |= EV_EOF;
3178                 return (1);
3179         }
3180         return (kn->kn_fflags != 0);
3181 }
3182