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#define MLOG_MASK_PREFIX ML_NAMEI
  44#include <cluster/masklog.h>
  45
  46#include "ocfs2.h"
  47
  48#include "alloc.h"
  49#include "file.h"
  50#include "inode.h"
  51#include "journal.h"
  52#include "symlink.h"
  53#include "xattr.h"
  54
  55#include "buffer_head_io.h"
  56
  57
  58static char *ocfs2_fast_symlink_getlink(struct inode *inode,
  59                                        struct buffer_head **bh)
  60{
  61        int status;
  62        char *link = NULL;
  63        struct ocfs2_dinode *fe;
  64
  65        mlog_entry_void();
  66
  67        status = ocfs2_read_inode_block(inode, bh);
  68        if (status < 0) {
  69                mlog_errno(status);
  70                link = ERR_PTR(status);
  71                goto bail;
  72        }
  73
  74        fe = (struct ocfs2_dinode *) (*bh)->b_data;
  75        link = (char *) fe->id2.i_symlink;
  76bail:
  77        mlog_exit(status);
  78
  79        return link;
  80}
  81
  82static int ocfs2_readlink(struct dentry *dentry,
  83                          char __user *buffer,
  84                          int buflen)
  85{
  86        int ret;
  87        char *link;
  88        struct buffer_head *bh = NULL;
  89        struct inode *inode = dentry->d_inode;
  90
  91        mlog_entry_void();
  92
  93        link = ocfs2_fast_symlink_getlink(inode, &bh);
  94        if (IS_ERR(link)) {
  95                ret = PTR_ERR(link);
  96                goto out;
  97        }
  98
  99        /*
 100         * Without vfsmount we can't update atime now,
 101         * but we will update atime here ultimately.
 102         */
 103        ret = vfs_readlink(dentry, buffer, buflen, link);
 104
 105        brelse(bh);
 106out:
 107        mlog_exit(ret);
 108        return ret;
 109}
 110
 111static void *ocfs2_fast_follow_link(struct dentry *dentry,
 112                                    struct nameidata *nd)
 113{
 114        int status = 0;
 115        int len;
 116        char *target, *link = ERR_PTR(-ENOMEM);
 117        struct inode *inode = dentry->d_inode;
 118        struct buffer_head *bh = NULL;
 119
 120        mlog_entry_void();
 121
 122        BUG_ON(!ocfs2_inode_is_fast_symlink(inode));
 123        target = ocfs2_fast_symlink_getlink(inode, &bh);
 124        if (IS_ERR(target)) {
 125                status = PTR_ERR(target);
 126                mlog_errno(status);
 127                goto bail;
 128        }
 129
 130        /* Fast symlinks can't be large */
 131        len = strnlen(target, ocfs2_fast_symlink_chars(inode->i_sb));
 132        link = kzalloc(len + 1, GFP_NOFS);
 133        if (!link) {
 134                status = -ENOMEM;
 135                mlog_errno(status);
 136                goto bail;
 137        }
 138
 139        memcpy(link, target, len);
 140
 141bail:
 142        nd_set_link(nd, status ? ERR_PTR(status) : link);
 143        brelse(bh);
 144
 145        mlog_exit(status);
 146        return NULL;
 147}
 148
 149static void ocfs2_fast_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
 150{
 151        char *link = nd_get_link(nd);
 152        if (!IS_ERR(link))
 153                kfree(link);
 154}
 155
 156const struct inode_operations ocfs2_symlink_inode_operations = {
 157        .readlink       = page_readlink,
 158        .follow_link    = page_follow_link_light,
 159        .put_link       = page_put_link,
 160        .getattr        = ocfs2_getattr,
 161        .setattr        = ocfs2_setattr,
 162        .setxattr       = generic_setxattr,
 163        .getxattr       = generic_getxattr,
 164        .listxattr      = ocfs2_listxattr,
 165        .removexattr    = generic_removexattr,
 166        .fiemap         = ocfs2_fiemap,
 167};
 168const struct inode_operations ocfs2_fast_symlink_inode_operations = {
 169        .readlink       = ocfs2_readlink,
 170        .follow_link    = ocfs2_fast_follow_link,
 171        .put_link       = ocfs2_fast_put_link,
 172        .getattr        = ocfs2_getattr,
 173        .setattr        = ocfs2_setattr,
 174        .setxattr       = generic_setxattr,
 175        .getxattr       = generic_getxattr,
 176        .listxattr      = ocfs2_listxattr,
 177        .removexattr    = generic_removexattr,
 178        .fiemap         = ocfs2_fiemap,
 179};
 180