d9cbef2bc27ef31bef4c1a1b430ddb1c7623caa4
[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.44 2008/04/29 04:43:08 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                 if ((ip->flags & HAMMER_INODE_REFLUSH) == 0) {
706                         ip->flags |= HAMMER_INODE_REFLUSH;
707                         if (flags & HAMMER_FLUSH_RELEASE) {
708                                 hammer_unref(&ip->lock);
709                                 KKASSERT(ip->lock.refs > 0);
710                         }
711                         if (flags & HAMMER_FLUSH_SIGNAL)
712                                 hammer_flusher_async(ip->hmp);
713                 }
714                 return;
715         }
716         if (ip->flush_state == HAMMER_FST_IDLE) {
717                 if ((ip->flags & HAMMER_INODE_MODMASK) ||
718                     (flags & HAMMER_FLUSH_FORCE)) {
719                         /*
720                          * Add a reference to represent the inode being queued
721                          * to the flusher.  If the caller wants us to 
722                          * release a reference the two cancel each other out.
723                          */
724                         if ((flags & HAMMER_FLUSH_RELEASE) == 0)
725                                 hammer_ref(&ip->lock);
726
727                         hammer_flush_inode_copysync(ip);
728                         /*
729                          * Move the inode to the flush list and add a ref to
730                          * it representing it on the list.
731                          */
732                         TAILQ_INSERT_TAIL(&ip->hmp->flush_list, ip, flush_entry);
733                         if (flags & HAMMER_FLUSH_SIGNAL)
734                                 hammer_flusher_async(ip->hmp);
735                 }
736         }
737 }
738
739 /*
740  * Helper routine to copy the frontend synchronization state to the backend.
741  * This routine may be called by either the frontend or the backend.
742  */
743 static void
744 hammer_flush_inode_copysync(hammer_inode_t ip)
745 {
746         int error;
747         int count;
748
749         /*
750          * Prevent anyone else from trying to do the same thing.
751          */
752         ip->flush_state = HAMMER_FST_SETUP;
753
754         /*
755          * Sync the buffer cache.  This will queue the BIOs.  If called
756          * from the context of the flusher the BIO's are thrown into bio_list
757          * regardless of ip->flush_state.
758          */
759         if (ip->vp != NULL)
760                 error = vfsync(ip->vp, MNT_NOWAIT, 1, NULL, NULL);
761         else
762                 error = 0;
763
764         /*
765          * This freezes strategy writes, any further BIOs will be
766          * queued to alt_bio (unless we are 
767          */
768         ip->flush_state = HAMMER_FST_FLUSH;
769
770         /*
771          * Snapshot the state of the inode for the backend flusher.
772          *
773          * The truncation must be retained in the frontend until after
774          * we've actually performed the record deletion.
775          */
776         ip->sync_flags = (ip->flags & HAMMER_INODE_MODMASK);
777         ip->sync_trunc_off = ip->trunc_off;
778         ip->sync_ino_rec = ip->ino_rec;
779         ip->sync_ino_data = ip->ino_data;
780         ip->flags &= ~HAMMER_INODE_MODMASK |
781                      HAMMER_INODE_TRUNCATED | HAMMER_INODE_BUFS;
782
783         /*
784          * Fix up the dirty buffer status.
785          */
786         if (ip->vp == NULL || RB_ROOT(&ip->vp->v_rbdirty_tree) == NULL)
787                 ip->flags &= ~HAMMER_INODE_BUFS;
788         if (TAILQ_FIRST(&ip->bio_list))
789                 ip->sync_flags |= HAMMER_INODE_BUFS;
790         else
791                 ip->sync_flags &= ~HAMMER_INODE_BUFS;
792
793         /*
794          * Set the state for the inode's in-memory records.  If some records
795          * could not be marked for backend flush (i.e. deleted records),
796          * re-set the XDIRTY flag.
797          */
798         count = RB_SCAN(hammer_rec_rb_tree, &ip->rec_tree, NULL,
799                         hammer_mark_record_callback, NULL);
800         if (count)
801                 ip->flags |= HAMMER_INODE_XDIRTY;
802 }
803
804 /*
805  * Mark records for backend flush, accumulate a count of the number of
806  * records which could not be marked.  Records marked for deletion
807  * by the frontend never make it to the media.  It is possible for
808  * a record queued to the backend to wind up with FE set after the
809  * fact, as long as BE has not yet been set.  The backend deals with
810  * this race by syncing the record as if FE had not been set, and
811  * then converting the record to a delete-on-disk record.
812  */
813 static int
814 hammer_mark_record_callback(hammer_record_t rec, void *data)
815 {
816         if (rec->state == HAMMER_FST_FLUSH) {
817                 return(0);
818         } else if ((rec->flags & HAMMER_RECF_DELETED_FE) == 0) {
819                 rec->state = HAMMER_FST_FLUSH;
820                 hammer_ref(&rec->lock);
821                 return(0);
822         } else {
823                 return(1);
824         }
825 }
826
827
828
829 /*
830  * Wait for a previously queued flush to complete
831  */
832 void
833 hammer_wait_inode(hammer_inode_t ip)
834 {
835         while (ip->flush_state == HAMMER_FST_FLUSH) {
836                 ip->flags |= HAMMER_INODE_FLUSHW;
837                 tsleep(&ip->flags, 0, "hmrwin", 0);
838         }
839 }
840
841 /*
842  * Called by the backend code when a flush has been completed.
843  * The inode has already been removed from the flush list.
844  *
845  * A pipelined flush can occur, in which case we must re-enter the
846  * inode on the list and re-copy its fields.
847  */
848 void
849 hammer_flush_inode_done(hammer_inode_t ip)
850 {
851         struct bio *bio;
852
853         KKASSERT(ip->flush_state == HAMMER_FST_FLUSH);
854
855         if (ip->sync_flags)
856                 kprintf("ip %p leftover sync_flags %08x\n", ip, ip->sync_flags);
857         ip->flags |= ip->sync_flags;
858         ip->flush_state = HAMMER_FST_IDLE;
859
860         /*
861          * Reflush any BIOs that wound up in the alt list.  Our inode will
862          * also wind up at the end of the flusher's list.
863          */
864         while ((bio = TAILQ_FIRST(&ip->bio_alt_list)) != NULL) {
865                 TAILQ_REMOVE(&ip->bio_alt_list, bio, bio_act);
866                 TAILQ_INSERT_TAIL(&ip->bio_list, bio, bio_act);
867                 ip->flags |= HAMMER_INODE_XDIRTY;
868                 ip->flags |= HAMMER_INODE_REFLUSH;
869                 kprintf("rebio %p ip %p @%016llx,%d\n", bio, ip, bio->bio_offset, bio->bio_buf->b_bufsize);
870         }
871
872         /*
873          * If the frontend made more changes and requested another flush,
874          * do it. 
875          */
876         if (ip->flags & HAMMER_INODE_REFLUSH) {
877                 ip->flags &= ~HAMMER_INODE_REFLUSH;
878                 hammer_flush_inode(ip, 0);
879                 if (ip->flush_state == HAMMER_FST_IDLE) {
880                         if (ip->flags & HAMMER_INODE_FLUSHW) {
881                                 ip->flags &= ~HAMMER_INODE_FLUSHW;
882                                 wakeup(&ip->flags);
883                         }
884                 }
885         } else {
886                 if (ip->flags & HAMMER_INODE_FLUSHW) {
887                         ip->flags &= ~HAMMER_INODE_FLUSHW;
888                         wakeup(&ip->flags);
889                 }
890         }
891         hammer_rel_inode(ip, 0);
892 }
893
894 /*
895  * Called from hammer_sync_inode() to synchronize in-memory records
896  * to the media.
897  */
898 static int
899 hammer_sync_record_callback(hammer_record_t record, void *data)
900 {
901         hammer_transaction_t trans = data;
902         int error;
903
904         /*
905          * Skip records that do not belong to the current flush.  Records
906          * belonging to the flush will have been referenced for us.
907          */
908         if (record->state != HAMMER_FST_FLUSH)
909                 return(0);
910
911         /*
912          * Interlock the record using the BE flag.  Once BE is set the
913          * frontend cannot change the state of FE.
914          *
915          * NOTE: If FE is set prior to us setting BE we still sync the
916          * record out, but the flush completion code converts it to 
917          * a delete-on-disk record instead of destroying it.
918          */
919         hammer_lock_ex(&record->lock);
920         if (record->flags & HAMMER_RECF_INTERLOCK_BE) {
921                 hammer_unlock(&record->lock);
922                 return(0);
923         }
924         record->flags |= HAMMER_RECF_INTERLOCK_BE;
925
926         /*
927          * If DELETED_FE is set we may have already sent dependant pieces
928          * to the disk and we must flush the record as if it hadn't been
929          * deleted.  This creates a bit of a mess because we have to
930          * have ip_sync_record convert the record to DELETE_ONDISK before
931          * it inserts the B-Tree record.  Otherwise the media sync might
932          * be visible to the frontend.
933          */
934         if (record->flags & HAMMER_RECF_DELETED_FE)
935                 record->flags |= HAMMER_RECF_CONVERT_DELETE_ONDISK;
936
937         /*
938          * Assign the create_tid for new records.  Deletions already
939          * have the record's entire key properly set up.
940          */
941         if ((record->flags & HAMMER_RECF_DELETE_ONDISK) == 0)
942                 record->rec.inode.base.base.create_tid = trans->tid;
943         error = hammer_ip_sync_record(trans, record);
944
945         if (error) {
946                 error = -error;
947                 if (error != -ENOSPC) {
948                         kprintf("hammer_sync_record_callback: sync failed rec "
949                                 "%p, error %d\n", record, error);
950                         Debugger("sync failed rec");
951                 }
952         }
953         hammer_flush_record_done(record, error);
954         return(error);
955 }
956
957 /*
958  * XXX error handling
959  */
960 int
961 hammer_sync_inode(hammer_inode_t ip, int handle_delete)
962 {
963         struct hammer_transaction trans;
964         struct bio *bio;
965         hammer_depend_t depend;
966         int error, tmp_error;
967
968         if ((ip->sync_flags & HAMMER_INODE_MODMASK) == 0 &&
969             handle_delete == 0) {
970                 return(0);
971         }
972
973         hammer_start_transaction_fls(&trans, ip->hmp);
974
975         /*
976          * Any (directory) records this inode depends on must also be
977          * synchronized.  The directory itself only needs to be flushed
978          * if its inode is not already on-disk.
979          */
980         while ((depend = TAILQ_FIRST(&ip->depend_list)) != NULL) {
981                 hammer_record_t record;
982
983                 record = depend->record;
984                 TAILQ_REMOVE(&depend->record->depend_list, depend, rec_entry);
985                 TAILQ_REMOVE(&ip->depend_list, depend, ip_entry);
986                 --ip->depend_count;
987                 if (record->state != HAMMER_FST_FLUSH) {
988                         record->state = HAMMER_FST_FLUSH;
989                         /* add ref (steal ref from dependancy) */
990                 } else {
991                         /* remove ref related to dependancy */
992                         /* record still has at least one ref from state */
993                         hammer_unref(&record->lock);
994                         KKASSERT(record->lock.refs > 0);
995                 }
996                 if (record->ip->flags & HAMMER_INODE_ONDISK) {
997                         kprintf("I");
998                         hammer_sync_record_callback(record, &trans);
999                 } else {
1000                         kprintf("J");
1001                         KKASSERT((record->ip->flags & HAMMER_INODE_NEW) == 0);
1002                         hammer_flush_inode(record->ip, 0);
1003                 }
1004                 hammer_unref(&ip->lock);
1005                 KKASSERT(ip->lock.refs > 0);
1006                 kfree(depend, M_HAMMER);
1007         }
1008
1009
1010         /*
1011          * Sync inode deletions and truncations.
1012          */
1013         if (ip->sync_ino_rec.ino_nlinks == 0 && handle_delete && 
1014             (ip->flags & HAMMER_INODE_GONE) == 0) {
1015                 /*
1016                  * Handle the case where the inode has been completely deleted
1017                  * and is no longer referenceable from the filesystem
1018                  * namespace.
1019                  *
1020                  * NOTE: We do not set the RDIRTY flag when updating the
1021                  * delete_tid, setting HAMMER_INODE_DELETED takes care of it.
1022                  */
1023
1024                 ip->flags |= HAMMER_INODE_GONE | HAMMER_INODE_DELETED;
1025                 ip->flags &= ~HAMMER_INODE_TRUNCATED;
1026                 ip->sync_flags &= ~HAMMER_INODE_TRUNCATED;
1027                 if (ip->vp)
1028                         vtruncbuf(ip->vp, 0, HAMMER_BUFSIZE);
1029                 error = hammer_ip_delete_range_all(&trans, ip);
1030                 if (error)
1031                         Debugger("hammer_ip_delete_range_all errored");
1032
1033                 /*
1034                  * Sanity check.  The only records that remain should be
1035                  * marked for back-end deletion.
1036                  */
1037                 {
1038                         hammer_record_t rec;
1039
1040                         RB_FOREACH(rec, hammer_rec_rb_tree, &ip->rec_tree) {
1041                                 KKASSERT(rec->state == HAMMER_FST_FLUSH);
1042                         }
1043                 }
1044
1045                 /*
1046                  * Set delete_tid in both the frontend and backend
1047                  * copy of the inode record.
1048                  */
1049                 ip->ino_rec.base.base.delete_tid = trans.tid;
1050                 ip->sync_ino_rec.base.base.delete_tid = trans.tid;
1051
1052                 /*
1053                  * Indicate that the inode has/is-being deleted.
1054                  */
1055                 ip->flags |= HAMMER_NODE_DELETED;
1056                 hammer_modify_inode(&trans, ip, HAMMER_INODE_RDIRTY);
1057                 hammer_modify_volume(&trans, trans.rootvol, NULL, 0);
1058                 --ip->hmp->rootvol->ondisk->vol0_stat_inodes;
1059                 hammer_modify_volume_done(trans.rootvol);
1060         } else if (ip->sync_flags & HAMMER_INODE_TRUNCATED) {
1061                 /*
1062                  * Interlock trunc_off.  The VOP front-end may continue to
1063                  * make adjustments to it while we are blocked.
1064                  */
1065                 off_t trunc_off;
1066                 off_t aligned_trunc_off;
1067
1068                 trunc_off = ip->sync_trunc_off;
1069                 aligned_trunc_off = (trunc_off + HAMMER_BUFMASK) &
1070                                     ~HAMMER_BUFMASK64;
1071
1072                 /*
1073                  * Delete any whole blocks on-media.  The front-end has
1074                  * already cleaned out any partial block and made it
1075                  * pending.  The front-end may have updated trunc_off
1076                  * while we were blocked so do not just unconditionally
1077                  * set it to the maximum offset.
1078                  */
1079                 kprintf("sync truncation range @ %016llx\n", aligned_trunc_off);
1080                 error = hammer_ip_delete_range(&trans, ip,
1081                                                 aligned_trunc_off,
1082                                                 0x7FFFFFFFFFFFFFFFLL);
1083                 if (error)
1084                         Debugger("hammer_ip_delete_range errored");
1085                 ip->sync_flags &= ~HAMMER_INODE_TRUNCATED;
1086                 if (ip->trunc_off >= trunc_off) {
1087                         ip->trunc_off = 0x7FFFFFFFFFFFFFFFLL;
1088                         ip->flags &= ~HAMMER_INODE_TRUNCATED;
1089                 }
1090         }
1091
1092         error = 0;      /* XXX vfsync used to be here */
1093
1094         /*
1095          * Flush any queued BIOs.
1096          */
1097         while ((bio = TAILQ_FIRST(&ip->bio_list)) != NULL) {
1098                 TAILQ_REMOVE(&ip->bio_list, bio, bio_act);
1099 #if 0
1100                 kprintf("dowrite %016llx ip %p bio %p @ %016llx\n", trans.tid, ip, bio, bio->bio_offset);
1101 #endif
1102                 tmp_error = hammer_dowrite(&trans, ip, bio);
1103                 if (tmp_error)
1104                         error = tmp_error;
1105         }
1106         ip->sync_flags &= ~HAMMER_INODE_BUFS;
1107
1108         /*
1109          * Now sync related records.
1110          */
1111         for (;;) {
1112                 tmp_error = RB_SCAN(hammer_rec_rb_tree, &ip->rec_tree, NULL,
1113                                 hammer_sync_record_callback, &trans);
1114                 KKASSERT(error <= 0);
1115                 if (tmp_error < 0)
1116                         tmp_error = -error;
1117                 if (tmp_error)
1118                         error = tmp_error;
1119                 break;
1120         }
1121
1122         /*
1123          * XDIRTY represents rec_tree and bio_list.  However, rec_tree may
1124          * contain new front-end records so short of scanning it we can't
1125          * just test whether it is empty or not. 
1126          *
1127          * If no error occured assume we succeeded.
1128          */
1129         if (error == 0)
1130                 ip->sync_flags &= ~HAMMER_INODE_XDIRTY;
1131
1132         if (error)
1133                 Debugger("RB_SCAN errored");
1134
1135         /*
1136          * Now update the inode's on-disk inode-data and/or on-disk record.
1137          * DELETED and ONDISK are managed only in ip->flags.
1138          */
1139         switch(ip->flags & (HAMMER_INODE_DELETED | HAMMER_INODE_ONDISK)) {
1140         case HAMMER_INODE_DELETED|HAMMER_INODE_ONDISK:
1141                 /*
1142                  * If deleted and on-disk, don't set any additional flags.
1143                  * the delete flag takes care of things.
1144                  */
1145                 break;
1146         case HAMMER_INODE_DELETED:
1147                 /*
1148                  * Take care of the case where a deleted inode was never
1149                  * flushed to the disk in the first place.
1150                  */
1151                 ip->sync_flags &= ~(HAMMER_INODE_RDIRTY|HAMMER_INODE_DDIRTY|
1152                                     HAMMER_INODE_XDIRTY|HAMMER_INODE_ITIMES);
1153                 while (RB_ROOT(&ip->rec_tree)) {
1154                         hammer_record_t record = RB_ROOT(&ip->rec_tree);
1155                         hammer_ref(&record->lock);
1156                         KKASSERT(record->lock.refs == 1);
1157                         record->flags |= HAMMER_RECF_DELETED_FE;
1158                         record->flags |= HAMMER_RECF_DELETED_BE;
1159                         hammer_cleardep_mem_record(record);
1160                         hammer_rel_mem_record(record);
1161                 }
1162                 break;
1163         case HAMMER_INODE_ONDISK:
1164                 /*
1165                  * If already on-disk, do not set any additional flags.
1166                  */
1167                 break;
1168         default:
1169                 /*
1170                  * If not on-disk and not deleted, set both dirty flags
1171                  * to force an initial record to be written.  Also set
1172                  * the create_tid for the inode.
1173                  *
1174                  * Set create_tid in both the frontend and backend
1175                  * copy of the inode record.
1176                  */
1177                 ip->ino_rec.base.base.create_tid = trans.tid;
1178                 ip->sync_ino_rec.base.base.create_tid = trans.tid;
1179                 ip->sync_flags |= HAMMER_INODE_RDIRTY | HAMMER_INODE_DDIRTY;
1180                 break;
1181         }
1182
1183         /*
1184          * If RDIRTY or DDIRTY is set, write out a new record.  If the inode
1185          * is already on-disk the old record is marked as deleted.
1186          *
1187          * If DELETED is set hammer_update_inode() will delete the existing
1188          * record without writing out a new one.
1189          *
1190          * If *ONLY* the ITIMES flag is set we can update the record in-place.
1191          */
1192         if (ip->flags & HAMMER_INODE_DELETED) {
1193                 error = hammer_update_inode(&trans, ip);
1194         } else 
1195         if ((ip->sync_flags & (HAMMER_INODE_RDIRTY | HAMMER_INODE_DDIRTY |
1196                                HAMMER_INODE_ITIMES)) == HAMMER_INODE_ITIMES) {
1197                 error = hammer_update_itimes(&trans, ip);
1198         } else
1199         if (ip->sync_flags & (HAMMER_INODE_RDIRTY | HAMMER_INODE_DDIRTY |
1200                               HAMMER_INODE_ITIMES)) {
1201                 error = hammer_update_inode(&trans, ip);
1202         }
1203         if (error)
1204                 Debugger("hammer_update_itimes/inode errored");
1205
1206         /*
1207          * Save the TID we used to sync the inode with to make sure we
1208          * do not improperly reuse it.
1209          */
1210         hammer_done_transaction(&trans);
1211         return(error);
1212 }
1213