xattr.c 14.1 KB
Newer Older
J
Jaegeuk Kim 已提交
1
/*
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 * fs/f2fs/xattr.c
 *
 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
 *             http://www.samsung.com/
 *
 * Portions of this code from linux/fs/ext2/xattr.c
 *
 * Copyright (C) 2001-2003 Andreas Gruenbacher <agruen@suse.de>
 *
 * Fix by Harrison Xing <harrison@mountainviewdata.com>.
 * Extended attributes for symlinks and special files added per
 *  suggestion of Luka Renko <luka.renko@hermes.si>.
 * xattr consolidation Copyright (c) 2004 James Morris <jmorris@redhat.com>,
 *  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/rwsem.h>
#include <linux/f2fs_fs.h>
23
#include <linux/security.h>
24
#include <linux/posix_acl_xattr.h>
25 26 27
#include "f2fs.h"
#include "xattr.h"

28
static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
29 30
		struct dentry *unused, struct inode *inode,
		const char *name, void *buffer, size_t size)
31
{
32
	struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
33

34
	switch (handler->flags) {
35 36 37 38 39 40 41 42
	case F2FS_XATTR_INDEX_USER:
		if (!test_opt(sbi, XATTR_USER))
			return -EOPNOTSUPP;
		break;
	case F2FS_XATTR_INDEX_TRUSTED:
		if (!capable(CAP_SYS_ADMIN))
			return -EPERM;
		break;
43 44
	case F2FS_XATTR_INDEX_SECURITY:
		break;
45 46 47
	default:
		return -EINVAL;
	}
48
	return f2fs_getxattr(inode, handler->flags, name,
49
			     buffer, size, NULL);
50 51
}

52
static int f2fs_xattr_generic_set(const struct xattr_handler *handler,
53 54
		struct dentry *unused, struct inode *inode,
		const char *name, const void *value,
55
		size_t size, int flags)
56
{
57
	struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
58

59
	switch (handler->flags) {
60 61 62 63 64 65 66 67
	case F2FS_XATTR_INDEX_USER:
		if (!test_opt(sbi, XATTR_USER))
			return -EOPNOTSUPP;
		break;
	case F2FS_XATTR_INDEX_TRUSTED:
		if (!capable(CAP_SYS_ADMIN))
			return -EPERM;
		break;
68 69
	case F2FS_XATTR_INDEX_SECURITY:
		break;
70 71 72
	default:
		return -EINVAL;
	}
73
	return f2fs_setxattr(inode, handler->flags, name,
74
					value, size, NULL, flags);
75 76
}

77
static bool f2fs_xattr_user_list(struct dentry *dentry)
J
Jaegeuk Kim 已提交
78
{
79 80 81 82
	struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);

	return test_opt(sbi, XATTR_USER);
}
J
Jaegeuk Kim 已提交
83

84 85 86
static bool f2fs_xattr_trusted_list(struct dentry *dentry)
{
	return capable(CAP_SYS_ADMIN);
J
Jaegeuk Kim 已提交
87 88
}

89
static int f2fs_xattr_advise_get(const struct xattr_handler *handler,
90 91
		struct dentry *unused, struct inode *inode,
		const char *name, void *buffer, size_t size)
J
Jaegeuk Kim 已提交
92
{
93 94
	if (buffer)
		*((char *)buffer) = F2FS_I(inode)->i_advise;
J
Jaegeuk Kim 已提交
95 96 97
	return sizeof(char);
}

98
static int f2fs_xattr_advise_set(const struct xattr_handler *handler,
99 100
		struct dentry *unused, struct inode *inode,
		const char *name, const void *value,
101
		size_t size, int flags)
J
Jaegeuk Kim 已提交
102 103 104 105 106 107 108
{
	if (!inode_owner_or_capable(inode))
		return -EPERM;
	if (value == NULL)
		return -EINVAL;

	F2FS_I(inode)->i_advise |= *(char *)value;
109
	f2fs_mark_inode_dirty_sync(inode, true);
J
Jaegeuk Kim 已提交
110 111 112
	return 0;
}

113 114 115 116 117 118 119 120
#ifdef CONFIG_F2FS_FS_SECURITY
static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
		void *page)
{
	const struct xattr *xattr;
	int err = 0;

	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
121
		err = f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY,
122
				xattr->name, xattr->value,
123
				xattr->value_len, (struct page *)page, 0);
124 125 126 127 128 129 130 131 132 133 134 135 136 137
		if (err < 0)
			break;
	}
	return err;
}

int f2fs_init_security(struct inode *inode, struct inode *dir,
				const struct qstr *qstr, struct page *ipage)
{
	return security_inode_init_security(inode, dir, qstr,
				&f2fs_initxattrs, ipage);
}
#endif

138 139 140
const struct xattr_handler f2fs_xattr_user_handler = {
	.prefix	= XATTR_USER_PREFIX,
	.flags	= F2FS_XATTR_INDEX_USER,
141
	.list	= f2fs_xattr_user_list,
142 143 144 145 146 147 148
	.get	= f2fs_xattr_generic_get,
	.set	= f2fs_xattr_generic_set,
};

const struct xattr_handler f2fs_xattr_trusted_handler = {
	.prefix	= XATTR_TRUSTED_PREFIX,
	.flags	= F2FS_XATTR_INDEX_TRUSTED,
149
	.list	= f2fs_xattr_trusted_list,
150 151 152 153
	.get	= f2fs_xattr_generic_get,
	.set	= f2fs_xattr_generic_set,
};

J
Jaegeuk Kim 已提交
154
const struct xattr_handler f2fs_xattr_advise_handler = {
155
	.name	= F2FS_SYSTEM_ADVISE_NAME,
J
Jaegeuk Kim 已提交
156 157 158 159 160
	.flags	= F2FS_XATTR_INDEX_ADVISE,
	.get    = f2fs_xattr_advise_get,
	.set    = f2fs_xattr_advise_set,
};

161 162 163 164 165 166 167
const struct xattr_handler f2fs_xattr_security_handler = {
	.prefix	= XATTR_SECURITY_PREFIX,
	.flags	= F2FS_XATTR_INDEX_SECURITY,
	.get	= f2fs_xattr_generic_get,
	.set	= f2fs_xattr_generic_set,
};

168 169 170
static const struct xattr_handler *f2fs_xattr_handler_map[] = {
	[F2FS_XATTR_INDEX_USER] = &f2fs_xattr_user_handler,
#ifdef CONFIG_F2FS_FS_POSIX_ACL
171 172
	[F2FS_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler,
	[F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler,
173 174
#endif
	[F2FS_XATTR_INDEX_TRUSTED] = &f2fs_xattr_trusted_handler,
175 176 177
#ifdef CONFIG_F2FS_FS_SECURITY
	[F2FS_XATTR_INDEX_SECURITY] = &f2fs_xattr_security_handler,
#endif
178 179 180 181 182 183
	[F2FS_XATTR_INDEX_ADVISE] = &f2fs_xattr_advise_handler,
};

const struct xattr_handler *f2fs_xattr_handlers[] = {
	&f2fs_xattr_user_handler,
#ifdef CONFIG_F2FS_FS_POSIX_ACL
184 185
	&posix_acl_access_xattr_handler,
	&posix_acl_default_xattr_handler,
186 187
#endif
	&f2fs_xattr_trusted_handler,
188 189 190
#ifdef CONFIG_F2FS_FS_SECURITY
	&f2fs_xattr_security_handler,
#endif
191 192 193 194
	&f2fs_xattr_advise_handler,
	NULL,
};

J
Jaegeuk Kim 已提交
195
static inline const struct xattr_handler *f2fs_xattr_handler(int index)
196 197 198
{
	const struct xattr_handler *handler = NULL;

J
Jaegeuk Kim 已提交
199 200
	if (index > 0 && index < ARRAY_SIZE(f2fs_xattr_handler_map))
		handler = f2fs_xattr_handler_map[index];
201 202 203
	return handler;
}

J
Jaegeuk Kim 已提交
204 205
static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
					size_t len, const char *name)
206 207 208 209
{
	struct f2fs_xattr_entry *entry;

	list_for_each_xattr(entry, base_addr) {
J
Jaegeuk Kim 已提交
210
		if (entry->e_name_index != index)
211
			continue;
J
Jaegeuk Kim 已提交
212
		if (entry->e_name_len != len)
213
			continue;
J
Jaegeuk Kim 已提交
214
		if (!memcmp(entry->e_name, name, len))
215 216 217 218 219
			break;
	}
	return entry;
}

220 221
static int read_all_xattrs(struct inode *inode, struct page *ipage,
							void **base_addr)
J
Jaegeuk Kim 已提交
222
{
223
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
J
Jaegeuk Kim 已提交
224 225 226
	struct f2fs_xattr_header *header;
	size_t size = PAGE_SIZE, inline_size = 0;
	void *txattr_addr;
227
	int err;
J
Jaegeuk Kim 已提交
228 229 230

	inline_size = inline_xattr_size(inode);

231
	txattr_addr = kzalloc(inline_size + size, GFP_F2FS_ZERO);
J
Jaegeuk Kim 已提交
232
	if (!txattr_addr)
233
		return -ENOMEM;
J
Jaegeuk Kim 已提交
234 235 236 237 238 239 240 241 242 243

	/* read from inline xattr */
	if (inline_size) {
		struct page *page = NULL;
		void *inline_addr;

		if (ipage) {
			inline_addr = inline_xattr_addr(ipage);
		} else {
			page = get_node_page(sbi, inode->i_ino);
244 245
			if (IS_ERR(page)) {
				err = PTR_ERR(page);
J
Jaegeuk Kim 已提交
246
				goto fail;
247
			}
J
Jaegeuk Kim 已提交
248 249 250 251 252 253 254 255 256 257 258 259 260
			inline_addr = inline_xattr_addr(page);
		}
		memcpy(txattr_addr, inline_addr, inline_size);
		f2fs_put_page(page, 1);
	}

	/* read from xattr node block */
	if (F2FS_I(inode)->i_xattr_nid) {
		struct page *xpage;
		void *xattr_addr;

		/* The inode already has an extended attribute block. */
		xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid);
261 262
		if (IS_ERR(xpage)) {
			err = PTR_ERR(xpage);
J
Jaegeuk Kim 已提交
263
			goto fail;
264
		}
J
Jaegeuk Kim 已提交
265 266 267 268 269 270 271 272 273 274 275 276 277

		xattr_addr = page_address(xpage);
		memcpy(txattr_addr + inline_size, xattr_addr, PAGE_SIZE);
		f2fs_put_page(xpage, 1);
	}

	header = XATTR_HDR(txattr_addr);

	/* never been allocated xattrs */
	if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) {
		header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC);
		header->h_refcount = cpu_to_le32(1);
	}
278 279
	*base_addr = txattr_addr;
	return 0;
J
Jaegeuk Kim 已提交
280 281
fail:
	kzfree(txattr_addr);
282
	return err;
J
Jaegeuk Kim 已提交
283 284 285 286 287
}

static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
				void *txattr_addr, struct page *ipage)
{
288
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
J
Jaegeuk Kim 已提交
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
	size_t inline_size = 0;
	void *xattr_addr;
	struct page *xpage;
	nid_t new_nid = 0;
	int err;

	inline_size = inline_xattr_size(inode);

	if (hsize > inline_size && !F2FS_I(inode)->i_xattr_nid)
		if (!alloc_nid(sbi, &new_nid))
			return -ENOSPC;

	/* write to inline xattr */
	if (inline_size) {
		struct page *page = NULL;
		void *inline_addr;

		if (ipage) {
			inline_addr = inline_xattr_addr(ipage);
308
			f2fs_wait_on_page_writeback(ipage, NODE, true);
309
			set_page_dirty(ipage);
J
Jaegeuk Kim 已提交
310 311 312 313 314 315 316
		} else {
			page = get_node_page(sbi, inode->i_ino);
			if (IS_ERR(page)) {
				alloc_nid_failed(sbi, new_nid);
				return PTR_ERR(page);
			}
			inline_addr = inline_xattr_addr(page);
317
			f2fs_wait_on_page_writeback(page, NODE, true);
J
Jaegeuk Kim 已提交
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
		}
		memcpy(inline_addr, txattr_addr, inline_size);
		f2fs_put_page(page, 1);

		/* no need to use xattr node block */
		if (hsize <= inline_size) {
			err = truncate_xattr_node(inode, ipage);
			alloc_nid_failed(sbi, new_nid);
			return err;
		}
	}

	/* write to xattr node block */
	if (F2FS_I(inode)->i_xattr_nid) {
		xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid);
		if (IS_ERR(xpage)) {
			alloc_nid_failed(sbi, new_nid);
			return PTR_ERR(xpage);
		}
337
		f2fs_bug_on(sbi, new_nid);
338
		f2fs_wait_on_page_writeback(xpage, NODE, true);
J
Jaegeuk Kim 已提交
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
	} else {
		struct dnode_of_data dn;
		set_new_dnode(&dn, inode, NULL, NULL, new_nid);
		xpage = new_node_page(&dn, XATTR_NODE_OFFSET, ipage);
		if (IS_ERR(xpage)) {
			alloc_nid_failed(sbi, new_nid);
			return PTR_ERR(xpage);
		}
		alloc_nid_done(sbi, new_nid);
	}

	xattr_addr = page_address(xpage);
	memcpy(xattr_addr, txattr_addr + inline_size, PAGE_SIZE -
						sizeof(struct node_footer));
	set_page_dirty(xpage);
	f2fs_put_page(xpage, 1);

	/* need to checkpoint during fsync */
	F2FS_I(inode)->xattr_ver = cur_cp_version(F2FS_CKPT(sbi));
	return 0;
}

J
Jaegeuk Kim 已提交
361
int f2fs_getxattr(struct inode *inode, int index, const char *name,
362
		void *buffer, size_t buffer_size, struct page *ipage)
363 364
{
	struct f2fs_xattr_entry *entry;
J
Jaegeuk Kim 已提交
365
	void *base_addr;
366
	int error = 0;
J
Jaegeuk Kim 已提交
367
	size_t size, len;
368 369 370

	if (name == NULL)
		return -EINVAL;
J
Jaegeuk Kim 已提交
371 372 373

	len = strlen(name);
	if (len > F2FS_NAME_LEN)
374
		return -ERANGE;
375

376 377 378
	error = read_all_xattrs(inode, ipage, &base_addr);
	if (error)
		return error;
379

J
Jaegeuk Kim 已提交
380
	entry = __find_xattr(base_addr, index, len, name);
381
	if (IS_XATTR_LAST_ENTRY(entry)) {
382 383 384 385
		error = -ENODATA;
		goto cleanup;
	}

J
Jaegeuk Kim 已提交
386
	size = le16_to_cpu(entry->e_value_size);
387

J
Jaegeuk Kim 已提交
388
	if (buffer && size > buffer_size) {
389 390 391 392 393 394
		error = -ERANGE;
		goto cleanup;
	}

	if (buffer) {
		char *pval = entry->e_name + entry->e_name_len;
J
Jaegeuk Kim 已提交
395
		memcpy(buffer, pval, size);
396
	}
J
Jaegeuk Kim 已提交
397
	error = size;
398 399

cleanup:
J
Jaegeuk Kim 已提交
400
	kzfree(base_addr);
401 402 403 404 405
	return error;
}

ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
{
406
	struct inode *inode = d_inode(dentry);
407 408 409 410 411
	struct f2fs_xattr_entry *entry;
	void *base_addr;
	int error = 0;
	size_t rest = buffer_size;

412 413 414
	error = read_all_xattrs(inode, NULL, &base_addr);
	if (error)
		return error;
415 416 417 418

	list_for_each_xattr(entry, base_addr) {
		const struct xattr_handler *handler =
			f2fs_xattr_handler(entry->e_name_index);
419 420
		const char *prefix;
		size_t prefix_len;
421 422
		size_t size;

423
		if (!handler || (handler->list && !handler->list(dentry)))
424 425
			continue;

426 427 428 429 430 431 432 433 434 435 436 437 438
		prefix = handler->prefix ?: handler->name;
		prefix_len = strlen(prefix);
		size = prefix_len + entry->e_name_len + 1;
		if (buffer) {
			if (size > rest) {
				error = -ERANGE;
				goto cleanup;
			}
			memcpy(buffer, prefix, prefix_len);
			buffer += prefix_len;
			memcpy(buffer, entry->e_name, entry->e_name_len);
			buffer += entry->e_name_len;
			*buffer++ = 0;
439 440 441 442 443
		}
		rest -= size;
	}
	error = buffer_size - rest;
cleanup:
J
Jaegeuk Kim 已提交
444
	kzfree(base_addr);
445 446 447
	return error;
}

J
Jaegeuk Kim 已提交
448 449
static int __f2fs_setxattr(struct inode *inode, int index,
			const char *name, const void *value, size_t size,
450
			struct page *ipage, int flags)
451 452 453
{
	struct f2fs_xattr_entry *here, *last;
	void *base_addr;
J
Jaegeuk Kim 已提交
454
	int found, newsize;
J
Jaegeuk Kim 已提交
455
	size_t len;
J
Jaegeuk Kim 已提交
456
	__u32 new_hsize;
457
	int error = 0;
458 459 460 461 462

	if (name == NULL)
		return -EINVAL;

	if (value == NULL)
J
Jaegeuk Kim 已提交
463
		size = 0;
464

J
Jaegeuk Kim 已提交
465
	len = strlen(name);
N
Namjae Jeon 已提交
466

467
	if (len > F2FS_NAME_LEN)
468 469
		return -ERANGE;

470 471 472
	if (size > MAX_VALUE_LEN(inode))
		return -E2BIG;

473 474 475
	error = read_all_xattrs(inode, ipage, &base_addr);
	if (error)
		return error;
476 477

	/* find entry with wanted name. */
J
Jaegeuk Kim 已提交
478
	here = __find_xattr(base_addr, index, len, name);
479

480
	found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
481

482 483 484 485 486 487 488 489 490
	if ((flags & XATTR_REPLACE) && !found) {
		error = -ENODATA;
		goto exit;
	} else if ((flags & XATTR_CREATE) && found) {
		error = -EEXIST;
		goto exit;
	}

	last = here;
491 492 493
	while (!IS_XATTR_LAST_ENTRY(last))
		last = XATTR_NEXT_ENTRY(last);

J
Jaegeuk Kim 已提交
494
	newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size);
495 496 497

	/* 1. Check space */
	if (value) {
J
Jaegeuk Kim 已提交
498 499 500
		int free;
		/*
		 * If value is NULL, it is remove operation.
A
arter97 已提交
501
		 * In case of update operation, we calculate free.
502
		 */
J
Jaegeuk Kim 已提交
503
		free = MIN_OFFSET(inode) - ((char *)last - (char *)base_addr);
504
		if (found)
505
			free = free + ENTRY_SIZE(here);
506

507
		if (unlikely(free < newsize)) {
508
			error = -E2BIG;
J
Jaegeuk Kim 已提交
509
			goto exit;
510 511 512 513 514
		}
	}

	/* 2. Remove old entry */
	if (found) {
J
Jaegeuk Kim 已提交
515 516
		/*
		 * If entry is found, remove old entry.
517 518 519 520 521 522 523 524 525 526
		 * If not found, remove operation is not needed.
		 */
		struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here);
		int oldsize = ENTRY_SIZE(here);

		memmove(here, next, (char *)last - (char *)next);
		last = (struct f2fs_xattr_entry *)((char *)last - oldsize);
		memset(last, 0, oldsize);
	}

J
Jaegeuk Kim 已提交
527 528
	new_hsize = (char *)last - (char *)base_addr;

529 530
	/* 3. Write new entry */
	if (value) {
J
Jaegeuk Kim 已提交
531 532 533 534 535
		char *pval;
		/*
		 * Before we come here, old entry is removed.
		 * We just write new entry.
		 */
J
Jaegeuk Kim 已提交
536 537 538 539 540 541
		last->e_name_index = index;
		last->e_name_len = len;
		memcpy(last->e_name, name, len);
		pval = last->e_name + len;
		memcpy(pval, value, size);
		last->e_value_size = cpu_to_le16(size);
J
Jaegeuk Kim 已提交
542
		new_hsize += newsize;
543 544
	}

J
Jaegeuk Kim 已提交
545 546 547
	error = write_all_xattrs(inode, new_hsize, base_addr, ipage);
	if (error)
		goto exit;
548

549 550
	if (is_inode_flag_set(inode, FI_ACL_MODE)) {
		inode->i_mode = F2FS_I(inode)->i_acl_mode;
551
		inode->i_ctime = current_time(inode);
552
		clear_inode_flag(inode, FI_ACL_MODE);
553
	}
554 555 556
	if (index == F2FS_XATTR_INDEX_ENCRYPTION &&
			!strcmp(name, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT))
		f2fs_set_encrypted_inode(inode);
557
	f2fs_mark_inode_dirty_sync(inode, true);
558 559
	if (!error && S_ISDIR(inode->i_mode))
		set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_CP);
N
Namjae Jeon 已提交
560
exit:
J
Jaegeuk Kim 已提交
561
	kzfree(base_addr);
562 563
	return error;
}
564

J
Jaegeuk Kim 已提交
565 566
int f2fs_setxattr(struct inode *inode, int index, const char *name,
				const void *value, size_t size,
567
				struct page *ipage, int flags)
568
{
569
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
570 571
	int err;

572 573 574 575
	/* this case is only from init_inode_metadata */
	if (ipage)
		return __f2fs_setxattr(inode, index, name, value,
						size, ipage, flags);
J
Jaegeuk Kim 已提交
576
	f2fs_balance_fs(sbi, true);
577

578
	f2fs_lock_op(sbi);
579 580
	/* protect xattr_ver */
	down_write(&F2FS_I(inode)->i_sem);
581
	err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags);
582
	up_write(&F2FS_I(inode)->i_sem);
583
	f2fs_unlock_op(sbi);
584

585
	f2fs_update_time(sbi, REQ_TIME);
586 587
	return err;
}