Blame view

fs/ocfs2/acl.c 9.17 KB
1802d0bee   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
929fb014e   Tiger Yang   ocfs2: add POSIX ...
2
3
4
5
6
7
8
9
10
11
  /* -*- mode: c; c-basic-offset: 8; -*-
   * vim: noexpandtab sw=8 ts=8 sts=0:
   *
   * acl.c
   *
   * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
   *
   * CREDITS:
   * Lots of code in this file is copy from linux/fs/ext3/acl.c.
   * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
929fb014e   Tiger Yang   ocfs2: add POSIX ...
12
13
14
15
   */
  
  #include <linux/init.h>
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
16
  #include <linux/slab.h>
929fb014e   Tiger Yang   ocfs2: add POSIX ...
17
  #include <linux/string.h>
929fb014e   Tiger Yang   ocfs2: add POSIX ...
18
19
20
21
22
23
  #include <cluster/masklog.h>
  
  #include "ocfs2.h"
  #include "alloc.h"
  #include "dlmglue.h"
  #include "file.h"
fcefd25ac   Mark Fasheh   ocfs2: set i_mode...
24
25
  #include "inode.h"
  #include "journal.h"
929fb014e   Tiger Yang   ocfs2: add POSIX ...
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  #include "ocfs2_fs.h"
  
  #include "xattr.h"
  #include "acl.h"
  
  /*
   * Convert from xattr value to acl struct.
   */
  static struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size)
  {
  	int n, count;
  	struct posix_acl *acl;
  
  	if (!value)
  		return NULL;
  	if (size < sizeof(struct posix_acl_entry))
  		return ERR_PTR(-EINVAL);
  
  	count = size / sizeof(struct posix_acl_entry);
929fb014e   Tiger Yang   ocfs2: add POSIX ...
45
46
47
48
49
50
51
52
53
54
  
  	acl = posix_acl_alloc(count, GFP_NOFS);
  	if (!acl)
  		return ERR_PTR(-ENOMEM);
  	for (n = 0; n < count; n++) {
  		struct ocfs2_acl_entry *entry =
  			(struct ocfs2_acl_entry *)value;
  
  		acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
  		acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
9522751cd   Eric W. Biederman   ocfs2: Handle kui...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  		switch(acl->a_entries[n].e_tag) {
  		case ACL_USER:
  			acl->a_entries[n].e_uid =
  				make_kuid(&init_user_ns,
  					  le32_to_cpu(entry->e_id));
  			break;
  		case ACL_GROUP:
  			acl->a_entries[n].e_gid =
  				make_kgid(&init_user_ns,
  					  le32_to_cpu(entry->e_id));
  			break;
  		default:
  			break;
  		}
929fb014e   Tiger Yang   ocfs2: add POSIX ...
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  		value += sizeof(struct posix_acl_entry);
  
  	}
  	return acl;
  }
  
  /*
   * Convert acl struct to xattr value.
   */
  static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size)
  {
  	struct ocfs2_acl_entry *entry = NULL;
  	char *ocfs2_acl;
  	size_t n;
  
  	*size = acl->a_count * sizeof(struct posix_acl_entry);
  
  	ocfs2_acl = kmalloc(*size, GFP_NOFS);
  	if (!ocfs2_acl)
  		return ERR_PTR(-ENOMEM);
  
  	entry = (struct ocfs2_acl_entry *)ocfs2_acl;
  	for (n = 0; n < acl->a_count; n++, entry++) {
  		entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);
  		entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
9522751cd   Eric W. Biederman   ocfs2: Handle kui...
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  		switch(acl->a_entries[n].e_tag) {
  		case ACL_USER:
  			entry->e_id = cpu_to_le32(
  				from_kuid(&init_user_ns,
  					  acl->a_entries[n].e_uid));
  			break;
  		case ACL_GROUP:
  			entry->e_id = cpu_to_le32(
  				from_kgid(&init_user_ns,
  					  acl->a_entries[n].e_gid));
  			break;
  		default:
  			entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
  			break;
  		}
929fb014e   Tiger Yang   ocfs2: add POSIX ...
109
110
111
112
113
114
115
116
  	}
  	return ocfs2_acl;
  }
  
  static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode,
  					      int type,
  					      struct buffer_head *di_bh)
  {
929fb014e   Tiger Yang   ocfs2: add POSIX ...
117
118
119
120
  	int name_index;
  	char *value = NULL;
  	struct posix_acl *acl;
  	int retval;
929fb014e   Tiger Yang   ocfs2: add POSIX ...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  	switch (type) {
  	case ACL_TYPE_ACCESS:
  		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
  		break;
  	case ACL_TYPE_DEFAULT:
  		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
  		break;
  	default:
  		return ERR_PTR(-EINVAL);
  	}
  
  	retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, "", NULL, 0);
  	if (retval > 0) {
  		value = kmalloc(retval, GFP_NOFS);
  		if (!value)
  			return ERR_PTR(-ENOMEM);
  		retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index,
  						"", value, retval);
  	}
  
  	if (retval > 0)
  		acl = ocfs2_acl_from_xattr(value, retval);
  	else if (retval == -ENODATA || retval == 0)
  		acl = NULL;
  	else
  		acl = ERR_PTR(retval);
  
  	kfree(value);
  
  	return acl;
  }
929fb014e   Tiger Yang   ocfs2: add POSIX ...
152
  /*
fcefd25ac   Mark Fasheh   ocfs2: set i_mode...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
   * Helper function to set i_mode in memory and disk. Some call paths
   * will not have di_bh or a journal handle to pass, in which case it
   * will create it's own.
   */
  static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh,
  			      handle_t *handle, umode_t new_mode)
  {
  	int ret, commit_handle = 0;
  	struct ocfs2_dinode *di;
  
  	if (di_bh == NULL) {
  		ret = ocfs2_read_inode_block(inode, &di_bh);
  		if (ret) {
  			mlog_errno(ret);
  			goto out;
  		}
  	} else
  		get_bh(di_bh);
  
  	if (handle == NULL) {
  		handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb),
  					   OCFS2_INODE_UPDATE_CREDITS);
  		if (IS_ERR(handle)) {
  			ret = PTR_ERR(handle);
  			mlog_errno(ret);
  			goto out_brelse;
  		}
  
  		commit_handle = 1;
  	}
  
  	di = (struct ocfs2_dinode *)di_bh->b_data;
  	ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
  				      OCFS2_JOURNAL_ACCESS_WRITE);
  	if (ret) {
  		mlog_errno(ret);
  		goto out_commit;
  	}
  
  	inode->i_mode = new_mode;
078cd8279   Deepa Dinamani   fs: Replace CURRE...
193
  	inode->i_ctime = current_time(inode);
fcefd25ac   Mark Fasheh   ocfs2: set i_mode...
194
  	di->i_mode = cpu_to_le16(inode->i_mode);
12828061c   Tao Ma   ocfs2: update cti...
195
196
  	di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
  	di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
6fdb702d6   Darrick J. Wong   ocfs2: call ocfs2...
197
  	ocfs2_update_inode_fsync_trans(handle, inode, 0);
fcefd25ac   Mark Fasheh   ocfs2: set i_mode...
198
199
200
201
202
203
204
205
206
207
208
209
210
  
  	ocfs2_journal_dirty(handle, di_bh);
  
  out_commit:
  	if (commit_handle)
  		ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
  out_brelse:
  	brelse(di_bh);
  out:
  	return ret;
  }
  
  /*
929fb014e   Tiger Yang   ocfs2: add POSIX ...
211
212
   * Set the access or default ACL of an inode.
   */
01ffb56bc   Jan Kara   ocfs2: make ocfs2...
213
  static int ocfs2_set_acl(handle_t *handle,
929fb014e   Tiger Yang   ocfs2: add POSIX ...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  			 struct inode *inode,
  			 struct buffer_head *di_bh,
  			 int type,
  			 struct posix_acl *acl,
  			 struct ocfs2_alloc_context *meta_ac,
  			 struct ocfs2_alloc_context *data_ac)
  {
  	int name_index;
  	void *value = NULL;
  	size_t size = 0;
  	int ret;
  
  	if (S_ISLNK(inode->i_mode))
  		return -EOPNOTSUPP;
  
  	switch (type) {
  	case ACL_TYPE_ACCESS:
  		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
929fb014e   Tiger Yang   ocfs2: add POSIX ...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  		break;
  	case ACL_TYPE_DEFAULT:
  		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
  		if (!S_ISDIR(inode->i_mode))
  			return acl ? -EACCES : 0;
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	if (acl) {
  		value = ocfs2_acl_to_xattr(acl, &size);
  		if (IS_ERR(value))
  			return (int)PTR_ERR(value);
  	}
  
  	if (handle)
  		ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index,
  					     "", value, size, 0,
  					     meta_ac, data_ac);
  	else
  		ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0);
  
  	kfree(value);
504ec37df   Gang He   ocfs2: fix remoun...
256
257
  	if (!ret)
  		set_cached_acl(inode, type, acl);
929fb014e   Tiger Yang   ocfs2: add POSIX ...
258
259
260
  
  	return ret;
  }
702e5bc68   Christoph Hellwig   ocfs2: use generi...
261
262
  int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type)
  {
743b5f143   Tariq Saeed   ocfs2: take inode...
263
  	struct buffer_head *bh = NULL;
b891fa502   Eric Ren   ocfs2: fix deadlo...
264
265
  	int status, had_lock;
  	struct ocfs2_lock_holder oh;
743b5f143   Tariq Saeed   ocfs2: take inode...
266

b891fa502   Eric Ren   ocfs2: fix deadlo...
267
268
269
  	had_lock = ocfs2_inode_lock_tracker(inode, &bh, 1, &oh);
  	if (had_lock < 0)
  		return had_lock;
19ec8e485   Jan Kara   ocfs2: don't clea...
270
271
272
273
274
275
276
277
278
279
280
  	if (type == ACL_TYPE_ACCESS && acl) {
  		umode_t mode;
  
  		status = posix_acl_update_mode(inode, &mode, &acl);
  		if (status)
  			goto unlock;
  
  		status = ocfs2_acl_set_mode(inode, bh, NULL, mode);
  		if (status)
  			goto unlock;
  	}
743b5f143   Tariq Saeed   ocfs2: take inode...
281
  	status = ocfs2_set_acl(NULL, inode, bh, type, acl, NULL, NULL);
19ec8e485   Jan Kara   ocfs2: don't clea...
282
  unlock:
b891fa502   Eric Ren   ocfs2: fix deadlo...
283
  	ocfs2_inode_unlock_tracker(inode, 1, &oh, had_lock);
743b5f143   Tariq Saeed   ocfs2: take inode...
284
285
  	brelse(bh);
  	return status;
702e5bc68   Christoph Hellwig   ocfs2: use generi...
286
  }
4e34e719e   Christoph Hellwig   fs: take the ACL ...
287
  struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type)
23fc2702b   Tiger Yang   ocfs2: add ocfs2_...
288
  {
b74c79e99   Nick Piggin   fs: provide rcu-w...
289
  	struct ocfs2_super *osb;
845b6cf34   Jiaju Zhang   Fix the nested PR...
290
291
  	struct buffer_head *di_bh = NULL;
  	struct posix_acl *acl;
b891fa502   Eric Ren   ocfs2: fix deadlo...
292
293
  	int had_lock;
  	struct ocfs2_lock_holder oh;
845b6cf34   Jiaju Zhang   Fix the nested PR...
294

b74c79e99   Nick Piggin   fs: provide rcu-w...
295
  	osb = OCFS2_SB(inode->i_sb);
845b6cf34   Jiaju Zhang   Fix the nested PR...
296
  	if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
4e34e719e   Christoph Hellwig   fs: take the ACL ...
297
  		return NULL;
b891fa502   Eric Ren   ocfs2: fix deadlo...
298
299
300
301
  
  	had_lock = ocfs2_inode_lock_tracker(inode, &di_bh, 0, &oh);
  	if (had_lock < 0)
  		return ERR_PTR(had_lock);
845b6cf34   Jiaju Zhang   Fix the nested PR...
302

16c8d569f   piaojun   ocfs2/acl: use 'i...
303
  	down_read(&OCFS2_I(inode)->ip_xattr_sem);
4e34e719e   Christoph Hellwig   fs: take the ACL ...
304
  	acl = ocfs2_get_acl_nolock(inode, type, di_bh);
16c8d569f   piaojun   ocfs2/acl: use 'i...
305
  	up_read(&OCFS2_I(inode)->ip_xattr_sem);
845b6cf34   Jiaju Zhang   Fix the nested PR...
306

b891fa502   Eric Ren   ocfs2: fix deadlo...
307
  	ocfs2_inode_unlock_tracker(inode, 0, &oh, had_lock);
845b6cf34   Jiaju Zhang   Fix the nested PR...
308
  	brelse(di_bh);
4e34e719e   Christoph Hellwig   fs: take the ACL ...
309
  	return acl;
23fc2702b   Tiger Yang   ocfs2: add ocfs2_...
310
  }
5ee0fbd50   Junxiao Bi   ocfs2: revert usi...
311
312
313
314
315
316
317
318
319
320
321
322
  
  int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh)
  {
  	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
  	struct posix_acl *acl;
  	int ret;
  
  	if (S_ISLNK(inode->i_mode))
  		return -EOPNOTSUPP;
  
  	if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
  		return 0;
16c8d569f   piaojun   ocfs2/acl: use 'i...
323
  	down_read(&OCFS2_I(inode)->ip_xattr_sem);
5ee0fbd50   Junxiao Bi   ocfs2: revert usi...
324
  	acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh);
16c8d569f   piaojun   ocfs2/acl: use 'i...
325
  	up_read(&OCFS2_I(inode)->ip_xattr_sem);
188c523e1   Ding Xiang   ocfs2: fix passin...
326
327
  	if (IS_ERR_OR_NULL(acl))
  		return PTR_ERR_OR_ZERO(acl);
5ee0fbd50   Junxiao Bi   ocfs2: revert usi...
328
329
330
331
332
333
334
335
  	ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
  	if (ret)
  		return ret;
  	ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS,
  			    acl, NULL, NULL);
  	posix_acl_release(acl);
  	return ret;
  }
c25a1e067   Junxiao Bi   ocfs2: fix posix_...
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  
  /*
   * Initialize the ACLs of a new inode. If parent directory has default ACL,
   * then clone to new inode. Called from ocfs2_mknod.
   */
  int ocfs2_init_acl(handle_t *handle,
  		   struct inode *inode,
  		   struct inode *dir,
  		   struct buffer_head *di_bh,
  		   struct buffer_head *dir_bh,
  		   struct ocfs2_alloc_context *meta_ac,
  		   struct ocfs2_alloc_context *data_ac)
  {
  	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
  	struct posix_acl *acl = NULL;
  	int ret = 0, ret2;
  	umode_t mode;
  
  	if (!S_ISLNK(inode->i_mode)) {
  		if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
16c8d569f   piaojun   ocfs2/acl: use 'i...
356
  			down_read(&OCFS2_I(dir)->ip_xattr_sem);
c25a1e067   Junxiao Bi   ocfs2: fix posix_...
357
358
  			acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT,
  						   dir_bh);
16c8d569f   piaojun   ocfs2/acl: use 'i...
359
  			up_read(&OCFS2_I(dir)->ip_xattr_sem);
c25a1e067   Junxiao Bi   ocfs2: fix posix_...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
  			if (IS_ERR(acl))
  				return PTR_ERR(acl);
  		}
  		if (!acl) {
  			mode = inode->i_mode & ~current_umask();
  			ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
  			if (ret) {
  				mlog_errno(ret);
  				goto cleanup;
  			}
  		}
  	}
  	if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
  		if (S_ISDIR(inode->i_mode)) {
  			ret = ocfs2_set_acl(handle, inode, di_bh,
  					    ACL_TYPE_DEFAULT, acl,
  					    meta_ac, data_ac);
  			if (ret)
  				goto cleanup;
  		}
  		mode = inode->i_mode;
  		ret = __posix_acl_create(&acl, GFP_NOFS, &mode);
  		if (ret < 0)
  			return ret;
  
  		ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
  		if (ret2) {
  			mlog_errno(ret2);
  			ret = ret2;
  			goto cleanup;
  		}
  		if (ret > 0) {
  			ret = ocfs2_set_acl(handle, inode,
  					    di_bh, ACL_TYPE_ACCESS,
  					    acl, meta_ac, data_ac);
  		}
  	}
  cleanup:
  	posix_acl_release(acl);
  	return ret;
  }