HAMMER 54C/Many: Performing tuning, bug fixes
[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.73 2008/06/12 01:55:58 dillon Exp $
35  */
36
37 #include "hammer.h"
38 #include <vm/vm_extern.h>
39 #include <sys/buf.h>
40 #include <sys/buf2.h>
41
42 static int      hammer_unload_inode(struct hammer_inode *ip);
43 static void     hammer_flush_inode_core(hammer_inode_t ip, int flags);
44 static int      hammer_setup_child_callback(hammer_record_t rec, void *data);
45 static int      hammer_setup_parent_inodes(hammer_record_t record);
46 static void     hammer_inode_wakereclaims(hammer_mount_t hmp);
47
48 #ifdef DEBUG_TRUNCATE
49 extern struct hammer_inode *HammerTruncIp;
50 #endif
51
52 /*
53  * The kernel is not actively referencing this vnode but is still holding
54  * it cached.
55  *
56  * This is called from the frontend.
57  */
58 int
59 hammer_vop_inactive(struct vop_inactive_args *ap)
60 {
61         struct hammer_inode *ip = VTOI(ap->a_vp);
62
63         /*
64          * Degenerate case
65          */
66         if (ip == NULL) {
67                 vrecycle(ap->a_vp);
68                 return(0);
69         }
70
71         /*
72          * If the inode no longer has visibility in the filesystem and is
73          * fairly clean, try to recycle it immediately.  This can deadlock
74          * in vfsync() if we aren't careful.
75          * 
76          * Do not queue the inode to the flusher if we still have visibility,
77          * otherwise namespace calls such as chmod will unnecessarily generate
78          * multiple inode updates.
79          */
80         hammer_inode_unloadable_check(ip, 0);
81         if (ip->ino_data.nlinks == 0) {
82                 if (ip->flags & HAMMER_INODE_MODMASK)
83                         hammer_flush_inode(ip, 0);
84                 else
85                         vrecycle(ap->a_vp);
86         }
87         return(0);
88 }
89
90 /*
91  * Release the vnode association.  This is typically (but not always)
92  * the last reference on the inode.
93  *
94  * Once the association is lost we are on our own with regards to
95  * flushing the inode.
96  */
97 int
98 hammer_vop_reclaim(struct vop_reclaim_args *ap)
99 {
100         hammer_mount_t hmp;
101         struct hammer_inode *ip;
102         struct vnode *vp;
103
104         vp = ap->a_vp;
105
106         if ((ip = vp->v_data) != NULL) {
107                 hmp = ip->hmp;
108                 vp->v_data = NULL;
109                 ip->vp = NULL;
110                 if ((ip->flags & HAMMER_INODE_RECLAIM) == 0) {
111                         ++hammer_count_reclaiming;
112                         ++hmp->inode_reclaims;
113                         ip->flags |= HAMMER_INODE_RECLAIM;
114                 }
115                 hammer_rel_inode(ip, 1);
116         }
117         return(0);
118 }
119
120 /*
121  * Return a locked vnode for the specified inode.  The inode must be
122  * referenced but NOT LOCKED on entry and will remain referenced on
123  * return.
124  *
125  * Called from the frontend.
126  */
127 int
128 hammer_get_vnode(struct hammer_inode *ip, struct vnode **vpp)
129 {
130         hammer_mount_t hmp;
131         struct vnode *vp;
132         int error = 0;
133
134         hmp = ip->hmp;
135
136         for (;;) {
137                 if ((vp = ip->vp) == NULL) {
138                         error = getnewvnode(VT_HAMMER, hmp->mp, vpp, 0, 0);
139                         if (error)
140                                 break;
141                         hammer_lock_ex(&ip->lock);
142                         if (ip->vp != NULL) {
143                                 hammer_unlock(&ip->lock);
144                                 vp->v_type = VBAD;
145                                 vx_put(vp);
146                                 continue;
147                         }
148                         hammer_ref(&ip->lock);
149                         vp = *vpp;
150                         ip->vp = vp;
151                         vp->v_type =
152                                 hammer_get_vnode_type(ip->ino_data.obj_type);
153
154                         if (ip->flags & HAMMER_INODE_RECLAIM) {
155                                 --hammer_count_reclaiming;
156                                 --hmp->inode_reclaims;
157                                 ip->flags &= ~HAMMER_INODE_RECLAIM;
158                                 if (hmp->flags & HAMMER_MOUNT_WAITIMAX)
159                                         hammer_inode_wakereclaims(hmp);
160                         }
161
162                         switch(ip->ino_data.obj_type) {
163                         case HAMMER_OBJTYPE_CDEV:
164                         case HAMMER_OBJTYPE_BDEV:
165                                 vp->v_ops = &hmp->mp->mnt_vn_spec_ops;
166                                 addaliasu(vp, ip->ino_data.rmajor,
167                                           ip->ino_data.rminor);
168                                 break;
169                         case HAMMER_OBJTYPE_FIFO:
170                                 vp->v_ops = &hmp->mp->mnt_vn_fifo_ops;
171                                 break;
172                         default:
173                                 break;
174                         }
175
176                         /*
177                          * Only mark as the root vnode if the ip is not
178                          * historical, otherwise the VFS cache will get
179                          * confused.  The other half of the special handling
180                          * is in hammer_vop_nlookupdotdot().
181                          */
182                         if (ip->obj_id == HAMMER_OBJID_ROOT &&
183                             ip->obj_asof == hmp->asof) {
184                                 vp->v_flag |= VROOT;
185                         }
186
187                         vp->v_data = (void *)ip;
188                         /* vnode locked by getnewvnode() */
189                         /* make related vnode dirty if inode dirty? */
190                         hammer_unlock(&ip->lock);
191                         if (vp->v_type == VREG)
192                                 vinitvmio(vp, ip->ino_data.size);
193                         break;
194                 }
195
196                 /*
197                  * loop if the vget fails (aka races), or if the vp
198                  * no longer matches ip->vp.
199                  */
200                 if (vget(vp, LK_EXCLUSIVE) == 0) {
201                         if (vp == ip->vp)
202                                 break;
203                         vput(vp);
204                 }
205         }
206         *vpp = vp;
207         return(error);
208 }
209
210 /*
211  * Acquire a HAMMER inode.  The returned inode is not locked.  These functions
212  * do not attach or detach the related vnode (use hammer_get_vnode() for
213  * that).
214  *
215  * The flags argument is only applied for newly created inodes, and only
216  * certain flags are inherited.
217  *
218  * Called from the frontend.
219  */
220 struct hammer_inode *
221 hammer_get_inode(hammer_transaction_t trans, struct hammer_node **cache,
222                  u_int64_t obj_id, hammer_tid_t asof, int flags, int *errorp)
223 {
224         hammer_mount_t hmp = trans->hmp;
225         struct hammer_inode_info iinfo;
226         struct hammer_cursor cursor;
227         struct hammer_inode *ip;
228
229         /*
230          * Determine if we already have an inode cached.  If we do then
231          * we are golden.
232          */
233         iinfo.obj_id = obj_id;
234         iinfo.obj_asof = asof;
235 loop:
236         ip = hammer_ino_rb_tree_RB_LOOKUP_INFO(&hmp->rb_inos_root, &iinfo);
237         if (ip) {
238                 hammer_ref(&ip->lock);
239                 *errorp = 0;
240                 return(ip);
241         }
242
243         /*
244          * Allocate a new inode structure and deal with races later.
245          */
246         ip = kmalloc(sizeof(*ip), M_HAMMER, M_WAITOK|M_ZERO);
247         ++hammer_count_inodes;
248         ++hmp->count_inodes;
249         ip->obj_id = obj_id;
250         ip->obj_asof = iinfo.obj_asof;
251         ip->hmp = hmp;
252         ip->flags = flags & HAMMER_INODE_RO;
253         if (hmp->ronly)
254                 ip->flags |= HAMMER_INODE_RO;
255         ip->trunc_off = 0x7FFFFFFFFFFFFFFFLL;
256         RB_INIT(&ip->rec_tree);
257         TAILQ_INIT(&ip->target_list);
258
259         /*
260          * Locate the on-disk inode.
261          */
262 retry:
263         hammer_init_cursor(trans, &cursor, cache, NULL);
264         cursor.key_beg.localization = HAMMER_LOCALIZE_INODE;
265         cursor.key_beg.obj_id = ip->obj_id;
266         cursor.key_beg.key = 0;
267         cursor.key_beg.create_tid = 0;
268         cursor.key_beg.delete_tid = 0;
269         cursor.key_beg.rec_type = HAMMER_RECTYPE_INODE;
270         cursor.key_beg.obj_type = 0;
271         cursor.asof = iinfo.obj_asof;
272         cursor.flags = HAMMER_CURSOR_GET_LEAF | HAMMER_CURSOR_GET_DATA |
273                        HAMMER_CURSOR_ASOF;
274
275         *errorp = hammer_btree_lookup(&cursor);
276         if (*errorp == EDEADLK) {
277                 hammer_done_cursor(&cursor);
278                 goto retry;
279         }
280
281         /*
282          * On success the B-Tree lookup will hold the appropriate
283          * buffer cache buffers and provide a pointer to the requested
284          * information.  Copy the information to the in-memory inode
285          * and cache the B-Tree node to improve future operations.
286          */
287         if (*errorp == 0) {
288                 ip->ino_leaf = cursor.node->ondisk->elms[cursor.index].leaf;
289                 ip->ino_data = cursor.data->inode;
290                 hammer_cache_node(cursor.node, &ip->cache[0]);
291                 if (cache)
292                         hammer_cache_node(cursor.node, cache);
293         }
294
295         /*
296          * On success load the inode's record and data and insert the
297          * inode into the B-Tree.  It is possible to race another lookup
298          * insertion of the same inode so deal with that condition too.
299          *
300          * The cursor's locked node interlocks against others creating and
301          * destroying ip while we were blocked.
302          */
303         if (*errorp == 0) {
304                 hammer_ref(&ip->lock);
305                 if (RB_INSERT(hammer_ino_rb_tree, &hmp->rb_inos_root, ip)) {
306                         hammer_uncache_node(&ip->cache[0]);
307                         hammer_uncache_node(&ip->cache[1]);
308                         KKASSERT(ip->lock.refs == 1);
309                         --hammer_count_inodes;
310                         --hmp->count_inodes;
311                         kfree(ip, M_HAMMER);
312                         hammer_done_cursor(&cursor);
313                         goto loop;
314                 }
315                 ip->flags |= HAMMER_INODE_ONDISK;
316         } else {
317                 /*
318                  * Do not panic on read-only accesses which fail, particularly
319                  * historical accesses where the snapshot might not have
320                  * complete connectivity.
321                  */
322                 if ((flags & HAMMER_INODE_RO) == 0) {
323                         kprintf("hammer_get_inode: failed ip %p obj_id %016llx cursor %p error %d\n",
324                                 ip, ip->obj_id, &cursor, *errorp);
325                         Debugger("x");
326                 }
327                 if (ip->flags & HAMMER_INODE_RSV_INODES) {
328                         ip->flags &= ~HAMMER_INODE_RSV_INODES; /* sanity */
329                         --hmp->rsv_inodes;
330                 }
331                 hmp->rsv_databufs -= ip->rsv_databufs;
332                 ip->rsv_databufs = 0;                          /* sanity */
333
334                 --hammer_count_inodes;
335                 --hmp->count_inodes;
336                 kfree(ip, M_HAMMER);
337                 ip = NULL;
338         }
339         hammer_done_cursor(&cursor);
340         return (ip);
341 }
342
343 /*
344  * Create a new filesystem object, returning the inode in *ipp.  The
345  * returned inode will be referenced.
346  *
347  * The inode is created in-memory.
348  */
349 int
350 hammer_create_inode(hammer_transaction_t trans, struct vattr *vap,
351                     struct ucred *cred, hammer_inode_t dip,
352                     struct hammer_inode **ipp)
353 {
354         hammer_mount_t hmp;
355         hammer_inode_t ip;
356         uid_t xuid;
357
358         hmp = trans->hmp;
359         ip = kmalloc(sizeof(*ip), M_HAMMER, M_WAITOK|M_ZERO);
360         ++hammer_count_inodes;
361         ++hmp->count_inodes;
362         ip->obj_id = hammer_alloc_objid(trans, dip);
363         KKASSERT(ip->obj_id != 0);
364         ip->obj_asof = hmp->asof;
365         ip->hmp = hmp;
366         ip->flush_state = HAMMER_FST_IDLE;
367         ip->flags = HAMMER_INODE_DDIRTY | HAMMER_INODE_ITIMES;
368
369         ip->trunc_off = 0x7FFFFFFFFFFFFFFFLL;
370         RB_INIT(&ip->rec_tree);
371         TAILQ_INIT(&ip->target_list);
372
373         ip->ino_leaf.atime = trans->time;
374         ip->ino_data.mtime = trans->time;
375         ip->ino_data.size = 0;
376         ip->ino_data.nlinks = 0;
377
378         /*
379          * A nohistory designator on the parent directory is inherited by
380          * the child.
381          */
382         ip->ino_data.uflags = dip->ino_data.uflags &
383                               (SF_NOHISTORY|UF_NOHISTORY|UF_NODUMP);
384
385         ip->ino_leaf.base.btype = HAMMER_BTREE_TYPE_RECORD;
386         ip->ino_leaf.base.localization = HAMMER_LOCALIZE_INODE;
387         ip->ino_leaf.base.obj_id = ip->obj_id;
388         ip->ino_leaf.base.key = 0;
389         ip->ino_leaf.base.create_tid = 0;
390         ip->ino_leaf.base.delete_tid = 0;
391         ip->ino_leaf.base.rec_type = HAMMER_RECTYPE_INODE;
392         ip->ino_leaf.base.obj_type = hammer_get_obj_type(vap->va_type);
393
394         ip->ino_data.obj_type = ip->ino_leaf.base.obj_type;
395         ip->ino_data.version = HAMMER_INODE_DATA_VERSION;
396         ip->ino_data.mode = vap->va_mode;
397         ip->ino_data.ctime = trans->time;
398         ip->ino_data.parent_obj_id = (dip) ? dip->ino_leaf.base.obj_id : 0;
399
400         switch(ip->ino_leaf.base.obj_type) {
401         case HAMMER_OBJTYPE_CDEV:
402         case HAMMER_OBJTYPE_BDEV:
403                 ip->ino_data.rmajor = vap->va_rmajor;
404                 ip->ino_data.rminor = vap->va_rminor;
405                 break;
406         default:
407                 break;
408         }
409
410         /*
411          * Calculate default uid/gid and overwrite with information from
412          * the vap.
413          */
414         xuid = hammer_to_unix_xid(&dip->ino_data.uid);
415         xuid = vop_helper_create_uid(hmp->mp, dip->ino_data.mode, xuid, cred,
416                                      &vap->va_mode);
417         ip->ino_data.mode = vap->va_mode;
418
419         if (vap->va_vaflags & VA_UID_UUID_VALID)
420                 ip->ino_data.uid = vap->va_uid_uuid;
421         else if (vap->va_uid != (uid_t)VNOVAL)
422                 hammer_guid_to_uuid(&ip->ino_data.uid, vap->va_uid);
423         else
424                 hammer_guid_to_uuid(&ip->ino_data.uid, xuid);
425
426         if (vap->va_vaflags & VA_GID_UUID_VALID)
427                 ip->ino_data.gid = vap->va_gid_uuid;
428         else if (vap->va_gid != (gid_t)VNOVAL)
429                 hammer_guid_to_uuid(&ip->ino_data.gid, vap->va_gid);
430         else
431                 ip->ino_data.gid = dip->ino_data.gid;
432
433         hammer_ref(&ip->lock);
434         if (RB_INSERT(hammer_ino_rb_tree, &hmp->rb_inos_root, ip)) {
435                 hammer_unref(&ip->lock);
436                 panic("hammer_create_inode: duplicate obj_id %llx", ip->obj_id);
437         }
438         *ipp = ip;
439         return(0);
440 }
441
442 /*
443  * Called by hammer_sync_inode().
444  */
445 static int
446 hammer_update_inode(hammer_cursor_t cursor, hammer_inode_t ip)
447 {
448         hammer_transaction_t trans = cursor->trans;
449         hammer_record_t record;
450         int error;
451
452 retry:
453         error = 0;
454
455         /*
456          * If the inode has a presence on-disk then locate it and mark
457          * it deleted, setting DELONDISK.
458          *
459          * The record may or may not be physically deleted, depending on
460          * the retention policy.
461          */
462         if ((ip->flags & (HAMMER_INODE_ONDISK|HAMMER_INODE_DELONDISK)) ==
463             HAMMER_INODE_ONDISK) {
464                 hammer_normalize_cursor(cursor);
465                 cursor->key_beg.localization = HAMMER_LOCALIZE_INODE;
466                 cursor->key_beg.obj_id = ip->obj_id;
467                 cursor->key_beg.key = 0;
468                 cursor->key_beg.create_tid = 0;
469                 cursor->key_beg.delete_tid = 0;
470                 cursor->key_beg.rec_type = HAMMER_RECTYPE_INODE;
471                 cursor->key_beg.obj_type = 0;
472                 cursor->asof = ip->obj_asof;
473                 cursor->flags &= ~HAMMER_CURSOR_INITMASK;
474                 cursor->flags |= HAMMER_CURSOR_GET_LEAF | HAMMER_CURSOR_ASOF;
475                 cursor->flags |= HAMMER_CURSOR_BACKEND;
476
477                 error = hammer_btree_lookup(cursor);
478                 if (hammer_debug_inode)
479                         kprintf("IPDEL %p %08x %d", ip, ip->flags, error);
480                 if (error) {
481                         kprintf("error %d\n", error);
482                         Debugger("hammer_update_inode");
483                 }
484
485                 if (error == 0) {
486                         error = hammer_ip_delete_record(cursor, ip, trans->tid);
487                         if (hammer_debug_inode)
488                                 kprintf(" error %d\n", error);
489                         if (error && error != EDEADLK) {
490                                 kprintf("error %d\n", error);
491                                 Debugger("hammer_update_inode2");
492                         }
493                         if (error == 0) {
494                                 ip->flags |= HAMMER_INODE_DELONDISK;
495                         }
496                         if (cursor->node)
497                                 hammer_cache_node(cursor->node, &ip->cache[0]);
498                 }
499                 if (error == EDEADLK) {
500                         hammer_done_cursor(cursor);
501                         error = hammer_init_cursor(trans, cursor,
502                                                    &ip->cache[0], ip);
503                         if (hammer_debug_inode)
504                                 kprintf("IPDED %p %d\n", ip, error);
505                         if (error == 0)
506                                 goto retry;
507                 }
508         }
509
510         /*
511          * Ok, write out the initial record or a new record (after deleting
512          * the old one), unless the DELETED flag is set.  This routine will
513          * clear DELONDISK if it writes out a record.
514          *
515          * Update our inode statistics if this is the first application of
516          * the inode on-disk.
517          */
518         if (error == 0 && (ip->flags & HAMMER_INODE_DELETED) == 0) {
519                 /*
520                  * Generate a record and write it to the media
521                  */
522                 record = hammer_alloc_mem_record(ip, 0);
523                 record->type = HAMMER_MEM_RECORD_INODE;
524                 record->flush_state = HAMMER_FST_FLUSH;
525                 record->leaf = ip->sync_ino_leaf;
526                 record->leaf.base.create_tid = trans->tid;
527                 record->leaf.data_len = sizeof(ip->sync_ino_data);
528                 record->data = (void *)&ip->sync_ino_data;
529                 record->flags |= HAMMER_RECF_INTERLOCK_BE;
530                 for (;;) {
531                         error = hammer_ip_sync_record_cursor(cursor, record);
532                         if (hammer_debug_inode)
533                                 kprintf("GENREC %p rec %08x %d\n",      
534                                         ip, record->flags, error);
535                         if (error != EDEADLK)
536                                 break;
537                         hammer_done_cursor(cursor);
538                         error = hammer_init_cursor(trans, cursor,
539                                                    &ip->cache[0], ip);
540                         if (hammer_debug_inode)
541                                 kprintf("GENREC reinit %d\n", error);
542                         if (error)
543                                 break;
544                 }
545                 if (error) {
546                         kprintf("error %d\n", error);
547                         Debugger("hammer_update_inode3");
548                 }
549
550                 /*
551                  * The record isn't managed by the inode's record tree,
552                  * destroy it whether we succeed or fail.
553                  */
554                 record->flags &= ~HAMMER_RECF_INTERLOCK_BE;
555                 record->flags |= HAMMER_RECF_DELETED_FE;
556                 record->flush_state = HAMMER_FST_IDLE;
557                 hammer_rel_mem_record(record);
558
559                 /*
560                  * Finish up.
561                  */
562                 if (error == 0) {
563                         if (hammer_debug_inode)
564                                 kprintf("CLEANDELOND %p %08x\n", ip, ip->flags);
565                         ip->sync_flags &= ~(HAMMER_INODE_DDIRTY |
566                                             HAMMER_INODE_ITIMES);
567                         ip->flags &= ~HAMMER_INODE_DELONDISK;
568
569                         /*
570                          * Root volume count of inodes
571                          */
572                         if ((ip->flags & HAMMER_INODE_ONDISK) == 0) {
573                                 hammer_modify_volume_field(trans,
574                                                            trans->rootvol,
575                                                            vol0_stat_inodes);
576                                 ++ip->hmp->rootvol->ondisk->vol0_stat_inodes;
577                                 hammer_modify_volume_done(trans->rootvol);
578                                 ip->flags |= HAMMER_INODE_ONDISK;
579                                 if (hammer_debug_inode)
580                                         kprintf("NOWONDISK %p\n", ip);
581                         }
582                 }
583         }
584
585         /*
586          * If the inode has been destroyed, clean out any left-over flags
587          * that may have been set by the frontend.
588          */
589         if (error == 0 && (ip->flags & HAMMER_INODE_DELETED)) { 
590                 ip->sync_flags &= ~(HAMMER_INODE_DDIRTY |
591                                     HAMMER_INODE_ITIMES);
592         }
593         return(error);
594 }
595
596 /*
597  * Update only the itimes fields.  This is done no-historically.  The
598  * record is updated in-place on the disk.
599  */
600 static int
601 hammer_update_itimes(hammer_cursor_t cursor, hammer_inode_t ip)
602 {
603         hammer_transaction_t trans = cursor->trans;
604         struct hammer_btree_leaf_elm *leaf;
605         int error;
606
607 retry:
608         error = 0;
609         if ((ip->flags & (HAMMER_INODE_ONDISK|HAMMER_INODE_DELONDISK)) ==
610             HAMMER_INODE_ONDISK) {
611                 hammer_normalize_cursor(cursor);
612                 cursor->key_beg.localization = HAMMER_LOCALIZE_INODE;
613                 cursor->key_beg.obj_id = ip->obj_id;
614                 cursor->key_beg.key = 0;
615                 cursor->key_beg.create_tid = 0;
616                 cursor->key_beg.delete_tid = 0;
617                 cursor->key_beg.rec_type = HAMMER_RECTYPE_INODE;
618                 cursor->key_beg.obj_type = 0;
619                 cursor->asof = ip->obj_asof;
620                 cursor->flags &= ~HAMMER_CURSOR_INITMASK;
621                 cursor->flags |= HAMMER_CURSOR_GET_LEAF | HAMMER_CURSOR_ASOF;
622                 cursor->flags |= HAMMER_CURSOR_BACKEND;
623
624                 error = hammer_btree_lookup(cursor);
625                 if (error) {
626                         kprintf("error %d\n", error);
627                         Debugger("hammer_update_itimes1");
628                 }
629                 if (error == 0) {
630                         /*
631                          * Do not generate UNDO records for atime updates.
632                          */
633                         leaf = cursor->leaf;
634                         hammer_modify_node(trans, cursor->node, 
635                                            &leaf->atime, sizeof(leaf->atime));
636                         leaf->atime = ip->sync_ino_leaf.atime;
637                         hammer_modify_node_done(cursor->node);
638                         /*rec->ino_mtime = ip->sync_ino_rec.ino_mtime;*/
639                         ip->sync_flags &= ~HAMMER_INODE_ITIMES;
640                         /* XXX recalculate crc */
641                         hammer_cache_node(cursor->node, &ip->cache[0]);
642                 }
643                 if (error == EDEADLK) {
644                         hammer_done_cursor(cursor);
645                         error = hammer_init_cursor(trans, cursor,
646                                                    &ip->cache[0], ip);
647                         if (error == 0)
648                                 goto retry;
649                 }
650         }
651         return(error);
652 }
653
654 /*
655  * Release a reference on an inode, flush as requested.
656  *
657  * On the last reference we queue the inode to the flusher for its final
658  * disposition.
659  */
660 void
661 hammer_rel_inode(struct hammer_inode *ip, int flush)
662 {
663         hammer_mount_t hmp = ip->hmp;
664
665         /*
666          * Handle disposition when dropping the last ref.
667          */
668         for (;;) {
669                 if (ip->lock.refs == 1) {
670                         /*
671                          * Determine whether on-disk action is needed for
672                          * the inode's final disposition.
673                          */
674                         KKASSERT(ip->vp == NULL);
675                         hammer_inode_unloadable_check(ip, 0);
676                         if (ip->flags & HAMMER_INODE_MODMASK) {
677                                 if (hmp->rsv_inodes > desiredvnodes) {
678                                         hammer_flush_inode(ip,
679                                                            HAMMER_FLUSH_SIGNAL);
680                                 } else {
681                                         hammer_flush_inode(ip, 0);
682                                 }
683                         } else if (ip->lock.refs == 1) {
684                                 hammer_unload_inode(ip);
685                                 break;
686                         }
687                 } else {
688                         if (flush)
689                                 hammer_flush_inode(ip, 0);
690
691                         /*
692                          * The inode still has multiple refs, try to drop
693                          * one ref.
694                          */
695                         KKASSERT(ip->lock.refs >= 1);
696                         if (ip->lock.refs > 1) {
697                                 hammer_unref(&ip->lock);
698                                 break;
699                         }
700                 }
701         }
702 }
703
704 /*
705  * Unload and destroy the specified inode.  Must be called with one remaining
706  * reference.  The reference is disposed of.
707  *
708  * This can only be called in the context of the flusher.
709  */
710 static int
711 hammer_unload_inode(struct hammer_inode *ip)
712 {
713         hammer_mount_t hmp = ip->hmp;
714
715         KASSERT(ip->lock.refs == 1,
716                 ("hammer_unload_inode: %d refs\n", ip->lock.refs));
717         KKASSERT(ip->vp == NULL);
718         KKASSERT(ip->flush_state == HAMMER_FST_IDLE);
719         KKASSERT(ip->cursor_ip_refs == 0);
720         KKASSERT(ip->lock.lockcount == 0);
721         KKASSERT((ip->flags & HAMMER_INODE_MODMASK) == 0);
722
723         KKASSERT(RB_EMPTY(&ip->rec_tree));
724         KKASSERT(TAILQ_EMPTY(&ip->target_list));
725
726         RB_REMOVE(hammer_ino_rb_tree, &hmp->rb_inos_root, ip);
727
728         hammer_uncache_node(&ip->cache[0]);
729         hammer_uncache_node(&ip->cache[1]);
730         if (ip->objid_cache)
731                 hammer_clear_objid(ip);
732         --hammer_count_inodes;
733         --hmp->count_inodes;
734
735         if (ip->flags & HAMMER_INODE_RECLAIM) {
736                 --hammer_count_reclaiming;
737                 --hmp->inode_reclaims;
738                 ip->flags &= ~HAMMER_INODE_RECLAIM;
739                 if (hmp->flags & HAMMER_MOUNT_WAITIMAX)
740                         hammer_inode_wakereclaims(hmp);
741         }
742         kfree(ip, M_HAMMER);
743
744         return(0);
745 }
746
747 /*
748  * Called on mount -u when switching from RW to RO or vise-versa.  Adjust
749  * the read-only flag for cached inodes.
750  *
751  * This routine is called from a RB_SCAN().
752  */
753 int
754 hammer_reload_inode(hammer_inode_t ip, void *arg __unused)
755 {
756         hammer_mount_t hmp = ip->hmp;
757
758         if (hmp->ronly || hmp->asof != HAMMER_MAX_TID)
759                 ip->flags |= HAMMER_INODE_RO;
760         else
761                 ip->flags &= ~HAMMER_INODE_RO;
762         return(0);
763 }
764
765 /*
766  * A transaction has modified an inode, requiring updates as specified by
767  * the passed flags.
768  *
769  * HAMMER_INODE_DDIRTY: Inode data has been updated
770  * HAMMER_INODE_XDIRTY: Dirty in-memory records
771  * HAMMER_INODE_BUFS:   Dirty buffer cache buffers
772  * HAMMER_INODE_DELETED: Inode record/data must be deleted
773  * HAMMER_INODE_ITIMES: mtime/atime has been updated
774  */
775 void
776 hammer_modify_inode(hammer_inode_t ip, int flags)
777 {
778         KKASSERT ((ip->flags & HAMMER_INODE_RO) == 0 ||
779                   (flags & (HAMMER_INODE_DDIRTY |
780                             HAMMER_INODE_XDIRTY | HAMMER_INODE_BUFS |
781                             HAMMER_INODE_DELETED | HAMMER_INODE_ITIMES)) == 0);
782         if ((ip->flags & HAMMER_INODE_RSV_INODES) == 0) {
783                 ip->flags |= HAMMER_INODE_RSV_INODES;
784                 ++ip->hmp->rsv_inodes;
785         }
786
787         ip->flags |= flags;
788 }
789
790 /*
791  * Request that an inode be flushed.  This whole mess cannot block and may
792  * recurse.  Once requested HAMMER will attempt to actively flush it until
793  * the flush can be done.
794  *
795  * The inode may already be flushing, or may be in a setup state.  We can
796  * place the inode in a flushing state if it is currently idle and flag it
797  * to reflush if it is currently flushing.
798  */
799 void
800 hammer_flush_inode(hammer_inode_t ip, int flags)
801 {
802         hammer_record_t depend;
803         int r, good;
804
805         /*
806          * Trivial 'nothing to flush' case.  If the inode is ina SETUP
807          * state we have to put it back into an IDLE state so we can
808          * drop the extra ref.
809          */
810         if ((ip->flags & HAMMER_INODE_MODMASK) == 0) {
811                 if (ip->flush_state == HAMMER_FST_SETUP) {
812                         ip->flush_state = HAMMER_FST_IDLE;
813                         hammer_rel_inode(ip, 0);
814                 }
815                 return;
816         }
817
818         /*
819          * Our flush action will depend on the current state.
820          */
821         switch(ip->flush_state) {
822         case HAMMER_FST_IDLE:
823                 /*
824                  * We have no dependancies and can flush immediately.  Some
825                  * our children may not be flushable so we have to re-test
826                  * with that additional knowledge.
827                  */
828                 hammer_flush_inode_core(ip, flags);
829                 break;
830         case HAMMER_FST_SETUP:
831                 /*
832                  * Recurse upwards through dependancies via target_list
833                  * and start their flusher actions going if possible.
834                  *
835                  * 'good' is our connectivity.  -1 means we have none and
836                  * can't flush, 0 means there weren't any dependancies, and
837                  * 1 means we have good connectivity.
838                  */
839                 good = 0;
840                 TAILQ_FOREACH(depend, &ip->target_list, target_entry) {
841                         r = hammer_setup_parent_inodes(depend);
842                         if (r < 0 && good == 0)
843                                 good = -1;
844                         if (r > 0)
845                                 good = 1;
846                 }
847
848                 /*
849                  * We can continue if good >= 0.  Determine how many records
850                  * under our inode can be flushed (and mark them).
851                  */
852                 if (good >= 0) {
853                         hammer_flush_inode_core(ip, flags);
854                 } else {
855                         ip->flags |= HAMMER_INODE_REFLUSH;
856                         if (flags & HAMMER_FLUSH_SIGNAL) {
857                                 ip->flags |= HAMMER_INODE_RESIGNAL;
858                                 hammer_flusher_async(ip->hmp);
859                         }
860                 }
861                 break;
862         default:
863                 /*
864                  * We are already flushing, flag the inode to reflush
865                  * if needed after it completes its current flush.
866                  */
867                 if ((ip->flags & HAMMER_INODE_REFLUSH) == 0)
868                         ip->flags |= HAMMER_INODE_REFLUSH;
869                 if (flags & HAMMER_FLUSH_SIGNAL) {
870                         ip->flags |= HAMMER_INODE_RESIGNAL;
871                         hammer_flusher_async(ip->hmp);
872                 }
873                 break;
874         }
875 }
876
877 /*
878  * We are asked to recurse upwards and convert the record from SETUP
879  * to FLUSH if possible.  record->ip is a parent of the caller's inode,
880  * and record->target_ip is the caller's inode.
881  *
882  * Return 1 if the record gives us connectivity
883  *
884  * Return 0 if the record is not relevant 
885  *
886  * Return -1 if we can't resolve the dependancy and there is no connectivity.
887  */
888 static int
889 hammer_setup_parent_inodes(hammer_record_t record)
890 {
891         hammer_mount_t hmp = record->ip->hmp;
892         hammer_record_t depend;
893         hammer_inode_t ip;
894         int r, good;
895
896         KKASSERT(record->flush_state != HAMMER_FST_IDLE);
897         ip = record->ip;
898
899         /*
900          * If the record is already flushing, is it in our flush group?
901          *
902          * If it is in our flush group but it is a general record or a 
903          * delete-on-disk, it does not improve our connectivity (return 0),
904          * and if the target inode is not trying to destroy itself we can't
905          * allow the operation yet anyway (the second return -1).
906          */
907         if (record->flush_state == HAMMER_FST_FLUSH) {
908                 if (record->flush_group != hmp->flusher.next) {
909                         ip->flags |= HAMMER_INODE_REFLUSH;
910                         return(-1);
911                 }
912                 if (record->type == HAMMER_MEM_RECORD_ADD)
913                         return(1);
914                 /* GENERAL or DEL */
915                 return(0);
916         }
917
918         /*
919          * It must be a setup record.  Try to resolve the setup dependancies
920          * by recursing upwards so we can place ip on the flush list.
921          */
922         KKASSERT(record->flush_state == HAMMER_FST_SETUP);
923
924         good = 0;
925         TAILQ_FOREACH(depend, &ip->target_list, target_entry) {
926                 r = hammer_setup_parent_inodes(depend);
927                 if (r < 0 && good == 0)
928                         good = -1;
929                 if (r > 0)
930                         good = 1;
931         }
932
933         /*
934          * We can't flush ip because it has no connectivity (XXX also check
935          * nlinks for pre-existing connectivity!).  Flag it so any resolution
936          * recurses back down.
937          */
938         if (good < 0) {
939                 ip->flags |= HAMMER_INODE_REFLUSH;
940                 return(good);
941         }
942
943         /*
944          * We are go, place the parent inode in a flushing state so we can
945          * place its record in a flushing state.  Note that the parent
946          * may already be flushing.  The record must be in the same flush
947          * group as the parent.
948          */
949         if (ip->flush_state != HAMMER_FST_FLUSH)
950                 hammer_flush_inode_core(ip, HAMMER_FLUSH_RECURSION);
951         KKASSERT(ip->flush_state == HAMMER_FST_FLUSH);
952         KKASSERT(record->flush_state == HAMMER_FST_SETUP);
953
954 #if 0
955         if (record->type == HAMMER_MEM_RECORD_DEL &&
956             (record->target_ip->flags & (HAMMER_INODE_DELETED|HAMMER_INODE_DELONDISK)) == 0) {
957                 /*
958                  * Regardless of flushing state we cannot sync this path if the
959                  * record represents a delete-on-disk but the target inode
960                  * is not ready to sync its own deletion.
961                  *
962                  * XXX need to count effective nlinks to determine whether
963                  * the flush is ok, otherwise removing a hardlink will
964                  * just leave the DEL record to rot.
965                  */
966                 record->target_ip->flags |= HAMMER_INODE_REFLUSH;
967                 return(-1);
968         } else
969 #endif
970         if (ip->flush_group == ip->hmp->flusher.next) {
971                 /*
972                  * This is the record we wanted to synchronize.
973                  */
974                 record->flush_state = HAMMER_FST_FLUSH;
975                 record->flush_group = ip->flush_group;
976                 hammer_ref(&record->lock);
977                 if (record->type == HAMMER_MEM_RECORD_ADD)
978                         return(1);
979
980                 /*
981                  * A general or delete-on-disk record does not contribute
982                  * to our visibility.  We can still flush it, however.
983                  */
984                 return(0);
985         } else {
986                 /*
987                  * We couldn't resolve the dependancies, request that the
988                  * inode be flushed when the dependancies can be resolved.
989                  */
990                 ip->flags |= HAMMER_INODE_REFLUSH;
991                 return(-1);
992         }
993 }
994
995 /*
996  * This is the core routine placing an inode into the FST_FLUSH state.
997  */
998 static void
999 hammer_flush_inode_core(hammer_inode_t ip, int flags)
1000 {
1001         int go_count;
1002
1003         /*
1004          * Set flush state and prevent the flusher from cycling into
1005          * the next flush group.  Do not place the ip on the list yet.
1006          * Inodes not in the idle state get an extra reference.
1007          */
1008         KKASSERT(ip->flush_state != HAMMER_FST_FLUSH);
1009         if (ip->flush_state == HAMMER_FST_IDLE)
1010                 hammer_ref(&ip->lock);
1011         ip->flush_state = HAMMER_FST_FLUSH;
1012         ip->flush_group = ip->hmp->flusher.next;
1013         ++ip->hmp->flusher.group_lock;
1014         ++ip->hmp->count_iqueued;
1015         ++hammer_count_iqueued;
1016
1017         /*
1018          * We need to be able to vfsync/truncate from the backend.
1019          */
1020         KKASSERT((ip->flags & HAMMER_INODE_VHELD) == 0);
1021         if (ip->vp && (ip->vp->v_flag & VINACTIVE) == 0) {
1022                 ip->flags |= HAMMER_INODE_VHELD;
1023                 vref(ip->vp);
1024         }
1025
1026         /*
1027          * Figure out how many in-memory records we can actually flush
1028          * (not including inode meta-data, buffers, etc).
1029          */
1030         if (flags & HAMMER_FLUSH_RECURSION) {
1031                 go_count = 1;
1032         } else {
1033                 go_count = RB_SCAN(hammer_rec_rb_tree, &ip->rec_tree, NULL,
1034                                    hammer_setup_child_callback, NULL);
1035         }
1036
1037         /*
1038          * This is a more involved test that includes go_count.  If we
1039          * can't flush, flag the inode and return.  If go_count is 0 we
1040          * were are unable to flush any records in our rec_tree and
1041          * must ignore the XDIRTY flag.
1042          */
1043         if (go_count == 0) {
1044                 if ((ip->flags & HAMMER_INODE_MODMASK_NOXDIRTY) == 0) {
1045                         ip->flags |= HAMMER_INODE_REFLUSH;
1046
1047                         --ip->hmp->count_iqueued;
1048                         --hammer_count_iqueued;
1049
1050                         ip->flush_state = HAMMER_FST_SETUP;
1051                         if (ip->flags & HAMMER_INODE_VHELD) {
1052                                 ip->flags &= ~HAMMER_INODE_VHELD;
1053                                 vrele(ip->vp);
1054                         }
1055                         if (flags & HAMMER_FLUSH_SIGNAL) {
1056                                 ip->flags |= HAMMER_INODE_RESIGNAL;
1057                                 hammer_flusher_async(ip->hmp);
1058                         }
1059                         if (--ip->hmp->flusher.group_lock == 0)
1060                                 wakeup(&ip->hmp->flusher.group_lock);
1061                         return;
1062                 }
1063         }
1064
1065         /*
1066          * Snapshot the state of the inode for the backend flusher.
1067          *
1068          * The truncation must be retained in the frontend until after
1069          * we've actually performed the record deletion.
1070          *
1071          * NOTE: The DELETING flag is a mod flag, but it is also sticky,
1072          * and stays in ip->flags.  Once set, it stays set until the
1073          * inode is destroyed.
1074          */
1075         ip->sync_flags = (ip->flags & HAMMER_INODE_MODMASK);
1076         ip->sync_trunc_off = ip->trunc_off;
1077         ip->sync_ino_leaf = ip->ino_leaf;
1078         ip->sync_ino_data = ip->ino_data;
1079         ip->trunc_off = 0x7FFFFFFFFFFFFFFFLL;
1080         ip->flags &= ~HAMMER_INODE_MODMASK;
1081 #ifdef DEBUG_TRUNCATE
1082         if ((ip->sync_flags & HAMMER_INODE_TRUNCATED) && ip == HammerTruncIp)
1083                 kprintf("truncateS %016llx\n", ip->sync_trunc_off);
1084 #endif
1085
1086         /*
1087          * The flusher list inherits our inode and reference.
1088          */
1089         TAILQ_INSERT_TAIL(&ip->hmp->flush_list, ip, flush_entry);
1090         if (--ip->hmp->flusher.group_lock == 0)
1091                 wakeup(&ip->hmp->flusher.group_lock);
1092
1093         if (flags & HAMMER_FLUSH_SIGNAL) {
1094                 hammer_flusher_async(ip->hmp);
1095         }
1096 }
1097
1098 /*
1099  * Callback for scan of ip->rec_tree.  Try to include each record in our
1100  * flush.  ip->flush_group has been set but the inode has not yet been
1101  * moved into a flushing state.
1102  *
1103  * If we get stuck on a record we have to set HAMMER_INODE_REFLUSH on
1104  * both inodes.
1105  *
1106  * We return 1 for any record placed or found in FST_FLUSH, which prevents
1107  * the caller from shortcutting the flush.
1108  */
1109 static int
1110 hammer_setup_child_callback(hammer_record_t rec, void *data)
1111 {
1112         hammer_inode_t target_ip;
1113         hammer_inode_t ip;
1114         int r;
1115
1116         /*
1117          * If the record has been deleted by the backend (it's being held
1118          * by the frontend in a race), just ignore it.
1119          */
1120         if (rec->flags & HAMMER_RECF_DELETED_BE)
1121                 return(0);
1122
1123         /*
1124          * If the record is in an idle state it has no dependancies and
1125          * can be flushed.
1126          */
1127         ip = rec->ip;
1128         r = 0;
1129
1130         switch(rec->flush_state) {
1131         case HAMMER_FST_IDLE:
1132                 /*
1133                  * Record has no setup dependancy, we can flush it.
1134                  */
1135                 KKASSERT(rec->target_ip == NULL);
1136                 rec->flush_state = HAMMER_FST_FLUSH;
1137                 rec->flush_group = ip->flush_group;
1138                 hammer_ref(&rec->lock);
1139                 r = 1;
1140                 break;
1141         case HAMMER_FST_SETUP:
1142                 /*
1143                  * Record has a setup dependancy.  Try to include the
1144                  * target ip in the flush. 
1145                  *
1146                  * We have to be careful here, if we do not do the right
1147                  * thing we can lose track of dirty inodes and the system
1148                  * will lockup trying to allocate buffers.
1149                  */
1150                 target_ip = rec->target_ip;
1151                 KKASSERT(target_ip != NULL);
1152                 KKASSERT(target_ip->flush_state != HAMMER_FST_IDLE);
1153                 if (target_ip->flush_state == HAMMER_FST_FLUSH) {
1154                         /*
1155                          * If the target IP is already flushing in our group
1156                          * we are golden, otherwise make sure the target
1157                          * reflushes.
1158                          */
1159                         if (target_ip->flush_group == ip->flush_group) {
1160                                 rec->flush_state = HAMMER_FST_FLUSH;
1161                                 rec->flush_group = ip->flush_group;
1162                                 hammer_ref(&rec->lock);
1163                                 r = 1;
1164                         } else {
1165                                 target_ip->flags |= HAMMER_INODE_REFLUSH;
1166                         }
1167                 } else if (rec->type == HAMMER_MEM_RECORD_ADD) {
1168                         /*
1169                          * If the target IP is not flushing we can force
1170                          * it to flush, even if it is unable to write out
1171                          * any of its own records we have at least one in
1172                          * hand that we CAN deal with.
1173                          */
1174                         rec->flush_state = HAMMER_FST_FLUSH;
1175                         rec->flush_group = ip->flush_group;
1176                         hammer_ref(&rec->lock);
1177                         hammer_flush_inode_core(target_ip,
1178                                                 HAMMER_FLUSH_RECURSION);
1179                         r = 1;
1180                 } else {
1181                         /*
1182                          * General or delete-on-disk record.
1183                          *
1184                          * XXX this needs help.  If a delete-on-disk we could
1185                          * disconnect the target.  If the target has its own
1186                          * dependancies they really need to be flushed.
1187                          *
1188                          * XXX
1189                          */
1190                         rec->flush_state = HAMMER_FST_FLUSH;
1191                         rec->flush_group = ip->flush_group;
1192                         hammer_ref(&rec->lock);
1193                         hammer_flush_inode_core(target_ip,
1194                                                 HAMMER_FLUSH_RECURSION);
1195                         r = 1;
1196                 }
1197                 break;
1198         case HAMMER_FST_FLUSH:
1199                 /* 
1200                  * Record already associated with a flush group.  It had
1201                  * better be ours.
1202                  */
1203                 KKASSERT(rec->flush_group == ip->flush_group);
1204                 r = 1;
1205                 break;
1206         }
1207         return(r);
1208 }
1209
1210 /*
1211  * Wait for a previously queued flush to complete
1212  */
1213 void
1214 hammer_wait_inode(hammer_inode_t ip)
1215 {
1216         while (ip->flush_state != HAMMER_FST_IDLE) {
1217                 if (ip->flush_state == HAMMER_FST_SETUP) {
1218                         hammer_flush_inode(ip, HAMMER_FLUSH_SIGNAL);
1219                 } else {
1220                         ip->flags |= HAMMER_INODE_FLUSHW;
1221                         tsleep(&ip->flags, 0, "hmrwin", 0);
1222                 }
1223         }
1224 }
1225
1226 /*
1227  * Wait for records to drain
1228  */
1229 void
1230 hammer_wait_inode_recs(hammer_inode_t ip)
1231 {
1232         while (ip->rsv_recs > hammer_limit_irecs) {
1233                 hammer_flush_inode(ip, HAMMER_FLUSH_SIGNAL);
1234                 if (ip->rsv_recs > hammer_limit_irecs) {
1235                         ip->flags |= HAMMER_INODE_PARTIALW;
1236                         tsleep(&ip->flags, 0, "hmrwpp", 0);
1237                 }
1238         }
1239 }
1240
1241 /*
1242  * Called by the backend code when a flush has been completed.
1243  * The inode has already been removed from the flush list.
1244  *
1245  * A pipelined flush can occur, in which case we must re-enter the
1246  * inode on the list and re-copy its fields.
1247  */
1248 void
1249 hammer_flush_inode_done(hammer_inode_t ip)
1250 {
1251         hammer_mount_t hmp;
1252         int dorel;
1253
1254         KKASSERT(ip->flush_state == HAMMER_FST_FLUSH);
1255
1256         hmp = ip->hmp;
1257
1258         /*
1259          * Merge left-over flags back into the frontend and fix the state.
1260          */
1261         ip->flags |= ip->sync_flags;
1262
1263         /*
1264          * The backend may have adjusted nlinks, so if the adjusted nlinks
1265          * does not match the fronttend set the frontend's RDIRTY flag again.
1266          */
1267         if (ip->ino_data.nlinks != ip->sync_ino_data.nlinks)
1268                 ip->flags |= HAMMER_INODE_DDIRTY;
1269
1270         /*
1271          * Fix up the dirty buffer status.  IO completions will also
1272          * try to clean up rsv_databufs.
1273          */
1274         if (ip->vp && RB_ROOT(&ip->vp->v_rbdirty_tree)) {
1275                 ip->flags |= HAMMER_INODE_BUFS;
1276         } else {
1277                 hmp->rsv_databufs -= ip->rsv_databufs;
1278                 ip->rsv_databufs = 0;
1279         }
1280
1281         /*
1282          * Re-set the XDIRTY flag if some of the inode's in-memory records
1283          * could not be flushed.
1284          */
1285         KKASSERT((RB_EMPTY(&ip->rec_tree) &&
1286                   (ip->flags & HAMMER_INODE_XDIRTY) == 0) ||
1287                  (!RB_EMPTY(&ip->rec_tree) &&
1288                   (ip->flags & HAMMER_INODE_XDIRTY) != 0));
1289
1290         /*
1291          * Do not lose track of inodes which no longer have vnode
1292          * assocations, otherwise they may never get flushed again.
1293          */
1294         if ((ip->flags & HAMMER_INODE_MODMASK) && ip->vp == NULL)
1295                 ip->flags |= HAMMER_INODE_REFLUSH;
1296
1297         /*
1298          * Adjust flush_state.  The target state (idle or setup) shouldn't
1299          * be terribly important since we will reflush if we really need
1300          * to do anything. XXX
1301          */
1302         if (TAILQ_EMPTY(&ip->target_list) && RB_EMPTY(&ip->rec_tree)) {
1303                 ip->flush_state = HAMMER_FST_IDLE;
1304                 dorel = 1;
1305         } else {
1306                 ip->flush_state = HAMMER_FST_SETUP;
1307                 dorel = 0;
1308         }
1309
1310         --hmp->count_iqueued;
1311         --hammer_count_iqueued;
1312
1313         /*
1314          * Clean up the vnode ref
1315          */
1316         if (ip->flags & HAMMER_INODE_VHELD) {
1317                 ip->flags &= ~HAMMER_INODE_VHELD;
1318                 vrele(ip->vp);
1319         }
1320
1321         /*
1322          * If the frontend made more changes and requested another flush,
1323          * then try to get it running.
1324          */
1325         if (ip->flags & HAMMER_INODE_REFLUSH) {
1326                 ip->flags &= ~HAMMER_INODE_REFLUSH;
1327                 if (ip->flags & HAMMER_INODE_RESIGNAL) {
1328                         ip->flags &= ~HAMMER_INODE_RESIGNAL;
1329                         hammer_flush_inode(ip, HAMMER_FLUSH_SIGNAL);
1330                 } else {
1331                         hammer_flush_inode(ip, 0);
1332                 }
1333         }
1334
1335         /*
1336          * If the inode is now clean drop the space reservation.
1337          */
1338         if ((ip->flags & HAMMER_INODE_MODMASK) == 0 &&
1339             (ip->flags & HAMMER_INODE_RSV_INODES)) {
1340                 ip->flags &= ~HAMMER_INODE_RSV_INODES;
1341                 --hmp->rsv_inodes;
1342         }
1343
1344         /*
1345          * Finally, if the frontend is waiting for a flush to complete,
1346          * wake it up.
1347          */
1348         if (ip->flush_state != HAMMER_FST_FLUSH) {
1349                 if (ip->flags & HAMMER_INODE_FLUSHW) {
1350                         ip->flags &= ~HAMMER_INODE_FLUSHW;
1351                         wakeup(&ip->flags);
1352                 }
1353         }
1354         if (dorel)
1355                 hammer_rel_inode(ip, 0);
1356 }
1357
1358 /*
1359  * Called from hammer_sync_inode() to synchronize in-memory records
1360  * to the media.
1361  */
1362 static int
1363 hammer_sync_record_callback(hammer_record_t record, void *data)
1364 {
1365         hammer_cursor_t cursor = data;
1366         hammer_transaction_t trans = cursor->trans;
1367         int error;
1368
1369         /*
1370          * Skip records that do not belong to the current flush.
1371          */
1372         ++hammer_stats_record_iterations;
1373         if (record->flush_state != HAMMER_FST_FLUSH)
1374                 return(0);
1375
1376 #if 1
1377         if (record->flush_group != record->ip->flush_group) {
1378                 kprintf("sync_record %p ip %p bad flush group %d %d\n", record, record->ip, record->flush_group ,record->ip->flush_group);
1379                 Debugger("blah2");
1380                 return(0);
1381         }
1382 #endif
1383         KKASSERT(record->flush_group == record->ip->flush_group);
1384
1385         /*
1386          * Interlock the record using the BE flag.  Once BE is set the
1387          * frontend cannot change the state of FE.
1388          *
1389          * NOTE: If FE is set prior to us setting BE we still sync the
1390          * record out, but the flush completion code converts it to 
1391          * a delete-on-disk record instead of destroying it.
1392          */
1393         KKASSERT((record->flags & HAMMER_RECF_INTERLOCK_BE) == 0);
1394         record->flags |= HAMMER_RECF_INTERLOCK_BE;
1395
1396         /*
1397          * The backend may have already disposed of the record.
1398          */
1399         if (record->flags & HAMMER_RECF_DELETED_BE) {
1400                 error = 0;
1401                 goto done;
1402         }
1403
1404         /*
1405          * If the whole inode is being deleting all on-disk records will
1406          * be deleted very soon, we can't sync any new records to disk
1407          * because they will be deleted in the same transaction they were
1408          * created in (delete_tid == create_tid), which will assert.
1409          *
1410          * XXX There may be a case with RECORD_ADD with DELETED_FE set
1411          * that we currently panic on.
1412          */
1413         if (record->ip->sync_flags & HAMMER_INODE_DELETING) {
1414                 switch(record->type) {
1415                 case HAMMER_MEM_RECORD_DATA:
1416                         /*
1417                          * We don't have to do anything, if the record was
1418                          * committed the space will have been accounted for
1419                          * in the blockmap.
1420                          */
1421                         /* fall through */
1422                 case HAMMER_MEM_RECORD_GENERAL:
1423                         record->flags |= HAMMER_RECF_DELETED_FE;
1424                         record->flags |= HAMMER_RECF_DELETED_BE;
1425                         error = 0;
1426                         goto done;
1427                 case HAMMER_MEM_RECORD_ADD:
1428                         panic("hammer_sync_record_callback: illegal add "
1429                               "during inode deletion record %p", record);
1430                         break; /* NOT REACHED */
1431                 case HAMMER_MEM_RECORD_INODE:
1432                         panic("hammer_sync_record_callback: attempt to "
1433                               "sync inode record %p?", record);
1434                         break; /* NOT REACHED */
1435                 case HAMMER_MEM_RECORD_DEL:
1436                         /* 
1437                          * Follow through and issue the on-disk deletion
1438                          */
1439                         break;
1440                 }
1441         }
1442
1443         /*
1444          * If DELETED_FE is set we may have already sent dependant pieces
1445          * to the disk and we must flush the record as if it hadn't been
1446          * deleted.  This creates a bit of a mess because we have to
1447          * have ip_sync_record convert the record to MEM_RECORD_DEL before
1448          * it inserts the B-Tree record.  Otherwise the media sync might
1449          * be visible to the frontend.
1450          */
1451         if (record->flags & HAMMER_RECF_DELETED_FE) {
1452                 if (record->type == HAMMER_MEM_RECORD_ADD) {
1453                         record->flags |= HAMMER_RECF_CONVERT_DELETE;
1454                 } else {
1455                         KKASSERT(record->type != HAMMER_MEM_RECORD_DEL);
1456                         return(0);
1457                 }
1458         }
1459
1460         /*
1461          * Assign the create_tid for new records.  Deletions already
1462          * have the record's entire key properly set up.
1463          */
1464         if (record->type != HAMMER_MEM_RECORD_DEL)
1465                 record->leaf.base.create_tid = trans->tid;
1466         for (;;) {
1467                 error = hammer_ip_sync_record_cursor(cursor, record);
1468                 if (error != EDEADLK)
1469                         break;
1470                 hammer_done_cursor(cursor);
1471                 error = hammer_init_cursor(trans, cursor, &record->ip->cache[0],
1472                                            record->ip);
1473                 if (error)
1474                         break;
1475         }
1476         record->flags &= ~HAMMER_RECF_CONVERT_DELETE;
1477
1478         if (error) {
1479                 error = -error;
1480                 if (error != -ENOSPC) {
1481                         kprintf("hammer_sync_record_callback: sync failed rec "
1482                                 "%p, error %d\n", record, error);
1483                         Debugger("sync failed rec");
1484                 }
1485         }
1486 done:
1487         hammer_flush_record_done(record, error);
1488         return(error);
1489 }
1490
1491 /*
1492  * XXX error handling
1493  */
1494 int
1495 hammer_sync_inode(hammer_inode_t ip)
1496 {
1497         struct hammer_transaction trans;
1498         struct hammer_cursor cursor;
1499         hammer_record_t depend;
1500         hammer_record_t next;
1501         int error, tmp_error;
1502         u_int64_t nlinks;
1503
1504         if ((ip->sync_flags & HAMMER_INODE_MODMASK) == 0)
1505                 return(0);
1506
1507         hammer_start_transaction_fls(&trans, ip->hmp);
1508         error = hammer_init_cursor(&trans, &cursor, &ip->cache[0], ip);
1509         if (error)
1510                 goto done;
1511
1512         /*
1513          * Any directory records referencing this inode which are not in
1514          * our current flush group must adjust our nlink count for the
1515          * purposes of synchronization to disk.
1516          *
1517          * Records which are in our flush group can be unlinked from our
1518          * inode now, potentially allowing the inode to be physically
1519          * deleted.
1520          */
1521         nlinks = ip->ino_data.nlinks;
1522         next = TAILQ_FIRST(&ip->target_list);
1523         while ((depend = next) != NULL) {
1524                 next = TAILQ_NEXT(depend, target_entry);
1525                 if (depend->flush_state == HAMMER_FST_FLUSH &&
1526                     depend->flush_group == ip->hmp->flusher.act) {
1527                         /*
1528                          * If this is an ADD that was deleted by the frontend
1529                          * the frontend nlinks count will have already been
1530                          * decremented, but the backend is going to sync its
1531                          * directory entry and must account for it.  The
1532                          * record will be converted to a delete-on-disk when
1533                          * it gets synced.
1534                          *
1535                          * If the ADD was not deleted by the frontend we
1536                          * can remove the dependancy from our target_list.
1537                          */
1538                         if (depend->flags & HAMMER_RECF_DELETED_FE) {
1539                                 ++nlinks;
1540                         } else {
1541                                 TAILQ_REMOVE(&ip->target_list, depend,
1542                                              target_entry);
1543                                 depend->target_ip = NULL;
1544                         }
1545                 } else if ((depend->flags & HAMMER_RECF_DELETED_FE) == 0) {
1546                         /*
1547                          * Not part of our flush group
1548                          */
1549                         KKASSERT((depend->flags & HAMMER_RECF_DELETED_BE) == 0);
1550                         switch(depend->type) {
1551                         case HAMMER_MEM_RECORD_ADD:
1552                                 --nlinks;
1553                                 break;
1554                         case HAMMER_MEM_RECORD_DEL:
1555                                 ++nlinks;
1556                                 break;
1557                         default:
1558                                 break;
1559                         }
1560                 }
1561         }
1562
1563         /*
1564          * Set dirty if we had to modify the link count.
1565          */
1566         if (ip->sync_ino_data.nlinks != nlinks) {
1567                 KKASSERT((int64_t)nlinks >= 0);
1568                 ip->sync_ino_data.nlinks = nlinks;
1569                 ip->sync_flags |= HAMMER_INODE_DDIRTY;
1570         }
1571
1572         /*
1573          * If there is a trunction queued destroy any data past the (aligned)
1574          * truncation point.  Userland will have dealt with the buffer
1575          * containing the truncation point for us.
1576          *
1577          * We don't flush pending frontend data buffers until after we've
1578          * dealth with the truncation.
1579          *
1580          * Don't bother if the inode is or has been deleted.
1581          */
1582         if (ip->sync_flags & HAMMER_INODE_TRUNCATED) {
1583                 /*
1584                  * Interlock trunc_off.  The VOP front-end may continue to
1585                  * make adjustments to it while we are blocked.
1586                  */
1587                 off_t trunc_off;
1588                 off_t aligned_trunc_off;
1589
1590                 trunc_off = ip->sync_trunc_off;
1591                 aligned_trunc_off = (trunc_off + HAMMER_BUFMASK) &
1592                                     ~HAMMER_BUFMASK64;
1593
1594                 /*
1595                  * Delete any whole blocks on-media.  The front-end has
1596                  * already cleaned out any partial block and made it
1597                  * pending.  The front-end may have updated trunc_off
1598                  * while we were blocked so we only use sync_trunc_off.
1599                  */
1600                 error = hammer_ip_delete_range(&cursor, ip,
1601                                                 aligned_trunc_off,
1602                                                 0x7FFFFFFFFFFFFFFFLL, 1);
1603                 if (error)
1604                         Debugger("hammer_ip_delete_range errored");
1605
1606                 /*
1607                  * Clear the truncation flag on the backend after we have
1608                  * complete the deletions.  Backend data is now good again
1609                  * (including new records we are about to sync, below).
1610                  */
1611                 ip->sync_flags &= ~HAMMER_INODE_TRUNCATED;
1612                 ip->sync_trunc_off = 0x7FFFFFFFFFFFFFFFLL;
1613         } else {
1614                 error = 0;
1615         }
1616
1617         /*
1618          * Now sync related records.  These will typically be directory
1619          * entries or delete-on-disk records.
1620          *
1621          * Not all records will be flushed, but clear XDIRTY anyway.  We
1622          * will set it again in the frontend hammer_flush_inode_done() 
1623          * if records remain.
1624          */
1625         if (error == 0) {
1626                 tmp_error = RB_SCAN(hammer_rec_rb_tree, &ip->rec_tree, NULL,
1627                                     hammer_sync_record_callback, &cursor);
1628                 if (tmp_error < 0)
1629                         tmp_error = -error;
1630                 if (tmp_error)
1631                         error = tmp_error;
1632         }
1633
1634         /*
1635          * If we are deleting the inode the frontend had better not have
1636          * any active references on elements making up the inode.
1637          */
1638         if (error == 0 && ip->sync_ino_data.nlinks == 0 &&
1639                 RB_EMPTY(&ip->rec_tree)  &&
1640             (ip->sync_flags & HAMMER_INODE_DELETING) &&
1641             (ip->flags & HAMMER_INODE_DELETED) == 0) {
1642                 int count1 = 0;
1643
1644                 ip->flags |= HAMMER_INODE_DELETED;
1645                 error = hammer_ip_delete_range_all(&cursor, ip, &count1);
1646                 if (error == 0) {
1647                         ip->sync_flags &= ~HAMMER_INODE_DELETING;
1648                         ip->sync_flags &= ~HAMMER_INODE_TRUNCATED;
1649                         KKASSERT(RB_EMPTY(&ip->rec_tree));
1650
1651                         /*
1652                          * Set delete_tid in both the frontend and backend
1653                          * copy of the inode record.  The DELETED flag handles
1654                          * this, do not set RDIRTY.
1655                          */
1656                         ip->ino_leaf.base.delete_tid = trans.tid;
1657                         ip->sync_ino_leaf.base.delete_tid = trans.tid;
1658
1659                         /*
1660                          * Adjust the inode count in the volume header
1661                          */
1662                         if (ip->flags & HAMMER_INODE_ONDISK) {
1663                                 hammer_modify_volume_field(&trans,
1664                                                            trans.rootvol,
1665                                                            vol0_stat_inodes);
1666                                 --ip->hmp->rootvol->ondisk->vol0_stat_inodes;
1667                                 hammer_modify_volume_done(trans.rootvol);
1668                         }
1669                 } else {
1670                         ip->flags &= ~HAMMER_INODE_DELETED;
1671                         Debugger("hammer_ip_delete_range_all errored");
1672                 }
1673         }
1674
1675         ip->sync_flags &= ~HAMMER_INODE_BUFS;
1676
1677         if (error)
1678                 Debugger("RB_SCAN errored");
1679
1680         /*
1681          * Now update the inode's on-disk inode-data and/or on-disk record.
1682          * DELETED and ONDISK are managed only in ip->flags.
1683          */
1684         switch(ip->flags & (HAMMER_INODE_DELETED | HAMMER_INODE_ONDISK)) {
1685         case HAMMER_INODE_DELETED|HAMMER_INODE_ONDISK:
1686                 /*
1687                  * If deleted and on-disk, don't set any additional flags.
1688                  * the delete flag takes care of things.
1689                  *
1690                  * Clear flags which may have been set by the frontend.
1691                  */
1692                 ip->sync_flags &= ~(HAMMER_INODE_DDIRTY|
1693                                     HAMMER_INODE_XDIRTY|HAMMER_INODE_ITIMES|
1694                                     HAMMER_INODE_DELETING);
1695                 break;
1696         case HAMMER_INODE_DELETED:
1697                 /*
1698                  * Take care of the case where a deleted inode was never
1699                  * flushed to the disk in the first place.
1700                  *
1701                  * Clear flags which may have been set by the frontend.
1702                  */
1703                 ip->sync_flags &= ~(HAMMER_INODE_DDIRTY|
1704                                     HAMMER_INODE_XDIRTY|HAMMER_INODE_ITIMES|
1705                                     HAMMER_INODE_DELETING);
1706                 while (RB_ROOT(&ip->rec_tree)) {
1707                         hammer_record_t record = RB_ROOT(&ip->rec_tree);
1708                         hammer_ref(&record->lock);
1709                         KKASSERT(record->lock.refs == 1);
1710                         record->flags |= HAMMER_RECF_DELETED_FE;
1711                         record->flags |= HAMMER_RECF_DELETED_BE;
1712                         hammer_rel_mem_record(record);
1713                 }
1714                 break;
1715         case HAMMER_INODE_ONDISK:
1716                 /*
1717                  * If already on-disk, do not set any additional flags.
1718                  */
1719                 break;
1720         default:
1721                 /*
1722                  * If not on-disk and not deleted, set both dirty flags
1723                  * to force an initial record to be written.  Also set
1724                  * the create_tid for the inode.
1725                  *
1726                  * Set create_tid in both the frontend and backend
1727                  * copy of the inode record.
1728                  */
1729                 ip->ino_leaf.base.create_tid = trans.tid;
1730                 ip->sync_ino_leaf.base.create_tid = trans.tid;
1731                 ip->sync_flags |= HAMMER_INODE_DDIRTY;
1732                 break;
1733         }
1734
1735         /*
1736          * If RDIRTY or DDIRTY is set, write out a new record.  If the inode
1737          * is already on-disk the old record is marked as deleted.
1738          *
1739          * If DELETED is set hammer_update_inode() will delete the existing
1740          * record without writing out a new one.
1741          *
1742          * If *ONLY* the ITIMES flag is set we can update the record in-place.
1743          */
1744         if (ip->flags & HAMMER_INODE_DELETED) {
1745                 error = hammer_update_inode(&cursor, ip);
1746         } else 
1747         if ((ip->sync_flags & (HAMMER_INODE_DDIRTY | HAMMER_INODE_ITIMES)) ==
1748             HAMMER_INODE_ITIMES) {
1749                 error = hammer_update_itimes(&cursor, ip);
1750         } else
1751         if (ip->sync_flags & (HAMMER_INODE_DDIRTY | HAMMER_INODE_ITIMES)) {
1752                 error = hammer_update_inode(&cursor, ip);
1753         }
1754         if (error)
1755                 Debugger("hammer_update_itimes/inode errored");
1756 done:
1757         /*
1758          * Save the TID we used to sync the inode with to make sure we
1759          * do not improperly reuse it.
1760          */
1761         hammer_done_cursor(&cursor);
1762         hammer_done_transaction(&trans);
1763         return(error);
1764 }
1765
1766 /*
1767  * This routine is called when the OS is no longer actively referencing
1768  * the inode (but might still be keeping it cached), or when releasing
1769  * the last reference to an inode.
1770  *
1771  * At this point if the inode's nlinks count is zero we want to destroy
1772  * it, which may mean destroying it on-media too.
1773  */
1774 void
1775 hammer_inode_unloadable_check(hammer_inode_t ip, int getvp)
1776 {
1777         struct vnode *vp;
1778
1779         /*
1780          * Set the DELETING flag when the link count drops to 0 and the
1781          * OS no longer has any opens on the inode.
1782          *
1783          * The backend will clear DELETING (a mod flag) and set DELETED
1784          * (a state flag) when it is actually able to perform the
1785          * operation.
1786          */
1787         if (ip->ino_data.nlinks == 0 &&
1788             (ip->flags & (HAMMER_INODE_DELETING|HAMMER_INODE_DELETED)) == 0) {
1789                 ip->flags |= HAMMER_INODE_DELETING;
1790                 ip->flags |= HAMMER_INODE_TRUNCATED;
1791                 ip->trunc_off = 0;
1792                 vp = NULL;
1793                 if (getvp) {
1794                         if (hammer_get_vnode(ip, &vp) != 0)
1795                                 return;
1796                 }
1797
1798                 /*
1799                  * Final cleanup
1800                  */
1801                 if (ip->vp) {
1802                         vtruncbuf(ip->vp, 0, HAMMER_BUFSIZE);
1803                         vnode_pager_setsize(ip->vp, 0);
1804                 }
1805                 if (getvp) {
1806                         vput(vp);
1807                 }
1808         }
1809 }
1810
1811 /*
1812  * Re-test an inode when a dependancy had gone away to see if we
1813  * can chain flush it.
1814  */
1815 void
1816 hammer_test_inode(hammer_inode_t ip)
1817 {
1818         if (ip->flags & HAMMER_INODE_REFLUSH) {
1819                 ip->flags &= ~HAMMER_INODE_REFLUSH;
1820                 hammer_ref(&ip->lock);
1821                 if (ip->flags & HAMMER_INODE_RESIGNAL) {
1822                         ip->flags &= ~HAMMER_INODE_RESIGNAL;
1823                         hammer_flush_inode(ip, HAMMER_FLUSH_SIGNAL);
1824                 } else {
1825                         hammer_flush_inode(ip, 0);
1826                 }
1827                 hammer_rel_inode(ip, 0);
1828         }
1829 }
1830
1831 /*
1832  * We need to slow down user processes if we get too large a backlog of
1833  * inodes in the flusher.  Even though the frontend can theoretically
1834  * get way, way ahead of the flusher, if we let it do that the flusher
1835  * will have no buffer cache locality of reference and will have to re-read
1836  * everything a second time, causing performance to drop precipitously.
1837  *
1838  * Reclaims are especially senssitive to this effect because the kernel has
1839  * already abandoned the related vnode.
1840  */
1841
1842 void
1843 hammer_inode_waitreclaims(hammer_inode_t ip)
1844 {
1845         hammer_mount_t hmp = ip->hmp;
1846         int delay;
1847         int factor;
1848         int flags = (ip->flags | ip->sync_flags);
1849
1850         if ((flags & HAMMER_INODE_MODMASK) == 0)
1851                 return;
1852         if ((flags & (HAMMER_INODE_MODMASK & ~HAMMER_INODE_MODEASY)) == 0) {
1853                 factor = 2;
1854         } else {
1855                 factor = 1;
1856         }
1857
1858         while (hmp->inode_reclaims > HAMMER_RECLAIM_MIN) {
1859                 if (hmp->inode_reclaims < HAMMER_RECLAIM_MID) {
1860                         hammer_flusher_async(hmp);
1861                         break;
1862                 }
1863                 if (hmp->inode_reclaims < HAMMER_RECLAIM_MAX) {
1864                         delay = (hmp->inode_reclaims - HAMMER_RECLAIM_MID) *
1865                                 hz / (HAMMER_RECLAIM_MAX - HAMMER_RECLAIM_MID);
1866                         delay = delay / factor;
1867                         if (delay == 0)
1868                                 delay = 1;
1869                         hammer_flusher_async(hmp);
1870                         tsleep(&delay, 0, "hmitik", delay);
1871                         break;
1872                 }
1873                 hmp->flags |= HAMMER_MOUNT_WAITIMAX;
1874                 hammer_flusher_async(hmp);
1875                 tsleep(&hmp->inode_reclaims, 0, "hmimax", hz / 10);
1876         }
1877 }
1878
1879 void
1880 hammer_inode_wakereclaims(hammer_mount_t hmp)
1881 {
1882         if ((hmp->flags & HAMMER_MOUNT_WAITIMAX) &&
1883             hmp->inode_reclaims < HAMMER_RECLAIM_MAX) {
1884                 hmp->flags &= ~HAMMER_MOUNT_WAITIMAX;
1885                 wakeup(&hmp->inode_reclaims);
1886         }
1887 }
1888