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"
2005-11-02 06:38:42 +03:00
# include "xfs_fs.h"
2005-04-17 02:20:36 +04:00
# include "xfs_types.h"
2009-06-10 19:07:47 +04:00
# include "xfs_acl.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_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_dinode.h"
# include "xfs_inode.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_quota.h"
# include "xfs_utils.h"
2008-10-30 09:39:58 +03:00
# include "xfs_trans_priv.h"
# include "xfs_inode_item.h"
2008-11-28 06:23:42 +03:00
# include "xfs_bmap.h"
2009-12-15 02:14:59 +03:00
# include "xfs_trace.h"
2008-11-28 06:23:42 +03:00
2010-12-23 03:57:13 +03:00
/*
* Define xfs inode iolock lockdep classes . We need to ensure that all active
* inodes are considered the same for lockdep purposes , including inodes that
* are recycled through the XFS_IRECLAIMABLE state . This is the the only way to
* guarantee the locks are considered the same when there are multiple lock
* initialisation siteѕ . Also , define a reclaimable inode class so it is
* obvious in lockdep reports which class the report is against .
*/
static struct lock_class_key xfs_iolock_active ;
struct lock_class_key xfs_iolock_reclaimable ;
2008-11-28 06:23:42 +03:00
/*
* Allocate and initialise an xfs_inode .
*/
STATIC struct xfs_inode *
xfs_inode_alloc (
struct xfs_mount * mp ,
xfs_ino_t ino )
{
struct xfs_inode * ip ;
/*
* if this didn ' t occur in transactions , we could use
* KM_MAYFAIL and return NULL here on ENOMEM . Set the
* code up to do this anyway .
*/
ip = kmem_zone_alloc ( xfs_inode_zone , KM_SLEEP ) ;
if ( ! ip )
return NULL ;
2009-08-07 21:38:25 +04:00
if ( inode_init_always ( mp - > m_super , VFS_I ( ip ) ) ) {
kmem_zone_free ( xfs_inode_zone , ip ) ;
return NULL ;
}
2008-11-28 06:23:42 +03:00
ASSERT ( atomic_read ( & ip - > i_iocount ) = = 0 ) ;
ASSERT ( atomic_read ( & ip - > i_pincount ) = = 0 ) ;
ASSERT ( ! spin_is_locked ( & ip - > i_flags_lock ) ) ;
ASSERT ( completion_done ( & ip - > i_flush ) ) ;
2010-12-17 09:29:43 +03:00
ASSERT ( ip - > i_ino = = 0 ) ;
2009-10-19 08:05:26 +04:00
mrlock_init ( & ip - > i_iolock , MRLOCK_BARRIER , " xfsio " , ip - > i_ino ) ;
2010-12-23 03:57:13 +03:00
lockdep_set_class_and_name ( & ip - > i_iolock . mr_lock ,
& xfs_iolock_active , " xfs_iolock_active " ) ;
2008-11-28 06:23:42 +03:00
/* initialise the xfs inode */
ip - > i_ino = ino ;
ip - > i_mount = mp ;
memset ( & ip - > i_imap , 0 , sizeof ( struct xfs_imap ) ) ;
ip - > i_afp = NULL ;
memset ( & ip - > i_df , 0 , sizeof ( xfs_ifork_t ) ) ;
ip - > i_flags = 0 ;
ip - > i_update_core = 0 ;
ip - > i_delayed_blks = 0 ;
memset ( & ip - > i_d , 0 , sizeof ( xfs_icdinode_t ) ) ;
ip - > i_size = 0 ;
ip - > i_new_size = 0 ;
return ip ;
}
2005-04-17 02:20:36 +04:00
2011-01-07 09:49:49 +03:00
STATIC void
xfs_inode_free_callback (
struct rcu_head * head )
{
struct inode * inode = container_of ( head , struct inode , i_rcu ) ;
struct xfs_inode * ip = XFS_I ( inode ) ;
INIT_LIST_HEAD ( & inode - > i_dentry ) ;
kmem_zone_free ( xfs_inode_zone , ip ) ;
}
2010-07-20 11:53:25 +04:00
void
2009-08-07 21:38:34 +04:00
xfs_inode_free (
struct xfs_inode * ip )
{
switch ( ip - > i_d . di_mode & S_IFMT ) {
case S_IFREG :
case S_IFDIR :
case S_IFLNK :
xfs_idestroy_fork ( ip , XFS_DATA_FORK ) ;
break ;
}
if ( ip - > i_afp )
xfs_idestroy_fork ( ip , XFS_ATTR_FORK ) ;
if ( ip - > i_itemp ) {
/*
* Only if we are shutting down the fs will we see an
* inode still in the AIL . If it is there , we should remove
* it to prevent a use - after - free from occurring .
*/
xfs_log_item_t * lip = & ip - > i_itemp - > ili_item ;
struct xfs_ail * ailp = lip - > li_ailp ;
ASSERT ( ( ( lip - > li_flags & XFS_LI_IN_AIL ) = = 0 ) | |
XFS_FORCED_SHUTDOWN ( ip - > i_mount ) ) ;
if ( lip - > li_flags & XFS_LI_IN_AIL ) {
spin_lock ( & ailp - > xa_lock ) ;
if ( lip - > li_flags & XFS_LI_IN_AIL )
xfs_trans_ail_delete ( ailp , lip ) ;
else
spin_unlock ( & ailp - > xa_lock ) ;
}
xfs_inode_item_destroy ( ip ) ;
ip - > i_itemp = NULL ;
}
/* asserts to verify all state is correct here */
ASSERT ( atomic_read ( & ip - > i_iocount ) = = 0 ) ;
ASSERT ( atomic_read ( & ip - > i_pincount ) = = 0 ) ;
ASSERT ( ! spin_is_locked ( & ip - > i_flags_lock ) ) ;
ASSERT ( completion_done ( & ip - > i_flush ) ) ;
2010-12-17 09:29:43 +03:00
/*
* Because we use RCU freeing we need to ensure the inode always
* appears to be reclaimed with an invalid inode number when in the
* free state . The ip - > i_flags_lock provides the barrier against lookup
* races .
*/
spin_lock ( & ip - > i_flags_lock ) ;
ip - > i_flags = XFS_IRECLAIM ;
ip - > i_ino = 0 ;
spin_unlock ( & ip - > i_flags_lock ) ;
2011-01-11 06:35:55 +03:00
call_rcu ( & VFS_I ( ip ) - > i_rcu , xfs_inode_free_callback ) ;
2009-08-07 21:38:34 +04:00
}
2005-04-17 02:20:36 +04:00
/*
2008-10-30 09:21:19 +03:00
* Check the validity of the inode we just found it the cache
2005-04-17 02:20:36 +04:00
*/
2008-10-30 09:21:19 +03:00
static int
xfs_iget_cache_hit (
struct xfs_perag * pag ,
struct xfs_inode * ip ,
2010-12-17 09:29:43 +03:00
xfs_ino_t ino ,
2008-10-30 09:21:19 +03:00
int flags ,
2010-12-17 09:29:43 +03:00
int lock_flags ) __releases ( RCU )
2005-04-17 02:20:36 +04:00
{
2009-08-17 04:36:34 +04:00
struct inode * inode = VFS_I ( ip ) ;
2008-10-30 09:21:19 +03:00
struct xfs_mount * mp = ip - > i_mount ;
2009-08-17 04:36:34 +04:00
int error ;
2010-12-17 09:29:43 +03:00
/*
* check for re - use of an inode within an RCU grace period due to the
* radix tree nodes not being updated yet . We monitor for this by
* setting the inode number to zero before freeing the inode structure .
* If the inode has been reallocated and set up , then the inode number
* will not match , so check for that , too .
*/
2009-08-17 04:36:34 +04:00
spin_lock ( & ip - > i_flags_lock ) ;
2010-12-17 09:29:43 +03:00
if ( ip - > i_ino ! = ino ) {
trace_xfs_iget_skip ( ip ) ;
XFS_STATS_INC ( xs_ig_frecycle ) ;
error = EAGAIN ;
goto out_error ;
}
2007-08-28 08:00:13 +04:00
2008-10-30 09:21:19 +03:00
/*
2009-08-17 04:36:34 +04:00
* If we are racing with another cache hit that is currently
* instantiating this inode or currently recycling it out of
* reclaimabe state , wait for the initialisation to complete
* before continuing .
*
* XXX ( hch ) : eventually we should do something equivalent to
* wait_on_inode to wait for these flags to be cleared
* instead of polling for it .
2008-10-30 09:21:19 +03:00
*/
2009-08-17 04:36:34 +04:00
if ( ip - > i_flags & ( XFS_INEW | XFS_IRECLAIM ) ) {
2009-12-15 02:14:59 +03:00
trace_xfs_iget_skip ( ip ) ;
2008-10-30 09:21:19 +03:00
XFS_STATS_INC ( xs_ig_frecycle ) ;
2009-08-17 04:36:34 +04:00
error = EAGAIN ;
2008-10-30 09:21:19 +03:00
goto out_error ;
}
2007-08-28 08:00:13 +04:00
2009-08-17 04:36:34 +04:00
/*
* If lookup is racing with unlink return an error immediately .
*/
if ( ip - > i_d . di_mode = = 0 & & ! ( flags & XFS_IGET_CREATE ) ) {
error = ENOENT ;
goto out_error ;
}
2008-10-30 09:36:14 +03:00
2009-08-17 04:36:34 +04:00
/*
* If IRECLAIMABLE is set , we ' ve torn down the VFS inode already .
* Need to carefully get it back into useable state .
*/
if ( ip - > i_flags & XFS_IRECLAIMABLE ) {
2009-12-15 02:14:59 +03:00
trace_xfs_iget_reclaim ( ip ) ;
2007-08-28 08:00:13 +04:00
2008-10-30 09:21:19 +03:00
/*
2010-03-01 14:30:31 +03:00
* We need to set XFS_IRECLAIM to prevent xfs_reclaim_inode
* from stomping over us while we recycle the inode . We can ' t
* clear the radix tree reclaimable tag yet as it requires
* pag_ici_lock to be held exclusive .
2008-10-30 09:21:19 +03:00
*/
2010-03-01 14:30:31 +03:00
ip - > i_flags | = XFS_IRECLAIM ;
2009-08-17 04:36:34 +04:00
spin_unlock ( & ip - > i_flags_lock ) ;
2010-12-17 09:29:43 +03:00
rcu_read_unlock ( ) ;
2009-08-17 04:36:34 +04:00
error = - inode_init_always ( mp - > m_super , inode ) ;
if ( error ) {
/*
* Re - initializing the inode failed , and we are in deep
* trouble . Try to re - add it to the reclaim list .
*/
2010-12-17 09:29:43 +03:00
rcu_read_lock ( ) ;
2009-08-17 04:36:34 +04:00
spin_lock ( & ip - > i_flags_lock ) ;
2011-06-23 05:34:59 +04:00
ip - > i_flags & = ~ ( XFS_INEW | XFS_IRECLAIM ) ;
ASSERT ( ip - > i_flags & XFS_IRECLAIMABLE ) ;
2010-06-24 05:50:22 +04:00
trace_xfs_iget_reclaim_fail ( ip ) ;
2008-10-30 09:21:19 +03:00
goto out_error ;
2007-08-28 08:00:13 +04:00
}
2010-03-01 14:30:31 +03:00
2010-12-16 09:08:41 +03:00
spin_lock ( & pag - > pag_ici_lock ) ;
2010-03-01 14:30:31 +03:00
spin_lock ( & ip - > i_flags_lock ) ;
2011-06-23 05:34:59 +04:00
/*
* Clear the per - lifetime state in the inode as we are now
* effectively a new inode and need to return to the initial
* state before reuse occurs .
*/
ip - > i_flags & = ~ XFS_IRECLAIM_RESET_FLAGS ;
2010-03-01 14:30:31 +03:00
ip - > i_flags | = XFS_INEW ;
__xfs_inode_clear_reclaim_tag ( mp , pag , ip ) ;
2009-12-17 16:25:01 +03:00
inode - > i_state = I_NEW ;
2010-12-23 03:57:13 +03:00
ASSERT ( ! rwsem_is_locked ( & ip - > i_iolock . mr_lock ) ) ;
mrlock_init ( & ip - > i_iolock , MRLOCK_BARRIER , " xfsio " , ip - > i_ino ) ;
lockdep_set_class_and_name ( & ip - > i_iolock . mr_lock ,
& xfs_iolock_active , " xfs_iolock_active " ) ;
2010-03-01 14:30:31 +03:00
spin_unlock ( & ip - > i_flags_lock ) ;
2010-12-16 09:08:41 +03:00
spin_unlock ( & pag - > pag_ici_lock ) ;
2009-08-17 04:36:34 +04:00
} else {
2008-10-30 09:36:14 +03:00
/* If the VFS inode is being torn down, pause and try again. */
2009-08-17 04:36:34 +04:00
if ( ! igrab ( inode ) ) {
2010-06-24 05:50:22 +04:00
trace_xfs_iget_skip ( ip ) ;
2009-08-17 04:36:34 +04:00
error = EAGAIN ;
goto out_error ;
}
2005-04-17 02:20:36 +04:00
2009-08-17 04:36:34 +04:00
/* We've got a live one. */
spin_unlock ( & ip - > i_flags_lock ) ;
2010-12-17 09:29:43 +03:00
rcu_read_unlock ( ) ;
2010-06-24 05:50:22 +04:00
trace_xfs_iget_hit ( ip ) ;
2008-10-30 09:21:19 +03:00
}
2007-08-28 08:00:13 +04:00
2008-10-30 09:21:19 +03:00
if ( lock_flags ! = 0 )
xfs_ilock ( ip , lock_flags ) ;
2007-08-28 08:00:13 +04:00
2008-10-30 09:21:19 +03:00
xfs_iflags_clear ( ip , XFS_ISTALE ) ;
XFS_STATS_INC ( xs_ig_found ) ;
2009-12-15 02:14:59 +03:00
2008-10-30 09:21:19 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
2008-10-30 09:21:19 +03:00
out_error :
2009-08-17 04:36:34 +04:00
spin_unlock ( & ip - > i_flags_lock ) ;
2010-12-17 09:29:43 +03:00
rcu_read_unlock ( ) ;
2008-10-30 09:21:19 +03:00
return error ;
}
static int
xfs_iget_cache_miss (
struct xfs_mount * mp ,
struct xfs_perag * pag ,
xfs_trans_t * tp ,
xfs_ino_t ino ,
struct xfs_inode * * ipp ,
int flags ,
2009-11-14 19:17:23 +03:00
int lock_flags )
2008-10-30 09:21:19 +03:00
{
struct xfs_inode * ip ;
int error ;
xfs_agino_t agino = XFS_INO_TO_AGINO ( mp , ino ) ;
2005-04-17 02:20:36 +04:00
2008-11-28 06:23:42 +03:00
ip = xfs_inode_alloc ( mp , ino ) ;
if ( ! ip )
return ENOMEM ;
2010-06-24 05:35:17 +04:00
error = xfs_iread ( mp , tp , ip , flags ) ;
2008-10-30 09:21:19 +03:00
if ( error )
2008-11-28 06:23:42 +03:00
goto out_destroy ;
2005-04-17 02:20:36 +04:00
2010-06-24 05:50:22 +04:00
trace_xfs_iget_miss ( ip ) ;
2005-04-17 02:20:36 +04:00
2006-09-28 05:02:23 +04:00
if ( ( ip - > i_d . di_mode = = 0 ) & & ! ( flags & XFS_IGET_CREATE ) ) {
2008-10-30 09:21:19 +03:00
error = ENOENT ;
goto out_destroy ;
2005-04-17 02:20:36 +04:00
}
/*
2008-03-06 05:43:49 +03:00
* Preload the radix tree so we can insert safely under the
2008-10-30 09:55:27 +03:00
* write spinlock . Note that we cannot sleep inside the preload
* region .
2005-04-17 02:20:36 +04:00
*/
2007-08-28 08:00:13 +04:00
if ( radix_tree_preload ( GFP_KERNEL ) ) {
2008-10-30 09:21:19 +03:00
error = EAGAIN ;
2009-03-03 22:48:35 +03:00
goto out_destroy ;
}
/*
* Because the inode hasn ' t been added to the radix - tree yet it can ' t
* be found by another thread , so we can do the non - sleeping lock here .
*/
if ( lock_flags ) {
if ( ! xfs_ilock_nowait ( ip , lock_flags ) )
BUG ( ) ;
2007-08-28 08:00:13 +04:00
}
2008-10-30 08:53:38 +03:00
2010-12-16 09:08:41 +03:00
spin_lock ( & pag - > pag_ici_lock ) ;
2008-10-30 09:21:19 +03:00
/* insert the new inode */
2007-08-28 08:00:13 +04:00
error = radix_tree_insert ( & pag - > pag_ici_root , agino , ip ) ;
if ( unlikely ( error ) ) {
2008-10-30 09:21:19 +03:00
WARN_ON ( error ! = - EEXIST ) ;
2007-08-28 08:00:13 +04:00
XFS_STATS_INC ( xs_ig_dup ) ;
2008-10-30 09:21:19 +03:00
error = EAGAIN ;
2008-10-30 09:55:27 +03:00
goto out_preload_end ;
2005-04-17 02:20:36 +04:00
}
2008-10-30 09:21:19 +03:00
/* These values _must_ be set before releasing the radix tree lock! */
2005-04-17 02:20:36 +04:00
ip - > i_udquot = ip - > i_gdquot = NULL ;
2006-11-11 10:04:54 +03:00
xfs_iflags_set ( ip , XFS_INEW ) ;
2005-04-17 02:20:36 +04:00
2010-12-16 09:08:41 +03:00
spin_unlock ( & pag - > pag_ici_lock ) ;
2007-08-28 08:00:13 +04:00
radix_tree_preload_end ( ) ;
2009-12-15 02:14:59 +03:00
2008-10-30 09:21:19 +03:00
* ipp = ip ;
return 0 ;
2008-10-30 09:55:27 +03:00
out_preload_end :
2010-12-16 09:08:41 +03:00
spin_unlock ( & pag - > pag_ici_lock ) ;
2008-10-30 09:21:19 +03:00
radix_tree_preload_end ( ) ;
2008-10-30 09:55:27 +03:00
if ( lock_flags )
xfs_iunlock ( ip , lock_flags ) ;
2008-10-30 09:21:19 +03:00
out_destroy :
2009-08-07 21:38:34 +04:00
__destroy_inode ( VFS_I ( ip ) ) ;
xfs_inode_free ( ip ) ;
2008-10-30 09:21:19 +03:00
return error ;
}
/*
* Look up an inode by number in the given file system .
* The inode is looked up in the cache held in each AG .
2008-10-30 09:36:14 +03:00
* If the inode is found in the cache , initialise the vfs inode
* if necessary .
2008-10-30 09:21:19 +03:00
*
* If it is not in core , read it in from the file system ' s device ,
2008-10-30 09:36:14 +03:00
* add it to the cache and initialise the vfs inode .
2008-10-30 09:21:19 +03:00
*
* The inode is locked according to the value of the lock_flags parameter .
* This flag parameter indicates how and if the inode ' s IO lock and inode lock
* should be taken .
*
* mp - - the mount point structure for the current file system . It points
* to the inode hash table .
* tp - - a pointer to the current transaction if there is one . This is
* simply passed through to the xfs_iread ( ) call .
* ino - - the number of the inode desired . This is the unique identifier
* within the file system for the inode being requested .
* lock_flags - - flags indicating how to lock the inode . See the comment
* for xfs_ilock ( ) for a list of valid values .
*/
2008-10-30 09:36:14 +03:00
int
xfs_iget (
2008-10-30 09:21:19 +03:00
xfs_mount_t * mp ,
xfs_trans_t * tp ,
xfs_ino_t ino ,
uint flags ,
uint lock_flags ,
2010-06-24 05:35:17 +04:00
xfs_inode_t * * ipp )
2008-10-30 09:21:19 +03:00
{
xfs_inode_t * ip ;
int error ;
xfs_perag_t * pag ;
xfs_agino_t agino ;
2010-10-06 22:31:23 +04:00
/* reject inode numbers outside existing AGs */
2010-12-17 09:29:43 +03:00
if ( ! ino | | XFS_INO_TO_AGNO ( mp , ino ) > = mp - > m_sb . sb_agcount )
2008-10-30 09:21:19 +03:00
return EINVAL ;
/* get the perag structure and ensure that it's inode capable */
2010-01-11 14:47:40 +03:00
pag = xfs_perag_get ( mp , XFS_INO_TO_AGNO ( mp , ino ) ) ;
2008-10-30 09:21:19 +03:00
agino = XFS_INO_TO_AGINO ( mp , ino ) ;
again :
error = 0 ;
2010-12-17 09:29:43 +03:00
rcu_read_lock ( ) ;
2008-10-30 09:21:19 +03:00
ip = radix_tree_lookup ( & pag - > pag_ici_root , agino ) ;
if ( ip ) {
2010-12-17 09:29:43 +03:00
error = xfs_iget_cache_hit ( pag , ip , ino , flags , lock_flags ) ;
2008-10-30 09:21:19 +03:00
if ( error )
goto out_error_or_again ;
} else {
2010-12-17 09:29:43 +03:00
rcu_read_unlock ( ) ;
2008-10-30 09:21:19 +03:00
XFS_STATS_INC ( xs_ig_missed ) ;
2010-06-24 05:35:17 +04:00
error = xfs_iget_cache_miss ( mp , pag , tp , ino , & ip ,
2008-10-30 09:21:19 +03:00
flags , lock_flags ) ;
if ( error )
goto out_error_or_again ;
}
2010-01-11 14:47:40 +03:00
xfs_perag_put ( pag ) ;
2005-04-17 02:20:36 +04:00
* ipp = ip ;
2008-10-30 09:36:14 +03:00
ASSERT ( ip - > i_df . if_ext_max = =
XFS_IFORK_DSIZE ( ip ) / sizeof ( xfs_bmbt_rec_t ) ) ;
2005-04-17 02:20:36 +04:00
/*
* If we have a real type for an on - disk inode , we can set ops ( & unlock )
* now . If it ' s a new inode being created , xfs_ialloc will handle it .
*/
2008-10-30 09:36:14 +03:00
if ( xfs_iflags_test ( ip , XFS_INEW ) & & ip - > i_d . di_mode ! = 0 )
2008-08-13 10:23:13 +04:00
xfs_setup_inode ( ip ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2008-10-30 09:21:19 +03:00
out_error_or_again :
if ( error = = EAGAIN ) {
delay ( 1 ) ;
goto again ;
}
2010-01-11 14:47:40 +03:00
xfs_perag_put ( pag ) ;
2008-10-30 09:21:19 +03:00
return error ;
2005-04-17 02:20:36 +04:00
}
/*
* This is a wrapper routine around the xfs_ilock ( ) routine
* used to centralize some grungy code . It is used in places
* that wish to lock the inode solely for reading the extents .
* The reason these places can ' t just call xfs_ilock ( SHARED )
* is that the inode lock also guards to bringing in of the
* extents from disk for a file in b - tree format . If the inode
* is in b - tree format , then we need to lock the inode exclusively
* until the extents are read in . Locking it exclusively all
* the time would limit our parallelism unnecessarily , though .
* What we do instead is check to see if the extents have been
* read in yet , and only lock the inode exclusively if they
* have not .
*
* The function returns a value which should be given to the
* corresponding xfs_iunlock_map_shared ( ) . This value is
* the mode in which the lock was actually taken .
*/
uint
xfs_ilock_map_shared (
xfs_inode_t * ip )
{
uint lock_mode ;
if ( ( ip - > i_d . di_format = = XFS_DINODE_FMT_BTREE ) & &
( ( ip - > i_df . if_flags & XFS_IFEXTENTS ) = = 0 ) ) {
lock_mode = XFS_ILOCK_EXCL ;
} else {
lock_mode = XFS_ILOCK_SHARED ;
}
xfs_ilock ( ip , lock_mode ) ;
return lock_mode ;
}
/*
* This is simply the unlock routine to go with xfs_ilock_map_shared ( ) .
* All it does is call xfs_iunlock ( ) with the given lock_mode .
*/
void
xfs_iunlock_map_shared (
xfs_inode_t * ip ,
unsigned int lock_mode )
{
xfs_iunlock ( ip , lock_mode ) ;
}
/*
* The xfs inode contains 2 locks : a multi - reader lock called the
* i_iolock and a multi - reader lock called the i_lock . This routine
* allows either or both of the locks to be obtained .
*
* The 2 locks should always be ordered so that the IO lock is
* obtained first in order to prevent deadlock .
*
* ip - - the inode being locked
* lock_flags - - this parameter indicates the inode ' s locks
* to be locked . It can be :
* XFS_IOLOCK_SHARED ,
* XFS_IOLOCK_EXCL ,
* XFS_ILOCK_SHARED ,
* XFS_ILOCK_EXCL ,
* XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED ,
* XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL ,
* XFS_IOLOCK_EXCL | XFS_ILOCK_SHARED ,
* XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL
*/
void
2008-04-22 11:34:00 +04:00
xfs_ilock (
xfs_inode_t * ip ,
uint lock_flags )
2005-04-17 02:20:36 +04:00
{
/*
* You can ' t set both SHARED and EXCL for the same lock ,
* and only XFS_IOLOCK_SHARED , XFS_IOLOCK_EXCL , XFS_ILOCK_SHARED ,
* and XFS_ILOCK_EXCL are valid values to set in lock_flags .
*/
ASSERT ( ( lock_flags & ( XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL ) ) ! =
( XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL ) ) ;
ASSERT ( ( lock_flags & ( XFS_ILOCK_SHARED | XFS_ILOCK_EXCL ) ) ! =
( XFS_ILOCK_SHARED | XFS_ILOCK_EXCL ) ) ;
2007-05-08 07:50:19 +04:00
ASSERT ( ( lock_flags & ~ ( XFS_LOCK_MASK | XFS_LOCK_DEP_MASK ) ) = = 0 ) ;
2005-04-17 02:20:36 +04:00
2008-04-22 11:34:00 +04:00
if ( lock_flags & XFS_IOLOCK_EXCL )
2007-05-08 07:50:19 +04:00
mrupdate_nested ( & ip - > i_iolock , XFS_IOLOCK_DEP ( lock_flags ) ) ;
2008-04-22 11:34:00 +04:00
else if ( lock_flags & XFS_IOLOCK_SHARED )
2007-05-08 07:50:19 +04:00
mraccess_nested ( & ip - > i_iolock , XFS_IOLOCK_DEP ( lock_flags ) ) ;
2008-04-22 11:34:00 +04:00
if ( lock_flags & XFS_ILOCK_EXCL )
2007-05-08 07:50:19 +04:00
mrupdate_nested ( & ip - > i_lock , XFS_ILOCK_DEP ( lock_flags ) ) ;
2008-04-22 11:34:00 +04:00
else if ( lock_flags & XFS_ILOCK_SHARED )
2007-05-08 07:50:19 +04:00
mraccess_nested ( & ip - > i_lock , XFS_ILOCK_DEP ( lock_flags ) ) ;
2008-04-22 11:34:00 +04:00
2009-12-15 02:14:59 +03:00
trace_xfs_ilock ( ip , lock_flags , _RET_IP_ ) ;
2005-04-17 02:20:36 +04:00
}
/*
* This is just like xfs_ilock ( ) , except that the caller
* is guaranteed not to sleep . It returns 1 if it gets
* the requested locks and 0 otherwise . If the IO lock is
* obtained but the inode lock cannot be , then the IO lock
* is dropped before returning .
*
* ip - - the inode being locked
* lock_flags - - this parameter indicates the inode ' s locks to be
* to be locked . See the comment for xfs_ilock ( ) for a list
* of valid values .
*/
int
2008-04-22 11:34:00 +04:00
xfs_ilock_nowait (
xfs_inode_t * ip ,
uint lock_flags )
2005-04-17 02:20:36 +04:00
{
/*
* You can ' t set both SHARED and EXCL for the same lock ,
* and only XFS_IOLOCK_SHARED , XFS_IOLOCK_EXCL , XFS_ILOCK_SHARED ,
* and XFS_ILOCK_EXCL are valid values to set in lock_flags .
*/
ASSERT ( ( lock_flags & ( XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL ) ) ! =
( XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL ) ) ;
ASSERT ( ( lock_flags & ( XFS_ILOCK_SHARED | XFS_ILOCK_EXCL ) ) ! =
( XFS_ILOCK_SHARED | XFS_ILOCK_EXCL ) ) ;
2007-05-08 07:50:19 +04:00
ASSERT ( ( lock_flags & ~ ( XFS_LOCK_MASK | XFS_LOCK_DEP_MASK ) ) = = 0 ) ;
2005-04-17 02:20:36 +04:00
if ( lock_flags & XFS_IOLOCK_EXCL ) {
2008-04-22 11:34:00 +04:00
if ( ! mrtryupdate ( & ip - > i_iolock ) )
goto out ;
2005-04-17 02:20:36 +04:00
} else if ( lock_flags & XFS_IOLOCK_SHARED ) {
2008-04-22 11:34:00 +04:00
if ( ! mrtryaccess ( & ip - > i_iolock ) )
goto out ;
2005-04-17 02:20:36 +04:00
}
if ( lock_flags & XFS_ILOCK_EXCL ) {
2008-04-22 11:34:00 +04:00
if ( ! mrtryupdate ( & ip - > i_lock ) )
goto out_undo_iolock ;
2005-04-17 02:20:36 +04:00
} else if ( lock_flags & XFS_ILOCK_SHARED ) {
2008-04-22 11:34:00 +04:00
if ( ! mrtryaccess ( & ip - > i_lock ) )
goto out_undo_iolock ;
2005-04-17 02:20:36 +04:00
}
2009-12-15 02:14:59 +03:00
trace_xfs_ilock_nowait ( ip , lock_flags , _RET_IP_ ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
2008-04-22 11:34:00 +04:00
out_undo_iolock :
if ( lock_flags & XFS_IOLOCK_EXCL )
mrunlock_excl ( & ip - > i_iolock ) ;
else if ( lock_flags & XFS_IOLOCK_SHARED )
mrunlock_shared ( & ip - > i_iolock ) ;
out :
return 0 ;
2005-04-17 02:20:36 +04:00
}
/*
* xfs_iunlock ( ) is used to drop the inode locks acquired with
* xfs_ilock ( ) and xfs_ilock_nowait ( ) . The caller must pass
* in the flags given to xfs_ilock ( ) or xfs_ilock_nowait ( ) so
* that we know which locks to drop .
*
* ip - - the inode being unlocked
* lock_flags - - this parameter indicates the inode ' s locks to be
* to be unlocked . See the comment for xfs_ilock ( ) for a list
* of valid values for this parameter .
*
*/
void
2008-04-22 11:34:00 +04:00
xfs_iunlock (
xfs_inode_t * ip ,
uint lock_flags )
2005-04-17 02:20:36 +04:00
{
/*
* You can ' t set both SHARED and EXCL for the same lock ,
* and only XFS_IOLOCK_SHARED , XFS_IOLOCK_EXCL , XFS_ILOCK_SHARED ,
* and XFS_ILOCK_EXCL are valid values to set in lock_flags .
*/
ASSERT ( ( lock_flags & ( XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL ) ) ! =
( XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL ) ) ;
ASSERT ( ( lock_flags & ( XFS_ILOCK_SHARED | XFS_ILOCK_EXCL ) ) ! =
( XFS_ILOCK_SHARED | XFS_ILOCK_EXCL ) ) ;
2007-05-08 07:50:19 +04:00
ASSERT ( ( lock_flags & ~ ( XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY |
XFS_LOCK_DEP_MASK ) ) = = 0 ) ;
2005-04-17 02:20:36 +04:00
ASSERT ( lock_flags ! = 0 ) ;
2008-04-22 11:34:00 +04:00
if ( lock_flags & XFS_IOLOCK_EXCL )
mrunlock_excl ( & ip - > i_iolock ) ;
else if ( lock_flags & XFS_IOLOCK_SHARED )
mrunlock_shared ( & ip - > i_iolock ) ;
2005-04-17 02:20:36 +04:00
2008-04-22 11:34:00 +04:00
if ( lock_flags & XFS_ILOCK_EXCL )
mrunlock_excl ( & ip - > i_lock ) ;
else if ( lock_flags & XFS_ILOCK_SHARED )
mrunlock_shared ( & ip - > i_lock ) ;
2005-04-17 02:20:36 +04:00
2008-04-22 11:34:00 +04:00
if ( ( lock_flags & ( XFS_ILOCK_SHARED | XFS_ILOCK_EXCL ) ) & &
! ( lock_flags & XFS_IUNLOCK_NONOTIFY ) & & ip - > i_itemp ) {
2005-04-17 02:20:36 +04:00
/*
* Let the AIL know that this item has been unlocked in case
* it is in the AIL and anyone is waiting on it . Don ' t do
* this if the caller has asked us not to .
*/
2008-10-30 09:39:58 +03:00
xfs_trans_unlocked_item ( ip - > i_itemp - > ili_item . li_ailp ,
2008-04-22 11:34:00 +04:00
( xfs_log_item_t * ) ( ip - > i_itemp ) ) ;
2005-04-17 02:20:36 +04:00
}
2009-12-15 02:14:59 +03:00
trace_xfs_iunlock ( ip , lock_flags , _RET_IP_ ) ;
2005-04-17 02:20:36 +04:00
}
/*
* give up write locks . the i / o lock cannot be held nested
* if it is being demoted .
*/
void
2008-04-22 11:34:00 +04:00
xfs_ilock_demote (
xfs_inode_t * ip ,
uint lock_flags )
2005-04-17 02:20:36 +04:00
{
ASSERT ( lock_flags & ( XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL ) ) ;
ASSERT ( ( lock_flags & ~ ( XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL ) ) = = 0 ) ;
2008-04-22 11:34:00 +04:00
if ( lock_flags & XFS_ILOCK_EXCL )
2005-04-17 02:20:36 +04:00
mrdemote ( & ip - > i_lock ) ;
2008-04-22 11:34:00 +04:00
if ( lock_flags & XFS_IOLOCK_EXCL )
2005-04-17 02:20:36 +04:00
mrdemote ( & ip - > i_iolock ) ;
2009-12-15 02:14:59 +03:00
trace_xfs_ilock_demote ( ip , lock_flags , _RET_IP_ ) ;
2008-04-22 11:34:00 +04:00
}
# ifdef DEBUG
int
xfs_isilocked (
xfs_inode_t * ip ,
uint lock_flags )
{
2010-06-03 10:22:29 +04:00
if ( lock_flags & ( XFS_ILOCK_EXCL | XFS_ILOCK_SHARED ) ) {
if ( ! ( lock_flags & XFS_ILOCK_SHARED ) )
return ! ! ip - > i_lock . mr_writer ;
return rwsem_is_locked ( & ip - > i_lock . mr_lock ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-22 11:34:00 +04:00
2010-06-03 10:22:29 +04:00
if ( lock_flags & ( XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED ) ) {
if ( ! ( lock_flags & XFS_IOLOCK_SHARED ) )
return ! ! ip - > i_iolock . mr_writer ;
return rwsem_is_locked ( & ip - > i_iolock . mr_lock ) ;
2008-04-22 11:34:00 +04:00
}
2010-06-03 10:22:29 +04:00
ASSERT ( 0 ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-04-22 11:34:00 +04:00
# endif