xref: /dragonfly/sys/vfs/hammer2/hammer2_xops.c (revision 265a1428)
1 /*
2  * Copyright (c) 2011-2018 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@dragonflybsd.org>
6  * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
7  * by Daniel Flores (GSOC 2013 - mentored by Matthew Dillon, compression)
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  * 3. Neither the name of The DragonFly Project nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific, prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
27  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 /*
37  * Per-node backend for kernel filesystem interface.
38  *
39  * This executes a VOP concurrently on multiple nodes, each node via its own
40  * thread, and competes to advance the original request.  The original
41  * request is retired the moment all requirements are met, even if the
42  * operation is still in-progress on some nodes.
43  */
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/fcntl.h>
48 #include <sys/buf.h>
49 #include <sys/proc.h>
50 #include <sys/namei.h>
51 #include <sys/mount.h>
52 #include <sys/vnode.h>
53 #include <sys/mountctl.h>
54 #include <sys/dirent.h>
55 #include <sys/uio.h>
56 #include <sys/objcache.h>
57 #include <sys/event.h>
58 #include <sys/file.h>
59 #include <vfs/fifofs/fifo.h>
60 
61 #include "hammer2.h"
62 
63 /*
64  * Determine if the specified directory is empty.
65  *
66  *	Returns 0 on success.
67  *
68  *	Returns HAMMER_ERROR_EAGAIN if caller must re-lookup the entry and
69  *	retry. (occurs if we race a ripup on oparent or ochain).
70  *
71  *	Or returns a permanent HAMMER2_ERROR_* error mask.
72  *
73  * The caller must pass in an exclusively locked oparent and ochain.  This
74  * function will handle the case where the chain is a directory entry or
75  * the inode itself.  The original oparent,ochain will be locked upon return.
76  *
77  * This function will unlock the underlying oparent,ochain temporarily when
78  * doing an inode lookup to avoid deadlocks.  The caller MUST handle the EAGAIN
79  * result as this means that oparent is no longer the parent of ochain, or
80  * that ochain was destroyed while it was unlocked.
81  */
82 static
83 int
84 checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex)
85 {
86 	hammer2_chain_t *parent;
87 	hammer2_chain_t *chain;
88 	hammer2_key_t key_next;
89 	hammer2_key_t inum;
90 	int error;
91 	int didunlock;
92 
93 	error = 0;
94 	didunlock = 0;
95 
96 	/*
97 	 * Find the inode, set it up as a locked 'chain'.  ochain can be the
98 	 * inode itself, or it can be a directory entry.
99 	 */
100 	if (ochain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
101 		inum = ochain->bref.embed.dirent.inum;
102 		hammer2_chain_unlock(ochain);
103 		hammer2_chain_unlock(oparent);
104 
105 		parent = NULL;
106 		chain = NULL;
107 		error = hammer2_chain_inode_find(ochain->pmp, inum,
108 						 clindex, 0,
109 						 &parent, &chain);
110 		if (parent) {
111 			hammer2_chain_unlock(parent);
112 			hammer2_chain_drop(parent);
113 		}
114 		didunlock = 1;
115 	} else {
116 		/*
117 		 * The directory entry *is* the directory inode
118 		 */
119 		chain = hammer2_chain_lookup_init(ochain, 0);
120 	}
121 
122 	/*
123 	 * Determine if the directory is empty or not by checking its
124 	 * visible namespace (the area which contains directory entries).
125 	 */
126 	if (error == 0) {
127 		parent = chain;
128 		chain = NULL;
129 		if (parent) {
130 			chain = hammer2_chain_lookup(&parent, &key_next,
131 						     HAMMER2_DIRHASH_VISIBLE,
132 						     HAMMER2_KEY_MAX,
133 						     &error, 0);
134 		}
135 		if (chain) {
136 			error = HAMMER2_ERROR_ENOTEMPTY;
137 			hammer2_chain_unlock(chain);
138 			hammer2_chain_drop(chain);
139 		}
140 		hammer2_chain_lookup_done(parent);
141 	}
142 
143 	if (didunlock) {
144 		hammer2_chain_lock(oparent, HAMMER2_RESOLVE_ALWAYS);
145 		hammer2_chain_lock(ochain, HAMMER2_RESOLVE_ALWAYS);
146 		if ((ochain->flags & HAMMER2_CHAIN_DELETED) ||
147 		    (oparent->flags & HAMMER2_CHAIN_DELETED) ||
148 		    ochain->parent != oparent) {
149 			kprintf("hammer2: debug: CHECKDIR inum %jd RETRY\n",
150 				inum);
151 			error = HAMMER2_ERROR_EAGAIN;
152 		}
153 	}
154 	return error;
155 }
156 
157 /*
158  * Backend for hammer2_vfs_root()
159  *
160  * This is called when a newly mounted PFS has not yet synchronized
161  * to the inode_tid and modify_tid.
162  */
163 void
164 hammer2_xop_ipcluster(hammer2_xop_t *arg, void *scratch, int clindex)
165 {
166 	hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
167 	hammer2_chain_t *chain;
168 	int error;
169 
170 	chain = hammer2_inode_chain(xop->head.ip1, clindex,
171 				    HAMMER2_RESOLVE_ALWAYS |
172 				    HAMMER2_RESOLVE_SHARED);
173 	if (chain)
174 		error = chain->error;
175 	else
176 		error = HAMMER2_ERROR_EIO;
177 
178 	hammer2_xop_feed(&xop->head, chain, clindex, error);
179 	if (chain) {
180 		hammer2_chain_unlock(chain);
181 		hammer2_chain_drop(chain);
182 	}
183 }
184 
185 /*
186  * Backend for hammer2_vop_readdir()
187  */
188 void
189 hammer2_xop_readdir(hammer2_xop_t *arg, void *scratch, int clindex)
190 {
191 	hammer2_xop_readdir_t *xop = &arg->xop_readdir;
192 	hammer2_chain_t *parent;
193 	hammer2_chain_t *chain;
194 	hammer2_key_t key_next;
195 	hammer2_key_t lkey;
196 	int error = 0;
197 
198 	lkey = xop->lkey;
199 	if (hammer2_debug & 0x0020)
200 		kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
201 
202 	/*
203 	 * The inode's chain is the iterator.  If we cannot acquire it our
204 	 * contribution ends here.
205 	 */
206 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
207 				     HAMMER2_RESOLVE_ALWAYS |
208 				     HAMMER2_RESOLVE_SHARED);
209 	if (parent == NULL) {
210 		kprintf("xop_readdir: NULL parent\n");
211 		goto done;
212 	}
213 
214 	/*
215 	 * Directory scan [re]start and loop, the feed inherits the chain's
216 	 * lock so do not unlock it on the iteration.
217 	 */
218 	chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
219 				     &error, HAMMER2_LOOKUP_SHARED);
220 	if (chain == NULL) {
221 		chain = hammer2_chain_lookup(&parent, &key_next,
222 					     lkey, HAMMER2_KEY_MAX,
223 					     &error, HAMMER2_LOOKUP_SHARED);
224 	}
225 	while (chain) {
226 		error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
227 		if (error)
228 			goto break2;
229 		chain = hammer2_chain_next(&parent, chain, &key_next,
230 					   key_next, HAMMER2_KEY_MAX,
231 					   &error, HAMMER2_LOOKUP_SHARED);
232 	}
233 break2:
234 	if (chain) {
235 		hammer2_chain_unlock(chain);
236 		hammer2_chain_drop(chain);
237 	}
238 	hammer2_chain_unlock(parent);
239 	hammer2_chain_drop(parent);
240 done:
241 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
242 }
243 
244 /*
245  * Backend for hammer2_vop_nresolve()
246  */
247 void
248 hammer2_xop_nresolve(hammer2_xop_t *arg, void *scratch, int clindex)
249 {
250 	hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
251 	hammer2_chain_t *parent;
252 	hammer2_chain_t *chain;
253 	const char *name;
254 	size_t name_len;
255 	hammer2_key_t key_next;
256 	hammer2_key_t lhc;
257 	int error;
258 
259 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
260 				     HAMMER2_RESOLVE_ALWAYS |
261 				     HAMMER2_RESOLVE_SHARED);
262 	if (parent == NULL) {
263 		kprintf("xop_nresolve: NULL parent\n");
264 		chain = NULL;
265 		error = HAMMER2_ERROR_EIO;
266 		goto done;
267 	}
268 	name = xop->head.name1;
269 	name_len = xop->head.name1_len;
270 
271 	/*
272 	 * Lookup the directory entry
273 	 */
274 	lhc = hammer2_dirhash(name, name_len);
275 	chain = hammer2_chain_lookup(&parent, &key_next,
276 				     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
277 				     &error,
278 				     HAMMER2_LOOKUP_ALWAYS |
279 				     HAMMER2_LOOKUP_SHARED);
280 	while (chain) {
281 		if (hammer2_chain_dirent_test(chain, name, name_len))
282 			break;
283 		chain = hammer2_chain_next(&parent, chain, &key_next,
284 					   key_next,
285 					   lhc + HAMMER2_DIRHASH_LOMASK,
286 					   &error,
287 					   HAMMER2_LOOKUP_ALWAYS |
288 					   HAMMER2_LOOKUP_SHARED);
289 	}
290 
291 	/*
292 	 * Locate the target inode for a directory entry
293 	 */
294 	if (chain && chain->error == 0) {
295 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
296 			lhc = chain->bref.embed.dirent.inum;
297 			error = hammer2_chain_inode_find(chain->pmp,
298 							 lhc,
299 							 clindex,
300 							 HAMMER2_LOOKUP_SHARED,
301 							 &parent,
302 							 &chain);
303 		}
304 	} else if (chain && error == 0) {
305 		error = chain->error;
306 	}
307 done:
308 	error = hammer2_xop_feed(&xop->head, chain, clindex, error);
309 	if (chain) {
310 		hammer2_chain_unlock(chain);
311 		hammer2_chain_drop(chain);
312 	}
313 	if (parent) {
314 		hammer2_chain_unlock(parent);
315 		hammer2_chain_drop(parent);
316 	}
317 }
318 
319 /*
320  * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and
321  * backend for pfs_delete.
322  *
323  * This function locates and removes a directory entry, and will lookup
324  * and return the underlying inode.  For directory entries the underlying
325  * inode is not removed.  If the directory entry is the actual inode itself,
326  * it may be conditonally removed and returned.
327  *
328  * WARNING!  Any target inode's nlinks may not be synchronized to the
329  *	     in-memory inode.  The frontend's hammer2_inode_unlink_finisher()
330  *	     is responsible for the final disposition of the actual inode.
331  */
332 void
333 hammer2_xop_unlink(hammer2_xop_t *arg, void *scratch, int clindex)
334 {
335 	hammer2_xop_unlink_t *xop = &arg->xop_unlink;
336 	hammer2_chain_t *parent;
337 	hammer2_chain_t *chain;
338 	const char *name;
339 	size_t name_len;
340 	hammer2_key_t key_next;
341 	hammer2_key_t lhc;
342 	int error;
343 
344 again:
345 	/*
346 	 * Requires exclusive lock
347 	 */
348 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
349 				     HAMMER2_RESOLVE_ALWAYS);
350 	chain = NULL;
351 	if (parent == NULL) {
352 		kprintf("xop_nresolve: NULL parent\n");
353 		error = HAMMER2_ERROR_EIO;
354 		goto done;
355 	}
356 	name = xop->head.name1;
357 	name_len = xop->head.name1_len;
358 
359 	/*
360 	 * Lookup the directory entry
361 	 */
362 	lhc = hammer2_dirhash(name, name_len);
363 	chain = hammer2_chain_lookup(&parent, &key_next,
364 				     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
365 				     &error, HAMMER2_LOOKUP_ALWAYS);
366 	while (chain) {
367 		if (hammer2_chain_dirent_test(chain, name, name_len))
368 			break;
369 		chain = hammer2_chain_next(&parent, chain, &key_next,
370 					   key_next,
371 					   lhc + HAMMER2_DIRHASH_LOMASK,
372 					   &error, HAMMER2_LOOKUP_ALWAYS);
373 	}
374 
375 	/*
376 	 * The directory entry will either be a BREF_TYPE_DIRENT or a
377 	 * BREF_TYPE_INODE.  We always permanently delete DIRENTs, but
378 	 * must go by xop->dopermanent for BREF_TYPE_INODE.
379 	 *
380 	 * Note that the target chain's nlinks may not be synchronized with
381 	 * the in-memory hammer2_inode_t structure, so we don't try to do
382 	 * anything fancy here.  The frontend deals with nlinks
383 	 * synchronization.
384 	 */
385 	if (chain && chain->error == 0) {
386 		int dopermanent = xop->dopermanent & H2DOPERM_PERMANENT;
387 		int doforce = xop->dopermanent & H2DOPERM_FORCE;
388 		uint8_t type;
389 
390 		/*
391 		 * If the directory entry is the actual inode then use its
392 		 * type for the directory typing tests, otherwise if it is
393 		 * a directory entry, pull the type field from the entry.
394 		 *
395 		 * Directory entries are always permanently deleted
396 		 * (because they aren't the actual inode).
397 		 */
398 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
399 			type = chain->bref.embed.dirent.type;
400 			dopermanent |= HAMMER2_DELETE_PERMANENT;
401 		} else {
402 			type = chain->data->ipdata.meta.type;
403 		}
404 
405 		/*
406 		 * Check directory typing and delete the entry.  Note that
407 		 * nlinks adjustments are made on the real inode by the
408 		 * frontend, not here.
409 		 *
410 		 * Unfortunately, checkdirempty() may have to unlock (parent).
411 		 * If it no longer matches chain->parent after re-locking,
412 		 * EAGAIN is returned.
413 		 */
414 		if (type == HAMMER2_OBJTYPE_DIRECTORY && doforce) {
415 			/*
416 			 * If doforce then execute the operation even if
417 			 * the directory is not empty or errored.  We
418 			 * ignore chain->error here, allowing an errored
419 			 * chain (aka directory entry) to still be deleted.
420 			 */
421 			error = hammer2_chain_delete(parent, chain,
422 					     xop->head.mtid, dopermanent);
423 		} else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
424 			   (error = checkdirempty(parent, chain, clindex)) != 0) {
425 			/*
426 			 * error may be EAGAIN or ENOTEMPTY
427 			 */
428 			if (error == HAMMER2_ERROR_EAGAIN) {
429 				hammer2_chain_unlock(chain);
430 				hammer2_chain_drop(chain);
431 				hammer2_chain_unlock(parent);
432 				hammer2_chain_drop(parent);
433 				goto again;
434 			}
435 		} else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
436 		    xop->isdir == 0) {
437 			error = HAMMER2_ERROR_EISDIR;
438 		} else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
439 			   xop->isdir >= 1) {
440 			error = HAMMER2_ERROR_ENOTDIR;
441 		} else {
442 			/*
443 			 * Delete the directory entry.  chain might also
444 			 * be a directly-embedded inode.
445 			 *
446 			 * Allow the deletion to proceed even if the chain
447 			 * is errored.  Give priority to error-on-delete over
448 			 * chain->error.
449 			 */
450 			error = hammer2_chain_delete(parent, chain,
451 						     xop->head.mtid,
452 						     dopermanent);
453 			if (error == 0)
454 				error = chain->error;
455 		}
456 	} else {
457 		if (chain && error == 0)
458 			error = chain->error;
459 	}
460 
461 	/*
462 	 * If chain is a directory entry we must resolve it.  We do not try
463 	 * to manipulate the contents as it might not be synchronized with
464 	 * the frontend hammer2_inode_t, nor do we try to lookup the
465 	 * frontend hammer2_inode_t here (we are the backend!).
466 	 */
467 	if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT &&
468 	    (xop->dopermanent & H2DOPERM_IGNINO) == 0) {
469 		int error2;
470 
471 		lhc = chain->bref.embed.dirent.inum;
472 
473 		error2 = hammer2_chain_inode_find(chain->pmp, lhc,
474 						  clindex, 0,
475 						  &parent, &chain);
476 		if (error2) {
477 			kprintf("inode_find: %016jx %p failed\n",
478 				lhc, chain);
479 			error2 = 0;	/* silently ignore */
480 		}
481 		if (error == 0)
482 			error = error2;
483 	}
484 
485 	/*
486 	 * Return the inode target for further action.  Typically used by
487 	 * hammer2_inode_unlink_finisher().
488 	 */
489 done:
490 	hammer2_xop_feed(&xop->head, chain, clindex, error);
491 	if (chain) {
492 		hammer2_chain_unlock(chain);
493 		hammer2_chain_drop(chain);
494 		chain = NULL;
495 	}
496 	if (parent) {
497 		hammer2_chain_unlock(parent);
498 		hammer2_chain_drop(parent);
499 		parent = NULL;
500 	}
501 }
502 
503 /*
504  * Backend for hammer2_vop_nrename()
505  *
506  * This handles the backend rename operation.  Typically this renames
507  * directory entries but can also be used to rename embedded inodes.
508  *
509  * NOTE! The frontend is responsible for updating the inode meta-data in
510  *	 the file being renamed and for decrementing the target-replaced
511  *	 inode's nlinks, if present.
512  */
513 void
514 hammer2_xop_nrename(hammer2_xop_t *arg, void *scratch, int clindex)
515 {
516 	hammer2_xop_nrename_t *xop = &arg->xop_nrename;
517 	hammer2_pfs_t *pmp;
518 	hammer2_chain_t *parent;
519 	hammer2_chain_t *chain;
520 	hammer2_chain_t *tmp;
521 	hammer2_inode_t *ip;
522 	hammer2_key_t key_next;
523 	int error;
524 
525 	/*
526 	 * We need the precise parent chain to issue the deletion.
527 	 *
528 	 * If this is a directory entry we must locate the underlying
529 	 * inode.  If it is an embedded inode we can act directly on it.
530 	 */
531 	ip = xop->head.ip2;
532 	pmp = ip->pmp;
533 	chain = NULL;
534 	error = 0;
535 
536 	if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
537 		/*
538 		 * Find ip's direct parent chain.
539 		 */
540 		chain = hammer2_inode_chain(ip, clindex,
541 					    HAMMER2_RESOLVE_ALWAYS);
542 		if (chain == NULL) {
543 			error = HAMMER2_ERROR_EIO;
544 			parent = NULL;
545 			goto done;
546 		}
547 		if (ip->flags & HAMMER2_INODE_CREATING) {
548 			parent = NULL;
549 		} else {
550 			parent = hammer2_chain_getparent(chain,
551 						    HAMMER2_RESOLVE_ALWAYS);
552 			if (parent == NULL) {
553 				error = HAMMER2_ERROR_EIO;
554 				goto done;
555 			}
556 		}
557 	} else {
558 		/*
559 		 * The directory entry for the head.ip1 inode
560 		 * is in fdip, do a namespace search.
561 		 */
562 		hammer2_key_t lhc;
563 		const char *name;
564 		size_t name_len;
565 
566 		parent = hammer2_inode_chain(xop->head.ip1, clindex,
567 					     HAMMER2_RESOLVE_ALWAYS);
568 		if (parent == NULL) {
569 			kprintf("xop_nrename: NULL parent\n");
570 			error = HAMMER2_ERROR_EIO;
571 			goto done;
572 		}
573 		name = xop->head.name1;
574 		name_len = xop->head.name1_len;
575 
576 		/*
577 		 * Lookup the directory entry
578 		 */
579 		lhc = hammer2_dirhash(name, name_len);
580 		chain = hammer2_chain_lookup(&parent, &key_next,
581 					     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
582 					     &error, HAMMER2_LOOKUP_ALWAYS);
583 		while (chain) {
584 			if (hammer2_chain_dirent_test(chain, name, name_len))
585 				break;
586 			chain = hammer2_chain_next(&parent, chain, &key_next,
587 						   key_next,
588 						   lhc + HAMMER2_DIRHASH_LOMASK,
589 						   &error,
590 						   HAMMER2_LOOKUP_ALWAYS);
591 		}
592 	}
593 
594 	if (chain == NULL) {
595 		/* XXX shouldn't happen, but does under fsstress */
596 		kprintf("hammer2_xop_rename: \"%s\" -> \"%s\"  ENOENT\n",
597 			xop->head.name1,
598 			xop->head.name2);
599 		if (error == 0)
600 			error = HAMMER2_ERROR_ENOENT;
601 		goto done;
602 	}
603 
604 	if (chain->error) {
605 		error = chain->error;
606 		goto done;
607 	}
608 
609 	/*
610 	 * Delete it, then create it in the new namespace.
611 	 *
612 	 * An error can occur if the chain being deleted requires
613 	 * modification and the media is full.
614 	 */
615 	error = hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
616 	hammer2_chain_unlock(parent);
617 	hammer2_chain_drop(parent);
618 	parent = NULL;		/* safety */
619 	if (error)
620 		goto done;
621 
622 	/*
623 	 * Adjust fields in the deleted chain appropriate for the rename
624 	 * operation.
625 	 *
626 	 * NOTE! For embedded inodes, the frontend will officially replicate
627 	 *	 the field adjustments, but we also do it here to maintain
628 	 *	 consistency in case of a crash.
629 	 */
630 	if (chain->bref.key != xop->lhc ||
631 	    xop->head.name1_len != xop->head.name2_len ||
632 	    bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
633 		if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
634 			hammer2_inode_data_t *wipdata;
635 
636 			error = hammer2_chain_modify(chain, xop->head.mtid,
637 						     0, 0);
638 			if (error == 0) {
639 				wipdata = &chain->data->ipdata;
640 
641 				bzero(wipdata->filename,
642 				      sizeof(wipdata->filename));
643 				bcopy(xop->head.name2,
644 				      wipdata->filename,
645 				      xop->head.name2_len);
646 				wipdata->meta.name_key = xop->lhc;
647 				wipdata->meta.name_len = xop->head.name2_len;
648 			}
649 		}
650 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
651 			if (xop->head.name2_len <=
652 			    sizeof(chain->bref.check.buf)) {
653 				/*
654 				 * Remove any related data buffer, we can
655 				 * embed the filename in the bref itself.
656 				 */
657 				error = hammer2_chain_resize(
658 						chain, xop->head.mtid, 0, 0, 0);
659 				if (error == 0) {
660 					error = hammer2_chain_modify(
661 							chain, xop->head.mtid,
662 							0, 0);
663 				}
664 				if (error == 0) {
665 					bzero(chain->bref.check.buf,
666 					      sizeof(chain->bref.check.buf));
667 					bcopy(xop->head.name2,
668 					      chain->bref.check.buf,
669 					      xop->head.name2_len);
670 				}
671 			} else {
672 				/*
673 				 * Associate a data buffer with the bref.
674 				 * Zero it for consistency.  Note that the
675 				 * data buffer is not 64KB so use chain->bytes
676 				 * instead of sizeof().
677 				 */
678 				error = hammer2_chain_resize(
679 					chain, xop->head.mtid, 0,
680 					hammer2_getradix(HAMMER2_ALLOC_MIN), 0);
681 				if (error == 0) {
682 					error = hammer2_chain_modify(
683 						    chain, xop->head.mtid,
684 						    0, 0);
685 				}
686 				if (error == 0) {
687 					bzero(chain->data->buf, chain->bytes);
688 					bcopy(xop->head.name2,
689 					      chain->data->buf,
690 					      xop->head.name2_len);
691 				}
692 			}
693 			if (error == 0) {
694 				chain->bref.embed.dirent.namlen =
695 					xop->head.name2_len;
696 			}
697 		}
698 	}
699 
700 	/*
701 	 * The frontend will replicate this operation and is the real final
702 	 * authority, but adjust the inode's iparent field too if the inode
703 	 * is embedded in the directory.
704 	 */
705 	if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
706 	    chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
707 		hammer2_inode_data_t *wipdata;
708 
709 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
710 		if (error == 0) {
711 			wipdata = &chain->data->ipdata;
712 			wipdata->meta.iparent = xop->head.ip3->meta.inum;
713 		}
714 	}
715 
716 	/*
717 	 * Destroy any matching target(s) before creating the new entry.
718 	 * This will result in some ping-ponging of the directory key
719 	 * iterator but that is ok.
720 	 */
721 	parent = hammer2_inode_chain(xop->head.ip3, clindex,
722 				     HAMMER2_RESOLVE_ALWAYS);
723 	if (parent == NULL) {
724 		error = HAMMER2_ERROR_EIO;
725 		goto done;
726 	}
727 
728 	/*
729 	 * Delete all matching directory entries.  That is, get rid of
730 	 * multiple duplicates if present, as a self-healing mechanism.
731 	 */
732 	if (error == 0) {
733 		tmp = hammer2_chain_lookup(&parent, &key_next,
734 					   xop->lhc & ~HAMMER2_DIRHASH_LOMASK,
735 					   xop->lhc | HAMMER2_DIRHASH_LOMASK,
736 					   &error,
737 					   HAMMER2_LOOKUP_ALWAYS);
738 		while (tmp) {
739 			int e2;
740 			if (hammer2_chain_dirent_test(tmp, xop->head.name2,
741 						      xop->head.name2_len)) {
742 				e2 = hammer2_chain_delete(parent, tmp,
743 							  xop->head.mtid, 0);
744 				if (error == 0 && e2)
745 					error = e2;
746 			}
747 			tmp = hammer2_chain_next(&parent, tmp, &key_next,
748 						 key_next,
749 						 xop->lhc |
750 						  HAMMER2_DIRHASH_LOMASK,
751 						 &error,
752 						 HAMMER2_LOOKUP_ALWAYS);
753 		}
754 	}
755 	if (error == 0) {
756 		/*
757 		 * A relookup is required before the create to properly
758 		 * position the parent chain.
759 		 */
760 		tmp = hammer2_chain_lookup(&parent, &key_next,
761 					   xop->lhc, xop->lhc,
762 					   &error, 0);
763 		KKASSERT(tmp == NULL);
764 		error = hammer2_chain_create(&parent, &chain, NULL, pmp,
765 					     HAMMER2_METH_DEFAULT,
766 					     xop->lhc, 0,
767 					     HAMMER2_BREF_TYPE_INODE,
768 					     HAMMER2_INODE_BYTES,
769 					     xop->head.mtid, 0, 0);
770 	}
771 done:
772 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
773 	if (parent) {
774 		hammer2_chain_unlock(parent);
775 		hammer2_chain_drop(parent);
776 	}
777 	if (chain) {
778 		hammer2_chain_unlock(chain);
779 		hammer2_chain_drop(chain);
780 	}
781 }
782 
783 /*
784  * Directory collision resolver scan helper (backend, threaded).
785  *
786  * Used by the inode create code to locate an unused lhc.
787  */
788 void
789 hammer2_xop_scanlhc(hammer2_xop_t *arg, void *scratch, int clindex)
790 {
791 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
792 	hammer2_chain_t *parent;
793 	hammer2_chain_t *chain;
794 	hammer2_key_t key_next;
795 	int error = 0;
796 
797 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
798 				     HAMMER2_RESOLVE_ALWAYS |
799 				     HAMMER2_RESOLVE_SHARED);
800 	if (parent == NULL) {
801 		kprintf("xop_nresolve: NULL parent\n");
802 		chain = NULL;
803 		error = HAMMER2_ERROR_EIO;
804 		goto done;
805 	}
806 
807 	/*
808 	 * Lookup all possibly conflicting directory entries, the feed
809 	 * inherits the chain's lock so do not unlock it on the iteration.
810 	 */
811 	chain = hammer2_chain_lookup(&parent, &key_next,
812 				     xop->lhc,
813 				     xop->lhc + HAMMER2_DIRHASH_LOMASK,
814 				     &error,
815 				     HAMMER2_LOOKUP_ALWAYS |
816 				     HAMMER2_LOOKUP_SHARED);
817 	while (chain) {
818 		error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
819 		if (error) {
820 			hammer2_chain_unlock(chain);
821 			hammer2_chain_drop(chain);
822 			chain = NULL;	/* safety */
823 			goto done;
824 		}
825 		chain = hammer2_chain_next(&parent, chain, &key_next,
826 					   key_next,
827 					   xop->lhc + HAMMER2_DIRHASH_LOMASK,
828 					   &error,
829 					   HAMMER2_LOOKUP_ALWAYS |
830 					   HAMMER2_LOOKUP_SHARED);
831 	}
832 done:
833 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
834 	if (parent) {
835 		hammer2_chain_unlock(parent);
836 		hammer2_chain_drop(parent);
837 	}
838 }
839 
840 /*
841  * Generic lookup of a specific key.
842  */
843 void
844 hammer2_xop_lookup(hammer2_xop_t *arg, void *scratch, int clindex)
845 {
846 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
847 	hammer2_chain_t *parent;
848 	hammer2_chain_t *chain;
849 	hammer2_key_t key_next;
850 	int error = 0;
851 
852 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
853 				     HAMMER2_RESOLVE_ALWAYS |
854 				     HAMMER2_RESOLVE_SHARED);
855 	chain = NULL;
856 	if (parent == NULL) {
857 		error = HAMMER2_ERROR_EIO;
858 		goto done;
859 	}
860 
861 	/*
862 	 * Lookup all possibly conflicting directory entries, the feed
863 	 * inherits the chain's lock so do not unlock it on the iteration.
864 	 */
865 	chain = hammer2_chain_lookup(&parent, &key_next,
866 				     xop->lhc, xop->lhc,
867 				     &error,
868 				     HAMMER2_LOOKUP_ALWAYS |
869 				     HAMMER2_LOOKUP_SHARED);
870 	if (error == 0) {
871 		if (chain)
872 			error = chain->error;
873 		else
874 			error = HAMMER2_ERROR_ENOENT;
875 	}
876 	hammer2_xop_feed(&xop->head, chain, clindex, error);
877 
878 done:
879 	if (chain) {
880 		hammer2_chain_unlock(chain);
881 		hammer2_chain_drop(chain);
882 	}
883 	if (parent) {
884 		hammer2_chain_unlock(parent);
885 		hammer2_chain_drop(parent);
886 	}
887 }
888 
889 void
890 hammer2_xop_delete(hammer2_xop_t *arg, void *scratch, int clindex)
891 {
892 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
893 	hammer2_chain_t *parent;
894 	hammer2_chain_t *chain;
895 	hammer2_key_t key_next;
896 	int error = 0;
897 
898 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
899 				     HAMMER2_RESOLVE_ALWAYS);
900 	chain = NULL;
901 	if (parent == NULL) {
902 		error = HAMMER2_ERROR_EIO;
903 		goto done;
904 	}
905 
906 	/*
907 	 * Lookup all possibly conflicting directory entries, the feed
908 	 * inherits the chain's lock so do not unlock it on the iteration.
909 	 */
910 	chain = hammer2_chain_lookup(&parent, &key_next,
911 				     xop->lhc, xop->lhc,
912 				     &error,
913 				     HAMMER2_LOOKUP_NODATA);
914 	if (error == 0) {
915 		if (chain)
916 			error = chain->error;
917 		else
918 			error = HAMMER2_ERROR_ENOENT;
919 	}
920 	if (chain) {
921 		error = hammer2_chain_delete(parent, chain, xop->head.mtid,
922 					     HAMMER2_DELETE_PERMANENT);
923 	}
924 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
925 
926 done:
927 	if (chain) {
928 		hammer2_chain_unlock(chain);
929 		hammer2_chain_drop(chain);
930 	}
931 	if (parent) {
932 		hammer2_chain_unlock(parent);
933 		hammer2_chain_drop(parent);
934 	}
935 }
936 
937 /*
938  * Generic scan
939  *
940  * WARNING! Fed chains must be locked shared so ownership can be transfered
941  *	    and to prevent frontend/backend stalls that would occur with an
942  *	    exclusive lock.  The shared lock also allows chain->data to be
943  *	    retained.
944  */
945 void
946 hammer2_xop_scanall(hammer2_xop_t *arg, void *scratch, int clindex)
947 {
948 	hammer2_xop_scanall_t *xop = &arg->xop_scanall;
949 	hammer2_chain_t *parent;
950 	hammer2_chain_t *chain;
951 	hammer2_key_t key_next;
952 	int error = 0;
953 
954 	/*
955 	 * Assert required flags.
956 	 */
957 	KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
958 	KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
959 
960 	/*
961 	 * The inode's chain is the iterator.  If we cannot acquire it our
962 	 * contribution ends here.
963 	 */
964 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
965 				     xop->resolve_flags);
966 	if (parent == NULL) {
967 		kprintf("xop_readdir: NULL parent\n");
968 		goto done;
969 	}
970 
971 	/*
972 	 * Generic scan of exact records.  Note that indirect blocks are
973 	 * automatically recursed and will not be returned.
974 	 */
975 	chain = hammer2_chain_lookup(&parent, &key_next,
976 				     xop->key_beg, xop->key_end,
977 				     &error, xop->lookup_flags);
978 	while (chain) {
979 		error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
980 		if (error)
981 			goto break2;
982 		chain = hammer2_chain_next(&parent, chain, &key_next,
983 					   key_next, xop->key_end,
984 					   &error, xop->lookup_flags);
985 	}
986 break2:
987 	if (chain) {
988 		hammer2_chain_unlock(chain);
989 		hammer2_chain_drop(chain);
990 	}
991 	hammer2_chain_unlock(parent);
992 	hammer2_chain_drop(parent);
993 done:
994 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
995 }
996 
997 /************************************************************************
998  *			    INODE LAYER XOPS				*
999  ************************************************************************
1000  *
1001  */
1002 /*
1003  * Helper to create a directory entry.
1004  */
1005 void
1006 hammer2_xop_inode_mkdirent(hammer2_xop_t *arg, void *scratch, int clindex)
1007 {
1008 	hammer2_xop_mkdirent_t *xop = &arg->xop_mkdirent;
1009 	hammer2_chain_t *parent;
1010 	hammer2_chain_t *chain;
1011 	hammer2_key_t key_next;
1012 	size_t data_len;
1013 	int error;
1014 
1015 	if (hammer2_debug & 0x0001)
1016 		kprintf("dirent_create lhc %016jx clindex %d\n",
1017 			xop->lhc, clindex);
1018 
1019 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1020 				     HAMMER2_RESOLVE_ALWAYS);
1021 	if (parent == NULL) {
1022 		error = HAMMER2_ERROR_EIO;
1023 		chain = NULL;
1024 		goto fail;
1025 	}
1026 	chain = hammer2_chain_lookup(&parent, &key_next,
1027 				     xop->lhc, xop->lhc,
1028 				     &error, 0);
1029 	if (chain) {
1030 		error = HAMMER2_ERROR_EEXIST;
1031 		goto fail;
1032 	}
1033 
1034 	/*
1035 	 * We may be able to embed the directory entry directly in the
1036 	 * blockref.
1037 	 */
1038 	if (xop->dirent.namlen <= sizeof(chain->bref.check.buf))
1039 		data_len = 0;
1040 	else
1041 		data_len = HAMMER2_ALLOC_MIN;
1042 
1043 	error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp,
1044 				     HAMMER2_METH_DEFAULT,
1045 				     xop->lhc, 0,
1046 				     HAMMER2_BREF_TYPE_DIRENT,
1047 				     data_len,
1048 				     xop->head.mtid, 0, 0);
1049 	if (error == 0) {
1050 		/*
1051 		 * WARNING: chain->data->buf is sized to chain->bytes,
1052 		 *	    do not use sizeof(chain->data->buf), which
1053 		 *	    will be much larger.
1054 		 */
1055 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1056 		if (error == 0) {
1057 			chain->bref.embed.dirent = xop->dirent;
1058 			if (xop->dirent.namlen <= sizeof(chain->bref.check.buf))
1059 				bcopy(xop->head.name1, chain->bref.check.buf,
1060 				      xop->dirent.namlen);
1061 			else
1062 				bcopy(xop->head.name1, chain->data->buf,
1063 				      xop->dirent.namlen);
1064 		}
1065 	}
1066 fail:
1067 	if (parent) {
1068 		hammer2_chain_unlock(parent);
1069 		hammer2_chain_drop(parent);
1070 	}
1071 	hammer2_xop_feed(&xop->head, chain, clindex, error);
1072 	if (chain) {
1073 		hammer2_chain_unlock(chain);
1074 		hammer2_chain_drop(chain);
1075 	}
1076 }
1077 
1078 /*
1079  * Inode create helper (threaded, backend)
1080  *
1081  * Used by ncreate, nmknod, nsymlink, nmkdir.
1082  * Used by nlink and rename to create HARDLINK pointers.
1083  *
1084  * Frontend holds the parent directory ip locked exclusively.  We
1085  * create the inode and feed the exclusively locked chain to the
1086  * frontend.
1087  */
1088 void
1089 hammer2_xop_inode_create(hammer2_xop_t *arg, void *scratch, int clindex)
1090 {
1091 	hammer2_xop_create_t *xop = &arg->xop_create;
1092 	hammer2_chain_t *parent;
1093 	hammer2_chain_t *chain;
1094 	hammer2_key_t key_next;
1095 	int error;
1096 
1097 	if (hammer2_debug & 0x0001)
1098 		kprintf("inode_create lhc %016jx clindex %d\n",
1099 			xop->lhc, clindex);
1100 
1101 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1102 				     HAMMER2_RESOLVE_ALWAYS);
1103 	if (parent == NULL) {
1104 		error = HAMMER2_ERROR_EIO;
1105 		chain = NULL;
1106 		goto fail;
1107 	}
1108 	chain = hammer2_chain_lookup(&parent, &key_next,
1109 				     xop->lhc, xop->lhc,
1110 				     &error, 0);
1111 	if (chain) {
1112 		error = HAMMER2_ERROR_EEXIST;
1113 		goto fail;
1114 	}
1115 
1116 	error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp,
1117 				     HAMMER2_METH_DEFAULT,
1118 				     xop->lhc, 0,
1119 				     HAMMER2_BREF_TYPE_INODE,
1120 				     HAMMER2_INODE_BYTES,
1121 				     xop->head.mtid, 0, xop->flags);
1122 	if (error == 0) {
1123 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1124 		if (error == 0) {
1125 			chain->data->ipdata.meta = xop->meta;
1126 			if (xop->head.name1) {
1127 				bcopy(xop->head.name1,
1128 				      chain->data->ipdata.filename,
1129 				      xop->head.name1_len);
1130 				chain->data->ipdata.meta.name_len =
1131 					xop->head.name1_len;
1132 			}
1133 			chain->data->ipdata.meta.name_key = xop->lhc;
1134 		}
1135 	}
1136 fail:
1137 	if (parent) {
1138 		hammer2_chain_unlock(parent);
1139 		hammer2_chain_drop(parent);
1140 	}
1141 	hammer2_xop_feed(&xop->head, chain, clindex, error);
1142 	if (chain) {
1143 		hammer2_chain_unlock(chain);
1144 		hammer2_chain_drop(chain);
1145 	}
1146 }
1147 
1148 /*
1149  * Create inode as above but leave it detached from the hierarchy.
1150  */
1151 void
1152 hammer2_xop_inode_create_det(hammer2_xop_t *arg, void *scratch, int clindex)
1153 {
1154 	hammer2_xop_create_t *xop = &arg->xop_create;
1155 	hammer2_chain_t *parent;
1156 	hammer2_chain_t *chain;
1157 	hammer2_chain_t *null_parent;
1158 	hammer2_key_t key_next;
1159 	hammer2_inode_t *pip;
1160 	hammer2_inode_t *iroot;
1161 	int error;
1162 
1163 	if (hammer2_debug & 0x0001)
1164 		kprintf("inode_create_det lhc %016jx clindex %d\n",
1165 			xop->lhc, clindex);
1166 
1167 	pip = xop->head.ip1;
1168 	iroot = pip->pmp->iroot;
1169 
1170 	parent = hammer2_inode_chain(iroot, clindex, HAMMER2_RESOLVE_ALWAYS);
1171 
1172 	if (parent == NULL) {
1173 		error = HAMMER2_ERROR_EIO;
1174 		chain = NULL;
1175 		goto fail;
1176 	}
1177 	chain = hammer2_chain_lookup(&parent, &key_next,
1178 				     xop->lhc, xop->lhc,
1179 				     &error, 0);
1180 	if (chain) {
1181 		error = HAMMER2_ERROR_EEXIST;
1182 		goto fail;
1183 	}
1184 
1185 	/*
1186 	 * Create as a detached chain with no parent.  We must specify
1187 	 * methods
1188 	 */
1189 	null_parent = NULL;
1190 	error = hammer2_chain_create(&null_parent, &chain,
1191 				     parent->hmp, pip->pmp,
1192 				     HAMMER2_ENC_COMP(pip->meta.comp_algo) +
1193 				     HAMMER2_ENC_CHECK(pip->meta.check_algo),
1194 				     xop->lhc, 0,
1195 				     HAMMER2_BREF_TYPE_INODE,
1196 				     HAMMER2_INODE_BYTES,
1197 				     xop->head.mtid, 0, xop->flags);
1198 	if (error == 0) {
1199 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1200 		if (error == 0) {
1201 			chain->data->ipdata.meta = xop->meta;
1202 			if (xop->head.name1) {
1203 				bcopy(xop->head.name1,
1204 				      chain->data->ipdata.filename,
1205 				      xop->head.name1_len);
1206 				chain->data->ipdata.meta.name_len =
1207 					xop->head.name1_len;
1208 			}
1209 			chain->data->ipdata.meta.name_key = xop->lhc;
1210 		}
1211 	}
1212 fail:
1213 	if (parent) {
1214 		hammer2_chain_unlock(parent);
1215 		hammer2_chain_drop(parent);
1216 	}
1217 	hammer2_xop_feed(&xop->head, chain, clindex, error);
1218 	if (chain) {
1219 		hammer2_chain_unlock(chain);
1220 		hammer2_chain_drop(chain);
1221 	}
1222 }
1223 
1224 /*
1225  * Take a detached chain and insert it into the topology
1226  */
1227 void
1228 hammer2_xop_inode_create_ins(hammer2_xop_t *arg, void *scratch, int clindex)
1229 {
1230 	hammer2_xop_create_t *xop = &arg->xop_create;
1231 	hammer2_chain_t *parent;
1232 	hammer2_chain_t *chain;
1233 	hammer2_key_t key_next;
1234 	int error;
1235 
1236 	if (hammer2_debug & 0x0001)
1237 		kprintf("inode_create_ins lhc %016jx clindex %d\n",
1238 			xop->lhc, clindex);
1239 
1240 	/*
1241 	 * (parent) will be the insertion point for inode under iroot
1242 	 */
1243 	parent = hammer2_inode_chain(xop->head.ip1->pmp->iroot, clindex,
1244 				     HAMMER2_RESOLVE_ALWAYS);
1245 	if (parent == NULL) {
1246 		error = HAMMER2_ERROR_EIO;
1247 		chain = NULL;
1248 		goto fail;
1249 	}
1250 	chain = hammer2_chain_lookup(&parent, &key_next,
1251 				     xop->lhc, xop->lhc,
1252 				     &error, 0);
1253 	if (chain) {
1254 		error = HAMMER2_ERROR_EEXIST;
1255 		goto fail;
1256 	}
1257 
1258 	/*
1259 	 * (chain) is the detached inode that is being inserted
1260 	 */
1261 	chain = hammer2_inode_chain(xop->head.ip1, clindex,
1262 				     HAMMER2_RESOLVE_ALWAYS);
1263 	if (chain == NULL) {
1264 		error = HAMMER2_ERROR_EIO;
1265 		chain = NULL;
1266 		goto fail;
1267 	}
1268 
1269 	/*
1270 	 * This create call will insert the non-NULL chain into parent.
1271 	 * Most of the auxillary fields are ignored since the chain already
1272 	 * exists.
1273 	 */
1274 	error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp,
1275 				     HAMMER2_METH_DEFAULT,
1276 				     xop->lhc, 0,
1277 				     HAMMER2_BREF_TYPE_INODE,
1278 				     HAMMER2_INODE_BYTES,
1279 				     xop->head.mtid, 0, xop->flags);
1280 #if 0
1281 	if (error == 0) {
1282 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1283 		if (error == 0) {
1284 			chain->data->ipdata.meta = xop->meta;
1285 			if (xop->head.name1) {
1286 				bcopy(xop->head.name1,
1287 				      chain->data->ipdata.filename,
1288 				      xop->head.name1_len);
1289 				chain->data->ipdata.meta.name_len =
1290 					xop->head.name1_len;
1291 			}
1292 			chain->data->ipdata.meta.name_key = xop->lhc;
1293 		}
1294 	}
1295 #endif
1296 fail:
1297 	if (parent) {
1298 		hammer2_chain_unlock(parent);
1299 		hammer2_chain_drop(parent);
1300 	}
1301 	hammer2_xop_feed(&xop->head, chain, clindex, error);
1302 	if (chain) {
1303 		hammer2_chain_unlock(chain);
1304 		hammer2_chain_drop(chain);
1305 	}
1306 }
1307 
1308 /*
1309  * Inode delete helper (backend, threaded)
1310  *
1311  * Generally used by hammer2_run_sideq()
1312  */
1313 void
1314 hammer2_xop_inode_destroy(hammer2_xop_t *arg, void *scratch, int clindex)
1315 {
1316 	hammer2_xop_destroy_t *xop = &arg->xop_destroy;
1317 	hammer2_pfs_t *pmp;
1318 	hammer2_chain_t *parent;
1319 	hammer2_chain_t *chain;
1320 	hammer2_inode_t *ip;
1321 	int error;
1322 
1323 	/*
1324 	 * We need the precise parent chain to issue the deletion.
1325 	 */
1326 	ip = xop->head.ip1;
1327 	pmp = ip->pmp;
1328 
1329 	chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
1330 	if (chain == NULL) {
1331 		parent = NULL;
1332 		error = HAMMER2_ERROR_EIO;
1333 		goto done;
1334 	}
1335 
1336 	if (ip->flags & HAMMER2_INODE_CREATING) {
1337 		/*
1338 		 * Inode's chains are not linked into the media topology
1339 		 * because it is a new inode (which is now being destroyed).
1340 		 */
1341 		parent = NULL;
1342 	} else {
1343 		/*
1344 		 * Inode's chains are linked into the media topology
1345 		 */
1346 		parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS);
1347 		if (parent == NULL) {
1348 			error = HAMMER2_ERROR_EIO;
1349 			goto done;
1350 		}
1351 	}
1352 	KKASSERT(chain->parent == parent);
1353 
1354 	/*
1355 	 * We have the correct parent, we can issue the deletion.
1356 	 */
1357 	hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
1358 	error = 0;
1359 done:
1360 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1361 	if (parent) {
1362 		hammer2_chain_unlock(parent);
1363 		hammer2_chain_drop(parent);
1364 	}
1365 	if (chain) {
1366 		hammer2_chain_unlock(chain);
1367 		hammer2_chain_drop(chain);
1368 	}
1369 }
1370 
1371 void
1372 hammer2_xop_inode_unlinkall(hammer2_xop_t *arg, void *scratch, int clindex)
1373 {
1374 	hammer2_xop_unlinkall_t *xop = &arg->xop_unlinkall;
1375 	hammer2_chain_t *parent;
1376 	hammer2_chain_t *chain;
1377 	hammer2_key_t key_next;
1378 	int error;
1379 
1380 	/*
1381 	 * We need the precise parent chain to issue the deletion.
1382 	 */
1383 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1384 				     HAMMER2_RESOLVE_ALWAYS);
1385 	chain = NULL;
1386 	if (parent == NULL) {
1387 		error = 0;
1388 		goto done;
1389 	}
1390 	chain = hammer2_chain_lookup(&parent, &key_next,
1391 				     xop->key_beg, xop->key_end,
1392 				     &error, HAMMER2_LOOKUP_ALWAYS);
1393 	while (chain) {
1394 		hammer2_chain_delete(parent, chain,
1395 				     xop->head.mtid, HAMMER2_DELETE_PERMANENT);
1396 		hammer2_xop_feed(&xop->head, chain, clindex, chain->error);
1397 		/* depend on function to unlock the shared lock */
1398 		chain = hammer2_chain_next(&parent, chain, &key_next,
1399 					   key_next, xop->key_end,
1400 					   &error,
1401 					   HAMMER2_LOOKUP_ALWAYS);
1402 	}
1403 done:
1404 	if (error == 0)
1405 		error = HAMMER2_ERROR_ENOENT;
1406 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1407 	if (parent) {
1408 		hammer2_chain_unlock(parent);
1409 		hammer2_chain_drop(parent);
1410 	}
1411 	if (chain) {
1412 		hammer2_chain_unlock(chain);
1413 		hammer2_chain_drop(chain);
1414 	}
1415 }
1416 
1417 void
1418 hammer2_xop_inode_connect(hammer2_xop_t *arg, void *scratch, int clindex)
1419 {
1420 	hammer2_xop_connect_t *xop = &arg->xop_connect;
1421 	hammer2_inode_data_t *wipdata;
1422 	hammer2_chain_t *parent;
1423 	hammer2_chain_t *chain;
1424 	hammer2_pfs_t *pmp;
1425 	hammer2_key_t key_dummy;
1426 	int error;
1427 
1428 	/*
1429 	 * Get directory, then issue a lookup to prime the parent chain
1430 	 * for the create.  The lookup is expected to fail.
1431 	 */
1432 	pmp = xop->head.ip1->pmp;
1433 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1434 				     HAMMER2_RESOLVE_ALWAYS);
1435 	if (parent == NULL) {
1436 		chain = NULL;
1437 		error = HAMMER2_ERROR_EIO;
1438 		goto fail;
1439 	}
1440 	chain = hammer2_chain_lookup(&parent, &key_dummy,
1441 				     xop->lhc, xop->lhc,
1442 				     &error, 0);
1443 	if (chain) {
1444 		hammer2_chain_unlock(chain);
1445 		hammer2_chain_drop(chain);
1446 		chain = NULL;
1447 		error = HAMMER2_ERROR_EEXIST;
1448 		goto fail;
1449 	}
1450 	if (error)
1451 		goto fail;
1452 
1453 	/*
1454 	 * Adjust the filename in the inode, set the name key.
1455 	 *
1456 	 * NOTE: Frontend must also adjust ip2->meta on success, we can't
1457 	 *	 do it here.
1458 	 */
1459 	chain = hammer2_inode_chain(xop->head.ip2, clindex,
1460 				    HAMMER2_RESOLVE_ALWAYS);
1461 	error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1462 	if (error)
1463 		goto fail;
1464 
1465 	wipdata = &chain->data->ipdata;
1466 
1467 	hammer2_inode_modify(xop->head.ip2);
1468 	if (xop->head.name1) {
1469 		bzero(wipdata->filename, sizeof(wipdata->filename));
1470 		bcopy(xop->head.name1, wipdata->filename, xop->head.name1_len);
1471 		wipdata->meta.name_len = xop->head.name1_len;
1472 	}
1473 	wipdata->meta.name_key = xop->lhc;
1474 
1475 	/*
1476 	 * Reconnect the chain to the new parent directory
1477 	 */
1478 	error = hammer2_chain_create(&parent, &chain, NULL, pmp,
1479 				     HAMMER2_METH_DEFAULT,
1480 				     xop->lhc, 0,
1481 				     HAMMER2_BREF_TYPE_INODE,
1482 				     HAMMER2_INODE_BYTES,
1483 				     xop->head.mtid, 0, 0);
1484 
1485 	/*
1486 	 * Feed result back.
1487 	 */
1488 fail:
1489 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1490 	if (parent) {
1491 		hammer2_chain_unlock(parent);
1492 		hammer2_chain_drop(parent);
1493 	}
1494 	if (chain) {
1495 		hammer2_chain_unlock(chain);
1496 		hammer2_chain_drop(chain);
1497 	}
1498 }
1499 
1500 /*
1501  * Synchronize the in-memory inode with the chain.  This does not flush
1502  * the chain to disk.  Instead, it makes front-end inode changes visible
1503  * in the chain topology, thus visible to the backend.  This is done in an
1504  * ad-hoc manner outside of the filesystem vfs_sync, and in a controlled
1505  * manner inside the vfs_sync.
1506  */
1507 void
1508 hammer2_xop_inode_chain_sync(hammer2_xop_t *arg, void *scratch, int clindex)
1509 {
1510 	hammer2_xop_fsync_t *xop = &arg->xop_fsync;
1511 	hammer2_chain_t	*parent;
1512 	hammer2_chain_t	*chain;
1513 	int error;
1514 
1515 	parent = hammer2_inode_chain(xop->head.ip1, clindex,
1516 				     HAMMER2_RESOLVE_ALWAYS);
1517 	chain = NULL;
1518 	if (parent == NULL) {
1519 		error = HAMMER2_ERROR_EIO;
1520 		goto done;
1521 	}
1522 	if (parent->error) {
1523 		error = parent->error;
1524 		goto done;
1525 	}
1526 
1527 	error = 0;
1528 
1529 	if ((xop->ipflags & HAMMER2_INODE_RESIZED) == 0) {
1530 		/* osize must be ignored */
1531 	} else if (xop->meta.size < xop->osize) {
1532 		/*
1533 		 * We must delete any chains beyond the EOF.  The chain
1534 		 * straddling the EOF will be pending in the bioq.
1535 		 */
1536 		hammer2_key_t lbase;
1537 		hammer2_key_t key_next;
1538 
1539 		lbase = (xop->meta.size + HAMMER2_PBUFMASK64) &
1540 			~HAMMER2_PBUFMASK64;
1541 		chain = hammer2_chain_lookup(&parent, &key_next,
1542 					     lbase, HAMMER2_KEY_MAX,
1543 					     &error,
1544 					     HAMMER2_LOOKUP_NODATA |
1545 					     HAMMER2_LOOKUP_NODIRECT);
1546 		while (chain) {
1547 			/*
1548 			 * Degenerate embedded case, nothing to loop on
1549 			 */
1550 			switch (chain->bref.type) {
1551 			case HAMMER2_BREF_TYPE_DIRENT:
1552 			case HAMMER2_BREF_TYPE_INODE:
1553 				KKASSERT(0);
1554 				break;
1555 			case HAMMER2_BREF_TYPE_DATA:
1556 				hammer2_chain_delete(parent, chain,
1557 						     xop->head.mtid,
1558 						     HAMMER2_DELETE_PERMANENT);
1559 				break;
1560 			}
1561 			chain = hammer2_chain_next(&parent, chain, &key_next,
1562 						   key_next, HAMMER2_KEY_MAX,
1563 						   &error,
1564 						   HAMMER2_LOOKUP_NODATA |
1565 						   HAMMER2_LOOKUP_NODIRECT);
1566 		}
1567 
1568 		/*
1569 		 * Reset to point at inode for following code, if necessary.
1570 		 */
1571 		if (parent->bref.type != HAMMER2_BREF_TYPE_INODE) {
1572 			hammer2_chain_unlock(parent);
1573 			hammer2_chain_drop(parent);
1574 			parent = hammer2_inode_chain(xop->head.ip1,
1575 						     clindex,
1576 						     HAMMER2_RESOLVE_ALWAYS);
1577 			kprintf("hammer2: TRUNCATE RESET on '%s'\n",
1578 				parent->data->ipdata.filename);
1579 		}
1580 	}
1581 
1582 	/*
1583 	 * Sync the inode meta-data, potentially clear the blockset area
1584 	 * of direct data so it can be used for blockrefs.
1585 	 */
1586 	if (error == 0) {
1587 		error = hammer2_chain_modify(parent, xop->head.mtid, 0, 0);
1588 		if (error == 0) {
1589 			parent->data->ipdata.meta = xop->meta;
1590 			if (xop->clear_directdata) {
1591 				bzero(&parent->data->ipdata.u.blockset,
1592 				      sizeof(parent->data->ipdata.u.blockset));
1593 			}
1594 		}
1595 	}
1596 done:
1597 	if (chain) {
1598 		hammer2_chain_unlock(chain);
1599 		hammer2_chain_drop(chain);
1600 	}
1601 	if (parent) {
1602 		hammer2_chain_unlock(parent);
1603 		hammer2_chain_drop(parent);
1604 	}
1605 	hammer2_xop_feed(&xop->head, NULL, clindex, error);
1606 }
1607