HAMMER 38E/Many: Undo/Synchronization and crash recovery
[dragonfly.git] / sys / vfs / hammer / hammer_inode.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_inode.c,v 1.41 2008/04/27 00:45:37 dillon Exp $
35  */
36
37 #include "hammer.h"
38 #include <sys/buf.h>
39 #include <sys/buf2.h>
40
41 static int hammer_unload_inode(struct hammer_inode *ip);
42 static void hammer_flush_inode_copysync(hammer_inode_t ip);
43 static int hammer_mark_record_callback(hammer_record_t rec, void *data);
44
45 /*
46  * The kernel is not actively referencing this vnode but is still holding
47  * it cached.
48  *
49  * This is called from the frontend.
50  */
51 int
52 hammer_vop_inactive(struct vop_inactive_args *ap)
53 {
54         struct hammer_inode *ip = VTOI(ap->a_vp);
55
56         /*
57          * Degenerate case
58          */
59         if (ip == NULL) {
60                 vrecycle(ap->a_vp);
61                 return(0);
62         }
63
64         /*
65          * If the inode no longer has any references we recover its
66          * in-memory resources immediately.
67          *
68          * NOTE: called from frontend, use ino_rec instead of sync_ino_rec.
69          */
70         if (ip->ino_rec.ino_nlinks == 0)
71                 vrecycle(ap->a_vp);
72         return(0);
73 }
74
75 /*
76  * Release the vnode association.  This is typically (but not always)
77  * the last reference on the inode and will flush the inode to the
78  * buffer cache.
79  *
80  * XXX Currently our sync code only runs through inodes with vnode
81  * associations, so we depend on hammer_rel_inode() to sync any inode
82  * record data to the block device prior to losing the association.
83  * Otherwise transactions that the user expected to be distinct by
84  * doing a manual sync may be merged.
85  */
86 int
87 hammer_vop_reclaim(struct vop_reclaim_args *ap)
88 {
89         struct hammer_inode *ip;
90         struct vnode *vp;
91
92         vp = ap->a_vp;
93
94         if ((ip = vp->v_data) != NULL) {
95                 vp->v_data = NULL;
96                 ip->vp = NULL;
97
98                 /*
99                  * Don't let too many dependancies build up on unreferenced
100                  * inodes or we could run ourselves out of memory.
101                  */
102                 if (TAILQ_FIRST(&ip->depend_list)) {
103                         ip->hmp->reclaim_count += ip->depend_count;
104                         if (ip->hmp->reclaim_count > 256) {
105                                 ip->hmp->reclaim_count = 0;
106                                 hammer_flusher_async(ip->hmp);
107                         }
108                 }
109                 hammer_rel_inode(ip, 1);
110         }
111         return(0);
112 }
113
114 /*
115  * Return a locked vnode for the specified inode.  The inode must be
116  * referenced but NOT LOCKED on entry and will remain referenced on
117  * return.
118  *
119  * Called from the frontend.
120  */
121 int
122 hammer_get_vnode(struct hammer_inode *ip, int lktype, struct vnode **vpp)
123 {
124         struct vnode *vp;
125         int error = 0;
126
127         for (;;) {
128                 if ((vp = ip->vp) == NULL) {
129                         error = getnewvnode(VT_HAMMER, ip->hmp->mp, vpp, 0, 0);
130                         if (error)
131                                 break;
132                         hammer_lock_ex(&ip->lock);
133                         if (ip->vp != NULL) {
134                                 hammer_unlock(&ip->lock);
135                                 vp->v_type = VBAD;
136                                 vx_put(vp);
137                                 continue;
138                         }
139                         hammer_ref(&ip->lock);
140                         vp = *vpp;
141                         ip->vp = vp;
142                         vp->v_type = hammer_get_vnode_type(
143                                             ip->ino_rec.base.base.obj_type);
144
145                         switch(ip->ino_rec.base.base.obj_type) {
146                         case HAMMER_OBJTYPE_CDEV:
147                         case HAMMER_OBJTYPE_BDEV:
148                                 vp->v_ops = &ip->hmp->mp->mnt_vn_spec_ops;
149                                 addaliasu(vp, ip->ino_data.rmajor,
150                                           ip->ino_data.rminor);
151                                 break;
152                         case HAMMER_OBJTYPE_FIFO:
153                                 vp->v_ops = &ip->hmp->mp->mnt_vn_fifo_ops;
154                                 break;
155                         default:
156                                 break;
157                         }
158
159                         /*
160                          * Only mark as the root vnode if the ip is not
161                          * historical, otherwise the VFS cache will get
162                          * confused.  The other half of the special handling
163                          * is in hammer_vop_nlookupdotdot().
164                          */
165                         if (ip->obj_id == HAMMER_OBJID_ROOT &&
166                             ip->obj_asof == ip->hmp->asof) {
167                                 vp->v_flag |= VROOT;
168                         }
169
170                         vp->v_data = (void *)ip;
171                         /* vnode locked by getnewvnode() */
172                         /* make related vnode dirty if inode dirty? */
173                         hammer_unlock(&ip->lock);
174                         if (vp->v_type == VREG)
175                                 vinitvmio(vp, ip->ino_rec.ino_size);
176                         break;
177                 }
178
179                 /*
180                  * loop if the vget fails (aka races), or if the vp
181                  * no longer matches ip->vp.
182                  */
183                 if (vget(vp, LK_EXCLUSIVE) == 0) {
184                         if (vp == ip->vp)
185                                 break;
186                         vput(vp);
187                 }
188         }
189         *vpp = vp;
190         return(error);
191 }
192
193 /*
194  * Acquire a HAMMER inode.  The returned inode is not locked.  These functions
195  * do not attach or detach the related vnode (use hammer_get_vnode() for
196  * that).
197  *
198  * The flags argument is only applied for newly created inodes, and only
199  * certain flags are inherited.
200  *
201  * Called from the frontend.
202  */
203 struct hammer_inode *
204 hammer_get_inode(hammer_transaction_t trans, struct hammer_node **cache,
205                  u_int64_t obj_id, hammer_tid_t asof, int flags, int *errorp)
206 {
207         hammer_mount_t hmp = trans->hmp;
208         struct hammer_inode_info iinfo;
209         struct hammer_cursor cursor;
210         struct hammer_inode *ip;
211
212         /*
213          * Determine if we already have an inode cached.  If we do then
214          * we are golden.
215          */
216         iinfo.obj_id = obj_id;
217         iinfo.obj_asof = asof;
218 loop:
219         ip = hammer_ino_rb_tree_RB_LOOKUP_INFO(&hmp->rb_inos_root, &iinfo);
220         if (ip) {
221                 hammer_ref(&ip->lock);
222                 *errorp = 0;
223                 return(ip);
224         }
225
226         ip = kmalloc(sizeof(*ip), M_HAMMER, M_WAITOK|M_ZERO);
227         ++hammer_count_inodes;
228         ip->obj_id = obj_id;
229         ip->obj_asof = iinfo.obj_asof;
230         ip->hmp = hmp;
231         ip->flags = flags & HAMMER_INODE_RO;
232         ip->trunc_off = 0x7FFFFFFFFFFFFFFFLL;
233         if (hmp->ronly)
234                 ip->flags |= HAMMER_INODE_RO;
235         RB_INIT(&ip->rec_tree);
236         TAILQ_INIT(&ip->bio_list);
237         TAILQ_INIT(&ip->bio_alt_list);
238         TAILQ_INIT(&ip->depend_list);
239
240         /*
241          * Locate the on-disk inode.
242          */
243 retry:
244         hammer_init_cursor(trans, &cursor, cache);
245         cursor.key_beg.obj_id = ip->obj_id;
246         cursor.key_beg.key = 0;
247         cursor.key_beg.create_tid = 0;
248         cursor.key_beg.delete_tid = 0;
249         cursor.key_beg.rec_type = HAMMER_RECTYPE_INODE;
250         cursor.key_beg.obj_type = 0;
251         cursor.asof = iinfo.obj_asof;
252         cursor.flags = HAMMER_CURSOR_GET_RECORD | HAMMER_CURSOR_GET_DATA |
253                        HAMMER_CURSOR_ASOF;
254
255         *errorp = hammer_btree_lookup(&cursor);
256         if (*errorp == EDEADLK) {
257                 hammer_done_cursor(&cursor);
258                 goto retry;
259         }
260
261         /*
262          * On success the B-Tree lookup will hold the appropriate
263          * buffer cache buffers and provide a pointer to the requested
264          * information.  Copy the information to the in-memory inode
265          * and cache the B-Tree node to improve future operations.
266          */
267         if (*errorp == 0) {
268                 ip->ino_rec = cursor.record->inode;
269                 ip->ino_data = cursor.data->inode;
270                 hammer_cache_node(cursor.node, &ip->cache[0]);
271                 if (cache)
272                         hammer_cache_node(cursor.node, cache);
273         }
274
275         /*
276          * On success load the inode's record and data and insert the
277          * inode into the B-Tree.  It is possible to race another lookup
278          * insertion of the same inode so deal with that condition too.
279          *
280          * The cursor's locked node interlocks against others creating and
281          * destroying ip while we were blocked.
282          */
283         if (*errorp == 0) {
284                 hammer_ref(&ip->lock);
285                 if (RB_INSERT(hammer_ino_rb_tree, &hmp->rb_inos_root, ip)) {
286                         hammer_uncache_node(&ip->cache[0]);
287                         hammer_uncache_node(&ip->cache[1]);
288                         KKASSERT(ip->lock.refs == 1);
289                         --hammer_count_inodes;
290                         kfree(ip, M_HAMMER);
291                         hammer_done_cursor(&cursor);
292                         goto loop;
293                 }
294                 ip->flags |= HAMMER_INODE_ONDISK;
295         } else {
296                 --hammer_count_inodes;
297                 kfree(ip, M_HAMMER);
298                 ip = NULL;
299         }
300         hammer_done_cursor(&cursor);
301         return (ip);
302 }
303
304 /*
305  * Create a new filesystem object, returning the inode in *ipp.  The
306  * returned inode will be referenced and also marked HAMMER_INODE_NEW,
307  * preventing it from being synchronized too early.  The caller must
308  * call hammer_finalize_inode() to make it available for media sync.
309  *
310  * The inode is created in-memory.
311  */
312 int
313 hammer_create_inode(hammer_transaction_t trans, struct vattr *vap,
314                     struct ucred *cred, hammer_inode_t dip,
315                     struct hammer_inode **ipp)
316 {
317         hammer_mount_t hmp;
318         hammer_inode_t ip;
319         uid_t xuid;
320
321         hmp = trans->hmp;
322         ip = kmalloc(sizeof(*ip), M_HAMMER, M_WAITOK|M_ZERO);
323         ++hammer_count_inodes;
324         ip->obj_id = hammer_alloc_tid(trans);
325         KKASSERT(ip->obj_id != 0);
326         ip->obj_asof = hmp->asof;
327         ip->hmp = hmp;
328         ip->flush_state = HAMMER_FST_IDLE;
329         ip->flags = HAMMER_INODE_DDIRTY | HAMMER_INODE_RDIRTY |
330                     HAMMER_INODE_ITIMES;
331         ip->flags |= HAMMER_INODE_NEW;
332
333         RB_INIT(&ip->rec_tree);
334         TAILQ_INIT(&ip->bio_list);
335         TAILQ_INIT(&ip->bio_alt_list);
336         TAILQ_INIT(&ip->depend_list);
337
338         ip->ino_rec.ino_atime = trans->time;
339         ip->ino_rec.ino_mtime = trans->time;
340         ip->ino_rec.ino_size = 0;
341         ip->ino_rec.ino_nlinks = 0;
342         /* XXX */
343         ip->ino_rec.base.base.btype = HAMMER_BTREE_TYPE_RECORD;
344         ip->ino_rec.base.base.obj_id = ip->obj_id;
345         ip->ino_rec.base.base.key = 0;
346         ip->ino_rec.base.base.create_tid = 0;
347         ip->ino_rec.base.base.delete_tid = 0;
348         ip->ino_rec.base.base.rec_type = HAMMER_RECTYPE_INODE;
349         ip->ino_rec.base.base.obj_type = hammer_get_obj_type(vap->va_type);
350
351         ip->ino_data.version = HAMMER_INODE_DATA_VERSION;
352         ip->ino_data.mode = vap->va_mode;
353         ip->ino_data.ctime = trans->time;
354         ip->ino_data.parent_obj_id = (dip) ? dip->ino_rec.base.base.obj_id : 0;
355
356         switch(ip->ino_rec.base.base.obj_type) {
357         case HAMMER_OBJTYPE_CDEV:
358         case HAMMER_OBJTYPE_BDEV:
359                 ip->ino_data.rmajor = vap->va_rmajor;
360                 ip->ino_data.rminor = vap->va_rminor;
361                 break;
362         default:
363                 break;
364         }
365
366         /*
367          * Calculate default uid/gid and overwrite with information from
368          * the vap.
369          */
370         xuid = hammer_to_unix_xid(&dip->ino_data.uid);
371         ip->ino_data.gid = dip->ino_data.gid;
372         xuid = vop_helper_create_uid(hmp->mp, dip->ino_data.mode, xuid, cred,
373                                      &vap->va_mode);
374         ip->ino_data.mode = vap->va_mode;
375
376         if (vap->va_vaflags & VA_UID_UUID_VALID)
377                 ip->ino_data.uid = vap->va_uid_uuid;
378         else if (vap->va_uid != (uid_t)VNOVAL)
379                 hammer_guid_to_uuid(&ip->ino_data.uid, xuid);
380         if (vap->va_vaflags & VA_GID_UUID_VALID)
381                 ip->ino_data.gid = vap->va_gid_uuid;
382         else if (vap->va_gid != (gid_t)VNOVAL)
383                 hammer_guid_to_uuid(&ip->ino_data.gid, vap->va_gid);
384
385         hammer_ref(&ip->lock);
386         if (RB_INSERT(hammer_ino_rb_tree, &hmp->rb_inos_root, ip)) {
387                 hammer_unref(&ip->lock);
388                 panic("hammer_create_inode: duplicate obj_id %llx", ip->obj_id);
389         }
390         *ipp = ip;
391         return(0);
392 }
393
394 /*
395  * Finalize a newly created inode, allowing it to be synchronized to the
396  * media.  If an error occured make sure the inode has been cleaned up and
397  * will not be synchronized to the media.
398  */
399 void
400 hammer_finalize_inode(hammer_transaction_t trans, hammer_inode_t ip, int error)
401 {
402         if (error) {
403                 ip->flags &= ~HAMMER_INODE_MODMASK;
404
405                 KASSERT(ip->lock.refs == 1,
406                         ("hammer_unload_inode: %d refs\n", ip->lock.refs));
407                 KKASSERT(ip->vp == NULL);
408                 KKASSERT(ip->flush_state == HAMMER_FST_IDLE);
409                 KKASSERT(ip->cursor_ip_refs == 0);
410                 KKASSERT((ip->flags & HAMMER_INODE_MODMASK) == 0);
411
412                 KKASSERT(RB_EMPTY(&ip->rec_tree));
413                 KKASSERT(TAILQ_EMPTY(&ip->bio_list));
414                 KKASSERT(TAILQ_EMPTY(&ip->bio_alt_list));
415         }
416         ip->flags &= ~HAMMER_INODE_NEW;
417 }
418
419 /*
420  * Called by hammer_sync_inode().
421  */
422 static int
423 hammer_update_inode(hammer_transaction_t trans, hammer_inode_t ip)
424 {
425         struct hammer_cursor cursor;
426         hammer_record_t record;
427         int error;
428
429         /*
430          * Locate the record on-disk and mark it as deleted.  Both the B-Tree
431          * node and the record must be marked deleted.  The record may or
432          * may not be physically deleted, depending on the retention policy.
433          *
434          * If the inode has already been deleted on-disk we have nothing
435          * to do.
436          *
437          * XXX Update the inode record and data in-place if the retention
438          * policy allows it.
439          */
440 retry:
441         error = 0;
442
443         if ((ip->flags & (HAMMER_INODE_ONDISK|HAMMER_INODE_DELONDISK)) ==
444             HAMMER_INODE_ONDISK) {
445                 hammer_init_cursor(trans, &cursor, &ip->cache[0]);
446                 cursor.key_beg.obj_id = ip->obj_id;
447                 cursor.key_beg.key = 0;
448                 cursor.key_beg.create_tid = 0;
449                 cursor.key_beg.delete_tid = 0;
450                 cursor.key_beg.rec_type = HAMMER_RECTYPE_INODE;
451                 cursor.key_beg.obj_type = 0;
452                 cursor.asof = ip->obj_asof;
453                 cursor.flags |= HAMMER_CURSOR_GET_RECORD | HAMMER_CURSOR_ASOF;
454                 cursor.flags |= HAMMER_CURSOR_BACKEND;
455
456                 error = hammer_btree_lookup(&cursor);
457                 if (error) {
458                         kprintf("error %d\n", error);
459                         Debugger("hammer_update_inode");
460                 }
461
462
463                 if (error == 0) {
464                         error = hammer_ip_delete_record(&cursor, trans->tid);
465                         if (error && error != EDEADLK) {
466                                 kprintf("error %d\n", error);
467                                 Debugger("hammer_update_inode2");
468                         }
469                         if (error == 0)
470                                 ip->flags |= HAMMER_INODE_DELONDISK;
471                         hammer_cache_node(cursor.node, &ip->cache[0]);
472                 }
473                 hammer_done_cursor(&cursor);
474                 if (error == EDEADLK)
475                         goto retry;
476         }
477
478         /*
479          * Write out a new record if the in-memory inode is not marked
480          * as having been deleted.  Update our inode statistics if this
481          * is the first application of the inode on-disk.
482          *
483          * If the inode has been deleted permanently, HAMMER_INODE_DELONDISK
484          * will remain set and prevent further updates.
485          */
486         if (error == 0 && (ip->flags & HAMMER_INODE_DELETED) == 0) { 
487                 record = hammer_alloc_mem_record(ip);
488                 record->state = HAMMER_FST_FLUSH;
489                 record->rec.inode = ip->sync_ino_rec;
490                 record->rec.inode.base.base.create_tid = trans->tid;
491                 record->rec.inode.base.data_len = sizeof(ip->sync_ino_data);
492                 record->data = (void *)&ip->sync_ino_data;
493                 record->flags |= HAMMER_RECF_INTERLOCK_BE;
494                 error = hammer_ip_sync_record(trans, record);
495                 if (error) {
496                         kprintf("error %d\n", error);
497                         Debugger("hammer_update_inode3");
498                 }
499
500                 /*
501                  * The record isn't managed by the inode's record tree,
502                  * destroy it whether we succeed or fail.
503                  */
504                 record->flags &= ~HAMMER_RECF_INTERLOCK_BE;
505                 record->flags |= HAMMER_RECF_DELETED_FE;
506                 record->state = HAMMER_FST_IDLE;
507                 KKASSERT(TAILQ_FIRST(&record->depend_list) == NULL);
508                 hammer_rel_mem_record(record);
509
510                 if (error == 0) {
511                         ip->sync_flags &= ~(HAMMER_INODE_RDIRTY |
512                                             HAMMER_INODE_DDIRTY |
513                                             HAMMER_INODE_ITIMES);
514                         ip->flags &= ~HAMMER_INODE_DELONDISK;
515                         if ((ip->flags & HAMMER_INODE_ONDISK) == 0) {
516                                 hammer_modify_volume(trans, trans->rootvol,
517                                                      NULL, 0);
518                                 ++ip->hmp->rootvol->ondisk->vol0_stat_inodes;
519                                 hammer_modify_volume_done(trans->rootvol);
520                                 ip->flags |= HAMMER_INODE_ONDISK;
521                         }
522                 }
523         }
524         if (error == 0 && (ip->flags & HAMMER_INODE_DELETED)) { 
525                 /*
526                  * Clean out any left-over flags if the inode has been
527                  * destroyed.
528                  */
529                 ip->sync_flags &= ~(HAMMER_INODE_RDIRTY |
530                                     HAMMER_INODE_DDIRTY |
531                                     HAMMER_INODE_ITIMES);
532         }
533         return(error);
534 }
535
536 /*
537  * Update only the itimes fields.  This is done no-historically.  The
538  * record is updated in-place on the disk.
539  */
540 static int
541 hammer_update_itimes(hammer_transaction_t trans, hammer_inode_t ip)
542 {
543         struct hammer_cursor cursor;
544         struct hammer_inode_record *rec;
545         int error;
546
547 retry:
548         error = 0;
549         if ((ip->flags & (HAMMER_INODE_ONDISK|HAMMER_INODE_DELONDISK)) ==
550             HAMMER_INODE_ONDISK) {
551                 hammer_init_cursor(trans, &cursor, &ip->cache[0]);
552                 cursor.key_beg.obj_id = ip->obj_id;
553                 cursor.key_beg.key = 0;
554                 cursor.key_beg.create_tid = 0;
555                 cursor.key_beg.delete_tid = 0;
556                 cursor.key_beg.rec_type = HAMMER_RECTYPE_INODE;
557                 cursor.key_beg.obj_type = 0;
558                 cursor.asof = ip->obj_asof;
559                 cursor.flags |= HAMMER_CURSOR_GET_RECORD | HAMMER_CURSOR_ASOF;
560                 cursor.flags |= HAMMER_CURSOR_BACKEND;
561
562                 error = hammer_btree_lookup(&cursor);
563                 if (error) {
564                         kprintf("error %d\n", error);
565                         Debugger("hammer_update_itimes1");
566                 }
567                 if (error == 0) {
568                         /*
569                          * Do not generate UNDO records for atime/mtime
570                          * updates.
571                          */
572                         rec = &cursor.record->inode;
573                         hammer_modify_buffer(cursor.trans, cursor.record_buffer,
574                                              NULL, 0);
575                         rec->ino_atime = ip->sync_ino_rec.ino_atime;
576                         rec->ino_mtime = ip->sync_ino_rec.ino_mtime;
577                         hammer_modify_buffer_done(cursor.record_buffer);
578                         ip->sync_flags &= ~HAMMER_INODE_ITIMES;
579                         /* XXX recalculate crc */
580                         hammer_cache_node(cursor.node, &ip->cache[0]);
581                 }
582                 hammer_done_cursor(&cursor);
583                 if (error == EDEADLK)
584                         goto retry;
585         }
586         return(error);
587 }
588
589 /*
590  * Release a reference on an inode.  If asked to flush the last release
591  * will flush the inode.
592  *
593  * On the last reference we queue the inode to the flusher for its final
594  * disposition.
595  */
596 void
597 hammer_rel_inode(struct hammer_inode *ip, int flush)
598 {
599         /*
600          * Handle disposition when dropping the last ref.
601          */
602         while (ip->lock.refs == 1) {
603                 if ((ip->flags & HAMMER_INODE_MODMASK) == 0) {
604                         hammer_unload_inode(ip);
605                         return;
606                 }
607
608                 /*
609                  * Hand the inode over to the flusher, which will
610                  * add another ref to it.
611                  */
612                 if (++ip->hmp->reclaim_count > 256) {
613                         ip->hmp->reclaim_count = 0;
614                         hammer_flush_inode(ip, HAMMER_FLUSH_FORCE |
615                                                 HAMMER_FLUSH_SIGNAL);
616                 } else {
617                         hammer_flush_inode(ip, HAMMER_FLUSH_FORCE);
618                 }
619                 /* retry */
620         }
621
622         /*
623          * The inode still has multiple refs, drop one ref.  If a flush was
624          * requested make sure the flusher sees it.  New inodes which have
625          * not been finalized cannot be flushed.
626          */
627         if (flush && ip->flush_state == HAMMER_FST_IDLE && 
628             (ip->flags & HAMMER_INODE_NEW) == 0) {
629                 hammer_flush_inode(ip, HAMMER_FLUSH_RELEASE);
630         } else {
631                 hammer_unref(&ip->lock);
632         }
633 }
634
635 /*
636  * Unload and destroy the specified inode.  Must be called with one remaining
637  * reference.  The reference is disposed of.
638  *
639  * This can only be called in the context of the flusher.
640  */
641 static int
642 hammer_unload_inode(struct hammer_inode *ip)
643 {
644         KASSERT(ip->lock.refs == 1,
645                 ("hammer_unload_inode: %d refs\n", ip->lock.refs));
646         KKASSERT(ip->vp == NULL);
647         KKASSERT(ip->flush_state == HAMMER_FST_IDLE);
648         KKASSERT(ip->cursor_ip_refs == 0);
649         KKASSERT((ip->flags & HAMMER_INODE_MODMASK) == 0);
650
651         KKASSERT(RB_EMPTY(&ip->rec_tree));
652         KKASSERT(TAILQ_EMPTY(&ip->bio_list));
653         KKASSERT(TAILQ_EMPTY(&ip->bio_alt_list));
654
655         RB_REMOVE(hammer_ino_rb_tree, &ip->hmp->rb_inos_root, ip);
656
657         hammer_uncache_node(&ip->cache[0]);
658         hammer_uncache_node(&ip->cache[1]);
659         --hammer_count_inodes;
660         kfree(ip, M_HAMMER);
661
662         return(0);
663 }
664
665 /*
666  * A transaction has modified an inode, requiring updates as specified by
667  * the passed flags.
668  *
669  * HAMMER_INODE_RDIRTY: Inode record has been updated
670  * HAMMER_INODE_DDIRTY: Inode data has been updated
671  * HAMMER_INODE_XDIRTY: Dirty frontend buffer cache buffer strategized
672  * HAMMER_INODE_DELETED: Inode record/data must be deleted
673  * HAMMER_INODE_ITIMES: mtime/atime has been updated
674  */
675 void
676 hammer_modify_inode(hammer_transaction_t trans, hammer_inode_t ip, int flags)
677 {
678         KKASSERT ((ip->flags & HAMMER_INODE_RO) == 0 ||
679                   (flags & (HAMMER_INODE_RDIRTY|HAMMER_INODE_DDIRTY|
680                    HAMMER_INODE_XDIRTY|
681                    HAMMER_INODE_DELETED|HAMMER_INODE_ITIMES)) == 0);
682
683         ip->flags |= flags;
684 }
685
686 /*
687  * Flush an inode.  If the inode is already being flushed wait for
688  * it to complete, then flush it again.  The interlock is against
689  * front-end transactions, the backend flusher does not hold the lock.
690  *
691  * The flusher must distinguish between the records that are part of the
692  * flush and any new records created in parallel with the flush.  The
693  * inode data and truncation fields are also copied.  BIOs are a bit more
694  * troublesome because some dirty buffers may not have been queued yet.
695  */
696 void
697 hammer_flush_inode(hammer_inode_t ip, int flags)
698 {
699         KKASSERT((ip->flags & HAMMER_INODE_NEW) == 0);
700         if (ip->flush_state != HAMMER_FST_IDLE &&
701             (ip->flags & HAMMER_INODE_MODMASK)) {
702                 ip->flags |= HAMMER_INODE_REFLUSH;
703                 if (flags & HAMMER_FLUSH_RELEASE) {
704                         hammer_unref(&ip->lock);
705                         KKASSERT(ip->lock.refs > 0);
706                 }
707                 return;
708         }
709         if (ip->flush_state == HAMMER_FST_IDLE) {
710                 if ((ip->flags & HAMMER_INODE_MODMASK) ||
711                     (flags & HAMMER_FLUSH_FORCE)) {
712                         /*
713                          * Add a reference to represent the inode being queued
714                          * to the flusher.  If the caller wants us to 
715                          * release a reference the two cancel each other out.
716                          */
717                         if ((flags & HAMMER_FLUSH_RELEASE) == 0)
718                                 hammer_ref(&ip->lock);
719
720                         hammer_flush_inode_copysync(ip);
721                         /*
722                          * Move the inode to the flush list and add a ref to
723                          * it representing it on the list.
724                          */
725                         TAILQ_INSERT_TAIL(&ip->hmp->flush_list, ip, flush_entry);
726                         if (flags & HAMMER_FLUSH_SIGNAL)
727                                 hammer_flusher_async(ip->hmp);
728                 }
729         }
730 }
731
732 /*
733  * Helper routine to copy the frontend synchronization state to the backend.
734  * This routine may be called by either the frontend or the backend.
735  */
736 static void
737 hammer_flush_inode_copysync(hammer_inode_t ip)
738 {
739         int error;
740         int count;
741
742         /*
743          * Prevent anyone else from trying to do the same thing.
744          */
745         ip->flush_state = HAMMER_FST_SETUP;
746
747         /*
748          * Sync the buffer cache.  This will queue the BIOs.  If called
749          * from the context of the flusher the BIO's are thrown into bio_list
750          * regardless of ip->flush_state.
751          */
752         if (ip->vp != NULL)
753                 error = vfsync(ip->vp, MNT_NOWAIT, 1, NULL, NULL);
754         else
755                 error = 0;
756
757         /*
758          * This freezes strategy writes, any further BIOs will be
759          * queued to alt_bio (unless we are 
760          */
761         ip->flush_state = HAMMER_FST_FLUSH;
762
763         /*
764          * Snapshot the state of the inode for the backend flusher.
765          *
766          * The truncation must be retained in the frontend until after
767          * we've actually performed the record deletion.
768          */
769         ip->sync_flags = (ip->flags & HAMMER_INODE_MODMASK);
770         ip->sync_trunc_off = ip->trunc_off;
771         ip->sync_ino_rec = ip->ino_rec;
772         ip->sync_ino_data = ip->ino_data;
773         ip->flags &= ~HAMMER_INODE_MODMASK |
774                      HAMMER_INODE_TRUNCATED | HAMMER_INODE_BUFS;
775
776         /*
777          * Fix up the dirty buffer status.
778          */
779         if (ip->vp == NULL || RB_ROOT(&ip->vp->v_rbdirty_tree) == NULL)
780                 ip->flags &= ~HAMMER_INODE_BUFS;
781         if (TAILQ_FIRST(&ip->bio_list))
782                 ip->sync_flags |= HAMMER_INODE_BUFS;
783         else
784                 ip->sync_flags &= ~HAMMER_INODE_BUFS;
785
786         /*
787          * Set the state for the inode's in-memory records.  If some records
788          * could not be marked for backend flush (i.e. deleted records),
789          * re-set the XDIRTY flag.
790          */
791         count = RB_SCAN(hammer_rec_rb_tree, &ip->rec_tree, NULL,
792                         hammer_mark_record_callback, NULL);
793         if (count)
794                 ip->flags |= HAMMER_INODE_XDIRTY;
795 }
796
797 /*
798  * Mark records for backend flush, accumulate a count of the number of
799  * records which could not be marked.  Records marked for deletion
800  * by the frontend never make it to the media.  It is possible for
801  * a record queued to the backend to wind up with FE set after the
802  * fact, as long as BE has not yet been set.  The backend deals with
803  * this race by syncing the record as if FE had not been set, and
804  * then converting the record to a delete-on-disk record.
805  */
806 static int
807 hammer_mark_record_callback(hammer_record_t rec, void *data)
808 {
809         if (rec->state == HAMMER_FST_FLUSH) {
810                 return(0);
811         } else if ((rec->flags & HAMMER_RECF_DELETED_FE) == 0) {
812                 rec->state = HAMMER_FST_FLUSH;
813                 hammer_ref(&rec->lock);
814                 return(0);
815         } else {
816                 return(1);
817         }
818 }
819
820
821
822 /*
823  * Wait for a previously queued flush to complete
824  */
825 void
826 hammer_wait_inode(hammer_inode_t ip)
827 {
828         while (ip->flush_state == HAMMER_FST_FLUSH) {
829                 ip->flags |= HAMMER_INODE_FLUSHW;
830                 tsleep(&ip->flags, 0, "hmrwin", 0);
831         }
832 }
833
834 /*
835  * Called by the backend code when a flush has been completed.
836  * The inode has already been removed from the flush list.
837  *
838  * A pipelined flush can occur, in which case we must re-enter the
839  * inode on the list and re-copy its fields.
840  */
841 void
842 hammer_flush_inode_done(hammer_inode_t ip)
843 {
844         struct bio *bio;
845
846         KKASSERT(ip->flush_state == HAMMER_FST_FLUSH);
847
848         if (ip->sync_flags)
849                 kprintf("ip %p leftover sync_flags %08x\n", ip, ip->sync_flags);
850         ip->flags |= ip->sync_flags;
851         ip->flush_state = HAMMER_FST_IDLE;
852
853         /*
854          * Reflush any BIOs that wound up in the alt list.  Our inode will
855          * also wind up at the end of the flusher's list.
856          */
857         while ((bio = TAILQ_FIRST(&ip->bio_alt_list)) != NULL) {
858                 TAILQ_REMOVE(&ip->bio_alt_list, bio, bio_act);
859                 TAILQ_INSERT_TAIL(&ip->bio_list, bio, bio_act);
860                 ip->flags |= HAMMER_INODE_XDIRTY;
861                 ip->flags |= HAMMER_INODE_REFLUSH;
862                 kprintf("rebio %p ip %p @%016llx,%d\n", bio, ip, bio->bio_offset, bio->bio_buf->b_bufsize);
863         }
864
865         /*
866          * If the frontend made more changes and requested another flush,
867          * do it. 
868          */
869         if (ip->flags & HAMMER_INODE_REFLUSH) {
870                 ip->flags &= ~HAMMER_INODE_REFLUSH;
871                 hammer_flush_inode(ip, 0);
872         } else {
873                 if (ip->flags & HAMMER_INODE_FLUSHW) {
874                         ip->flags &= ~HAMMER_INODE_FLUSHW;
875                         wakeup(&ip->flags);
876                 }
877         }
878         hammer_rel_inode(ip, 0);
879 }
880
881 /*
882  * Called from hammer_sync_inode() to synchronize in-memory records
883  * to the media.
884  */
885 static int
886 hammer_sync_record_callback(hammer_record_t record, void *data)
887 {
888         hammer_transaction_t trans = data;
889         int error;
890
891         /*
892          * Skip records that do not belong to the current flush.  Records
893          * belonging to the flush will have been referenced for us.
894          */
895         if (record->state != HAMMER_FST_FLUSH)
896                 return(0);
897
898         /*
899          * Interlock the record using the BE flag.  Once BE is set the
900          * frontend cannot change the state of FE.
901          *
902          * NOTE: If FE is set prior to us setting BE we still sync the
903          * record out, but the flush completion code converts it to 
904          * a delete-on-disk record instead of destroying it.
905          */
906         hammer_lock_ex(&record->lock);
907         if (record->flags & HAMMER_RECF_INTERLOCK_BE) {
908                 hammer_unlock(&record->lock);
909                 return(0);
910         }
911         record->flags |= HAMMER_RECF_INTERLOCK_BE;
912
913         /*
914          * If DELETED_FE is set we may have already sent dependant pieces
915          * to the disk and we must flush the record as if it hadn't been
916          * deleted.  This creates a bit of a mess because we have to
917          * have ip_sync_record convert the record to DELETE_ONDISK before
918          * it inserts the B-Tree record.  Otherwise the media sync might
919          * be visible to the frontend.
920          */
921         if (record->flags & HAMMER_RECF_DELETED_FE)
922                 record->flags |= HAMMER_RECF_CONVERT_DELETE_ONDISK;
923
924         /*
925          * Assign the create_tid for new records.  Deletions already
926          * have the record's entire key properly set up.
927          */
928         if ((record->flags & HAMMER_RECF_DELETE_ONDISK) == 0)
929                 record->rec.inode.base.base.create_tid = trans->tid;
930         error = hammer_ip_sync_record(trans, record);
931
932         if (error) {
933                 error = -error;
934                 if (error != -ENOSPC) {
935                         kprintf("hammer_sync_record_callback: sync failed rec "
936                                 "%p, error %d\n", record, error);
937                         Debugger("sync failed rec");
938                 }
939         }
940         hammer_flush_record_done(record, error);
941         return(error);
942 }
943
944 /*
945  * XXX error handling
946  */
947 int
948 hammer_sync_inode(hammer_inode_t ip, int handle_delete)
949 {
950         struct hammer_transaction trans;
951         struct bio *bio;
952         hammer_depend_t depend;
953         int error, tmp_error;
954
955         if ((ip->sync_flags & HAMMER_INODE_MODMASK) == 0 &&
956             handle_delete == 0) {
957                 return(0);
958         }
959
960         hammer_start_transaction_fls(&trans, ip->hmp);
961
962         /*
963          * Any (directory) records this inode depends on must also be
964          * synchronized.  The directory itself only needs to be flushed
965          * if its inode is not already on-disk.
966          */
967         while ((depend = TAILQ_FIRST(&ip->depend_list)) != NULL) {
968                 hammer_record_t record;
969
970                 record = depend->record;
971                 TAILQ_REMOVE(&depend->record->depend_list, depend, rec_entry);
972                 TAILQ_REMOVE(&ip->depend_list, depend, ip_entry);
973                 --ip->depend_count;
974                 if (record->state != HAMMER_FST_FLUSH) {
975                         record->state = HAMMER_FST_FLUSH;
976                         /* add ref (steal ref from dependancy) */
977                 } else {
978                         /* remove ref related to dependancy */
979                         /* record still has at least one ref from state */
980                         hammer_unref(&record->lock);
981                         KKASSERT(record->lock.refs > 0);
982                 }
983                 if (record->ip->flags & HAMMER_INODE_ONDISK) {
984                         kprintf("I");
985                         hammer_sync_record_callback(record, &trans);
986                 } else {
987                         kprintf("J");
988                         KKASSERT((record->ip->flags & HAMMER_INODE_NEW) == 0);
989                         hammer_flush_inode(record->ip, 0);
990                 }
991                 hammer_unref(&ip->lock);
992                 KKASSERT(ip->lock.refs > 0);
993                 kfree(depend, M_HAMMER);
994         }
995
996
997         /*
998          * Sync inode deletions and truncations.
999          */
1000         if (ip->sync_ino_rec.ino_nlinks == 0 && handle_delete && 
1001             (ip->flags & HAMMER_INODE_GONE) == 0) {
1002                 /*
1003                  * Handle the case where the inode has been completely deleted
1004                  * and is no longer referenceable from the filesystem
1005                  * namespace.
1006                  *
1007                  * NOTE: We do not set the RDIRTY flag when updating the
1008                  * delete_tid, setting HAMMER_INODE_DELETED takes care of it.
1009                  */
1010
1011                 ip->flags |= HAMMER_INODE_GONE | HAMMER_INODE_DELETED;
1012                 ip->flags &= ~HAMMER_INODE_TRUNCATED;
1013                 ip->sync_flags &= ~HAMMER_INODE_TRUNCATED;
1014                 if (ip->vp)
1015                         vtruncbuf(ip->vp, 0, HAMMER_BUFSIZE);
1016                 error = hammer_ip_delete_range_all(&trans, ip);
1017                 if (error)
1018                         Debugger("hammer_ip_delete_range_all errored");
1019
1020                 /*
1021                  * Sanity check.  The only records that remain should be
1022                  * marked for back-end deletion.
1023                  */
1024                 {
1025                         hammer_record_t rec;
1026
1027                         RB_FOREACH(rec, hammer_rec_rb_tree, &ip->rec_tree) {
1028                                 KKASSERT(rec->state == HAMMER_FST_FLUSH);
1029                         }
1030                 }
1031
1032                 /*
1033                  * Set delete_tid in both the frontend and backend
1034                  * copy of the inode record.
1035                  */
1036                 ip->ino_rec.base.base.delete_tid = trans.tid;
1037                 ip->sync_ino_rec.base.base.delete_tid = trans.tid;
1038
1039                 /*
1040                  * Indicate that the inode has/is-being deleted.
1041                  */
1042                 ip->flags |= HAMMER_NODE_DELETED;
1043                 hammer_modify_inode(&trans, ip, HAMMER_INODE_RDIRTY);
1044                 hammer_modify_volume(&trans, trans.rootvol, NULL, 0);
1045                 --ip->hmp->rootvol->ondisk->vol0_stat_inodes;
1046                 hammer_modify_volume_done(trans.rootvol);
1047         } else if (ip->sync_flags & HAMMER_INODE_TRUNCATED) {
1048                 /*
1049                  * Interlock trunc_off.  The VOP front-end may continue to
1050                  * make adjustments to it while we are blocked.
1051                  */
1052                 off_t trunc_off;
1053                 off_t aligned_trunc_off;
1054
1055                 trunc_off = ip->sync_trunc_off;
1056                 aligned_trunc_off = (trunc_off + HAMMER_BUFMASK) &
1057                                     ~HAMMER_BUFMASK64;
1058
1059                 /*
1060                  * Delete any whole blocks on-media.  The front-end has
1061                  * already cleaned out any partial block and made it
1062                  * pending.  The front-end may have updated trunc_off
1063                  * while we were blocked so do not just unconditionally
1064                  * set it to the maximum offset.
1065                  */
1066                 kprintf("sync truncation range @ %016llx\n", aligned_trunc_off);
1067                 error = hammer_ip_delete_range(&trans, ip,
1068                                                 aligned_trunc_off,
1069                                                 0x7FFFFFFFFFFFFFFFLL);
1070                 if (error)
1071                         Debugger("hammer_ip_delete_range errored");
1072                 ip->sync_flags &= ~HAMMER_INODE_TRUNCATED;
1073                 if (ip->trunc_off >= trunc_off) {
1074                         ip->trunc_off = 0x7FFFFFFFFFFFFFFFLL;
1075                         ip->flags &= ~HAMMER_INODE_TRUNCATED;
1076                 }
1077         }
1078
1079         error = 0;      /* XXX vfsync used to be here */
1080
1081         /*
1082          * Flush any queued BIOs.
1083          */
1084         while ((bio = TAILQ_FIRST(&ip->bio_list)) != NULL) {
1085                 TAILQ_REMOVE(&ip->bio_list, bio, bio_act);
1086 #if 0
1087                 kprintf("dowrite %016llx ip %p bio %p @ %016llx\n", trans.tid, ip, bio, bio->bio_offset);
1088 #endif
1089                 tmp_error = hammer_dowrite(&trans, ip, bio);
1090                 if (tmp_error)
1091                         error = tmp_error;
1092         }
1093         ip->sync_flags &= ~HAMMER_INODE_BUFS;
1094
1095         /*
1096          * Now sync related records.
1097          */
1098         for (;;) {
1099                 tmp_error = RB_SCAN(hammer_rec_rb_tree, &ip->rec_tree, NULL,
1100                                 hammer_sync_record_callback, &trans);
1101                 KKASSERT(error <= 0);
1102                 if (tmp_error < 0)
1103                         tmp_error = -error;
1104                 if (tmp_error)
1105                         error = tmp_error;
1106                 break;
1107         }
1108
1109         /*
1110          * XDIRTY represents rec_tree and bio_list.  However, rec_tree may
1111          * contain new front-end records so short of scanning it we can't
1112          * just test whether it is empty or not. 
1113          *
1114          * If no error occured assume we succeeded.
1115          */
1116         if (error == 0)
1117                 ip->sync_flags &= ~HAMMER_INODE_XDIRTY;
1118
1119         if (error)
1120                 Debugger("RB_SCAN errored");
1121
1122         /*
1123          * Now update the inode's on-disk inode-data and/or on-disk record.
1124          * DELETED and ONDISK are managed only in ip->flags.
1125          */
1126         switch(ip->flags & (HAMMER_INODE_DELETED | HAMMER_INODE_ONDISK)) {
1127         case HAMMER_INODE_DELETED|HAMMER_INODE_ONDISK:
1128                 /*
1129                  * If deleted and on-disk, don't set any additional flags.
1130                  * the delete flag takes care of things.
1131                  */
1132                 break;
1133         case HAMMER_INODE_DELETED:
1134                 /*
1135                  * Take care of the case where a deleted inode was never
1136                  * flushed to the disk in the first place.
1137                  */
1138                 ip->sync_flags &= ~(HAMMER_INODE_RDIRTY|HAMMER_INODE_DDIRTY|
1139                                     HAMMER_INODE_XDIRTY|HAMMER_INODE_ITIMES);
1140                 while (RB_ROOT(&ip->rec_tree)) {
1141                         hammer_record_t record = RB_ROOT(&ip->rec_tree);
1142                         hammer_ref(&record->lock);
1143                         KKASSERT(record->lock.refs == 1);
1144                         record->flags |= HAMMER_RECF_DELETED_FE;
1145                         record->flags |= HAMMER_RECF_DELETED_BE;
1146                         hammer_cleardep_mem_record(record);
1147                         hammer_rel_mem_record(record);
1148                 }
1149                 break;
1150         case HAMMER_INODE_ONDISK:
1151                 /*
1152                  * If already on-disk, do not set any additional flags.
1153                  */
1154                 break;
1155         default:
1156                 /*
1157                  * If not on-disk and not deleted, set both dirty flags
1158                  * to force an initial record to be written.  Also set
1159                  * the create_tid for the inode.
1160                  *
1161                  * Set create_tid in both the frontend and backend
1162                  * copy of the inode record.
1163                  */
1164                 ip->ino_rec.base.base.create_tid = trans.tid;
1165                 ip->sync_ino_rec.base.base.create_tid = trans.tid;
1166                 ip->sync_flags |= HAMMER_INODE_RDIRTY | HAMMER_INODE_DDIRTY;
1167                 break;
1168         }
1169
1170         /*
1171          * If RDIRTY or DDIRTY is set, write out a new record.  If the inode
1172          * is already on-disk the old record is marked as deleted.
1173          *
1174          * If DELETED is set hammer_update_inode() will delete the existing
1175          * record without writing out a new one.
1176          *
1177          * If *ONLY* the ITIMES flag is set we can update the record in-place.
1178          */
1179         if (ip->flags & HAMMER_INODE_DELETED) {
1180                 error = hammer_update_inode(&trans, ip);
1181         } else 
1182         if ((ip->sync_flags & (HAMMER_INODE_RDIRTY | HAMMER_INODE_DDIRTY |
1183                                HAMMER_INODE_ITIMES)) == HAMMER_INODE_ITIMES) {
1184                 error = hammer_update_itimes(&trans, ip);
1185         } else
1186         if (ip->sync_flags & (HAMMER_INODE_RDIRTY | HAMMER_INODE_DDIRTY |
1187                               HAMMER_INODE_ITIMES)) {
1188                 error = hammer_update_inode(&trans, ip);
1189         }
1190         if (error)
1191                 Debugger("hammer_update_itimes/inode errored");
1192
1193         /*
1194          * Save the TID we used to sync the inode with to make sure we
1195          * do not improperly reuse it.
1196          */
1197         hammer_done_transaction(&trans);
1198         return(error);
1199 }
1200