diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-11-11 12:31:32 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-11-11 12:31:32 -0500 |
commit | ad1164b79f1905ec1611cdc2a44949618bced2a6 (patch) | |
tree | cdc4be3325d6bcd58f90d552f3760585f4e4658f /fs | |
parent | 0906dd9df2f79042cfa82d8388895be7cbe7a51b (diff) | |
parent | 6c1e183e12dbd78a897a859f13220406296fee31 (diff) |
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mfasheh/ocfs2
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mfasheh/ocfs2: (21 commits)
ocfs2: Check search result in ocfs2_xattr_block_get()
ocfs2: fix printk related build warnings in xattr.c
ocfs2: truncate outstanding block after direct io failure
ocfs2/xattr: Proper hash collision handle in bucket division
ocfs2: return 0 in page_mkwrite to let VFS retry.
ocfs2: Set journal descriptor to NULL after journal shutdown
ocfs2: Fix check of return value of ocfs2_start_trans() in xattr.c.
ocfs2: Let inode be really deleted when ocfs2_mknod_locked() fails
ocfs2: Fix checking of return value of new_inode()
ocfs2: Fix check of return value of ocfs2_start_trans()
ocfs2: Fix some typos in xattr annotations.
ocfs2: Remove unused ocfs2_restore_xattr_block().
ocfs2: Don't repeat ocfs2_xattr_block_find()
ocfs2: Specify appropriate journal access for new xattr buckets.
ocfs2: Check errors from ocfs2_xattr_update_xattr_search()
ocfs2: Don't return -EFAULT from a corrupt xattr entry.
ocfs2: Check xattr block signatures properly.
ocfs2: add handler_map array bounds checking
ocfs2: remove duplicate definition in xattr
ocfs2: fix function declaration and definition in xattr
...
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/file.c | 27 | ||||
-rw-r--r-- | fs/ocfs2/inode.c | 6 | ||||
-rw-r--r-- | fs/ocfs2/journal.c | 1 | ||||
-rw-r--r-- | fs/ocfs2/mmap.c | 6 | ||||
-rw-r--r-- | fs/ocfs2/namei.c | 8 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2.h | 3 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2_fs.h | 17 | ||||
-rw-r--r-- | fs/ocfs2/xattr.c | 372 | ||||
-rw-r--r-- | fs/ocfs2/xattr.h | 38 |
9 files changed, 256 insertions, 222 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 7efe937a415f..e2570a3bc2b2 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -247,8 +247,8 @@ int ocfs2_update_inode_atime(struct inode *inode, | |||
247 | mlog_entry_void(); | 247 | mlog_entry_void(); |
248 | 248 | ||
249 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); | 249 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); |
250 | if (handle == NULL) { | 250 | if (IS_ERR(handle)) { |
251 | ret = -ENOMEM; | 251 | ret = PTR_ERR(handle); |
252 | mlog_errno(ret); | 252 | mlog_errno(ret); |
253 | goto out; | 253 | goto out; |
254 | } | 254 | } |
@@ -312,8 +312,8 @@ static int ocfs2_simple_size_update(struct inode *inode, | |||
312 | handle_t *handle = NULL; | 312 | handle_t *handle = NULL; |
313 | 313 | ||
314 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); | 314 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); |
315 | if (handle == NULL) { | 315 | if (IS_ERR(handle)) { |
316 | ret = -ENOMEM; | 316 | ret = PTR_ERR(handle); |
317 | mlog_errno(ret); | 317 | mlog_errno(ret); |
318 | goto out; | 318 | goto out; |
319 | } | 319 | } |
@@ -1055,8 +1055,8 @@ static int __ocfs2_write_remove_suid(struct inode *inode, | |||
1055 | (unsigned long long)OCFS2_I(inode)->ip_blkno, inode->i_mode); | 1055 | (unsigned long long)OCFS2_I(inode)->ip_blkno, inode->i_mode); |
1056 | 1056 | ||
1057 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); | 1057 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); |
1058 | if (handle == NULL) { | 1058 | if (IS_ERR(handle)) { |
1059 | ret = -ENOMEM; | 1059 | ret = PTR_ERR(handle); |
1060 | mlog_errno(ret); | 1060 | mlog_errno(ret); |
1061 | goto out; | 1061 | goto out; |
1062 | } | 1062 | } |
@@ -1259,8 +1259,8 @@ static int __ocfs2_remove_inode_range(struct inode *inode, | |||
1259 | } | 1259 | } |
1260 | 1260 | ||
1261 | handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); | 1261 | handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); |
1262 | if (handle == NULL) { | 1262 | if (IS_ERR(handle)) { |
1263 | ret = -ENOMEM; | 1263 | ret = PTR_ERR(handle); |
1264 | mlog_errno(ret); | 1264 | mlog_errno(ret); |
1265 | goto out; | 1265 | goto out; |
1266 | } | 1266 | } |
@@ -1352,8 +1352,8 @@ static int ocfs2_zero_partial_clusters(struct inode *inode, | |||
1352 | goto out; | 1352 | goto out; |
1353 | 1353 | ||
1354 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); | 1354 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); |
1355 | if (handle == NULL) { | 1355 | if (IS_ERR(handle)) { |
1356 | ret = -ENOMEM; | 1356 | ret = PTR_ERR(handle); |
1357 | mlog_errno(ret); | 1357 | mlog_errno(ret); |
1358 | goto out; | 1358 | goto out; |
1359 | } | 1359 | } |
@@ -1866,6 +1866,13 @@ relock: | |||
1866 | written = generic_file_direct_write(iocb, iov, &nr_segs, *ppos, | 1866 | written = generic_file_direct_write(iocb, iov, &nr_segs, *ppos, |
1867 | ppos, count, ocount); | 1867 | ppos, count, ocount); |
1868 | if (written < 0) { | 1868 | if (written < 0) { |
1869 | /* | ||
1870 | * direct write may have instantiated a few | ||
1871 | * blocks outside i_size. Trim these off again. | ||
1872 | * Don't need i_size_read because we hold i_mutex. | ||
1873 | */ | ||
1874 | if (*ppos + count > inode->i_size) | ||
1875 | vmtruncate(inode, inode->i_size); | ||
1869 | ret = written; | 1876 | ret = written; |
1870 | goto out_dio; | 1877 | goto out_dio; |
1871 | } | 1878 | } |
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 4903688f72a9..7aa00d511874 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
@@ -1106,6 +1106,12 @@ void ocfs2_clear_inode(struct inode *inode) | |||
1106 | oi->ip_last_trans = 0; | 1106 | oi->ip_last_trans = 0; |
1107 | oi->ip_dir_start_lookup = 0; | 1107 | oi->ip_dir_start_lookup = 0; |
1108 | oi->ip_blkno = 0ULL; | 1108 | oi->ip_blkno = 0ULL; |
1109 | |||
1110 | /* | ||
1111 | * ip_jinode is used to track txns against this inode. We ensure that | ||
1112 | * the journal is flushed before journal shutdown. Thus it is safe to | ||
1113 | * have inodes get cleaned up after journal shutdown. | ||
1114 | */ | ||
1109 | jbd2_journal_release_jbd_inode(OCFS2_SB(inode->i_sb)->journal->j_journal, | 1115 | jbd2_journal_release_jbd_inode(OCFS2_SB(inode->i_sb)->journal->j_journal, |
1110 | &oi->ip_jinode); | 1116 | &oi->ip_jinode); |
1111 | 1117 | ||
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 81e40677eecb..99fe9d584f3c 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c | |||
@@ -690,6 +690,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb) | |||
690 | 690 | ||
691 | /* Shutdown the kernel journal system */ | 691 | /* Shutdown the kernel journal system */ |
692 | jbd2_journal_destroy(journal->j_journal); | 692 | jbd2_journal_destroy(journal->j_journal); |
693 | journal->j_journal = NULL; | ||
693 | 694 | ||
694 | OCFS2_I(inode)->ip_open_count--; | 695 | OCFS2_I(inode)->ip_open_count--; |
695 | 696 | ||
diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c index 3dc18d67557c..eea1d24713ea 100644 --- a/fs/ocfs2/mmap.c +++ b/fs/ocfs2/mmap.c | |||
@@ -113,7 +113,11 @@ static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh, | |||
113 | * ocfs2_write_begin_nolock(). | 113 | * ocfs2_write_begin_nolock(). |
114 | */ | 114 | */ |
115 | if (!PageUptodate(page) || page->mapping != inode->i_mapping) { | 115 | if (!PageUptodate(page) || page->mapping != inode->i_mapping) { |
116 | ret = -EINVAL; | 116 | /* |
117 | * the page has been umapped in ocfs2_data_downconvert_worker. | ||
118 | * So return 0 here and let VFS retry. | ||
119 | */ | ||
120 | ret = 0; | ||
117 | goto out; | 121 | goto out; |
118 | } | 122 | } |
119 | 123 | ||
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 485a6aa0ad39..f4967e634ffd 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -378,8 +378,8 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, | |||
378 | } | 378 | } |
379 | 379 | ||
380 | inode = new_inode(dir->i_sb); | 380 | inode = new_inode(dir->i_sb); |
381 | if (IS_ERR(inode)) { | 381 | if (!inode) { |
382 | status = PTR_ERR(inode); | 382 | status = -ENOMEM; |
383 | mlog(ML_ERROR, "new_inode failed!\n"); | 383 | mlog(ML_ERROR, "new_inode failed!\n"); |
384 | goto leave; | 384 | goto leave; |
385 | } | 385 | } |
@@ -491,8 +491,10 @@ leave: | |||
491 | brelse(*new_fe_bh); | 491 | brelse(*new_fe_bh); |
492 | *new_fe_bh = NULL; | 492 | *new_fe_bh = NULL; |
493 | } | 493 | } |
494 | if (inode) | 494 | if (inode) { |
495 | clear_nlink(inode); | ||
495 | iput(inode); | 496 | iput(inode); |
497 | } | ||
496 | } | 498 | } |
497 | 499 | ||
498 | mlog_exit(status); | 500 | mlog_exit(status); |
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index a21a465490c4..fef7ece32376 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
@@ -473,6 +473,9 @@ static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super *osb) | |||
473 | (____gd)->bg_signature); \ | 473 | (____gd)->bg_signature); \ |
474 | } while (0) | 474 | } while (0) |
475 | 475 | ||
476 | #define OCFS2_IS_VALID_XATTR_BLOCK(ptr) \ | ||
477 | (!strcmp((ptr)->xb_signature, OCFS2_XATTR_BLOCK_SIGNATURE)) | ||
478 | |||
476 | static inline unsigned long ino_from_blkno(struct super_block *sb, | 479 | static inline unsigned long ino_from_blkno(struct super_block *sb, |
477 | u64 blkno) | 480 | u64 blkno) |
478 | { | 481 | { |
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index f24ce3d3f956..5f180cf7abbd 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h | |||
@@ -742,12 +742,12 @@ struct ocfs2_group_desc | |||
742 | */ | 742 | */ |
743 | struct ocfs2_xattr_entry { | 743 | struct ocfs2_xattr_entry { |
744 | __le32 xe_name_hash; /* hash value of xattr prefix+suffix. */ | 744 | __le32 xe_name_hash; /* hash value of xattr prefix+suffix. */ |
745 | __le16 xe_name_offset; /* byte offset from the 1st etnry in the local | 745 | __le16 xe_name_offset; /* byte offset from the 1st entry in the |
746 | local xattr storage(inode, xattr block or | 746 | local xattr storage(inode, xattr block or |
747 | xattr bucket). */ | 747 | xattr bucket). */ |
748 | __u8 xe_name_len; /* xattr name len, does't include prefix. */ | 748 | __u8 xe_name_len; /* xattr name len, does't include prefix. */ |
749 | __u8 xe_type; /* the low 7 bits indicates the name prefix's | 749 | __u8 xe_type; /* the low 7 bits indicate the name prefix |
750 | * type and the highest 1 bits indicate whether | 750 | * type and the highest bit indicates whether |
751 | * the EA is stored in the local storage. */ | 751 | * the EA is stored in the local storage. */ |
752 | __le64 xe_value_size; /* real xattr value length. */ | 752 | __le64 xe_value_size; /* real xattr value length. */ |
753 | }; | 753 | }; |
@@ -766,9 +766,10 @@ struct ocfs2_xattr_header { | |||
766 | xattr. */ | 766 | xattr. */ |
767 | __le16 xh_name_value_len; /* total length of name/value | 767 | __le16 xh_name_value_len; /* total length of name/value |
768 | length in this bucket. */ | 768 | length in this bucket. */ |
769 | __le16 xh_num_buckets; /* bucket nums in one extent | 769 | __le16 xh_num_buckets; /* Number of xattr buckets |
770 | record, only valid in the | 770 | in this extent record, |
771 | first bucket. */ | 771 | only valid in the first |
772 | bucket. */ | ||
772 | __le64 xh_csum; | 773 | __le64 xh_csum; |
773 | struct ocfs2_xattr_entry xh_entries[0]; /* xattr entry list. */ | 774 | struct ocfs2_xattr_entry xh_entries[0]; /* xattr entry list. */ |
774 | }; | 775 | }; |
@@ -776,8 +777,8 @@ struct ocfs2_xattr_header { | |||
776 | /* | 777 | /* |
777 | * On disk structure for xattr value root. | 778 | * On disk structure for xattr value root. |
778 | * | 779 | * |
779 | * It is used when one extended attribute's size is larger, and we will save it | 780 | * When an xattr's value is large enough, it is stored in an external |
780 | * in an outside cluster. It will stored in a b-tree like file content. | 781 | * b-tree like file data. The xattr value root points to this structure. |
781 | */ | 782 | */ |
782 | struct ocfs2_xattr_value_root { | 783 | struct ocfs2_xattr_value_root { |
783 | /*00*/ __le32 xr_clusters; /* clusters covered by xattr value. */ | 784 | /*00*/ __le32 xr_clusters; /* clusters covered by xattr value. */ |
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 802c41492214..054e2efb0b7e 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -3,25 +3,20 @@ | |||
3 | * | 3 | * |
4 | * xattr.c | 4 | * xattr.c |
5 | * | 5 | * |
6 | * Copyright (C) 2008 Oracle. All rights reserved. | 6 | * Copyright (C) 2004, 2008 Oracle. All rights reserved. |
7 | * | 7 | * |
8 | * CREDITS: | 8 | * CREDITS: |
9 | * Lots of code in this file is taken from ext3. | 9 | * Lots of code in this file is copy from linux/fs/ext3/xattr.c. |
10 | * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> | ||
10 | * | 11 | * |
11 | * This program is free software; you can redistribute it and/or | 12 | * This program is free software; you can redistribute it and/or |
12 | * modify it under the terms of the GNU General Public | 13 | * modify it under the terms of the GNU General Public |
13 | * License as published by the Free Software Foundation; either | 14 | * License version 2 as published by the Free Software Foundation. |
14 | * version 2 of the License, or (at your option) any later version. | ||
15 | * | 15 | * |
16 | * This program is distributed in the hope that it will be useful, | 16 | * This program is distributed in the hope that it will be useful, |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
19 | * General Public License for more details. | 19 | * General Public License for more details. |
20 | * | ||
21 | * You should have received a copy of the GNU General Public | ||
22 | * License along with this program; if not, write to the | ||
23 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
24 | * Boston, MA 021110-1307, USA. | ||
25 | */ | 20 | */ |
26 | 21 | ||
27 | #include <linux/capability.h> | 22 | #include <linux/capability.h> |
@@ -83,7 +78,7 @@ struct xattr_handler *ocfs2_xattr_handlers[] = { | |||
83 | NULL | 78 | NULL |
84 | }; | 79 | }; |
85 | 80 | ||
86 | static struct xattr_handler *ocfs2_xattr_handler_map[] = { | 81 | static struct xattr_handler *ocfs2_xattr_handler_map[OCFS2_XATTR_MAX] = { |
87 | [OCFS2_XATTR_INDEX_USER] = &ocfs2_xattr_user_handler, | 82 | [OCFS2_XATTR_INDEX_USER] = &ocfs2_xattr_user_handler, |
88 | [OCFS2_XATTR_INDEX_TRUSTED] = &ocfs2_xattr_trusted_handler, | 83 | [OCFS2_XATTR_INDEX_TRUSTED] = &ocfs2_xattr_trusted_handler, |
89 | }; | 84 | }; |
@@ -116,6 +111,10 @@ static int ocfs2_xattr_bucket_get_name_value(struct inode *inode, | |||
116 | int *block_off, | 111 | int *block_off, |
117 | int *new_offset); | 112 | int *new_offset); |
118 | 113 | ||
114 | static int ocfs2_xattr_block_find(struct inode *inode, | ||
115 | int name_index, | ||
116 | const char *name, | ||
117 | struct ocfs2_xattr_search *xs); | ||
119 | static int ocfs2_xattr_index_block_find(struct inode *inode, | 118 | static int ocfs2_xattr_index_block_find(struct inode *inode, |
120 | struct buffer_head *root_bh, | 119 | struct buffer_head *root_bh, |
121 | int name_index, | 120 | int name_index, |
@@ -137,6 +136,24 @@ static int ocfs2_xattr_set_entry_index_block(struct inode *inode, | |||
137 | static int ocfs2_delete_xattr_index_block(struct inode *inode, | 136 | static int ocfs2_delete_xattr_index_block(struct inode *inode, |
138 | struct buffer_head *xb_bh); | 137 | struct buffer_head *xb_bh); |
139 | 138 | ||
139 | static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) | ||
140 | { | ||
141 | return (1 << osb->s_clustersize_bits) / OCFS2_XATTR_BUCKET_SIZE; | ||
142 | } | ||
143 | |||
144 | static inline u16 ocfs2_blocks_per_xattr_bucket(struct super_block *sb) | ||
145 | { | ||
146 | return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits); | ||
147 | } | ||
148 | |||
149 | static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb) | ||
150 | { | ||
151 | u16 len = sb->s_blocksize - | ||
152 | offsetof(struct ocfs2_xattr_header, xh_entries); | ||
153 | |||
154 | return len / sizeof(struct ocfs2_xattr_entry); | ||
155 | } | ||
156 | |||
140 | static inline const char *ocfs2_xattr_prefix(int name_index) | 157 | static inline const char *ocfs2_xattr_prefix(int name_index) |
141 | { | 158 | { |
142 | struct xattr_handler *handler = NULL; | 159 | struct xattr_handler *handler = NULL; |
@@ -542,14 +559,12 @@ static int ocfs2_xattr_block_list(struct inode *inode, | |||
542 | mlog_errno(ret); | 559 | mlog_errno(ret); |
543 | return ret; | 560 | return ret; |
544 | } | 561 | } |
545 | /*Verify the signature of xattr block*/ | ||
546 | if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, | ||
547 | strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { | ||
548 | ret = -EFAULT; | ||
549 | goto cleanup; | ||
550 | } | ||
551 | 562 | ||
552 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; | 563 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; |
564 | if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) { | ||
565 | ret = -EIO; | ||
566 | goto cleanup; | ||
567 | } | ||
553 | 568 | ||
554 | if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { | 569 | if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { |
555 | struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header; | 570 | struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header; |
@@ -749,47 +764,25 @@ static int ocfs2_xattr_block_get(struct inode *inode, | |||
749 | size_t buffer_size, | 764 | size_t buffer_size, |
750 | struct ocfs2_xattr_search *xs) | 765 | struct ocfs2_xattr_search *xs) |
751 | { | 766 | { |
752 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; | ||
753 | struct buffer_head *blk_bh = NULL; | ||
754 | struct ocfs2_xattr_block *xb; | 767 | struct ocfs2_xattr_block *xb; |
755 | struct ocfs2_xattr_value_root *xv; | 768 | struct ocfs2_xattr_value_root *xv; |
756 | size_t size; | 769 | size_t size; |
757 | int ret = -ENODATA, name_offset, name_len, block_off, i; | 770 | int ret = -ENODATA, name_offset, name_len, block_off, i; |
758 | 771 | ||
759 | if (!di->i_xattr_loc) | ||
760 | return ret; | ||
761 | |||
762 | memset(&xs->bucket, 0, sizeof(xs->bucket)); | 772 | memset(&xs->bucket, 0, sizeof(xs->bucket)); |
763 | 773 | ||
764 | ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh); | 774 | ret = ocfs2_xattr_block_find(inode, name_index, name, xs); |
765 | if (ret < 0) { | 775 | if (ret) { |
766 | mlog_errno(ret); | 776 | mlog_errno(ret); |
767 | return ret; | ||
768 | } | ||
769 | /*Verify the signature of xattr block*/ | ||
770 | if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, | ||
771 | strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { | ||
772 | ret = -EFAULT; | ||
773 | goto cleanup; | 777 | goto cleanup; |
774 | } | 778 | } |
775 | 779 | ||
776 | xs->xattr_bh = blk_bh; | 780 | if (xs->not_found) { |
777 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; | 781 | ret = -ENODATA; |
778 | |||
779 | if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { | ||
780 | xs->header = &xb->xb_attrs.xb_header; | ||
781 | xs->base = (void *)xs->header; | ||
782 | xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size; | ||
783 | xs->here = xs->header->xh_entries; | ||
784 | |||
785 | ret = ocfs2_xattr_find_entry(name_index, name, xs); | ||
786 | } else | ||
787 | ret = ocfs2_xattr_index_block_find(inode, blk_bh, | ||
788 | name_index, | ||
789 | name, xs); | ||
790 | |||
791 | if (ret) | ||
792 | goto cleanup; | 782 | goto cleanup; |
783 | } | ||
784 | |||
785 | xb = (struct ocfs2_xattr_block *)xs->xattr_bh->b_data; | ||
793 | size = le64_to_cpu(xs->here->xe_value_size); | 786 | size = le64_to_cpu(xs->here->xe_value_size); |
794 | if (buffer) { | 787 | if (buffer) { |
795 | ret = -ERANGE; | 788 | ret = -ERANGE; |
@@ -828,7 +821,8 @@ cleanup: | |||
828 | brelse(xs->bucket.bhs[i]); | 821 | brelse(xs->bucket.bhs[i]); |
829 | memset(&xs->bucket, 0, sizeof(xs->bucket)); | 822 | memset(&xs->bucket, 0, sizeof(xs->bucket)); |
830 | 823 | ||
831 | brelse(blk_bh); | 824 | brelse(xs->xattr_bh); |
825 | xs->xattr_bh = NULL; | ||
832 | return ret; | 826 | return ret; |
833 | } | 827 | } |
834 | 828 | ||
@@ -837,11 +831,11 @@ cleanup: | |||
837 | * Copy an extended attribute into the buffer provided. | 831 | * Copy an extended attribute into the buffer provided. |
838 | * Buffer is NULL to compute the size of buffer required. | 832 | * Buffer is NULL to compute the size of buffer required. |
839 | */ | 833 | */ |
840 | int ocfs2_xattr_get(struct inode *inode, | 834 | static int ocfs2_xattr_get(struct inode *inode, |
841 | int name_index, | 835 | int name_index, |
842 | const char *name, | 836 | const char *name, |
843 | void *buffer, | 837 | void *buffer, |
844 | size_t buffer_size) | 838 | size_t buffer_size) |
845 | { | 839 | { |
846 | int ret; | 840 | int ret; |
847 | struct ocfs2_dinode *di = NULL; | 841 | struct ocfs2_dinode *di = NULL; |
@@ -871,7 +865,7 @@ int ocfs2_xattr_get(struct inode *inode, | |||
871 | down_read(&oi->ip_xattr_sem); | 865 | down_read(&oi->ip_xattr_sem); |
872 | ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer, | 866 | ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer, |
873 | buffer_size, &xis); | 867 | buffer_size, &xis); |
874 | if (ret == -ENODATA) | 868 | if (ret == -ENODATA && di->i_xattr_loc) |
875 | ret = ocfs2_xattr_block_get(inode, name_index, name, buffer, | 869 | ret = ocfs2_xattr_block_get(inode, name_index, name, buffer, |
876 | buffer_size, &xbs); | 870 | buffer_size, &xbs); |
877 | up_read(&oi->ip_xattr_sem); | 871 | up_read(&oi->ip_xattr_sem); |
@@ -1229,7 +1223,7 @@ static int ocfs2_xattr_set_entry(struct inode *inode, | |||
1229 | 1223 | ||
1230 | free = min_offs - ((void *)last - xs->base) - sizeof(__u32); | 1224 | free = min_offs - ((void *)last - xs->base) - sizeof(__u32); |
1231 | if (free < 0) | 1225 | if (free < 0) |
1232 | return -EFAULT; | 1226 | return -EIO; |
1233 | 1227 | ||
1234 | if (!xs->not_found) { | 1228 | if (!xs->not_found) { |
1235 | size_t size = 0; | 1229 | size_t size = 0; |
@@ -1514,10 +1508,9 @@ static int ocfs2_xattr_free_block(struct inode *inode, | |||
1514 | goto out; | 1508 | goto out; |
1515 | } | 1509 | } |
1516 | 1510 | ||
1517 | /*Verify the signature of xattr block*/ | 1511 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; |
1518 | if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, | 1512 | if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) { |
1519 | strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { | 1513 | ret = -EIO; |
1520 | ret = -EFAULT; | ||
1521 | goto out; | 1514 | goto out; |
1522 | } | 1515 | } |
1523 | 1516 | ||
@@ -1527,7 +1520,6 @@ static int ocfs2_xattr_free_block(struct inode *inode, | |||
1527 | goto out; | 1520 | goto out; |
1528 | } | 1521 | } |
1529 | 1522 | ||
1530 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; | ||
1531 | blk = le64_to_cpu(xb->xb_blkno); | 1523 | blk = le64_to_cpu(xb->xb_blkno); |
1532 | bit = le16_to_cpu(xb->xb_suballoc_bit); | 1524 | bit = le16_to_cpu(xb->xb_suballoc_bit); |
1533 | bg_blkno = ocfs2_which_suballoc_group(blk, bit); | 1525 | bg_blkno = ocfs2_which_suballoc_group(blk, bit); |
@@ -1771,15 +1763,14 @@ static int ocfs2_xattr_block_find(struct inode *inode, | |||
1771 | mlog_errno(ret); | 1763 | mlog_errno(ret); |
1772 | return ret; | 1764 | return ret; |
1773 | } | 1765 | } |
1774 | /*Verify the signature of xattr block*/ | 1766 | |
1775 | if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, | 1767 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; |
1776 | strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { | 1768 | if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) { |
1777 | ret = -EFAULT; | 1769 | ret = -EIO; |
1778 | goto cleanup; | 1770 | goto cleanup; |
1779 | } | 1771 | } |
1780 | 1772 | ||
1781 | xs->xattr_bh = blk_bh; | 1773 | xs->xattr_bh = blk_bh; |
1782 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; | ||
1783 | 1774 | ||
1784 | if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { | 1775 | if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { |
1785 | xs->header = &xb->xb_attrs.xb_header; | 1776 | xs->header = &xb->xb_attrs.xb_header; |
@@ -1806,52 +1797,6 @@ cleanup: | |||
1806 | } | 1797 | } |
1807 | 1798 | ||
1808 | /* | 1799 | /* |
1809 | * When all the xattrs are deleted from index btree, the ocfs2_xattr_tree | ||
1810 | * will be erased and ocfs2_xattr_block will have its ocfs2_xattr_header | ||
1811 | * re-initialized. | ||
1812 | */ | ||
1813 | static int ocfs2_restore_xattr_block(struct inode *inode, | ||
1814 | struct ocfs2_xattr_search *xs) | ||
1815 | { | ||
1816 | int ret; | ||
1817 | handle_t *handle; | ||
1818 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
1819 | struct ocfs2_xattr_block *xb = | ||
1820 | (struct ocfs2_xattr_block *)xs->xattr_bh->b_data; | ||
1821 | struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list; | ||
1822 | u16 xb_flags = le16_to_cpu(xb->xb_flags); | ||
1823 | |||
1824 | BUG_ON(!(xb_flags & OCFS2_XATTR_INDEXED) || | ||
1825 | le16_to_cpu(el->l_next_free_rec) != 0); | ||
1826 | |||
1827 | handle = ocfs2_start_trans(osb, OCFS2_XATTR_BLOCK_UPDATE_CREDITS); | ||
1828 | if (IS_ERR(handle)) { | ||
1829 | ret = PTR_ERR(handle); | ||
1830 | handle = NULL; | ||
1831 | goto out; | ||
1832 | } | ||
1833 | |||
1834 | ret = ocfs2_journal_access(handle, inode, xs->xattr_bh, | ||
1835 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
1836 | if (ret < 0) { | ||
1837 | mlog_errno(ret); | ||
1838 | goto out_commit; | ||
1839 | } | ||
1840 | |||
1841 | memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize - | ||
1842 | offsetof(struct ocfs2_xattr_block, xb_attrs)); | ||
1843 | |||
1844 | xb->xb_flags = cpu_to_le16(xb_flags & ~OCFS2_XATTR_INDEXED); | ||
1845 | |||
1846 | ocfs2_journal_dirty(handle, xs->xattr_bh); | ||
1847 | |||
1848 | out_commit: | ||
1849 | ocfs2_commit_trans(osb, handle); | ||
1850 | out: | ||
1851 | return ret; | ||
1852 | } | ||
1853 | |||
1854 | /* | ||
1855 | * ocfs2_xattr_block_set() | 1800 | * ocfs2_xattr_block_set() |
1856 | * | 1801 | * |
1857 | * Set, replace or remove an extended attribute into external block. | 1802 | * Set, replace or remove an extended attribute into external block. |
@@ -1961,8 +1906,6 @@ out: | |||
1961 | } | 1906 | } |
1962 | 1907 | ||
1963 | ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs); | 1908 | ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs); |
1964 | if (!ret && xblk->xb_attrs.xb_root.xt_list.l_next_free_rec == 0) | ||
1965 | ret = ocfs2_restore_xattr_block(inode, xs); | ||
1966 | 1909 | ||
1967 | end: | 1910 | end: |
1968 | 1911 | ||
@@ -2398,7 +2341,8 @@ static int ocfs2_xattr_index_block_find(struct inode *inode, | |||
2398 | BUG_ON(p_blkno == 0 || num_clusters == 0 || first_hash > name_hash); | 2341 | BUG_ON(p_blkno == 0 || num_clusters == 0 || first_hash > name_hash); |
2399 | 2342 | ||
2400 | mlog(0, "find xattr extent rec %u clusters from %llu, the first hash " | 2343 | mlog(0, "find xattr extent rec %u clusters from %llu, the first hash " |
2401 | "in the rec is %u\n", num_clusters, p_blkno, first_hash); | 2344 | "in the rec is %u\n", num_clusters, (unsigned long long)p_blkno, |
2345 | first_hash); | ||
2402 | 2346 | ||
2403 | ret = ocfs2_xattr_bucket_find(inode, name_index, name, name_hash, | 2347 | ret = ocfs2_xattr_bucket_find(inode, name_index, name, name_hash, |
2404 | p_blkno, first_hash, num_clusters, xs); | 2348 | p_blkno, first_hash, num_clusters, xs); |
@@ -2422,7 +2366,7 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode, | |||
2422 | memset(&bucket, 0, sizeof(bucket)); | 2366 | memset(&bucket, 0, sizeof(bucket)); |
2423 | 2367 | ||
2424 | mlog(0, "iterating xattr buckets in %u clusters starting from %llu\n", | 2368 | mlog(0, "iterating xattr buckets in %u clusters starting from %llu\n", |
2425 | clusters, blkno); | 2369 | clusters, (unsigned long long)blkno); |
2426 | 2370 | ||
2427 | for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) { | 2371 | for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) { |
2428 | ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, | 2372 | ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, |
@@ -2440,7 +2384,8 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode, | |||
2440 | if (i == 0) | 2384 | if (i == 0) |
2441 | num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets); | 2385 | num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets); |
2442 | 2386 | ||
2443 | mlog(0, "iterating xattr bucket %llu, first hash %u\n", blkno, | 2387 | mlog(0, "iterating xattr bucket %llu, first hash %u\n", |
2388 | (unsigned long long)blkno, | ||
2444 | le32_to_cpu(bucket.xh->xh_entries[0].xe_name_hash)); | 2389 | le32_to_cpu(bucket.xh->xh_entries[0].xe_name_hash)); |
2445 | if (func) { | 2390 | if (func) { |
2446 | ret = func(inode, &bucket, para); | 2391 | ret = func(inode, &bucket, para); |
@@ -2776,7 +2721,8 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, | |||
2776 | */ | 2721 | */ |
2777 | blkno = ocfs2_clusters_to_blocks(inode->i_sb, bit_off); | 2722 | blkno = ocfs2_clusters_to_blocks(inode->i_sb, bit_off); |
2778 | 2723 | ||
2779 | mlog(0, "allocate 1 cluster from %llu to xattr block\n", blkno); | 2724 | mlog(0, "allocate 1 cluster from %llu to xattr block\n", |
2725 | (unsigned long long)blkno); | ||
2780 | 2726 | ||
2781 | xh_bh = sb_getblk(inode->i_sb, blkno); | 2727 | xh_bh = sb_getblk(inode->i_sb, blkno); |
2782 | if (!xh_bh) { | 2728 | if (!xh_bh) { |
@@ -2818,7 +2764,11 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, | |||
2818 | if (data_bh) | 2764 | if (data_bh) |
2819 | ocfs2_journal_dirty(handle, data_bh); | 2765 | ocfs2_journal_dirty(handle, data_bh); |
2820 | 2766 | ||
2821 | ocfs2_xattr_update_xattr_search(inode, xs, xb_bh, xh_bh); | 2767 | ret = ocfs2_xattr_update_xattr_search(inode, xs, xb_bh, xh_bh); |
2768 | if (ret) { | ||
2769 | mlog_errno(ret); | ||
2770 | goto out_commit; | ||
2771 | } | ||
2822 | 2772 | ||
2823 | /* Change from ocfs2_xattr_header to ocfs2_xattr_tree_root */ | 2773 | /* Change from ocfs2_xattr_header to ocfs2_xattr_tree_root */ |
2824 | memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize - | 2774 | memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize - |
@@ -2941,8 +2891,8 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, | |||
2941 | 2891 | ||
2942 | mlog(0, "adjust xattr bucket in %llu, count = %u, " | 2892 | mlog(0, "adjust xattr bucket in %llu, count = %u, " |
2943 | "xh_free_start = %u, xh_name_value_len = %u.\n", | 2893 | "xh_free_start = %u, xh_name_value_len = %u.\n", |
2944 | blkno, le16_to_cpu(xh->xh_count), xh_free_start, | 2894 | (unsigned long long)blkno, le16_to_cpu(xh->xh_count), |
2945 | le16_to_cpu(xh->xh_name_value_len)); | 2895 | xh_free_start, le16_to_cpu(xh->xh_name_value_len)); |
2946 | 2896 | ||
2947 | /* | 2897 | /* |
2948 | * sort all the entries by their offset. | 2898 | * sort all the entries by their offset. |
@@ -3058,7 +3008,7 @@ static int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode, | |||
3058 | prev_blkno += (num_clusters - 1) * bpc + bpc / 2; | 3008 | prev_blkno += (num_clusters - 1) * bpc + bpc / 2; |
3059 | 3009 | ||
3060 | mlog(0, "move half of xattrs in cluster %llu to %llu\n", | 3010 | mlog(0, "move half of xattrs in cluster %llu to %llu\n", |
3061 | prev_blkno, new_blkno); | 3011 | (unsigned long long)prev_blkno, (unsigned long long)new_blkno); |
3062 | 3012 | ||
3063 | /* | 3013 | /* |
3064 | * We need to update the 1st half of the new cluster and | 3014 | * We need to update the 1st half of the new cluster and |
@@ -3168,26 +3118,74 @@ static int ocfs2_read_xattr_bucket(struct inode *inode, | |||
3168 | } | 3118 | } |
3169 | 3119 | ||
3170 | /* | 3120 | /* |
3171 | * Move half num of the xattrs in old bucket(blk) to new bucket(new_blk). | 3121 | * Find the suitable pos when we divide a bucket into 2. |
3122 | * We have to make sure the xattrs with the same hash value exist | ||
3123 | * in the same bucket. | ||
3124 | * | ||
3125 | * If this ocfs2_xattr_header covers more than one hash value, find a | ||
3126 | * place where the hash value changes. Try to find the most even split. | ||
3127 | * The most common case is that all entries have different hash values, | ||
3128 | * and the first check we make will find a place to split. | ||
3129 | */ | ||
3130 | static int ocfs2_xattr_find_divide_pos(struct ocfs2_xattr_header *xh) | ||
3131 | { | ||
3132 | struct ocfs2_xattr_entry *entries = xh->xh_entries; | ||
3133 | int count = le16_to_cpu(xh->xh_count); | ||
3134 | int delta, middle = count / 2; | ||
3135 | |||
3136 | /* | ||
3137 | * We start at the middle. Each step gets farther away in both | ||
3138 | * directions. We therefore hit the change in hash value | ||
3139 | * nearest to the middle. Note that this loop does not execute for | ||
3140 | * count < 2. | ||
3141 | */ | ||
3142 | for (delta = 0; delta < middle; delta++) { | ||
3143 | /* Let's check delta earlier than middle */ | ||
3144 | if (cmp_xe(&entries[middle - delta - 1], | ||
3145 | &entries[middle - delta])) | ||
3146 | return middle - delta; | ||
3147 | |||
3148 | /* For even counts, don't walk off the end */ | ||
3149 | if ((middle + delta + 1) == count) | ||
3150 | continue; | ||
3151 | |||
3152 | /* Now try delta past middle */ | ||
3153 | if (cmp_xe(&entries[middle + delta], | ||
3154 | &entries[middle + delta + 1])) | ||
3155 | return middle + delta + 1; | ||
3156 | } | ||
3157 | |||
3158 | /* Every entry had the same hash */ | ||
3159 | return count; | ||
3160 | } | ||
3161 | |||
3162 | /* | ||
3163 | * Move some xattrs in old bucket(blk) to new bucket(new_blk). | ||
3172 | * first_hash will record the 1st hash of the new bucket. | 3164 | * first_hash will record the 1st hash of the new bucket. |
3165 | * | ||
3166 | * Normally half of the xattrs will be moved. But we have to make | ||
3167 | * sure that the xattrs with the same hash value are stored in the | ||
3168 | * same bucket. If all the xattrs in this bucket have the same hash | ||
3169 | * value, the new bucket will be initialized as an empty one and the | ||
3170 | * first_hash will be initialized as (hash_value+1). | ||
3173 | */ | 3171 | */ |
3174 | static int ocfs2_half_xattr_bucket(struct inode *inode, | 3172 | static int ocfs2_divide_xattr_bucket(struct inode *inode, |
3175 | handle_t *handle, | 3173 | handle_t *handle, |
3176 | u64 blk, | 3174 | u64 blk, |
3177 | u64 new_blk, | 3175 | u64 new_blk, |
3178 | u32 *first_hash, | 3176 | u32 *first_hash, |
3179 | int new_bucket_head) | 3177 | int new_bucket_head) |
3180 | { | 3178 | { |
3181 | int ret, i; | 3179 | int ret, i; |
3182 | u16 count, start, len, name_value_len, xe_len, name_offset; | 3180 | int count, start, len, name_value_len = 0, xe_len, name_offset = 0; |
3183 | u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); | 3181 | u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); |
3184 | struct buffer_head **s_bhs, **t_bhs = NULL; | 3182 | struct buffer_head **s_bhs, **t_bhs = NULL; |
3185 | struct ocfs2_xattr_header *xh; | 3183 | struct ocfs2_xattr_header *xh; |
3186 | struct ocfs2_xattr_entry *xe; | 3184 | struct ocfs2_xattr_entry *xe; |
3187 | int blocksize = inode->i_sb->s_blocksize; | 3185 | int blocksize = inode->i_sb->s_blocksize; |
3188 | 3186 | ||
3189 | mlog(0, "move half of xattrs from bucket %llu to %llu\n", | 3187 | mlog(0, "move some of xattrs from bucket %llu to %llu\n", |
3190 | blk, new_blk); | 3188 | (unsigned long long)blk, (unsigned long long)new_blk); |
3191 | 3189 | ||
3192 | s_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS); | 3190 | s_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS); |
3193 | if (!s_bhs) | 3191 | if (!s_bhs) |
@@ -3220,21 +3218,44 @@ static int ocfs2_half_xattr_bucket(struct inode *inode, | |||
3220 | 3218 | ||
3221 | for (i = 0; i < blk_per_bucket; i++) { | 3219 | for (i = 0; i < blk_per_bucket; i++) { |
3222 | ret = ocfs2_journal_access(handle, inode, t_bhs[i], | 3220 | ret = ocfs2_journal_access(handle, inode, t_bhs[i], |
3223 | OCFS2_JOURNAL_ACCESS_CREATE); | 3221 | new_bucket_head ? |
3222 | OCFS2_JOURNAL_ACCESS_CREATE : | ||
3223 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
3224 | if (ret) { | 3224 | if (ret) { |
3225 | mlog_errno(ret); | 3225 | mlog_errno(ret); |
3226 | goto out; | 3226 | goto out; |
3227 | } | 3227 | } |
3228 | } | 3228 | } |
3229 | 3229 | ||
3230 | xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data; | ||
3231 | count = le16_to_cpu(xh->xh_count); | ||
3232 | start = ocfs2_xattr_find_divide_pos(xh); | ||
3233 | |||
3234 | if (start == count) { | ||
3235 | xe = &xh->xh_entries[start-1]; | ||
3236 | |||
3237 | /* | ||
3238 | * initialized a new empty bucket here. | ||
3239 | * The hash value is set as one larger than | ||
3240 | * that of the last entry in the previous bucket. | ||
3241 | */ | ||
3242 | for (i = 0; i < blk_per_bucket; i++) | ||
3243 | memset(t_bhs[i]->b_data, 0, blocksize); | ||
3244 | |||
3245 | xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data; | ||
3246 | xh->xh_free_start = cpu_to_le16(blocksize); | ||
3247 | xh->xh_entries[0].xe_name_hash = xe->xe_name_hash; | ||
3248 | le32_add_cpu(&xh->xh_entries[0].xe_name_hash, 1); | ||
3249 | |||
3250 | goto set_num_buckets; | ||
3251 | } | ||
3252 | |||
3230 | /* copy the whole bucket to the new first. */ | 3253 | /* copy the whole bucket to the new first. */ |
3231 | for (i = 0; i < blk_per_bucket; i++) | 3254 | for (i = 0; i < blk_per_bucket; i++) |
3232 | memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize); | 3255 | memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize); |
3233 | 3256 | ||
3234 | /* update the new bucket. */ | 3257 | /* update the new bucket. */ |
3235 | xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data; | 3258 | xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data; |
3236 | count = le16_to_cpu(xh->xh_count); | ||
3237 | start = count / 2; | ||
3238 | 3259 | ||
3239 | /* | 3260 | /* |
3240 | * Calculate the total name/value len and xh_free_start for | 3261 | * Calculate the total name/value len and xh_free_start for |
@@ -3291,6 +3312,7 @@ static int ocfs2_half_xattr_bucket(struct inode *inode, | |||
3291 | xh->xh_free_start = xe->xe_name_offset; | 3312 | xh->xh_free_start = xe->xe_name_offset; |
3292 | } | 3313 | } |
3293 | 3314 | ||
3315 | set_num_buckets: | ||
3294 | /* set xh->xh_num_buckets for the new xh. */ | 3316 | /* set xh->xh_num_buckets for the new xh. */ |
3295 | if (new_bucket_head) | 3317 | if (new_bucket_head) |
3296 | xh->xh_num_buckets = cpu_to_le16(1); | 3318 | xh->xh_num_buckets = cpu_to_le16(1); |
@@ -3308,9 +3330,13 @@ static int ocfs2_half_xattr_bucket(struct inode *inode, | |||
3308 | *first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash); | 3330 | *first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash); |
3309 | 3331 | ||
3310 | /* | 3332 | /* |
3311 | * Now only update the 1st block of the old bucket. | 3333 | * Now only update the 1st block of the old bucket. If we |
3312 | * Please note that the entry has been sorted already above. | 3334 | * just added a new empty bucket, there is no need to modify |
3335 | * it. | ||
3313 | */ | 3336 | */ |
3337 | if (start == count) | ||
3338 | goto out; | ||
3339 | |||
3314 | xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data; | 3340 | xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data; |
3315 | memset(&xh->xh_entries[start], 0, | 3341 | memset(&xh->xh_entries[start], 0, |
3316 | sizeof(struct ocfs2_xattr_entry) * (count - start)); | 3342 | sizeof(struct ocfs2_xattr_entry) * (count - start)); |
@@ -3358,7 +3384,8 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode, | |||
3358 | BUG_ON(s_blkno == t_blkno); | 3384 | BUG_ON(s_blkno == t_blkno); |
3359 | 3385 | ||
3360 | mlog(0, "cp bucket %llu to %llu, target is %d\n", | 3386 | mlog(0, "cp bucket %llu to %llu, target is %d\n", |
3361 | s_blkno, t_blkno, t_is_new); | 3387 | (unsigned long long)s_blkno, (unsigned long long)t_blkno, |
3388 | t_is_new); | ||
3362 | 3389 | ||
3363 | s_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket, | 3390 | s_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket, |
3364 | GFP_NOFS); | 3391 | GFP_NOFS); |
@@ -3382,6 +3409,8 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode, | |||
3382 | 3409 | ||
3383 | for (i = 0; i < blk_per_bucket; i++) { | 3410 | for (i = 0; i < blk_per_bucket; i++) { |
3384 | ret = ocfs2_journal_access(handle, inode, t_bhs[i], | 3411 | ret = ocfs2_journal_access(handle, inode, t_bhs[i], |
3412 | t_is_new ? | ||
3413 | OCFS2_JOURNAL_ACCESS_CREATE : | ||
3385 | OCFS2_JOURNAL_ACCESS_WRITE); | 3414 | OCFS2_JOURNAL_ACCESS_WRITE); |
3386 | if (ret) | 3415 | if (ret) |
3387 | goto out; | 3416 | goto out; |
@@ -3428,7 +3457,8 @@ static int ocfs2_cp_xattr_cluster(struct inode *inode, | |||
3428 | struct ocfs2_xattr_header *xh; | 3457 | struct ocfs2_xattr_header *xh; |
3429 | u64 to_blk_start = to_blk; | 3458 | u64 to_blk_start = to_blk; |
3430 | 3459 | ||
3431 | mlog(0, "cp xattrs from cluster %llu to %llu\n", src_blk, to_blk); | 3460 | mlog(0, "cp xattrs from cluster %llu to %llu\n", |
3461 | (unsigned long long)src_blk, (unsigned long long)to_blk); | ||
3432 | 3462 | ||
3433 | /* | 3463 | /* |
3434 | * We need to update the new cluster and 1 more for the update of | 3464 | * We need to update the new cluster and 1 more for the update of |
@@ -3493,15 +3523,15 @@ out: | |||
3493 | } | 3523 | } |
3494 | 3524 | ||
3495 | /* | 3525 | /* |
3496 | * Move half of the xattrs in this cluster to the new cluster. | 3526 | * Move some xattrs in this cluster to the new cluster. |
3497 | * This function should only be called when bucket size == cluster size. | 3527 | * This function should only be called when bucket size == cluster size. |
3498 | * Otherwise ocfs2_mv_xattr_bucket_cross_cluster should be used instead. | 3528 | * Otherwise ocfs2_mv_xattr_bucket_cross_cluster should be used instead. |
3499 | */ | 3529 | */ |
3500 | static int ocfs2_half_xattr_cluster(struct inode *inode, | 3530 | static int ocfs2_divide_xattr_cluster(struct inode *inode, |
3501 | handle_t *handle, | 3531 | handle_t *handle, |
3502 | u64 prev_blk, | 3532 | u64 prev_blk, |
3503 | u64 new_blk, | 3533 | u64 new_blk, |
3504 | u32 *first_hash) | 3534 | u32 *first_hash) |
3505 | { | 3535 | { |
3506 | u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); | 3536 | u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); |
3507 | int ret, credits = 2 * blk_per_bucket; | 3537 | int ret, credits = 2 * blk_per_bucket; |
@@ -3515,8 +3545,8 @@ static int ocfs2_half_xattr_cluster(struct inode *inode, | |||
3515 | } | 3545 | } |
3516 | 3546 | ||
3517 | /* Move half of the xattr in start_blk to the next bucket. */ | 3547 | /* Move half of the xattr in start_blk to the next bucket. */ |
3518 | return ocfs2_half_xattr_bucket(inode, handle, prev_blk, | 3548 | return ocfs2_divide_xattr_bucket(inode, handle, prev_blk, |
3519 | new_blk, first_hash, 1); | 3549 | new_blk, first_hash, 1); |
3520 | } | 3550 | } |
3521 | 3551 | ||
3522 | /* | 3552 | /* |
@@ -3559,7 +3589,8 @@ static int ocfs2_adjust_xattr_cross_cluster(struct inode *inode, | |||
3559 | int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); | 3589 | int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); |
3560 | 3590 | ||
3561 | mlog(0, "adjust xattrs from cluster %llu len %u to %llu\n", | 3591 | mlog(0, "adjust xattrs from cluster %llu len %u to %llu\n", |
3562 | prev_blk, prev_clusters, new_blk); | 3592 | (unsigned long long)prev_blk, prev_clusters, |
3593 | (unsigned long long)new_blk); | ||
3563 | 3594 | ||
3564 | if (ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb)) > 1) | 3595 | if (ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb)) > 1) |
3565 | ret = ocfs2_mv_xattr_bucket_cross_cluster(inode, | 3596 | ret = ocfs2_mv_xattr_bucket_cross_cluster(inode, |
@@ -3578,9 +3609,9 @@ static int ocfs2_adjust_xattr_cross_cluster(struct inode *inode, | |||
3578 | last_blk, new_blk, | 3609 | last_blk, new_blk, |
3579 | v_start); | 3610 | v_start); |
3580 | else { | 3611 | else { |
3581 | ret = ocfs2_half_xattr_cluster(inode, handle, | 3612 | ret = ocfs2_divide_xattr_cluster(inode, handle, |
3582 | last_blk, new_blk, | 3613 | last_blk, new_blk, |
3583 | v_start); | 3614 | v_start); |
3584 | 3615 | ||
3585 | if ((*header_bh)->b_blocknr == last_blk && extend) | 3616 | if ((*header_bh)->b_blocknr == last_blk && extend) |
3586 | *extend = 0; | 3617 | *extend = 0; |
@@ -3629,7 +3660,7 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, | |||
3629 | mlog(0, "Add new xattr cluster for %llu, previous xattr hash = %u, " | 3660 | mlog(0, "Add new xattr cluster for %llu, previous xattr hash = %u, " |
3630 | "previous xattr blkno = %llu\n", | 3661 | "previous xattr blkno = %llu\n", |
3631 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | 3662 | (unsigned long long)OCFS2_I(inode)->ip_blkno, |
3632 | prev_cpos, prev_blkno); | 3663 | prev_cpos, (unsigned long long)prev_blkno); |
3633 | 3664 | ||
3634 | ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh); | 3665 | ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh); |
3635 | 3666 | ||
@@ -3716,7 +3747,7 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, | |||
3716 | } | 3747 | } |
3717 | } | 3748 | } |
3718 | mlog(0, "Insert %u clusters at block %llu for xattr at %u\n", | 3749 | mlog(0, "Insert %u clusters at block %llu for xattr at %u\n", |
3719 | num_bits, block, v_start); | 3750 | num_bits, (unsigned long long)block, v_start); |
3720 | ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block, | 3751 | ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block, |
3721 | num_bits, 0, meta_ac); | 3752 | num_bits, 0, meta_ac); |
3722 | if (ret < 0) { | 3753 | if (ret < 0) { |
@@ -3761,7 +3792,7 @@ static int ocfs2_extend_xattr_bucket(struct inode *inode, | |||
3761 | u16 bucket = le16_to_cpu(first_xh->xh_num_buckets); | 3792 | u16 bucket = le16_to_cpu(first_xh->xh_num_buckets); |
3762 | 3793 | ||
3763 | mlog(0, "extend xattr bucket in %llu, xattr extend rec starting " | 3794 | mlog(0, "extend xattr bucket in %llu, xattr extend rec starting " |
3764 | "from %llu, len = %u\n", start_blk, | 3795 | "from %llu, len = %u\n", (unsigned long long)start_blk, |
3765 | (unsigned long long)first_bh->b_blocknr, num_clusters); | 3796 | (unsigned long long)first_bh->b_blocknr, num_clusters); |
3766 | 3797 | ||
3767 | BUG_ON(bucket >= num_buckets); | 3798 | BUG_ON(bucket >= num_buckets); |
@@ -3797,8 +3828,8 @@ static int ocfs2_extend_xattr_bucket(struct inode *inode, | |||
3797 | } | 3828 | } |
3798 | 3829 | ||
3799 | /* Move half of the xattr in start_blk to the next bucket. */ | 3830 | /* Move half of the xattr in start_blk to the next bucket. */ |
3800 | ret = ocfs2_half_xattr_bucket(inode, handle, start_blk, | 3831 | ret = ocfs2_divide_xattr_bucket(inode, handle, start_blk, |
3801 | start_blk + blk_per_bucket, NULL, 0); | 3832 | start_blk + blk_per_bucket, NULL, 0); |
3802 | 3833 | ||
3803 | le16_add_cpu(&first_xh->xh_num_buckets, 1); | 3834 | le16_add_cpu(&first_xh->xh_num_buckets, 1); |
3804 | ocfs2_journal_dirty(handle, first_bh); | 3835 | ocfs2_journal_dirty(handle, first_bh); |
@@ -4146,7 +4177,7 @@ static int ocfs2_xattr_value_update_size(struct inode *inode, | |||
4146 | handle_t *handle = NULL; | 4177 | handle_t *handle = NULL; |
4147 | 4178 | ||
4148 | handle = ocfs2_start_trans(osb, 1); | 4179 | handle = ocfs2_start_trans(osb, 1); |
4149 | if (handle == NULL) { | 4180 | if (IS_ERR(handle)) { |
4150 | ret = -ENOMEM; | 4181 | ret = -ENOMEM; |
4151 | mlog_errno(ret); | 4182 | mlog_errno(ret); |
4152 | goto out; | 4183 | goto out; |
@@ -4313,7 +4344,7 @@ static int ocfs2_rm_xattr_cluster(struct inode *inode, | |||
4313 | } | 4344 | } |
4314 | 4345 | ||
4315 | handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); | 4346 | handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); |
4316 | if (handle == NULL) { | 4347 | if (IS_ERR(handle)) { |
4317 | ret = -ENOMEM; | 4348 | ret = -ENOMEM; |
4318 | mlog_errno(ret); | 4349 | mlog_errno(ret); |
4319 | goto out; | 4350 | goto out; |
@@ -4489,11 +4520,21 @@ out: | |||
4489 | return ret; | 4520 | return ret; |
4490 | } | 4521 | } |
4491 | 4522 | ||
4492 | /* check whether the xattr bucket is filled up with the same hash value. */ | 4523 | /* |
4524 | * check whether the xattr bucket is filled up with the same hash value. | ||
4525 | * If we want to insert the xattr with the same hash, return -ENOSPC. | ||
4526 | * If we want to insert a xattr with different hash value, go ahead | ||
4527 | * and ocfs2_divide_xattr_bucket will handle this. | ||
4528 | */ | ||
4493 | static int ocfs2_check_xattr_bucket_collision(struct inode *inode, | 4529 | static int ocfs2_check_xattr_bucket_collision(struct inode *inode, |
4494 | struct ocfs2_xattr_bucket *bucket) | 4530 | struct ocfs2_xattr_bucket *bucket, |
4531 | const char *name) | ||
4495 | { | 4532 | { |
4496 | struct ocfs2_xattr_header *xh = bucket->xh; | 4533 | struct ocfs2_xattr_header *xh = bucket->xh; |
4534 | u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name)); | ||
4535 | |||
4536 | if (name_hash != le32_to_cpu(xh->xh_entries[0].xe_name_hash)) | ||
4537 | return 0; | ||
4497 | 4538 | ||
4498 | if (xh->xh_entries[le16_to_cpu(xh->xh_count) - 1].xe_name_hash == | 4539 | if (xh->xh_entries[le16_to_cpu(xh->xh_count) - 1].xe_name_hash == |
4499 | xh->xh_entries[0].xe_name_hash) { | 4540 | xh->xh_entries[0].xe_name_hash) { |
@@ -4616,7 +4657,9 @@ try_again: | |||
4616 | * one bucket's worth, so check it here whether we need to | 4657 | * one bucket's worth, so check it here whether we need to |
4617 | * add a new bucket for the insert. | 4658 | * add a new bucket for the insert. |
4618 | */ | 4659 | */ |
4619 | ret = ocfs2_check_xattr_bucket_collision(inode, &xs->bucket); | 4660 | ret = ocfs2_check_xattr_bucket_collision(inode, |
4661 | &xs->bucket, | ||
4662 | xi->name); | ||
4620 | if (ret) { | 4663 | if (ret) { |
4621 | mlog_errno(ret); | 4664 | mlog_errno(ret); |
4622 | goto out; | 4665 | goto out; |
@@ -4727,14 +4770,11 @@ out: | |||
4727 | /* | 4770 | /* |
4728 | * 'trusted' attributes support | 4771 | * 'trusted' attributes support |
4729 | */ | 4772 | */ |
4730 | |||
4731 | #define XATTR_TRUSTED_PREFIX "trusted." | ||
4732 | |||
4733 | static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list, | 4773 | static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list, |
4734 | size_t list_size, const char *name, | 4774 | size_t list_size, const char *name, |
4735 | size_t name_len) | 4775 | size_t name_len) |
4736 | { | 4776 | { |
4737 | const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX) - 1; | 4777 | const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN; |
4738 | const size_t total_len = prefix_len + name_len + 1; | 4778 | const size_t total_len = prefix_len + name_len + 1; |
4739 | 4779 | ||
4740 | if (list && total_len <= list_size) { | 4780 | if (list && total_len <= list_size) { |
@@ -4771,18 +4811,14 @@ struct xattr_handler ocfs2_xattr_trusted_handler = { | |||
4771 | .set = ocfs2_xattr_trusted_set, | 4811 | .set = ocfs2_xattr_trusted_set, |
4772 | }; | 4812 | }; |
4773 | 4813 | ||
4774 | |||
4775 | /* | 4814 | /* |
4776 | * 'user' attributes support | 4815 | * 'user' attributes support |
4777 | */ | 4816 | */ |
4778 | |||
4779 | #define XATTR_USER_PREFIX "user." | ||
4780 | |||
4781 | static size_t ocfs2_xattr_user_list(struct inode *inode, char *list, | 4817 | static size_t ocfs2_xattr_user_list(struct inode *inode, char *list, |
4782 | size_t list_size, const char *name, | 4818 | size_t list_size, const char *name, |
4783 | size_t name_len) | 4819 | size_t name_len) |
4784 | { | 4820 | { |
4785 | const size_t prefix_len = sizeof(XATTR_USER_PREFIX) - 1; | 4821 | const size_t prefix_len = XATTR_USER_PREFIX_LEN; |
4786 | const size_t total_len = prefix_len + name_len + 1; | 4822 | const size_t total_len = prefix_len + name_len + 1; |
4787 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 4823 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
4788 | 4824 | ||
diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h index c25c7c62a059..1d8314c7656d 100644 --- a/fs/ocfs2/xattr.h +++ b/fs/ocfs2/xattr.h | |||
@@ -3,24 +3,16 @@ | |||
3 | * | 3 | * |
4 | * xattr.h | 4 | * xattr.h |
5 | * | 5 | * |
6 | * Function prototypes | 6 | * Copyright (C) 2004, 2008 Oracle. All rights reserved. |
7 | * | ||
8 | * Copyright (C) 2008 Oracle. All rights reserved. | ||
9 | * | 7 | * |
10 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
11 | * modify it under the terms of the GNU General Public | 9 | * modify it under the terms of the GNU General Public |
12 | * License as published by the Free Software Foundation; either | 10 | * License version 2 as published by the Free Software Foundation. |
13 | * version 2 of the License, or (at your option) any later version. | ||
14 | * | 11 | * |
15 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | * General Public License for more details. | 15 | * General Public License for more details. |
19 | * | ||
20 | * You should have received a copy of the GNU General Public | ||
21 | * License along with this program; if not, write to the | ||
22 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
23 | * Boston, MA 021110-1307, USA. | ||
24 | */ | 16 | */ |
25 | 17 | ||
26 | #ifndef OCFS2_XATTR_H | 18 | #ifndef OCFS2_XATTR_H |
@@ -40,29 +32,11 @@ enum ocfs2_xattr_type { | |||
40 | 32 | ||
41 | extern struct xattr_handler ocfs2_xattr_user_handler; | 33 | extern struct xattr_handler ocfs2_xattr_user_handler; |
42 | extern struct xattr_handler ocfs2_xattr_trusted_handler; | 34 | extern struct xattr_handler ocfs2_xattr_trusted_handler; |
43 | |||
44 | extern ssize_t ocfs2_listxattr(struct dentry *, char *, size_t); | ||
45 | extern int ocfs2_xattr_get(struct inode *, int, const char *, void *, size_t); | ||
46 | extern int ocfs2_xattr_set(struct inode *, int, const char *, const void *, | ||
47 | size_t, int); | ||
48 | extern int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh); | ||
49 | extern struct xattr_handler *ocfs2_xattr_handlers[]; | 35 | extern struct xattr_handler *ocfs2_xattr_handlers[]; |
50 | 36 | ||
51 | static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) | 37 | ssize_t ocfs2_listxattr(struct dentry *, char *, size_t); |
52 | { | 38 | int ocfs2_xattr_set(struct inode *, int, const char *, const void *, |
53 | return (1 << osb->s_clustersize_bits) / OCFS2_XATTR_BUCKET_SIZE; | 39 | size_t, int); |
54 | } | 40 | int ocfs2_xattr_remove(struct inode *, struct buffer_head *); |
55 | |||
56 | static inline u16 ocfs2_blocks_per_xattr_bucket(struct super_block *sb) | ||
57 | { | ||
58 | return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits); | ||
59 | } | ||
60 | |||
61 | static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb) | ||
62 | { | ||
63 | u16 len = sb->s_blocksize - | ||
64 | offsetof(struct ocfs2_xattr_header, xh_entries); | ||
65 | 41 | ||
66 | return len / sizeof(struct ocfs2_xattr_entry); | ||
67 | } | ||
68 | #endif /* OCFS2_XATTR_H */ | 42 | #endif /* OCFS2_XATTR_H */ |