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>
# include <linux/utsname.h>
# 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_page_getlink ( struct dentry * dentry ,
struct page * * ppage ) ;
static char * ocfs2_fast_symlink_getlink ( struct inode * inode ,
struct buffer_head * * bh ) ;
/* get the link contents into pagecache */
static char * ocfs2_page_getlink ( struct dentry * dentry ,
struct page * * ppage )
{
struct page * page ;
struct address_space * mapping = dentry - > d_inode - > i_mapping ;
2006-06-23 13:05:08 +04:00
page = read_mapping_page ( mapping , 0 , NULL ) ;
2005-12-16 01:31:24 +03:00
if ( IS_ERR ( page ) )
goto sync_fail ;
* ppage = page ;
return kmap ( page ) ;
sync_fail :
return ( char * ) page ;
}
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-10-10 04:20:31 +04:00
status = ocfs2_read_block ( inode , OCFS2_I ( inode ) - > ip_blkno , 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 ;
}
static void * ocfs2_follow_link ( struct dentry * dentry ,
struct nameidata * nd )
{
int status ;
char * link ;
struct inode * inode = dentry - > d_inode ;
struct page * page = NULL ;
struct buffer_head * bh = NULL ;
if ( ocfs2_inode_is_fast_symlink ( inode ) )
link = ocfs2_fast_symlink_getlink ( inode , & bh ) ;
else
link = ocfs2_page_getlink ( dentry , & page ) ;
if ( IS_ERR ( link ) ) {
status = PTR_ERR ( link ) ;
mlog_errno ( status ) ;
goto bail ;
}
status = vfs_follow_link ( nd , link ) ;
2007-01-04 04:25:40 +03:00
2005-12-16 01:31:24 +03:00
bail :
if ( page ) {
kunmap ( page ) ;
page_cache_release ( page ) ;
}
2008-10-08 01:25:16 +04:00
brelse ( bh ) ;
2005-12-16 01:31:24 +03:00
return ERR_PTR ( status ) ;
}
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 ,
. follow_link = ocfs2_follow_link ,
. 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 ,
. follow_link = ocfs2_follow_link ,
. 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
} ;