2005-12-16 01:31:24 +03:00
/* -*- mode: c; c-basic-offset: 8; -*-
* vim : noexpandtab sw = 8 ts = 8 sts = 0 :
*
* linux / cluster / ssi / cfs / symlink . c
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of
* the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE , GOOD TITLE
* or NON INFRINGEMENT . See the GNU General Public License for more
* details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
* Questions / Comments / Bugfixes to ssic - linux - devel @ lists . sourceforge . net
*
* Copyright ( C ) 1992 Rick Sladkey
*
* Optimization changes Copyright ( C ) 1994 Florian La Roche
*
* Jun 7 1999 , cache symlink lookups in the page cache . - DaveM
*
* Portions Copyright ( C ) 2001 Compaq Computer Corporation
*
* ocfs2 symlink handling code .
*
* Copyright ( C ) 2004 , 2005 Oracle .
*
*/
# include <linux/fs.h>
# include <linux/types.h>
# include <linux/slab.h>
# include <linux/pagemap.h>
2009-04-07 03:43:42 +04:00
# include <linux/namei.h>
2005-12-16 01:31:24 +03:00
# define MLOG_MASK_PREFIX ML_NAMEI
# include <cluster/masklog.h>
# include "ocfs2.h"
# include "alloc.h"
# include "file.h"
# include "inode.h"
# include "journal.h"
# include "symlink.h"
2008-08-18 13:11:00 +04:00
# include "xattr.h"
2005-12-16 01:31:24 +03:00
# include "buffer_head_io.h"
static char * ocfs2_fast_symlink_getlink ( struct inode * inode ,
struct buffer_head * * bh )
{
int status ;
char * link = NULL ;
struct ocfs2_dinode * fe ;
mlog_entry_void ( ) ;
2008-11-14 01:49:11 +03:00
status = ocfs2_read_inode_block ( inode , bh ) ;
2005-12-16 01:31:24 +03:00
if ( status < 0 ) {
mlog_errno ( status ) ;
link = ERR_PTR ( status ) ;
goto bail ;
}
fe = ( struct ocfs2_dinode * ) ( * bh ) - > b_data ;
link = ( char * ) fe - > id2 . i_symlink ;
bail :
mlog_exit ( status ) ;
return link ;
}
static int ocfs2_readlink ( struct dentry * dentry ,
char __user * buffer ,
int buflen )
{
int ret ;
char * link ;
struct buffer_head * bh = NULL ;
struct inode * inode = dentry - > d_inode ;
mlog_entry_void ( ) ;
link = ocfs2_fast_symlink_getlink ( inode , & bh ) ;
if ( IS_ERR ( link ) ) {
ret = PTR_ERR ( link ) ;
goto out ;
}
2006-11-15 10:49:02 +03:00
/*
* Without vfsmount we can ' t update atime now ,
* but we will update atime here ultimately .
*/
2005-12-16 01:31:24 +03:00
ret = vfs_readlink ( dentry , buffer , buflen , link ) ;
brelse ( bh ) ;
out :
mlog_exit ( ret ) ;
return ret ;
}
2009-04-07 03:43:42 +04:00
static void * ocfs2_fast_follow_link ( struct dentry * dentry ,
struct nameidata * nd )
2005-12-16 01:31:24 +03:00
{
2009-04-07 03:43:42 +04:00
int status = 0 ;
int len ;
char * target , * link = ERR_PTR ( - ENOMEM ) ;
2005-12-16 01:31:24 +03:00
struct inode * inode = dentry - > d_inode ;
struct buffer_head * bh = NULL ;
2009-04-07 03:43:42 +04:00
mlog_entry_void ( ) ;
BUG_ON ( ! ocfs2_inode_is_fast_symlink ( inode ) ) ;
target = ocfs2_fast_symlink_getlink ( inode , & bh ) ;
if ( IS_ERR ( target ) ) {
status = PTR_ERR ( target ) ;
2005-12-16 01:31:24 +03:00
mlog_errno ( status ) ;
goto bail ;
}
2009-04-07 03:43:42 +04:00
/* Fast symlinks can't be large */
len = strlen ( target ) ;
link = kzalloc ( len + 1 , GFP_NOFS ) ;
if ( ! link ) {
status = - ENOMEM ;
mlog_errno ( status ) ;
goto bail ;
}
memcpy ( link , target , len ) ;
nd_set_link ( nd , link ) ;
2007-01-04 04:25:40 +03:00
2005-12-16 01:31:24 +03:00
bail :
2008-10-08 01:25:16 +04:00
brelse ( bh ) ;
2005-12-16 01:31:24 +03:00
2009-04-07 03:43:42 +04:00
mlog_exit ( status ) ;
return status ? ERR_PTR ( status ) : link ;
}
static void ocfs2_fast_put_link ( struct dentry * dentry , struct nameidata * nd , void * cookie )
{
char * link = cookie ;
kfree ( link ) ;
2005-12-16 01:31:24 +03:00
}
2007-02-12 11:55:39 +03:00
const struct inode_operations ocfs2_symlink_inode_operations = {
2005-12-16 01:31:24 +03:00
. readlink = page_readlink ,
2009-04-07 03:43:42 +04:00
. follow_link = page_follow_link_light ,
. put_link = page_put_link ,
2005-12-16 01:31:24 +03:00
. getattr = ocfs2_getattr ,
2008-04-18 21:23:53 +04:00
. setattr = ocfs2_setattr ,
2008-08-18 13:11:00 +04:00
. setxattr = generic_setxattr ,
. getxattr = generic_getxattr ,
. listxattr = ocfs2_listxattr ,
. removexattr = generic_removexattr ,
2005-12-16 01:31:24 +03:00
} ;
2007-02-12 11:55:39 +03:00
const struct inode_operations ocfs2_fast_symlink_inode_operations = {
2005-12-16 01:31:24 +03:00
. readlink = ocfs2_readlink ,
2009-04-07 03:43:42 +04:00
. follow_link = ocfs2_fast_follow_link ,
. put_link = ocfs2_fast_put_link ,
2005-12-16 01:31:24 +03:00
. getattr = ocfs2_getattr ,
2008-04-18 21:23:53 +04:00
. setattr = ocfs2_setattr ,
2008-08-18 13:11:00 +04:00
. setxattr = generic_setxattr ,
. getxattr = generic_getxattr ,
. listxattr = ocfs2_listxattr ,
. removexattr = generic_removexattr ,
2005-12-16 01:31:24 +03:00
} ;