#include <sys/zap.h>
#include <sys/dmu.h>
#include <sys/atomic.h>
+#include <sys/zfs_ctldir.h>
#include <sys/zfs_fuid.h>
#include <sys/sa.h>
#include <sys/zfs_sa.h>
zfs_match_find(zfs_sb_t *zsb, znode_t *dzp, char *name, boolean_t exact,
boolean_t update, int *deflags, pathname_t *rpnp, uint64_t *zoid)
{
+ boolean_t conflict = B_FALSE;
int error;
if (zsb->z_norm) {
matchtype_t mt = MT_FIRST;
- boolean_t conflict = B_FALSE;
size_t bufsz = 0;
char *buf = NULL;
*/
error = zap_lookup_norm(zsb->z_os, dzp->z_id, name, 8, 1,
zoid, mt, buf, bufsz, &conflict);
- if (!error && deflags)
- *deflags = conflict ? ED_CASE_CONFLICT : 0;
} else {
error = zap_lookup(zsb->z_os, dzp->z_id, name, 8, 1, zoid);
}
+
+ /*
+ * Allow multiple entries provided the first entry is
+ * the object id. Non-zpl consumers may safely make
+ * use of the additional space.
+ *
+ * XXX: This should be a feature flag for compatibility
+ */
+ if (error == EOVERFLOW)
+ error = 0;
+
+ if (zsb->z_norm && !error && deflags)
+ *deflags = conflict ? ED_CASE_CONFLICT : 0;
+
*zoid = ZFS_DIRENT_OBJ(*zoid);
#ifdef HAVE_DNLC
/*
* If we are a snapshot mounted under .zfs, return
- * the vp for the snapshot directory.
+ * the inode pointer for the snapshot directory.
*/
if ((error = sa_lookup(dzp->z_sa_hdl,
SA_ZPL_PARENT(zsb), &parent, sizeof (parent))) != 0)
return (error);
-#ifdef HAVE_SNAPSHOT
+
if (parent == dzp->z_id && zsb->z_parent != zsb) {
error = zfsctl_root_lookup(zsb->z_parent->z_ctldir,
- "snapshot", ipp, NULL, 0, NULL, kcred,
- NULL, NULL, NULL);
+ "snapshot", ipp, 0, kcred, NULL, NULL);
return (error);
}
-#endif /* HAVE_SNAPSHOT */
rw_enter(&dzp->z_parent_lock, RW_READER);
error = zfs_zget(zsb, parent, &zp);
if (error == 0)
*ipp = ZTOI(zp);
rw_exit(&dzp->z_parent_lock);
-#ifdef HAVE_SNAPSHOT
} else if (zfs_has_ctldir(dzp) && strcmp(name, ZFS_CTLDIR_NAME) == 0) {
*ipp = zfsctl_root(dzp);
-#endif /* HAVE_SNAPSHOT */
} else {
int zf;
}
/*
- * Clean up any znodes that had no links when we either crashed or
- * (force) umounted the file system.
- */
-void
-zfs_unlinked_drain(zfs_sb_t *zsb)
-{
- zap_cursor_t zc;
- zap_attribute_t zap;
- dmu_object_info_t doi;
- znode_t *zp;
- int error;
-
- /*
- * Interate over the contents of the unlinked set.
- */
- for (zap_cursor_init(&zc, zsb->z_os, zsb->z_unlinkedobj);
- zap_cursor_retrieve(&zc, &zap) == 0;
- zap_cursor_advance(&zc)) {
-
- /*
- * See what kind of object we have in list
- */
-
- error = dmu_object_info(zsb->z_os, zap.za_first_integer, &doi);
- if (error != 0)
- continue;
-
- ASSERT((doi.doi_type == DMU_OT_PLAIN_FILE_CONTENTS) ||
- (doi.doi_type == DMU_OT_DIRECTORY_CONTENTS));
- /*
- * We need to re-mark these list entries for deletion,
- * so we pull them back into core and set zp->z_unlinked.
- */
- error = zfs_zget(zsb, zap.za_first_integer, &zp);
-
- /*
- * We may pick up znodes that are already marked for deletion.
- * This could happen during the purge of an extended attribute
- * directory. All we need to do is skip over them, since they
- * are already in the system marked z_unlinked.
- */
- if (error != 0)
- continue;
-
- zp->z_unlinked = B_TRUE;
- iput(ZTOI(zp));
- }
- zap_cursor_fini(&zc);
-}
-
-/*
* Delete the entire contents of a directory. Return a count
* of the number of entries that could not be deleted. If we encounter
* an error, return a count of at least one so that the directory stays
return (skipped);
}
+/*
+ * Clean up any znodes that had no links when we either crashed or
+ * (force) umounted the file system.
+ */
+void
+zfs_unlinked_drain(zfs_sb_t *zsb)
+{
+ zap_cursor_t zc;
+ zap_attribute_t zap;
+ dmu_object_info_t doi;
+ znode_t *zp;
+ int error;
+
+ /*
+ * Interate over the contents of the unlinked set.
+ */
+ for (zap_cursor_init(&zc, zsb->z_os, zsb->z_unlinkedobj);
+ zap_cursor_retrieve(&zc, &zap) == 0;
+ zap_cursor_advance(&zc)) {
+
+ /*
+ * See what kind of object we have in list
+ */
+
+ error = dmu_object_info(zsb->z_os, zap.za_first_integer, &doi);
+ if (error != 0)
+ continue;
+
+ ASSERT((doi.doi_type == DMU_OT_PLAIN_FILE_CONTENTS) ||
+ (doi.doi_type == DMU_OT_DIRECTORY_CONTENTS));
+ /*
+ * We need to re-mark these list entries for deletion,
+ * so we pull them back into core and set zp->z_unlinked.
+ */
+ error = zfs_zget(zsb, zap.za_first_integer, &zp);
+
+ /*
+ * We may pick up znodes that are already marked for deletion.
+ * This could happen during the purge of an extended attribute
+ * directory. All we need to do is skip over them, since they
+ * are already in the system marked z_unlinked.
+ */
+ if (error != 0)
+ continue;
+
+ zp->z_unlinked = B_TRUE;
+
+ /*
+ * If this is an attribute directory, purge its contents.
+ */
+ if (S_ISDIR(ZTOI(zp)->i_mode) && (zp->z_pflags & ZFS_XATTR)) {
+ /*
+ * We don't need to check the return value of
+ * zfs_purgedir here, because zfs_rmnode will just
+ * return this xattr directory to the unlinked set
+ * until all of its xattrs are gone.
+ */
+ (void) zfs_purgedir(zp);
+ }
+
+ iput(ZTOI(zp));
+ }
+ zap_cursor_fini(&zc);
+}
+
void
zfs_rmnode(znode_t *zp)
{
dmu_tx_t *tx;
uint64_t acl_obj;
uint64_t xattr_obj;
+ uint64_t count;
int error;
ASSERT(zp->z_links == 0);
* If this is an attribute directory, purge its contents.
*/
if (S_ISDIR(ZTOI(zp)->i_mode) && (zp->z_pflags & ZFS_XATTR)) {
- if (zfs_purgedir(zp) != 0) {
+ error = zap_count(os, zp->z_id, &count);
+ if (error) {
+ zfs_znode_dmu_fini(zp);
+ return;
+ }
+
+ if (count > 0) {
+ taskq_t *taskq;
+
/*
- * Not enough space to delete some xattrs.
- * Leave it in the unlinked set.
+ * There are still directory entries in this xattr
+ * directory. Let zfs_unlinked_drain() deal with
+ * them to avoid deadlocking this process in the
+ * zfs_purgedir()->zfs_zget()->ilookup() callpath
+ * on the xattr inode's I_FREEING bit.
*/
- zfs_znode_dmu_fini(zp);
- zfs_inode_destroy(ZTOI(zp));
+ taskq = dsl_pool_iput_taskq(dmu_objset_pool(os));
+ taskq_dispatch(taskq, (task_func_t *)
+ zfs_unlinked_drain, zsb, TQ_SLEEP);
+ zfs_znode_dmu_fini(zp);
return;
}
}
* Not enough space. Leave the file in the unlinked set.
*/
zfs_znode_dmu_fini(zp);
- zfs_inode_destroy(ZTOI(zp));
return;
}
*/
dmu_tx_abort(tx);
zfs_znode_dmu_fini(zp);
- zfs_inode_destroy(ZTOI(zp));
goto out;
}
8, 1, &value, tx);
ASSERT(error == 0);
-#ifdef HAVE_DNLC
- dnlc_update(ZTOI(dzp), dl->dl_name, vp);
-#endif /* HAVE_DNLC */
-
return (0);
}
}
/*
- * Unlink zp from dl, and mark zp for deletion if this was the last link.
- * Can fail if zp is a mount point (EBUSY) or a non-empty directory (EEXIST).
+ * Unlink zp from dl, and mark zp for deletion if this was the last link. Can
+ * fail if zp is a mount point (EBUSY) or a non-empty directory (ENOTEMPTY).
* If 'unlinkedp' is NULL, we put unlinked znodes on the unlinked list.
* If it's non-NULL, we use it to indicate whether the znode needs deletion,
* and it's the caller's job to do it.
if (zp_is_dir && !zfs_dirempty(zp)) {
mutex_exit(&zp->z_lock);
- return (EEXIST);
+ return (ENOTEMPTY);
}
/*
return (ENOENT);
}
- if (zsb->z_vfs->mnt_flags & MNT_READONLY) {
+ if (zfs_is_readonly(zsb)) {
zfs_dirent_unlock(dl);
return (EROFS);
}
va.va_mode = S_IFDIR | S_ISVTX | 0777;
zfs_fuid_map_ids(zp, cr, &va.va_uid, &va.va_gid);
+ va.va_dentry = NULL;
error = zfs_make_xattrdir(zp, &va, xipp, cr);
zfs_dirent_unlock(dl);