linux/fs/ocfs2/symlink.c
<<
>>
Prefs
   1/* -*- mode: c; c-basic-offset: 8; -*-
   2 * vim: noexpandtab sw=8 ts=8 sts=0:
   3 *
   4 *  linux/cluster/ssi/cfs/symlink.c
   5 *
   6 *      This program is free software; you can redistribute it and/or
   7 *      modify it under the terms of the GNU General Public License as
   8 *      published by the Free Software Foundation; either version 2 of
   9 *      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, GOOD TITLE
  14 *      or NON INFRINGEMENT.  See the GNU General Public License for more
  15 *      details.
  16 *
  17 *      You should have received a copy of the GNU General Public License
  18 *      along with this program; if not, write to the Free Software
  19 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 *
  21 *      Questions/Comments/Bugfixes to ssic-linux-devel@lists.sourceforge.net
  22 *
  23 *  Copyright (C) 1992  Rick Sladkey
  24 *
  25 *  Optimization changes Copyright (C) 1994 Florian La Roche
  26 *
  27 *  Jun 7 1999, cache symlink lookups in the page cache.  -DaveM
  28 *
  29 *  Portions Copyright (C) 2001 Compaq Computer Corporation
  30 *
  31 *  ocfs2 symlink handling code.
  32 *
  33 *  Copyright (C) 2004, 2005 Oracle.
  34 *
  35 */
  36
  37#include <linux/fs.h>
  38#include <linux/types.h>
  39#include <linux/slab.h>
  40#include <linux/pagemap.h>
  41#include <linux/namei.h>
  42
  43#include <cluster/masklog.h>
  44
  45#include "ocfs2.h"
  46
  47#include "alloc.h"
  48#include "file.h"
  49#include "inode.h"
  50#include "journal.h"
  51#include "symlink.h"
  52#include "xattr.h"
  53
  54#include "buffer_head_io.h"
  55
  56
  57static char *ocfs2_fast_symlink_getlink(struct inode *inode,
  58                                        struct buffer_head **bh)
  59{
  60        int status;
  61        char *link = NULL;
  62        struct ocfs2_dinode *fe;
  63
  64        status = ocfs2_read_inode_block(inode, bh);
  65        if (status < 0) {
  66                mlog_errno(status);
  67                link = ERR_PTR(status);
  68                goto bail;
  69        }
  70
  71        fe = (struct ocfs2_dinode *) (*bh)->b_data;
  72        link = (char *) fe->id2.i_symlink;
  73bail:
  74
  75        return link;
  76}
  77
  78static int ocfs2_readlink(struct dentry *dentry,
  79                          char __user *buffer,
  80                          int buflen)
  81{
  82        int ret;
  83        char *link;
  84        struct buffer_head *bh = NULL;
  85        struct inode *inode = dentry->d_inode;
  86
  87        link = ocfs2_fast_symlink_getlink(inode, &bh);
  88        if (IS_ERR(link)) {
  89                ret = PTR_ERR(link);
  90                goto out;
  91        }
  92
  93        /*
  94         * Without vfsmount we can't update atime now,
  95         * but we will update atime here ultimately.
  96         */
  97        ret = vfs_readlink(dentry, buffer, buflen, link);
  98
  99        brelse(bh);
 100out:
 101        if (ret < 0)
 102                mlog_errno(ret);
 103        return ret;
 104}
 105
 106static void *ocfs2_fast_follow_link(struct dentry *dentry,
 107                                    struct nameidata *nd)
 108{
 109        int status = 0;
 110        int len;
 111        char *target, *link = ERR_PTR(-ENOMEM);
 112        struct inode *inode = dentry->d_inode;
 113        struct buffer_head *bh = NULL;
 114
 115        BUG_ON(!ocfs2_inode_is_fast_symlink(inode));
 116        target = ocfs2_fast_symlink_getlink(inode, &bh);
 117        if (IS_ERR(target)) {
 118                status = PTR_ERR(target);
 119                mlog_errno(status);
 120                goto bail;
 121        }
 122
 123        /* Fast symlinks can't be large */
 124        len = strnlen(target, ocfs2_fast_symlink_chars(inode->i_sb));
 125        link = kzalloc(len + 1, GFP_NOFS);
 126        if (!link) {
 127                status = -ENOMEM;
 128                mlog_errno(status);
 129                goto bail;
 130        }
 131
 132        memcpy(link, target, len);
 133
 134bail:
 135        nd_set_link(nd, status ? ERR_PTR(status) : link);
 136        brelse(bh);
 137
 138        if (status)
 139                mlog_errno(status);
 140        return NULL;
 141}
 142
 143static void ocfs2_fast_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
 144{
 145        char *link = nd_get_link(nd);
 146        if (!IS_ERR(link))
 147                kfree(link);
 148}
 149
 150const struct inode_operations ocfs2_symlink_inode_operations = {
 151        .readlink       = page_readlink,
 152        .follow_link    = page_follow_link_light,
 153        .put_link       = page_put_link,
 154        .getattr        = ocfs2_getattr,
 155        .setattr        = ocfs2_setattr,
 156        .setxattr       = generic_setxattr,
 157        .getxattr       = generic_getxattr,
 158        .listxattr      = ocfs2_listxattr,
 159        .removexattr    = generic_removexattr,
 160        .fiemap         = ocfs2_fiemap,
 161};
 162const struct inode_operations ocfs2_fast_symlink_inode_operations = {
 163        .readlink       = ocfs2_readlink,
 164        .follow_link    = ocfs2_fast_follow_link,
 165        .put_link       = ocfs2_fast_put_link,
 166        .getattr        = ocfs2_getattr,
 167        .setattr        = ocfs2_setattr,
 168        .setxattr       = generic_setxattr,
 169        .getxattr       = generic_getxattr,
 170        .listxattr      = ocfs2_listxattr,
 171        .removexattr    = generic_removexattr,
 172        .fiemap         = ocfs2_fiemap,
 173};
 174