2019-05-31 11:09:56 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2006-01-16 19:50:04 +03:00
/*
* Copyright ( C ) Sistina Software , Inc . 1997 - 2003 All rights reserved .
2006-05-18 23:09:15 +04:00
* Copyright ( C ) 2004 - 2006 Red Hat , Inc . All rights reserved .
2006-01-16 19:50:04 +03:00
*/
# include <linux/sched.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/completion.h>
# include <linux/buffer_head.h>
2009-10-02 14:50:54 +04:00
# include <linux/xattr.h>
2006-01-16 19:50:04 +03:00
# include <linux/posix_acl.h>
# include <linux/posix_acl_xattr.h>
2006-02-28 01:23:27 +03:00
# include <linux/gfs2_ondisk.h>
2006-01-16 19:50:04 +03:00
# include "gfs2.h"
2006-02-28 01:23:27 +03:00
# include "incore.h"
2006-01-16 19:50:04 +03:00
# include "acl.h"
2009-08-26 21:51:04 +04:00
# include "xattr.h"
2006-01-16 19:50:04 +03:00
# include "glock.h"
# include "inode.h"
# include "meta_io.h"
2016-05-13 04:59:17 +03:00
# include "rgrp.h"
2006-01-16 19:50:04 +03:00
# include "trans.h"
2006-02-28 01:23:27 +03:00
# include "util.h"
2006-01-16 19:50:04 +03:00
2009-10-02 15:00:00 +04:00
static const char * gfs2_acl_name ( int type )
2006-01-16 19:50:04 +03:00
{
2009-10-02 15:00:00 +04:00
switch ( type ) {
case ACL_TYPE_ACCESS :
2015-12-02 16:44:35 +03:00
return XATTR_POSIX_ACL_ACCESS ;
2009-10-02 15:00:00 +04:00
case ACL_TYPE_DEFAULT :
2015-12-02 16:44:35 +03:00
return XATTR_POSIX_ACL_DEFAULT ;
2009-10-02 15:00:00 +04:00
}
return NULL ;
}
2006-01-16 19:50:04 +03:00
2016-05-13 04:59:17 +03:00
static struct posix_acl * __gfs2_get_acl ( struct inode * inode , int type )
2009-10-02 15:00:00 +04:00
{
2011-11-23 17:31:51 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
2009-10-02 15:00:00 +04:00
struct posix_acl * acl ;
const char * name ;
char * data ;
int len ;
2009-08-26 21:41:32 +04:00
2008-11-03 17:28:42 +03:00
if ( ! ip - > i_eattr )
2009-10-02 15:00:00 +04:00
return NULL ;
2006-01-16 19:50:04 +03:00
2009-10-02 15:00:00 +04:00
name = gfs2_acl_name ( type ) ;
len = gfs2_xattr_acl_get ( ip , name , & data ) ;
2016-05-13 04:59:17 +03:00
if ( len < = 0 )
2009-10-02 15:00:00 +04:00
return ERR_PTR ( len ) ;
2012-09-11 07:17:44 +04:00
acl = posix_acl_from_xattr ( & init_user_ns , data , len ) ;
2009-10-02 15:00:00 +04:00
kfree ( data ) ;
return acl ;
2006-01-16 19:50:04 +03:00
}
2016-05-13 04:59:17 +03:00
struct posix_acl * gfs2_get_acl ( struct inode * inode , int type )
{
struct gfs2_inode * ip = GFS2_I ( inode ) ;
struct gfs2_holder gh ;
bool need_unlock = false ;
struct posix_acl * acl ;
if ( ! gfs2_glock_is_locked_by_me ( ip - > i_gl ) ) {
int ret = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_SHARED ,
LM_FLAG_ANY , & gh ) ;
if ( ret )
return ERR_PTR ( ret ) ;
need_unlock = true ;
}
acl = __gfs2_get_acl ( inode , type ) ;
if ( need_unlock )
gfs2_glock_dq_uninit ( & gh ) ;
return acl ;
}
int __gfs2_set_acl ( struct inode * inode , struct posix_acl * acl , int type )
2006-01-16 19:50:04 +03:00
{
int error ;
2018-06-22 04:51:43 +03:00
size_t len ;
2009-10-02 15:00:00 +04:00
char * data ;
const char * name = gfs2_acl_name ( type ) ;
2013-12-20 17:16:52 +04:00
if ( acl ) {
2018-06-22 04:51:43 +03:00
len = posix_acl_xattr_size ( acl - > a_count ) ;
2013-12-20 17:16:52 +04:00
data = kmalloc ( len , GFP_NOFS ) ;
if ( data = = NULL )
return - ENOMEM ;
error = posix_acl_to_xattr ( & init_user_ns , acl , data , len ) ;
if ( error < 0 )
goto out ;
} else {
data = NULL ;
len = 0 ;
2009-09-29 19:26:23 +04:00
}
2013-12-20 17:16:52 +04:00
error = __gfs2_xattr_set ( inode , name , data , len , 0 , GFS2_EATYPE_SYS ) ;
if ( error )
goto out ;
2015-02-13 21:16:37 +03:00
set_cached_acl ( inode , type , acl ) ;
2009-10-02 14:50:54 +04:00
out :
2013-12-20 17:16:52 +04:00
kfree ( data ) ;
2009-10-02 14:50:54 +04:00
return error ;
}
2016-05-13 04:59:17 +03:00
int gfs2_set_acl ( struct inode * inode , struct posix_acl * acl , int type )
{
struct gfs2_inode * ip = GFS2_I ( inode ) ;
struct gfs2_holder gh ;
bool need_unlock = false ;
int ret ;
2017-08-31 15:53:15 +03:00
umode_t mode ;
2016-05-13 04:59:17 +03:00
2017-07-19 18:56:42 +03:00
if ( acl & & acl - > a_count > GFS2_ACL_MAX_ENTRIES ( GFS2_SB ( inode ) ) )
return - E2BIG ;
2016-05-13 04:59:17 +03:00
ret = gfs2_rsqa_alloc ( ip ) ;
if ( ret )
return ret ;
if ( ! gfs2_glock_is_locked_by_me ( ip - > i_gl ) ) {
ret = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_EXCLUSIVE , 0 , & gh ) ;
if ( ret )
return ret ;
need_unlock = true ;
}
2017-07-19 18:56:42 +03:00
2017-08-31 15:53:15 +03:00
mode = inode - > i_mode ;
if ( type = = ACL_TYPE_ACCESS & & acl ) {
ret = posix_acl_update_mode ( inode , & mode , & acl ) ;
2017-07-19 18:56:42 +03:00
if ( ret )
goto unlock ;
}
2016-05-13 04:59:17 +03:00
ret = __gfs2_set_acl ( inode , acl , type ) ;
2017-08-31 15:53:15 +03:00
if ( ! ret & & mode ! = inode - > i_mode ) {
2017-09-25 16:37:15 +03:00
inode - > i_ctime = current_time ( inode ) ;
2017-08-31 15:53:15 +03:00
inode - > i_mode = mode ;
mark_inode_dirty ( inode ) ;
}
2017-07-19 18:56:42 +03:00
unlock :
2016-05-13 04:59:17 +03:00
if ( need_unlock )
gfs2_glock_dq_uninit ( & gh ) ;
return ret ;
}