HAMMER 39/Many: Parallel operations optimizations
[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.43 2008/04/29 01:10: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         if (hmp->ronly)
233                 ip->flags |= HAMMER_INODE_RO;
234         ip->trunc_off = 0x7FFFFFFFFFFFFFFFLL;
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_objid(trans, dip);
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         ip->trunc_off = 0x7FFFFFFFFFFFFFFFLL;
334         RB_INIT(&ip->rec_tree);
335         TAILQ_INIT(&ip->bio_list);
336         TAILQ_INIT(&ip->bio_alt_list);
337         TAILQ_INIT(&ip->depend_list);
338
339         ip->ino_rec.ino_atime = trans->time;
340         ip->ino_rec.ino_mtime = trans->time;
341         ip->ino_rec.ino_size = 0;
342         ip->ino_rec.ino_nlinks = 0;
343         /* XXX */
344         ip->ino_rec.base.base.btype = HAMMER_BTREE_TYPE_RECORD;
345         ip->ino_rec.base.base.obj_id = ip->obj_id;
346         ip->ino_rec.base.base.key = 0;
347         ip->ino_rec.base.base.create_tid = 0;
348         ip->ino_rec.base.base.delete_tid = 0;
349         ip->ino_rec.base.base.rec_type = HAMMER_RECTYPE_INODE;
350         ip->ino_rec.base.base.obj_type = hammer_get_obj_type(vap->va_type);
351
352         ip->ino_data.version = HAMMER_INODE_DATA_VERSION;
353         ip->ino_data.mode = vap->va_mode;
354         ip->ino_data.ctime = trans->time;
355         ip->ino_data.parent_obj_id = (dip) ? dip->ino_rec.base.base.obj_id : 0;
356
357         switch(ip->ino_rec.base.base.obj_type) {
358         case HAMMER_OBJTYPE_CDEV:
359         case HAMMER_OBJTYPE_BDEV:
360                 ip->ino_data.rmajor = vap->va_rmajor;
361                 ip->ino_data.rminor = vap->va_rminor;
362                 break;
363         default:
364                 break;
365         }
366
367         /*
368          * Calculate default uid/gid and overwrite with information from
369          * the vap.
370          */
371         xuid = hammer_to_unix_xid(&dip->ino_data.uid);
372         ip->ino_data.gid = dip->ino_data.gid;
373         xuid = vop_helper_create_uid(hmp->mp, dip->ino_data.mode, xuid, cred,
374                                      &vap->va_mode);
375         ip->ino_data.mode = vap->va_mode;
376
377         if (vap->va_vaflags & VA_UID_UUID_VALID)
378                 ip->ino_data.uid = vap->va_uid_uuid;
379         else if (vap->va_uid != (uid_t)VNOVAL)
380                 hammer_guid_to_uuid(&ip->ino_data.uid, xuid);
381         if (vap->va_vaflags & VA_GID_UUID_VALID)
382                 ip->ino_data.gid = vap->va_gid_uuid;
383         else if (vap->va_gid != (gid_t)VNOVAL)
384                 hammer_guid_to_uuid(&ip->ino_data.gid, vap->va_gid);
385
386         hammer_ref(&ip->lock);
387         if (RB_INSERT(hammer_ino_rb_tree, &hmp->rb_inos_root, ip)) {
388                 hammer_unref(&ip->lock);
389                 panic("hammer_create_inode: duplicate obj_id %llx", ip->obj_id);
390         }
391         *ipp = ip;
392         return(0);
393 }
394
395 /*
396  * Finalize a newly created inode, allowing it to be synchronized to the
397  * media.  If an error occured make sure the inode has been cleaned up and
398  * will not be synchronized to the media.
399  */
400 void
401 hammer_finalize_inode(hammer_transaction_t trans, hammer_inode_t ip, int error)
402 {
403         if (error) {
404                 ip->flags &= ~HAMMER_INODE_MODMASK;
405
406                 KASSERT(ip->lock.refs == 1,
407                         ("hammer_unload_inode: %d refs\n", ip->lock.refs));
408                 KKASSERT(ip->vp == NULL);
409                 KKASSERT(ip->flush_state == HAMMER_FST_IDLE);
410                 KKASSERT(ip->cursor_ip_refs == 0);
411                 KKASSERT((ip->flags & HAMMER_INODE_MODMASK) == 0);
412
413                 KKASSERT(RB_EMPTY(&ip->rec_tree));
414                 KKASSERT(TAILQ_EMPTY(&ip->bio_list));
415                 KKASSERT(TAILQ_EMPTY(&ip->bio_alt_list));
416         }
417         ip->flags &= ~HAMMER_INODE_NEW;
418 }
419
420 /*
421  * Called by hammer_sync_inode().
422  */
423 static int
424 hammer_update_inode(hammer_transaction_t trans, hammer_inode_t ip)
425 {
426         struct hammer_cursor cursor;
427         hammer_record_t record;
428         int error;
429
430         /*
431          * Locate the record on-disk and mark it as deleted.  Both the B-Tree
432          * node and the record must be marked deleted.  The record may or
433          * may not be physically deleted, depending on the retention policy.
434          *
435          * If the inode has already been deleted on-disk we have nothing
436          * to do.
437          *
438          * XXX Update the inode record and data in-place if the retention
439          * policy allows it.
440          */
441 retry:
442         error = 0;
443
444         if ((ip->flags & (HAMMER_INODE_ONDISK|HAMMER_INODE_DELONDISK)) ==
445             HAMMER_INODE_ONDISK) {
446                 hammer_init_cursor(trans, &cursor, &ip->cache[0]);
447                 cursor.key_beg.obj_id = ip->obj_id;
448                 cursor.key_beg.key = 0;
449                 cursor.key_beg.create_tid = 0;
450                 cursor.key_beg.delete_tid = 0;
451                 cursor.key_beg.rec_type = HAMMER_RECTYPE_INODE;
452                 cursor.key_beg.obj_type = 0;
453                 cursor.asof = ip->obj_asof;
454                 cursor.flags |= HAMMER_CURSOR_GET_RECORD | HAMMER_CURSOR_ASOF;
455                 cursor.flags |= HAMMER_CURSOR_BACKEND;
456
457                 error = hammer_btree_lookup(&cursor);
458                 if (error) {
459                         kprintf("error %d\n", error);
460                         Debugger("hammer_update_inode");
461                 }
462
463
464                 if (error == 0) {
465                         error = hammer_ip_delete_record(&cursor, trans->tid);
466                         if (error && error != EDEADLK) {
467                                 kprintf("error %d\n", error);
468                                 Debugger("hammer_update_inode2");
469                         }
470                         if (error == 0)
471                                 ip->flags |= HAMMER_INODE_DELONDISK;
472                         hammer_cache_node(cursor.node, &ip->cache[0]);
473                 }
474                 hammer_done_cursor(&cursor);
475                 if (error == EDEADLK)
476                         goto retry;
477         }
478
479         /*
480          * Write out a new record if the in-memory inode is not marked
481          * as having been deleted.  Update our inode statistics if this
482          * is the first application of the inode on-disk.
483          *
484          * If the inode has been deleted permanently, HAMMER_INODE_DELONDISK
485          * will remain set and prevent further updates.
486          */
487         if (error == 0 && (ip->flags & HAMMER_INODE_DELETED) == 0) { 
488                 record = hammer_alloc_mem_record(ip);
489                 record->state = HAMMER_FST_FLUSH;
490                 record->rec.inode = ip->sync_ino_rec;
491                 record->rec.inode.base.base.create_tid = trans->tid;
492                 record->rec.inode.base.data_len = sizeof(ip->sync_ino_data);
493                 record->data = (void *)&ip->sync_ino_data;
494                 record->flags |= HAMMER_RECF_INTERLOCK_BE;
495                 error = hammer_ip_sync_record(trans, record);
496                 if (error) {
497                         kprintf("error %d\n", error);
498                         Debugger("hammer_update_inode3");
499                 }
500
501                 /*
502                  * The record isn't managed by the inode's record tree,
503                  * destroy it whether we succeed or fail.
504                  */
505                 record->flags &= ~HAMMER_RECF_INTERLOCK_BE;
506                 record->flags |= HAMMER_RECF_DELETED_FE;
507                 record->state = HAMMER_FST_IDLE;
508                 KKASSERT(TAILQ_FIRST(&record->depend_list) == NULL);
509                 hammer_rel_mem_record(record);
510
511                 if (error == 0) {
512                         ip->sync_flags &= ~(HAMMER_INODE_RDIRTY |
513                                             HAMMER_INODE_DDIRTY |
514                                             HAMMER_INODE_ITIMES);
515                         ip->flags &= ~HAMMER_INODE_DELONDISK;
516                         if ((ip->flags & HAMMER_INODE_ONDISK) == 0) {
517                                 hammer_modify_volume(trans, trans->rootvol,
518                                                      NULL, 0);
519                                 ++ip->hmp->rootvol->ondisk->vol0_stat_inodes;
520                                 hammer_modify_volume_done(trans->rootvol);
521                                 ip->flags |= HAMMER_INODE_ONDISK;
522                         }
523                 }
524         }
525         if (error == 0 && (ip->flags & HAMMER_INODE_DELETED)) { 
526                 /*
527                  * Clean out any left-over flags if the inode has been
528                  * destroyed.
529                  */
530                 ip->sync_flags &= ~(HAMMER_INODE_RDIRTY |
531                                     HAMMER_INODE_DDIRTY |
532                                     HAMMER_INODE_ITIMES);
533         }
534         return(error);
535 }
536
537 /*
538  * Update only the itimes fields.  This is done no-historically.  The
539  * record is updated in-place on the disk.
540  */
541 static int
542 hammer_update_itimes(hammer_transaction_t trans, hammer_inode_t ip)
543 {
544         struct hammer_cursor cursor;
545         struct hammer_inode_record *rec;
546         int error;
547
548 retry:
549         error = 0;
550         if ((ip->flags & (HAMMER_INODE_ONDISK|HAMMER_INODE_DELONDISK)) ==
551             HAMMER_INODE_ONDISK) {
552                 hammer_init_cursor(trans, &cursor, &ip->cache[0]);
553                 cursor.key_beg.obj_id = ip->obj_id;
554                 cursor.key_beg.key = 0;
555                 cursor.key_beg.create_tid = 0;
556                 cursor.key_beg.delete_tid = 0;
557                 cursor.key_beg.rec_type = HAMMER_RECTYPE_INODE;
558                 cursor.key_beg.obj_type = 0;
559                 cursor.asof = ip->obj_asof;
560                 cursor.flags |= HAMMER_CURSOR_GET_RECORD | HAMMER_CURSOR_ASOF;
561                 cursor.flags |= HAMMER_CURSOR_BACKEND;
562
563                 error = hammer_btree_lookup(&cursor);
564                 if (error) {
565                         kprintf("error %d\n", error);
566                         Debugger("hammer_update_itimes1");
567                 }
568                 if (error == 0) {
569                         /*
570                          * Do not generate UNDO records for atime/mtime
571                          * updates.
572                          */
573                         rec = &cursor.record->inode;
574                         hammer_modify_buffer(cursor.trans, cursor.record_buffer,
575                                              NULL, 0);
576                         rec->ino_atime = ip->sync_ino_rec.ino_atime;
577                         rec->ino_mtime = ip->sync_ino_rec.ino_mtime;
578                         hammer_modify_buffer_done(cursor.record_buffer);
579                         ip->sync_flags &= ~HAMMER_INODE_ITIMES;
580                         /* XXX recalculate crc */
581                         hammer_cache_node(cursor.node, &ip->cache[0]);
582                 }
583                 hammer_done_cursor(&cursor);
584                 if (error == EDEADLK)
585                         goto retry;
586         }
587         return(error);
588 }
589
590 /*
591  * Release a reference on an inode.  If asked to flush the last release
592  * will flush the inode.
593  *
594  * On the last reference we queue the inode to the flusher for its final
595  * disposition.
596  */
597 void
598 hammer_rel_inode(struct hammer_inode *ip, int flush)
599 {
600         /*
601          * Handle disposition when dropping the last ref.
602          */
603         while (ip->lock.refs == 1) {
604                 if ((ip->flags & HAMMER_INODE_MODMASK) == 0) {
605                         hammer_unload_inode(ip);
606                         return;
607                 }
608
609                 /*
610                  * Hand the inode over to the flusher, which will
611                  * add another ref to it.
612                  */
613                 if (++ip->hmp->reclaim_count > 256) {
614                         ip->hmp->reclaim_count = 0;
615                         hammer_flush_inode(ip, HAMMER_FLUSH_FORCE |
616                                                 HAMMER_FLUSH_SIGNAL);
617                 } else {
618                         hammer_flush_inode(ip, HAMMER_FLUSH_FORCE);
619                 }
620                 /* retry */
621         }
622
623         /*
624          * The inode still has multiple refs, drop one ref.  If a flush was
625          * requested make sure the flusher sees it.  New inodes which have
626          * not been finalized cannot be flushed.
627          */
628         if (flush && ip->flush_state == HAMMER_FST_IDLE && 
629             (ip->flags & HAMMER_INODE_NEW) == 0) {
630                 hammer_flush_inode(ip, HAMMER_FLUSH_RELEASE);
631         } else {
632                 hammer_unref(&ip->lock);
633         }
634 }
635
636 /*
637  * Unload and destroy the specified inode.  Must be called with one remaining
638  * reference.  The reference is disposed of.
639  *
640  * This can only be called in the context of the flusher.
641  */
642 static int
643 hammer_unload_inode(struct hammer_inode *ip)
644 {
645         KASSERT(ip->lock.refs == 1,
646                 ("hammer_unload_inode: %d refs\n", ip->lock.refs));
647         KKASSERT(ip->vp == NULL);
648         KKASSERT(ip->flush_state == HAMMER_FST_IDLE);
649         KKASSERT(ip->cursor_ip_refs == 0);
650         KKASSERT((ip->flags & HAMMER_INODE_MODMASK) == 0);
651
652         KKASSERT(RB_EMPTY(&ip->rec_tree));
653         KKASSERT(TAILQ_EMPTY(&ip->bio_list));
654         KKASSERT(TAILQ_EMPTY(&ip->bio_alt_list));
655
656         RB_REMOVE(hammer_ino_rb_tree, &ip->hmp->rb_inos_root, ip);
657
658         hammer_uncache_node(&ip->cache[0]);
659         hammer_uncache_node(&ip->cache[1]);
660         if (ip->objid_cache)
661                 hammer_clear_objid(ip);
662         --hammer_count_inodes;
663         kfree(ip, M_HAMMER);
664
665         return(0);
666 }
667
668 /*
669  * A transaction has modified an inode, requiring updates as specified by
670  * the passed flags.
671  *
672  * HAMMER_INODE_RDIRTY: Inode record has been updated
673  * HAMMER_INODE_DDIRTY: Inode data has been updated
674  * HAMMER_INODE_XDIRTY: Dirty frontend buffer cache buffer strategized
675  * HAMMER_INODE_DELETED: Inode record/data must be deleted
676  * HAMMER_INODE_ITIMES: mtime/atime has been updated
677  */
678 void
679 hammer_modify_inode(hammer_transaction_t trans, hammer_inode_t ip, int flags)
680 {
681         KKASSERT ((ip->flags & HAMMER_INODE_RO) == 0 ||
682                   (flags & (HAMMER_INODE_RDIRTY|HAMMER_INODE_DDIRTY|
683                    HAMMER_INODE_XDIRTY|
684                    HAMMER_INODE_DELETED|HAMMER_INODE_ITIMES)) == 0);
685
686         ip->flags |= flags;
687 }
688
689 /*
690  * Flush an inode.  If the inode is already being flushed wait for
691  * it to complete, then flush it again.  The interlock is against
692  * front-end transactions, the backend flusher does not hold the lock.
693  *
694  * The flusher must distinguish between the records that are part of the
695  * flush and any new records created in parallel with the flush.  The
696  * inode data and truncation fields are also copied.  BIOs are a bit more
697  * troublesome because some dirty buffers may not have been queued yet.
698  */
699 void
700 hammer_flush_inode(hammer_inode_t ip, int flags)
701 {
702         KKASSERT((ip->flags & HAMMER_INODE_NEW) == 0);
703         if (ip->flush_state != HAMMER_FST_IDLE &&
704             (ip->flags & HAMMER_INODE_MODMASK)) {
705                 ip->flags |= HAMMER_INODE_REFLUSH;
706                 if (flags & HAMMER_FLUSH_RELEASE) {
707                         hammer_unref(&ip->lock);
708                         KKASSERT(ip->lock.refs > 0);
709                 }
710                 return;
711         }
712         if (ip->flush_state == HAMMER_FST_IDLE) {
713                 if ((ip->flags & HAMMER_INODE_MODMASK) ||
714                     (flags & HAMMER_FLUSH_FORCE)) {
715                         /*
716                          * Add a reference to represent the inode being queued
717                          * to the flusher.  If the caller wants us to 
718                          * release a reference the two cancel each other out.
719                          */
720                         if ((flags & HAMMER_FLUSH_RELEASE) == 0)
721                                 hammer_ref(&ip->lock);
722
723                         hammer_flush_inode_copysync(ip);
724                         /*
725                          * Move the inode to the flush list and add a ref to
726                          * it representing it on the list.
727                          */
728                         TAILQ_INSERT_TAIL(&ip->hmp->flush_list, ip, flush_entry);
729                         if (flags & HAMMER_FLUSH_SIGNAL)
730                                 hammer_flusher_async(ip->hmp);
731                 }
732         }
733 }
734
735 /*
736  * Helper routine to copy the frontend synchronization state to the backend.
737  * This routine may be called by either the frontend or the backend.
738  */
739 static void
740 hammer_flush_inode_copysync(hammer_inode_t ip)
741 {
742         int error;
743         int count;
744
745         /*
746          * Prevent anyone else from trying to do the same thing.
747          */
748         ip->flush_state = HAMMER_FST_SETUP;
749
750         /*
751          * Sync the buffer cache.  This will queue the BIOs.  If called
752          * from the context of the flusher the BIO's are thrown into bio_list
753          * regardless of ip->flush_state.
754          */
755         if (ip->vp != NULL)
756                 error = vfsync(ip->vp, MNT_NOWAIT, 1, NULL, NULL);
757         else
758                 error = 0;
759
760         /*
761          * This freezes strategy writes, any further BIOs will be
762          * queued to alt_bio (unless we are 
763          */
764         ip->flush_state = HAMMER_FST_FLUSH;
765
766         /*
767          * Snapshot the state of the inode for the backend flusher.
768          *
769          * The truncation must be retained in the frontend until after
770          * we've actually performed the record deletion.
771          */
772         ip->sync_flags = (ip->flags & HAMMER_INODE_MODMASK);
773         ip->sync_trunc_off = ip->trunc_off;
774         ip->sync_ino_rec = ip->ino_rec;
775         ip->sync_ino_data = ip->ino_data;
776         ip->flags &= ~HAMMER_INODE_MODMASK |
777                      HAMMER_INODE_TRUNCATED | HAMMER_INODE_BUFS;
778
779         /*
780          * Fix up the dirty buffer status.
781          */
782         if (ip->vp == NULL || RB_ROOT(&ip->vp->v_rbdirty_tree) == NULL)
783                 ip->flags &= ~HAMMER_INODE_BUFS;
784         if (TAILQ_FIRST(&ip->bio_list))
785                 ip->sync_flags |= HAMMER_INODE_BUFS;
786         else
787                 ip->sync_flags &= ~HAMMER_INODE_BUFS;
788
789         /*
790          * Set the state for the inode's in-memory records.  If some records
791          * could not be marked for backend flush (i.e. deleted records),
792          * re-set the XDIRTY flag.
793          */
794         count = RB_SCAN(hammer_rec_rb_tree, &ip->rec_tree, NULL,
795                         hammer_mark_record_callback, NULL);
796         if (count)
797                 ip->flags |= HAMMER_INODE_XDIRTY;
798 }
799
800 /*
801  * Mark records for backend flush, accumulate a count of the number of
802  * records which could not be marked.  Records marked for deletion
803  * by the frontend never make it to the media.  It is possible for
804  * a record queued to the backend to wind up with FE set after the
805  * fact, as long as BE has not yet been set.  The backend deals with
806  * this race by syncing the record as if FE had not been set, and
807  * then converting the record to a delete-on-disk record.
808  */
809 static int
810 hammer_mark_record_callback(hammer_record_t rec, void *data)
811 {
812         if (rec->state == HAMMER_FST_FLUSH) {
813                 return(0);
814         } else if ((rec->flags & HAMMER_RECF_DELETED_FE) == 0) {
815                 rec->state = HAMMER_FST_FLUSH;
816                 hammer_ref(&rec->lock);
817                 return(0);
818         } else {
819                 return(1);
820         }
821 }
822
823
824
825 /*
826  * Wait for a previously queued flush to complete
827  */
828 void
829 hammer_wait_inode(hammer_inode_t ip)
830 {
831         while (ip->flush_state == HAMMER_FST_FLUSH) {
832                 ip->flags |= HAMMER_INODE_FLUSHW;
833                 tsleep(&ip->flags, 0, "hmrwin", 0);
834         }
835 }
836
837 /*
838  * Called by the backend code when a flush has been completed.
839  * The inode has already been removed from the flush list.
840  *
841  * A pipelined flush can occur, in which case we must re-enter the
842  * inode on the list and re-copy its fields.
843  */
844 void
845 hammer_flush_inode_done(hammer_inode_t ip)
846 {
847         struct bio *bio;
848
849         KKASSERT(ip->flush_state == HAMMER_FST_FLUSH);
850
851         if (ip->sync_flags)
852                 kprintf("ip %p leftover sync_flags %08x\n", ip, ip->sync_flags);
853         ip->flags |= ip->sync_flags;
854         ip->flush_state = HAMMER_FST_IDLE;
855
856         /*
857          * Reflush any BIOs that wound up in the alt list.  Our inode will
858          * also wind up at the end of the flusher's list.
859          */
860         while ((bio = TAILQ_FIRST(&ip->bio_alt_list)) != NULL) {
861                 TAILQ_REMOVE(&ip->bio_alt_list, bio, bio_act);
862                 TAILQ_INSERT_TAIL(&ip->bio_list, bio, bio_act);
863                 ip->flags |= HAMMER_INODE_XDIRTY;
864                 ip->flags |= HAMMER_INODE_REFLUSH;
865                 kprintf("rebio %p ip %p @%016llx,%d\n", bio, ip, bio->bio_offset, bio->bio_buf->b_bufsize);
866         }
867
868         /*
869          * If the frontend made more changes and requested another flush,
870          * do it. 
871          */
872         if (ip->flags & HAMMER_INODE_REFLUSH) {
873                 ip->flags &= ~HAMMER_INODE_REFLUSH;
874                 hammer_flush_inode(ip, 0);
875                 if (ip->flush_state == HAMMER_FST_IDLE) {
876                         if (ip->flags & HAMMER_INODE_FLUSHW) {
877                                 ip->flags &= ~HAMMER_INODE_FLUSHW;
878                                 wakeup(&ip->flags);
879                         }
880                 }
881         } else {
882                 if (ip->flags & HAMMER_INODE_FLUSHW) {
883                         ip->flags &= ~HAMMER_INODE_FLUSHW;
884                         wakeup(&ip->flags);
885                 }
886         }
887         hammer_rel_inode(ip, 0);
888 }
889
890 /*
891  * Called from hammer_sync_inode() to synchronize in-memory records
892  * to the media.
893  */
894 static int
895 hammer_sync_record_callback(hammer_record_t record, void *data)
896 {
897         hammer_transaction_t trans = data;
898         int error;
899
900         /*
901          * Skip records that do not belong to the current flush.  Records
902          * belonging to the flush will have been referenced for us.
903          */
904         if (record->state != HAMMER_FST_FLUSH)
905                 return(0);
906
907         /*
908          * Interlock the record using the BE flag.  Once BE is set the
909          * frontend cannot change the state of FE.
910          *
911          * NOTE: If FE is set prior to us setting BE we still sync the
912          * record out, but the flush completion code converts it to 
913          * a delete-on-disk record instead of destroying it.
914          */
915         hammer_lock_ex(&record->lock);
916         if (record->flags & HAMMER_RECF_INTERLOCK_BE) {
917                 hammer_unlock(&record->lock);
918                 return(0);
919         }
920         record->flags |= HAMMER_RECF_INTERLOCK_BE;
921
922         /*
923          * If DELETED_FE is set we may have already sent dependant pieces
924          * to the disk and we must flush the record as if it hadn't been
925          * deleted.  This creates a bit of a mess because we have to
926          * have ip_sync_record convert the record to DELETE_ONDISK before
927          * it inserts the B-Tree record.  Otherwise the media sync might
928          * be visible to the frontend.
929          */
930         if (record->flags & HAMMER_RECF_DELETED_FE)
931                 record->flags |= HAMMER_RECF_CONVERT_DELETE_ONDISK;
932
933         /*
934          * Assign the create_tid for new records.  Deletions already
935          * have the record's entire key properly set up.
936          */
937         if ((record->flags & HAMMER_RECF_DELETE_ONDISK) == 0)
938                 record->rec.inode.base.base.create_tid = trans->tid;
939         error = hammer_ip_sync_record(trans, record);
940
941         if (error) {
942                 error = -error;
943                 if (error != -ENOSPC) {
944                         kprintf("hammer_sync_record_callback: sync failed rec "
945                                 "%p, error %d\n", record, error);
946                         Debugger("sync failed rec");
947                 }
948         }
949         hammer_flush_record_done(record, error);
950         return(error);
951 }
952
953 /*
954  * XXX error handling
955  */
956 int
957 hammer_sync_inode(hammer_inode_t ip, int handle_delete)
958 {
959         struct hammer_transaction trans;
960         struct bio *bio;
961         hammer_depend_t depend;
962         int error, tmp_error;
963
964         if ((ip->sync_flags & HAMMER_INODE_MODMASK) == 0 &&
965             handle_delete == 0) {
966                 return(0);
967         }
968
969         hammer_start_transaction_fls(&trans, ip->hmp);
970
971         /*
972          * Any (directory) records this inode depends on must also be
973          * synchronized.  The directory itself only needs to be flushed
974          * if its inode is not already on-disk.
975          */
976         while ((depend = TAILQ_FIRST(&ip->depend_list)) != NULL) {
977                 hammer_record_t record;
978
979                 record = depend->record;
980                 TAILQ_REMOVE(&depend->record->depend_list, depend, rec_entry);
981                 TAILQ_REMOVE(&ip->depend_list, depend, ip_entry);
982                 --ip->depend_count;
983                 if (record->state != HAMMER_FST_FLUSH) {
984                         record->state = HAMMER_FST_FLUSH;
985                         /* add ref (steal ref from dependancy) */
986                 } else {
987                         /* remove ref related to dependancy */
988                         /* record still has at least one ref from state */
989                         hammer_unref(&record->lock);
990                         KKASSERT(record->lock.refs > 0);
991                 }
992                 if (record->ip->flags & HAMMER_INODE_ONDISK) {
993                         kprintf("I");
994                         hammer_sync_record_callback(record, &trans);
995                 } else {
996                         kprintf("J");
997                         KKASSERT((record->ip->flags & HAMMER_INODE_NEW) == 0);
998                         hammer_flush_inode(record->ip, 0);
999                 }
1000                 hammer_unref(&ip->lock);
1001                 KKASSERT(ip->lock.refs > 0);
1002                 kfree(depend, M_HAMMER);
1003         }
1004
1005
1006         /*
1007          * Sync inode deletions and truncations.
1008          */
1009         if (ip->sync_ino_rec.ino_nlinks == 0 && handle_delete && 
1010             (ip->flags & HAMMER_INODE_GONE) == 0) {
1011                 /*
1012                  * Handle the case where the inode has been completely deleted
1013                  * and is no longer referenceable from the filesystem
1014                  * namespace.
1015                  *
1016                  * NOTE: We do not set the RDIRTY flag when updating the
1017                  * delete_tid, setting HAMMER_INODE_DELETED takes care of it.
1018                  */
1019
1020                 ip->flags |= HAMMER_INODE_GONE | HAMMER_INODE_DELETED;
1021                 ip->flags &= ~HAMMER_INODE_TRUNCATED;
1022                 ip->sync_flags &= ~HAMMER_INODE_TRUNCATED;
1023                 if (ip->vp)
1024                         vtruncbuf(ip->vp, 0, HAMMER_BUFSIZE);
1025                 error = hammer_ip_delete_range_all(&trans, ip);
1026                 if (error)
1027                         Debugger("hammer_ip_delete_range_all errored");
1028
1029                 /*
1030                  * Sanity check.  The only records that remain should be
1031                  * marked for back-end deletion.
1032                  */
1033                 {
1034                         hammer_record_t rec;
1035
1036                         RB_FOREACH(rec, hammer_rec_rb_tree, &ip->rec_tree) {
1037                                 KKASSERT(rec->state == HAMMER_FST_FLUSH);
1038                         }
1039                 }
1040
1041                 /*
1042                  * Set delete_tid in both the frontend and backend
1043                  * copy of the inode record.
1044                  */
1045                 ip->ino_rec.base.base.delete_tid = trans.tid;
1046                 ip->sync_ino_rec.base.base.delete_tid = trans.tid;
1047
1048                 /*
1049                  * Indicate that the inode has/is-being deleted.
1050                  */
1051                 ip->flags |= HAMMER_NODE_DELETED;
1052                 hammer_modify_inode(&trans, ip, HAMMER_INODE_RDIRTY);
1053                 hammer_modify_volume(&trans, trans.rootvol, NULL, 0);
1054                 --ip->hmp->rootvol->ondisk->vol0_stat_inodes;
1055                 hammer_modify_volume_done(trans.rootvol);
1056         } else if (ip->sync_flags & HAMMER_INODE_TRUNCATED) {
1057                 /*
1058                  * Interlock trunc_off.  The VOP front-end may continue to
1059                  * make adjustments to it while we are blocked.
1060                  */
1061                 off_t trunc_off;
1062                 off_t aligned_trunc_off;
1063
1064                 trunc_off = ip->sync_trunc_off;
1065                 aligned_trunc_off = (trunc_off + HAMMER_BUFMASK) &
1066                                     ~HAMMER_BUFMASK64;
1067
1068                 /*
1069                  * Delete any whole blocks on-media.  The front-end has
1070                  * already cleaned out any partial block and made it
1071                  * pending.  The front-end may have updated trunc_off
1072                  * while we were blocked so do not just unconditionally
1073                  * set it to the maximum offset.
1074                  */
1075                 kprintf("sync truncation range @ %016llx\n", aligned_trunc_off);
1076                 error = hammer_ip_delete_range(&trans, ip,
1077                                                 aligned_trunc_off,
1078                                                 0x7FFFFFFFFFFFFFFFLL);
1079                 if (error)
1080                         Debugger("hammer_ip_delete_range errored");
1081                 ip->sync_flags &= ~HAMMER_INODE_TRUNCATED;
1082                 if (ip->trunc_off >= trunc_off) {
1083                         ip->trunc_off = 0x7FFFFFFFFFFFFFFFLL;
1084                         ip->flags &= ~HAMMER_INODE_TRUNCATED;
1085                 }
1086         }
1087
1088         error = 0;      /* XXX vfsync used to be here */
1089
1090         /*
1091          * Flush any queued BIOs.
1092          */
1093         while ((bio = TAILQ_FIRST(&ip->bio_list)) != NULL) {
1094                 TAILQ_REMOVE(&ip->bio_list, bio, bio_act);
1095 #if 0
1096                 kprintf("dowrite %016llx ip %p bio %p @ %016llx\n", trans.tid, ip, bio, bio->bio_offset);
1097 #endif
1098                 tmp_error = hammer_dowrite(&trans, ip, bio);
1099                 if (tmp_error)
1100                         error = tmp_error;
1101         }
1102         ip->sync_flags &= ~HAMMER_INODE_BUFS;
1103
1104         /*
1105          * Now sync related records.
1106          */
1107         for (;;) {
1108                 tmp_error = RB_SCAN(hammer_rec_rb_tree, &ip->rec_tree, NULL,
1109                                 hammer_sync_record_callback, &trans);
1110                 KKASSERT(error <= 0);
1111                 if (tmp_error < 0)
1112                         tmp_error = -error;
1113                 if (tmp_error)
1114                         error = tmp_error;
1115                 break;
1116         }
1117
1118         /*
1119          * XDIRTY represents rec_tree and bio_list.  However, rec_tree may
1120          * contain new front-end records so short of scanning it we can't
1121          * just test whether it is empty or not. 
1122          *
1123          * If no error occured assume we succeeded.
1124          */
1125         if (error == 0)
1126                 ip->sync_flags &= ~HAMMER_INODE_XDIRTY;
1127
1128         if (error)
1129                 Debugger("RB_SCAN errored");
1130
1131         /*
1132          * Now update the inode's on-disk inode-data and/or on-disk record.
1133          * DELETED and ONDISK are managed only in ip->flags.
1134          */
1135         switch(ip->flags & (HAMMER_INODE_DELETED | HAMMER_INODE_ONDISK)) {
1136         case HAMMER_INODE_DELETED|HAMMER_INODE_ONDISK:
1137                 /*
1138                  * If deleted and on-disk, don't set any additional flags.
1139                  * the delete flag takes care of things.
1140                  */
1141                 break;
1142         case HAMMER_INODE_DELETED:
1143                 /*
1144                  * Take care of the case where a deleted inode was never
1145                  * flushed to the disk in the first place.
1146                  */
1147                 ip->sync_flags &= ~(HAMMER_INODE_RDIRTY|HAMMER_INODE_DDIRTY|
1148                                     HAMMER_INODE_XDIRTY|HAMMER_INODE_ITIMES);
1149                 while (RB_ROOT(&ip->rec_tree)) {
1150                         hammer_record_t record = RB_ROOT(&ip->rec_tree);
1151                         hammer_ref(&record->lock);
1152                         KKASSERT(record->lock.refs == 1);
1153                         record->flags |= HAMMER_RECF_DELETED_FE;
1154                         record->flags |= HAMMER_RECF_DELETED_BE;
1155                         hammer_cleardep_mem_record(record);
1156                         hammer_rel_mem_record(record);
1157                 }
1158                 break;
1159         case HAMMER_INODE_ONDISK:
1160                 /*
1161                  * If already on-disk, do not set any additional flags.
1162                  */
1163                 break;
1164         default:
1165                 /*
1166                  * If not on-disk and not deleted, set both dirty flags
1167                  * to force an initial record to be written.  Also set
1168                  * the create_tid for the inode.
1169                  *
1170                  * Set create_tid in both the frontend and backend
1171                  * copy of the inode record.
1172                  */
1173                 ip->ino_rec.base.base.create_tid = trans.tid;
1174                 ip->sync_ino_rec.base.base.create_tid = trans.tid;
1175                 ip->sync_flags |= HAMMER_INODE_RDIRTY | HAMMER_INODE_DDIRTY;
1176                 break;
1177         }
1178
1179         /*
1180          * If RDIRTY or DDIRTY is set, write out a new record.  If the inode
1181          * is already on-disk the old record is marked as deleted.
1182          *
1183          * If DELETED is set hammer_update_inode() will delete the existing
1184          * record without writing out a new one.
1185          *
1186          * If *ONLY* the ITIMES flag is set we can update the record in-place.
1187          */
1188         if (ip->flags & HAMMER_INODE_DELETED) {
1189                 error = hammer_update_inode(&trans, ip);
1190         } else 
1191         if ((ip->sync_flags & (HAMMER_INODE_RDIRTY | HAMMER_INODE_DDIRTY |
1192                                HAMMER_INODE_ITIMES)) == HAMMER_INODE_ITIMES) {
1193                 error = hammer_update_itimes(&trans, ip);
1194         } else
1195         if (ip->sync_flags & (HAMMER_INODE_RDIRTY | HAMMER_INODE_DDIRTY |
1196                               HAMMER_INODE_ITIMES)) {
1197                 error = hammer_update_inode(&trans, ip);
1198         }
1199         if (error)
1200                 Debugger("hammer_update_itimes/inode errored");
1201
1202         /*
1203          * Save the TID we used to sync the inode with to make sure we
1204          * do not improperly reuse it.
1205          */
1206         hammer_done_transaction(&trans);
1207         return(error);
1208 }
1209