linux/fs/configfs/symlink.c
<<
>>
Prefs
   1/* -*- mode: c; c-basic-offset: 8; -*-
   2 * vim: noexpandtab sw=8 ts=8 sts=0:
   3 *
   4 * symlink.c - operations for configfs symlinks.
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public
  17 * License along with this program; if not, write to the
  18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19 * Boston, MA 021110-1307, USA.
  20 *
  21 * Based on sysfs:
  22 *      sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
  23 *
  24 * configfs Copyright (C) 2005 Oracle.  All rights reserved.
  25 */
  26
  27#include <linux/fs.h>
  28#include <linux/module.h>
  29#include <linux/namei.h>
  30#include <linux/slab.h>
  31
  32#include <linux/configfs.h>
  33#include "configfs_internal.h"
  34
  35/* Protects attachments of new symlinks */
  36DEFINE_MUTEX(configfs_symlink_mutex);
  37
  38static int item_depth(struct config_item * item)
  39{
  40        struct config_item * p = item;
  41        int depth = 0;
  42        do { depth++; } while ((p = p->ci_parent) && !configfs_is_root(p));
  43        return depth;
  44}
  45
  46static int item_path_length(struct config_item * item)
  47{
  48        struct config_item * p = item;
  49        int length = 1;
  50        do {
  51                length += strlen(config_item_name(p)) + 1;
  52                p = p->ci_parent;
  53        } while (p && !configfs_is_root(p));
  54        return length;
  55}
  56
  57static void fill_item_path(struct config_item * item, char * buffer, int length)
  58{
  59        struct config_item * p;
  60
  61        --length;
  62        for (p = item; p && !configfs_is_root(p); p = p->ci_parent) {
  63                int cur = strlen(config_item_name(p));
  64
  65                /* back up enough to print this bus id with '/' */
  66                length -= cur;
  67                strncpy(buffer + length,config_item_name(p),cur);
  68                *(buffer + --length) = '/';
  69        }
  70}
  71
  72static int create_link(struct config_item *parent_item,
  73                       struct config_item *item,
  74                       struct dentry *dentry)
  75{
  76        struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata;
  77        struct configfs_symlink *sl;
  78        int ret;
  79
  80        ret = -ENOENT;
  81        if (!configfs_dirent_is_ready(target_sd))
  82                goto out;
  83        ret = -ENOMEM;
  84        sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL);
  85        if (sl) {
  86                spin_lock(&configfs_dirent_lock);
  87                if (target_sd->s_type & CONFIGFS_USET_DROPPING) {
  88                        spin_unlock(&configfs_dirent_lock);
  89                        kfree(sl);
  90                        return -ENOENT;
  91                }
  92                sl->sl_target = config_item_get(item);
  93                list_add(&sl->sl_list, &target_sd->s_links);
  94                spin_unlock(&configfs_dirent_lock);
  95                ret = configfs_create_link(sl, parent_item->ci_dentry,
  96                                           dentry);
  97                if (ret) {
  98                        spin_lock(&configfs_dirent_lock);
  99                        list_del_init(&sl->sl_list);
 100                        spin_unlock(&configfs_dirent_lock);
 101                        config_item_put(item);
 102                        kfree(sl);
 103                }
 104        }
 105
 106out:
 107        return ret;
 108}
 109
 110
 111static int get_target(const char *symname, struct path *path,
 112                      struct config_item **target, struct super_block *sb)
 113{
 114        int ret;
 115
 116        ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path);
 117        if (!ret) {
 118                if (path->dentry->d_sb == sb) {
 119                        *target = configfs_get_config_item(path->dentry);
 120                        if (!*target) {
 121                                ret = -ENOENT;
 122                                path_put(path);
 123                        }
 124                } else {
 125                        ret = -EPERM;
 126                        path_put(path);
 127                }
 128        }
 129
 130        return ret;
 131}
 132
 133
 134int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 135{
 136        int ret;
 137        struct path path;
 138        struct configfs_dirent *sd;
 139        struct config_item *parent_item;
 140        struct config_item *target_item = NULL;
 141        struct config_item_type *type;
 142
 143        sd = dentry->d_parent->d_fsdata;
 144        /*
 145         * Fake invisibility if dir belongs to a group/default groups hierarchy
 146         * being attached
 147         */
 148        ret = -ENOENT;
 149        if (!configfs_dirent_is_ready(sd))
 150                goto out;
 151
 152        parent_item = configfs_get_config_item(dentry->d_parent);
 153        type = parent_item->ci_type;
 154
 155        ret = -EPERM;
 156        if (!type || !type->ct_item_ops ||
 157            !type->ct_item_ops->allow_link)
 158                goto out_put;
 159
 160        ret = get_target(symname, &path, &target_item, dentry->d_sb);
 161        if (ret)
 162                goto out_put;
 163
 164        ret = type->ct_item_ops->allow_link(parent_item, target_item);
 165        if (!ret) {
 166                mutex_lock(&configfs_symlink_mutex);
 167                ret = create_link(parent_item, target_item, dentry);
 168                mutex_unlock(&configfs_symlink_mutex);
 169                if (ret && type->ct_item_ops->drop_link)
 170                        type->ct_item_ops->drop_link(parent_item,
 171                                                     target_item);
 172        }
 173
 174        config_item_put(target_item);
 175        path_put(&path);
 176
 177out_put:
 178        config_item_put(parent_item);
 179
 180out:
 181        return ret;
 182}
 183
 184int configfs_unlink(struct inode *dir, struct dentry *dentry)
 185{
 186        struct configfs_dirent *sd = dentry->d_fsdata;
 187        struct configfs_symlink *sl;
 188        struct config_item *parent_item;
 189        struct config_item_type *type;
 190        int ret;
 191
 192        ret = -EPERM;  /* What lack-of-symlink returns */
 193        if (!(sd->s_type & CONFIGFS_ITEM_LINK))
 194                goto out;
 195
 196        sl = sd->s_element;
 197
 198        parent_item = configfs_get_config_item(dentry->d_parent);
 199        type = parent_item->ci_type;
 200
 201        spin_lock(&configfs_dirent_lock);
 202        list_del_init(&sd->s_sibling);
 203        spin_unlock(&configfs_dirent_lock);
 204        configfs_drop_dentry(sd, dentry->d_parent);
 205        dput(dentry);
 206        configfs_put(sd);
 207
 208        /*
 209         * drop_link() must be called before
 210         * list_del_init(&sl->sl_list), so that the order of
 211         * drop_link(this, target) and drop_item(target) is preserved.
 212         */
 213        if (type && type->ct_item_ops &&
 214            type->ct_item_ops->drop_link)
 215                type->ct_item_ops->drop_link(parent_item,
 216                                               sl->sl_target);
 217
 218        spin_lock(&configfs_dirent_lock);
 219        list_del_init(&sl->sl_list);
 220        spin_unlock(&configfs_dirent_lock);
 221
 222        /* Put reference from create_link() */
 223        config_item_put(sl->sl_target);
 224        kfree(sl);
 225
 226        config_item_put(parent_item);
 227
 228        ret = 0;
 229
 230out:
 231        return ret;
 232}
 233
 234static int configfs_get_target_path(struct config_item * item, struct config_item * target,
 235                                   char *path)
 236{
 237        char * s;
 238        int depth, size;
 239
 240        depth = item_depth(item);
 241        size = item_path_length(target) + depth * 3 - 1;
 242        if (size > PATH_MAX)
 243                return -ENAMETOOLONG;
 244
 245        pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size);
 246
 247        for (s = path; depth--; s += 3)
 248                strcpy(s,"../");
 249
 250        fill_item_path(target, path, size);
 251        pr_debug("%s: path = '%s'\n", __func__, path);
 252
 253        return 0;
 254}
 255
 256static int configfs_getlink(struct dentry *dentry, char * path)
 257{
 258        struct config_item *item, *target_item;
 259        int error = 0;
 260
 261        item = configfs_get_config_item(dentry->d_parent);
 262        if (!item)
 263                return -EINVAL;
 264
 265        target_item = configfs_get_config_item(dentry);
 266        if (!target_item) {
 267                config_item_put(item);
 268                return -EINVAL;
 269        }
 270
 271        down_read(&configfs_rename_sem);
 272        error = configfs_get_target_path(item, target_item, path);
 273        up_read(&configfs_rename_sem);
 274
 275        config_item_put(item);
 276        config_item_put(target_item);
 277        return error;
 278
 279}
 280
 281static const char *configfs_get_link(struct dentry *dentry,
 282                                     struct inode *inode,
 283                                     struct delayed_call *done)
 284{
 285        char *body;
 286        int error;
 287
 288        if (!dentry)
 289                return ERR_PTR(-ECHILD);
 290
 291        body = kzalloc(PAGE_SIZE, GFP_KERNEL);
 292        if (!body)
 293                return ERR_PTR(-ENOMEM);
 294
 295        error = configfs_getlink(dentry, body);
 296        if (!error) {
 297                set_delayed_call(done, kfree_link, body);
 298                return body;
 299        }
 300
 301        kfree(body);
 302        return ERR_PTR(error);
 303}
 304
 305const struct inode_operations configfs_symlink_inode_operations = {
 306        .get_link = configfs_get_link,
 307        .setattr = configfs_setattr,
 308};
 309
 310