xattr.c 33.7 KB
Newer Older
David Teigland's avatar
David Teigland committed
1
2
/*
 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
3
 * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
David Teigland's avatar
David Teigland committed
4
5
6
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
7
 * of the GNU General Public License version 2.
David Teigland's avatar
David Teigland committed
8
9
10
11
12
13
14
 */

#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/xattr.h>
15
#include <linux/gfs2_ondisk.h>
David Teigland's avatar
David Teigland committed
16
17
18
#include <asm/uaccess.h>

#include "gfs2.h"
19
#include "incore.h"
David Teigland's avatar
David Teigland committed
20
#include "acl.h"
21
#include "xattr.h"
David Teigland's avatar
David Teigland committed
22
23
24
25
26
27
#include "glock.h"
#include "inode.h"
#include "meta_io.h"
#include "quota.h"
#include "rgrp.h"
#include "trans.h"
28
#include "util.h"
David Teigland's avatar
David Teigland committed
29
30
31
32
33
34
35
36
37
38
39

/**
 * ea_calc_size - returns the acutal number of bytes the request will take up
 *                (not counting any unstuffed data blocks)
 * @sdp:
 * @er:
 * @size:
 *
 * Returns: 1 if the EA should be stuffed
 */

40
static int ea_calc_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize,
David Teigland's avatar
David Teigland committed
41
42
			unsigned int *size)
{
43
44
45
46
47
48
	unsigned int jbsize = sdp->sd_jbsize;

	/* Stuffed */
	*size = ALIGN(sizeof(struct gfs2_ea_header) + nsize + dsize, 8);

	if (*size <= jbsize)
David Teigland's avatar
David Teigland committed
49
50
		return 1;

51
52
53
	/* Unstuffed */
	*size = ALIGN(sizeof(struct gfs2_ea_header) + nsize +
		      (sizeof(__be64) * DIV_ROUND_UP(dsize, jbsize)), 8);
David Teigland's avatar
David Teigland committed
54
55
56
57

	return 0;
}

58
static int ea_check_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize)
David Teigland's avatar
David Teigland committed
59
60
61
{
	unsigned int size;

62
	if (dsize > GFS2_EA_MAX_DATA_LEN)
David Teigland's avatar
David Teigland committed
63
64
		return -ERANGE;

65
	ea_calc_size(sdp, nsize, dsize, &size);
David Teigland's avatar
David Teigland committed
66
67
68
69
70
71
72
73

	/* This can only happen with 512 byte blocks */
	if (size > sdp->sd_jbsize)
		return -ERANGE;

	return 0;
}

74
typedef int (*ea_call_t) (struct gfs2_inode *ip, struct buffer_head *bh,
David Teigland's avatar
David Teigland committed
75
			  struct gfs2_ea_header *ea,
76
			  struct gfs2_ea_header *prev, void *private);
David Teigland's avatar
David Teigland committed
77
78
79
80
81
82
83

static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh,
			ea_call_t ea_call, void *data)
{
	struct gfs2_ea_header *ea, *prev = NULL;
	int error = 0;

84
	if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_EA))
David Teigland's avatar
David Teigland committed
85
86
87
88
89
		return -EIO;

	for (ea = GFS2_EA_BH2FIRST(bh);; prev = ea, ea = GFS2_EA2NEXT(ea)) {
		if (!GFS2_EA_REC_LEN(ea))
			goto fail;
90
91
		if (!(bh->b_data <= (char *)ea && (char *)GFS2_EA2NEXT(ea) <=
						  bh->b_data + bh->b_size))
David Teigland's avatar
David Teigland committed
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
			goto fail;
		if (!GFS2_EATYPE_VALID(ea->ea_type))
			goto fail;

		error = ea_call(ip, bh, ea, prev, data);
		if (error)
			return error;

		if (GFS2_EA_IS_LAST(ea)) {
			if ((char *)GFS2_EA2NEXT(ea) !=
			    bh->b_data + bh->b_size)
				goto fail;
			break;
		}
	}

	return error;

110
fail:
David Teigland's avatar
David Teigland committed
111
112
113
114
115
116
117
	gfs2_consist_inode(ip);
	return -EIO;
}

static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data)
{
	struct buffer_head *bh, *eabh;
118
	__be64 *eablk, *end;
David Teigland's avatar
David Teigland committed
119
120
	int error;

121
	error = gfs2_meta_read(ip->i_gl, ip->i_eattr, DIO_WAIT, &bh);
David Teigland's avatar
David Teigland committed
122
123
124
	if (error)
		return error;

125
	if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT)) {
David Teigland's avatar
David Teigland committed
126
127
128
129
		error = ea_foreach_i(ip, bh, ea_call, data);
		goto out;
	}

130
	if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_IN)) {
David Teigland's avatar
David Teigland committed
131
132
133
134
		error = -EIO;
		goto out;
	}

135
	eablk = (__be64 *)(bh->b_data + sizeof(struct gfs2_meta_header));
136
	end = eablk + GFS2_SB(&ip->i_inode)->sd_inptrs;
David Teigland's avatar
David Teigland committed
137
138

	for (; eablk < end; eablk++) {
139
		u64 bn;
David Teigland's avatar
David Teigland committed
140
141
142
143
144

		if (!*eablk)
			break;
		bn = be64_to_cpu(*eablk);

145
		error = gfs2_meta_read(ip->i_gl, bn, DIO_WAIT, &eabh);
David Teigland's avatar
David Teigland committed
146
147
148
149
150
151
152
		if (error)
			break;
		error = ea_foreach_i(ip, eabh, ea_call, data);
		brelse(eabh);
		if (error)
			break;
	}
153
out:
David Teigland's avatar
David Teigland committed
154
155
156
157
158
	brelse(bh);
	return error;
}

struct ea_find {
159
160
161
	int type;
	const char *name;
	size_t namel;
David Teigland's avatar
David Teigland committed
162
163
164
165
166
167
168
169
170
171
172
173
	struct gfs2_ea_location *ef_el;
};

static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh,
		     struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
		     void *private)
{
	struct ea_find *ef = private;

	if (ea->ea_type == GFS2_EATYPE_UNUSED)
		return 0;

174
175
176
	if (ea->ea_type == ef->type) {
		if (ea->ea_name_len == ef->namel &&
		    !memcmp(GFS2_EA2NAME(ea), ef->name, ea->ea_name_len)) {
David Teigland's avatar
David Teigland committed
177
178
179
180
181
182
183
184
185
186
187
188
			struct gfs2_ea_location *el = ef->ef_el;
			get_bh(bh);
			el->el_bh = bh;
			el->el_ea = ea;
			el->el_prev = prev;
			return 1;
		}
	}

	return 0;
}

189
int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name,
David Teigland's avatar
David Teigland committed
190
191
192
193
194
		 struct gfs2_ea_location *el)
{
	struct ea_find ef;
	int error;

195
196
197
	ef.type = type;
	ef.name = name;
	ef.namel = strlen(name);
David Teigland's avatar
David Teigland committed
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
	ef.ef_el = el;

	memset(el, 0, sizeof(struct gfs2_ea_location));

	error = ea_foreach(ip, ea_find_i, &ef);
	if (error > 0)
		return 0;

	return error;
}

/**
 * ea_dealloc_unstuffed -
 * @ip:
 * @bh:
 * @ea:
 * @prev:
 * @private:
 *
 * Take advantage of the fact that all unstuffed blocks are
 * allocated from the same RG.  But watch, this may not always
 * be true.
 *
 * Returns: errno
 */

static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
				struct gfs2_ea_header *ea,
				struct gfs2_ea_header *prev, void *private)
{
	int *leave = private;
229
	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
David Teigland's avatar
David Teigland committed
230
231
232
	struct gfs2_rgrpd *rgd;
	struct gfs2_holder rg_gh;
	struct buffer_head *dibh;
233
234
	__be64 *dataptrs;
	u64 bn = 0;
235
	u64 bstart = 0;
David Teigland's avatar
David Teigland committed
236
237
238
239
240
241
242
243
244
	unsigned int blen = 0;
	unsigned int blks = 0;
	unsigned int x;
	int error;

	if (GFS2_EA_IS_STUFFED(ea))
		return 0;

	dataptrs = GFS2_EA2DATAPTRS(ea);
245
	for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) {
David Teigland's avatar
David Teigland committed
246
247
248
249
		if (*dataptrs) {
			blks++;
			bn = be64_to_cpu(*dataptrs);
		}
250
	}
David Teigland's avatar
David Teigland committed
251
252
253
254
255
256
257
258
259
260
261
262
263
	if (!blks)
		return 0;

	rgd = gfs2_blk2rgrpd(sdp, bn);
	if (!rgd) {
		gfs2_consist_inode(ip);
		return -EIO;
	}

	error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
	if (error)
		return error;

264
	error = gfs2_trans_begin(sdp, rgd->rd_length + RES_DINODE +
265
				 RES_EATTR + RES_STATFS + RES_QUOTA, blks);
David Teigland's avatar
David Teigland committed
266
267
268
	if (error)
		goto out_gunlock;

269
	gfs2_trans_add_bh(ip->i_gl, bh, 1);
David Teigland's avatar
David Teigland committed
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286

	dataptrs = GFS2_EA2DATAPTRS(ea);
	for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) {
		if (!*dataptrs)
			break;
		bn = be64_to_cpu(*dataptrs);

		if (bstart + blen == bn)
			blen++;
		else {
			if (bstart)
				gfs2_free_meta(ip, bstart, blen);
			bstart = bn;
			blen = 1;
		}

		*dataptrs = 0;
287
		gfs2_add_inode_blocks(&ip->i_inode, -1);
David Teigland's avatar
David Teigland committed
288
289
290
291
292
	}
	if (bstart)
		gfs2_free_meta(ip, bstart, blen);

	if (prev && !leave) {
293
		u32 len;
David Teigland's avatar
David Teigland committed
294
295
296
297
298
299
300
301
302
303
304
305
306

		len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea);
		prev->ea_rec_len = cpu_to_be32(len);

		if (GFS2_EA_IS_LAST(ea))
			prev->ea_flags |= GFS2_EAFLAG_LAST;
	} else {
		ea->ea_type = GFS2_EATYPE_UNUSED;
		ea->ea_num_ptrs = 0;
	}

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (!error) {
307
		ip->i_inode.i_ctime = CURRENT_TIME;
308
		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
309
		gfs2_dinode_out(ip, dibh->b_data);
David Teigland's avatar
David Teigland committed
310
311
312
313
314
		brelse(dibh);
	}

	gfs2_trans_end(sdp);

315
out_gunlock:
David Teigland's avatar
David Teigland committed
316
317
318
319
320
321
322
323
324
325
326
327
	gfs2_glock_dq_uninit(&rg_gh);
	return error;
}

static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
			       struct gfs2_ea_header *ea,
			       struct gfs2_ea_header *prev, int leave)
{
	struct gfs2_alloc *al;
	int error;

	al = gfs2_alloc_get(ip);
328
329
	if (!al)
		return -ENOMEM;
David Teigland's avatar
David Teigland committed
330
331
332
333
334

	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
	if (error)
		goto out_alloc;

335
	error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
David Teigland's avatar
David Teigland committed
336
337
338
	if (error)
		goto out_quota;

339
	error = ea_dealloc_unstuffed(ip, bh, ea, prev, (leave) ? &error : NULL);
David Teigland's avatar
David Teigland committed
340
341
342

	gfs2_glock_dq_uninit(&al->al_ri_gh);

343
out_quota:
David Teigland's avatar
David Teigland committed
344
	gfs2_quota_unhold(ip);
345
out_alloc:
David Teigland's avatar
David Teigland committed
346
347
348
349
350
351
352
353
354
	gfs2_alloc_put(ip);
	return error;
}

struct ea_list {
	struct gfs2_ea_request *ei_er;
	unsigned int ei_size;
};

355
356
357
358
359
360
361
362
363
364
365
366
367
368
static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea)
{
	switch (ea->ea_type) {
	case GFS2_EATYPE_USR:
		return 5 + ea->ea_name_len + 1;
	case GFS2_EATYPE_SYS:
		return 7 + ea->ea_name_len + 1;
	case GFS2_EATYPE_SECURITY:
		return 9 + ea->ea_name_len + 1;
	default:
		return 0;
	}
}

David Teigland's avatar
David Teigland committed
369
370
371
372
373
374
static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh,
		     struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
		     void *private)
{
	struct ea_list *ei = private;
	struct gfs2_ea_request *er = ei->ei_er;
Ryan O'Hara's avatar
Ryan O'Hara committed
375
	unsigned int ea_size = gfs2_ea_strlen(ea);
David Teigland's avatar
David Teigland committed
376
377
378
379
380

	if (ea->ea_type == GFS2_EATYPE_UNUSED)
		return 0;

	if (er->er_data_len) {
381
382
		char *prefix = NULL;
		unsigned int l = 0;
David Teigland's avatar
David Teigland committed
383
384
385
386
387
		char c = 0;

		if (ei->ei_size + ea_size > er->er_data_len)
			return -ERANGE;

Ryan O'Hara's avatar
Ryan O'Hara committed
388
389
		switch (ea->ea_type) {
		case GFS2_EATYPE_USR:
David Teigland's avatar
David Teigland committed
390
391
			prefix = "user.";
			l = 5;
Ryan O'Hara's avatar
Ryan O'Hara committed
392
393
			break;
		case GFS2_EATYPE_SYS:
David Teigland's avatar
David Teigland committed
394
395
			prefix = "system.";
			l = 7;
Ryan O'Hara's avatar
Ryan O'Hara committed
396
397
398
399
400
			break;
		case GFS2_EATYPE_SECURITY:
			prefix = "security.";
			l = 9;
			break;
David Teigland's avatar
David Teigland committed
401
402
		}

403
404
		BUG_ON(l == 0);

405
406
		memcpy(er->er_data + ei->ei_size, prefix, l);
		memcpy(er->er_data + ei->ei_size + l, GFS2_EA2NAME(ea),
David Teigland's avatar
David Teigland committed
407
		       ea->ea_name_len);
408
		memcpy(er->er_data + ei->ei_size + ea_size - 1, &c, 1);
David Teigland's avatar
David Teigland committed
409
410
411
412
413
414
415
416
	}

	ei->ei_size += ea_size;

	return 0;
}

/**
417
418
419
420
 * gfs2_listxattr - List gfs2 extended attributes
 * @dentry: The dentry whose inode we are interested in
 * @buffer: The buffer to write the results
 * @size: The size of the buffer
David Teigland's avatar
David Teigland committed
421
422
423
424
 *
 * Returns: actual size of data on success, -errno on error
 */

425
ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
David Teigland's avatar
David Teigland committed
426
{
427
428
	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
	struct gfs2_ea_request er;
David Teigland's avatar
David Teigland committed
429
430
431
	struct gfs2_holder i_gh;
	int error;

432
433
434
435
	memset(&er, 0, sizeof(struct gfs2_ea_request));
	if (size) {
		er.er_data = buffer;
		er.er_data_len = size;
David Teigland's avatar
David Teigland committed
436
437
	}

438
	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
David Teigland's avatar
David Teigland committed
439
440
441
	if (error)
		return error;

442
	if (ip->i_eattr) {
443
		struct ea_list ei = { .ei_er = &er, .ei_size = 0 };
David Teigland's avatar
David Teigland committed
444
445
446
447
448
449
450
451
452
453
454
455
456
457

		error = ea_foreach(ip, ea_list_i, &ei);
		if (!error)
			error = ei.ei_size;
	}

	gfs2_glock_dq_uninit(&i_gh);

	return error;
}

/**
 * ea_get_unstuffed - actually copies the unstuffed data into the
 *                    request buffer
458
459
460
 * @ip: The GFS2 inode
 * @ea: The extended attribute header structure
 * @data: The data to be copied
David Teigland's avatar
David Teigland committed
461
462
463
464
465
466
467
 *
 * Returns: errno
 */

static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
			    char *data)
{
468
	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
David Teigland's avatar
David Teigland committed
469
470
	struct buffer_head **bh;
	unsigned int amount = GFS2_EA_DATA_LEN(ea);
471
	unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize);
472
	__be64 *dataptrs = GFS2_EA2DATAPTRS(ea);
David Teigland's avatar
David Teigland committed
473
474
475
	unsigned int x;
	int error = 0;

Josef Bacik's avatar
Josef Bacik committed
476
	bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_NOFS);
David Teigland's avatar
David Teigland committed
477
478
479
480
	if (!bh)
		return -ENOMEM;

	for (x = 0; x < nptrs; x++) {
481
482
		error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0,
				       bh + x);
David Teigland's avatar
David Teigland committed
483
484
485
486
487
488
489
490
491
		if (error) {
			while (x--)
				brelse(bh[x]);
			goto out;
		}
		dataptrs++;
	}

	for (x = 0; x < nptrs; x++) {
492
		error = gfs2_meta_wait(sdp, bh[x]);
David Teigland's avatar
David Teigland committed
493
494
495
496
497
498
499
500
501
502
503
504
		if (error) {
			for (; x < nptrs; x++)
				brelse(bh[x]);
			goto out;
		}
		if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) {
			for (; x < nptrs; x++)
				brelse(bh[x]);
			error = -EIO;
			goto out;
		}

505
		memcpy(data, bh[x]->b_data + sizeof(struct gfs2_meta_header),
David Teigland's avatar
David Teigland committed
506
507
508
509
510
511
512
513
		       (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize);

		amount -= sdp->sd_jbsize;
		data += sdp->sd_jbsize;

		brelse(bh[x]);
	}

514
out:
David Teigland's avatar
David Teigland committed
515
516
517
518
519
	kfree(bh);
	return error;
}

int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el,
520
		     char *data, size_t size)
David Teigland's avatar
David Teigland committed
521
{
522
523
524
525
526
	int ret;
	size_t len = GFS2_EA_DATA_LEN(el->el_ea);
	if (len > size)
		return -ERANGE;

David Teigland's avatar
David Teigland committed
527
	if (GFS2_EA_IS_STUFFED(el->el_ea)) {
528
529
530
531
532
533
534
		memcpy(data, GFS2_EA2DATA(el->el_ea), len);
		return len;
	}
	ret = ea_get_unstuffed(ip, el->el_ea, data);
	if (ret < 0)
		return ret;
	return len;
David Teigland's avatar
David Teigland committed
535
536
537
}

/**
538
539
540
541
542
543
 * gfs2_xattr_get - Get a GFS2 extended attribute
 * @inode: The inode
 * @type: The type of extended attribute
 * @name: The name of the extended attribute
 * @buffer: The buffer to write the result into
 * @size: The size of the buffer
David Teigland's avatar
David Teigland committed
544
545
546
547
 *
 * Returns: actual size of data on success, -errno on error
 */

548
549
int gfs2_xattr_get(struct inode *inode, int type, const char *name,
		   void *buffer, size_t size)
David Teigland's avatar
David Teigland committed
550
{
551
	struct gfs2_inode *ip = GFS2_I(inode);
David Teigland's avatar
David Teigland committed
552
553
554
	struct gfs2_ea_location el;
	int error;

555
	if (!ip->i_eattr)
David Teigland's avatar
David Teigland committed
556
		return -ENODATA;
557
558
	if (strlen(name) > GFS2_EA_MAX_NAME_LEN)
		return -EINVAL;
David Teigland's avatar
David Teigland committed
559

560
	error = gfs2_ea_find(ip, type, name, &el);
David Teigland's avatar
David Teigland committed
561
562
563
564
	if (error)
		return error;
	if (!el.el_ea)
		return -ENODATA;
565
566
567
	if (size) 
		error = gfs2_ea_get_copy(ip, &el, buffer, size);
	else
David Teigland's avatar
David Teigland committed
568
569
570
571
572
573
574
575
576
		error = GFS2_EA_DATA_LEN(el.el_ea);
	brelse(el.el_bh);

	return error;
}

/**
 * ea_alloc_blk - allocates a new block for extended attributes.
 * @ip: A pointer to the inode that's getting extended attributes
577
 * @bhp: Pointer to pointer to a struct buffer_head
David Teigland's avatar
David Teigland committed
578
579
580
581
582
583
 *
 * Returns: errno
 */

static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp)
{
584
	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
David Teigland's avatar
David Teigland committed
585
	struct gfs2_ea_header *ea;
586
	unsigned int n = 1;
587
	u64 block;
588
	int error;
David Teigland's avatar
David Teigland committed
589

590
591
592
	error = gfs2_alloc_block(ip, &block, &n);
	if (error)
		return error;
593
	gfs2_trans_add_unrevoke(sdp, block, 1);
David Teigland's avatar
David Teigland committed
594
	*bhp = gfs2_meta_new(ip->i_gl, block);
595
	gfs2_trans_add_bh(ip->i_gl, *bhp, 1);
David Teigland's avatar
David Teigland committed
596
597
598
599
600
601
602
603
604
	gfs2_metatype_set(*bhp, GFS2_METATYPE_EA, GFS2_FORMAT_EA);
	gfs2_buffer_clear_tail(*bhp, sizeof(struct gfs2_meta_header));

	ea = GFS2_EA_BH2FIRST(*bhp);
	ea->ea_rec_len = cpu_to_be32(sdp->sd_jbsize);
	ea->ea_type = GFS2_EATYPE_UNUSED;
	ea->ea_flags = GFS2_EAFLAG_LAST;
	ea->ea_num_ptrs = 0;

605
	gfs2_add_inode_blocks(&ip->i_inode, 1);
David Teigland's avatar
David Teigland committed
606
607
608
609
610
611
612

	return 0;
}

/**
 * ea_write - writes the request info to an ea, creating new blocks if
 *            necessary
613
614
 * @ip: inode that is being modified
 * @ea: the location of the new ea in a block
David Teigland's avatar
David Teigland committed
615
616
617
618
619
620
621
622
623
624
 * @er: the write request
 *
 * Note: does not update ea_rec_len or the GFS2_EAFLAG_LAST bin of ea_flags
 *
 * returns : errno
 */

static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
		    struct gfs2_ea_request *er)
{
625
	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
626
	int error;
David Teigland's avatar
David Teigland committed
627
628
629
630
631
632
633
634
635
636
637
638

	ea->ea_data_len = cpu_to_be32(er->er_data_len);
	ea->ea_name_len = er->er_name_len;
	ea->ea_type = er->er_type;
	ea->__pad = 0;

	memcpy(GFS2_EA2NAME(ea), er->er_name, er->er_name_len);

	if (GFS2_EAREQ_SIZE_STUFFED(er) <= sdp->sd_jbsize) {
		ea->ea_num_ptrs = 0;
		memcpy(GFS2_EA2DATA(ea), er->er_data, er->er_data_len);
	} else {
639
		__be64 *dataptr = GFS2_EA2DATAPTRS(ea);
David Teigland's avatar
David Teigland committed
640
641
642
643
644
		const char *data = er->er_data;
		unsigned int data_len = er->er_data_len;
		unsigned int copy;
		unsigned int x;

645
		ea->ea_num_ptrs = DIV_ROUND_UP(er->er_data_len, sdp->sd_jbsize);
David Teigland's avatar
David Teigland committed
646
647
		for (x = 0; x < ea->ea_num_ptrs; x++) {
			struct buffer_head *bh;
648
			u64 block;
David Teigland's avatar
David Teigland committed
649
			int mh_size = sizeof(struct gfs2_meta_header);
650
			unsigned int n = 1;
David Teigland's avatar
David Teigland committed
651

652
653
654
			error = gfs2_alloc_block(ip, &block, &n);
			if (error)
				return error;
655
			gfs2_trans_add_unrevoke(sdp, block, 1);
David Teigland's avatar
David Teigland committed
656
			bh = gfs2_meta_new(ip->i_gl, block);
657
			gfs2_trans_add_bh(ip->i_gl, bh, 1);
David Teigland's avatar
David Teigland committed
658
659
			gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED);

660
			gfs2_add_inode_blocks(&ip->i_inode, 1);
David Teigland's avatar
David Teigland committed
661

662
663
			copy = data_len > sdp->sd_jbsize ? sdp->sd_jbsize :
							   data_len;
David Teigland's avatar
David Teigland committed
664
665
666
667
668
			memcpy(bh->b_data + mh_size, data, copy);
			if (copy < sdp->sd_jbsize)
				memset(bh->b_data + mh_size + copy, 0,
				       sdp->sd_jbsize - copy);

669
			*dataptr++ = cpu_to_be64(bh->b_blocknr);
David Teigland's avatar
David Teigland committed
670
671
672
673
674
675
676
677
678
679
680
681
682
			data += copy;
			data_len -= copy;

			brelse(bh);
		}

		gfs2_assert_withdraw(sdp, !data_len);
	}

	return 0;
}

typedef int (*ea_skeleton_call_t) (struct gfs2_inode *ip,
683
				   struct gfs2_ea_request *er, void *private);
David Teigland's avatar
David Teigland committed
684
685
686

static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
			     unsigned int blks,
687
			     ea_skeleton_call_t skeleton_call, void *private)
David Teigland's avatar
David Teigland committed
688
689
690
691
692
693
{
	struct gfs2_alloc *al;
	struct buffer_head *dibh;
	int error;

	al = gfs2_alloc_get(ip);
694
695
	if (!al)
		return -ENOMEM;
David Teigland's avatar
David Teigland committed
696

697
	error = gfs2_quota_lock_check(ip);
David Teigland's avatar
David Teigland committed
698
699
700
701
702
703
704
705
706
	if (error)
		goto out;

	al->al_requested = blks;

	error = gfs2_inplace_reserve(ip);
	if (error)
		goto out_gunlock_q;

707
	error = gfs2_trans_begin(GFS2_SB(&ip->i_inode),
708
				 blks + al->al_rgd->rd_length +
David Teigland's avatar
David Teigland committed
709
710
711
712
713
714
715
716
717
718
				 RES_DINODE + RES_STATFS + RES_QUOTA, 0);
	if (error)
		goto out_ipres;

	error = skeleton_call(ip, er, private);
	if (error)
		goto out_end_trans;

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (!error) {
719
		ip->i_inode.i_ctime = CURRENT_TIME;
720
		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
721
		gfs2_dinode_out(ip, dibh->b_data);
David Teigland's avatar
David Teigland committed
722
723
724
		brelse(dibh);
	}

725
out_end_trans:
726
	gfs2_trans_end(GFS2_SB(&ip->i_inode));
727
out_ipres:
David Teigland's avatar
David Teigland committed
728
	gfs2_inplace_release(ip);
729
out_gunlock_q:
David Teigland's avatar
David Teigland committed
730
	gfs2_quota_unlock(ip);
731
out:
David Teigland's avatar
David Teigland committed
732
733
734
735
736
737
738
739
740
741
742
743
744
745
	gfs2_alloc_put(ip);
	return error;
}

static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er,
		     void *private)
{
	struct buffer_head *bh;
	int error;

	error = ea_alloc_blk(ip, &bh);
	if (error)
		return error;

746
	ip->i_eattr = bh->b_blocknr;
David Teigland's avatar
David Teigland committed
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
	error = ea_write(ip, GFS2_EA_BH2FIRST(bh), er);

	brelse(bh);

	return error;
}

/**
 * ea_init - initializes a new eattr block
 * @ip:
 * @er:
 *
 * Returns: errno
 */

762
763
static int ea_init(struct gfs2_inode *ip, int type, const char *name,
		   const void *data, size_t size)
David Teigland's avatar
David Teigland committed
764
{
765
	struct gfs2_ea_request er;
766
	unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize;
David Teigland's avatar
David Teigland committed
767
768
	unsigned int blks = 1;

769
770
771
772
773
774
775
776
	er.er_type = type;
	er.er_name = name;
	er.er_name_len = strlen(name);
	er.er_data = (void *)data;
	er.er_data_len = size;

	if (GFS2_EAREQ_SIZE_STUFFED(&er) > jbsize)
		blks += DIV_ROUND_UP(er.er_data_len, jbsize);
David Teigland's avatar
David Teigland committed
777

778
	return ea_alloc_skeleton(ip, &er, blks, ea_init_i, NULL);
David Teigland's avatar
David Teigland committed
779
780
781
782
}

static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea)
{
783
	u32 ea_size = GFS2_EA_SIZE(ea);
784
785
	struct gfs2_ea_header *new = (struct gfs2_ea_header *)((char *)ea +
				     ea_size);
786
	u32 new_size = GFS2_EA_REC_LEN(ea) - ea_size;
David Teigland's avatar
David Teigland committed
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
	int last = ea->ea_flags & GFS2_EAFLAG_LAST;

	ea->ea_rec_len = cpu_to_be32(ea_size);
	ea->ea_flags ^= last;

	new->ea_rec_len = cpu_to_be32(new_size);
	new->ea_flags = last;

	return new;
}

static void ea_set_remove_stuffed(struct gfs2_inode *ip,
				  struct gfs2_ea_location *el)
{
	struct gfs2_ea_header *ea = el->el_ea;
	struct gfs2_ea_header *prev = el->el_prev;
803
	u32 len;
David Teigland's avatar
David Teigland committed
804

805
	gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
David Teigland's avatar
David Teigland committed
806
807
808
809
810
811

	if (!prev || !GFS2_EA_IS_STUFFED(ea)) {
		ea->ea_type = GFS2_EATYPE_UNUSED;
		return;
	} else if (GFS2_EA2NEXT(prev) != ea) {
		prev = GFS2_EA2NEXT(prev);
812
		gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), GFS2_EA2NEXT(prev) == ea);
David Teigland's avatar
David Teigland committed
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
	}

	len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea);
	prev->ea_rec_len = cpu_to_be32(len);

	if (GFS2_EA_IS_LAST(ea))
		prev->ea_flags |= GFS2_EAFLAG_LAST;
}

struct ea_set {
	int ea_split;

	struct gfs2_ea_request *es_er;
	struct gfs2_ea_location *es_el;

	struct buffer_head *es_bh;
	struct gfs2_ea_header *es_ea;
};

static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh,
				 struct gfs2_ea_header *ea, struct ea_set *es)
{
	struct gfs2_ea_request *er = es->es_er;
	struct buffer_head *dibh;
	int error;

839
	error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + 2 * RES_EATTR, 0);
David Teigland's avatar
David Teigland committed
840
841
842
	if (error)
		return error;

843
	gfs2_trans_add_bh(ip->i_gl, bh, 1);
David Teigland's avatar
David Teigland committed
844
845
846
847
848
849
850
851
852
853
854
855

	if (es->ea_split)
		ea = ea_split_ea(ea);

	ea_write(ip, ea, er);

	if (es->es_el)
		ea_set_remove_stuffed(ip, es->es_el);

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (error)
		goto out;
856
	ip->i_inode.i_ctime = CURRENT_TIME;
857
	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
858
	gfs2_dinode_out(ip, dibh->b_data);
David Teigland's avatar
David Teigland committed
859
	brelse(dibh);
860
out:
861
	gfs2_trans_end(GFS2_SB(&ip->i_inode));
David Teigland's avatar
David Teigland committed
862
863
864
865
866
867
868
869
870
871
	return error;
}

static int ea_set_simple_alloc(struct gfs2_inode *ip,
			       struct gfs2_ea_request *er, void *private)
{
	struct ea_set *es = private;
	struct gfs2_ea_header *ea = es->es_ea;
	int error;

872
	gfs2_trans_add_bh(ip->i_gl, es->es_bh, 1);
David Teigland's avatar
David Teigland committed
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895

	if (es->ea_split)
		ea = ea_split_ea(ea);

	error = ea_write(ip, ea, er);
	if (error)
		return error;

	if (es->es_el)
		ea_set_remove_stuffed(ip, es->es_el);

	return 0;
}

static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh,
			 struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
			 void *private)
{
	struct ea_set *es = private;
	unsigned int size;
	int stuffed;
	int error;

896
897
	stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er->er_name_len,
			       es->es_er->er_data_len, &size);
David Teigland's avatar
David Teigland committed
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921

	if (ea->ea_type == GFS2_EATYPE_UNUSED) {
		if (GFS2_EA_REC_LEN(ea) < size)
			return 0;
		if (!GFS2_EA_IS_STUFFED(ea)) {
			error = ea_remove_unstuffed(ip, bh, ea, prev, 1);
			if (error)
				return error;
		}
		es->ea_split = 0;
	} else if (GFS2_EA_REC_LEN(ea) - GFS2_EA_SIZE(ea) >= size)
		es->ea_split = 1;
	else
		return 0;

	if (stuffed) {
		error = ea_set_simple_noalloc(ip, bh, ea, es);
		if (error)
			return error;
	} else {
		unsigned int blks;

		es->es_bh = bh;
		es->es_ea = ea;
922
		blks = 2 + DIV_ROUND_UP(es->es_er->er_data_len,
923
					GFS2_SB(&ip->i_inode)->sd_jbsize);
David Teigland's avatar
David Teigland committed
924
925
926
927
928
929
930
931
932
933
934
935
936

		error = ea_alloc_skeleton(ip, es->es_er, blks,
					  ea_set_simple_alloc, es);
		if (error)
			return error;
	}

	return 1;
}

static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er,
			void *private)
{
937
	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
David Teigland's avatar
David Teigland committed
938
	struct buffer_head *indbh, *newbh;
939
	__be64 *eablk;
David Teigland's avatar
David Teigland committed
940
941
942
	int error;
	int mh_size = sizeof(struct gfs2_meta_header);

943
	if (ip->i_diskflags & GFS2_DIF_EA_INDIRECT) {
944
		__be64 *end;
David Teigland's avatar
David Teigland committed
945

946
		error = gfs2_meta_read(ip->i_gl, ip->i_eattr, DIO_WAIT,
947
				       &indbh);
David Teigland's avatar
David Teigland committed
948
949
950
951
952
953
954
955
		if (error)
			return error;

		if (gfs2_metatype_check(sdp, indbh, GFS2_METATYPE_IN)) {
			error = -EIO;
			goto out;
		}

956
		eablk = (__be64 *)(indbh->b_data + mh_size);
David Teigland's avatar
David Teigland committed
957
958
959
960
961
962
963
964
965
966
967
		end = eablk + sdp->sd_inptrs;

		for (; eablk < end; eablk++)
			if (!*eablk)
				break;

		if (eablk == end) {
			error = -ENOSPC;
			goto out;
		}

968
		gfs2_trans_add_bh(ip->i_gl, indbh, 1);
David Teigland's avatar
David Teigland committed
969
	} else {
970
		u64 blk;
971
		unsigned int n = 1;
972
973
974
		error = gfs2_alloc_block(ip, &blk, &n);
		if (error)
			return error;
975
		gfs2_trans_add_unrevoke(sdp, blk, 1);
David Teigland's avatar
David Teigland committed
976
		indbh = gfs2_meta_new(ip->i_gl, blk);
977
		gfs2_trans_add_bh(ip->i_gl, indbh, 1);
David Teigland's avatar
David Teigland committed
978
979
980
		gfs2_metatype_set(indbh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
		gfs2_buffer_clear_tail(indbh, mh_size);

981
		eablk = (__be64 *)(indbh->b_data + mh_size);
982
983
		*eablk = cpu_to_be64(ip->i_eattr);
		ip->i_eattr = blk;
984
		ip->i_diskflags |= GFS2_DIF_EA_INDIRECT;
985
		gfs2_add_inode_blocks(&ip->i_inode, 1);
David Teigland's avatar
David Teigland committed
986
987
988
989
990
991
992
993

		eablk++;
	}

	error = ea_alloc_blk(ip, &newbh);
	if (error)
		goto out;

994
	*eablk = cpu_to_be64((u64)newbh->b_blocknr);
David Teigland's avatar
David Teigland committed
995
996
997
998
999
1000
	error = ea_write(ip, GFS2_EA_BH2FIRST(newbh), er);
	brelse(newbh);
	if (error)
		goto out;

	if (private)
1001
		ea_set_remove_stuffed(ip, private);
David Teigland's avatar
David Teigland committed
1002

1003
out:
David Teigland's avatar
David Teigland committed
1004
1005
1006
1007
	brelse(indbh);
	return error;
}

1008
1009
static int ea_set_i(struct gfs2_inode *ip, int type, const char *name,
		    const void *value, size_t size, struct gfs2_ea_location *el)
David Teigland's avatar
David Teigland committed
1010
{
1011
	struct gfs2_ea_request er;
David Teigland's avatar
David Teigland committed
1012
1013
1014
1015
	struct ea_set es;
	unsigned int blks = 2;
	int error;

1016
1017
1018
1019
1020
1021
	er.er_type = type;
	er.er_name = name;
	er.er_data = (void *)value;
	er.er_name_len = strlen(name);
	er.er_data_len = size;

David Teigland's avatar
David Teigland committed
1022
	memset(&es, 0, sizeof(struct ea_set));
1023
	es.es_er = &er;
David Teigland's avatar
David Teigland committed
1024
1025
1026
1027
1028
1029
1030
1031
	es.es_el = el;

	error = ea_foreach(ip, ea_set_simple, &es);
	if (error > 0)
		return 0;
	if (error)
		return error;

1032
	if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT))
David Teigland's avatar
David Teigland committed
1033
		blks++;
1034
1035
	if (GFS2_EAREQ_SIZE_STUFFED(&er) > GFS2_SB(&ip->i_inode)->sd_jbsize)
		blks += DIV_ROUND_UP(er.er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize);
David Teigland's avatar
David Teigland committed
1036

1037
	return ea_alloc_skeleton(ip, &er, blks, ea_set_block, el);
David Teigland's avatar
David Teigland committed
1038
1039
1040
1041
1042
1043
1044
}

static int ea_set_remove_unstuffed(struct gfs2_inode *ip,
				   struct gfs2_ea_location *el)
{
	if (el->el_prev && GFS2_EA2NEXT(el->el_prev) != el->el_ea) {
		el->el_prev = GFS2_EA2NEXT(el->el_prev);
1045
		gfs2_assert_withdraw(GFS2_SB(&ip->i_inode),
David Teigland's avatar
David Teigland committed
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
				     GFS2_EA2NEXT(el->el_prev) == el->el_ea);
	}

	return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0);
}

static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
{
	struct gfs2_ea_header *ea = el->el_ea;
	struct gfs2_ea_header *prev = el->el_prev;
	struct buffer_head *dibh;
	int error;

1059
	error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0);
David Teigland's avatar
David Teigland committed
1060
1061
1062
	if (error)
		return error;

1063
	gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
David Teigland's avatar
David Teigland committed
1064
1065

	if (prev) {
1066
		u32 len;
David Teigland's avatar
David Teigland committed
1067
1068
1069
1070
1071
1072

		len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea);
		prev->ea_rec_len = cpu_to_be32(len);

		if (GFS2_EA_IS_LAST(ea))
			prev->ea_flags |= GFS2_EAFLAG_LAST;
1073
	} else {
David Teigland's avatar
David Teigland committed
1074
		ea->ea_type = GFS2_EATYPE_UNUSED;
1075
	}
David Teigland's avatar
David Teigland committed
1076
1077
1078

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (!error) {
1079
		ip->i_inode.i_ctime = CURRENT_TIME;
1080
		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
1081
		gfs2_dinode_out(ip, dibh->b_data);
David Teigland's avatar
David Teigland committed
1082
		brelse(dibh);
1083
	}
David Teigland's avatar
David Teigland committed
1084

1085
	gfs2_trans_end(GFS2_SB(&ip->i_inode));
David Teigland's avatar
David Teigland committed
1086
1087
1088
1089

	return error;
}

1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
/**
 * gfs2_xattr_remove - Remove a GFS2 extended attribute
 * @inode: The inode
 * @type: The type of the extended attribute
 * @name: The name of the extended attribute
 *
 * This is not called directly by the VFS since we use the (common)
 * scheme of making a "set with NULL data" mean a remove request. Note
 * that this is different from a set with zero length data.
 *
 * Returns: 0, or errno on failure
 */

static int gfs2_xattr_remove(struct inode *inode, int type, const char *name)
David Teigland's avatar
David Teigland committed
1104
{
1105
	struct gfs2_inode *ip = GFS2_I(inode);
David Teigland's avatar
David Teigland committed
1106
1107
1108
	struct gfs2_ea_location el;
	int error;

1109
	if (!ip->i_eattr)
David Teigland's avatar
David Teigland committed
1110
1111
		return -ENODATA;

1112
	error = gfs2_ea_find(ip, type, name, &el);
David Teigland's avatar
David Teigland committed
1113
1114
1115
1116
1117
1118
1119
1120
	if (error)
		return error;
	if (!el.el_ea)
		return -ENODATA;

	if (GFS2_EA_IS_STUFFED(el.el_ea))
		error = ea_remove_stuffed(ip, &el);
	else
1121
		error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, 0);
David Teigland's avatar
David Teigland committed
1122
1123
1124
1125
1126
1127
1128

	brelse(el.el_bh);

	return error;
}

/**
1129
1130
1131
1132
1133
1134
1135
 * gfs2_xattr_set - Set (or remove) a GFS2 extended attribute
 * @inode: The inode
 * @type: The type of the extended attribute
 * @name: The name of the extended attribute
 * @value: The value of the extended attribute (NULL for remove)
 * @size: The size of the @value argument
 * @flags: Create or Replace
David Teigland's avatar
David Teigland committed
1136
 *
1137
1138
1139
 * See gfs2_xattr_remove() for details of the removal of xattrs.
 *
 * Returns: 0 or errno on failure
David Teigland's avatar
David Teigland committed
1140
1141
 */

1142
1143
int gfs2_xattr_set(struct inode *inode, int type, const char *name,
		   const void *value, size_t size, int flags)
David Teigland's avatar
David Teigland committed
1144
{
1145
1146
1147
1148
	struct gfs2_sbd *sdp = GFS2_SB(inode);
	struct gfs2_inode *ip = GFS2_I(inode);
	struct gfs2_ea_location el;
	unsigned int namel = strlen(name);
David Teigland's avatar
David Teigland committed
1149
1150
	int error;

1151
1152
1153
1154
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		return -EPERM;
	if (namel > GFS2_EA_MAX_NAME_LEN)
		return -ERANGE;
David Teigland's avatar
David Teigland committed
1155

1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
	if (value == NULL)
		return gfs2_xattr_remove(inode, type, name);

	if (ea_check_size(sdp, namel, size))
		return -ERANGE;

	if (!ip->i_eattr) {
		if (flags & XATTR_REPLACE)
			return -ENODATA;
		return ea_init(ip, type, name, value, size);
	}

	error = gfs2_ea_find(ip, type, name, &el);
David Teigland's avatar
David Teigland committed
1169
1170
1171
	if (error)
		return error;

1172
1173
1174
1175
1176
	if (el.el_ea) {
		if (ip->i_diskflags & GFS2_DIF_APPENDONLY) {
			brelse(el.el_bh);
			return -EPERM;
		}
David Teigland's avatar
David Teigland committed
1177

1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
		error = -EEXIST;
		if (!(flags & XATTR_CREATE)) {
			int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea);
			error = ea_set_i(ip, type, name, value, size, &el);
			if (!error && unstuffed)
				ea_set_remove_unstuffed(ip, &el);
		}

		brelse(el.el_bh);
		return error;
	}

	error = -ENODATA;
	if (!(flags & XATTR_REPLACE))
		error = ea_set_i(ip, type, name, value, size, NULL);
David Teigland's avatar
David Teigland committed
1193
1194
1195
1196
1197
1198
1199

	return error;
}

static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
				  struct gfs2_ea_header *ea, char *data)
{
1200
	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
David Teigland's avatar
David Teigland committed
1201
1202
	struct buffer_head **bh;
	unsigned int amount = GFS2_EA_DATA_LEN(ea);
1203
	unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize);
1204
	__be64 *dataptrs = GFS2_EA2DATAPTRS(ea);
David Teigland's avatar
David Teigland committed
1205
1206
1207
	unsigned int x;
	int error;

Josef Bacik's avatar
Josef Bacik committed
1208
	bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_NOFS);
David Teigland's avatar
David Teigland committed
1209
1210
1211
1212
1213
1214
1215
1216
	if (!bh)
		return -ENOMEM;

	error = gfs2_trans_begin(sdp, nptrs + RES_DINODE, 0);
	if (error)
		goto out;

	for (x = 0; x < nptrs; x++) {
1217
1218
		error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0,
				       bh + x);
David Teigland's avatar
David Teigland committed
1219
1220
1221
1222
1223
1224
1225
1226
1227
		if (error) {
			while (x--)
				brelse(bh[x]);
			goto fail;
		}
		dataptrs++;
	}

	for (x = 0; x < nptrs; x++) {
1228
		error = gfs2_meta_wait(sdp, bh[x]);
David Teigland's avatar
David Teigland committed
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
		if (error) {
			for (; x < nptrs; x++)
				brelse(bh[x]);
			goto fail;
		}
		if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) {
			for (; x < nptrs; x++)
				brelse(bh[x]);
			error = -EIO;
			goto fail;
		}

1241
		gfs2_trans_add_bh(ip->i_gl, bh[x], 1);
David Teigland's avatar
David Teigland committed
1242

1243
		memcpy(bh[x]->b_data + sizeof(struct gfs2_meta_header), data,
David Teigland's avatar
David Teigland committed
1244
1245
1246
1247
1248
1249
1250
1251
		       (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize);

		amount -= sdp->sd_jbsize;
		data += sdp->sd_jbsize;

		brelse(bh[x]);
	}

1252
out:
David Teigland's avatar
David Teigland committed
1253
1254
1255
	kfree(bh);
	return error;

1256
fail:
David Teigland's avatar
David Teigland committed
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
	gfs2_trans_end(sdp);
	kfree(bh);
	return error;
}

int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el,
		      struct iattr *attr, char *data)
{
	struct buffer_head *dibh;
	int error;

	if (GFS2_EA_IS_STUFFED(el->el_ea)) {
1269
		error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0);
David Teigland's avatar
David Teigland committed
1270
1271
1272
		if (error)
			return error;

1273
		gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
1274
		memcpy(GFS2_EA2DATA(el->el_ea), data,
David Teigland's avatar
David Teigland committed
1275
1276
1277
1278
1279
1280
1281
1282
1283
		       GFS2_EA_DATA_LEN(el->el_ea));
	} else
		error = ea_acl_chmod_unstuffed(ip, el->el_ea, data);

	if (error)
		return error;

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (!error) {
1284
1285
		error = inode_setattr(&ip->i_inode, attr);
		gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
1286
		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
1287
		gfs2_dinode_out(ip, dibh->b_data);
David Teigland's avatar
David Teigland committed
1288
1289
1290
		brelse(dibh);
	}