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

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

	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
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) {
C
Chao Yu 已提交
253
		inline_addr = inline_xattr_addr(inode, ipage);
C
Chao Yu 已提交
254 255 256 257 258
	} else {
		page = get_node_page(sbi, inode->i_ino);
		if (IS_ERR(page))
			return PTR_ERR(page);

C
Chao Yu 已提交
259
		inline_addr = inline_xattr_addr(inode, page);
C
Chao Yu 已提交
260 261 262 263 264 265 266
	}
	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

C
Chao Yu 已提交
312
		*xe = __find_inline_xattr(inode, txattr_addr, &last_addr,
C
Chao Yu 已提交
313 314 315 316 317 318 319
						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);
392
	struct page *in_page = NULL;
J
Jaegeuk Kim 已提交
393
	void *xattr_addr;
394
	void *inline_addr = NULL;
J
Jaegeuk Kim 已提交
395 396
	struct page *xpage;
	nid_t new_nid = 0;
397
	int err = 0;
J
Jaegeuk Kim 已提交
398 399 400 401 402 403 404 405

	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) {
		if (ipage) {
C
Chao Yu 已提交
406
			inline_addr = inline_xattr_addr(inode, ipage);
J
Jaegeuk Kim 已提交
407
		} else {
408 409
			in_page = get_node_page(sbi, inode->i_ino);
			if (IS_ERR(in_page)) {
J
Jaegeuk Kim 已提交
410
				alloc_nid_failed(sbi, new_nid);
411
				return PTR_ERR(in_page);
J
Jaegeuk Kim 已提交
412
			}
413
			inline_addr = inline_xattr_addr(inode, in_page);
J
Jaegeuk Kim 已提交
414 415
		}

416 417
		f2fs_wait_on_page_writeback(ipage ? ipage : in_page,
							NODE, true);
J
Jaegeuk Kim 已提交
418 419
		/* no need to use xattr node block */
		if (hsize <= inline_size) {
420
			err = truncate_xattr_node(inode);
J
Jaegeuk Kim 已提交
421
			alloc_nid_failed(sbi, new_nid);
422 423 424 425 426 427 428
			if (err) {
				f2fs_put_page(in_page, 1);
				return err;
			}
			memcpy(inline_addr, txattr_addr, inline_size);
			set_page_dirty(ipage ? ipage : in_page);
			goto in_page_out;
J
Jaegeuk Kim 已提交
429 430 431 432 433 434 435 436
		}
	}

	/* 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);
437
			goto in_page_out;
J
Jaegeuk Kim 已提交
438
		}
439
		f2fs_bug_on(sbi, new_nid);
440
		f2fs_wait_on_page_writeback(xpage, NODE, true);
J
Jaegeuk Kim 已提交
441 442 443
	} else {
		struct dnode_of_data dn;
		set_new_dnode(&dn, inode, NULL, NULL, new_nid);
Y
Yunlei He 已提交
444
		xpage = new_node_page(&dn, XATTR_NODE_OFFSET);
J
Jaegeuk Kim 已提交
445 446
		if (IS_ERR(xpage)) {
			alloc_nid_failed(sbi, new_nid);
447
			goto in_page_out;
J
Jaegeuk Kim 已提交
448 449 450 451
		}
		alloc_nid_done(sbi, new_nid);
	}
	xattr_addr = page_address(xpage);
452 453 454

	if (inline_size)
		memcpy(inline_addr, txattr_addr, inline_size);
455
	memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE);
456 457 458

	if (inline_size)
		set_page_dirty(ipage ? ipage : in_page);
J
Jaegeuk Kim 已提交
459 460
	set_page_dirty(xpage);

461 462 463 464
	f2fs_put_page(xpage, 1);
in_page_out:
	f2fs_put_page(in_page, 1);
	return err;
J
Jaegeuk Kim 已提交
465 466
}

J
Jaegeuk Kim 已提交
467
int f2fs_getxattr(struct inode *inode, int index, const char *name,
468
		void *buffer, size_t buffer_size, struct page *ipage)
469
{
C
Chao Yu 已提交
470
	struct f2fs_xattr_entry *entry = NULL;
471
	int error = 0;
C
Chao Yu 已提交
472 473
	unsigned int size, len;
	void *base_addr = NULL;
474 475 476

	if (name == NULL)
		return -EINVAL;
J
Jaegeuk Kim 已提交
477 478 479

	len = strlen(name);
	if (len > F2FS_NAME_LEN)
480
		return -ERANGE;
481

482
	down_read(&F2FS_I(inode)->i_xattr_sem);
C
Chao Yu 已提交
483 484
	error = lookup_all_xattrs(inode, ipage, index, len, name,
				&entry, &base_addr);
485
	up_read(&F2FS_I(inode)->i_xattr_sem);
486 487
	if (error)
		return error;
488

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

J
Jaegeuk Kim 已提交
491
	if (buffer && size > buffer_size) {
492
		error = -ERANGE;
C
Chao Yu 已提交
493
		goto out;
494 495 496 497
	}

	if (buffer) {
		char *pval = entry->e_name + entry->e_name_len;
J
Jaegeuk Kim 已提交
498
		memcpy(buffer, pval, size);
499
	}
J
Jaegeuk Kim 已提交
500
	error = size;
C
Chao Yu 已提交
501
out:
J
Jaegeuk Kim 已提交
502
	kzfree(base_addr);
503 504 505 506 507
	return error;
}

ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
{
508
	struct inode *inode = d_inode(dentry);
509 510 511 512 513
	struct f2fs_xattr_entry *entry;
	void *base_addr;
	int error = 0;
	size_t rest = buffer_size;

514
	down_read(&F2FS_I(inode)->i_xattr_sem);
515
	error = read_all_xattrs(inode, NULL, &base_addr);
516
	up_read(&F2FS_I(inode)->i_xattr_sem);
517 518
	if (error)
		return error;
519 520 521 522

	list_for_each_xattr(entry, base_addr) {
		const struct xattr_handler *handler =
			f2fs_xattr_handler(entry->e_name_index);
523 524
		const char *prefix;
		size_t prefix_len;
525 526
		size_t size;

527
		if (!handler || (handler->list && !handler->list(dentry)))
528 529
			continue;

530 531 532 533 534 535 536 537 538 539 540 541 542
		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;
543 544 545 546 547
		}
		rest -= size;
	}
	error = buffer_size - rest;
cleanup:
J
Jaegeuk Kim 已提交
548
	kzfree(base_addr);
549 550 551
	return error;
}

552 553 554 555
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;
556 557 558

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

J
Jaegeuk Kim 已提交
561 562
static int __f2fs_setxattr(struct inode *inode, int index,
			const char *name, const void *value, size_t size,
563
			struct page *ipage, int flags)
564 565 566
{
	struct f2fs_xattr_entry *here, *last;
	void *base_addr;
J
Jaegeuk Kim 已提交
567
	int found, newsize;
J
Jaegeuk Kim 已提交
568
	size_t len;
J
Jaegeuk Kim 已提交
569
	__u32 new_hsize;
570
	int error = 0;
571 572 573 574 575

	if (name == NULL)
		return -EINVAL;

	if (value == NULL)
J
Jaegeuk Kim 已提交
576
		size = 0;
577

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

580
	if (len > F2FS_NAME_LEN)
581 582
		return -ERANGE;

583 584 585
	if (size > MAX_VALUE_LEN(inode))
		return -E2BIG;

586 587 588
	error = read_all_xattrs(inode, ipage, &base_addr);
	if (error)
		return error;
589 590

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

593
	found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
594

595 596 597 598 599 600 601 602 603
	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)) {
604 605 606 607 608
		error = -ENODATA;
		goto exit;
	}

	last = here;
609 610 611
	while (!IS_XATTR_LAST_ENTRY(last))
		last = XATTR_NEXT_ENTRY(last);

J
Jaegeuk Kim 已提交
612
	newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size);
613 614 615

	/* 1. Check space */
	if (value) {
J
Jaegeuk Kim 已提交
616 617 618
		int free;
		/*
		 * If value is NULL, it is remove operation.
A
arter97 已提交
619
		 * In case of update operation, we calculate free.
620
		 */
J
Jaegeuk Kim 已提交
621
		free = MIN_OFFSET(inode) - ((char *)last - (char *)base_addr);
622
		if (found)
623
			free = free + ENTRY_SIZE(here);
624

625
		if (unlikely(free < newsize)) {
626
			error = -E2BIG;
J
Jaegeuk Kim 已提交
627
			goto exit;
628 629 630 631 632
		}
	}

	/* 2. Remove old entry */
	if (found) {
J
Jaegeuk Kim 已提交
633 634
		/*
		 * If entry is found, remove old entry.
635 636 637 638 639 640 641 642 643 644
		 * 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 已提交
645 646
	new_hsize = (char *)last - (char *)base_addr;

647 648
	/* 3. Write new entry */
	if (value) {
J
Jaegeuk Kim 已提交
649 650 651 652 653
		char *pval;
		/*
		 * Before we come here, old entry is removed.
		 * We just write new entry.
		 */
J
Jaegeuk Kim 已提交
654 655 656 657 658 659
		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 已提交
660
		new_hsize += newsize;
661 662
	}

J
Jaegeuk Kim 已提交
663 664 665
	error = write_all_xattrs(inode, new_hsize, base_addr, ipage);
	if (error)
		goto exit;
666

667 668
	if (is_inode_flag_set(inode, FI_ACL_MODE)) {
		inode->i_mode = F2FS_I(inode)->i_acl_mode;
669
		inode->i_ctime = current_time(inode);
670
		clear_inode_flag(inode, FI_ACL_MODE);
671
	}
672 673 674
	if (index == F2FS_XATTR_INDEX_ENCRYPTION &&
			!strcmp(name, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT))
		f2fs_set_encrypted_inode(inode);
675
	f2fs_mark_inode_dirty_sync(inode, true);
676 677
	if (!error && S_ISDIR(inode->i_mode))
		set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_CP);
N
Namjae Jeon 已提交
678
exit:
J
Jaegeuk Kim 已提交
679
	kzfree(base_addr);
680 681
	return error;
}
682

J
Jaegeuk Kim 已提交
683 684
int f2fs_setxattr(struct inode *inode, int index, const char *name,
				const void *value, size_t size,
685
				struct page *ipage, int flags)
686
{
687
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
688 689
	int err;

J
Jaegeuk Kim 已提交
690 691 692 693
	err = dquot_initialize(inode);
	if (err)
		return err;

694 695 696 697
	/* this case is only from init_inode_metadata */
	if (ipage)
		return __f2fs_setxattr(inode, index, name, value,
						size, ipage, flags);
J
Jaegeuk Kim 已提交
698
	f2fs_balance_fs(sbi, true);
699

700
	f2fs_lock_op(sbi);
701 702
	/* protect xattr_ver */
	down_write(&F2FS_I(inode)->i_sem);
703
	down_write(&F2FS_I(inode)->i_xattr_sem);
704
	err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags);
705
	up_write(&F2FS_I(inode)->i_xattr_sem);
706
	up_write(&F2FS_I(inode)->i_sem);
707
	f2fs_unlock_op(sbi);
708

709
	f2fs_update_time(sbi, REQ_TIME);
710 711
	return err;
}