xref: /dflybsd-src/usr.sbin/makefs/hammer2/hammer2_xops.c (revision ec1c3f3acbcc9eec2e3e83bf248a95cca926a503)
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