2015-07-17 17:38:12 +03:00
/*
* ( C ) 2001 Clemson University and The University of Chicago
*
* See COPYING in top - level directory .
*/
# include "protocol.h"
2015-12-04 20:56:14 +03:00
# include "orangefs-kernel.h"
# include "orangefs-bufmap.h"
2015-07-17 17:38:12 +03:00
# include <linux/posix_acl_xattr.h>
# include <linux/fs_struct.h>
2015-11-24 23:12:14 +03:00
struct posix_acl * orangefs_get_acl ( struct inode * inode , int type )
2015-07-17 17:38:12 +03:00
{
struct posix_acl * acl ;
int ret ;
char * key = NULL , * value = NULL ;
switch ( type ) {
case ACL_TYPE_ACCESS :
2015-11-24 23:12:14 +03:00
key = ORANGEFS_XATTR_NAME_ACL_ACCESS ;
2015-07-17 17:38:12 +03:00
break ;
case ACL_TYPE_DEFAULT :
2015-11-24 23:12:14 +03:00
key = ORANGEFS_XATTR_NAME_ACL_DEFAULT ;
2015-07-17 17:38:12 +03:00
break ;
default :
2015-11-24 23:12:14 +03:00
gossip_err ( " orangefs_get_acl: bogus value of type %d \n " , type ) ;
2015-07-17 17:38:12 +03:00
return ERR_PTR ( - EINVAL ) ;
}
/*
* Rather than incurring a network call just to determine the exact
* length of the attribute , I just allocate a max length to save on
* the network call . Conceivably , we could pass NULL to
2015-11-24 23:12:14 +03:00
* orangefs_inode_getxattr ( ) to probe the length of the value , but
2015-07-17 17:38:12 +03:00
* I don ' t do that for now .
*/
2015-11-24 23:12:14 +03:00
value = kmalloc ( ORANGEFS_MAX_XATTR_VALUELEN , GFP_KERNEL ) ;
2015-07-17 17:38:12 +03:00
if ( value = = NULL )
return ERR_PTR ( - ENOMEM ) ;
gossip_debug ( GOSSIP_ACL_DEBUG ,
" inode %pU, key %s, type %d \n " ,
get_khandle_from_ino ( inode ) ,
key ,
type ) ;
2015-11-24 23:12:14 +03:00
ret = orangefs_inode_getxattr ( inode ,
2015-07-17 17:38:12 +03:00
" " ,
key ,
value ,
2015-11-24 23:12:14 +03:00
ORANGEFS_MAX_XATTR_VALUELEN ) ;
2015-07-17 17:38:12 +03:00
/* if the key exists, convert it to an in-memory rep */
if ( ret > 0 ) {
acl = posix_acl_from_xattr ( & init_user_ns , value , ret ) ;
} else if ( ret = = - ENODATA | | ret = = - ENOSYS ) {
acl = NULL ;
} else {
gossip_err ( " inode %pU retrieving acl's failed with error %d \n " ,
get_khandle_from_ino ( inode ) ,
ret ) ;
acl = ERR_PTR ( ret ) ;
}
/* kfree(NULL) is safe, so don't worry if value ever got used */
kfree ( value ) ;
return acl ;
}
2015-11-24 23:12:14 +03:00
int orangefs_set_acl ( struct inode * inode , struct posix_acl * acl , int type )
2015-07-17 17:38:12 +03:00
{
2015-11-24 23:12:14 +03:00
struct orangefs_inode_s * orangefs_inode = ORANGEFS_I ( inode ) ;
2015-07-17 17:38:12 +03:00
int error = 0 ;
void * value = NULL ;
size_t size = 0 ;
const char * name = NULL ;
switch ( type ) {
case ACL_TYPE_ACCESS :
2015-11-24 23:12:14 +03:00
name = ORANGEFS_XATTR_NAME_ACL_ACCESS ;
2015-07-17 17:38:12 +03:00
if ( acl ) {
umode_t mode = inode - > i_mode ;
/*
* can we represent this with the traditional file
* mode permission bits ?
*/
error = posix_acl_equiv_mode ( acl , & mode ) ;
if ( error < 0 ) {
gossip_err ( " %s: posix_acl_equiv_mode err: %d \n " ,
__func__ ,
error ) ;
return error ;
}
if ( inode - > i_mode ! = mode )
2015-11-24 23:12:14 +03:00
SetModeFlag ( orangefs_inode ) ;
2015-07-17 17:38:12 +03:00
inode - > i_mode = mode ;
mark_inode_dirty_sync ( inode ) ;
if ( error = = 0 )
acl = NULL ;
}
break ;
case ACL_TYPE_DEFAULT :
2015-11-24 23:12:14 +03:00
name = ORANGEFS_XATTR_NAME_ACL_DEFAULT ;
2015-07-17 17:38:12 +03:00
break ;
default :
gossip_err ( " %s: invalid type %d! \n " , __func__ , type ) ;
return - EINVAL ;
}
gossip_debug ( GOSSIP_ACL_DEBUG ,
" %s: inode %pU, key %s type %d \n " ,
__func__ , get_khandle_from_ino ( inode ) ,
name ,
type ) ;
if ( acl ) {
size = posix_acl_xattr_size ( acl - > a_count ) ;
value = kmalloc ( size , GFP_KERNEL ) ;
if ( ! value )
return - ENOMEM ;
error = posix_acl_to_xattr ( & init_user_ns , acl , value , size ) ;
if ( error < 0 )
goto out ;
}
gossip_debug ( GOSSIP_ACL_DEBUG ,
" %s: name %s, value %p, size %zd, acl %p \n " ,
__func__ , name , value , size , acl ) ;
/*
* Go ahead and set the extended attribute now . NOTE : Suppose acl
* was NULL , then value will be NULL and size will be 0 and that
* will xlate to a removexattr . However , we don ' t want removexattr
* complain if attributes does not exist .
*/
2015-11-24 23:12:14 +03:00
error = orangefs_inode_setxattr ( inode , " " , name , value , size , 0 ) ;
2015-07-17 17:38:12 +03:00
out :
kfree ( value ) ;
if ( ! error )
set_cached_acl ( inode , type , acl ) ;
return error ;
}
2015-11-24 23:12:14 +03:00
int orangefs_init_acl ( struct inode * inode , struct inode * dir )
2015-07-17 17:38:12 +03:00
{
2015-11-24 23:12:14 +03:00
struct orangefs_inode_s * orangefs_inode = ORANGEFS_I ( inode ) ;
2015-07-17 17:38:12 +03:00
struct posix_acl * default_acl , * acl ;
umode_t mode = inode - > i_mode ;
int error = 0 ;
2015-11-24 23:12:14 +03:00
ClearModeFlag ( orangefs_inode ) ;
2015-07-17 17:38:12 +03:00
error = posix_acl_create ( dir , & mode , & default_acl , & acl ) ;
if ( error )
return error ;
if ( default_acl ) {
2015-11-24 23:12:14 +03:00
error = orangefs_set_acl ( inode , default_acl , ACL_TYPE_DEFAULT ) ;
2015-07-17 17:38:12 +03:00
posix_acl_release ( default_acl ) ;
}
if ( acl ) {
if ( ! error )
2015-11-24 23:12:14 +03:00
error = orangefs_set_acl ( inode , acl , ACL_TYPE_ACCESS ) ;
2015-07-17 17:38:12 +03:00
posix_acl_release ( acl ) ;
}
/* If mode of the inode was changed, then do a forcible ->setattr */
if ( mode ! = inode - > i_mode ) {
2015-11-24 23:12:14 +03:00
SetModeFlag ( orangefs_inode ) ;
2015-07-17 17:38:12 +03:00
inode - > i_mode = mode ;
2015-11-24 23:12:14 +03:00
orangefs_flush_inode ( inode ) ;
2015-07-17 17:38:12 +03:00
}
return error ;
}