xattr.c 16.8 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;
}

C
Chao Yu 已提交
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
static struct f2fs_xattr_entry *__find_inline_xattr(void *base_addr,
					void **last_addr, int index,
					size_t len, const char *name)
{
	struct f2fs_xattr_entry *entry;
	unsigned int inline_size = F2FS_INLINE_XATTR_ADDRS << 2;

	list_for_each_xattr(entry, base_addr) {
		if ((void *)entry + sizeof(__u32) > base_addr + inline_size ||
			(void *)XATTR_NEXT_ENTRY(entry) + sizeof(__u32) >
			base_addr + inline_size) {
			*last_addr = entry;
			return NULL;
		}
		if (entry->e_name_index != index)
			continue;
		if (entry->e_name_len != len)
			continue;
		if (!memcmp(entry->e_name, name, len))
			break;
	}
	return entry;
}

C
Chao Yu 已提交
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
static int read_inline_xattr(struct inode *inode, struct page *ipage,
							void *txattr_addr)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	unsigned int inline_size = inline_xattr_size(inode);
	struct page *page = NULL;
	void *inline_addr;

	if (ipage) {
		inline_addr = inline_xattr_addr(ipage);
	} else {
		page = get_node_page(sbi, inode->i_ino);
		if (IS_ERR(page))
			return PTR_ERR(page);

		inline_addr = inline_xattr_addr(page);
	}
	memcpy(txattr_addr, inline_addr, inline_size);
	f2fs_put_page(page, 1);

	return 0;
}

C
Chao Yu 已提交
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
static int read_xattr_block(struct inode *inode, void *txattr_addr)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	nid_t xnid = F2FS_I(inode)->i_xattr_nid;
	unsigned int inline_size = inline_xattr_size(inode);
	struct page *xpage;
	void *xattr_addr;

	/* The inode already has an extended attribute block. */
	xpage = get_node_page(sbi, xnid);
	if (IS_ERR(xpage))
		return PTR_ERR(xpage);

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

	return 0;
}

C
Chao Yu 已提交
287 288 289 290 291 292 293 294
static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
				unsigned int index, unsigned int len,
				const char *name, struct f2fs_xattr_entry **xe,
				void **base_addr)
{
	void *cur_addr, *txattr_addr, *last_addr = NULL;
	nid_t xnid = F2FS_I(inode)->i_xattr_nid;
	unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
C
Chao Yu 已提交
295
	unsigned int inline_size = inline_xattr_size(inode);
C
Chao Yu 已提交
296 297 298 299 300
	int err = 0;

	if (!size && !inline_size)
		return -ENODATA;

301
	txattr_addr = kzalloc(inline_size + size + XATTR_PADDING_SIZE,
C
Chao Yu 已提交
302 303 304 305 306 307
							GFP_F2FS_ZERO);
	if (!txattr_addr)
		return -ENOMEM;

	/* read from inline xattr */
	if (inline_size) {
C
Chao Yu 已提交
308 309 310
		err = read_inline_xattr(inode, ipage, txattr_addr);
		if (err)
			goto out;
C
Chao Yu 已提交
311 312 313 314 315 316 317 318 319

		*xe = __find_inline_xattr(txattr_addr, &last_addr,
						index, len, name);
		if (*xe)
			goto check;
	}

	/* read from xattr node block */
	if (xnid) {
C
Chao Yu 已提交
320 321
		err = read_xattr_block(inode, txattr_addr);
		if (err)
C
Chao Yu 已提交
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
			goto out;
	}

	if (last_addr)
		cur_addr = XATTR_HDR(last_addr) - 1;
	else
		cur_addr = txattr_addr;

	*xe = __find_xattr(cur_addr, index, len, name);
check:
	if (IS_XATTR_LAST_ENTRY(*xe)) {
		err = -ENODATA;
		goto out;
	}

	*base_addr = txattr_addr;
	return 0;
out:
	kzfree(txattr_addr);
	return err;
}

344 345
static int read_all_xattrs(struct inode *inode, struct page *ipage,
							void **base_addr)
J
Jaegeuk Kim 已提交
346 347
{
	struct f2fs_xattr_header *header;
C
Chao Yu 已提交
348 349 350
	nid_t xnid = F2FS_I(inode)->i_xattr_nid;
	unsigned int size = VALID_XATTR_BLOCK_SIZE;
	unsigned int inline_size = inline_xattr_size(inode);
J
Jaegeuk Kim 已提交
351
	void *txattr_addr;
352
	int err;
J
Jaegeuk Kim 已提交
353

354
	txattr_addr = kzalloc(inline_size + size + XATTR_PADDING_SIZE,
C
Chao Yu 已提交
355
							GFP_F2FS_ZERO);
J
Jaegeuk Kim 已提交
356
	if (!txattr_addr)
357
		return -ENOMEM;
J
Jaegeuk Kim 已提交
358 359 360

	/* read from inline xattr */
	if (inline_size) {
C
Chao Yu 已提交
361 362 363
		err = read_inline_xattr(inode, ipage, txattr_addr);
		if (err)
			goto fail;
J
Jaegeuk Kim 已提交
364 365 366
	}

	/* read from xattr node block */
C
Chao Yu 已提交
367
	if (xnid) {
C
Chao Yu 已提交
368 369
		err = read_xattr_block(inode, txattr_addr);
		if (err)
J
Jaegeuk Kim 已提交
370 371 372 373 374 375 376 377 378 379
			goto fail;
	}

	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);
	}
380 381
	*base_addr = txattr_addr;
	return 0;
J
Jaegeuk Kim 已提交
382 383
fail:
	kzfree(txattr_addr);
384
	return err;
J
Jaegeuk Kim 已提交
385 386 387 388 389
}

static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
				void *txattr_addr, struct page *ipage)
{
390
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
C
Chao Yu 已提交
391
	size_t inline_size = inline_xattr_size(inode);
J
Jaegeuk Kim 已提交
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
	void *xattr_addr;
	struct page *xpage;
	nid_t new_nid = 0;
	int err;

	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);
408
			f2fs_wait_on_page_writeback(ipage, NODE, true);
409
			set_page_dirty(ipage);
J
Jaegeuk Kim 已提交
410 411 412 413 414 415 416
		} 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);
417
			f2fs_wait_on_page_writeback(page, NODE, true);
J
Jaegeuk Kim 已提交
418 419 420 421 422 423
		}
		memcpy(inline_addr, txattr_addr, inline_size);
		f2fs_put_page(page, 1);

		/* no need to use xattr node block */
		if (hsize <= inline_size) {
424
			err = truncate_xattr_node(inode);
J
Jaegeuk Kim 已提交
425 426 427 428 429 430 431 432 433 434 435 436
			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);
		}
437
		f2fs_bug_on(sbi, new_nid);
438
		f2fs_wait_on_page_writeback(xpage, NODE, true);
J
Jaegeuk Kim 已提交
439 440 441
	} else {
		struct dnode_of_data dn;
		set_new_dnode(&dn, inode, NULL, NULL, new_nid);
Y
Yunlei He 已提交
442
		xpage = new_node_page(&dn, XATTR_NODE_OFFSET);
J
Jaegeuk Kim 已提交
443 444 445 446 447 448 449 450
		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);
451
	memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE);
J
Jaegeuk Kim 已提交
452 453 454 455 456 457
	set_page_dirty(xpage);
	f2fs_put_page(xpage, 1);

	return 0;
}

J
Jaegeuk Kim 已提交
458
int f2fs_getxattr(struct inode *inode, int index, const char *name,
459
		void *buffer, size_t buffer_size, struct page *ipage)
460
{
C
Chao Yu 已提交
461
	struct f2fs_xattr_entry *entry = NULL;
462
	int error = 0;
C
Chao Yu 已提交
463 464
	unsigned int size, len;
	void *base_addr = NULL;
465 466 467

	if (name == NULL)
		return -EINVAL;
J
Jaegeuk Kim 已提交
468 469 470

	len = strlen(name);
	if (len > F2FS_NAME_LEN)
471
		return -ERANGE;
472

473
	down_read(&F2FS_I(inode)->i_xattr_sem);
C
Chao Yu 已提交
474 475
	error = lookup_all_xattrs(inode, ipage, index, len, name,
				&entry, &base_addr);
476
	up_read(&F2FS_I(inode)->i_xattr_sem);
477 478
	if (error)
		return error;
479

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

J
Jaegeuk Kim 已提交
482
	if (buffer && size > buffer_size) {
483
		error = -ERANGE;
C
Chao Yu 已提交
484
		goto out;
485 486 487 488
	}

	if (buffer) {
		char *pval = entry->e_name + entry->e_name_len;
J
Jaegeuk Kim 已提交
489
		memcpy(buffer, pval, size);
490
	}
J
Jaegeuk Kim 已提交
491
	error = size;
C
Chao Yu 已提交
492
out:
J
Jaegeuk Kim 已提交
493
	kzfree(base_addr);
494 495 496 497 498
	return error;
}

ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
{
499
	struct inode *inode = d_inode(dentry);
500 501 502 503 504
	struct f2fs_xattr_entry *entry;
	void *base_addr;
	int error = 0;
	size_t rest = buffer_size;

505
	down_read(&F2FS_I(inode)->i_xattr_sem);
506
	error = read_all_xattrs(inode, NULL, &base_addr);
507
	up_read(&F2FS_I(inode)->i_xattr_sem);
508 509
	if (error)
		return error;
510 511 512 513

	list_for_each_xattr(entry, base_addr) {
		const struct xattr_handler *handler =
			f2fs_xattr_handler(entry->e_name_index);
514 515
		const char *prefix;
		size_t prefix_len;
516 517
		size_t size;

518
		if (!handler || (handler->list && !handler->list(dentry)))
519 520
			continue;

521 522 523 524 525 526 527 528 529 530 531 532 533
		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;
534 535 536 537 538
		}
		rest -= size;
	}
	error = buffer_size - rest;
cleanup:
J
Jaegeuk Kim 已提交
539
	kzfree(base_addr);
540 541 542
	return error;
}

543 544 545 546
static bool f2fs_xattr_value_same(struct f2fs_xattr_entry *entry,
					const void *value, size_t size)
{
	void *pval = entry->e_name + entry->e_name_len;
547 548 549

	return (le16_to_cpu(entry->e_value_size) == size) &&
					!memcmp(pval, value, size);
550 551
}

J
Jaegeuk Kim 已提交
552 553
static int __f2fs_setxattr(struct inode *inode, int index,
			const char *name, const void *value, size_t size,
554
			struct page *ipage, int flags)
555 556 557
{
	struct f2fs_xattr_entry *here, *last;
	void *base_addr;
J
Jaegeuk Kim 已提交
558
	int found, newsize;
J
Jaegeuk Kim 已提交
559
	size_t len;
J
Jaegeuk Kim 已提交
560
	__u32 new_hsize;
561
	int error = 0;
562 563 564 565 566

	if (name == NULL)
		return -EINVAL;

	if (value == NULL)
J
Jaegeuk Kim 已提交
567
		size = 0;
568

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

571
	if (len > F2FS_NAME_LEN)
572 573
		return -ERANGE;

574 575 576
	if (size > MAX_VALUE_LEN(inode))
		return -E2BIG;

577 578 579
	error = read_all_xattrs(inode, ipage, &base_addr);
	if (error)
		return error;
580 581

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

584
	found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
585

586 587 588 589 590 591 592 593 594
	if (found) {
		if ((flags & XATTR_CREATE)) {
			error = -EEXIST;
			goto exit;
		}

		if (f2fs_xattr_value_same(here, value, size))
			goto exit;
	} else if ((flags & XATTR_REPLACE)) {
595 596 597 598 599
		error = -ENODATA;
		goto exit;
	}

	last = here;
600 601 602
	while (!IS_XATTR_LAST_ENTRY(last))
		last = XATTR_NEXT_ENTRY(last);

J
Jaegeuk Kim 已提交
603
	newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size);
604 605 606

	/* 1. Check space */
	if (value) {
J
Jaegeuk Kim 已提交
607 608 609
		int free;
		/*
		 * If value is NULL, it is remove operation.
A
arter97 已提交
610
		 * In case of update operation, we calculate free.
611
		 */
J
Jaegeuk Kim 已提交
612
		free = MIN_OFFSET(inode) - ((char *)last - (char *)base_addr);
613
		if (found)
614
			free = free + ENTRY_SIZE(here);
615

616
		if (unlikely(free < newsize)) {
617
			error = -E2BIG;
J
Jaegeuk Kim 已提交
618
			goto exit;
619 620 621 622 623
		}
	}

	/* 2. Remove old entry */
	if (found) {
J
Jaegeuk Kim 已提交
624 625
		/*
		 * If entry is found, remove old entry.
626 627 628 629 630 631 632 633 634 635
		 * 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 已提交
636 637
	new_hsize = (char *)last - (char *)base_addr;

638 639
	/* 3. Write new entry */
	if (value) {
J
Jaegeuk Kim 已提交
640 641 642 643 644
		char *pval;
		/*
		 * Before we come here, old entry is removed.
		 * We just write new entry.
		 */
J
Jaegeuk Kim 已提交
645 646 647 648 649 650
		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 已提交
651
		new_hsize += newsize;
652 653
	}

J
Jaegeuk Kim 已提交
654 655 656
	error = write_all_xattrs(inode, new_hsize, base_addr, ipage);
	if (error)
		goto exit;
657

658 659
	if (is_inode_flag_set(inode, FI_ACL_MODE)) {
		inode->i_mode = F2FS_I(inode)->i_acl_mode;
660
		inode->i_ctime = current_time(inode);
661
		clear_inode_flag(inode, FI_ACL_MODE);
662
	}
663 664 665
	if (index == F2FS_XATTR_INDEX_ENCRYPTION &&
			!strcmp(name, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT))
		f2fs_set_encrypted_inode(inode);
666
	f2fs_mark_inode_dirty_sync(inode, true);
667 668
	if (!error && S_ISDIR(inode->i_mode))
		set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_CP);
N
Namjae Jeon 已提交
669
exit:
J
Jaegeuk Kim 已提交
670
	kzfree(base_addr);
671 672
	return error;
}
673

J
Jaegeuk Kim 已提交
674 675
int f2fs_setxattr(struct inode *inode, int index, const char *name,
				const void *value, size_t size,
676
				struct page *ipage, int flags)
677
{
678
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
679 680
	int err;

681 682 683 684
	/* this case is only from init_inode_metadata */
	if (ipage)
		return __f2fs_setxattr(inode, index, name, value,
						size, ipage, flags);
J
Jaegeuk Kim 已提交
685
	f2fs_balance_fs(sbi, true);
686

687
	f2fs_lock_op(sbi);
688 689
	/* protect xattr_ver */
	down_write(&F2FS_I(inode)->i_sem);
690
	down_write(&F2FS_I(inode)->i_xattr_sem);
691
	err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags);
692
	up_write(&F2FS_I(inode)->i_xattr_sem);
693
	up_write(&F2FS_I(inode)->i_sem);
694
	f2fs_unlock_op(sbi);
695

696
	f2fs_update_time(sbi, REQ_TIME);
697 698
	return err;
}