mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-11-17 01:51:00 +03:00
zfs_znode: lift common code to a single shared file
For now, userspace has no znode implementation. Some of the property and path handling code is used there though and is the same on all platforms, so we only need a single copy of it. Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Signed-off-by: Rob Norris <robn@despairlabs.com> Sponsored-by: https://despairlabs.com/sponsor/ Closes #16492
This commit is contained in:
parent
4c9b59e541
commit
c22d56e3ed
@ -158,6 +158,8 @@ extern "C" {
|
||||
#define ZFS_DIRENT_OBJ(de) BF64_GET(de, 0, 48)
|
||||
|
||||
extern int zfs_obj_to_path(objset_t *osp, uint64_t obj, char *buf, int len);
|
||||
extern int zfs_obj_to_pobj(objset_t *osp, sa_handle_t *hdl,
|
||||
sa_attr_type_t *sa_table, uint64_t *pobjp, int *is_xattrdir);
|
||||
extern int zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value);
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
@ -47,7 +47,6 @@ nodist_libzpool_la_SOURCES = \
|
||||
\
|
||||
module/os/linux/zfs/vdev_file.c \
|
||||
module/os/linux/zfs/zfs_debug.c \
|
||||
module/os/linux/zfs/zfs_znode.c \
|
||||
module/os/linux/zfs/zio_crypt.c \
|
||||
\
|
||||
module/zcommon/cityhash.c \
|
||||
@ -183,6 +182,7 @@ nodist_libzpool_la_SOURCES = \
|
||||
module/zfs/zfs_ratelimit.c \
|
||||
module/zfs/zfs_rlock.c \
|
||||
module/zfs/zfs_sa.c \
|
||||
module/zfs/zfs_znode.c \
|
||||
module/zfs/zil.c \
|
||||
module/zfs/zio.c \
|
||||
module/zfs/zio_checksum.c \
|
||||
|
@ -424,6 +424,7 @@ ZFS_OBJS := \
|
||||
zfs_rlock.o \
|
||||
zfs_sa.o \
|
||||
zfs_vnops.o \
|
||||
zfs_znode.o \
|
||||
zil.o \
|
||||
zio.o \
|
||||
zio_checksum.o \
|
||||
@ -458,7 +459,7 @@ ZFS_OBJS_OS := \
|
||||
zfs_uio.o \
|
||||
zfs_vfsops.o \
|
||||
zfs_vnops_os.o \
|
||||
zfs_znode.o \
|
||||
zfs_znode_os.o \
|
||||
zio_crypt.o \
|
||||
zpl_ctldir.o \
|
||||
zpl_export.o \
|
||||
|
@ -212,7 +212,7 @@ SRCS+= abd_os.c \
|
||||
zfs_racct.c \
|
||||
zfs_vfsops.c \
|
||||
zfs_vnops_os.c \
|
||||
zfs_znode.c \
|
||||
zfs_znode_os.c \
|
||||
zio_crypt.c \
|
||||
zvol_os.c
|
||||
|
||||
@ -358,6 +358,7 @@ SRCS+= abd.c \
|
||||
zfs_rlock.c \
|
||||
zfs_sa.c \
|
||||
zfs_vnops.c \
|
||||
zfs_znode.c \
|
||||
zil.c \
|
||||
zio.c \
|
||||
zio_checksum.c \
|
||||
|
@ -27,7 +27,6 @@
|
||||
/* Portions Copyright 2007 Jeremy Teo */
|
||||
/* Portions Copyright 2011 Martin Matuska <mm@FreeBSD.org> */
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
@ -52,8 +51,6 @@
|
||||
#include <sys/zfs_fuid.h>
|
||||
#include <sys/dnode.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include <sys/dmu.h>
|
||||
#include <sys/dmu_objset.h>
|
||||
#include <sys/dmu_tx.h>
|
||||
@ -86,12 +83,6 @@ SYSCTL_INT(_debug_sizeof, OID_AUTO, znode, CTLFLAG_RD,
|
||||
#define ZNODE_STAT_ADD(stat) /* nothing */
|
||||
#endif /* ZNODE_STATS */
|
||||
|
||||
/*
|
||||
* Functions needed for userland (ie: libzpool) are not put under
|
||||
* #ifdef_KERNEL; the rest of the functions have dependencies
|
||||
* (such as VFS logic) that will not compile easily in userland.
|
||||
*/
|
||||
#ifdef _KERNEL
|
||||
#if !defined(KMEM_DEBUG)
|
||||
#define _ZFS_USE_SMR
|
||||
static uma_zone_t znode_uma_zone;
|
||||
@ -1787,376 +1778,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx)
|
||||
mutex_destroy(&zfsvfs->z_hold_mtx[i]);
|
||||
kmem_free(zfsvfs, sizeof (zfsvfs_t));
|
||||
}
|
||||
#endif /* _KERNEL */
|
||||
|
||||
static int
|
||||
zfs_sa_setup(objset_t *osp, sa_attr_type_t **sa_table)
|
||||
{
|
||||
uint64_t sa_obj = 0;
|
||||
int error;
|
||||
|
||||
error = zap_lookup(osp, MASTER_NODE_OBJ, ZFS_SA_ATTRS, 8, 1, &sa_obj);
|
||||
if (error != 0 && error != ENOENT)
|
||||
return (error);
|
||||
|
||||
error = sa_setup(osp, sa_obj, zfs_attr_table, ZPL_END, sa_table);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_grab_sa_handle(objset_t *osp, uint64_t obj, sa_handle_t **hdlp,
|
||||
dmu_buf_t **db, const void *tag)
|
||||
{
|
||||
dmu_object_info_t doi;
|
||||
int error;
|
||||
|
||||
if ((error = sa_buf_hold(osp, obj, tag, db)) != 0)
|
||||
return (error);
|
||||
|
||||
dmu_object_info_from_db(*db, &doi);
|
||||
if ((doi.doi_bonus_type != DMU_OT_SA &&
|
||||
doi.doi_bonus_type != DMU_OT_ZNODE) ||
|
||||
(doi.doi_bonus_type == DMU_OT_ZNODE &&
|
||||
doi.doi_bonus_size < sizeof (znode_phys_t))) {
|
||||
sa_buf_rele(*db, tag);
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
}
|
||||
|
||||
error = sa_handle_get(osp, obj, NULL, SA_HDL_PRIVATE, hdlp);
|
||||
if (error != 0) {
|
||||
sa_buf_rele(*db, tag);
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
zfs_release_sa_handle(sa_handle_t *hdl, dmu_buf_t *db, const void *tag)
|
||||
{
|
||||
sa_handle_destroy(hdl);
|
||||
sa_buf_rele(db, tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given an object number, return its parent object number and whether
|
||||
* or not the object is an extended attribute directory.
|
||||
*/
|
||||
static int
|
||||
zfs_obj_to_pobj(objset_t *osp, sa_handle_t *hdl, sa_attr_type_t *sa_table,
|
||||
uint64_t *pobjp, int *is_xattrdir)
|
||||
{
|
||||
uint64_t parent;
|
||||
uint64_t pflags;
|
||||
uint64_t mode;
|
||||
uint64_t parent_mode;
|
||||
sa_bulk_attr_t bulk[3];
|
||||
sa_handle_t *sa_hdl;
|
||||
dmu_buf_t *sa_db;
|
||||
int count = 0;
|
||||
int error;
|
||||
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_PARENT], NULL,
|
||||
&parent, sizeof (parent));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_FLAGS], NULL,
|
||||
&pflags, sizeof (pflags));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_MODE], NULL,
|
||||
&mode, sizeof (mode));
|
||||
|
||||
if ((error = sa_bulk_lookup(hdl, bulk, count)) != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* When a link is removed its parent pointer is not changed and will
|
||||
* be invalid. There are two cases where a link is removed but the
|
||||
* file stays around, when it goes to the delete queue and when there
|
||||
* are additional links.
|
||||
*/
|
||||
error = zfs_grab_sa_handle(osp, parent, &sa_hdl, &sa_db, FTAG);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = sa_lookup(sa_hdl, ZPL_MODE, &parent_mode, sizeof (parent_mode));
|
||||
zfs_release_sa_handle(sa_hdl, sa_db, FTAG);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
*is_xattrdir = ((pflags & ZFS_XATTR) != 0) && S_ISDIR(mode);
|
||||
|
||||
/*
|
||||
* Extended attributes can be applied to files, directories, etc.
|
||||
* Otherwise the parent must be a directory.
|
||||
*/
|
||||
if (!*is_xattrdir && !S_ISDIR(parent_mode))
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
*pobjp = parent;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given an object number, return some zpl level statistics
|
||||
*/
|
||||
static int
|
||||
zfs_obj_to_stats_impl(sa_handle_t *hdl, sa_attr_type_t *sa_table,
|
||||
zfs_stat_t *sb)
|
||||
{
|
||||
sa_bulk_attr_t bulk[4];
|
||||
int count = 0;
|
||||
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_MODE], NULL,
|
||||
&sb->zs_mode, sizeof (sb->zs_mode));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_GEN], NULL,
|
||||
&sb->zs_gen, sizeof (sb->zs_gen));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_LINKS], NULL,
|
||||
&sb->zs_links, sizeof (sb->zs_links));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_CTIME], NULL,
|
||||
&sb->zs_ctime, sizeof (sb->zs_ctime));
|
||||
|
||||
return (sa_bulk_lookup(hdl, bulk, count));
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
|
||||
sa_attr_type_t *sa_table, char *buf, int len)
|
||||
{
|
||||
sa_handle_t *sa_hdl;
|
||||
sa_handle_t *prevhdl = NULL;
|
||||
dmu_buf_t *prevdb = NULL;
|
||||
dmu_buf_t *sa_db = NULL;
|
||||
char *path = buf + len - 1;
|
||||
int error;
|
||||
|
||||
*path = '\0';
|
||||
sa_hdl = hdl;
|
||||
|
||||
uint64_t deleteq_obj;
|
||||
VERIFY0(zap_lookup(osp, MASTER_NODE_OBJ,
|
||||
ZFS_UNLINKED_SET, sizeof (uint64_t), 1, &deleteq_obj));
|
||||
error = zap_lookup_int(osp, deleteq_obj, obj);
|
||||
if (error == 0) {
|
||||
return (ESTALE);
|
||||
} else if (error != ENOENT) {
|
||||
return (error);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
uint64_t pobj;
|
||||
char component[MAXNAMELEN + 2];
|
||||
size_t complen;
|
||||
int is_xattrdir;
|
||||
|
||||
if (prevdb) {
|
||||
ASSERT3P(prevhdl, !=, NULL);
|
||||
zfs_release_sa_handle(prevhdl, prevdb, FTAG);
|
||||
}
|
||||
|
||||
if ((error = zfs_obj_to_pobj(osp, sa_hdl, sa_table, &pobj,
|
||||
&is_xattrdir)) != 0)
|
||||
break;
|
||||
|
||||
if (pobj == obj) {
|
||||
if (path[0] != '/')
|
||||
*--path = '/';
|
||||
break;
|
||||
}
|
||||
|
||||
component[0] = '/';
|
||||
if (is_xattrdir) {
|
||||
(void) sprintf(component + 1, "<xattrdir>");
|
||||
} else {
|
||||
error = zap_value_search(osp, pobj, obj,
|
||||
ZFS_DIRENT_OBJ(-1ULL), component + 1);
|
||||
if (error != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
complen = strlen(component);
|
||||
path -= complen;
|
||||
ASSERT3P(path, >=, buf);
|
||||
memcpy(path, component, complen);
|
||||
obj = pobj;
|
||||
|
||||
if (sa_hdl != hdl) {
|
||||
prevhdl = sa_hdl;
|
||||
prevdb = sa_db;
|
||||
}
|
||||
error = zfs_grab_sa_handle(osp, obj, &sa_hdl, &sa_db, FTAG);
|
||||
if (error != 0) {
|
||||
sa_hdl = prevhdl;
|
||||
sa_db = prevdb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sa_hdl != NULL && sa_hdl != hdl) {
|
||||
ASSERT3P(sa_db, !=, NULL);
|
||||
zfs_release_sa_handle(sa_hdl, sa_db, FTAG);
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
(void) memmove(buf, path, buf + len - path);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_obj_to_path(objset_t *osp, uint64_t obj, char *buf, int len)
|
||||
{
|
||||
sa_attr_type_t *sa_table;
|
||||
sa_handle_t *hdl;
|
||||
dmu_buf_t *db;
|
||||
int error;
|
||||
|
||||
error = zfs_sa_setup(osp, &sa_table);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len);
|
||||
|
||||
zfs_release_sa_handle(hdl, db, FTAG);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_obj_to_stats(objset_t *osp, uint64_t obj, zfs_stat_t *sb,
|
||||
char *buf, int len)
|
||||
{
|
||||
char *path = buf + len - 1;
|
||||
sa_attr_type_t *sa_table;
|
||||
sa_handle_t *hdl;
|
||||
dmu_buf_t *db;
|
||||
int error;
|
||||
|
||||
*path = '\0';
|
||||
|
||||
error = zfs_sa_setup(osp, &sa_table);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = zfs_obj_to_stats_impl(hdl, sa_table, sb);
|
||||
if (error != 0) {
|
||||
zfs_release_sa_handle(hdl, db, FTAG);
|
||||
return (error);
|
||||
}
|
||||
|
||||
error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len);
|
||||
|
||||
zfs_release_sa_handle(hdl, db, FTAG);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a property stored within the master node.
|
||||
*/
|
||||
int
|
||||
zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value)
|
||||
{
|
||||
uint64_t *cached_copy = NULL;
|
||||
|
||||
/*
|
||||
* Figure out where in the objset_t the cached copy would live, if it
|
||||
* is available for the requested property.
|
||||
*/
|
||||
if (os != NULL) {
|
||||
switch (prop) {
|
||||
case ZFS_PROP_VERSION:
|
||||
cached_copy = &os->os_version;
|
||||
break;
|
||||
case ZFS_PROP_NORMALIZE:
|
||||
cached_copy = &os->os_normalization;
|
||||
break;
|
||||
case ZFS_PROP_UTF8ONLY:
|
||||
cached_copy = &os->os_utf8only;
|
||||
break;
|
||||
case ZFS_PROP_CASE:
|
||||
cached_copy = &os->os_casesensitivity;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cached_copy != NULL && *cached_copy != OBJSET_PROP_UNINITIALIZED) {
|
||||
*value = *cached_copy;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the property wasn't cached, look up the file system's value for
|
||||
* the property. For the version property, we look up a slightly
|
||||
* different string.
|
||||
*/
|
||||
const char *pname;
|
||||
int error = ENOENT;
|
||||
if (prop == ZFS_PROP_VERSION) {
|
||||
pname = ZPL_VERSION_STR;
|
||||
} else {
|
||||
pname = zfs_prop_to_name(prop);
|
||||
}
|
||||
|
||||
if (os != NULL) {
|
||||
ASSERT3U(os->os_phys->os_type, ==, DMU_OST_ZFS);
|
||||
error = zap_lookup(os, MASTER_NODE_OBJ, pname, 8, 1, value);
|
||||
}
|
||||
|
||||
if (error == ENOENT) {
|
||||
/* No value set, use the default value */
|
||||
switch (prop) {
|
||||
case ZFS_PROP_VERSION:
|
||||
*value = ZPL_VERSION;
|
||||
break;
|
||||
case ZFS_PROP_NORMALIZE:
|
||||
case ZFS_PROP_UTF8ONLY:
|
||||
*value = 0;
|
||||
break;
|
||||
case ZFS_PROP_CASE:
|
||||
*value = ZFS_CASE_SENSITIVE;
|
||||
break;
|
||||
case ZFS_PROP_ACLTYPE:
|
||||
*value = ZFS_ACLTYPE_NFSV4;
|
||||
break;
|
||||
default:
|
||||
return (error);
|
||||
}
|
||||
error = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If one of the methods for getting the property value above worked,
|
||||
* copy it into the objset_t's cache.
|
||||
*/
|
||||
if (error == 0 && cached_copy != NULL) {
|
||||
*cached_copy = *value;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
zfs_znode_update_vfs(znode_t *zp)
|
||||
{
|
||||
vm_object_t object;
|
||||
|
||||
if ((object = ZTOV(zp)->v_object) == NULL ||
|
||||
zp->z_size == object->un_pager.vnp.vnp_size)
|
||||
return;
|
||||
|
||||
vnode_pager_setsize(ZTOV(zp), zp->z_size);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _KERNEL
|
||||
int
|
||||
zfs_znode_parent_and_name(znode_t *zp, znode_t **dzpp, char *buf)
|
||||
{
|
||||
@ -2186,9 +1808,7 @@ zfs_znode_parent_and_name(znode_t *zp, znode_t **dzpp, char *buf)
|
||||
err = zfs_zget(zfsvfs, parent, dzpp);
|
||||
return (err);
|
||||
}
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#ifdef _KERNEL
|
||||
int
|
||||
zfs_rlimit_fsize(off_t fsize)
|
||||
{
|
||||
@ -2211,4 +1831,3 @@ zfs_rlimit_fsize(off_t fsize)
|
||||
|
||||
return (EFBIG);
|
||||
}
|
||||
#endif /* _KERNEL */
|
@ -25,7 +25,6 @@
|
||||
|
||||
/* Portions Copyright 2007 Jeremy Teo */
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
@ -49,8 +48,6 @@
|
||||
#include <sys/dnode.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/zpl.h>
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#include <sys/dmu.h>
|
||||
#include <sys/dmu_objset.h>
|
||||
#include <sys/dmu_tx.h>
|
||||
@ -65,13 +62,6 @@
|
||||
#include "zfs_prop.h"
|
||||
#include "zfs_comutil.h"
|
||||
|
||||
/*
|
||||
* Functions needed for userland (ie: libzpool) are not put under
|
||||
* #ifdef_KERNEL; the rest of the functions have dependencies
|
||||
* (such as VFS logic) that will not compile easily in userland.
|
||||
*/
|
||||
#ifdef _KERNEL
|
||||
|
||||
static kmem_cache_t *znode_cache = NULL;
|
||||
static kmem_cache_t *znode_hold_cache = NULL;
|
||||
unsigned int zfs_object_mutex_size = ZFS_OBJ_MTX_SZ;
|
||||
@ -1972,360 +1962,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx)
|
||||
kmem_free(sb, sizeof (struct super_block));
|
||||
kmem_free(zfsvfs, sizeof (zfsvfs_t));
|
||||
}
|
||||
#endif /* _KERNEL */
|
||||
|
||||
static int
|
||||
zfs_sa_setup(objset_t *osp, sa_attr_type_t **sa_table)
|
||||
{
|
||||
uint64_t sa_obj = 0;
|
||||
int error;
|
||||
|
||||
error = zap_lookup(osp, MASTER_NODE_OBJ, ZFS_SA_ATTRS, 8, 1, &sa_obj);
|
||||
if (error != 0 && error != ENOENT)
|
||||
return (error);
|
||||
|
||||
error = sa_setup(osp, sa_obj, zfs_attr_table, ZPL_END, sa_table);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_grab_sa_handle(objset_t *osp, uint64_t obj, sa_handle_t **hdlp,
|
||||
dmu_buf_t **db, const void *tag)
|
||||
{
|
||||
dmu_object_info_t doi;
|
||||
int error;
|
||||
|
||||
if ((error = sa_buf_hold(osp, obj, tag, db)) != 0)
|
||||
return (error);
|
||||
|
||||
dmu_object_info_from_db(*db, &doi);
|
||||
if ((doi.doi_bonus_type != DMU_OT_SA &&
|
||||
doi.doi_bonus_type != DMU_OT_ZNODE) ||
|
||||
(doi.doi_bonus_type == DMU_OT_ZNODE &&
|
||||
doi.doi_bonus_size < sizeof (znode_phys_t))) {
|
||||
sa_buf_rele(*db, tag);
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
}
|
||||
|
||||
error = sa_handle_get(osp, obj, NULL, SA_HDL_PRIVATE, hdlp);
|
||||
if (error != 0) {
|
||||
sa_buf_rele(*db, tag);
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
zfs_release_sa_handle(sa_handle_t *hdl, dmu_buf_t *db, const void *tag)
|
||||
{
|
||||
sa_handle_destroy(hdl);
|
||||
sa_buf_rele(db, tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given an object number, return its parent object number and whether
|
||||
* or not the object is an extended attribute directory.
|
||||
*/
|
||||
static int
|
||||
zfs_obj_to_pobj(objset_t *osp, sa_handle_t *hdl, sa_attr_type_t *sa_table,
|
||||
uint64_t *pobjp, int *is_xattrdir)
|
||||
{
|
||||
uint64_t parent;
|
||||
uint64_t pflags;
|
||||
uint64_t mode;
|
||||
uint64_t parent_mode;
|
||||
sa_bulk_attr_t bulk[3];
|
||||
sa_handle_t *sa_hdl;
|
||||
dmu_buf_t *sa_db;
|
||||
int count = 0;
|
||||
int error;
|
||||
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_PARENT], NULL,
|
||||
&parent, sizeof (parent));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_FLAGS], NULL,
|
||||
&pflags, sizeof (pflags));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_MODE], NULL,
|
||||
&mode, sizeof (mode));
|
||||
|
||||
if ((error = sa_bulk_lookup(hdl, bulk, count)) != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* When a link is removed its parent pointer is not changed and will
|
||||
* be invalid. There are two cases where a link is removed but the
|
||||
* file stays around, when it goes to the delete queue and when there
|
||||
* are additional links.
|
||||
*/
|
||||
error = zfs_grab_sa_handle(osp, parent, &sa_hdl, &sa_db, FTAG);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = sa_lookup(sa_hdl, ZPL_MODE, &parent_mode, sizeof (parent_mode));
|
||||
zfs_release_sa_handle(sa_hdl, sa_db, FTAG);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
*is_xattrdir = ((pflags & ZFS_XATTR) != 0) && S_ISDIR(mode);
|
||||
|
||||
/*
|
||||
* Extended attributes can be applied to files, directories, etc.
|
||||
* Otherwise the parent must be a directory.
|
||||
*/
|
||||
if (!*is_xattrdir && !S_ISDIR(parent_mode))
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
*pobjp = parent;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given an object number, return some zpl level statistics
|
||||
*/
|
||||
static int
|
||||
zfs_obj_to_stats_impl(sa_handle_t *hdl, sa_attr_type_t *sa_table,
|
||||
zfs_stat_t *sb)
|
||||
{
|
||||
sa_bulk_attr_t bulk[4];
|
||||
int count = 0;
|
||||
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_MODE], NULL,
|
||||
&sb->zs_mode, sizeof (sb->zs_mode));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_GEN], NULL,
|
||||
&sb->zs_gen, sizeof (sb->zs_gen));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_LINKS], NULL,
|
||||
&sb->zs_links, sizeof (sb->zs_links));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_CTIME], NULL,
|
||||
&sb->zs_ctime, sizeof (sb->zs_ctime));
|
||||
|
||||
return (sa_bulk_lookup(hdl, bulk, count));
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
|
||||
sa_attr_type_t *sa_table, char *buf, int len)
|
||||
{
|
||||
sa_handle_t *sa_hdl;
|
||||
sa_handle_t *prevhdl = NULL;
|
||||
dmu_buf_t *prevdb = NULL;
|
||||
dmu_buf_t *sa_db = NULL;
|
||||
char *path = buf + len - 1;
|
||||
int error;
|
||||
|
||||
*path = '\0';
|
||||
sa_hdl = hdl;
|
||||
|
||||
uint64_t deleteq_obj;
|
||||
VERIFY0(zap_lookup(osp, MASTER_NODE_OBJ,
|
||||
ZFS_UNLINKED_SET, sizeof (uint64_t), 1, &deleteq_obj));
|
||||
error = zap_lookup_int(osp, deleteq_obj, obj);
|
||||
if (error == 0) {
|
||||
return (ESTALE);
|
||||
} else if (error != ENOENT) {
|
||||
return (error);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
uint64_t pobj = 0;
|
||||
char component[MAXNAMELEN + 2];
|
||||
size_t complen;
|
||||
int is_xattrdir = 0;
|
||||
|
||||
if (prevdb) {
|
||||
ASSERT(prevhdl != NULL);
|
||||
zfs_release_sa_handle(prevhdl, prevdb, FTAG);
|
||||
}
|
||||
|
||||
if ((error = zfs_obj_to_pobj(osp, sa_hdl, sa_table, &pobj,
|
||||
&is_xattrdir)) != 0)
|
||||
break;
|
||||
|
||||
if (pobj == obj) {
|
||||
if (path[0] != '/')
|
||||
*--path = '/';
|
||||
break;
|
||||
}
|
||||
|
||||
component[0] = '/';
|
||||
if (is_xattrdir) {
|
||||
strcpy(component + 1, "<xattrdir>");
|
||||
} else {
|
||||
error = zap_value_search(osp, pobj, obj,
|
||||
ZFS_DIRENT_OBJ(-1ULL), component + 1);
|
||||
if (error != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
complen = strlen(component);
|
||||
path -= complen;
|
||||
ASSERT(path >= buf);
|
||||
memcpy(path, component, complen);
|
||||
obj = pobj;
|
||||
|
||||
if (sa_hdl != hdl) {
|
||||
prevhdl = sa_hdl;
|
||||
prevdb = sa_db;
|
||||
}
|
||||
error = zfs_grab_sa_handle(osp, obj, &sa_hdl, &sa_db, FTAG);
|
||||
if (error != 0) {
|
||||
sa_hdl = prevhdl;
|
||||
sa_db = prevdb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sa_hdl != NULL && sa_hdl != hdl) {
|
||||
ASSERT(sa_db != NULL);
|
||||
zfs_release_sa_handle(sa_hdl, sa_db, FTAG);
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
(void) memmove(buf, path, buf + len - path);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_obj_to_path(objset_t *osp, uint64_t obj, char *buf, int len)
|
||||
{
|
||||
sa_attr_type_t *sa_table;
|
||||
sa_handle_t *hdl;
|
||||
dmu_buf_t *db;
|
||||
int error;
|
||||
|
||||
error = zfs_sa_setup(osp, &sa_table);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len);
|
||||
|
||||
zfs_release_sa_handle(hdl, db, FTAG);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_obj_to_stats(objset_t *osp, uint64_t obj, zfs_stat_t *sb,
|
||||
char *buf, int len)
|
||||
{
|
||||
char *path = buf + len - 1;
|
||||
sa_attr_type_t *sa_table;
|
||||
sa_handle_t *hdl;
|
||||
dmu_buf_t *db;
|
||||
int error;
|
||||
|
||||
*path = '\0';
|
||||
|
||||
error = zfs_sa_setup(osp, &sa_table);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = zfs_obj_to_stats_impl(hdl, sa_table, sb);
|
||||
if (error != 0) {
|
||||
zfs_release_sa_handle(hdl, db, FTAG);
|
||||
return (error);
|
||||
}
|
||||
|
||||
error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len);
|
||||
|
||||
zfs_release_sa_handle(hdl, db, FTAG);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a property stored within the master node.
|
||||
*/
|
||||
int
|
||||
zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value)
|
||||
{
|
||||
uint64_t *cached_copy = NULL;
|
||||
|
||||
/*
|
||||
* Figure out where in the objset_t the cached copy would live, if it
|
||||
* is available for the requested property.
|
||||
*/
|
||||
if (os != NULL) {
|
||||
switch (prop) {
|
||||
case ZFS_PROP_VERSION:
|
||||
cached_copy = &os->os_version;
|
||||
break;
|
||||
case ZFS_PROP_NORMALIZE:
|
||||
cached_copy = &os->os_normalization;
|
||||
break;
|
||||
case ZFS_PROP_UTF8ONLY:
|
||||
cached_copy = &os->os_utf8only;
|
||||
break;
|
||||
case ZFS_PROP_CASE:
|
||||
cached_copy = &os->os_casesensitivity;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cached_copy != NULL && *cached_copy != OBJSET_PROP_UNINITIALIZED) {
|
||||
*value = *cached_copy;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the property wasn't cached, look up the file system's value for
|
||||
* the property. For the version property, we look up a slightly
|
||||
* different string.
|
||||
*/
|
||||
const char *pname;
|
||||
int error = ENOENT;
|
||||
if (prop == ZFS_PROP_VERSION)
|
||||
pname = ZPL_VERSION_STR;
|
||||
else
|
||||
pname = zfs_prop_to_name(prop);
|
||||
|
||||
if (os != NULL) {
|
||||
ASSERT3U(os->os_phys->os_type, ==, DMU_OST_ZFS);
|
||||
error = zap_lookup(os, MASTER_NODE_OBJ, pname, 8, 1, value);
|
||||
}
|
||||
|
||||
if (error == ENOENT) {
|
||||
/* No value set, use the default value */
|
||||
switch (prop) {
|
||||
case ZFS_PROP_VERSION:
|
||||
*value = ZPL_VERSION;
|
||||
break;
|
||||
case ZFS_PROP_NORMALIZE:
|
||||
case ZFS_PROP_UTF8ONLY:
|
||||
*value = 0;
|
||||
break;
|
||||
case ZFS_PROP_CASE:
|
||||
*value = ZFS_CASE_SENSITIVE;
|
||||
break;
|
||||
case ZFS_PROP_ACLTYPE:
|
||||
*value = ZFS_ACLTYPE_OFF;
|
||||
break;
|
||||
default:
|
||||
return (error);
|
||||
}
|
||||
error = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If one of the methods for getting the property value above worked,
|
||||
* copy it into the objset_t's cache.
|
||||
*/
|
||||
if (error == 0 && cached_copy != NULL) {
|
||||
*cached_copy = *value;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
#if defined(_KERNEL)
|
||||
EXPORT_SYMBOL(zfs_create_fs);
|
||||
EXPORT_SYMBOL(zfs_obj_to_path);
|
||||
|
||||
@ -2335,4 +1972,3 @@ MODULE_PARM_DESC(zfs_object_mutex_size, "Size of znode hold array");
|
||||
module_param(zfs_unlink_suspend_progress, int, 0644);
|
||||
MODULE_PARM_DESC(zfs_unlink_suspend_progress, "Set to prevent async unlinks "
|
||||
"(debug - leaks space into the unlinked set)");
|
||||
#endif
|
397
module/zfs/zfs_znode.c
Normal file
397
module/zfs/zfs_znode.c
Normal file
@ -0,0 +1,397 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2014 Integros [integros.com]
|
||||
*/
|
||||
|
||||
/* Portions Copyright 2007 Jeremy Teo */
|
||||
/* Portions Copyright 2011 Martin Matuska <mm@FreeBSD.org> */
|
||||
|
||||
#include <sys/dmu.h>
|
||||
#include <sys/dmu_objset.h>
|
||||
#include <sys/dmu_tx.h>
|
||||
#include <sys/zfs_refcount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/zap.h>
|
||||
#include <sys/zfs_znode.h>
|
||||
#include <sys/sa.h>
|
||||
#include <sys/zfs_sa.h>
|
||||
#include <sys/zfs_stat.h>
|
||||
|
||||
#include "zfs_prop.h"
|
||||
#include "zfs_comutil.h"
|
||||
|
||||
static int
|
||||
zfs_sa_setup(objset_t *osp, sa_attr_type_t **sa_table)
|
||||
{
|
||||
uint64_t sa_obj = 0;
|
||||
int error;
|
||||
|
||||
error = zap_lookup(osp, MASTER_NODE_OBJ, ZFS_SA_ATTRS, 8, 1, &sa_obj);
|
||||
if (error != 0 && error != ENOENT)
|
||||
return (error);
|
||||
|
||||
error = sa_setup(osp, sa_obj, zfs_attr_table, ZPL_END, sa_table);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_grab_sa_handle(objset_t *osp, uint64_t obj, sa_handle_t **hdlp,
|
||||
dmu_buf_t **db, const void *tag)
|
||||
{
|
||||
dmu_object_info_t doi;
|
||||
int error;
|
||||
|
||||
if ((error = sa_buf_hold(osp, obj, tag, db)) != 0)
|
||||
return (error);
|
||||
|
||||
dmu_object_info_from_db(*db, &doi);
|
||||
if ((doi.doi_bonus_type != DMU_OT_SA &&
|
||||
doi.doi_bonus_type != DMU_OT_ZNODE) ||
|
||||
(doi.doi_bonus_type == DMU_OT_ZNODE &&
|
||||
doi.doi_bonus_size < sizeof (znode_phys_t))) {
|
||||
sa_buf_rele(*db, tag);
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
}
|
||||
|
||||
error = sa_handle_get(osp, obj, NULL, SA_HDL_PRIVATE, hdlp);
|
||||
if (error != 0) {
|
||||
sa_buf_rele(*db, tag);
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
zfs_release_sa_handle(sa_handle_t *hdl, dmu_buf_t *db, const void *tag)
|
||||
{
|
||||
sa_handle_destroy(hdl);
|
||||
sa_buf_rele(db, tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given an object number, return its parent object number and whether
|
||||
* or not the object is an extended attribute directory.
|
||||
*/
|
||||
int
|
||||
zfs_obj_to_pobj(objset_t *osp, sa_handle_t *hdl, sa_attr_type_t *sa_table,
|
||||
uint64_t *pobjp, int *is_xattrdir)
|
||||
{
|
||||
uint64_t parent;
|
||||
uint64_t pflags;
|
||||
uint64_t mode;
|
||||
uint64_t parent_mode;
|
||||
sa_bulk_attr_t bulk[3];
|
||||
sa_handle_t *sa_hdl;
|
||||
dmu_buf_t *sa_db;
|
||||
int count = 0;
|
||||
int error;
|
||||
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_PARENT], NULL,
|
||||
&parent, sizeof (parent));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_FLAGS], NULL,
|
||||
&pflags, sizeof (pflags));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_MODE], NULL,
|
||||
&mode, sizeof (mode));
|
||||
|
||||
if ((error = sa_bulk_lookup(hdl, bulk, count)) != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* When a link is removed its parent pointer is not changed and will
|
||||
* be invalid. There are two cases where a link is removed but the
|
||||
* file stays around, when it goes to the delete queue and when there
|
||||
* are additional links.
|
||||
*/
|
||||
error = zfs_grab_sa_handle(osp, parent, &sa_hdl, &sa_db, FTAG);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = sa_lookup(sa_hdl, ZPL_MODE, &parent_mode, sizeof (parent_mode));
|
||||
zfs_release_sa_handle(sa_hdl, sa_db, FTAG);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
*is_xattrdir = ((pflags & ZFS_XATTR) != 0) && S_ISDIR(mode);
|
||||
|
||||
/*
|
||||
* Extended attributes can be applied to files, directories, etc.
|
||||
* Otherwise the parent must be a directory.
|
||||
*/
|
||||
if (!*is_xattrdir && !S_ISDIR(parent_mode))
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
*pobjp = parent;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given an object number, return some zpl level statistics
|
||||
*/
|
||||
static int
|
||||
zfs_obj_to_stats_impl(sa_handle_t *hdl, sa_attr_type_t *sa_table,
|
||||
zfs_stat_t *sb)
|
||||
{
|
||||
sa_bulk_attr_t bulk[4];
|
||||
int count = 0;
|
||||
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_MODE], NULL,
|
||||
&sb->zs_mode, sizeof (sb->zs_mode));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_GEN], NULL,
|
||||
&sb->zs_gen, sizeof (sb->zs_gen));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_LINKS], NULL,
|
||||
&sb->zs_links, sizeof (sb->zs_links));
|
||||
SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_CTIME], NULL,
|
||||
&sb->zs_ctime, sizeof (sb->zs_ctime));
|
||||
|
||||
return (sa_bulk_lookup(hdl, bulk, count));
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
|
||||
sa_attr_type_t *sa_table, char *buf, int len)
|
||||
{
|
||||
sa_handle_t *sa_hdl;
|
||||
sa_handle_t *prevhdl = NULL;
|
||||
dmu_buf_t *prevdb = NULL;
|
||||
dmu_buf_t *sa_db = NULL;
|
||||
char *path = buf + len - 1;
|
||||
int error;
|
||||
|
||||
*path = '\0';
|
||||
sa_hdl = hdl;
|
||||
|
||||
uint64_t deleteq_obj;
|
||||
VERIFY0(zap_lookup(osp, MASTER_NODE_OBJ,
|
||||
ZFS_UNLINKED_SET, sizeof (uint64_t), 1, &deleteq_obj));
|
||||
error = zap_lookup_int(osp, deleteq_obj, obj);
|
||||
if (error == 0) {
|
||||
return (ESTALE);
|
||||
} else if (error != ENOENT) {
|
||||
return (error);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
uint64_t pobj = 0;
|
||||
char component[MAXNAMELEN + 2];
|
||||
size_t complen;
|
||||
int is_xattrdir = 0;
|
||||
|
||||
if (prevdb) {
|
||||
ASSERT3P(prevhdl, !=, NULL);
|
||||
zfs_release_sa_handle(prevhdl, prevdb, FTAG);
|
||||
}
|
||||
|
||||
if ((error = zfs_obj_to_pobj(osp, sa_hdl, sa_table, &pobj,
|
||||
&is_xattrdir)) != 0)
|
||||
break;
|
||||
|
||||
if (pobj == obj) {
|
||||
if (path[0] != '/')
|
||||
*--path = '/';
|
||||
break;
|
||||
}
|
||||
|
||||
component[0] = '/';
|
||||
if (is_xattrdir) {
|
||||
strcpy(component + 1, "<xattrdir>");
|
||||
} else {
|
||||
error = zap_value_search(osp, pobj, obj,
|
||||
ZFS_DIRENT_OBJ(-1ULL), component + 1);
|
||||
if (error != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
complen = strlen(component);
|
||||
path -= complen;
|
||||
ASSERT3P(path, >=, buf);
|
||||
memcpy(path, component, complen);
|
||||
obj = pobj;
|
||||
|
||||
if (sa_hdl != hdl) {
|
||||
prevhdl = sa_hdl;
|
||||
prevdb = sa_db;
|
||||
}
|
||||
error = zfs_grab_sa_handle(osp, obj, &sa_hdl, &sa_db, FTAG);
|
||||
if (error != 0) {
|
||||
sa_hdl = prevhdl;
|
||||
sa_db = prevdb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sa_hdl != NULL && sa_hdl != hdl) {
|
||||
ASSERT3P(sa_db, !=, NULL);
|
||||
zfs_release_sa_handle(sa_hdl, sa_db, FTAG);
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
(void) memmove(buf, path, buf + len - path);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_obj_to_path(objset_t *osp, uint64_t obj, char *buf, int len)
|
||||
{
|
||||
sa_attr_type_t *sa_table;
|
||||
sa_handle_t *hdl;
|
||||
dmu_buf_t *db;
|
||||
int error;
|
||||
|
||||
error = zfs_sa_setup(osp, &sa_table);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len);
|
||||
|
||||
zfs_release_sa_handle(hdl, db, FTAG);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_obj_to_stats(objset_t *osp, uint64_t obj, zfs_stat_t *sb,
|
||||
char *buf, int len)
|
||||
{
|
||||
char *path = buf + len - 1;
|
||||
sa_attr_type_t *sa_table;
|
||||
sa_handle_t *hdl;
|
||||
dmu_buf_t *db;
|
||||
int error;
|
||||
|
||||
*path = '\0';
|
||||
|
||||
error = zfs_sa_setup(osp, &sa_table);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = zfs_obj_to_stats_impl(hdl, sa_table, sb);
|
||||
if (error != 0) {
|
||||
zfs_release_sa_handle(hdl, db, FTAG);
|
||||
return (error);
|
||||
}
|
||||
|
||||
error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len);
|
||||
|
||||
zfs_release_sa_handle(hdl, db, FTAG);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a property stored within the master node.
|
||||
*/
|
||||
int
|
||||
zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value)
|
||||
{
|
||||
uint64_t *cached_copy = NULL;
|
||||
|
||||
/*
|
||||
* Figure out where in the objset_t the cached copy would live, if it
|
||||
* is available for the requested property.
|
||||
*/
|
||||
if (os != NULL) {
|
||||
switch (prop) {
|
||||
case ZFS_PROP_VERSION:
|
||||
cached_copy = &os->os_version;
|
||||
break;
|
||||
case ZFS_PROP_NORMALIZE:
|
||||
cached_copy = &os->os_normalization;
|
||||
break;
|
||||
case ZFS_PROP_UTF8ONLY:
|
||||
cached_copy = &os->os_utf8only;
|
||||
break;
|
||||
case ZFS_PROP_CASE:
|
||||
cached_copy = &os->os_casesensitivity;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cached_copy != NULL && *cached_copy != OBJSET_PROP_UNINITIALIZED) {
|
||||
*value = *cached_copy;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the property wasn't cached, look up the file system's value for
|
||||
* the property. For the version property, we look up a slightly
|
||||
* different string.
|
||||
*/
|
||||
const char *pname;
|
||||
int error = ENOENT;
|
||||
if (prop == ZFS_PROP_VERSION)
|
||||
pname = ZPL_VERSION_STR;
|
||||
else
|
||||
pname = zfs_prop_to_name(prop);
|
||||
|
||||
if (os != NULL) {
|
||||
ASSERT3U(os->os_phys->os_type, ==, DMU_OST_ZFS);
|
||||
error = zap_lookup(os, MASTER_NODE_OBJ, pname, 8, 1, value);
|
||||
}
|
||||
|
||||
if (error == ENOENT) {
|
||||
/* No value set, use the default value */
|
||||
switch (prop) {
|
||||
case ZFS_PROP_VERSION:
|
||||
*value = ZPL_VERSION;
|
||||
break;
|
||||
case ZFS_PROP_NORMALIZE:
|
||||
case ZFS_PROP_UTF8ONLY:
|
||||
*value = 0;
|
||||
break;
|
||||
case ZFS_PROP_CASE:
|
||||
*value = ZFS_CASE_SENSITIVE;
|
||||
break;
|
||||
case ZFS_PROP_ACLTYPE:
|
||||
#ifdef __FreeBSD__
|
||||
*value = ZFS_ACLTYPE_NFSV4;
|
||||
#else
|
||||
*value = ZFS_ACLTYPE_OFF;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return (error);
|
||||
}
|
||||
error = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If one of the methods for getting the property value above worked,
|
||||
* copy it into the objset_t's cache.
|
||||
*/
|
||||
if (error == 0 && cached_copy != NULL) {
|
||||
*cached_copy = *value;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
Loading…
Reference in New Issue
Block a user