Merge from vendor branch TCSH:
[dragonfly.git] / sys / vfs / hammer / hammer_object.c
1 /*
2  * Copyright (c) 2007 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_object.c,v 1.18 2008/01/10 07:41:03 dillon Exp $
35  */
36
37 #include "hammer.h"
38
39 static int hammer_mem_add(hammer_transaction_t trans,
40                              hammer_record_t record);
41 static int hammer_mem_lookup(hammer_cursor_t cursor, hammer_inode_t ip);
42 static int hammer_mem_first(hammer_cursor_t cursor, hammer_inode_t ip);
43
44 /*
45  * Red-black tree support.
46  */
47 static int
48 hammer_rec_rb_compare(hammer_record_t rec1, hammer_record_t rec2)
49 {
50         if (rec1->rec.base.base.rec_type < rec2->rec.base.base.rec_type)
51                 return(-1);
52         if (rec1->rec.base.base.rec_type > rec2->rec.base.base.rec_type)
53                 return(1);
54
55         if (rec1->rec.base.base.key < rec2->rec.base.base.key)
56                 return(-1);
57         if (rec1->rec.base.base.key > rec2->rec.base.base.key)
58                 return(1);
59
60         if (rec1->rec.base.base.create_tid < rec2->rec.base.base.create_tid)
61                 return(-1);
62         if (rec1->rec.base.base.create_tid > rec2->rec.base.base.create_tid)
63                 return(1);
64         return(0);
65 }
66
67 static int
68 hammer_rec_compare(hammer_base_elm_t info, hammer_record_t rec)
69 {
70         if (info->rec_type < rec->rec.base.base.rec_type)
71                 return(-3);
72         if (info->rec_type > rec->rec.base.base.rec_type)
73                 return(3);
74
75         if (info->key < rec->rec.base.base.key)
76                 return(-2);
77         if (info->key > rec->rec.base.base.key)
78                 return(2);
79
80         /*
81          * This test has a number of special cases.  create_tid in key1 is
82          * the as-of transction id, and delete_tid in key1 is NOT USED.
83          *
84          * A key1->create_tid of 0 matches any record regardles of when
85          * it was created or destroyed.  0xFFFFFFFFFFFFFFFFULL should be
86          * used to search for the most current state of the object.
87          *
88          * key2->create_tid is a HAMMER record and will never be
89          * 0.   key2->delete_tid is the deletion transaction id or 0 if
90          * the record has not yet been deleted.
91          */
92         if (info->create_tid) {
93                 if (info->create_tid < rec->rec.base.base.create_tid)
94                         return(-1);
95                 if (rec->rec.base.base.delete_tid &&
96                     info->create_tid >= rec->rec.base.base.delete_tid) {
97                         return(1);
98                 }
99         }
100         return(0);
101 }
102
103 /*
104  * RB_SCAN comparison code for hammer_mem_first().  The argument order
105  * is reversed so the comparison result has to be negated.  key_beg and
106  * key_end are both range-inclusive.
107  *
108  * The creation timestamp can cause hammer_rec_compare() to return -1 or +1.
109  * These do not stop the scan.
110  *
111  * Localized deletions are not cached in-memory.
112  */
113 static
114 int
115 hammer_rec_scan_cmp(hammer_record_t rec, void *data)
116 {
117         hammer_cursor_t cursor = data;
118         int r;
119
120         r = hammer_rec_compare(&cursor->key_beg, rec);
121         if (r > 1)
122                 return(-1);
123         if (r == 0)
124                 return(0);
125         r = hammer_rec_compare(&cursor->key_end, rec);
126         if (r < -1)
127                 return(1);
128         return(0);
129 }
130
131 RB_GENERATE(hammer_rec_rb_tree, hammer_record, rb_node, hammer_rec_rb_compare);
132 RB_GENERATE_XLOOKUP(hammer_rec_rb_tree, INFO, hammer_record, rb_node,
133                     hammer_rec_compare, hammer_base_elm_t);
134
135 /*
136  * Allocate a record for the caller to finish filling in.  The record is
137  * returned referenced.
138  */
139 hammer_record_t
140 hammer_alloc_mem_record(hammer_inode_t ip)
141 {
142         hammer_record_t record;
143
144         ++hammer_count_records;
145         record = kmalloc(sizeof(*record), M_HAMMER, M_WAITOK|M_ZERO);
146         record->ip = ip;
147         hammer_ref(&record->lock);
148         return (record);
149 }
150
151 /*
152  * Release a memory record.  Records marked for deletion are immediately
153  * removed from the RB-Tree but otherwise left intact until the last ref
154  * goes away.
155  */
156 void
157 hammer_rel_mem_record(struct hammer_record *record)
158 {
159         hammer_unref(&record->lock);
160         if (record->flags & HAMMER_RECF_DELETED) {
161                 if (record->flags & HAMMER_RECF_ONRBTREE) {
162                         RB_REMOVE(hammer_rec_rb_tree, &record->ip->rec_tree,
163                                   record);
164                         record->flags &= ~HAMMER_RECF_ONRBTREE;
165                 }
166                 if (record->lock.refs == 0) {
167                         if (record->flags & HAMMER_RECF_ALLOCDATA) {
168                                 --hammer_count_record_datas;
169                                 kfree(record->data, M_HAMMER);
170                                 record->flags &= ~HAMMER_RECF_ALLOCDATA;
171                         }
172                         record->data = NULL;
173                         --hammer_count_records;
174                         kfree(record, M_HAMMER);
175                 }
176         }
177 }
178
179 /*
180  * Lookup an in-memory record given the key specified in the cursor.  Works
181  * just like hammer_btree_lookup() but operates on an inode's in-memory
182  * record list.
183  *
184  * The lookup must fail if the record is marked for deferred deletion.
185  */
186 static
187 int
188 hammer_mem_lookup(hammer_cursor_t cursor, hammer_inode_t ip)
189 {
190         int error;
191
192         if (cursor->iprec) {
193                 hammer_rel_mem_record(cursor->iprec);
194                 cursor->iprec = NULL;
195         }
196         if (cursor->ip) {
197                 hammer_rec_rb_tree_scan_info_done(&cursor->scan,
198                                                   &cursor->ip->rec_tree);
199         }
200         cursor->ip = ip;
201         hammer_rec_rb_tree_scan_info_link(&cursor->scan, &ip->rec_tree);
202         cursor->scan.node = NULL;
203         cursor->iprec = hammer_rec_rb_tree_RB_LOOKUP_INFO(
204                                 &ip->rec_tree, &cursor->key_beg);
205         if (cursor->iprec == NULL) {
206                 error = ENOENT;
207         } else {
208                 hammer_ref(&cursor->iprec->lock);
209                 error = 0;
210         }
211         return(error);
212 }
213
214 /*
215  * hammer_mem_first() - locate the first in-memory record matching the
216  * cursor.
217  *
218  * The RB_SCAN function we use is designed as a callback.  We terminate it
219  * (return -1) as soon as we get a match.
220  */
221 static
222 int
223 hammer_rec_scan_callback(hammer_record_t rec, void *data)
224 {
225         hammer_cursor_t cursor = data;
226
227         /*
228          * Skip if not visible due to our as-of TID
229          */
230         if (cursor->key_beg.create_tid) {
231                 if (cursor->key_beg.create_tid < rec->rec.base.base.create_tid)
232                         return(0);
233                 if (rec->rec.base.base.delete_tid &&
234                     cursor->key_beg.create_tid >=
235                      rec->rec.base.base.delete_tid) {
236                         return(0);
237                 }
238         }
239
240         /*
241          * Return the first matching record and stop the scan
242          */
243         if (cursor->iprec == NULL) {
244                 cursor->iprec = rec;
245                 hammer_ref(&rec->lock);
246                 return(-1);
247         }
248         return(0);
249 }
250
251 static
252 int
253 hammer_mem_first(hammer_cursor_t cursor, hammer_inode_t ip)
254 {
255         if (cursor->iprec) {
256                 hammer_rel_mem_record(cursor->iprec);
257                 cursor->iprec = NULL;
258         }
259         if (cursor->ip) {
260                 hammer_rec_rb_tree_scan_info_done(&cursor->scan,
261                                                   &cursor->ip->rec_tree);
262         }
263         cursor->ip = ip;
264         hammer_rec_rb_tree_scan_info_link(&cursor->scan, &ip->rec_tree);
265
266         cursor->scan.node = NULL;
267         hammer_rec_rb_tree_RB_SCAN(&ip->rec_tree, hammer_rec_scan_cmp,
268                                    hammer_rec_scan_callback, cursor);
269
270         /*
271          * Adjust scan.node and keep it linked into the RB-tree so we can
272          * hold the cursor through third party modifications of the RB-tree.
273          */
274         if (cursor->iprec) {
275                 cursor->scan.node = hammer_rec_rb_tree_RB_NEXT(cursor->iprec);
276                 return(0);
277         }
278         return(ENOENT);
279 }
280
281 void
282 hammer_mem_done(hammer_cursor_t cursor)
283 {
284         if (cursor->ip) {
285                 hammer_rec_rb_tree_scan_info_done(&cursor->scan,
286                                                   &cursor->ip->rec_tree);
287                 cursor->ip = NULL;
288         }
289         if (cursor->iprec) {
290                 hammer_rel_mem_record(cursor->iprec);
291                 cursor->iprec = NULL;
292         }
293 }
294
295 /************************************************************************
296  *                   HAMMER IN-MEMORY RECORD FUNCTIONS                  *
297  ************************************************************************
298  *
299  * These functions manipulate in-memory records.  Such records typically
300  * exist prior to being committed to disk or indexed via the on-disk B-Tree.
301  */
302
303 /*
304  * Add a directory entry (dip,ncp) which references inode (ip).
305  *
306  * Note that the low 32 bits of the namekey are set temporarily to create
307  * a unique in-memory record, and may be modified a second time when the
308  * record is synchronized to disk.  In particular, the low 32 bits cannot be
309  * all 0's when synching to disk, which is not handled here.
310  */
311 int
312 hammer_ip_add_directory(struct hammer_transaction *trans,
313                      struct hammer_inode *dip, struct namecache *ncp,
314                      struct hammer_inode *ip)
315 {
316         hammer_record_t record;
317         int error;
318         int bytes;
319
320         record = hammer_alloc_mem_record(dip);
321
322         bytes = ncp->nc_nlen;   /* NOTE: terminating \0 is NOT included */
323         if (++trans->hmp->namekey_iterator == 0)
324                 ++trans->hmp->namekey_iterator;
325
326         record->rec.entry.base.base.obj_id = dip->obj_id;
327         record->rec.entry.base.base.key =
328                 hammer_directory_namekey(ncp->nc_name, bytes);
329         record->rec.entry.base.base.key += trans->hmp->namekey_iterator;
330         record->rec.entry.base.base.create_tid = trans->tid;
331         record->rec.entry.base.base.rec_type = HAMMER_RECTYPE_DIRENTRY;
332         record->rec.entry.base.base.obj_type = ip->ino_rec.base.base.obj_type;
333         record->rec.entry.obj_id = ip->obj_id;
334         if (bytes <= sizeof(record->rec.entry.den_name)) {
335                 record->data = (void *)record->rec.entry.den_name;
336                 record->flags |= HAMMER_RECF_EMBEDDED_DATA;
337         } else {
338                 ++hammer_count_record_datas;
339                 record->data = kmalloc(bytes, M_HAMMER, M_WAITOK);
340                 record->flags |= HAMMER_RECF_ALLOCDATA;
341         }
342         bcopy(ncp->nc_name, record->data, bytes);
343         record->rec.entry.base.data_len = bytes;
344         ++ip->ino_rec.ino_nlinks;
345         hammer_modify_inode(trans, ip, HAMMER_INODE_RDIRTY);
346         error = hammer_mem_add(trans, record);
347         return(error);
348 }
349
350 /*
351  * Delete the directory entry and update the inode link count.  The
352  * cursor must be seeked to the directory entry record being deleted.
353  *
354  * NOTE: HAMMER_CURSOR_DELETE may not have been set.  XXX remove flag.
355  */
356 int
357 hammer_ip_del_directory(struct hammer_transaction *trans,
358                      hammer_cursor_t cursor, struct hammer_inode *dip,
359                      struct hammer_inode *ip)
360 {
361         int error;
362
363         error = hammer_ip_delete_record(cursor, trans->tid);
364
365         /*
366          * One less link.  The file may still be open in the OS even after
367          * all links have gone away so we only try to sync if the OS has
368          * no references and nlinks falls to 0.
369          */
370         if (error == 0) {
371                 --ip->ino_rec.ino_nlinks;
372                 hammer_modify_inode(trans, ip, HAMMER_INODE_RDIRTY);
373                 if (ip->ino_rec.ino_nlinks == 0 &&
374                     (ip->vp == NULL || (ip->vp->v_flag & VINACTIVE))) {
375                         hammer_sync_inode(ip, MNT_NOWAIT, 1);
376                 }
377
378         }
379         return(error);
380 }
381
382 /*
383  * Add a record to an inode.
384  *
385  * The caller must allocate the record with hammer_alloc_mem_record(ip) and
386  * initialize the following additional fields:
387  *
388  * record->rec.entry.base.base.key
389  * record->rec.entry.base.base.rec_type
390  * record->rec.entry.base.base.data_len
391  * record->data         (a copy will be kmalloc'd if not embedded)
392  */
393 int
394 hammer_ip_add_record(struct hammer_transaction *trans, hammer_record_t record)
395 {
396         hammer_inode_t ip = record->ip;
397         int error;
398         int bytes;
399         void *data;
400
401         record->rec.base.base.obj_id = ip->obj_id;
402         record->rec.base.base.create_tid = trans->tid;
403         record->rec.base.base.obj_type = ip->ino_rec.base.base.obj_type;
404         bytes = record->rec.base.data_len;
405
406         if (record->data) {
407                 if ((char *)record->data < (char *)&record->rec ||
408                     (char *)record->data >= (char *)(&record->rec + 1)) {
409                         ++hammer_count_record_datas;
410                         data = kmalloc(bytes, M_HAMMER, M_WAITOK);
411                         record->flags |= HAMMER_RECF_ALLOCDATA;
412                         bcopy(record->data, data, bytes);
413                         record->data = data;
414                 } else {
415                         record->flags |= HAMMER_RECF_EMBEDDED_DATA;
416                 }
417         }
418         hammer_modify_inode(trans, ip, HAMMER_INODE_RDIRTY);
419         error = hammer_mem_add(trans, record);
420         return(error);
421 }
422
423 /*
424  * Sync data from a buffer cache buffer (typically) to the filesystem.  This
425  * is called via the strategy called from a cached data source.  This code
426  * is responsible for actually writing a data record out to the disk.
427  */
428 int
429 hammer_ip_sync_data(hammer_transaction_t trans, hammer_inode_t ip,
430                        int64_t offset, void *data, int bytes,
431                        struct hammer_cursor **spike)
432 {
433         struct hammer_cursor cursor;
434         hammer_record_ondisk_t rec;
435         union hammer_btree_elm elm;
436         void *bdata;
437         int error;
438
439         error = hammer_init_cursor_hmp(&cursor, &ip->cache[0], ip->hmp);
440         if (error)
441                 return(error);
442         cursor.key_beg.obj_id = ip->obj_id;
443         cursor.key_beg.key = offset + bytes;
444         cursor.key_beg.create_tid = trans->tid;
445         cursor.key_beg.delete_tid = 0;
446         cursor.key_beg.rec_type = HAMMER_RECTYPE_DATA;
447         cursor.flags = HAMMER_CURSOR_INSERT;
448
449         /*
450          * Issue a lookup to position the cursor and locate the cluster
451          */
452         error = hammer_btree_lookup(&cursor);
453         if (error == 0) {
454                 kprintf("hammer_ip_sync_data: duplicate data at (%lld,%d)\n",
455                         offset, bytes);
456                 hammer_print_btree_elm(&cursor.node->ondisk->elms[cursor.index],
457                                        HAMMER_BTREE_TYPE_LEAF, cursor.index);
458                 error = EIO;
459         }
460         if (error != ENOENT)
461                 goto done;
462
463         /*
464          * Allocate record and data space now that we know which cluster
465          * the B-Tree node ended up in.
466          */
467         bdata = hammer_alloc_data(cursor.node->cluster, bytes, &error,
468                                   &cursor.data_buffer);
469         if (bdata == NULL)
470                 goto done;
471         rec = hammer_alloc_record(cursor.node->cluster, &error,
472                                   &cursor.record_buffer);
473         if (rec == NULL)
474                 goto fail1;
475
476         /*
477          * Fill everything in and insert our B-Tree node.
478          */
479         hammer_modify_buffer(cursor.record_buffer);
480         rec->base.base = cursor.key_beg;
481         rec->base.data_crc = crc32(data, bytes);
482         rec->base.rec_id = 0;   /* XXX */
483         rec->base.data_offset = hammer_bclu_offset(cursor.data_buffer, bdata);
484         rec->base.data_len = bytes;
485
486         hammer_modify_buffer(cursor.data_buffer);
487         bcopy(data, bdata, bytes);
488
489         elm.leaf.base = cursor.key_beg;
490         elm.leaf.rec_offset = hammer_bclu_offset(cursor.record_buffer, rec);
491         elm.leaf.data_offset = rec->base.data_offset;
492         elm.leaf.data_len = bytes;
493         elm.leaf.data_crc = rec->base.data_crc;
494
495         /*
496          * Data records can wind up on-disk before the inode itself is
497          * on-disk.  One must assume data records may be on-disk if either
498          * HAMMER_INODE_DONDISK or HAMMER_INODE_ONDISK is set
499          */
500         ip->flags |= HAMMER_INODE_DONDISK;
501
502         error = hammer_btree_insert(&cursor, &elm);
503         if (error == 0) {
504                 hammer_update_syncid(cursor.record_buffer->cluster, trans->tid);
505                 goto done;
506         }
507
508         hammer_free_record_ptr(cursor.record_buffer, rec);
509 fail1:
510         hammer_free_data_ptr(cursor.data_buffer, bdata, bytes);
511 done:
512         /*
513          * If ENOSPC in cluster fill in the spike structure and return
514          * ENOSPC.
515          */
516         if (error == ENOSPC)
517                 hammer_load_spike(&cursor, spike);
518         hammer_done_cursor(&cursor);
519         return(error);
520 }
521
522 /*
523  * Sync an in-memory record to the disk.  this is typically called via fsync
524  * from a cached record source.  This code is responsible for actually
525  * writing a record out to the disk.
526  */
527 int
528 hammer_ip_sync_record(hammer_record_t record, struct hammer_cursor **spike)
529 {
530         struct hammer_cursor cursor;
531         hammer_record_ondisk_t rec;
532         hammer_mount_t hmp;
533         union hammer_btree_elm elm;
534         void *bdata;
535         int error;
536
537         error = hammer_init_cursor_hmp(&cursor, &record->ip->cache[0],
538                                        record->ip->hmp);
539         if (error)
540                 return(error);
541         cursor.key_beg = record->rec.base.base;
542         cursor.flags = HAMMER_CURSOR_INSERT;
543
544         /*
545          * Issue a lookup to position the cursor and locate the cluster.  The
546          * target key should not exist.  If we are creating a directory entry
547          * we may have to iterate the low 32 bits of the key to find an unused
548          * key.
549          *
550          * If we run out of space trying to adjust the B-Tree for the
551          * insert, re-lookup without the insert flag so the cursor
552          * is properly positioned for the spike.
553          */
554 again:
555         error = hammer_btree_lookup(&cursor);
556         if (error == 0) {
557                 if (record->rec.base.base.rec_type == HAMMER_RECTYPE_DIRENTRY) {
558                         hmp = cursor.node->cluster->volume->hmp;
559                         if (++hmp->namekey_iterator == 0)
560                                 ++hmp->namekey_iterator;
561                         record->rec.base.base.key &= ~(0xFFFFFFFFLL);
562                         record->rec.base.base.key |= hmp->namekey_iterator;
563                         goto again;
564                 }
565                 kprintf("hammer_ip_sync_record: duplicate rec at (%016llx)\n",
566                         record->rec.base.base.key);
567                 Debugger("duplicate record1");
568                 error = EIO;
569         }
570         if (error != ENOENT)
571                 goto done;
572
573         /*
574          * Mark the record as undergoing synchronization.  Our cursor is
575          * holding a locked B-Tree node for the insertion which interlocks
576          * anyone trying to access this record.
577          *
578          * XXX There is still a race present related to iterations.  An
579          * iteration may process the record, a sync may occur, and then
580          * later process the B-Tree element for the same record.
581          *
582          * We do not try to synchronize a deleted record.
583          */
584         if (record->flags & (HAMMER_RECF_DELETED | HAMMER_RECF_SYNCING)) {
585                 error = 0;
586                 goto done;
587         }
588         record->flags |= HAMMER_RECF_SYNCING;
589
590         /*
591          * Allocate record and data space now that we know which cluster
592          * the B-Tree node ended up in.
593          */
594         if (record->data == NULL ||
595             (record->flags & HAMMER_RECF_EMBEDDED_DATA)) {
596                 bdata = record->data;
597         } else {
598                 bdata = hammer_alloc_data(cursor.node->cluster,
599                                           record->rec.base.data_len, &error,
600                                           &cursor.data_buffer);
601                 if (bdata == NULL)
602                         goto fail2;
603         }
604         rec = hammer_alloc_record(cursor.node->cluster, &error,
605                                   &cursor.record_buffer);
606         if (rec == NULL)
607                 goto fail1;
608
609         /*
610          * Fill everything in and insert our B-Tree node.
611          *
612          * XXX assign rec_id here
613          */
614         hammer_modify_buffer(cursor.record_buffer);
615         *rec = record->rec;
616         if (bdata) {
617                 rec->base.data_crc = crc32(record->data,
618                                            record->rec.base.data_len);
619                 if (record->flags & HAMMER_RECF_EMBEDDED_DATA) {
620                         /*
621                          * Data embedded in record
622                          */
623                         rec->base.data_offset = ((char *)bdata -
624                                                  (char *)&record->rec);
625                         KKASSERT(rec->base.data_offset >= 0 && 
626                                  rec->base.data_offset + rec->base.data_len <=
627                                   sizeof(*rec));
628                         rec->base.data_offset += hammer_bclu_offset(cursor.record_buffer, rec);
629                 } else {
630                         /*
631                          * Data separate from record
632                          */
633                         rec->base.data_offset = hammer_bclu_offset(cursor.data_buffer,bdata);
634                         hammer_modify_buffer(cursor.data_buffer);
635                         bcopy(record->data, bdata, rec->base.data_len);
636                 }
637         }
638         rec->base.rec_id = 0;   /* XXX */
639
640         elm.leaf.base = cursor.key_beg;
641         elm.leaf.rec_offset = hammer_bclu_offset(cursor.record_buffer, rec);
642         elm.leaf.data_offset = rec->base.data_offset;
643         elm.leaf.data_len = rec->base.data_len;
644         elm.leaf.data_crc = rec->base.data_crc;
645
646         error = hammer_btree_insert(&cursor, &elm);
647
648         /*
649          * Clean up on success, or fall through on error.
650          */
651         if (error == 0) {
652                 record->flags |= HAMMER_RECF_DELETED;
653                 record->flags &= ~HAMMER_RECF_SYNCING;
654                 hammer_update_syncid(cursor.record_buffer->cluster,
655                                      record->rec.base.base.create_tid);
656                 goto done;
657         }
658
659         hammer_free_record_ptr(cursor.record_buffer, rec);
660 fail1:
661         if (record->data && (record->flags & HAMMER_RECF_EMBEDDED_DATA) == 0) {
662                 hammer_free_data_ptr(cursor.data_buffer, bdata,
663                                      record->rec.base.data_len);
664         }
665 fail2:
666         record->flags &= ~HAMMER_RECF_SYNCING;
667 done:
668         /*
669          * If ENOSPC in cluster fill in the spike structure and return
670          * ENOSPC.
671          */
672         if (error == ENOSPC)
673                 hammer_load_spike(&cursor, spike);
674         hammer_done_cursor(&cursor);
675         return(error);
676 }
677
678 /*
679  * Write out a record using the specified cursor.  The caller does not have
680  * to seek the cursor.  The flags are used to determine whether the data
681  * (if any) is embedded in the record or not.
682  *
683  * The target cursor will be modified by this call.  Note in particular
684  * that HAMMER_CURSOR_INSERT is set.
685  */
686 int
687 hammer_write_record(hammer_cursor_t cursor, hammer_record_ondisk_t orec,
688                     void *data, int cursor_flags)
689 {
690         union hammer_btree_elm elm;
691         hammer_record_ondisk_t nrec;
692         void *bdata;
693         int error;
694
695         cursor->key_beg = orec->base.base;
696         cursor->flags |= HAMMER_CURSOR_INSERT;
697
698         /*
699          * Issue a lookup to position the cursor and locate the cluster.  The
700          * target key should not exist.
701          *
702          * If we run out of space trying to adjust the B-Tree for the
703          * insert, re-lookup without the insert flag so the cursor
704          * is properly positioned for the spike.
705          */
706         error = hammer_btree_lookup(cursor);
707         if (error == 0) {
708                 kprintf("hammer_ip_sync_record: duplicate rec at (%016llx)\n",
709                         orec->base.base.key);
710                 Debugger("duplicate record2");
711                 error = EIO;
712         }
713         if (error != ENOENT)
714                 goto done;
715
716         /*
717          * Allocate record and data space now that we know which cluster
718          * the B-Tree node ended up in.
719          */
720         if (data == NULL ||
721             (cursor_flags & HAMMER_RECF_EMBEDDED_DATA)) {
722                 bdata = data;
723         } else {
724                 bdata = hammer_alloc_data(cursor->node->cluster,
725                                           orec->base.data_len, &error,
726                                           &cursor->data_buffer);
727                 if (bdata == NULL)
728                         goto done;
729         }
730         nrec = hammer_alloc_record(cursor->node->cluster, &error,
731                                   &cursor->record_buffer);
732         if (nrec == NULL)
733                 goto fail1;
734
735         /*
736          * Fill everything in and insert our B-Tree node.
737          *
738          * XXX assign rec_id here
739          */
740         hammer_modify_buffer(cursor->record_buffer);
741         *nrec = *orec;
742         nrec->base.data_offset = 0;
743         if (bdata) {
744                 nrec->base.data_crc = crc32(bdata, nrec->base.data_len);
745                 if (cursor_flags & HAMMER_RECF_EMBEDDED_DATA) {
746                         /*
747                          * Data embedded in record
748                          */
749                         nrec->base.data_offset = ((char *)bdata - (char *)orec);
750                         KKASSERT(nrec->base.data_offset >= 0 && 
751                                  nrec->base.data_offset + nrec->base.data_len <
752                                   sizeof(*nrec));
753                         nrec->base.data_offset += hammer_bclu_offset(cursor->record_buffer, nrec);
754                 } else {
755                         /*
756                          * Data separate from record
757                          */
758                         nrec->base.data_offset = hammer_bclu_offset(cursor->data_buffer, bdata);
759                         hammer_modify_buffer(cursor->data_buffer);
760                         bcopy(data, bdata, nrec->base.data_len);
761                 }
762         }
763         nrec->base.rec_id = 0;  /* XXX */
764
765         elm.leaf.base = nrec->base.base;
766         elm.leaf.rec_offset = hammer_bclu_offset(cursor->record_buffer, nrec);
767         elm.leaf.data_offset = nrec->base.data_offset;
768         elm.leaf.data_len = nrec->base.data_len;
769         elm.leaf.data_crc = nrec->base.data_crc;
770
771         error = hammer_btree_insert(cursor, &elm);
772         if (error == 0) {
773                 hammer_update_syncid(cursor->record_buffer->cluster,
774                                      nrec->base.base.create_tid);
775                 goto done;
776         }
777
778         hammer_free_record_ptr(cursor->record_buffer, nrec);
779 fail1:
780         if (data && (cursor_flags & HAMMER_RECF_EMBEDDED_DATA) == 0) {
781                 hammer_free_data_ptr(cursor->data_buffer, bdata,
782                                      orec->base.data_len);
783         }
784 done:
785         /* leave cursor intact */
786         return(error);
787 }
788
789 /*
790  * Add the record to the inode's rec_tree.  The low 32 bits of a directory
791  * entry's key is used to deal with hash collisions in the upper 32 bits.
792  * A unique 64 bit key is generated in-memory and may be regenerated a
793  * second time when the directory record is flushed to the on-disk B-Tree.
794  *
795  * A referenced record is passed to this function.  This function
796  * eats the reference.  If an error occurs the record will be deleted.
797  */
798 static
799 int
800 hammer_mem_add(struct hammer_transaction *trans, hammer_record_t record)
801 {
802         while (RB_INSERT(hammer_rec_rb_tree, &record->ip->rec_tree, record)) {
803                 if (record->rec.base.base.rec_type != HAMMER_RECTYPE_DIRENTRY){
804                         record->flags |= HAMMER_RECF_DELETED;
805                         hammer_rel_mem_record(record);
806                         return (EEXIST);
807                 }
808                 if (++trans->hmp->namekey_iterator == 0)
809                         ++trans->hmp->namekey_iterator;
810                 record->rec.base.base.key &= ~(0xFFFFFFFFLL);
811                 record->rec.base.base.key |= trans->hmp->namekey_iterator;
812         }
813         record->flags |= HAMMER_RECF_ONRBTREE;
814         hammer_modify_inode(trans, record->ip, HAMMER_INODE_XDIRTY);
815         hammer_rel_mem_record(record);
816         return(0);
817 }
818
819 /************************************************************************
820  *                   HAMMER INODE MERGED-RECORD FUNCTIONS               *
821  ************************************************************************
822  *
823  * These functions augment the B-Tree scanning functions in hammer_btree.c
824  * by merging in-memory records with on-disk records.
825  */
826
827 /*
828  * Locate a particular record either in-memory or on-disk.
829  *
830  * NOTE: This is basically a standalone routine, hammer_ip_next() may
831  * NOT be called to iterate results.
832  */
833 int
834 hammer_ip_lookup(hammer_cursor_t cursor, struct hammer_inode *ip)
835 {
836         int error;
837
838         /*
839          * If the element is in-memory return it without searching the
840          * on-disk B-Tree
841          */
842         error = hammer_mem_lookup(cursor, ip);
843         if (error == 0) {
844                 cursor->record = &cursor->iprec->rec;
845                 return(error);
846         }
847         if (error != ENOENT)
848                 return(error);
849
850         /*
851          * If the inode has on-disk components search the on-disk B-Tree.
852          */
853         if ((ip->flags & (HAMMER_INODE_ONDISK|HAMMER_INODE_DONDISK)) == 0)
854                 return(error);
855         error = hammer_btree_lookup(cursor);
856         if (error == 0)
857                 error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_RECORD);
858         return(error);
859 }
860
861 /*
862  * Locate the first record within the cursor's key_beg/key_end range,
863  * restricted to a particular inode.  0 is returned on success, ENOENT
864  * if no records matched the requested range, or some other error.
865  *
866  * When 0 is returned hammer_ip_next() may be used to iterate additional
867  * records within the requested range.
868  */
869 int
870 hammer_ip_first(hammer_cursor_t cursor, struct hammer_inode *ip)
871 {
872         int error;
873
874         /*
875          * Clean up fields and setup for merged scan
876          */
877         cursor->flags &= ~HAMMER_CURSOR_DELBTREE;
878         cursor->flags |= HAMMER_CURSOR_ATEDISK | HAMMER_CURSOR_ATEMEM;
879         cursor->flags |= HAMMER_CURSOR_DISKEOF | HAMMER_CURSOR_MEMEOF;
880         if (cursor->iprec) {
881                 hammer_rel_mem_record(cursor->iprec);
882                 cursor->iprec = NULL;
883         }
884
885         /*
886          * Search the on-disk B-Tree.  hammer_btree_lookup() only does an
887          * exact lookup so if we get ENOENT we have to call the iterate
888          * function to validate the first record after the begin key.
889          *
890          * The ATEDISK flag is used by hammer_btree_iterate to determine
891          * whether it must index forwards or not.  It is also used here
892          * to select the next record from in-memory or on-disk.
893          */
894         if (ip->flags & (HAMMER_INODE_ONDISK|HAMMER_INODE_DONDISK)) {
895                 error = hammer_btree_lookup(cursor);
896                 if (error == ENOENT) {
897                         cursor->flags &= ~HAMMER_CURSOR_ATEDISK;
898                         error = hammer_btree_iterate(cursor);
899                 }
900                 if (error && error != ENOENT) 
901                         return(error);
902                 if (error == 0) {
903                         cursor->flags &= ~HAMMER_CURSOR_DISKEOF;
904                         cursor->flags &= ~HAMMER_CURSOR_ATEDISK;
905                 } else {
906                         cursor->flags |= HAMMER_CURSOR_ATEDISK;
907                 }
908         }
909
910         /*
911          * Search the in-memory record list (Red-Black tree).  Unlike the
912          * B-Tree search, mem_first checks for records in the range.
913          */
914         error = hammer_mem_first(cursor, ip);
915         if (error && error != ENOENT)
916                 return(error);
917         if (error == 0) {
918                 cursor->flags &= ~HAMMER_CURSOR_MEMEOF;
919                 cursor->flags &= ~HAMMER_CURSOR_ATEMEM;
920         }
921
922         /*
923          * This will return the first matching record.
924          */
925         return(hammer_ip_next(cursor));
926 }
927
928 /*
929  * Retrieve the next record in a merged iteration within the bounds of the
930  * cursor.  This call may be made multiple times after the cursor has been
931  * initially searched with hammer_ip_first().
932  *
933  * 0 is returned on success, ENOENT if no further records match the
934  * requested range, or some other error code is returned.
935  */
936 int
937 hammer_ip_next(hammer_cursor_t cursor)
938 {
939         hammer_btree_elm_t elm;
940         hammer_record_t rec;
941         int error;
942         int r;
943
944         /*
945          * Load the current on-disk and in-memory record.  If we ate any
946          * records we have to get the next one. 
947          *
948          * If we deleted the last on-disk record we had scanned ATEDISK will
949          * be clear and DELBTREE will be set, forcing a call to iterate. The
950          * fact that ATEDISK is clear causes iterate to re-test the 'current'
951          * element.  If ATEDISK is set, iterate will skip the 'current'
952          * element.
953          *
954          * Get the next on-disk record
955          */
956         if (cursor->flags & (HAMMER_CURSOR_ATEDISK|HAMMER_CURSOR_DELBTREE)) {
957                 if ((cursor->flags & HAMMER_CURSOR_DISKEOF) == 0) {
958                         error = hammer_btree_iterate(cursor);
959                         cursor->flags &= ~HAMMER_CURSOR_DELBTREE;
960                         if (error == 0)
961                                 cursor->flags &= ~HAMMER_CURSOR_ATEDISK;
962                         else
963                                 cursor->flags |= HAMMER_CURSOR_DISKEOF |
964                                                  HAMMER_CURSOR_ATEDISK;
965                 }
966         }
967
968         /*
969          * Get the next in-memory record.  The record can be ripped out
970          * of the RB tree so we maintain a scan_info structure to track
971          * the next node.
972          *
973          * hammer_rec_scan_cmp:  Is the record still in our general range,
974          *                       (non-inclusive of snapshot exclusions)?
975          * hammer_rec_scan_callback: Is the record in our snapshot?
976          */
977         if (cursor->flags & HAMMER_CURSOR_ATEMEM) {
978                 if ((cursor->flags & HAMMER_CURSOR_MEMEOF) == 0) {
979                         if (cursor->iprec) {
980                                 hammer_rel_mem_record(cursor->iprec);
981                                 cursor->iprec = NULL;
982                         }
983                         rec = cursor->scan.node;        /* next node */
984                         while (rec) {
985                                 if (hammer_rec_scan_cmp(rec, cursor) != 0)
986                                         break;
987                                 if (hammer_rec_scan_callback(rec, cursor) != 0)
988                                         break;
989                                 rec = hammer_rec_rb_tree_RB_NEXT(rec);
990                         }
991                         if (cursor->iprec) {
992                                 KKASSERT(cursor->iprec == rec);
993                                 cursor->flags &= ~HAMMER_CURSOR_ATEMEM;
994                                 cursor->scan.node =
995                                         hammer_rec_rb_tree_RB_NEXT(rec);
996                         } else {
997                                 cursor->flags |= HAMMER_CURSOR_MEMEOF;
998                         }
999                 }
1000         }
1001
1002         /*
1003          * Extract either the disk or memory record depending on their
1004          * relative position.
1005          */
1006         error = 0;
1007         switch(cursor->flags & (HAMMER_CURSOR_ATEDISK | HAMMER_CURSOR_ATEMEM)) {
1008         case 0:
1009                 /*
1010                  * Both entries valid
1011                  */
1012                 elm = &cursor->node->ondisk->elms[cursor->index];
1013                 r = hammer_btree_cmp(&elm->base, &cursor->iprec->rec.base.base);
1014                 if (r < 0) {
1015                         error = hammer_btree_extract(cursor,
1016                                                      HAMMER_CURSOR_GET_RECORD);
1017                         cursor->flags |= HAMMER_CURSOR_ATEDISK;
1018                         break;
1019                 }
1020                 /* fall through to the memory entry */
1021         case HAMMER_CURSOR_ATEDISK:
1022                 /*
1023                  * Only the memory entry is valid
1024                  */
1025                 cursor->record = &cursor->iprec->rec;
1026                 cursor->flags |= HAMMER_CURSOR_ATEMEM;
1027                 break;
1028         case HAMMER_CURSOR_ATEMEM:
1029                 /*
1030                  * Only the disk entry is valid
1031                  */
1032                 error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_RECORD);
1033                 cursor->flags |= HAMMER_CURSOR_ATEDISK;
1034                 break;
1035         default:
1036                 /*
1037                  * Neither entry is valid
1038                  *
1039                  * XXX error not set properly
1040                  */
1041                 cursor->record = NULL;
1042                 error = ENOENT;
1043                 break;
1044         }
1045         return(error);
1046 }
1047
1048 /*
1049  * Resolve the cursor->data pointer for the current cursor position in
1050  * a merged iteration.
1051  */
1052 int
1053 hammer_ip_resolve_data(hammer_cursor_t cursor)
1054 {
1055         int error;
1056
1057         if (cursor->iprec && cursor->record == &cursor->iprec->rec) {
1058                 cursor->data = cursor->iprec->data;
1059                 error = 0;
1060         } else {
1061                 error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_DATA);
1062         }
1063         return(error);
1064 }
1065
1066 /*
1067  * Delete all records within the specified range for inode ip.
1068  *
1069  * NOTE: An unaligned range will cause new records to be added to cover
1070  * the edge cases. (XXX not implemented yet).
1071  *
1072  * NOTE: ran_end is inclusive (e.g. 0,1023 instead of 0,1024).
1073  *
1074  * NOTE: Record keys for regular file data have to be special-cased since
1075  * they indicate the end of the range (key = base + bytes).
1076  *
1077  * NOTE: The spike structure must be filled in if we return ENOSPC.
1078  */
1079 int
1080 hammer_ip_delete_range(hammer_transaction_t trans, hammer_inode_t ip,
1081                        int64_t ran_beg, int64_t ran_end,
1082                        struct hammer_cursor **spike)
1083 {
1084         struct hammer_cursor cursor;
1085         hammer_record_ondisk_t rec;
1086         hammer_base_elm_t base;
1087         int error;
1088         int64_t off;
1089
1090         hammer_init_cursor_hmp(&cursor, &ip->cache[0], ip->hmp);
1091
1092         cursor.key_beg.obj_id = ip->obj_id;
1093         cursor.key_beg.create_tid = ip->obj_asof;
1094         cursor.key_beg.delete_tid = 0;
1095         cursor.key_beg.obj_type = 0;
1096
1097         cursor.key_end = cursor.key_beg;
1098         if (ip->ino_rec.base.base.obj_type == HAMMER_OBJTYPE_DBFILE) {
1099                 cursor.key_beg.key = ran_beg;
1100                 cursor.key_beg.rec_type = HAMMER_RECTYPE_DB;
1101                 cursor.key_end.rec_type = HAMMER_RECTYPE_DB;
1102                 cursor.key_end.key = ran_end;
1103         } else {
1104                 /*
1105                  * The key in the B-Tree is (base+bytes), so the first possible
1106                  * matching key is ran_beg + 1.
1107                  */
1108                 int64_t tmp64;
1109
1110                 cursor.key_beg.key = ran_beg + 1;
1111                 cursor.key_beg.rec_type = HAMMER_RECTYPE_DATA;
1112                 cursor.key_end.rec_type = HAMMER_RECTYPE_DATA;
1113
1114                 tmp64 = ran_end + MAXPHYS + 1;  /* work around GCC-4 bug */
1115                 if (tmp64 < ran_end)
1116                         cursor.key_end.key = 0x7FFFFFFFFFFFFFFFLL;
1117                 else
1118                         cursor.key_end.key = ran_end + MAXPHYS + 1;
1119         }
1120         cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
1121
1122         error = hammer_ip_first(&cursor, ip);
1123
1124         /*
1125          * Iterate through matching records and mark them as deleted.
1126          */
1127         while (error == 0) {
1128                 rec = cursor.record;
1129                 base = &rec->base.base;
1130
1131                 KKASSERT(base->delete_tid == 0);
1132
1133                 /*
1134                  * There may be overlap cases for regular file data.  Also
1135                  * remember the key for a regular file record is the offset
1136                  * of the last byte of the record (base + len - 1), NOT the
1137                  * base offset.
1138                  */
1139 #if 0
1140                 kprintf("delete_range rec_type %02x\n", base->rec_type);
1141 #endif
1142                 if (base->rec_type == HAMMER_RECTYPE_DATA) {
1143 #if 0
1144                         kprintf("delete_range loop key %016llx\n",
1145                                 base->key - rec->base.data_len);
1146 #endif
1147                         off = base->key - rec->base.data_len;
1148                         /*
1149                          * Check the left edge case.  We currently do not
1150                          * split existing records.
1151                          */
1152                         if (off < ran_beg) {
1153                                 panic("hammer left edge case %016llx %d\n",
1154                                         base->key, rec->base.data_len);
1155                         }
1156
1157                         /*
1158                          * Check the right edge case.  Note that the
1159                          * record can be completely out of bounds, which
1160                          * terminates the search.
1161                          *
1162                          * base->key is exclusive of the right edge while
1163                          * ran_end is inclusive of the right edge.  The
1164                          * (key - data_len) left boundary is inclusive.
1165                          *
1166                          * XXX theory-check this test at some point, are
1167                          * we missing a + 1 somewhere?  Note that ran_end
1168                          * could overflow.
1169                          */
1170                         if (base->key - 1 > ran_end) {
1171                                 if (base->key - rec->base.data_len > ran_end)
1172                                         break;
1173                                 panic("hammer right edge case\n");
1174                         }
1175                 }
1176
1177                 /*
1178                  * Mark the record and B-Tree entry as deleted.  This will
1179                  * also physically delete the B-Tree entry, record, and
1180                  * data if the retention policy dictates.  The function
1181                  * will set HAMMER_CURSOR_DELBTREE which hammer_ip_next()
1182                  * uses to perform a fixup.
1183                  */
1184                 error = hammer_ip_delete_record(&cursor, trans->tid);
1185                 if (error)
1186                         break;
1187                 error = hammer_ip_next(&cursor);
1188         }
1189         hammer_done_cursor(&cursor);
1190         if (error == ENOENT)
1191                 error = 0;
1192         return(error);
1193 }
1194
1195 /*
1196  * Delete all records associated with an inode except the inode record
1197  * itself.
1198  */
1199 int
1200 hammer_ip_delete_range_all(hammer_transaction_t trans, hammer_inode_t ip)
1201 {
1202         struct hammer_cursor cursor;
1203         hammer_record_ondisk_t rec;
1204         hammer_base_elm_t base;
1205         int error;
1206
1207         hammer_init_cursor_hmp(&cursor, &ip->cache[0], ip->hmp);
1208
1209         cursor.key_beg.obj_id = ip->obj_id;
1210         cursor.key_beg.create_tid = ip->obj_asof;
1211         cursor.key_beg.delete_tid = 0;
1212         cursor.key_beg.obj_type = 0;
1213         cursor.key_beg.rec_type = HAMMER_RECTYPE_INODE + 1;
1214         cursor.key_beg.key = HAMMER_MIN_KEY;
1215
1216         cursor.key_end = cursor.key_beg;
1217         cursor.key_end.rec_type = 0xFFFF;
1218         cursor.key_end.key = HAMMER_MAX_KEY;
1219
1220         cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
1221
1222         error = hammer_ip_first(&cursor, ip);
1223
1224         /*
1225          * Iterate through matching records and mark them as deleted.
1226          */
1227         while (error == 0) {
1228                 rec = cursor.record;
1229                 base = &rec->base.base;
1230
1231                 KKASSERT(base->delete_tid == 0);
1232
1233                 /*
1234                  * Mark the record and B-Tree entry as deleted.  This will
1235                  * also physically delete the B-Tree entry, record, and
1236                  * data if the retention policy dictates.  The function
1237                  * will set HAMMER_CURSOR_DELBTREE which hammer_ip_next()
1238                  * uses to perform a fixup.
1239                  */
1240                 error = hammer_ip_delete_record(&cursor, trans->tid);
1241                 if (error)
1242                         break;
1243                 error = hammer_ip_next(&cursor);
1244         }
1245         hammer_done_cursor(&cursor);
1246         if (error == ENOENT)
1247                 error = 0;
1248         return(error);
1249 }
1250
1251 /*
1252  * Delete the record at the current cursor
1253  */
1254 int
1255 hammer_ip_delete_record(hammer_cursor_t cursor, hammer_tid_t tid)
1256 {
1257         hammer_btree_elm_t elm;
1258         hammer_mount_t hmp;
1259         int error;
1260
1261         /*
1262          * In-memory (unsynchronized) records can simply be freed.
1263          */
1264         if (cursor->record == &cursor->iprec->rec) {
1265                 cursor->iprec->flags |= HAMMER_RECF_DELETED;
1266                 return(0);
1267         }
1268
1269         /*
1270          * On-disk records are marked as deleted by updating their delete_tid.
1271          */
1272         error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_RECORD);
1273         elm = NULL;
1274         hmp = cursor->node->cluster->volume->hmp;
1275
1276         if (error == 0) {
1277                 hammer_modify_buffer(cursor->record_buffer);
1278                 cursor->record->base.base.delete_tid = tid;
1279
1280                 hammer_modify_node(cursor->node);
1281                 elm = &cursor->node->ondisk->elms[cursor->index];
1282                 elm->leaf.base.delete_tid = tid;
1283                 hammer_update_syncid(cursor->record_buffer->cluster, tid);
1284         }
1285
1286         /*
1287          * If we were mounted with the nohistory option, we physically
1288          * delete the record.
1289          */
1290         if (error == 0 && (hmp->hflags & HMNT_NOHISTORY)) {
1291                 int32_t rec_offset;
1292                 int32_t data_offset;
1293                 int32_t data_len;
1294                 hammer_cluster_t cluster;
1295
1296                 rec_offset = elm->leaf.rec_offset;
1297                 data_offset = elm->leaf.data_offset;
1298                 data_len = elm->leaf.data_len;
1299 #if 0
1300                 kprintf("hammer_ip_delete_record: %08x %08x/%d\n",
1301                         rec_offset, data_offset, data_len);
1302 #endif
1303                 cluster = cursor->node->cluster;
1304                 hammer_ref_cluster(cluster);
1305
1306                 error = hammer_btree_delete(cursor);
1307                 if (error == 0) {
1308                         /*
1309                          * This forces a fixup for the iteration because
1310                          * the cursor is now either sitting at the 'next'
1311                          * element or sitting at the end of a leaf.
1312                          */
1313                         if ((cursor->flags & HAMMER_CURSOR_DISKEOF) == 0) {
1314                                 cursor->flags |= HAMMER_CURSOR_DELBTREE;
1315                                 cursor->flags &= ~HAMMER_CURSOR_ATEDISK;
1316                         }
1317                         hammer_free_record(cluster, rec_offset);
1318                         if (data_offset && (data_offset - rec_offset < 0 ||
1319                             data_offset - rec_offset >= HAMMER_RECORD_SIZE)) {
1320                                 hammer_free_data(cluster, data_offset,data_len);
1321                         }
1322                 }
1323                 hammer_rel_cluster(cluster, 0);
1324                 if (error) {
1325                         panic("hammer_ip_delete_record: unable to physically delete the record!\n");
1326                         error = 0;
1327                 }
1328         }
1329         return(error);
1330 }
1331
1332 /*
1333  * Determine whether a directory is empty or not.  Returns 0 if the directory
1334  * is empty, ENOTEMPTY if it isn't, plus other possible errors.
1335  */
1336 int
1337 hammer_ip_check_directory_empty(hammer_transaction_t trans, hammer_inode_t ip)
1338 {
1339         struct hammer_cursor cursor;
1340         int error;
1341
1342         hammer_init_cursor_hmp(&cursor, &ip->cache[0], ip->hmp);
1343
1344         cursor.key_beg.obj_id = ip->obj_id;
1345         cursor.key_beg.create_tid = ip->obj_asof;
1346         cursor.key_beg.delete_tid = 0;
1347         cursor.key_beg.obj_type = 0;
1348         cursor.key_beg.rec_type = HAMMER_RECTYPE_INODE + 1;
1349         cursor.key_beg.key = HAMMER_MIN_KEY;
1350
1351         cursor.key_end = cursor.key_beg;
1352         cursor.key_end.rec_type = 0xFFFF;
1353         cursor.key_end.key = HAMMER_MAX_KEY;
1354
1355         cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
1356
1357         error = hammer_ip_first(&cursor, ip);
1358         if (error == ENOENT)
1359                 error = 0;
1360         else if (error == 0)
1361                 error = ENOTEMPTY;
1362         hammer_done_cursor(&cursor);
1363         return(error);
1364 }
1365