xref: /openbmc/linux/fs/reiserfs/xattr_acl.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
216f7e0feSRandy Dunlap #include <linux/capability.h>
31da177e4SLinus Torvalds #include <linux/fs.h>
41da177e4SLinus Torvalds #include <linux/posix_acl.h>
5f466c6fdSAl Viro #include "reiserfs.h"
61da177e4SLinus Torvalds #include <linux/errno.h>
71da177e4SLinus Torvalds #include <linux/pagemap.h>
81da177e4SLinus Torvalds #include <linux/xattr.h>
95a0e3ad6STejun Heo #include <linux/slab.h>
109a59f452SChristoph Hellwig #include <linux/posix_acl_xattr.h>
11c45ac888SAl Viro #include "xattr.h"
12a3063ab8SAl Viro #include "acl.h"
1317093991SFabian Frederick #include <linux/uaccess.h>
141da177e4SLinus Torvalds 
1547f70d08SChristoph Hellwig static int __reiserfs_set_acl(struct reiserfs_transaction_handle *th,
160ab2621eSJeff Mahoney 			    struct inode *inode, int type,
17bd4c625cSLinus Torvalds 			    struct posix_acl *acl);
181da177e4SLinus Torvalds 
1947f70d08SChristoph Hellwig 
2047f70d08SChristoph Hellwig int
reiserfs_set_acl(struct mnt_idmap * idmap,struct dentry * dentry,struct posix_acl * acl,int type)2113e83a49SChristian Brauner reiserfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
22549c7297SChristian Brauner 		 struct posix_acl *acl, int type)
231da177e4SLinus Torvalds {
240ab2621eSJeff Mahoney 	int error, error2;
250ab2621eSJeff Mahoney 	struct reiserfs_transaction_handle th;
260ab2621eSJeff Mahoney 	size_t jcreate_blocks;
2747f70d08SChristoph Hellwig 	int size = acl ? posix_acl_xattr_size(acl->a_count) : 0;
28fcea8aedSErnesto A. Fernández 	int update_mode = 0;
29138060baSChristian Brauner 	struct inode *inode = d_inode(dentry);
30fcea8aedSErnesto A. Fernández 	umode_t mode = inode->i_mode;
311da177e4SLinus Torvalds 
32098297b2SJeff Mahoney 	/*
33098297b2SJeff Mahoney 	 * Pessimism: We can't assume that anything from the xattr root up
34098297b2SJeff Mahoney 	 * has been created.
35098297b2SJeff Mahoney 	 */
360ab2621eSJeff Mahoney 
370ab2621eSJeff Mahoney 	jcreate_blocks = reiserfs_xattr_jcreate_nblocks(inode) +
380ab2621eSJeff Mahoney 			 reiserfs_xattr_nblocks(inode, size) * 2;
390ab2621eSJeff Mahoney 
400ab2621eSJeff Mahoney 	reiserfs_write_lock(inode->i_sb);
410ab2621eSJeff Mahoney 	error = journal_begin(&th, inode->i_sb, jcreate_blocks);
424c05141dSJeff Mahoney 	reiserfs_write_unlock(inode->i_sb);
430ab2621eSJeff Mahoney 	if (error == 0) {
446883cd7fSJan Kara 		if (type == ACL_TYPE_ACCESS && acl) {
45700b7940SChristian Brauner 			error = posix_acl_update_mode(&nop_mnt_idmap, inode,
46e65ce2a5SChristian Brauner 						      &mode, &acl);
476883cd7fSJan Kara 			if (error)
486883cd7fSJan Kara 				goto unlock;
49fcea8aedSErnesto A. Fernández 			update_mode = 1;
506883cd7fSJan Kara 		}
5147f70d08SChristoph Hellwig 		error = __reiserfs_set_acl(&th, inode, type, acl);
52fcea8aedSErnesto A. Fernández 		if (!error && update_mode)
53fcea8aedSErnesto A. Fernández 			inode->i_mode = mode;
546883cd7fSJan Kara unlock:
554c05141dSJeff Mahoney 		reiserfs_write_lock(inode->i_sb);
5658d85426SJeff Mahoney 		error2 = journal_end(&th);
574c05141dSJeff Mahoney 		reiserfs_write_unlock(inode->i_sb);
580ab2621eSJeff Mahoney 		if (error2)
590ab2621eSJeff Mahoney 			error = error2;
600ab2621eSJeff Mahoney 	}
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds 	return error;
631da177e4SLinus Torvalds }
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds /*
661da177e4SLinus Torvalds  * Convert from filesystem to in-memory representation.
671da177e4SLinus Torvalds  */
reiserfs_posix_acl_from_disk(const void * value,size_t size)689dad943aSChristoph Hellwig static struct posix_acl *reiserfs_posix_acl_from_disk(const void *value, size_t size)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds 	const char *end = (char *)value + size;
711da177e4SLinus Torvalds 	int n, count;
721da177e4SLinus Torvalds 	struct posix_acl *acl;
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 	if (!value)
751da177e4SLinus Torvalds 		return NULL;
761da177e4SLinus Torvalds 	if (size < sizeof(reiserfs_acl_header))
771da177e4SLinus Torvalds 		return ERR_PTR(-EINVAL);
781da177e4SLinus Torvalds 	if (((reiserfs_acl_header *) value)->a_version !=
791da177e4SLinus Torvalds 	    cpu_to_le32(REISERFS_ACL_VERSION))
801da177e4SLinus Torvalds 		return ERR_PTR(-EINVAL);
811da177e4SLinus Torvalds 	value = (char *)value + sizeof(reiserfs_acl_header);
821da177e4SLinus Torvalds 	count = reiserfs_acl_count(size);
831da177e4SLinus Torvalds 	if (count < 0)
841da177e4SLinus Torvalds 		return ERR_PTR(-EINVAL);
851da177e4SLinus Torvalds 	if (count == 0)
861da177e4SLinus Torvalds 		return NULL;
871da177e4SLinus Torvalds 	acl = posix_acl_alloc(count, GFP_NOFS);
881da177e4SLinus Torvalds 	if (!acl)
891da177e4SLinus Torvalds 		return ERR_PTR(-ENOMEM);
901da177e4SLinus Torvalds 	for (n = 0; n < count; n++) {
91bd4c625cSLinus Torvalds 		reiserfs_acl_entry *entry = (reiserfs_acl_entry *) value;
921da177e4SLinus Torvalds 		if ((char *)value + sizeof(reiserfs_acl_entry_short) > end)
931da177e4SLinus Torvalds 			goto fail;
941da177e4SLinus Torvalds 		acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
951da177e4SLinus Torvalds 		acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
961da177e4SLinus Torvalds 		switch (acl->a_entries[n].e_tag) {
971da177e4SLinus Torvalds 		case ACL_USER_OBJ:
981da177e4SLinus Torvalds 		case ACL_GROUP_OBJ:
991da177e4SLinus Torvalds 		case ACL_MASK:
1001da177e4SLinus Torvalds 		case ACL_OTHER:
1011da177e4SLinus Torvalds 			value = (char *)value +
1021da177e4SLinus Torvalds 			    sizeof(reiserfs_acl_entry_short);
1031da177e4SLinus Torvalds 			break;
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 		case ACL_USER:
106df814654SEric W. Biederman 			value = (char *)value + sizeof(reiserfs_acl_entry);
107df814654SEric W. Biederman 			if ((char *)value > end)
108df814654SEric W. Biederman 				goto fail;
109df814654SEric W. Biederman 			acl->a_entries[n].e_uid =
110df814654SEric W. Biederman 				make_kuid(&init_user_ns,
111df814654SEric W. Biederman 					  le32_to_cpu(entry->e_id));
112df814654SEric W. Biederman 			break;
1131da177e4SLinus Torvalds 		case ACL_GROUP:
1141da177e4SLinus Torvalds 			value = (char *)value + sizeof(reiserfs_acl_entry);
1151da177e4SLinus Torvalds 			if ((char *)value > end)
1161da177e4SLinus Torvalds 				goto fail;
117df814654SEric W. Biederman 			acl->a_entries[n].e_gid =
118df814654SEric W. Biederman 				make_kgid(&init_user_ns,
119df814654SEric W. Biederman 					  le32_to_cpu(entry->e_id));
1201da177e4SLinus Torvalds 			break;
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds 		default:
1231da177e4SLinus Torvalds 			goto fail;
1241da177e4SLinus Torvalds 		}
1251da177e4SLinus Torvalds 	}
1261da177e4SLinus Torvalds 	if (value != end)
1271da177e4SLinus Torvalds 		goto fail;
1281da177e4SLinus Torvalds 	return acl;
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds fail:
1311da177e4SLinus Torvalds 	posix_acl_release(acl);
1321da177e4SLinus Torvalds 	return ERR_PTR(-EINVAL);
1331da177e4SLinus Torvalds }
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds /*
1361da177e4SLinus Torvalds  * Convert from in-memory to filesystem representation.
1371da177e4SLinus Torvalds  */
reiserfs_posix_acl_to_disk(const struct posix_acl * acl,size_t * size)1389dad943aSChristoph Hellwig static void *reiserfs_posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
1391da177e4SLinus Torvalds {
1401da177e4SLinus Torvalds 	reiserfs_acl_header *ext_acl;
1411da177e4SLinus Torvalds 	char *e;
1421da177e4SLinus Torvalds 	int n;
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	*size = reiserfs_acl_size(acl->a_count);
1455cbded58SRobert P. J. Day 	ext_acl = kmalloc(sizeof(reiserfs_acl_header) +
146bd4c625cSLinus Torvalds 						  acl->a_count *
147bd4c625cSLinus Torvalds 						  sizeof(reiserfs_acl_entry),
148bd4c625cSLinus Torvalds 						  GFP_NOFS);
1491da177e4SLinus Torvalds 	if (!ext_acl)
1501da177e4SLinus Torvalds 		return ERR_PTR(-ENOMEM);
1511da177e4SLinus Torvalds 	ext_acl->a_version = cpu_to_le32(REISERFS_ACL_VERSION);
1521da177e4SLinus Torvalds 	e = (char *)ext_acl + sizeof(reiserfs_acl_header);
1531da177e4SLinus Torvalds 	for (n = 0; n < acl->a_count; n++) {
154df814654SEric W. Biederman 		const struct posix_acl_entry *acl_e = &acl->a_entries[n];
1551da177e4SLinus Torvalds 		reiserfs_acl_entry *entry = (reiserfs_acl_entry *) e;
1561da177e4SLinus Torvalds 		entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
1571da177e4SLinus Torvalds 		entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
1581da177e4SLinus Torvalds 		switch (acl->a_entries[n].e_tag) {
1591da177e4SLinus Torvalds 		case ACL_USER:
160df814654SEric W. Biederman 			entry->e_id = cpu_to_le32(
161df814654SEric W. Biederman 				from_kuid(&init_user_ns, acl_e->e_uid));
162df814654SEric W. Biederman 			e += sizeof(reiserfs_acl_entry);
163df814654SEric W. Biederman 			break;
1641da177e4SLinus Torvalds 		case ACL_GROUP:
165df814654SEric W. Biederman 			entry->e_id = cpu_to_le32(
166df814654SEric W. Biederman 				from_kgid(&init_user_ns, acl_e->e_gid));
1671da177e4SLinus Torvalds 			e += sizeof(reiserfs_acl_entry);
1681da177e4SLinus Torvalds 			break;
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds 		case ACL_USER_OBJ:
1711da177e4SLinus Torvalds 		case ACL_GROUP_OBJ:
1721da177e4SLinus Torvalds 		case ACL_MASK:
1731da177e4SLinus Torvalds 		case ACL_OTHER:
1741da177e4SLinus Torvalds 			e += sizeof(reiserfs_acl_entry_short);
1751da177e4SLinus Torvalds 			break;
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds 		default:
1781da177e4SLinus Torvalds 			goto fail;
1791da177e4SLinus Torvalds 		}
1801da177e4SLinus Torvalds 	}
1811da177e4SLinus Torvalds 	return (char *)ext_acl;
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds fail:
1841da177e4SLinus Torvalds 	kfree(ext_acl);
1851da177e4SLinus Torvalds 	return ERR_PTR(-EINVAL);
1861da177e4SLinus Torvalds }
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds /*
1891da177e4SLinus Torvalds  * Inode operation get_posix_acl().
1901da177e4SLinus Torvalds  *
1911b1dcc1bSJes Sorensen  * inode->i_mutex: down
1921da177e4SLinus Torvalds  * BKL held [before 2.5.x]
1931da177e4SLinus Torvalds  */
reiserfs_get_acl(struct inode * inode,int type,bool rcu)1940cad6246SMiklos Szeredi struct posix_acl *reiserfs_get_acl(struct inode *inode, int type, bool rcu)
1951da177e4SLinus Torvalds {
1961da177e4SLinus Torvalds 	char *name, *value;
197073aaa1bSAl Viro 	struct posix_acl *acl;
1983cdc409cSAdrian Bunk 	int size;
1991da177e4SLinus Torvalds 	int retval;
2001da177e4SLinus Torvalds 
2010cad6246SMiklos Szeredi 	if (rcu)
2020cad6246SMiklos Szeredi 		return ERR_PTR(-ECHILD);
2030cad6246SMiklos Szeredi 
2041da177e4SLinus Torvalds 	switch (type) {
2051da177e4SLinus Torvalds 	case ACL_TYPE_ACCESS:
20697d79299SAndreas Gruenbacher 		name = XATTR_NAME_POSIX_ACL_ACCESS;
2071da177e4SLinus Torvalds 		break;
2081da177e4SLinus Torvalds 	case ACL_TYPE_DEFAULT:
20997d79299SAndreas Gruenbacher 		name = XATTR_NAME_POSIX_ACL_DEFAULT;
2101da177e4SLinus Torvalds 		break;
2111da177e4SLinus Torvalds 	default:
212073aaa1bSAl Viro 		BUG();
2131da177e4SLinus Torvalds 	}
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds 	size = reiserfs_xattr_get(inode, name, NULL, 0);
2163cdc409cSAdrian Bunk 	if (size < 0) {
217b8a7a3a6SAndreas Gruenbacher 		if (size == -ENODATA || size == -ENOSYS)
2181da177e4SLinus Torvalds 			return NULL;
2191da177e4SLinus Torvalds 		return ERR_PTR(size);
2201da177e4SLinus Torvalds 	}
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 	value = kmalloc(size, GFP_NOFS);
2231da177e4SLinus Torvalds 	if (!value)
2241da177e4SLinus Torvalds 		return ERR_PTR(-ENOMEM);
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds 	retval = reiserfs_xattr_get(inode, name, value, size);
2271da177e4SLinus Torvalds 	if (retval == -ENODATA || retval == -ENOSYS) {
228098297b2SJeff Mahoney 		/*
229098297b2SJeff Mahoney 		 * This shouldn't actually happen as it should have
230098297b2SJeff Mahoney 		 * been caught above.. but just in case
231098297b2SJeff Mahoney 		 */
2321da177e4SLinus Torvalds 		acl = NULL;
2331da177e4SLinus Torvalds 	} else if (retval < 0) {
2341da177e4SLinus Torvalds 		acl = ERR_PTR(retval);
2351da177e4SLinus Torvalds 	} else {
2369dad943aSChristoph Hellwig 		acl = reiserfs_posix_acl_from_disk(value, retval);
2371da177e4SLinus Torvalds 	}
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 	kfree(value);
2401da177e4SLinus Torvalds 	return acl;
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds /*
2441da177e4SLinus Torvalds  * Inode operation set_posix_acl().
2451da177e4SLinus Torvalds  *
2461b1dcc1bSJes Sorensen  * inode->i_mutex: down
2471da177e4SLinus Torvalds  * BKL held [before 2.5.x]
2481da177e4SLinus Torvalds  */
2491da177e4SLinus Torvalds static int
__reiserfs_set_acl(struct reiserfs_transaction_handle * th,struct inode * inode,int type,struct posix_acl * acl)25047f70d08SChristoph Hellwig __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
2510ab2621eSJeff Mahoney 		 int type, struct posix_acl *acl)
2521da177e4SLinus Torvalds {
2531da177e4SLinus Torvalds 	char *name;
2541da177e4SLinus Torvalds 	void *value = NULL;
25548b32a35SJeff Mahoney 	size_t size = 0;
2561da177e4SLinus Torvalds 	int error;
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	switch (type) {
2591da177e4SLinus Torvalds 	case ACL_TYPE_ACCESS:
26097d79299SAndreas Gruenbacher 		name = XATTR_NAME_POSIX_ACL_ACCESS;
2611da177e4SLinus Torvalds 		break;
2621da177e4SLinus Torvalds 	case ACL_TYPE_DEFAULT:
26397d79299SAndreas Gruenbacher 		name = XATTR_NAME_POSIX_ACL_DEFAULT;
2641da177e4SLinus Torvalds 		if (!S_ISDIR(inode->i_mode))
2651da177e4SLinus Torvalds 			return acl ? -EACCES : 0;
2661da177e4SLinus Torvalds 		break;
2671da177e4SLinus Torvalds 	default:
2681da177e4SLinus Torvalds 		return -EINVAL;
2691da177e4SLinus Torvalds 	}
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 	if (acl) {
2729dad943aSChristoph Hellwig 		value = reiserfs_posix_acl_to_disk(acl, &size);
2731da177e4SLinus Torvalds 		if (IS_ERR(value))
2741da177e4SLinus Torvalds 			return (int)PTR_ERR(value);
27548b32a35SJeff Mahoney 	}
27648b32a35SJeff Mahoney 
2770ab2621eSJeff Mahoney 	error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0);
27848b32a35SJeff Mahoney 
27948b32a35SJeff Mahoney 	/*
28048b32a35SJeff Mahoney 	 * Ensure that the inode gets dirtied if we're only using
28148b32a35SJeff Mahoney 	 * the mode bits and an old ACL didn't exist. We don't need
28248b32a35SJeff Mahoney 	 * to check if the inode is hashed here since we won't get
28348b32a35SJeff Mahoney 	 * called by reiserfs_inherit_default_acl().
2841da177e4SLinus Torvalds 	 */
28548b32a35SJeff Mahoney 	if (error == -ENODATA) {
2861da177e4SLinus Torvalds 		error = 0;
28748b32a35SJeff Mahoney 		if (type == ACL_TYPE_ACCESS) {
288*ae834901SJeff Layton 			inode_set_ctime_current(inode);
28948b32a35SJeff Mahoney 			mark_inode_dirty(inode);
2901da177e4SLinus Torvalds 		}
2911da177e4SLinus Torvalds 	}
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 	kfree(value);
2941da177e4SLinus Torvalds 
295d984561bSJeff Mahoney 	if (!error)
296073aaa1bSAl Viro 		set_cached_acl(inode, type, acl);
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 	return error;
2991da177e4SLinus Torvalds }
3001da177e4SLinus Torvalds 
301098297b2SJeff Mahoney /*
302098297b2SJeff Mahoney  * dir->i_mutex: locked,
303098297b2SJeff Mahoney  * inode is new and not released into the wild yet
304098297b2SJeff Mahoney  */
3051da177e4SLinus Torvalds int
reiserfs_inherit_default_acl(struct reiserfs_transaction_handle * th,struct inode * dir,struct dentry * dentry,struct inode * inode)3060ab2621eSJeff Mahoney reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
3070ab2621eSJeff Mahoney 			     struct inode *dir, struct dentry *dentry,
308bd4c625cSLinus Torvalds 			     struct inode *inode)
3091da177e4SLinus Torvalds {
31047f70d08SChristoph Hellwig 	struct posix_acl *default_acl, *acl;
3111da177e4SLinus Torvalds 	int err = 0;
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds 	/* ACLs only get applied to files and directories */
3141da177e4SLinus Torvalds 	if (S_ISLNK(inode->i_mode))
3151da177e4SLinus Torvalds 		return 0;
3161da177e4SLinus Torvalds 
317098297b2SJeff Mahoney 	/*
318098297b2SJeff Mahoney 	 * ACLs can only be used on "new" objects, so if it's an old object
319098297b2SJeff Mahoney 	 * there is nothing to inherit from
320098297b2SJeff Mahoney 	 */
3211da177e4SLinus Torvalds 	if (get_inode_sd_version(dir) == STAT_DATA_V1)
3221da177e4SLinus Torvalds 		goto apply_umask;
3231da177e4SLinus Torvalds 
324098297b2SJeff Mahoney 	/*
325098297b2SJeff Mahoney 	 * Don't apply ACLs to objects in the .reiserfs_priv tree.. This
3261da177e4SLinus Torvalds 	 * would be useless since permissions are ignored, and a pain because
327098297b2SJeff Mahoney 	 * it introduces locking cycles
328098297b2SJeff Mahoney 	 */
32960e4cf67SJeff Mahoney 	if (IS_PRIVATE(inode))
3301da177e4SLinus Torvalds 		goto apply_umask;
3311da177e4SLinus Torvalds 
33247f70d08SChristoph Hellwig 	err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
3331da177e4SLinus Torvalds 	if (err)
334826cae2fSAl Viro 		return err;
3351da177e4SLinus Torvalds 
33647f70d08SChristoph Hellwig 	if (default_acl) {
33747f70d08SChristoph Hellwig 		err = __reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
33847f70d08SChristoph Hellwig 					 default_acl);
33947f70d08SChristoph Hellwig 		posix_acl_release(default_acl);
34047f70d08SChristoph Hellwig 	}
34147f70d08SChristoph Hellwig 	if (acl) {
34247f70d08SChristoph Hellwig 		if (!err)
34347f70d08SChristoph Hellwig 			err = __reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS,
34447f70d08SChristoph Hellwig 						 acl);
3451da177e4SLinus Torvalds 		posix_acl_release(acl);
34647f70d08SChristoph Hellwig 	}
34747f70d08SChristoph Hellwig 
34847f70d08SChristoph Hellwig 	return err;
34947f70d08SChristoph Hellwig 
3501da177e4SLinus Torvalds apply_umask:
3511da177e4SLinus Torvalds 	/* no ACL, apply umask */
352ce3b0f8dSAl Viro 	inode->i_mode &= ~current_umask();
3531da177e4SLinus Torvalds 	return err;
3541da177e4SLinus Torvalds }
3551da177e4SLinus Torvalds 
3560ab2621eSJeff Mahoney /* This is used to cache the default acl before a new object is created.
3570ab2621eSJeff Mahoney  * The biggest reason for this is to get an idea of how many blocks will
3580ab2621eSJeff Mahoney  * actually be required for the create operation if we must inherit an ACL.
3590ab2621eSJeff Mahoney  * An ACL write can add up to 3 object creations and an additional file write
3600ab2621eSJeff Mahoney  * so we'd prefer not to reserve that many blocks in the journal if we can.
3610ab2621eSJeff Mahoney  * It also has the advantage of not loading the ACL with a transaction open,
3620ab2621eSJeff Mahoney  * this may seem silly, but if the owner of the directory is doing the
3630ab2621eSJeff Mahoney  * creation, the ACL may not be loaded since the permissions wouldn't require
3640ab2621eSJeff Mahoney  * it.
3650ab2621eSJeff Mahoney  * We return the number of blocks required for the transaction.
3660ab2621eSJeff Mahoney  */
reiserfs_cache_default_acl(struct inode * inode)367bd4c625cSLinus Torvalds int reiserfs_cache_default_acl(struct inode *inode)
3681da177e4SLinus Torvalds {
3691da177e4SLinus Torvalds 	struct posix_acl *acl;
3700ab2621eSJeff Mahoney 	int nblocks = 0;
3710ab2621eSJeff Mahoney 
3720ab2621eSJeff Mahoney 	if (IS_PRIVATE(inode))
3730ab2621eSJeff Mahoney 		return 0;
3740ab2621eSJeff Mahoney 
375cac2f8b8SChristian Brauner 	acl = get_inode_acl(inode, ACL_TYPE_DEFAULT);
3760ab2621eSJeff Mahoney 
3770ab2621eSJeff Mahoney 	if (acl && !IS_ERR(acl)) {
3780ab2621eSJeff Mahoney 		int size = reiserfs_acl_size(acl->a_count);
3790ab2621eSJeff Mahoney 
3800ab2621eSJeff Mahoney 		/* Other xattrs can be created during inode creation. We don't
3810ab2621eSJeff Mahoney 		 * want to claim too many blocks, so we check to see if we
3829436fb4dSRandy Dunlap 		 * need to create the tree to the xattrs, and then we
3830ab2621eSJeff Mahoney 		 * just want two files. */
3840ab2621eSJeff Mahoney 		nblocks = reiserfs_xattr_jcreate_nblocks(inode);
3850ab2621eSJeff Mahoney 		nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
3860ab2621eSJeff Mahoney 
3870ab2621eSJeff Mahoney 		REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
3880ab2621eSJeff Mahoney 
3890ab2621eSJeff Mahoney 		/* We need to account for writes + bitmaps for two files */
3900ab2621eSJeff Mahoney 		nblocks += reiserfs_xattr_nblocks(inode, size) * 4;
3911da177e4SLinus Torvalds 		posix_acl_release(acl);
3921da177e4SLinus Torvalds 	}
3931da177e4SLinus Torvalds 
3940ab2621eSJeff Mahoney 	return nblocks;
3951da177e4SLinus Torvalds }
3961da177e4SLinus Torvalds 
3974c05141dSJeff Mahoney /*
3984c05141dSJeff Mahoney  * Called under i_mutex
3994c05141dSJeff Mahoney  */
reiserfs_acl_chmod(struct dentry * dentry)400138060baSChristian Brauner int reiserfs_acl_chmod(struct dentry *dentry)
4011da177e4SLinus Torvalds {
402138060baSChristian Brauner 	struct inode *inode = d_inode(dentry);
403138060baSChristian Brauner 
4044a857011SJeff Mahoney 	if (IS_PRIVATE(inode))
4054a857011SJeff Mahoney 		return 0;
4061da177e4SLinus Torvalds 	if (get_inode_sd_version(inode) == STAT_DATA_V1 ||
40747f70d08SChristoph Hellwig 	    !reiserfs_posixacl(inode->i_sb))
4081da177e4SLinus Torvalds 		return 0;
40947f70d08SChristoph Hellwig 
41013e83a49SChristian Brauner 	return posix_acl_chmod(&nop_mnt_idmap, dentry, inode->i_mode);
4111da177e4SLinus Torvalds }
412