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