2016-12-16 13:02:56 +03:00
/*
* Copyright ( C ) 2011 Novell Inc .
* Copyright ( C ) 2016 Red Hat , Inc .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation .
*/
# include <linux/fs.h>
# include <linux/mount.h>
# include <linux/slab.h>
2017-02-02 19:54:15 +03:00
# include <linux/cred.h>
2016-12-16 13:02:56 +03:00
# include <linux/xattr.h>
2017-06-21 15:28:36 +03:00
# include <linux/exportfs.h>
# include <linux/uuid.h>
2016-12-16 13:02:56 +03:00
# include "overlayfs.h"
# include "ovl_entry.h"
int ovl_want_write ( struct dentry * dentry )
{
struct ovl_fs * ofs = dentry - > d_sb - > s_fs_info ;
return mnt_want_write ( ofs - > upper_mnt ) ;
}
void ovl_drop_write ( struct dentry * dentry )
{
struct ovl_fs * ofs = dentry - > d_sb - > s_fs_info ;
mnt_drop_write ( ofs - > upper_mnt ) ;
}
struct dentry * ovl_workdir ( struct dentry * dentry )
{
struct ovl_fs * ofs = dentry - > d_sb - > s_fs_info ;
return ofs - > workdir ;
}
const struct cred * ovl_override_creds ( struct super_block * sb )
{
struct ovl_fs * ofs = sb - > s_fs_info ;
return override_creds ( ofs - > creator_cred ) ;
}
2017-03-22 15:42:21 +03:00
struct super_block * ovl_same_sb ( struct super_block * sb )
{
struct ovl_fs * ofs = sb - > s_fs_info ;
return ofs - > same_sb ;
}
2017-06-21 15:28:36 +03:00
bool ovl_can_decode_fh ( struct super_block * sb )
{
return ( sb - > s_export_op & & sb - > s_export_op - > fh_to_dentry & &
! uuid_is_null ( & sb - > s_uuid ) ) ;
}
struct dentry * ovl_indexdir ( struct super_block * sb )
{
struct ovl_fs * ofs = sb - > s_fs_info ;
return ofs - > indexdir ;
}
2016-12-16 13:02:56 +03:00
struct ovl_entry * ovl_alloc_entry ( unsigned int numlower )
{
size_t size = offsetof ( struct ovl_entry , lowerstack [ numlower ] ) ;
struct ovl_entry * oe = kzalloc ( size , GFP_KERNEL ) ;
if ( oe )
oe - > numlower = numlower ;
return oe ;
}
bool ovl_dentry_remote ( struct dentry * dentry )
{
return dentry - > d_flags &
( DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE |
DCACHE_OP_REAL ) ;
}
bool ovl_dentry_weird ( struct dentry * dentry )
{
return dentry - > d_flags & ( DCACHE_NEED_AUTOMOUNT |
DCACHE_MANAGE_TRANSIT |
DCACHE_OP_HASH |
DCACHE_OP_COMPARE ) ;
}
enum ovl_path_type ovl_path_type ( struct dentry * dentry )
{
struct ovl_entry * oe = dentry - > d_fsdata ;
enum ovl_path_type type = 0 ;
2017-07-04 23:03:16 +03:00
if ( ovl_dentry_upper ( dentry ) ) {
2016-12-16 13:02:56 +03:00
type = __OVL_PATH_UPPER ;
/*
2017-04-23 23:12:34 +03:00
* Non - dir dentry can hold lower dentry of its copy up origin .
2016-12-16 13:02:56 +03:00
*/
2017-04-23 23:12:34 +03:00
if ( oe - > numlower ) {
type | = __OVL_PATH_ORIGIN ;
if ( d_is_dir ( dentry ) )
type | = __OVL_PATH_MERGE ;
}
2016-12-16 13:02:56 +03:00
} else {
if ( oe - > numlower > 1 )
type | = __OVL_PATH_MERGE ;
}
return type ;
}
void ovl_path_upper ( struct dentry * dentry , struct path * path )
{
struct ovl_fs * ofs = dentry - > d_sb - > s_fs_info ;
path - > mnt = ofs - > upper_mnt ;
2017-07-04 23:03:16 +03:00
path - > dentry = ovl_dentry_upper ( dentry ) ;
2016-12-16 13:02:56 +03:00
}
void ovl_path_lower ( struct dentry * dentry , struct path * path )
{
struct ovl_entry * oe = dentry - > d_fsdata ;
2017-03-30 00:02:19 +03:00
* path = oe - > numlower ? oe - > lowerstack [ 0 ] : ( struct path ) { } ;
2016-12-16 13:02:56 +03:00
}
enum ovl_path_type ovl_path_real ( struct dentry * dentry , struct path * path )
{
enum ovl_path_type type = ovl_path_type ( dentry ) ;
if ( ! OVL_TYPE_UPPER ( type ) )
ovl_path_lower ( dentry , path ) ;
else
ovl_path_upper ( dentry , path ) ;
return type ;
}
struct dentry * ovl_dentry_upper ( struct dentry * dentry )
{
2017-07-04 23:03:16 +03:00
return ovl_upperdentry_dereference ( OVL_I ( d_inode ( dentry ) ) ) ;
2016-12-16 13:02:56 +03:00
}
struct dentry * ovl_dentry_lower ( struct dentry * dentry )
{
struct ovl_entry * oe = dentry - > d_fsdata ;
2017-07-04 23:03:16 +03:00
return oe - > numlower ? oe - > lowerstack [ 0 ] . dentry : NULL ;
2016-12-16 13:02:56 +03:00
}
struct dentry * ovl_dentry_real ( struct dentry * dentry )
{
2017-07-04 23:03:16 +03:00
return ovl_dentry_upper ( dentry ) ? : ovl_dentry_lower ( dentry ) ;
2016-12-16 13:02:56 +03:00
}
2017-07-04 23:03:16 +03:00
struct inode * ovl_inode_upper ( struct inode * inode )
2017-07-04 23:03:16 +03:00
{
2017-07-04 23:03:16 +03:00
struct dentry * upperdentry = ovl_upperdentry_dereference ( OVL_I ( inode ) ) ;
2017-07-04 23:03:16 +03:00
2017-07-04 23:03:16 +03:00
return upperdentry ? d_inode ( upperdentry ) : NULL ;
}
2017-07-04 23:03:16 +03:00
2017-07-04 23:03:16 +03:00
struct inode * ovl_inode_lower ( struct inode * inode )
{
return OVL_I ( inode ) - > lower ;
}
2017-07-04 23:03:16 +03:00
2017-07-04 23:03:16 +03:00
struct inode * ovl_inode_real ( struct inode * inode )
{
return ovl_inode_upper ( inode ) ? : ovl_inode_lower ( inode ) ;
2017-07-04 23:03:16 +03:00
}
2017-07-04 23:03:16 +03:00
2016-12-16 13:02:56 +03:00
struct ovl_dir_cache * ovl_dir_cache ( struct dentry * dentry )
{
2017-07-04 23:03:16 +03:00
return OVL_I ( d_inode ( dentry ) ) - > cache ;
2016-12-16 13:02:56 +03:00
}
void ovl_set_dir_cache ( struct dentry * dentry , struct ovl_dir_cache * cache )
{
2017-07-04 23:03:16 +03:00
OVL_I ( d_inode ( dentry ) ) - > cache = cache ;
2016-12-16 13:02:56 +03:00
}
bool ovl_dentry_is_opaque ( struct dentry * dentry )
{
struct ovl_entry * oe = dentry - > d_fsdata ;
return oe - > opaque ;
}
bool ovl_dentry_is_whiteout ( struct dentry * dentry )
{
return ! dentry - > d_inode & & ovl_dentry_is_opaque ( dentry ) ;
}
2016-12-16 13:02:57 +03:00
void ovl_dentry_set_opaque ( struct dentry * dentry )
2016-12-16 13:02:56 +03:00
{
struct ovl_entry * oe = dentry - > d_fsdata ;
2016-12-16 13:02:57 +03:00
oe - > opaque = true ;
2016-12-16 13:02:56 +03:00
}
2017-07-04 23:03:18 +03:00
/*
* For hard links it ' s possible for ovl_dentry_upper ( ) to return positive , while
* there ' s no actual upper alias for the inode . Copy up code needs to know
* about the existence of the upper alias , so it can ' t use ovl_dentry_upper ( ) .
*/
bool ovl_dentry_has_upper_alias ( struct dentry * dentry )
{
struct ovl_entry * oe = dentry - > d_fsdata ;
return oe - > has_upper ;
}
void ovl_dentry_set_upper_alias ( struct dentry * dentry )
{
struct ovl_entry * oe = dentry - > d_fsdata ;
oe - > has_upper = true ;
}
2016-12-16 13:02:56 +03:00
bool ovl_redirect_dir ( struct super_block * sb )
{
struct ovl_fs * ofs = sb - > s_fs_info ;
2017-05-17 00:12:41 +03:00
return ofs - > config . redirect_dir & & ! ofs - > noxattr ;
2016-12-16 13:02:56 +03:00
}
const char * ovl_dentry_get_redirect ( struct dentry * dentry )
{
2017-07-04 23:03:16 +03:00
return OVL_I ( d_inode ( dentry ) ) - > redirect ;
2016-12-16 13:02:56 +03:00
}
void ovl_dentry_set_redirect ( struct dentry * dentry , const char * redirect )
{
2017-07-04 23:03:16 +03:00
struct ovl_inode * oi = OVL_I ( d_inode ( dentry ) ) ;
2016-12-16 13:02:56 +03:00
2017-07-04 23:03:16 +03:00
kfree ( oi - > redirect ) ;
oi - > redirect = redirect ;
2016-12-16 13:02:56 +03:00
}
2017-07-04 23:03:16 +03:00
void ovl_inode_init ( struct inode * inode , struct dentry * upperdentry ,
struct dentry * lowerdentry )
2016-12-16 13:02:56 +03:00
{
2017-07-04 23:03:16 +03:00
if ( upperdentry )
OVL_I ( inode ) - > __upperdentry = upperdentry ;
if ( lowerdentry )
OVL_I ( inode ) - > lower = d_inode ( lowerdentry ) ;
2016-12-16 13:02:56 +03:00
2017-07-04 23:03:16 +03:00
ovl_copyattr ( d_inode ( upperdentry ? : lowerdentry ) , inode ) ;
2016-12-16 13:02:56 +03:00
}
2017-07-04 23:03:16 +03:00
void ovl_inode_update ( struct inode * inode , struct dentry * upperdentry )
2016-12-16 13:02:56 +03:00
{
2017-07-04 23:03:16 +03:00
struct inode * upperinode = d_inode ( upperdentry ) ;
2017-07-04 23:03:16 +03:00
2017-07-04 23:03:16 +03:00
WARN_ON ( OVL_I ( inode ) - > __upperdentry ) ;
2017-07-04 23:03:16 +03:00
/*
2017-07-04 23:03:16 +03:00
* Make sure upperdentry is consistent before making it visible
2017-07-04 23:03:16 +03:00
*/
smp_wmb ( ) ;
2017-07-04 23:03:16 +03:00
OVL_I ( inode ) - > __upperdentry = upperdentry ;
2017-07-04 23:03:17 +03:00
if ( ! S_ISDIR ( upperinode - > i_mode ) & & inode_unhashed ( inode ) ) {
2017-07-04 23:03:16 +03:00
inode - > i_private = upperinode ;
2016-12-16 13:02:56 +03:00
__insert_inode_hash ( inode , ( unsigned long ) upperinode ) ;
2017-07-04 23:03:16 +03:00
}
2016-12-16 13:02:56 +03:00
}
void ovl_dentry_version_inc ( struct dentry * dentry )
{
2017-07-04 23:03:16 +03:00
struct inode * inode = d_inode ( dentry ) ;
2016-12-16 13:02:56 +03:00
2017-07-04 23:03:16 +03:00
WARN_ON ( ! inode_is_locked ( inode ) ) ;
OVL_I ( inode ) - > version + + ;
2016-12-16 13:02:56 +03:00
}
u64 ovl_dentry_version_get ( struct dentry * dentry )
{
2017-07-04 23:03:16 +03:00
struct inode * inode = d_inode ( dentry ) ;
2016-12-16 13:02:56 +03:00
2017-07-04 23:03:16 +03:00
WARN_ON ( ! inode_is_locked ( inode ) ) ;
return OVL_I ( inode ) - > version ;
2016-12-16 13:02:56 +03:00
}
bool ovl_is_whiteout ( struct dentry * dentry )
{
struct inode * inode = dentry - > d_inode ;
return inode & & IS_WHITEOUT ( inode ) ;
}
struct file * ovl_path_open ( struct path * path , int flags )
{
return dentry_open ( path , flags | O_NOATIME , current_cred ( ) ) ;
}
2017-01-17 07:34:56 +03:00
int ovl_copy_up_start ( struct dentry * dentry )
{
2017-06-21 15:28:51 +03:00
struct ovl_inode * oi = OVL_I ( d_inode ( dentry ) ) ;
2017-01-17 07:34:56 +03:00
int err ;
2017-06-21 15:28:51 +03:00
err = mutex_lock_interruptible ( & oi - > lock ) ;
2017-06-20 15:25:46 +03:00
if ( ! err & & ovl_dentry_has_upper_alias ( dentry ) ) {
2017-06-21 15:28:51 +03:00
err = 1 ; /* Already copied up */
mutex_unlock ( & oi - > lock ) ;
2017-01-17 07:34:56 +03:00
}
return err ;
}
void ovl_copy_up_end ( struct dentry * dentry )
{
2017-06-21 15:28:51 +03:00
mutex_unlock ( & OVL_I ( d_inode ( dentry ) ) - > lock ) ;
2017-01-17 07:34:56 +03:00
}
2017-05-17 00:12:40 +03:00
2017-05-24 15:29:33 +03:00
bool ovl_check_dir_xattr ( struct dentry * dentry , const char * name )
{
int res ;
char val ;
if ( ! d_is_dir ( dentry ) )
return false ;
res = vfs_getxattr ( dentry , name , & val , 1 ) ;
if ( res = = 1 & & val = = ' y ' )
return true ;
return false ;
}
2017-05-17 00:12:40 +03:00
int ovl_check_setxattr ( struct dentry * dentry , struct dentry * upperdentry ,
const char * name , const void * value , size_t size ,
int xerr )
{
int err ;
struct ovl_fs * ofs = dentry - > d_sb - > s_fs_info ;
if ( ofs - > noxattr )
return xerr ;
err = ovl_do_setxattr ( upperdentry , name , value , size , 0 ) ;
if ( err = = - EOPNOTSUPP ) {
pr_warn ( " overlayfs: cannot set %s xattr on upper \n " , name ) ;
ofs - > noxattr = true ;
return xerr ;
}
return err ;
}
2017-05-24 15:29:33 +03:00
int ovl_set_impure ( struct dentry * dentry , struct dentry * upperdentry )
{
int err ;
2017-07-04 23:03:16 +03:00
if ( ovl_test_flag ( OVL_IMPURE , d_inode ( dentry ) ) )
2017-05-24 15:29:33 +03:00
return 0 ;
/*
* Do not fail when upper doesn ' t support xattrs .
* Upper inodes won ' t have origin nor redirect xattr anyway .
*/
err = ovl_check_setxattr ( dentry , upperdentry , OVL_XATTR_IMPURE ,
" y " , 1 , 0 ) ;
if ( ! err )
2017-07-04 23:03:16 +03:00
ovl_set_flag ( OVL_IMPURE , d_inode ( dentry ) ) ;
2017-05-24 15:29:33 +03:00
return err ;
}
2017-07-04 23:03:16 +03:00
void ovl_set_flag ( unsigned long flag , struct inode * inode )
{
set_bit ( flag , & OVL_I ( inode ) - > flags ) ;
}
bool ovl_test_flag ( unsigned long flag , struct inode * inode )
{
return test_bit ( flag , & OVL_I ( inode ) - > flags ) ;
}
2017-06-21 15:28:32 +03:00
/**
* Caller must hold a reference to inode to prevent it from being freed while
* it is marked inuse .
*/
bool ovl_inuse_trylock ( struct dentry * dentry )
{
struct inode * inode = d_inode ( dentry ) ;
bool locked = false ;
spin_lock ( & inode - > i_lock ) ;
if ( ! ( inode - > i_state & I_OVL_INUSE ) ) {
inode - > i_state | = I_OVL_INUSE ;
locked = true ;
}
spin_unlock ( & inode - > i_lock ) ;
return locked ;
}
void ovl_inuse_unlock ( struct dentry * dentry )
{
if ( dentry ) {
struct inode * inode = d_inode ( dentry ) ;
spin_lock ( & inode - > i_lock ) ;
WARN_ON ( ! ( inode - > i_state & I_OVL_INUSE ) ) ;
inode - > i_state & = ~ I_OVL_INUSE ;
spin_unlock ( & inode - > i_lock ) ;
}
}