The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/module/os/linux/zfs/zfs_sysfs.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * CDDL HEADER START
    3  *
    4  * The contents of this file are subject to the terms of the
    5  * Common Development and Distribution License (the "License").
    6  * You may not use this file except in compliance with the License.
    7  *
    8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
    9  * or https://opensource.org/licenses/CDDL-1.0.
   10  * See the License for the specific language governing permissions
   11  * and limitations under the License.
   12  *
   13  * When distributing Covered Code, include this CDDL HEADER in each
   14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   15  * If applicable, add the following below this CDDL HEADER, with the
   16  * fields enclosed by brackets "[]" replaced with your own identifying
   17  * information: Portions Copyright [yyyy] [name of copyright owner]
   18  *
   19  * CDDL HEADER END
   20  */
   21 /*
   22  * Copyright (c) 2018, 2019 by Delphix. All rights reserved.
   23  */
   24 
   25 #include <sys/types.h>
   26 #include <sys/param.h>
   27 #include <sys/zfeature.h>
   28 #include <sys/zfs_ioctl.h>
   29 #include <sys/zfs_sysfs.h>
   30 #include <sys/kmem.h>
   31 #include <sys/fs/zfs.h>
   32 #include <linux/kobject.h>
   33 
   34 #include "zfs_prop.h"
   35 
   36 #if !defined(_KERNEL)
   37 #error kernel builds only
   38 #endif
   39 
   40 /*
   41  * ZFS Module sysfs support
   42  *
   43  * This extends our sysfs '/sys/module/zfs' entry to include feature
   44  * and property attributes. The primary consumer of this information
   45  * is user processes, like the zfs CLI, that need to know what the
   46  * current loaded ZFS module supports. The libzfs binary will consult
   47  * this information when instantiating the zfs|zpool property tables
   48  * and the pool features table.
   49  *
   50  * The added top-level directories are:
   51  * /sys/module/zfs
   52  *              ├── features.kernel
   53  *              ├── features.pool
   54  *              ├── properties.dataset
   55  *              └── properties.pool
   56  *
   57  * The local interface for the zfs kobjects includes:
   58  *      zfs_kobj_init()
   59  *      zfs_kobj_add()
   60  *      zfs_kobj_release()
   61  *      zfs_kobj_add_attr()
   62  *      zfs_kobj_fini()
   63  */
   64 
   65 /*
   66  * A zfs_mod_kobj_t represents a zfs kobject under '/sys/module/zfs'
   67  */
   68 typedef struct zfs_mod_kobj zfs_mod_kobj_t;
   69 struct zfs_mod_kobj {
   70         struct kobject          zko_kobj;
   71         struct kobj_type        zko_kobj_type;
   72         struct sysfs_ops        zko_sysfs_ops;
   73         size_t                  zko_attr_count;
   74         struct attribute        *zko_attr_list;         /* allocated */
   75         struct attribute_group  zko_default_group;      /* .attrs allocated */
   76         const struct attribute_group    *zko_default_groups[2];
   77         size_t                  zko_child_count;
   78         zfs_mod_kobj_t          *zko_children;          /* allocated */
   79 };
   80 
   81 #define ATTR_TABLE_SIZE(cnt)    (sizeof (struct attribute) * (cnt))
   82 /* Note +1 for NULL terminator slot */
   83 #define DEFAULT_ATTR_SIZE(cnt)  (sizeof (struct attribute *) * (cnt + 1))
   84 #define CHILD_TABLE_SIZE(cnt)   (sizeof (zfs_mod_kobj_t) * (cnt))
   85 
   86 /*
   87  * These are the top-level kobjects under '/sys/module/zfs/'
   88  */
   89 static zfs_mod_kobj_t kernel_features_kobj;
   90 static zfs_mod_kobj_t pool_features_kobj;
   91 static zfs_mod_kobj_t dataset_props_kobj;
   92 static zfs_mod_kobj_t vdev_props_kobj;
   93 static zfs_mod_kobj_t pool_props_kobj;
   94 
   95 /*
   96  * The show function is used to provide the content
   97  * of an attribute into a PAGE_SIZE buffer.
   98  */
   99 typedef ssize_t (*sysfs_show_func)(struct kobject *, struct attribute *,
  100     char *);
  101 
  102 static void
  103 zfs_kobj_fini(zfs_mod_kobj_t *zkobj)
  104 {
  105         /* finalize any child kobjects */
  106         if (zkobj->zko_child_count != 0) {
  107                 ASSERT(zkobj->zko_children);
  108                 for (int i = 0; i < zkobj->zko_child_count; i++)
  109                         zfs_kobj_fini(&zkobj->zko_children[i]);
  110         }
  111 
  112         /* kobject_put() will call zfs_kobj_release() to release memory */
  113         kobject_del(&zkobj->zko_kobj);
  114         kobject_put(&zkobj->zko_kobj);
  115 }
  116 
  117 static void
  118 zfs_kobj_release(struct kobject *kobj)
  119 {
  120         zfs_mod_kobj_t *zkobj = container_of(kobj, zfs_mod_kobj_t, zko_kobj);
  121 
  122         if (zkobj->zko_attr_list != NULL) {
  123                 ASSERT3S(zkobj->zko_attr_count, !=, 0);
  124                 kmem_free(zkobj->zko_attr_list,
  125                     ATTR_TABLE_SIZE(zkobj->zko_attr_count));
  126                 zkobj->zko_attr_list = NULL;
  127         }
  128 
  129         if (zkobj->zko_default_group.attrs != NULL) {
  130                 kmem_free(zkobj->zko_default_group.attrs,
  131                     DEFAULT_ATTR_SIZE(zkobj->zko_attr_count));
  132                 zkobj->zko_default_group.attrs = NULL;
  133         }
  134 
  135         if (zkobj->zko_child_count != 0) {
  136                 ASSERT(zkobj->zko_children);
  137 
  138                 kmem_free(zkobj->zko_children,
  139                     CHILD_TABLE_SIZE(zkobj->zko_child_count));
  140                 zkobj->zko_child_count = 0;
  141                 zkobj->zko_children = NULL;
  142         }
  143 
  144         zkobj->zko_attr_count = 0;
  145 }
  146 
  147 #ifndef sysfs_attr_init
  148 #define sysfs_attr_init(attr) do {} while (0)
  149 #endif
  150 
  151 static void
  152 zfs_kobj_add_attr(zfs_mod_kobj_t *zkobj, int attr_num, const char *attr_name)
  153 {
  154         VERIFY3U(attr_num, <, zkobj->zko_attr_count);
  155         ASSERT(zkobj->zko_attr_list);
  156         ASSERT(zkobj->zko_default_group.attrs);
  157 
  158         zkobj->zko_attr_list[attr_num].name = attr_name;
  159         zkobj->zko_attr_list[attr_num].mode = 0444;
  160         zkobj->zko_default_group.attrs[attr_num] =
  161             &zkobj->zko_attr_list[attr_num];
  162         sysfs_attr_init(&zkobj->zko_attr_list[attr_num]);
  163 }
  164 
  165 static int
  166 zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt,
  167     sysfs_show_func show_func)
  168 {
  169         /*
  170          * Initialize object's attributes. Count can be zero.
  171          */
  172         if (attr_cnt > 0) {
  173                 zkobj->zko_attr_list = kmem_zalloc(ATTR_TABLE_SIZE(attr_cnt),
  174                     KM_SLEEP);
  175                 if (zkobj->zko_attr_list == NULL)
  176                         return (ENOMEM);
  177         }
  178         /* this will always have at least one slot for NULL termination */
  179         zkobj->zko_default_group.attrs =
  180             kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt), KM_SLEEP);
  181         if (zkobj->zko_default_group.attrs == NULL) {
  182                 if (zkobj->zko_attr_list != NULL) {
  183                         kmem_free(zkobj->zko_attr_list,
  184                             ATTR_TABLE_SIZE(attr_cnt));
  185                 }
  186                 return (ENOMEM);
  187         }
  188         zkobj->zko_attr_count = attr_cnt;
  189         zkobj->zko_default_groups[0] = &zkobj->zko_default_group;
  190 #ifdef HAVE_SYSFS_DEFAULT_GROUPS
  191         zkobj->zko_kobj_type.default_groups = zkobj->zko_default_groups;
  192 #else
  193         zkobj->zko_kobj_type.default_attrs = zkobj->zko_default_group.attrs;
  194 #endif
  195 
  196         if (child_cnt > 0) {
  197                 zkobj->zko_children = kmem_zalloc(CHILD_TABLE_SIZE(child_cnt),
  198                     KM_SLEEP);
  199                 if (zkobj->zko_children == NULL) {
  200                         if (zkobj->zko_default_group.attrs != NULL) {
  201                                 kmem_free(zkobj->zko_default_group.attrs,
  202                                     DEFAULT_ATTR_SIZE(attr_cnt));
  203                         }
  204                         if (zkobj->zko_attr_list != NULL) {
  205                                 kmem_free(zkobj->zko_attr_list,
  206                                     ATTR_TABLE_SIZE(attr_cnt));
  207                         }
  208                         return (ENOMEM);
  209                 }
  210                 zkobj->zko_child_count = child_cnt;
  211         }
  212 
  213         zkobj->zko_sysfs_ops.show = show_func;
  214         zkobj->zko_kobj_type.sysfs_ops = &zkobj->zko_sysfs_ops;
  215         zkobj->zko_kobj_type.release = zfs_kobj_release;
  216 
  217         return (0);
  218 }
  219 
  220 static int
  221 zfs_kobj_add(zfs_mod_kobj_t *zkobj, struct kobject *parent, const char *name)
  222 {
  223         /* zko_default_group.attrs must be NULL terminated */
  224         ASSERT(zkobj->zko_default_group.attrs != NULL);
  225         ASSERT(zkobj->zko_default_group.attrs[zkobj->zko_attr_count] == NULL);
  226 
  227         kobject_init(&zkobj->zko_kobj, &zkobj->zko_kobj_type);
  228         return (kobject_add(&zkobj->zko_kobj, parent, name));
  229 }
  230 
  231 /*
  232  * Each zfs property has these common attributes
  233  */
  234 static const char *const zprop_attrs[]  = {
  235         "type",
  236         "readonly",
  237         "setonce",
  238         "visible",
  239         "values",
  240         "default",
  241         "datasets"      /* zfs properties only */
  242 };
  243 
  244 #define ZFS_PROP_ATTR_COUNT     ARRAY_SIZE(zprop_attrs)
  245 #define ZPOOL_PROP_ATTR_COUNT   (ZFS_PROP_ATTR_COUNT - 1)
  246 
  247 static const char *const zprop_types[]  = {
  248         "number",
  249         "string",
  250         "index",
  251 };
  252 
  253 typedef struct zfs_type_map {
  254         zfs_type_t      ztm_type;
  255         const char      *ztm_name;
  256 } zfs_type_map_t;
  257 
  258 static const zfs_type_map_t type_map[] = {
  259         {ZFS_TYPE_FILESYSTEM,   "filesystem"},
  260         {ZFS_TYPE_SNAPSHOT,     "snapshot"},
  261         {ZFS_TYPE_VOLUME,       "volume"},
  262         {ZFS_TYPE_BOOKMARK,     "bookmark"}
  263 };
  264 
  265 /*
  266  * Show the content for a zfs property attribute
  267  */
  268 static ssize_t
  269 zprop_sysfs_show(const char *attr_name, const zprop_desc_t *property,
  270     char *buf, size_t buflen)
  271 {
  272         const char *show_str;
  273         char number[32];
  274 
  275         /* For dataset properties list the dataset types that apply */
  276         if (strcmp(attr_name, "datasets") == 0 &&
  277             property->pd_types != ZFS_TYPE_POOL) {
  278                 int len = 0;
  279 
  280                 for (int i = 0; i < ARRAY_SIZE(type_map); i++) {
  281                         if (type_map[i].ztm_type & property->pd_types)  {
  282                                 len += kmem_scnprintf(buf + len, buflen - len,
  283                                     "%s ", type_map[i].ztm_name);
  284                         }
  285                 }
  286                 len += kmem_scnprintf(buf + len, buflen - len, "\n");
  287                 return (len);
  288         }
  289 
  290         if (strcmp(attr_name, "type") == 0) {
  291                 show_str = zprop_types[property->pd_proptype];
  292         } else if (strcmp(attr_name, "readonly") == 0) {
  293                 show_str = property->pd_attr == PROP_READONLY ? "1" : "";
  294         } else if (strcmp(attr_name, "setonce") == 0) {
  295                 show_str = property->pd_attr == PROP_ONETIME ? "1" : "";
  296         } else if (strcmp(attr_name, "visible") == 0) {
  297                 show_str = property->pd_visible ? "1" : "";
  298         } else if (strcmp(attr_name, "values") == 0) {
  299                 show_str = property->pd_values ? property->pd_values : "";
  300         } else if (strcmp(attr_name, "default") == 0) {
  301                 switch (property->pd_proptype) {
  302                 case PROP_TYPE_NUMBER:
  303                         (void) snprintf(number, sizeof (number), "%llu",
  304                             (u_longlong_t)property->pd_numdefault);
  305                         show_str = number;
  306                         break;
  307                 case PROP_TYPE_STRING:
  308                         show_str = property->pd_strdefault ?
  309                             property->pd_strdefault : "";
  310                         break;
  311                 case PROP_TYPE_INDEX:
  312                         if (zprop_index_to_string(property->pd_propnum,
  313                             property->pd_numdefault, &show_str,
  314                             property->pd_types) != 0) {
  315                                 show_str = "";
  316                         }
  317                         break;
  318                 default:
  319                         return (0);
  320                 }
  321         } else {
  322                 return (0);
  323         }
  324 
  325         return (snprintf(buf, buflen, "%s\n", show_str));
  326 }
  327 
  328 static ssize_t
  329 dataset_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
  330 {
  331         zfs_prop_t prop = zfs_name_to_prop(kobject_name(kobj));
  332         zprop_desc_t *prop_tbl = zfs_prop_get_table();
  333         ssize_t len;
  334 
  335         ASSERT3U(prop, <, ZFS_NUM_PROPS);
  336 
  337         len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
  338 
  339         return (len);
  340 }
  341 
  342 static ssize_t
  343 vdev_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
  344 {
  345         vdev_prop_t prop = vdev_name_to_prop(kobject_name(kobj));
  346         zprop_desc_t *prop_tbl = vdev_prop_get_table();
  347         ssize_t len;
  348 
  349         ASSERT3U(prop, <, VDEV_NUM_PROPS);
  350 
  351         len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
  352 
  353         return (len);
  354 }
  355 
  356 static ssize_t
  357 pool_property_show(struct kobject *kobj, struct attribute *attr, char *buf)
  358 {
  359         zpool_prop_t prop = zpool_name_to_prop(kobject_name(kobj));
  360         zprop_desc_t *prop_tbl = zpool_prop_get_table();
  361         ssize_t len;
  362 
  363         ASSERT3U(prop, <, ZPOOL_NUM_PROPS);
  364 
  365         len = zprop_sysfs_show(attr->name, &prop_tbl[prop], buf, PAGE_SIZE);
  366 
  367         return (len);
  368 }
  369 
  370 /*
  371  * ZFS kernel feature attributes for '/sys/module/zfs/features.kernel'
  372  *
  373  * This list is intended for kernel features that don't have a pool feature
  374  * association or that extend existing user kernel interfaces.
  375  *
  376  * A user process can easily check if the running zfs kernel module
  377  * supports the new feature.
  378  */
  379 static const char *const zfs_kernel_features[] = {
  380         /* --> Add new kernel features here */
  381         "com.delphix:vdev_initialize",
  382         "org.zfsonlinux:vdev_trim",
  383         "org.openzfs:l2arc_persistent",
  384 };
  385 
  386 #define KERNEL_FEATURE_COUNT    ARRAY_SIZE(zfs_kernel_features)
  387 
  388 static ssize_t
  389 kernel_feature_show(struct kobject *kobj, struct attribute *attr, char *buf)
  390 {
  391         if (strcmp(attr->name, "supported") == 0)
  392                 return (snprintf(buf, PAGE_SIZE, "yes\n"));
  393         return (0);
  394 }
  395 
  396 static void
  397 kernel_feature_to_kobj(zfs_mod_kobj_t *parent, int slot, const char *name)
  398 {
  399         zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[slot];
  400 
  401         ASSERT3U(slot, <, KERNEL_FEATURE_COUNT);
  402         ASSERT(name);
  403 
  404         int err = zfs_kobj_init(zfs_kobj, 1, 0, kernel_feature_show);
  405         if (err)
  406                 return;
  407 
  408         zfs_kobj_add_attr(zfs_kobj, 0, "supported");
  409 
  410         err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
  411         if (err)
  412                 zfs_kobj_release(&zfs_kobj->zko_kobj);
  413 }
  414 
  415 static int
  416 zfs_kernel_features_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent)
  417 {
  418         /*
  419          * Create a parent kobject to host kernel features.
  420          *
  421          * '/sys/module/zfs/features.kernel'
  422          */
  423         int err = zfs_kobj_init(zfs_kobj, 0, KERNEL_FEATURE_COUNT,
  424             kernel_feature_show);
  425         if (err)
  426                 return (err);
  427         err = zfs_kobj_add(zfs_kobj, parent, ZFS_SYSFS_KERNEL_FEATURES);
  428         if (err) {
  429                 zfs_kobj_release(&zfs_kobj->zko_kobj);
  430                 return (err);
  431         }
  432 
  433         /*
  434          * Now create a kobject for each feature.
  435          *
  436          * '/sys/module/zfs/features.kernel/<feature>'
  437          */
  438         for (int f = 0; f < KERNEL_FEATURE_COUNT; f++)
  439                 kernel_feature_to_kobj(zfs_kobj, f, zfs_kernel_features[f]);
  440 
  441         return (0);
  442 }
  443 
  444 /*
  445  * Each pool feature has these common attributes
  446  */
  447 static const char *const pool_feature_attrs[]  = {
  448         "description",
  449         "guid",
  450         "uname",
  451         "readonly_compatible",
  452         "required_for_mos",
  453         "activate_on_enable",
  454         "per_dataset"
  455 };
  456 
  457 #define ZPOOL_FEATURE_ATTR_COUNT        ARRAY_SIZE(pool_feature_attrs)
  458 
  459 /*
  460  * Show the content for the given zfs pool feature attribute
  461  */
  462 static ssize_t
  463 pool_feature_show(struct kobject *kobj, struct attribute *attr, char *buf)
  464 {
  465         spa_feature_t fid;
  466 
  467         if (zfeature_lookup_guid(kobject_name(kobj), &fid) != 0)
  468                 return (0);
  469 
  470         ASSERT3U(fid, <, SPA_FEATURES);
  471 
  472         zfeature_flags_t flags = spa_feature_table[fid].fi_flags;
  473         const char *show_str = NULL;
  474 
  475         if (strcmp(attr->name, "description") == 0) {
  476                 show_str = spa_feature_table[fid].fi_desc;
  477         } else if (strcmp(attr->name, "guid") == 0) {
  478                 show_str = spa_feature_table[fid].fi_guid;
  479         } else if (strcmp(attr->name, "uname") == 0) {
  480                 show_str = spa_feature_table[fid].fi_uname;
  481         } else if (strcmp(attr->name, "readonly_compatible") == 0) {
  482                 show_str = flags & ZFEATURE_FLAG_READONLY_COMPAT ? "1" : "";
  483         } else if (strcmp(attr->name, "required_for_mos") == 0) {
  484                 show_str = flags & ZFEATURE_FLAG_MOS ? "1" : "";
  485         } else if (strcmp(attr->name, "activate_on_enable") == 0) {
  486                 show_str = flags & ZFEATURE_FLAG_ACTIVATE_ON_ENABLE ? "1" : "";
  487         } else if (strcmp(attr->name, "per_dataset") == 0) {
  488                 show_str = flags & ZFEATURE_FLAG_PER_DATASET ? "1" : "";
  489         }
  490         if (show_str == NULL)
  491                 return (0);
  492 
  493         return (snprintf(buf, PAGE_SIZE, "%s\n", show_str));
  494 }
  495 
  496 static void
  497 pool_feature_to_kobj(zfs_mod_kobj_t *parent, spa_feature_t fid,
  498     const char *name)
  499 {
  500         zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[fid];
  501 
  502         ASSERT3U(fid, <, SPA_FEATURES);
  503         ASSERT(name);
  504 
  505         int err = zfs_kobj_init(zfs_kobj, ZPOOL_FEATURE_ATTR_COUNT, 0,
  506             pool_feature_show);
  507         if (err)
  508                 return;
  509 
  510         for (int i = 0; i < ZPOOL_FEATURE_ATTR_COUNT; i++)
  511                 zfs_kobj_add_attr(zfs_kobj, i, pool_feature_attrs[i]);
  512 
  513         err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
  514         if (err)
  515                 zfs_kobj_release(&zfs_kobj->zko_kobj);
  516 }
  517 
  518 static int
  519 zfs_pool_features_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent)
  520 {
  521         /*
  522          * Create a parent kobject to host pool features.
  523          *
  524          * '/sys/module/zfs/features.pool'
  525          */
  526         int err = zfs_kobj_init(zfs_kobj, 0, SPA_FEATURES, pool_feature_show);
  527         if (err)
  528                 return (err);
  529         err = zfs_kobj_add(zfs_kobj, parent, ZFS_SYSFS_POOL_FEATURES);
  530         if (err) {
  531                 zfs_kobj_release(&zfs_kobj->zko_kobj);
  532                 return (err);
  533         }
  534 
  535         /*
  536          * Now create a kobject for each feature.
  537          *
  538          * '/sys/module/zfs/features.pool/<feature>'
  539          */
  540         for (spa_feature_t i = 0; i < SPA_FEATURES; i++)
  541                 pool_feature_to_kobj(zfs_kobj, i, spa_feature_table[i].fi_guid);
  542 
  543         return (0);
  544 }
  545 
  546 typedef struct prop_to_kobj_arg {
  547         zprop_desc_t    *p2k_table;
  548         zfs_mod_kobj_t  *p2k_parent;
  549         sysfs_show_func p2k_show_func;
  550         int             p2k_attr_count;
  551 } prop_to_kobj_arg_t;
  552 
  553 static int
  554 zprop_to_kobj(int prop, void *args)
  555 {
  556         prop_to_kobj_arg_t *data = args;
  557         zfs_mod_kobj_t *parent = data->p2k_parent;
  558         zfs_mod_kobj_t *zfs_kobj = &parent->zko_children[prop];
  559         const char *name = data->p2k_table[prop].pd_name;
  560         int err;
  561 
  562         ASSERT(name);
  563 
  564         err = zfs_kobj_init(zfs_kobj, data->p2k_attr_count, 0,
  565             data->p2k_show_func);
  566         if (err)
  567                 return (ZPROP_CONT);
  568 
  569         for (int i = 0; i < data->p2k_attr_count; i++)
  570                 zfs_kobj_add_attr(zfs_kobj, i, zprop_attrs[i]);
  571 
  572         err = zfs_kobj_add(zfs_kobj, &parent->zko_kobj, name);
  573         if (err)
  574                 zfs_kobj_release(&zfs_kobj->zko_kobj);
  575 
  576         return (ZPROP_CONT);
  577 }
  578 
  579 static int
  580 zfs_sysfs_properties_init(zfs_mod_kobj_t *zfs_kobj, struct kobject *parent,
  581     zfs_type_t type)
  582 {
  583         prop_to_kobj_arg_t context;
  584         const char *name;
  585         int err;
  586 
  587         /*
  588          * Create a parent kobject to host properties.
  589          *
  590          * '/sys/module/zfs/properties.<type>'
  591          */
  592         if (type == ZFS_TYPE_POOL) {
  593                 name = ZFS_SYSFS_POOL_PROPERTIES;
  594                 context.p2k_table = zpool_prop_get_table();
  595                 context.p2k_attr_count = ZPOOL_PROP_ATTR_COUNT;
  596                 context.p2k_parent = zfs_kobj;
  597                 context.p2k_show_func = pool_property_show;
  598                 err = zfs_kobj_init(zfs_kobj, 0, ZPOOL_NUM_PROPS,
  599                     pool_property_show);
  600         } else if (type == ZFS_TYPE_VDEV) {
  601                 name = ZFS_SYSFS_VDEV_PROPERTIES;
  602                 context.p2k_table = vdev_prop_get_table();
  603                 context.p2k_attr_count = ZPOOL_PROP_ATTR_COUNT;
  604                 context.p2k_parent = zfs_kobj;
  605                 context.p2k_show_func = vdev_property_show;
  606                 err = zfs_kobj_init(zfs_kobj, 0, VDEV_NUM_PROPS,
  607                     vdev_property_show);
  608         } else {
  609                 name = ZFS_SYSFS_DATASET_PROPERTIES;
  610                 context.p2k_table = zfs_prop_get_table();
  611                 context.p2k_attr_count = ZFS_PROP_ATTR_COUNT;
  612                 context.p2k_parent = zfs_kobj;
  613                 context.p2k_show_func = dataset_property_show;
  614                 err = zfs_kobj_init(zfs_kobj, 0, ZFS_NUM_PROPS,
  615                     dataset_property_show);
  616         }
  617 
  618         if (err)
  619                 return (err);
  620 
  621         err = zfs_kobj_add(zfs_kobj, parent, name);
  622         if (err) {
  623                 zfs_kobj_release(&zfs_kobj->zko_kobj);
  624                 return (err);
  625         }
  626 
  627         /*
  628          * Create a kobject for each property.
  629          *
  630          * '/sys/module/zfs/properties.<type>/<property>'
  631          */
  632         (void) zprop_iter_common(zprop_to_kobj, &context, B_TRUE,
  633             B_FALSE, type);
  634 
  635         return (err);
  636 }
  637 
  638 void
  639 zfs_sysfs_init(void)
  640 {
  641         struct kobject *parent;
  642 #if defined(CONFIG_ZFS) && !defined(CONFIG_ZFS_MODULE)
  643         parent = kobject_create_and_add("zfs", fs_kobj);
  644 #else
  645         parent = &(((struct module *)(THIS_MODULE))->mkobj).kobj;
  646 #endif
  647         int err;
  648 
  649         if (parent == NULL)
  650                 return;
  651 
  652         err = zfs_kernel_features_init(&kernel_features_kobj, parent);
  653         if (err)
  654                 return;
  655 
  656         err = zfs_pool_features_init(&pool_features_kobj, parent);
  657         if (err) {
  658                 zfs_kobj_fini(&kernel_features_kobj);
  659                 return;
  660         }
  661 
  662         err = zfs_sysfs_properties_init(&pool_props_kobj, parent,
  663             ZFS_TYPE_POOL);
  664         if (err) {
  665                 zfs_kobj_fini(&kernel_features_kobj);
  666                 zfs_kobj_fini(&pool_features_kobj);
  667                 return;
  668         }
  669 
  670         err = zfs_sysfs_properties_init(&vdev_props_kobj, parent,
  671             ZFS_TYPE_VDEV);
  672         if (err) {
  673                 zfs_kobj_fini(&kernel_features_kobj);
  674                 zfs_kobj_fini(&pool_features_kobj);
  675                 zfs_kobj_fini(&pool_props_kobj);
  676                 return;
  677         }
  678 
  679         err = zfs_sysfs_properties_init(&dataset_props_kobj, parent,
  680             ZFS_TYPE_FILESYSTEM);
  681         if (err) {
  682                 zfs_kobj_fini(&kernel_features_kobj);
  683                 zfs_kobj_fini(&pool_features_kobj);
  684                 zfs_kobj_fini(&pool_props_kobj);
  685                 zfs_kobj_fini(&vdev_props_kobj);
  686                 return;
  687         }
  688 }
  689 
  690 void
  691 zfs_sysfs_fini(void)
  692 {
  693         /*
  694          * Remove top-level kobjects; each will remove any children kobjects
  695          */
  696         zfs_kobj_fini(&kernel_features_kobj);
  697         zfs_kobj_fini(&pool_features_kobj);
  698         zfs_kobj_fini(&pool_props_kobj);
  699         zfs_kobj_fini(&vdev_props_kobj);
  700         zfs_kobj_fini(&dataset_props_kobj);
  701 }

Cache object: f627e754901fa2a58c34afa85405568b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.