xref: /dragonfly/sys/vfs/hammer2/hammer2_xops.c (revision 6e4c95df)
1 /*
2  * Copyright (c) 2011-2015 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@dragonflybsd.org>
6  * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
7  * by Daniel Flores (GSOC 2013 - mentored by Matthew Dillon, compression)
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  * 3. Neither the name of The DragonFly Project nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific, prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
27  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 /*
37  * Per-node backend for kernel filesystem interface.
38  *
39  * This executes a VOP concurrently on multiple nodes, each node via its own
40  * thread, and competes to advance the original request.  The original
41  * request is retired the moment all requirements are met, even if the
42  * operation is still in-progress on some nodes.
43  */
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/fcntl.h>
48 #include <sys/buf.h>
49 #include <sys/proc.h>
50 #include <sys/namei.h>
51 #include <sys/mount.h>
52 #include <sys/vnode.h>
53 #include <sys/mountctl.h>
54 #include <sys/dirent.h>
55 #include <sys/uio.h>
56 #include <sys/objcache.h>
57 #include <sys/event.h>
58 #include <sys/file.h>
59 #include <vfs/fifofs/fifo.h>
60 
61 #include "hammer2.h"
62 
63 /*
64  * Determine if the specified directory is empty.  Returns 0 on success.
65  */
66 static
67 int
68 checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex)
69 {
70 	hammer2_chain_t *parent;
71 	hammer2_chain_t *chain;
72 	hammer2_key_t key_next;
73 	hammer2_key_t inum;
74 	int error;
75 
76 	error = 0;
77 	chain = hammer2_chain_lookup_init(ochain, 0);
78 
79 	if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
80 		if (oparent)
81 			hammer2_chain_unlock(oparent);
82 		inum = chain->bref.embed.dirent.inum;
83 		parent = NULL;
84 		error = hammer2_chain_inode_find(chain->pmp, inum,
85 						 clindex, 0,
86 						 &parent, &chain);
87 		if (parent) {
88 			hammer2_chain_unlock(parent);
89 			hammer2_chain_drop(parent);
90 		}
91 		if (oparent) {
92 			hammer2_chain_lock(oparent, HAMMER2_RESOLVE_ALWAYS);
93 			if (ochain->parent != oparent) {
94 				if (chain) {
95 					hammer2_chain_unlock(chain);
96 					hammer2_chain_drop(chain);
97 				}
98 				return HAMMER2_ERROR_EAGAIN;
99 			}
100 		}
101 	}
102 
103 	/*
104 	 * Determine if the directory is empty or not by checking its
105 	 * visible namespace (the area which contains directory entries).
106 	 */
107 	parent = chain;
108 	chain = NULL;
109 	if (parent) {
110 		chain = hammer2_chain_lookup(&parent, &key_next,
111 					     HAMMER2_DIRHASH_VISIBLE,
112 					     HAMMER2_KEY_MAX,
113 					     &error, 0);
114 	}
115 	if (chain) {
116 		error = HAMMER2_ERROR_ENOTEMPTY;
117 		hammer2_chain_unlock(chain);
118 		hammer2_chain_drop(chain);
119 	}
120 	hammer2_chain_lookup_done(parent);
121 
122 	return error;
123 }
124 
125 /*
126  * Backend for hammer2_vfs_root()
127  *
128  * This is called when a newly mounted PFS has not yet synchronized
129  * to the inode_tid and modify_tid.
130  */
131 void
132 hammer2_xop_ipcluster(hammer2_thread_t *thr, hammer2_xop_t *arg)
133 {
134 	hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
135 	hammer2_chain_t *chain;
136 	int error;
137 
138 	chain = hammer2_inode_chain(xop->head.ip1, thr->clindex,
139 				    HAMMER2_RESOLVE_ALWAYS |
140 				    HAMMER2_RESOLVE_SHARED);
141 	if (chain)
142 		error = chain->error;
143 	else
144 		error = HAMMER2_ERROR_EIO;
145 
146 	hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
147 	if (chain) {
148 		hammer2_chain_unlock(chain);
149 		hammer2_chain_drop(chain);
150 	}
151 }
152 
153 /*
154  * Backend for hammer2_vop_readdir()
155  */
156 void
157 hammer2_xop_readdir(hammer2_thread_t *thr, hammer2_xop_t *arg)
158 {
159 	hammer2_xop_readdir_t *xop = &arg->xop_readdir;
160 	hammer2_chain_t *parent;
161 	hammer2_chain_t *chain;
162 	hammer2_key_t key_next;
163 	hammer2_key_t lkey;
164 	int error = 0;
165 
166 	lkey = xop->lkey;
167 	if (hammer2_debug & 0x0020)
168 		kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
169 
170 	/*
171 	 * The inode's chain is the iterator.  If we cannot acquire it our
172 	 * contribution ends here.
173 	 */
174 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
175 				     HAMMER2_RESOLVE_ALWAYS |
176 				     HAMMER2_RESOLVE_SHARED);
177 	if (parent == NULL) {
178 		kprintf("xop_readdir: NULL parent\n");
179 		goto done;
180 	}
181 
182 	/*
183 	 * Directory scan [re]start and loop, the feed inherits the chain's
184 	 * lock so do not unlock it on the iteration.
185 	 */
186 	chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
187 				     &error, HAMMER2_LOOKUP_SHARED);
188 	if (chain == NULL) {
189 		chain = hammer2_chain_lookup(&parent, &key_next,
190 					     lkey, HAMMER2_KEY_MAX,
191 					     &error, HAMMER2_LOOKUP_SHARED);
192 	}
193 	while (chain) {
194 		error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
195 		if (error)
196 			goto break2;
197 		chain = hammer2_chain_next(&parent, chain, &key_next,
198 					   key_next, HAMMER2_KEY_MAX,
199 					   &error, HAMMER2_LOOKUP_SHARED);
200 	}
201 break2:
202 	if (chain) {
203 		hammer2_chain_unlock(chain);
204 		hammer2_chain_drop(chain);
205 	}
206 	hammer2_chain_unlock(parent);
207 	hammer2_chain_drop(parent);
208 done:
209 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
210 }
211 
212 /*
213  * Backend for hammer2_vop_nresolve()
214  */
215 void
216 hammer2_xop_nresolve(hammer2_thread_t *thr, hammer2_xop_t *arg)
217 {
218 	hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
219 	hammer2_chain_t *parent;
220 	hammer2_chain_t *chain;
221 	const char *name;
222 	size_t name_len;
223 	hammer2_key_t key_next;
224 	hammer2_key_t lhc;
225 	int error;
226 
227 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
228 				     HAMMER2_RESOLVE_ALWAYS |
229 				     HAMMER2_RESOLVE_SHARED);
230 	if (parent == NULL) {
231 		kprintf("xop_nresolve: NULL parent\n");
232 		chain = NULL;
233 		error = HAMMER2_ERROR_EIO;
234 		goto done;
235 	}
236 	name = xop->head.name1;
237 	name_len = xop->head.name1_len;
238 
239 	/*
240 	 * Lookup the directory entry
241 	 */
242 	lhc = hammer2_dirhash(name, name_len);
243 	chain = hammer2_chain_lookup(&parent, &key_next,
244 				     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
245 				     &error,
246 				     HAMMER2_LOOKUP_ALWAYS |
247 				     HAMMER2_LOOKUP_SHARED);
248 	while (chain) {
249 		if (hammer2_chain_dirent_test(chain, name, name_len))
250 			break;
251 		chain = hammer2_chain_next(&parent, chain, &key_next,
252 					   key_next,
253 					   lhc + HAMMER2_DIRHASH_LOMASK,
254 					   &error,
255 					   HAMMER2_LOOKUP_ALWAYS |
256 					   HAMMER2_LOOKUP_SHARED);
257 	}
258 
259 	/*
260 	 * If the entry is a hardlink pointer, resolve it.
261 	 */
262 	if (chain && chain->error == 0) {
263 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
264 			lhc = chain->bref.embed.dirent.inum;
265 			error = hammer2_chain_inode_find(chain->pmp,
266 							 lhc,
267 							 thr->clindex,
268 							 HAMMER2_LOOKUP_SHARED,
269 							 &parent,
270 							 &chain);
271 		}
272 	} else if (chain && error == 0) {
273 		error = chain->error;
274 	}
275 done:
276 	error = hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
277 	if (chain) {
278 		hammer2_chain_unlock(chain);
279 		hammer2_chain_drop(chain);
280 	}
281 	if (parent) {
282 		hammer2_chain_unlock(parent);
283 		hammer2_chain_drop(parent);
284 	}
285 }
286 
287 /*
288  * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and
289  * backend for pfs_delete.
290  *
291  * This function locates and removes a directory entry, and will lookup
292  * and return the underlying inode.  For directory entries the underlying
293  * inode is not removed.  If the directory entry is the actual inode itself,
294  * it may be conditonally removed and returned.
295  *
296  * WARNING!  Any target inode's nlinks may not be synchronized to the
297  *	     in-memory inode.  The frontend's hammer2_inode_unlink_finisher()
298  *	     is responsible for the final disposition of the actual inode.
299  */
300 void
301 hammer2_xop_unlink(hammer2_thread_t *thr, hammer2_xop_t *arg)
302 {
303 	hammer2_xop_unlink_t *xop = &arg->xop_unlink;
304 	hammer2_chain_t *parent;
305 	hammer2_chain_t *chain;
306 	const char *name;
307 	size_t name_len;
308 	hammer2_key_t key_next;
309 	hammer2_key_t lhc;
310 	int error;
311 
312 again:
313 	/*
314 	 * Requires exclusive lock
315 	 */
316 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
317 				     HAMMER2_RESOLVE_ALWAYS);
318 	chain = NULL;
319 	if (parent == NULL) {
320 		kprintf("xop_nresolve: NULL parent\n");
321 		error = HAMMER2_ERROR_EIO;
322 		goto done;
323 	}
324 	name = xop->head.name1;
325 	name_len = xop->head.name1_len;
326 
327 	/*
328 	 * Lookup the directory entry
329 	 */
330 	lhc = hammer2_dirhash(name, name_len);
331 	chain = hammer2_chain_lookup(&parent, &key_next,
332 				     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
333 				     &error, HAMMER2_LOOKUP_ALWAYS);
334 	while (chain) {
335 		if (hammer2_chain_dirent_test(chain, name, name_len))
336 			break;
337 		chain = hammer2_chain_next(&parent, chain, &key_next,
338 					   key_next,
339 					   lhc + HAMMER2_DIRHASH_LOMASK,
340 					   &error, HAMMER2_LOOKUP_ALWAYS);
341 	}
342 
343 	/*
344 	 * The directory entry will either be a BREF_TYPE_DIRENT or a
345 	 * BREF_TYPE_INODE.  We always permanently delete DIRENTs, but
346 	 * must go by xop->dopermanent for BREF_TYPE_INODE.
347 	 *
348 	 * Note that the target chain's nlinks may not be synchronized with
349 	 * the in-memory hammer2_inode_t structure, so we don't try to do
350 	 * anything fancy here.  The frontend deals with nlinks
351 	 * synchronization.
352 	 */
353 	if (chain && chain->error == 0) {
354 		int dopermanent = xop->dopermanent & 1;
355 		int doforce = xop->dopermanent & 2;
356 		uint8_t type;
357 
358 		/*
359 		 * If the directory entry is the actual inode then use its
360 		 * type for the directory typing tests, otherwise if it is
361 		 * a directory entry, pull the type field from the entry.
362 		 *
363 		 * Directory entries are always permanently deleted
364 		 * (because they aren't the actual inode).
365 		 */
366 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
367 			type = chain->bref.embed.dirent.type;
368 			dopermanent |= HAMMER2_DELETE_PERMANENT;
369 		} else {
370 			type = chain->data->ipdata.meta.type;
371 		}
372 
373 		/*
374 		 * Check directory typing and delete the entry.  Note that
375 		 * nlinks adjustments are made on the real inode by the
376 		 * frontend, not here.
377 		 *
378 		 * Unfortunately, checkdirempty() may have to unlock (parent).
379 		 * If it no longer matches chain->parent after re-locking,
380 		 * EAGAIN is returned.
381 		 */
382 		if (type == HAMMER2_OBJTYPE_DIRECTORY && doforce) {
383 			/*
384 			 * If doforce then execute the operation even if
385 			 * the directory is not empty or errored.
386 			 */
387 			/* ignore chain->error */
388 			error = hammer2_chain_delete(parent, chain,
389 					     xop->head.mtid, dopermanent);
390 		} else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
391 			   (error = checkdirempty(parent, chain, thr->clindex)) != 0) {
392 			/*
393 			 * error may be EAGAIN or ENOTEMPTY
394 			 */
395 			if (error == HAMMER2_ERROR_EAGAIN) {
396 				hammer2_chain_unlock(chain);
397 				hammer2_chain_drop(chain);
398 				hammer2_chain_unlock(parent);
399 				hammer2_chain_drop(parent);
400 				goto again;
401 			}
402 		} else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
403 		    xop->isdir == 0) {
404 			error = HAMMER2_ERROR_ENOTDIR;
405 		} else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
406 			   xop->isdir >= 1) {
407 			error = HAMMER2_ERROR_EISDIR;
408 		} else {
409 			/*
410 			 * Delete the directory entry.  chain might also
411 			 * be a directly-embedded inode.
412 			 */
413 			error = chain->error;
414 			hammer2_chain_delete(parent, chain,
415 					     xop->head.mtid, dopermanent);
416 		}
417 	} else {
418 		if (chain && error == 0)
419 			error = chain->error;
420 	}
421 
422 	/*
423 	 * If chain is a directory entry we must resolve it.  We do not try
424 	 * to manipulate the contents as it might not be synchronized with
425 	 * the frontend hammer2_inode_t, nor do we try to lookup the
426 	 * frontend hammer2_inode_t here (we are the backend!).
427 	 */
428 	if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
429 		int error2;
430 
431 		lhc = chain->bref.embed.dirent.inum;
432 
433 		error2 = hammer2_chain_inode_find(chain->pmp, lhc,
434 						  thr->clindex, 0,
435 						  &parent, &chain);
436 		if (error2) {
437 			kprintf("inode_find: %016jx %p failed\n",
438 				lhc, chain);
439 			error2 = 0;	/* silently ignore */
440 		}
441 		if (error == 0)
442 			error = error2;
443 	}
444 
445 	/*
446 	 * Return the inode target for further action.  Typically used by
447 	 * hammer2_inode_unlink_finisher().
448 	 */
449 done:
450 	hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
451 	if (chain) {
452 		hammer2_chain_unlock(chain);
453 		hammer2_chain_drop(chain);
454 		chain = NULL;
455 	}
456 	if (parent) {
457 		hammer2_chain_unlock(parent);
458 		hammer2_chain_drop(parent);
459 		parent = NULL;
460 	}
461 }
462 
463 /*
464  * Backend for hammer2_vop_nrename()
465  *
466  * This handles the backend rename operation.  Typically this renames
467  * directory entries but can also be used to rename embedded inodes.
468  *
469  * NOTE! The frontend is responsible for updating the inode meta-data in
470  *	 the file being renamed and for decrementing the target-replaced
471  *	 inode's nlinks, if present.
472  */
473 void
474 hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg)
475 {
476 	hammer2_xop_nrename_t *xop = &arg->xop_nrename;
477 	hammer2_pfs_t *pmp;
478 	hammer2_chain_t *parent;
479 	hammer2_chain_t *chain;
480 	hammer2_chain_t *tmp;
481 	hammer2_inode_t *ip;
482 	hammer2_key_t key_next;
483 	int error;
484 
485 	/*
486 	 * We need the precise parent chain to issue the deletion.
487 	 *
488 	 * If this is a directory entry we must locate the underlying
489 	 * inode.  If it is an embedded inode we can act directly on it.
490 	 */
491 	ip = xop->head.ip2;
492 	pmp = ip->pmp;
493 	chain = NULL;
494 	error = 0;
495 
496 	if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
497 		/*
498 		 * Find ip's direct parent chain.
499 		 */
500 		chain = hammer2_inode_chain(ip, thr->clindex,
501 					    HAMMER2_RESOLVE_ALWAYS);
502 		if (chain == NULL) {
503 			error = HAMMER2_ERROR_EIO;
504 			parent = NULL;
505 			goto done;
506 		}
507 		parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS);
508 		if (parent == NULL) {
509 			error = HAMMER2_ERROR_EIO;
510 			goto done;
511 		}
512 	} else {
513 		/*
514 		 * The directory entry for the head.ip1 inode
515 		 * is in fdip, do a namespace search.
516 		 */
517 		hammer2_key_t lhc;
518 		const char *name;
519 		size_t name_len;
520 
521 		parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
522 					     HAMMER2_RESOLVE_ALWAYS);
523 		if (parent == NULL) {
524 			kprintf("xop_nrename: NULL parent\n");
525 			error = HAMMER2_ERROR_EIO;
526 			goto done;
527 		}
528 		name = xop->head.name1;
529 		name_len = xop->head.name1_len;
530 
531 		/*
532 		 * Lookup the directory entry
533 		 */
534 		lhc = hammer2_dirhash(name, name_len);
535 		chain = hammer2_chain_lookup(&parent, &key_next,
536 					     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
537 					     &error, HAMMER2_LOOKUP_ALWAYS);
538 		while (chain) {
539 			if (hammer2_chain_dirent_test(chain, name, name_len))
540 				break;
541 			chain = hammer2_chain_next(&parent, chain, &key_next,
542 						   key_next,
543 						   lhc + HAMMER2_DIRHASH_LOMASK,
544 						   &error,
545 						   HAMMER2_LOOKUP_ALWAYS);
546 		}
547 	}
548 
549 	if (chain == NULL) {
550 		/* XXX shouldn't happen, but does under fsstress */
551 		kprintf("hammer2_xop_rename: \"%s\" -> \"%s\"  ENOENT\n",
552 			xop->head.name1,
553 			xop->head.name2);
554 		if (error == 0)
555 			error = HAMMER2_ERROR_ENOENT;
556 		goto done;
557 	}
558 
559 	if (chain->error) {
560 		error = chain->error;
561 		goto done;
562 	}
563 
564 	/*
565 	 * Delete it, then create it in the new namespace.
566 	 */
567 	hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
568 	hammer2_chain_unlock(parent);
569 	hammer2_chain_drop(parent);
570 	parent = NULL;		/* safety */
571 
572 	/*
573 	 * Adjust fields in the deleted chain appropriate for the rename
574 	 * operation.
575 	 *
576 	 * NOTE! For embedded inodes, the frontend will officially replicate
577 	 *	 the field adjustments, but we also do it here to maintain
578 	 *	 consistency in case of a crash.
579 	 */
580 	if (chain->bref.key != xop->lhc ||
581 	    xop->head.name1_len != xop->head.name2_len ||
582 	    bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
583 		if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
584 			hammer2_inode_data_t *wipdata;
585 
586 			error = hammer2_chain_modify(chain, xop->head.mtid,
587 						     0, 0);
588 			if (error == 0) {
589 				wipdata = &chain->data->ipdata;
590 
591 				bzero(wipdata->filename,
592 				      sizeof(wipdata->filename));
593 				bcopy(xop->head.name2,
594 				      wipdata->filename,
595 				      xop->head.name2_len);
596 				wipdata->meta.name_key = xop->lhc;
597 				wipdata->meta.name_len = xop->head.name2_len;
598 			}
599 		}
600 		if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
601 			if (xop->head.name2_len <=
602 			    sizeof(chain->bref.check.buf)) {
603 				/*
604 				 * Remove any related data buffer, we can
605 				 * embed the filename in the bref itself.
606 				 */
607 				error = hammer2_chain_resize(
608 						chain, xop->head.mtid, 0, 0, 0);
609 				if (error == 0) {
610 					error = hammer2_chain_modify(
611 							chain, xop->head.mtid,
612 							0, 0);
613 				}
614 				if (error == 0) {
615 					bzero(chain->bref.check.buf,
616 					      sizeof(chain->bref.check.buf));
617 					bcopy(xop->head.name2,
618 					      chain->bref.check.buf,
619 					      xop->head.name2_len);
620 				}
621 			} else {
622 				/*
623 				 * Associate a data buffer with the bref.
624 				 * Zero it for consistency.  Note that the
625 				 * data buffer is not 64KB so use chain->bytes
626 				 * instead of sizeof().
627 				 */
628 				error = hammer2_chain_resize(
629 					chain, xop->head.mtid, 0,
630 					hammer2_getradix(HAMMER2_ALLOC_MIN), 0);
631 				if (error == 0) {
632 					error = hammer2_chain_modify(
633 						    chain, xop->head.mtid,
634 						    0, 0);
635 				}
636 				if (error == 0) {
637 					bzero(chain->data->buf, chain->bytes);
638 					bcopy(xop->head.name2,
639 					      chain->data->buf,
640 					      xop->head.name2_len);
641 				}
642 			}
643 			if (error == 0) {
644 				chain->bref.embed.dirent.namlen =
645 					xop->head.name2_len;
646 			}
647 		}
648 	}
649 
650 	/*
651 	 * The frontend will replicate this operation and is the real final
652 	 * authority, but adjust the inode's iparent field too if the inode
653 	 * is embedded in the directory.
654 	 */
655 	if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
656 	    chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
657 		hammer2_inode_data_t *wipdata;
658 
659 		error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
660 		if (error == 0) {
661 			wipdata = &chain->data->ipdata;
662 			wipdata->meta.iparent = xop->head.ip3->meta.inum;
663 		}
664 	}
665 
666 	/*
667 	 * Destroy any matching target(s) before creating the new entry.
668 	 * This will result in some ping-ponging of the directory key
669 	 * iterator but that is ok.
670 	 */
671 	parent = hammer2_inode_chain(xop->head.ip3, thr->clindex,
672 				     HAMMER2_RESOLVE_ALWAYS);
673 	if (parent == NULL) {
674 		error = HAMMER2_ERROR_EIO;
675 		goto done;
676 	}
677 
678 	if (error == 0) {
679 		tmp = hammer2_chain_lookup(&parent, &key_next,
680 					   xop->lhc & ~HAMMER2_DIRHASH_LOMASK,
681 					   xop->lhc | HAMMER2_DIRHASH_LOMASK,
682 					   &error,
683 					   HAMMER2_LOOKUP_ALWAYS);
684 		while (tmp) {
685 			if (hammer2_chain_dirent_test(tmp, xop->head.name2,
686 						      xop->head.name2_len)) {
687 				hammer2_chain_delete(parent, tmp,
688 						     xop->head.mtid, 0);
689 			}
690 			tmp = hammer2_chain_next(&parent, tmp, &key_next,
691 						 key_next,
692 						 xop->lhc |
693 						  HAMMER2_DIRHASH_LOMASK,
694 						 &error,
695 						 HAMMER2_LOOKUP_ALWAYS);
696 		}
697 	}
698 	if (error == 0) {
699 		/*
700 		 * A relookup is required before the create to properly
701 		 * position the parent chain.
702 		 */
703 		tmp = hammer2_chain_lookup(&parent, &key_next,
704 					   xop->lhc, xop->lhc,
705 					   &error, 0);
706 		KKASSERT(tmp == NULL);
707 		error = hammer2_chain_create(&parent, &chain,
708 					     pmp, HAMMER2_METH_DEFAULT,
709 					     xop->lhc, 0,
710 					     HAMMER2_BREF_TYPE_INODE,
711 					     HAMMER2_INODE_BYTES,
712 					     xop->head.mtid, 0, 0);
713 	}
714 done:
715 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
716 	if (parent) {
717 		hammer2_chain_unlock(parent);
718 		hammer2_chain_drop(parent);
719 	}
720 	if (chain) {
721 		hammer2_chain_unlock(chain);
722 		hammer2_chain_drop(chain);
723 	}
724 }
725 
726 /*
727  * Directory collision resolver scan helper (backend, threaded).
728  *
729  * Used by the inode create code to locate an unused lhc.
730  */
731 void
732 hammer2_xop_scanlhc(hammer2_thread_t *thr, hammer2_xop_t *arg)
733 {
734 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
735 	hammer2_chain_t *parent;
736 	hammer2_chain_t *chain;
737 	hammer2_key_t key_next;
738 	int error = 0;
739 
740 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
741 				     HAMMER2_RESOLVE_ALWAYS |
742 				     HAMMER2_RESOLVE_SHARED);
743 	if (parent == NULL) {
744 		kprintf("xop_nresolve: NULL parent\n");
745 		chain = NULL;
746 		error = HAMMER2_ERROR_EIO;
747 		goto done;
748 	}
749 
750 	/*
751 	 * Lookup all possibly conflicting directory entries, the feed
752 	 * inherits the chain's lock so do not unlock it on the iteration.
753 	 */
754 	chain = hammer2_chain_lookup(&parent, &key_next,
755 				     xop->lhc,
756 				     xop->lhc + HAMMER2_DIRHASH_LOMASK,
757 				     &error,
758 				     HAMMER2_LOOKUP_ALWAYS |
759 				     HAMMER2_LOOKUP_SHARED);
760 	while (chain) {
761 		error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
762 		if (error) {
763 			hammer2_chain_unlock(chain);
764 			hammer2_chain_drop(chain);
765 			chain = NULL;	/* safety */
766 			goto done;
767 		}
768 		chain = hammer2_chain_next(&parent, chain, &key_next,
769 					   key_next,
770 					   xop->lhc + HAMMER2_DIRHASH_LOMASK,
771 					   &error,
772 					   HAMMER2_LOOKUP_ALWAYS |
773 					   HAMMER2_LOOKUP_SHARED);
774 	}
775 done:
776 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
777 	if (parent) {
778 		hammer2_chain_unlock(parent);
779 		hammer2_chain_drop(parent);
780 	}
781 }
782 
783 /*
784  * Generic lookup of a specific key.
785  *
786  * Used by the inode hidden directory code to find the hidden directory.
787  */
788 void
789 hammer2_xop_lookup(hammer2_thread_t *thr, hammer2_xop_t *arg)
790 {
791 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
792 	hammer2_chain_t *parent;
793 	hammer2_chain_t *chain;
794 	hammer2_key_t key_next;
795 	int error = 0;
796 
797 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
798 				     HAMMER2_RESOLVE_ALWAYS |
799 				     HAMMER2_RESOLVE_SHARED);
800 	chain = NULL;
801 	if (parent == NULL) {
802 		error = HAMMER2_ERROR_EIO;
803 		goto done;
804 	}
805 
806 	/*
807 	 * Lookup all possibly conflicting directory entries, the feed
808 	 * inherits the chain's lock so do not unlock it on the iteration.
809 	 */
810 	chain = hammer2_chain_lookup(&parent, &key_next,
811 				     xop->lhc, xop->lhc,
812 				     &error,
813 				     HAMMER2_LOOKUP_ALWAYS |
814 				     HAMMER2_LOOKUP_SHARED);
815 	if (error == 0) {
816 		if (chain)
817 			error = chain->error;
818 		else
819 			error = HAMMER2_ERROR_ENOENT;
820 	}
821 	hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
822 
823 done:
824 	if (chain) {
825 		hammer2_chain_unlock(chain);
826 		hammer2_chain_drop(chain);
827 	}
828 	if (parent) {
829 		hammer2_chain_unlock(parent);
830 		hammer2_chain_drop(parent);
831 	}
832 }
833 
834 /*
835  * Generic scan
836  *
837  * WARNING! Fed chains must be locked shared so ownership can be transfered
838  *	    and to prevent frontend/backend stalls that would occur with an
839  *	    exclusive lock.  The shared lock also allows chain->data to be
840  *	    retained.
841  */
842 void
843 hammer2_xop_scanall(hammer2_thread_t *thr, hammer2_xop_t *arg)
844 {
845 	hammer2_xop_scanall_t *xop = &arg->xop_scanall;
846 	hammer2_chain_t *parent;
847 	hammer2_chain_t *chain;
848 	hammer2_key_t key_next;
849 	int error = 0;
850 
851 	/*
852 	 * Assert required flags.
853 	 */
854 	KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
855 	KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
856 
857 	/*
858 	 * The inode's chain is the iterator.  If we cannot acquire it our
859 	 * contribution ends here.
860 	 */
861 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
862 				     xop->resolve_flags);
863 	if (parent == NULL) {
864 		kprintf("xop_readdir: NULL parent\n");
865 		goto done;
866 	}
867 
868 	/*
869 	 * Generic scan of exact records.  Note that indirect blocks are
870 	 * automatically recursed and will not be returned.
871 	 */
872 	chain = hammer2_chain_lookup(&parent, &key_next,
873 				     xop->key_beg, xop->key_end,
874 				     &error, xop->lookup_flags);
875 	while (chain) {
876 		error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
877 		if (error)
878 			goto break2;
879 		chain = hammer2_chain_next(&parent, chain, &key_next,
880 					   key_next, xop->key_end,
881 					   &error, xop->lookup_flags);
882 	}
883 break2:
884 	if (chain) {
885 		hammer2_chain_unlock(chain);
886 		hammer2_chain_drop(chain);
887 	}
888 	hammer2_chain_unlock(parent);
889 	hammer2_chain_drop(parent);
890 done:
891 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
892 }
893