diff options
Diffstat (limited to 'fs/gfs2/eattr.c')
-rw-r--r-- | fs/gfs2/eattr.c | 421 |
1 files changed, 237 insertions, 184 deletions
diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 07ea9529adda..d9a9e260d5ac 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include "gfs2.h" | 18 | #include "gfs2.h" |
19 | #include "incore.h" | 19 | #include "incore.h" |
20 | #include "acl.h" | 20 | #include "acl.h" |
21 | #include "eaops.h" | ||
22 | #include "eattr.h" | 21 | #include "eattr.h" |
23 | #include "glock.h" | 22 | #include "glock.h" |
24 | #include "inode.h" | 23 | #include "inode.h" |
@@ -38,26 +37,32 @@ | |||
38 | * Returns: 1 if the EA should be stuffed | 37 | * Returns: 1 if the EA should be stuffed |
39 | */ | 38 | */ |
40 | 39 | ||
41 | static int ea_calc_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er, | 40 | static int ea_calc_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize, |
42 | unsigned int *size) | 41 | unsigned int *size) |
43 | { | 42 | { |
44 | *size = GFS2_EAREQ_SIZE_STUFFED(er); | 43 | unsigned int jbsize = sdp->sd_jbsize; |
45 | if (*size <= sdp->sd_jbsize) | 44 | |
45 | /* Stuffed */ | ||
46 | *size = ALIGN(sizeof(struct gfs2_ea_header) + nsize + dsize, 8); | ||
47 | |||
48 | if (*size <= jbsize) | ||
46 | return 1; | 49 | return 1; |
47 | 50 | ||
48 | *size = GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er); | 51 | /* Unstuffed */ |
52 | *size = ALIGN(sizeof(struct gfs2_ea_header) + nsize + | ||
53 | (sizeof(__be64) * DIV_ROUND_UP(dsize, jbsize)), 8); | ||
49 | 54 | ||
50 | return 0; | 55 | return 0; |
51 | } | 56 | } |
52 | 57 | ||
53 | static int ea_check_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er) | 58 | static int ea_check_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize) |
54 | { | 59 | { |
55 | unsigned int size; | 60 | unsigned int size; |
56 | 61 | ||
57 | if (er->er_data_len > GFS2_EA_MAX_DATA_LEN) | 62 | if (dsize > GFS2_EA_MAX_DATA_LEN) |
58 | return -ERANGE; | 63 | return -ERANGE; |
59 | 64 | ||
60 | ea_calc_size(sdp, er, &size); | 65 | ea_calc_size(sdp, nsize, dsize, &size); |
61 | 66 | ||
62 | /* This can only happen with 512 byte blocks */ | 67 | /* This can only happen with 512 byte blocks */ |
63 | if (size > sdp->sd_jbsize) | 68 | if (size > sdp->sd_jbsize) |
@@ -151,7 +156,9 @@ out: | |||
151 | } | 156 | } |
152 | 157 | ||
153 | struct ea_find { | 158 | struct ea_find { |
154 | struct gfs2_ea_request *ef_er; | 159 | int type; |
160 | const char *name; | ||
161 | size_t namel; | ||
155 | struct gfs2_ea_location *ef_el; | 162 | struct gfs2_ea_location *ef_el; |
156 | }; | 163 | }; |
157 | 164 | ||
@@ -160,14 +167,13 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
160 | void *private) | 167 | void *private) |
161 | { | 168 | { |
162 | struct ea_find *ef = private; | 169 | struct ea_find *ef = private; |
163 | struct gfs2_ea_request *er = ef->ef_er; | ||
164 | 170 | ||
165 | if (ea->ea_type == GFS2_EATYPE_UNUSED) | 171 | if (ea->ea_type == GFS2_EATYPE_UNUSED) |
166 | return 0; | 172 | return 0; |
167 | 173 | ||
168 | if (ea->ea_type == er->er_type) { | 174 | if (ea->ea_type == ef->type) { |
169 | if (ea->ea_name_len == er->er_name_len && | 175 | if (ea->ea_name_len == ef->namel && |
170 | !memcmp(GFS2_EA2NAME(ea), er->er_name, ea->ea_name_len)) { | 176 | !memcmp(GFS2_EA2NAME(ea), ef->name, ea->ea_name_len)) { |
171 | struct gfs2_ea_location *el = ef->ef_el; | 177 | struct gfs2_ea_location *el = ef->ef_el; |
172 | get_bh(bh); | 178 | get_bh(bh); |
173 | el->el_bh = bh; | 179 | el->el_bh = bh; |
@@ -180,13 +186,15 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
180 | return 0; | 186 | return 0; |
181 | } | 187 | } |
182 | 188 | ||
183 | int gfs2_ea_find(struct gfs2_inode *ip, struct gfs2_ea_request *er, | 189 | int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, |
184 | struct gfs2_ea_location *el) | 190 | struct gfs2_ea_location *el) |
185 | { | 191 | { |
186 | struct ea_find ef; | 192 | struct ea_find ef; |
187 | int error; | 193 | int error; |
188 | 194 | ||
189 | ef.ef_er = er; | 195 | ef.type = type; |
196 | ef.name = name; | ||
197 | ef.namel = strlen(name); | ||
190 | ef.ef_el = el; | 198 | ef.ef_el = el; |
191 | 199 | ||
192 | memset(el, 0, sizeof(struct gfs2_ea_location)); | 200 | memset(el, 0, sizeof(struct gfs2_ea_location)); |
@@ -344,6 +352,20 @@ struct ea_list { | |||
344 | unsigned int ei_size; | 352 | unsigned int ei_size; |
345 | }; | 353 | }; |
346 | 354 | ||
355 | static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea) | ||
356 | { | ||
357 | switch (ea->ea_type) { | ||
358 | case GFS2_EATYPE_USR: | ||
359 | return 5 + ea->ea_name_len + 1; | ||
360 | case GFS2_EATYPE_SYS: | ||
361 | return 7 + ea->ea_name_len + 1; | ||
362 | case GFS2_EATYPE_SECURITY: | ||
363 | return 9 + ea->ea_name_len + 1; | ||
364 | default: | ||
365 | return 0; | ||
366 | } | ||
367 | } | ||
368 | |||
347 | static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, | 369 | static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, |
348 | struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, | 370 | struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, |
349 | void *private) | 371 | void *private) |
@@ -392,21 +414,25 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
392 | } | 414 | } |
393 | 415 | ||
394 | /** | 416 | /** |
395 | * gfs2_ea_list - | 417 | * gfs2_listxattr - List gfs2 extended attributes |
396 | * @ip: | 418 | * @dentry: The dentry whose inode we are interested in |
397 | * @er: | 419 | * @buffer: The buffer to write the results |
420 | * @size: The size of the buffer | ||
398 | * | 421 | * |
399 | * Returns: actual size of data on success, -errno on error | 422 | * Returns: actual size of data on success, -errno on error |
400 | */ | 423 | */ |
401 | 424 | ||
402 | int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 425 | ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) |
403 | { | 426 | { |
427 | struct gfs2_inode *ip = GFS2_I(dentry->d_inode); | ||
428 | struct gfs2_ea_request er; | ||
404 | struct gfs2_holder i_gh; | 429 | struct gfs2_holder i_gh; |
405 | int error; | 430 | int error; |
406 | 431 | ||
407 | if (!er->er_data || !er->er_data_len) { | 432 | memset(&er, 0, sizeof(struct gfs2_ea_request)); |
408 | er->er_data = NULL; | 433 | if (size) { |
409 | er->er_data_len = 0; | 434 | er.er_data = buffer; |
435 | er.er_data_len = size; | ||
410 | } | 436 | } |
411 | 437 | ||
412 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); | 438 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); |
@@ -414,7 +440,7 @@ int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er) | |||
414 | return error; | 440 | return error; |
415 | 441 | ||
416 | if (ip->i_eattr) { | 442 | if (ip->i_eattr) { |
417 | struct ea_list ei = { .ei_er = er, .ei_size = 0 }; | 443 | struct ea_list ei = { .ei_er = &er, .ei_size = 0 }; |
418 | 444 | ||
419 | error = ea_foreach(ip, ea_list_i, &ei); | 445 | error = ea_foreach(ip, ea_list_i, &ei); |
420 | if (!error) | 446 | if (!error) |
@@ -491,84 +517,61 @@ out: | |||
491 | } | 517 | } |
492 | 518 | ||
493 | int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, | 519 | int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, |
494 | char *data) | 520 | char *data, size_t size) |
495 | { | 521 | { |
522 | int ret; | ||
523 | size_t len = GFS2_EA_DATA_LEN(el->el_ea); | ||
524 | if (len > size) | ||
525 | return -ERANGE; | ||
526 | |||
496 | if (GFS2_EA_IS_STUFFED(el->el_ea)) { | 527 | if (GFS2_EA_IS_STUFFED(el->el_ea)) { |
497 | memcpy(data, GFS2_EA2DATA(el->el_ea), GFS2_EA_DATA_LEN(el->el_ea)); | 528 | memcpy(data, GFS2_EA2DATA(el->el_ea), len); |
498 | return 0; | 529 | return len; |
499 | } else | 530 | } |
500 | return ea_get_unstuffed(ip, el->el_ea, data); | 531 | ret = ea_get_unstuffed(ip, el->el_ea, data); |
532 | if (ret < 0) | ||
533 | return ret; | ||
534 | return len; | ||
501 | } | 535 | } |
502 | 536 | ||
503 | /** | 537 | /** |
504 | * gfs2_ea_get_i - | 538 | * gfs2_xattr_get - Get a GFS2 extended attribute |
505 | * @ip: The GFS2 inode | 539 | * @inode: The inode |
506 | * @er: The request structure | 540 | * @type: The type of extended attribute |
541 | * @name: The name of the extended attribute | ||
542 | * @buffer: The buffer to write the result into | ||
543 | * @size: The size of the buffer | ||
507 | * | 544 | * |
508 | * Returns: actual size of data on success, -errno on error | 545 | * Returns: actual size of data on success, -errno on error |
509 | */ | 546 | */ |
510 | 547 | ||
511 | int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 548 | int gfs2_xattr_get(struct inode *inode, int type, const char *name, |
549 | void *buffer, size_t size) | ||
512 | { | 550 | { |
551 | struct gfs2_inode *ip = GFS2_I(inode); | ||
513 | struct gfs2_ea_location el; | 552 | struct gfs2_ea_location el; |
514 | int error; | 553 | int error; |
515 | 554 | ||
516 | if (!ip->i_eattr) | 555 | if (!ip->i_eattr) |
517 | return -ENODATA; | 556 | return -ENODATA; |
557 | if (strlen(name) > GFS2_EA_MAX_NAME_LEN) | ||
558 | return -EINVAL; | ||
518 | 559 | ||
519 | error = gfs2_ea_find(ip, er, &el); | 560 | error = gfs2_ea_find(ip, type, name, &el); |
520 | if (error) | 561 | if (error) |
521 | return error; | 562 | return error; |
522 | if (!el.el_ea) | 563 | if (!el.el_ea) |
523 | return -ENODATA; | 564 | return -ENODATA; |
524 | 565 | if (size) | |
525 | if (er->er_data_len) { | 566 | error = gfs2_ea_get_copy(ip, &el, buffer, size); |
526 | if (GFS2_EA_DATA_LEN(el.el_ea) > er->er_data_len) | 567 | else |
527 | error = -ERANGE; | ||
528 | else | ||
529 | error = gfs2_ea_get_copy(ip, &el, er->er_data); | ||
530 | } | ||
531 | if (!error) | ||
532 | error = GFS2_EA_DATA_LEN(el.el_ea); | 568 | error = GFS2_EA_DATA_LEN(el.el_ea); |
533 | |||
534 | brelse(el.el_bh); | 569 | brelse(el.el_bh); |
535 | 570 | ||
536 | return error; | 571 | return error; |
537 | } | 572 | } |
538 | 573 | ||
539 | /** | 574 | /** |
540 | * gfs2_ea_get - | ||
541 | * @ip: The GFS2 inode | ||
542 | * @er: The request structure | ||
543 | * | ||
544 | * Returns: actual size of data on success, -errno on error | ||
545 | */ | ||
546 | |||
547 | int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
548 | { | ||
549 | struct gfs2_holder i_gh; | ||
550 | int error; | ||
551 | |||
552 | if (!er->er_name_len || | ||
553 | er->er_name_len > GFS2_EA_MAX_NAME_LEN) | ||
554 | return -EINVAL; | ||
555 | if (!er->er_data || !er->er_data_len) { | ||
556 | er->er_data = NULL; | ||
557 | er->er_data_len = 0; | ||
558 | } | ||
559 | |||
560 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); | ||
561 | if (error) | ||
562 | return error; | ||
563 | |||
564 | error = gfs2_ea_ops[er->er_type]->eo_get(ip, er); | ||
565 | |||
566 | gfs2_glock_dq_uninit(&i_gh); | ||
567 | |||
568 | return error; | ||
569 | } | ||
570 | |||
571 | /** | ||
572 | * ea_alloc_blk - allocates a new block for extended attributes. | 575 | * ea_alloc_blk - allocates a new block for extended attributes. |
573 | * @ip: A pointer to the inode that's getting extended attributes | 576 | * @ip: A pointer to the inode that's getting extended attributes |
574 | * @bhp: Pointer to pointer to a struct buffer_head | 577 | * @bhp: Pointer to pointer to a struct buffer_head |
@@ -713,12 +716,6 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
713 | 716 | ||
714 | error = gfs2_meta_inode_buffer(ip, &dibh); | 717 | error = gfs2_meta_inode_buffer(ip, &dibh); |
715 | if (!error) { | 718 | if (!error) { |
716 | if (er->er_flags & GFS2_ERF_MODE) { | ||
717 | gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), | ||
718 | (ip->i_inode.i_mode & S_IFMT) == | ||
719 | (er->er_mode & S_IFMT)); | ||
720 | ip->i_inode.i_mode = er->er_mode; | ||
721 | } | ||
722 | ip->i_inode.i_ctime = CURRENT_TIME; | 719 | ip->i_inode.i_ctime = CURRENT_TIME; |
723 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 720 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
724 | gfs2_dinode_out(ip, dibh->b_data); | 721 | gfs2_dinode_out(ip, dibh->b_data); |
@@ -762,15 +759,23 @@ static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
762 | * Returns: errno | 759 | * Returns: errno |
763 | */ | 760 | */ |
764 | 761 | ||
765 | static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 762 | static int ea_init(struct gfs2_inode *ip, int type, const char *name, |
763 | const void *data, size_t size) | ||
766 | { | 764 | { |
765 | struct gfs2_ea_request er; | ||
767 | unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize; | 766 | unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize; |
768 | unsigned int blks = 1; | 767 | unsigned int blks = 1; |
769 | 768 | ||
770 | if (GFS2_EAREQ_SIZE_STUFFED(er) > jbsize) | 769 | er.er_type = type; |
771 | blks += DIV_ROUND_UP(er->er_data_len, jbsize); | 770 | er.er_name = name; |
771 | er.er_name_len = strlen(name); | ||
772 | er.er_data = (void *)data; | ||
773 | er.er_data_len = size; | ||
774 | |||
775 | if (GFS2_EAREQ_SIZE_STUFFED(&er) > jbsize) | ||
776 | blks += DIV_ROUND_UP(er.er_data_len, jbsize); | ||
772 | 777 | ||
773 | return ea_alloc_skeleton(ip, er, blks, ea_init_i, NULL); | 778 | return ea_alloc_skeleton(ip, &er, blks, ea_init_i, NULL); |
774 | } | 779 | } |
775 | 780 | ||
776 | static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea) | 781 | static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea) |
@@ -848,12 +853,6 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, | |||
848 | error = gfs2_meta_inode_buffer(ip, &dibh); | 853 | error = gfs2_meta_inode_buffer(ip, &dibh); |
849 | if (error) | 854 | if (error) |
850 | goto out; | 855 | goto out; |
851 | |||
852 | if (er->er_flags & GFS2_ERF_MODE) { | ||
853 | gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), | ||
854 | (ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT)); | ||
855 | ip->i_inode.i_mode = er->er_mode; | ||
856 | } | ||
857 | ip->i_inode.i_ctime = CURRENT_TIME; | 856 | ip->i_inode.i_ctime = CURRENT_TIME; |
858 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 857 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
859 | gfs2_dinode_out(ip, dibh->b_data); | 858 | gfs2_dinode_out(ip, dibh->b_data); |
@@ -894,7 +893,8 @@ static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh, | |||
894 | int stuffed; | 893 | int stuffed; |
895 | int error; | 894 | int error; |
896 | 895 | ||
897 | stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er, &size); | 896 | stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er->er_name_len, |
897 | es->es_er->er_data_len, &size); | ||
898 | 898 | ||
899 | if (ea->ea_type == GFS2_EATYPE_UNUSED) { | 899 | if (ea->ea_type == GFS2_EATYPE_UNUSED) { |
900 | if (GFS2_EA_REC_LEN(ea) < size) | 900 | if (GFS2_EA_REC_LEN(ea) < size) |
@@ -1005,15 +1005,22 @@ out: | |||
1005 | return error; | 1005 | return error; |
1006 | } | 1006 | } |
1007 | 1007 | ||
1008 | static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | 1008 | static int ea_set_i(struct gfs2_inode *ip, int type, const char *name, |
1009 | struct gfs2_ea_location *el) | 1009 | const void *value, size_t size, struct gfs2_ea_location *el) |
1010 | { | 1010 | { |
1011 | struct gfs2_ea_request er; | ||
1011 | struct ea_set es; | 1012 | struct ea_set es; |
1012 | unsigned int blks = 2; | 1013 | unsigned int blks = 2; |
1013 | int error; | 1014 | int error; |
1014 | 1015 | ||
1016 | er.er_type = type; | ||
1017 | er.er_name = name; | ||
1018 | er.er_data = (void *)value; | ||
1019 | er.er_name_len = strlen(name); | ||
1020 | er.er_data_len = size; | ||
1021 | |||
1015 | memset(&es, 0, sizeof(struct ea_set)); | 1022 | memset(&es, 0, sizeof(struct ea_set)); |
1016 | es.es_er = er; | 1023 | es.es_er = &er; |
1017 | es.es_el = el; | 1024 | es.es_el = el; |
1018 | 1025 | ||
1019 | error = ea_foreach(ip, ea_set_simple, &es); | 1026 | error = ea_foreach(ip, ea_set_simple, &es); |
@@ -1024,10 +1031,10 @@ static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
1024 | 1031 | ||
1025 | if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT)) | 1032 | if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT)) |
1026 | blks++; | 1033 | blks++; |
1027 | if (GFS2_EAREQ_SIZE_STUFFED(er) > GFS2_SB(&ip->i_inode)->sd_jbsize) | 1034 | if (GFS2_EAREQ_SIZE_STUFFED(&er) > GFS2_SB(&ip->i_inode)->sd_jbsize) |
1028 | blks += DIV_ROUND_UP(er->er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize); | 1035 | blks += DIV_ROUND_UP(er.er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize); |
1029 | 1036 | ||
1030 | return ea_alloc_skeleton(ip, er, blks, ea_set_block, el); | 1037 | return ea_alloc_skeleton(ip, &er, blks, ea_set_block, el); |
1031 | } | 1038 | } |
1032 | 1039 | ||
1033 | static int ea_set_remove_unstuffed(struct gfs2_inode *ip, | 1040 | static int ea_set_remove_unstuffed(struct gfs2_inode *ip, |
@@ -1042,74 +1049,6 @@ static int ea_set_remove_unstuffed(struct gfs2_inode *ip, | |||
1042 | return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0); | 1049 | return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0); |
1043 | } | 1050 | } |
1044 | 1051 | ||
1045 | int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
1046 | { | ||
1047 | struct gfs2_ea_location el; | ||
1048 | int error; | ||
1049 | |||
1050 | if (!ip->i_eattr) { | ||
1051 | if (er->er_flags & XATTR_REPLACE) | ||
1052 | return -ENODATA; | ||
1053 | return ea_init(ip, er); | ||
1054 | } | ||
1055 | |||
1056 | error = gfs2_ea_find(ip, er, &el); | ||
1057 | if (error) | ||
1058 | return error; | ||
1059 | |||
1060 | if (el.el_ea) { | ||
1061 | if (ip->i_diskflags & GFS2_DIF_APPENDONLY) { | ||
1062 | brelse(el.el_bh); | ||
1063 | return -EPERM; | ||
1064 | } | ||
1065 | |||
1066 | error = -EEXIST; | ||
1067 | if (!(er->er_flags & XATTR_CREATE)) { | ||
1068 | int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea); | ||
1069 | error = ea_set_i(ip, er, &el); | ||
1070 | if (!error && unstuffed) | ||
1071 | ea_set_remove_unstuffed(ip, &el); | ||
1072 | } | ||
1073 | |||
1074 | brelse(el.el_bh); | ||
1075 | } else { | ||
1076 | error = -ENODATA; | ||
1077 | if (!(er->er_flags & XATTR_REPLACE)) | ||
1078 | error = ea_set_i(ip, er, NULL); | ||
1079 | } | ||
1080 | |||
1081 | return error; | ||
1082 | } | ||
1083 | |||
1084 | int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
1085 | { | ||
1086 | struct gfs2_holder i_gh; | ||
1087 | int error; | ||
1088 | |||
1089 | if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN) | ||
1090 | return -EINVAL; | ||
1091 | if (!er->er_data || !er->er_data_len) { | ||
1092 | er->er_data = NULL; | ||
1093 | er->er_data_len = 0; | ||
1094 | } | ||
1095 | error = ea_check_size(GFS2_SB(&ip->i_inode), er); | ||
1096 | if (error) | ||
1097 | return error; | ||
1098 | |||
1099 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); | ||
1100 | if (error) | ||
1101 | return error; | ||
1102 | |||
1103 | if (IS_IMMUTABLE(&ip->i_inode)) | ||
1104 | error = -EPERM; | ||
1105 | else | ||
1106 | error = gfs2_ea_ops[er->er_type]->eo_set(ip, er); | ||
1107 | |||
1108 | gfs2_glock_dq_uninit(&i_gh); | ||
1109 | |||
1110 | return error; | ||
1111 | } | ||
1112 | |||
1113 | static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) | 1052 | static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) |
1114 | { | 1053 | { |
1115 | struct gfs2_ea_header *ea = el->el_ea; | 1054 | struct gfs2_ea_header *ea = el->el_ea; |
@@ -1131,8 +1070,9 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) | |||
1131 | 1070 | ||
1132 | if (GFS2_EA_IS_LAST(ea)) | 1071 | if (GFS2_EA_IS_LAST(ea)) |
1133 | prev->ea_flags |= GFS2_EAFLAG_LAST; | 1072 | prev->ea_flags |= GFS2_EAFLAG_LAST; |
1134 | } else | 1073 | } else { |
1135 | ea->ea_type = GFS2_EATYPE_UNUSED; | 1074 | ea->ea_type = GFS2_EATYPE_UNUSED; |
1075 | } | ||
1136 | 1076 | ||
1137 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1077 | error = gfs2_meta_inode_buffer(ip, &dibh); |
1138 | if (!error) { | 1078 | if (!error) { |
@@ -1147,15 +1087,29 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) | |||
1147 | return error; | 1087 | return error; |
1148 | } | 1088 | } |
1149 | 1089 | ||
1150 | int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 1090 | /** |
1091 | * gfs2_xattr_remove - Remove a GFS2 extended attribute | ||
1092 | * @inode: The inode | ||
1093 | * @type: The type of the extended attribute | ||
1094 | * @name: The name of the extended attribute | ||
1095 | * | ||
1096 | * This is not called directly by the VFS since we use the (common) | ||
1097 | * scheme of making a "set with NULL data" mean a remove request. Note | ||
1098 | * that this is different from a set with zero length data. | ||
1099 | * | ||
1100 | * Returns: 0, or errno on failure | ||
1101 | */ | ||
1102 | |||
1103 | static int gfs2_xattr_remove(struct inode *inode, int type, const char *name) | ||
1151 | { | 1104 | { |
1105 | struct gfs2_inode *ip = GFS2_I(inode); | ||
1152 | struct gfs2_ea_location el; | 1106 | struct gfs2_ea_location el; |
1153 | int error; | 1107 | int error; |
1154 | 1108 | ||
1155 | if (!ip->i_eattr) | 1109 | if (!ip->i_eattr) |
1156 | return -ENODATA; | 1110 | return -ENODATA; |
1157 | 1111 | ||
1158 | error = gfs2_ea_find(ip, er, &el); | 1112 | error = gfs2_ea_find(ip, type, name, &el); |
1159 | if (error) | 1113 | if (error) |
1160 | return error; | 1114 | return error; |
1161 | if (!el.el_ea) | 1115 | if (!el.el_ea) |
@@ -1164,8 +1118,7 @@ int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | |||
1164 | if (GFS2_EA_IS_STUFFED(el.el_ea)) | 1118 | if (GFS2_EA_IS_STUFFED(el.el_ea)) |
1165 | error = ea_remove_stuffed(ip, &el); | 1119 | error = ea_remove_stuffed(ip, &el); |
1166 | else | 1120 | else |
1167 | error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, | 1121 | error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, 0); |
1168 | 0); | ||
1169 | 1122 | ||
1170 | brelse(el.el_bh); | 1123 | brelse(el.el_bh); |
1171 | 1124 | ||
@@ -1173,31 +1126,70 @@ int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | |||
1173 | } | 1126 | } |
1174 | 1127 | ||
1175 | /** | 1128 | /** |
1176 | * gfs2_ea_remove - sets (or creates or replaces) an extended attribute | 1129 | * gfs2_xattr_set - Set (or remove) a GFS2 extended attribute |
1177 | * @ip: pointer to the inode of the target file | 1130 | * @inode: The inode |
1178 | * @er: request information | 1131 | * @type: The type of the extended attribute |
1132 | * @name: The name of the extended attribute | ||
1133 | * @value: The value of the extended attribute (NULL for remove) | ||
1134 | * @size: The size of the @value argument | ||
1135 | * @flags: Create or Replace | ||
1179 | * | 1136 | * |
1180 | * Returns: errno | 1137 | * See gfs2_xattr_remove() for details of the removal of xattrs. |
1138 | * | ||
1139 | * Returns: 0 or errno on failure | ||
1181 | */ | 1140 | */ |
1182 | 1141 | ||
1183 | int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 1142 | int gfs2_xattr_set(struct inode *inode, int type, const char *name, |
1143 | const void *value, size_t size, int flags) | ||
1184 | { | 1144 | { |
1185 | struct gfs2_holder i_gh; | 1145 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
1146 | struct gfs2_inode *ip = GFS2_I(inode); | ||
1147 | struct gfs2_ea_location el; | ||
1148 | unsigned int namel = strlen(name); | ||
1186 | int error; | 1149 | int error; |
1187 | 1150 | ||
1188 | if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN) | 1151 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
1189 | return -EINVAL; | 1152 | return -EPERM; |
1153 | if (namel > GFS2_EA_MAX_NAME_LEN) | ||
1154 | return -ERANGE; | ||
1190 | 1155 | ||
1191 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); | 1156 | if (value == NULL) |
1157 | return gfs2_xattr_remove(inode, type, name); | ||
1158 | |||
1159 | if (ea_check_size(sdp, namel, size)) | ||
1160 | return -ERANGE; | ||
1161 | |||
1162 | if (!ip->i_eattr) { | ||
1163 | if (flags & XATTR_REPLACE) | ||
1164 | return -ENODATA; | ||
1165 | return ea_init(ip, type, name, value, size); | ||
1166 | } | ||
1167 | |||
1168 | error = gfs2_ea_find(ip, type, name, &el); | ||
1192 | if (error) | 1169 | if (error) |
1193 | return error; | 1170 | return error; |
1194 | 1171 | ||
1195 | if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) | 1172 | if (el.el_ea) { |
1196 | error = -EPERM; | 1173 | if (ip->i_diskflags & GFS2_DIF_APPENDONLY) { |
1197 | else | 1174 | brelse(el.el_bh); |
1198 | error = gfs2_ea_ops[er->er_type]->eo_remove(ip, er); | 1175 | return -EPERM; |
1176 | } | ||
1199 | 1177 | ||
1200 | gfs2_glock_dq_uninit(&i_gh); | 1178 | error = -EEXIST; |
1179 | if (!(flags & XATTR_CREATE)) { | ||
1180 | int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea); | ||
1181 | error = ea_set_i(ip, type, name, value, size, &el); | ||
1182 | if (!error && unstuffed) | ||
1183 | ea_set_remove_unstuffed(ip, &el); | ||
1184 | } | ||
1185 | |||
1186 | brelse(el.el_bh); | ||
1187 | return error; | ||
1188 | } | ||
1189 | |||
1190 | error = -ENODATA; | ||
1191 | if (!(flags & XATTR_REPLACE)) | ||
1192 | error = ea_set_i(ip, type, name, value, size, NULL); | ||
1201 | 1193 | ||
1202 | return error; | 1194 | return error; |
1203 | } | 1195 | } |
@@ -1503,3 +1495,64 @@ out_alloc: | |||
1503 | return error; | 1495 | return error; |
1504 | } | 1496 | } |
1505 | 1497 | ||
1498 | static int gfs2_xattr_user_get(struct inode *inode, const char *name, | ||
1499 | void *buffer, size_t size) | ||
1500 | { | ||
1501 | return gfs2_xattr_get(inode, GFS2_EATYPE_USR, name, buffer, size); | ||
1502 | } | ||
1503 | |||
1504 | static int gfs2_xattr_user_set(struct inode *inode, const char *name, | ||
1505 | const void *value, size_t size, int flags) | ||
1506 | { | ||
1507 | return gfs2_xattr_set(inode, GFS2_EATYPE_USR, name, value, size, flags); | ||
1508 | } | ||
1509 | |||
1510 | static int gfs2_xattr_system_get(struct inode *inode, const char *name, | ||
1511 | void *buffer, size_t size) | ||
1512 | { | ||
1513 | return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size); | ||
1514 | } | ||
1515 | |||
1516 | static int gfs2_xattr_system_set(struct inode *inode, const char *name, | ||
1517 | const void *value, size_t size, int flags) | ||
1518 | { | ||
1519 | return gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, flags); | ||
1520 | } | ||
1521 | |||
1522 | static int gfs2_xattr_security_get(struct inode *inode, const char *name, | ||
1523 | void *buffer, size_t size) | ||
1524 | { | ||
1525 | return gfs2_xattr_get(inode, GFS2_EATYPE_SECURITY, name, buffer, size); | ||
1526 | } | ||
1527 | |||
1528 | static int gfs2_xattr_security_set(struct inode *inode, const char *name, | ||
1529 | const void *value, size_t size, int flags) | ||
1530 | { | ||
1531 | return gfs2_xattr_set(inode, GFS2_EATYPE_SECURITY, name, value, size, flags); | ||
1532 | } | ||
1533 | |||
1534 | static struct xattr_handler gfs2_xattr_user_handler = { | ||
1535 | .prefix = XATTR_USER_PREFIX, | ||
1536 | .get = gfs2_xattr_user_get, | ||
1537 | .set = gfs2_xattr_user_set, | ||
1538 | }; | ||
1539 | |||
1540 | static struct xattr_handler gfs2_xattr_security_handler = { | ||
1541 | .prefix = XATTR_SECURITY_PREFIX, | ||
1542 | .get = gfs2_xattr_security_get, | ||
1543 | .set = gfs2_xattr_security_set, | ||
1544 | }; | ||
1545 | |||
1546 | static struct xattr_handler gfs2_xattr_system_handler = { | ||
1547 | .prefix = XATTR_SYSTEM_PREFIX, | ||
1548 | .get = gfs2_xattr_system_get, | ||
1549 | .set = gfs2_xattr_system_set, | ||
1550 | }; | ||
1551 | |||
1552 | struct xattr_handler *gfs2_xattr_handlers[] = { | ||
1553 | &gfs2_xattr_user_handler, | ||
1554 | &gfs2_xattr_security_handler, | ||
1555 | &gfs2_xattr_system_handler, | ||
1556 | NULL, | ||
1557 | }; | ||
1558 | |||