2005-04-17 02:20:36 +04:00
/*
2005-11-02 06:58:39 +03:00
* Copyright ( c ) 2000 - 2005 Silicon Graphics , Inc .
* All Rights Reserved .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
2005-04-17 02:20:36 +04:00
* published by the Free Software Foundation .
*
2005-11-02 06:58:39 +03:00
* This program is distributed in the hope that it would be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-04-17 02:20:36 +04:00
*/
# include "xfs.h"
# include "xfs_fs.h"
2005-11-02 06:38:42 +03:00
# include "xfs_bit.h"
2005-04-17 02:20:36 +04:00
# include "xfs_log.h"
2005-11-02 06:38:42 +03:00
# include "xfs_inum.h"
2005-04-17 02:20:36 +04:00
# include "xfs_trans.h"
# include "xfs_sb.h"
# include "xfs_ag.h"
# include "xfs_dir2.h"
# include "xfs_alloc.h"
# include "xfs_dmapi.h"
# include "xfs_quota.h"
# include "xfs_mount.h"
# include "xfs_bmap_btree.h"
2005-11-02 06:38:42 +03:00
# include "xfs_alloc_btree.h"
2005-04-17 02:20:36 +04:00
# include "xfs_ialloc_btree.h"
# include "xfs_dir2_sf.h"
2005-11-02 06:38:42 +03:00
# include "xfs_attr_sf.h"
2005-04-17 02:20:36 +04:00
# include "xfs_dinode.h"
# include "xfs_inode.h"
# include "xfs_bmap.h"
2005-11-02 06:38:42 +03:00
# include "xfs_btree.h"
# include "xfs_ialloc.h"
2005-04-17 02:20:36 +04:00
# include "xfs_rtalloc.h"
# include "xfs_error.h"
# include "xfs_itable.h"
# include "xfs_rw.h"
# include "xfs_acl.h"
# include "xfs_attr.h"
# include "xfs_buf_item.h"
# include "xfs_utils.h"
2007-08-29 04:58:01 +04:00
# include "xfs_vnodeops.h"
2005-04-17 02:20:36 +04:00
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/xattr.h>
# include <linux/namei.h>
2006-01-11 07:35:44 +03:00
# include <linux/security.h>
2007-11-23 08:29:25 +03:00
# include <linux/falloc.h>
2005-04-17 02:20:36 +04:00
2006-01-11 07:35:17 +03:00
/*
* Bring the atime in the XFS inode uptodate .
* Used before logging the inode to disk or when the Linux inode goes away .
*/
void
xfs_synchronize_atime (
xfs_inode_t * ip )
{
2008-08-13 09:45:15 +04:00
struct inode * inode = VFS_I ( ip ) ;
2006-01-11 07:35:17 +03:00
2008-10-30 09:36:14 +03:00
if ( ! ( inode - > i_state & I_CLEAR ) ) {
2008-03-06 05:46:43 +03:00
ip - > i_d . di_atime . t_sec = ( __int32_t ) inode - > i_atime . tv_sec ;
ip - > i_d . di_atime . t_nsec = ( __int32_t ) inode - > i_atime . tv_nsec ;
2006-01-11 07:35:17 +03:00
}
}
2007-11-23 08:29:18 +03:00
/*
2008-10-30 09:36:14 +03:00
* If the linux inode is valid , mark it dirty .
2007-11-23 08:29:18 +03:00
* Used when commiting a dirty inode into a transaction so that
* the inode will get written back by the linux code
*/
void
xfs_mark_inode_dirty_sync (
xfs_inode_t * ip )
{
2008-08-13 09:45:15 +04:00
struct inode * inode = VFS_I ( ip ) ;
2007-11-23 08:29:18 +03:00
2008-10-30 09:36:14 +03:00
if ( ! ( inode - > i_state & ( I_WILL_FREE | I_FREEING | I_CLEAR ) ) )
2008-03-06 05:46:43 +03:00
mark_inode_dirty_sync ( inode ) ;
2007-11-23 08:29:18 +03:00
}
2005-11-02 03:43:58 +03:00
/*
* Change the requested timestamp in the given inode .
* We don ' t lock across timestamp updates , and we don ' t log them but
* we do record the fact that there is dirty information in core .
*/
void
xfs_ichgtime (
xfs_inode_t * ip ,
int flags )
{
2008-08-13 10:00:45 +04:00
struct inode * inode = VFS_I ( ip ) ;
2005-11-02 03:43:58 +03:00
timespec_t tv ;
2008-08-13 10:45:13 +04:00
int sync_it = 0 ;
2005-11-02 03:43:58 +03:00
2008-08-13 10:45:13 +04:00
tv = current_fs_time ( inode - > i_sb ) ;
if ( ( flags & XFS_ICHGTIME_MOD ) & &
! timespec_equal ( & inode - > i_mtime , & tv ) ) {
2005-11-02 03:43:58 +03:00
inode - > i_mtime = tv ;
ip - > i_d . di_mtime . t_sec = ( __int32_t ) tv . tv_sec ;
ip - > i_d . di_mtime . t_nsec = ( __int32_t ) tv . tv_nsec ;
2008-08-13 10:45:13 +04:00
sync_it = 1 ;
2005-11-02 03:43:58 +03:00
}
2008-08-13 10:45:13 +04:00
if ( ( flags & XFS_ICHGTIME_CHG ) & &
! timespec_equal ( & inode - > i_ctime , & tv ) ) {
2005-11-02 03:43:58 +03:00
inode - > i_ctime = tv ;
ip - > i_d . di_ctime . t_sec = ( __int32_t ) tv . tv_sec ;
ip - > i_d . di_ctime . t_nsec = ( __int32_t ) tv . tv_nsec ;
2008-08-13 10:45:13 +04:00
sync_it = 1 ;
2005-11-02 03:43:58 +03:00
}
/*
* We update the i_update_core field _after_ changing
* the timestamps in order to coordinate properly with
* xfs_iflush ( ) so that we don ' t lose timestamp updates .
* This keeps us from having to hold the inode lock
* while doing this . We use the SYNCHRONIZE macro to
* ensure that the compiler does not reorder the update
* of i_update_core above the timestamp updates above .
*/
2008-08-13 10:45:13 +04:00
if ( sync_it ) {
SYNCHRONIZE ( ) ;
ip - > i_update_core = 1 ;
2008-10-30 09:21:30 +03:00
xfs_mark_inode_dirty_sync ( ip ) ;
2008-08-13 10:45:13 +04:00
}
2005-11-02 03:43:58 +03:00
}
2006-01-11 07:35:44 +03:00
/*
* Hook in SELinux . This is not quite correct yet , what we really need
* here ( as we do for default ACLs ) is a mechanism by which creation of
* these attrs can be journalled at inode creation time ( along with the
* inode , of course , such that log replay can ' t cause these to be lost ) .
*/
STATIC int
2006-03-14 06:00:51 +03:00
xfs_init_security (
2008-03-06 05:46:43 +03:00
struct inode * inode ,
2006-01-11 07:35:44 +03:00
struct inode * dir )
{
2008-03-06 05:46:43 +03:00
struct xfs_inode * ip = XFS_I ( inode ) ;
2006-01-11 07:35:44 +03:00
size_t length ;
void * value ;
char * name ;
int error ;
2008-03-06 05:46:43 +03:00
error = security_inode_init_security ( inode , dir , & name ,
& value , & length ) ;
2006-01-11 07:35:44 +03:00
if ( error ) {
if ( error = = - EOPNOTSUPP )
return 0 ;
return - error ;
}
2008-03-06 05:46:43 +03:00
error = xfs_attr_set ( ip , name , value , length , ATTR_SECURE ) ;
2006-01-11 07:35:44 +03:00
if ( ! error )
2008-03-06 05:46:43 +03:00
xfs_iflags_set ( ip , XFS_IMODIFIED ) ;
2006-01-11 07:35:44 +03:00
kfree ( name ) ;
kfree ( value ) ;
return error ;
}
2008-04-10 06:22:07 +04:00
static void
xfs_dentry_to_name (
struct xfs_name * namep ,
struct dentry * dentry )
{
namep - > name = dentry - > d_name . name ;
namep - > len = dentry - > d_name . len ;
}
2007-02-10 10:34:56 +03:00
STATIC void
2006-03-14 06:00:51 +03:00
xfs_cleanup_inode (
2007-08-29 04:58:01 +04:00
struct inode * dir ,
2008-03-06 05:46:43 +03:00
struct inode * inode ,
2008-06-23 07:25:17 +04:00
struct dentry * dentry )
2006-02-01 04:14:34 +03:00
{
2008-04-10 06:22:07 +04:00
struct xfs_name teardown ;
2006-02-01 04:14:34 +03:00
/* Oh, the horror.
2006-03-14 05:33:36 +03:00
* If we can ' t add the ACL or we fail in
2006-03-14 06:00:51 +03:00
* xfs_init_security we must back out .
2006-02-01 04:14:34 +03:00
* ENOSPC can hit here , among other things .
*/
2008-04-10 06:22:07 +04:00
xfs_dentry_to_name ( & teardown , dentry ) ;
2006-02-01 04:14:34 +03:00
2008-06-23 07:25:17 +04:00
xfs_remove ( XFS_I ( dir ) , & teardown , XFS_I ( inode ) ) ;
2008-03-06 05:46:43 +03:00
iput ( inode ) ;
2006-02-01 04:14:34 +03:00
}
2005-04-17 02:20:36 +04:00
STATIC int
2006-03-14 06:00:51 +03:00
xfs_vn_mknod (
2005-04-17 02:20:36 +04:00
struct inode * dir ,
struct dentry * dentry ,
int mode ,
dev_t rdev )
{
2008-03-06 05:44:35 +03:00
struct inode * inode ;
2008-03-06 05:46:05 +03:00
struct xfs_inode * ip = NULL ;
2005-04-17 02:20:36 +04:00
xfs_acl_t * default_acl = NULL ;
2008-04-10 06:22:07 +04:00
struct xfs_name name ;
2008-06-23 07:23:01 +04:00
int ( * test_default_acl ) ( struct inode * ) = _ACL_DEFAULT_EXISTS ;
2005-04-17 02:20:36 +04:00
int error ;
/*
* Irix uses Missed ' em ' V split , but doesn ' t want to see
* the upper 5 bits of ( 14 bit ) major .
*/
2006-03-14 05:33:36 +03:00
if ( unlikely ( ! sysv_valid_dev ( rdev ) | | MAJOR ( rdev ) & ~ 0x1ff ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2008-03-06 05:46:05 +03:00
if ( test_default_acl & & test_default_acl ( dir ) ) {
2006-03-14 05:33:36 +03:00
if ( ! _ACL_ALLOC ( default_acl ) ) {
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2006-03-14 05:33:36 +03:00
}
2008-03-06 05:46:05 +03:00
if ( ! _ACL_GET_DEFAULT ( dir , default_acl ) ) {
2005-04-17 02:20:36 +04:00
_ACL_FREE ( default_acl ) ;
default_acl = NULL ;
}
}
2008-04-10 06:22:07 +04:00
xfs_dentry_to_name ( & name , dentry ) ;
2008-03-06 05:44:35 +03:00
if ( IS_POSIXACL ( dir ) & & ! default_acl )
2005-04-17 02:20:36 +04:00
mode & = ~ current - > fs - > umask ;
switch ( mode & S_IFMT ) {
2008-03-06 05:44:35 +03:00
case S_IFCHR :
case S_IFBLK :
case S_IFIFO :
case S_IFSOCK :
2007-10-11 12:09:12 +04:00
rdev = sysv_encode_dev ( rdev ) ;
2005-04-17 02:20:36 +04:00
case S_IFREG :
2008-04-10 06:22:07 +04:00
error = xfs_create ( XFS_I ( dir ) , & name , mode , rdev , & ip , NULL ) ;
2005-04-17 02:20:36 +04:00
break ;
case S_IFDIR :
2008-04-10 06:22:07 +04:00
error = xfs_mkdir ( XFS_I ( dir ) , & name , mode , & ip , NULL ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
error = EINVAL ;
break ;
}
2008-03-06 05:44:35 +03:00
if ( unlikely ( error ) )
goto out_free_acl ;
2006-01-11 07:35:44 +03:00
2008-08-13 09:45:15 +04:00
inode = VFS_I ( ip ) ;
2008-03-06 05:46:05 +03:00
error = xfs_init_security ( inode , dir ) ;
2008-03-06 05:44:35 +03:00
if ( unlikely ( error ) )
goto out_cleanup_inode ;
if ( default_acl ) {
2008-03-06 05:46:05 +03:00
error = _ACL_INHERIT ( inode , mode , default_acl ) ;
2008-03-06 05:44:35 +03:00
if ( unlikely ( error ) )
goto out_cleanup_inode ;
2008-03-06 05:46:05 +03:00
xfs_iflags_set ( ip , XFS_IMODIFIED ) ;
2005-04-17 02:20:36 +04:00
_ACL_FREE ( default_acl ) ;
}
2008-03-06 05:44:35 +03:00
d_instantiate ( dentry , inode ) ;
return - error ;
out_cleanup_inode :
2008-06-23 07:25:17 +04:00
xfs_cleanup_inode ( dir , inode , dentry ) ;
2008-03-06 05:44:35 +03:00
out_free_acl :
if ( default_acl )
_ACL_FREE ( default_acl ) ;
2005-04-17 02:20:36 +04:00
return - error ;
}
STATIC int
2006-03-14 06:00:51 +03:00
xfs_vn_create (
2005-04-17 02:20:36 +04:00
struct inode * dir ,
struct dentry * dentry ,
int mode ,
struct nameidata * nd )
{
2006-03-14 06:00:51 +03:00
return xfs_vn_mknod ( dir , dentry , mode , 0 ) ;
2005-04-17 02:20:36 +04:00
}
STATIC int
2006-03-14 06:00:51 +03:00
xfs_vn_mkdir (
2005-04-17 02:20:36 +04:00
struct inode * dir ,
struct dentry * dentry ,
int mode )
{
2006-03-14 06:00:51 +03:00
return xfs_vn_mknod ( dir , dentry , mode | S_IFDIR , 0 ) ;
2005-04-17 02:20:36 +04:00
}
STATIC struct dentry *
2006-03-14 06:00:51 +03:00
xfs_vn_lookup (
2005-04-17 02:20:36 +04:00
struct inode * dir ,
struct dentry * dentry ,
struct nameidata * nd )
{
2008-03-06 05:46:25 +03:00
struct xfs_inode * cip ;
2008-04-10 06:22:07 +04:00
struct xfs_name name ;
2005-04-17 02:20:36 +04:00
int error ;
if ( dentry - > d_name . len > = MAXNAMELEN )
return ERR_PTR ( - ENAMETOOLONG ) ;
2008-04-10 06:22:07 +04:00
xfs_dentry_to_name ( & name , dentry ) ;
2008-05-21 10:58:22 +04:00
error = xfs_lookup ( XFS_I ( dir ) , & name , & cip , NULL ) ;
2006-06-09 11:00:52 +04:00
if ( unlikely ( error ) ) {
2005-04-17 02:20:36 +04:00
if ( unlikely ( error ! = ENOENT ) )
return ERR_PTR ( - error ) ;
d_add ( dentry , NULL ) ;
return NULL ;
}
2008-08-13 09:45:15 +04:00
return d_splice_alias ( VFS_I ( cip ) , dentry ) ;
2005-04-17 02:20:36 +04:00
}
2008-05-21 10:58:22 +04:00
STATIC struct dentry *
xfs_vn_ci_lookup (
struct inode * dir ,
struct dentry * dentry ,
struct nameidata * nd )
{
struct xfs_inode * ip ;
struct xfs_name xname ;
struct xfs_name ci_name ;
struct qstr dname ;
int error ;
if ( dentry - > d_name . len > = MAXNAMELEN )
return ERR_PTR ( - ENAMETOOLONG ) ;
xfs_dentry_to_name ( & xname , dentry ) ;
error = xfs_lookup ( XFS_I ( dir ) , & xname , & ip , & ci_name ) ;
if ( unlikely ( error ) ) {
if ( unlikely ( error ! = ENOENT ) )
return ERR_PTR ( - error ) ;
2008-05-22 11:21:40 +04:00
/*
* call d_add ( dentry , NULL ) here when d_drop_negative_children
* is called in xfs_vn_mknod ( ie . allow negative dentries
* with CI filesystems ) .
*/
2008-05-21 10:58:22 +04:00
return NULL ;
}
/* if exact match, just splice and exit */
if ( ! ci_name . name )
2008-08-13 09:45:15 +04:00
return d_splice_alias ( VFS_I ( ip ) , dentry ) ;
2008-05-21 10:58:22 +04:00
/* else case-insensitive match... */
dname . name = ci_name . name ;
dname . len = ci_name . len ;
2008-08-08 01:49:07 +04:00
dentry = d_add_ci ( dentry , VFS_I ( ip ) , & dname ) ;
2008-05-21 10:58:22 +04:00
kmem_free ( ci_name . name ) ;
return dentry ;
}
2005-04-17 02:20:36 +04:00
STATIC int
2006-03-14 06:00:51 +03:00
xfs_vn_link (
2005-04-17 02:20:36 +04:00
struct dentry * old_dentry ,
struct inode * dir ,
struct dentry * dentry )
{
2008-03-06 05:46:12 +03:00
struct inode * inode ; /* inode of guy being linked to */
2008-04-10 06:22:07 +04:00
struct xfs_name name ;
2005-04-17 02:20:36 +04:00
int error ;
2008-03-06 05:46:12 +03:00
inode = old_dentry - > d_inode ;
2008-04-10 06:22:07 +04:00
xfs_dentry_to_name ( & name , dentry ) ;
2005-04-17 02:20:36 +04:00
2008-03-06 05:46:12 +03:00
igrab ( inode ) ;
2008-04-10 06:22:07 +04:00
error = xfs_link ( XFS_I ( dir ) , XFS_I ( inode ) , & name ) ;
2006-06-27 10:13:46 +04:00
if ( unlikely ( error ) ) {
2008-03-06 05:46:12 +03:00
iput ( inode ) ;
return - error ;
2005-04-17 02:20:36 +04:00
}
2008-03-06 05:46:12 +03:00
xfs_iflags_set ( XFS_I ( dir ) , XFS_IMODIFIED ) ;
d_instantiate ( dentry , inode ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
STATIC int
2006-03-14 06:00:51 +03:00
xfs_vn_unlink (
2005-04-17 02:20:36 +04:00
struct inode * dir ,
struct dentry * dentry )
{
2008-04-10 06:22:07 +04:00
struct xfs_name name ;
2005-04-17 02:20:36 +04:00
int error ;
2008-04-10 06:22:07 +04:00
xfs_dentry_to_name ( & name , dentry ) ;
2005-04-17 02:20:36 +04:00
2008-06-23 07:25:25 +04:00
error = - xfs_remove ( XFS_I ( dir ) , & name , XFS_I ( dentry - > d_inode ) ) ;
if ( error )
return error ;
/*
* With unlink , the VFS makes the dentry " negative " : no inode ,
* but still hashed . This is incompatible with case - insensitive
* mode , so invalidate ( unhash ) the dentry in CI - mode .
*/
if ( xfs_sb_version_hasasciici ( & XFS_M ( dir - > i_sb ) - > m_sb ) )
d_invalidate ( dentry ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
STATIC int
2006-03-14 06:00:51 +03:00
xfs_vn_symlink (
2005-04-17 02:20:36 +04:00
struct inode * dir ,
struct dentry * dentry ,
const char * symname )
{
2008-03-06 05:46:19 +03:00
struct inode * inode ;
struct xfs_inode * cip = NULL ;
2008-04-10 06:22:07 +04:00
struct xfs_name name ;
2005-04-17 02:20:36 +04:00
int error ;
2007-10-11 12:09:12 +04:00
mode_t mode ;
2005-04-17 02:20:36 +04:00
2007-10-11 12:09:12 +04:00
mode = S_IFLNK |
2005-09-02 10:46:51 +04:00
( irix_symlink_mode ? 0777 & ~ current - > fs - > umask : S_IRWXUGO ) ;
2008-04-10 06:22:07 +04:00
xfs_dentry_to_name ( & name , dentry ) ;
2005-04-17 02:20:36 +04:00
2008-04-10 06:22:07 +04:00
error = xfs_symlink ( XFS_I ( dir ) , & name , symname , mode , & cip , NULL ) ;
2008-03-06 05:46:19 +03:00
if ( unlikely ( error ) )
goto out ;
2008-08-13 09:45:15 +04:00
inode = VFS_I ( cip ) ;
2008-03-06 05:46:19 +03:00
error = xfs_init_security ( inode , dir ) ;
if ( unlikely ( error ) )
goto out_cleanup_inode ;
d_instantiate ( dentry , inode ) ;
return 0 ;
out_cleanup_inode :
2008-06-23 07:25:17 +04:00
xfs_cleanup_inode ( dir , inode , dentry ) ;
2008-03-06 05:46:19 +03:00
out :
2005-04-17 02:20:36 +04:00
return - error ;
}
STATIC int
2006-03-14 06:00:51 +03:00
xfs_vn_rename (
2005-04-17 02:20:36 +04:00
struct inode * odir ,
struct dentry * odentry ,
struct inode * ndir ,
struct dentry * ndentry )
{
struct inode * new_inode = ndentry - > d_inode ;
2008-04-10 06:22:07 +04:00
struct xfs_name oname ;
struct xfs_name nname ;
2005-04-17 02:20:36 +04:00
2008-04-10 06:22:07 +04:00
xfs_dentry_to_name ( & oname , odentry ) ;
xfs_dentry_to_name ( & nname , ndentry ) ;
2008-06-23 07:25:25 +04:00
return - xfs_rename ( XFS_I ( odir ) , & oname , XFS_I ( odentry - > d_inode ) ,
2008-04-22 11:34:06 +04:00
XFS_I ( ndir ) , & nname , new_inode ?
XFS_I ( new_inode ) : NULL ) ;
2005-04-17 02:20:36 +04:00
}
/*
* careful here - this function can get called recursively , so
* we need to be very careful about how much stack we use .
* uio is kmalloced for this reason . . .
*/
[PATCH] Fix up symlink function pointers
This fixes up the symlink functions for the calling convention change:
* afs, autofs4, befs, devfs, freevxfs, jffs2, jfs, ncpfs, procfs,
smbfs, sysvfs, ufs, xfs - prototype change for ->follow_link()
* befs, smbfs, xfs - same for ->put_link()
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-08-20 03:17:39 +04:00
STATIC void *
2006-03-14 06:00:51 +03:00
xfs_vn_follow_link (
2005-04-17 02:20:36 +04:00
struct dentry * dentry ,
struct nameidata * nd )
{
char * link ;
2007-08-28 07:59:03 +04:00
int error = - ENOMEM ;
2005-04-17 02:20:36 +04:00
2006-09-27 12:49:39 +04:00
link = kmalloc ( MAXPATHLEN + 1 , GFP_KERNEL ) ;
2007-08-28 07:59:03 +04:00
if ( ! link )
goto out_err ;
2005-04-17 02:20:36 +04:00
2007-08-29 04:58:01 +04:00
error = - xfs_readlink ( XFS_I ( dentry - > d_inode ) , link ) ;
2007-08-28 07:59:03 +04:00
if ( unlikely ( error ) )
goto out_kfree ;
2005-04-17 02:20:36 +04:00
nd_set_link ( nd , link ) ;
[PATCH] Fix up symlink function pointers
This fixes up the symlink functions for the calling convention change:
* afs, autofs4, befs, devfs, freevxfs, jffs2, jfs, ncpfs, procfs,
smbfs, sysvfs, ufs, xfs - prototype change for ->follow_link()
* befs, smbfs, xfs - same for ->put_link()
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-08-20 03:17:39 +04:00
return NULL ;
2007-08-28 07:59:03 +04:00
out_kfree :
kfree ( link ) ;
out_err :
nd_set_link ( nd , ERR_PTR ( error ) ) ;
return NULL ;
2005-04-17 02:20:36 +04:00
}
2005-09-05 05:47:01 +04:00
STATIC void
2006-03-14 06:00:51 +03:00
xfs_vn_put_link (
2005-09-05 05:47:01 +04:00
struct dentry * dentry ,
struct nameidata * nd ,
void * p )
2005-04-17 02:20:36 +04:00
{
2005-09-05 05:47:01 +04:00
char * s = nd_get_link ( nd ) ;
2005-04-17 02:20:36 +04:00
if ( ! IS_ERR ( s ) )
kfree ( s ) ;
}
# ifdef CONFIG_XFS_POSIX_ACL
2008-02-05 04:13:24 +03:00
STATIC int
xfs_check_acl (
struct inode * inode ,
int mask )
{
struct xfs_inode * ip = XFS_I ( inode ) ;
int error ;
xfs_itrace_entry ( ip ) ;
if ( XFS_IFORK_Q ( ip ) ) {
error = xfs_acl_iaccess ( ip , mask , NULL ) ;
if ( error ! = - 1 )
return - error ;
}
return - EAGAIN ;
}
2005-04-17 02:20:36 +04:00
STATIC int
2006-03-14 06:00:51 +03:00
xfs_vn_permission (
2008-02-05 04:13:24 +03:00
struct inode * inode ,
2008-07-16 05:03:57 +04:00
int mask )
2005-04-17 02:20:36 +04:00
{
2008-02-05 04:13:24 +03:00
return generic_permission ( inode , mask , xfs_check_acl ) ;
2005-04-17 02:20:36 +04:00
}
# else
2006-03-14 06:00:51 +03:00
# define xfs_vn_permission NULL
2005-04-17 02:20:36 +04:00
# endif
STATIC int
2006-03-14 06:00:51 +03:00
xfs_vn_getattr (
2007-10-11 11:46:39 +04:00
struct vfsmount * mnt ,
struct dentry * dentry ,
struct kstat * stat )
2005-04-17 02:20:36 +04:00
{
2007-10-11 11:46:39 +04:00
struct inode * inode = dentry - > d_inode ;
struct xfs_inode * ip = XFS_I ( inode ) ;
struct xfs_mount * mp = ip - > i_mount ;
xfs_itrace_entry ( ip ) ;
if ( XFS_FORCED_SHUTDOWN ( mp ) )
return XFS_ERROR ( EIO ) ;
stat - > size = XFS_ISIZE ( ip ) ;
stat - > dev = inode - > i_sb - > s_dev ;
stat - > mode = ip - > i_d . di_mode ;
stat - > nlink = ip - > i_d . di_nlink ;
stat - > uid = ip - > i_d . di_uid ;
stat - > gid = ip - > i_d . di_gid ;
stat - > ino = ip - > i_ino ;
# if XFS_BIG_INUMS
stat - > ino + = mp - > m_inoadd ;
# endif
stat - > atime = inode - > i_atime ;
stat - > mtime . tv_sec = ip - > i_d . di_mtime . t_sec ;
stat - > mtime . tv_nsec = ip - > i_d . di_mtime . t_nsec ;
stat - > ctime . tv_sec = ip - > i_d . di_ctime . t_sec ;
stat - > ctime . tv_nsec = ip - > i_d . di_ctime . t_nsec ;
stat - > blocks =
XFS_FSB_TO_BB ( mp , ip - > i_d . di_nblocks + ip - > i_delayed_blks ) ;
switch ( inode - > i_mode & S_IFMT ) {
case S_IFBLK :
case S_IFCHR :
stat - > blksize = BLKDEV_IOSIZE ;
stat - > rdev = MKDEV ( sysv_major ( ip - > i_df . if_u2 . if_rdev ) & 0x1ff ,
sysv_minor ( ip - > i_df . if_u2 . if_rdev ) ) ;
break ;
default :
2007-11-23 08:29:42 +03:00
if ( XFS_IS_REALTIME_INODE ( ip ) ) {
2007-10-11 11:46:39 +04:00
/*
* If the file blocks are being allocated from a
* realtime volume , then return the inode ' s realtime
* extent size or the realtime volume ' s extent size .
*/
stat - > blksize =
xfs_get_extsz_hint ( ip ) < < mp - > m_sb . sb_blocklog ;
} else
stat - > blksize = xfs_preferred_iosize ( mp ) ;
stat - > rdev = 0 ;
break ;
2006-09-28 05:01:22 +04:00
}
2007-10-11 11:46:39 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
STATIC int
2006-03-14 06:00:51 +03:00
xfs_vn_setattr (
2005-04-17 02:20:36 +04:00
struct dentry * dentry ,
2008-07-18 11:13:28 +04:00
struct iattr * iattr )
2005-04-17 02:20:36 +04:00
{
2008-10-30 10:27:48 +03:00
return - xfs_setattr ( XFS_I ( dentry - > d_inode ) , iattr , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-10 06:21:46 +04:00
/*
* block_truncate_page can return an error , but we can ' t propagate it
* at all here . Leave a complaint + stack trace in the syslog because
* this could be bad . If it is bad , we need to propagate the error further .
*/
2005-04-17 02:20:36 +04:00
STATIC void
2006-03-14 06:00:51 +03:00
xfs_vn_truncate (
2005-04-17 02:20:36 +04:00
struct inode * inode )
{
2008-04-10 06:21:46 +04:00
int error ;
error = block_truncate_page ( inode - > i_mapping , inode - > i_size ,
xfs_get_blocks ) ;
WARN_ON ( error ) ;
2005-04-17 02:20:36 +04:00
}
2007-11-23 08:29:25 +03:00
STATIC long
xfs_vn_fallocate (
struct inode * inode ,
int mode ,
loff_t offset ,
loff_t len )
{
long error ;
loff_t new_size = 0 ;
xfs_flock64_t bf ;
xfs_inode_t * ip = XFS_I ( inode ) ;
/* preallocation on directories not yet supported */
error = - ENODEV ;
if ( S_ISDIR ( inode - > i_mode ) )
goto out_error ;
bf . l_whence = 0 ;
bf . l_start = offset ;
bf . l_len = len ;
xfs_ilock ( ip , XFS_IOLOCK_EXCL ) ;
error = xfs_change_file_space ( ip , XFS_IOC_RESVSP , & bf ,
2008-10-30 10:27:48 +03:00
0 , XFS_ATTR_NOLOCK ) ;
2007-11-23 08:29:25 +03:00
if ( ! error & & ! ( mode & FALLOC_FL_KEEP_SIZE ) & &
offset + len > i_size_read ( inode ) )
new_size = offset + len ;
/* Change file size if needed */
if ( new_size ) {
2008-07-18 11:13:28 +04:00
struct iattr iattr ;
2007-11-23 08:29:25 +03:00
2008-07-18 11:13:28 +04:00
iattr . ia_valid = ATTR_SIZE ;
iattr . ia_size = new_size ;
2008-10-30 10:27:48 +03:00
error = xfs_setattr ( ip , & iattr , XFS_ATTR_NOLOCK ) ;
2007-11-23 08:29:25 +03:00
}
xfs_iunlock ( ip , XFS_IOLOCK_EXCL ) ;
out_error :
return error ;
}
2005-04-17 02:20:36 +04:00
2008-08-13 10:23:13 +04:00
static const struct inode_operations xfs_inode_operations = {
2006-03-14 06:00:51 +03:00
. permission = xfs_vn_permission ,
. truncate = xfs_vn_truncate ,
. getattr = xfs_vn_getattr ,
. setattr = xfs_vn_setattr ,
2008-06-23 07:23:01 +04:00
. setxattr = generic_setxattr ,
. getxattr = generic_getxattr ,
. removexattr = generic_removexattr ,
2006-03-14 06:00:51 +03:00
. listxattr = xfs_vn_listxattr ,
2007-11-23 08:29:25 +03:00
. fallocate = xfs_vn_fallocate ,
2005-04-17 02:20:36 +04:00
} ;
2008-08-13 10:23:13 +04:00
static const struct inode_operations xfs_dir_inode_operations = {
2006-03-14 06:00:51 +03:00
. create = xfs_vn_create ,
. lookup = xfs_vn_lookup ,
. link = xfs_vn_link ,
. unlink = xfs_vn_unlink ,
. symlink = xfs_vn_symlink ,
. mkdir = xfs_vn_mkdir ,
2008-06-23 07:25:17 +04:00
/*
* Yes , XFS uses the same method for rmdir and unlink .
*
* There are some subtile differences deeper in the code ,
* but we use S_ISDIR to check for those .
*/
. rmdir = xfs_vn_unlink ,
2006-03-14 06:00:51 +03:00
. mknod = xfs_vn_mknod ,
. rename = xfs_vn_rename ,
. permission = xfs_vn_permission ,
. getattr = xfs_vn_getattr ,
. setattr = xfs_vn_setattr ,
2008-06-23 07:23:01 +04:00
. setxattr = generic_setxattr ,
. getxattr = generic_getxattr ,
. removexattr = generic_removexattr ,
2006-03-14 06:00:51 +03:00
. listxattr = xfs_vn_listxattr ,
2005-04-17 02:20:36 +04:00
} ;
2008-08-13 10:23:13 +04:00
static const struct inode_operations xfs_dir_ci_inode_operations = {
2008-05-21 10:58:22 +04:00
. create = xfs_vn_create ,
. lookup = xfs_vn_ci_lookup ,
. link = xfs_vn_link ,
. unlink = xfs_vn_unlink ,
. symlink = xfs_vn_symlink ,
. mkdir = xfs_vn_mkdir ,
2008-06-23 07:25:17 +04:00
/*
* Yes , XFS uses the same method for rmdir and unlink .
*
* There are some subtile differences deeper in the code ,
* but we use S_ISDIR to check for those .
*/
. rmdir = xfs_vn_unlink ,
2008-05-21 10:58:22 +04:00
. mknod = xfs_vn_mknod ,
. rename = xfs_vn_rename ,
. permission = xfs_vn_permission ,
. getattr = xfs_vn_getattr ,
. setattr = xfs_vn_setattr ,
2008-06-23 07:23:01 +04:00
. setxattr = generic_setxattr ,
. getxattr = generic_getxattr ,
. removexattr = generic_removexattr ,
2008-05-21 10:58:22 +04:00
. listxattr = xfs_vn_listxattr ,
} ;
2008-08-13 10:23:13 +04:00
static const struct inode_operations xfs_symlink_inode_operations = {
2005-04-17 02:20:36 +04:00
. readlink = generic_readlink ,
2006-03-14 06:00:51 +03:00
. follow_link = xfs_vn_follow_link ,
. put_link = xfs_vn_put_link ,
. permission = xfs_vn_permission ,
. getattr = xfs_vn_getattr ,
. setattr = xfs_vn_setattr ,
2008-06-23 07:23:01 +04:00
. setxattr = generic_setxattr ,
. getxattr = generic_getxattr ,
. removexattr = generic_removexattr ,
2006-03-14 06:00:51 +03:00
. listxattr = xfs_vn_listxattr ,
2005-04-17 02:20:36 +04:00
} ;
2008-08-13 10:23:13 +04:00
STATIC void
xfs_diflags_to_iflags (
struct inode * inode ,
struct xfs_inode * ip )
{
if ( ip - > i_d . di_flags & XFS_DIFLAG_IMMUTABLE )
inode - > i_flags | = S_IMMUTABLE ;
else
inode - > i_flags & = ~ S_IMMUTABLE ;
if ( ip - > i_d . di_flags & XFS_DIFLAG_APPEND )
inode - > i_flags | = S_APPEND ;
else
inode - > i_flags & = ~ S_APPEND ;
if ( ip - > i_d . di_flags & XFS_DIFLAG_SYNC )
inode - > i_flags | = S_SYNC ;
else
inode - > i_flags & = ~ S_SYNC ;
if ( ip - > i_d . di_flags & XFS_DIFLAG_NOATIME )
inode - > i_flags | = S_NOATIME ;
else
inode - > i_flags & = ~ S_NOATIME ;
}
/*
* Initialize the Linux inode , set up the operation vectors and
* unlock the inode .
*
* When reading existing inodes from disk this is called directly
* from xfs_iget , when creating a new inode it is called from
* xfs_ialloc after setting up the inode .
2008-10-30 09:36:14 +03:00
*
* We are always called with an uninitialised linux inode here .
* We need to initialise the necessary fields and take a reference
* on it .
2008-08-13 10:23:13 +04:00
*/
void
xfs_setup_inode (
struct xfs_inode * ip )
{
2008-10-30 09:36:14 +03:00
struct inode * inode = & ip - > i_vnode ;
inode - > i_ino = ip - > i_ino ;
inode - > i_state = I_NEW | I_LOCK ;
inode_add_to_lists ( ip - > i_mount - > m_super , inode ) ;
2008-08-13 10:23:13 +04:00
inode - > i_mode = ip - > i_d . di_mode ;
inode - > i_nlink = ip - > i_d . di_nlink ;
inode - > i_uid = ip - > i_d . di_uid ;
inode - > i_gid = ip - > i_d . di_gid ;
switch ( inode - > i_mode & S_IFMT ) {
case S_IFBLK :
case S_IFCHR :
inode - > i_rdev =
MKDEV ( sysv_major ( ip - > i_df . if_u2 . if_rdev ) & 0x1ff ,
sysv_minor ( ip - > i_df . if_u2 . if_rdev ) ) ;
break ;
default :
inode - > i_rdev = 0 ;
break ;
}
inode - > i_generation = ip - > i_d . di_gen ;
i_size_write ( inode , ip - > i_d . di_size ) ;
inode - > i_atime . tv_sec = ip - > i_d . di_atime . t_sec ;
inode - > i_atime . tv_nsec = ip - > i_d . di_atime . t_nsec ;
inode - > i_mtime . tv_sec = ip - > i_d . di_mtime . t_sec ;
inode - > i_mtime . tv_nsec = ip - > i_d . di_mtime . t_nsec ;
inode - > i_ctime . tv_sec = ip - > i_d . di_ctime . t_sec ;
inode - > i_ctime . tv_nsec = ip - > i_d . di_ctime . t_nsec ;
xfs_diflags_to_iflags ( inode , ip ) ;
xfs_iflags_clear ( ip , XFS_IMODIFIED ) ;
switch ( inode - > i_mode & S_IFMT ) {
case S_IFREG :
inode - > i_op = & xfs_inode_operations ;
inode - > i_fop = & xfs_file_operations ;
inode - > i_mapping - > a_ops = & xfs_address_space_operations ;
break ;
case S_IFDIR :
if ( xfs_sb_version_hasasciici ( & XFS_M ( inode - > i_sb ) - > m_sb ) )
inode - > i_op = & xfs_dir_ci_inode_operations ;
else
inode - > i_op = & xfs_dir_inode_operations ;
inode - > i_fop = & xfs_dir_file_operations ;
break ;
case S_IFLNK :
inode - > i_op = & xfs_symlink_inode_operations ;
if ( ! ( ip - > i_df . if_flags & XFS_IFINLINE ) )
inode - > i_mapping - > a_ops = & xfs_address_space_operations ;
break ;
default :
inode - > i_op = & xfs_inode_operations ;
init_special_inode ( inode , inode - > i_mode , inode - > i_rdev ) ;
break ;
}
xfs_iflags_clear ( ip , XFS_INEW ) ;
barrier ( ) ;
unlock_new_inode ( inode ) ;
}