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