]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.25/patches.suse/ocfs2-Add-extended-attribute-support.patch
Changed checkfs to auto reboot after correctable fsck fixes.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.suse / ocfs2-Add-extended-attribute-support.patch
CommitLineData
00e5a55c
BS
1From: Tiger Yang <tiger.yang@oracle.com>
2Subject: [PATCH 09/16] ocfs2: Add extended attribute support
3Patch-mainline: 2.6.28?
4References: FATE302067
5
6This patch implements storing extended attributes both in inode or a single
7external block. We only store EA's in-inode when blocksize > 512 or that
8inode block has free space for it. When an EA's value is larger than 80
9bytes, we will store the value via b-tree outside inode or block.
10
11Signed-off-by: Tiger Yang <tiger.yang@oracle.com>
12Signed-off-by: Mark Fasheh <mfasheh@suse.com>
13---
14 fs/ocfs2/Makefile | 2
15 fs/ocfs2/file.c | 5
16 fs/ocfs2/inode.c | 8
17 fs/ocfs2/inode.h | 3
18 fs/ocfs2/journal.h | 10
19 fs/ocfs2/namei.c | 5
20 fs/ocfs2/ocfs2.h | 2
21 fs/ocfs2/ocfs2_fs.h | 8
22 fs/ocfs2/suballoc.c | 17
23 fs/ocfs2/suballoc.h | 3
24 fs/ocfs2/super.c | 14
25 fs/ocfs2/symlink.c | 9
26 fs/ocfs2/xattr.c | 1636 +++++++++++++++++++++++++++++++++++++++++++++++
27 fs/ocfs2/xattr.h | 58 +
28 fs/ocfs2/xattr_trusted.c | 82 ++
29 fs/ocfs2/xattr_user.c | 94 ++
30 16 files changed, 1950 insertions(+), 6 deletions(-)
31 create mode 100644 fs/ocfs2/xattr.h
32 create mode 100644 fs/ocfs2/xattr_trusted.c
33 create mode 100644 fs/ocfs2/xattr_user.c
34
35--- a/fs/ocfs2/Makefile
36+++ b/fs/ocfs2/Makefile
37@@ -36,6 +36,8 @@ ocfs2-objs := \
38 uptodate.o \
39 ver.o \
40 xattr.o \
41+ xattr_user.o \
42+ xattr_trusted.o
43
44 ocfs2_stackglue-objs := stackglue.o
45 ocfs2_stack_o2cb-objs := stack_o2cb.o
46--- a/fs/ocfs2/file.c
47+++ b/fs/ocfs2/file.c
48@@ -55,6 +55,7 @@
49 #include "mmap.h"
50 #include "suballoc.h"
51 #include "super.h"
52+#include "xattr.h"
53
54 #include "buffer_head_io.h"
55
56@@ -2128,6 +2129,10 @@ const struct inode_operations ocfs2_file
57 .setattr = ocfs2_setattr,
58 .getattr = ocfs2_getattr,
59 .permission = ocfs2_permission,
60+ .setxattr = generic_setxattr,
61+ .getxattr = generic_getxattr,
62+ .listxattr = ocfs2_listxattr,
63+ .removexattr = generic_removexattr,
64 .fallocate = ocfs2_fallocate,
65 };
66
67--- a/fs/ocfs2/inode.c
68+++ b/fs/ocfs2/inode.c
69@@ -49,6 +49,7 @@
70 #include "symlink.h"
71 #include "sysfile.h"
72 #include "uptodate.h"
73+#include "xattr.h"
74
75 #include "buffer_head_io.h"
76
77@@ -728,6 +729,13 @@ static int ocfs2_wipe_inode(struct inode
78 if (status < 0) {
79 mlog_errno(status);
80 goto bail_unlock_dir;
81+ }
82+
83+ /*Free extended attribute resources associated with this inode.*/
84+ status = ocfs2_xattr_remove(inode, di_bh);
85+ if (status < 0) {
86+ mlog_errno(status);
87+ goto bail_unlock_dir;
88 }
89
90 status = ocfs2_remove_inode(inode, di_bh, orphan_dir_inode,
91--- a/fs/ocfs2/inode.h
92+++ b/fs/ocfs2/inode.h
93@@ -40,6 +40,9 @@ struct ocfs2_inode_info
94 /* protects allocation changes on this inode. */
95 struct rw_semaphore ip_alloc_sem;
96
97+ /* protects extended attribute changes on this inode */
98+ struct rw_semaphore ip_xattr_sem;
99+
100 /* These fields are protected by ip_lock */
101 spinlock_t ip_lock;
102 u32 ip_open_count;
103--- a/fs/ocfs2/journal.h
104+++ b/fs/ocfs2/journal.h
105@@ -283,6 +283,9 @@ int ocfs2_journal_dirty
106 /* simple file updates like chmod, etc. */
107 #define OCFS2_INODE_UPDATE_CREDITS 1
108
109+/* extended attribute block update */
110+#define OCFS2_XATTR_BLOCK_UPDATE_CREDITS 1
111+
112 /* group extend. inode update and last group update. */
113 #define OCFS2_GROUP_EXTEND_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1)
114
115@@ -340,6 +343,13 @@ int ocfs2_journal_dirty
116 #define OCFS2_RENAME_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3 \
117 + OCFS2_UNLINK_CREDITS)
118
119+/* global bitmap dinode, group desc., relinked group,
120+ * suballocator dinode, group desc., relinked group,
121+ * dinode, xattr block */
122+#define OCFS2_XATTR_BLOCK_CREATE_CREDITS (OCFS2_SUBALLOC_ALLOC * 2 + \
123+ + OCFS2_INODE_UPDATE_CREDITS \
124+ + OCFS2_XATTR_BLOCK_UPDATE_CREDITS)
125+
126 /*
127 * Please note that the caller must make sure that root_el is the root
128 * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
129--- a/fs/ocfs2/namei.c
130+++ b/fs/ocfs2/namei.c
131@@ -60,6 +60,7 @@
132 #include "symlink.h"
133 #include "sysfile.h"
134 #include "uptodate.h"
135+#include "xattr.h"
136
137 #include "buffer_head_io.h"
138
139@@ -1918,4 +1919,8 @@ const struct inode_operations ocfs2_dir_
140 .setattr = ocfs2_setattr,
141 .getattr = ocfs2_getattr,
142 .permission = ocfs2_permission,
143+ .setxattr = generic_setxattr,
144+ .getxattr = generic_getxattr,
145+ .listxattr = ocfs2_listxattr,
146+ .removexattr = generic_removexattr,
147 };
148--- a/fs/ocfs2/ocfs2.h
149+++ b/fs/ocfs2/ocfs2.h
150@@ -184,6 +184,7 @@ enum ocfs2_mount_options
151 OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */
152 OCFS2_MOUNT_DATA_WRITEBACK = 1 << 4, /* No data ordering */
153 OCFS2_MOUNT_LOCALFLOCKS = 1 << 5, /* No cluster aware user file locks */
154+ OCFS2_MOUNT_NOUSERXATTR = 1 << 6, /* No user xattr */
155 };
156
157 #define OCFS2_OSB_SOFT_RO 0x0001
158@@ -214,6 +215,7 @@ struct ocfs2_super
159 u32 bitmap_cpg;
160 u8 *uuid;
161 char *uuid_str;
162+ u32 uuid_hash;
163 u8 *vol_label;
164 u64 first_cluster_group_blkno;
165 u32 fs_generation;
166--- a/fs/ocfs2/ocfs2_fs.h
167+++ b/fs/ocfs2/ocfs2_fs.h
168@@ -570,7 +570,7 @@ struct ocfs2_super_block {
169 /*40*/ __le16 s_max_slots; /* Max number of simultaneous mounts
170 before tunefs required */
171 __le16 s_tunefs_flag;
172- __le32 s_reserved1;
173+ __le32 s_uuid_hash; /* hash value of uuid */
174 __le64 s_first_cluster_group; /* Block offset of 1st cluster
175 * group header */
176 /*50*/ __u8 s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */
177@@ -787,7 +787,11 @@ struct ocfs2_xattr_tree_root {
178 /*10*/ struct ocfs2_extent_list xt_list; /* Extent record list */
179 };
180
181-#define OCFS2_XATTR_INDEXED 0x1
182+#define OCFS2_XATTR_INDEXED 0x1
183+#define OCFS2_HASH_SHIFT 5
184+#define OCFS2_XATTR_ROUND 3
185+#define OCFS2_XATTR_SIZE(size) (((size) + OCFS2_XATTR_ROUND) & \
186+ ~(OCFS2_XATTR_ROUND))
187
188 /*
189 * On disk structure for xattr block.
190--- a/fs/ocfs2/suballoc.c
191+++ b/fs/ocfs2/suballoc.c
192@@ -493,9 +493,9 @@ bail:
193 return status;
194 }
195
196-int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
197- struct ocfs2_extent_list *root_el,
198- struct ocfs2_alloc_context **ac)
199+int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb,
200+ int blocks,
201+ struct ocfs2_alloc_context **ac)
202 {
203 int status;
204 u32 slot;
205@@ -507,7 +507,7 @@ int ocfs2_reserve_new_metadata(struct oc
206 goto bail;
207 }
208
209- (*ac)->ac_bits_wanted = ocfs2_extend_meta_needed(root_el);
210+ (*ac)->ac_bits_wanted = blocks;
211 (*ac)->ac_which = OCFS2_AC_USE_META;
212 slot = osb->slot_num;
213 (*ac)->ac_group_search = ocfs2_block_group_search;
214@@ -532,6 +532,15 @@ bail:
215 return status;
216 }
217
218+int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
219+ struct ocfs2_extent_list *root_el,
220+ struct ocfs2_alloc_context **ac)
221+{
222+ return ocfs2_reserve_new_metadata_blocks(osb,
223+ ocfs2_extend_meta_needed(root_el),
224+ ac);
225+}
226+
227 static int ocfs2_steal_inode_from_other_nodes(struct ocfs2_super *osb,
228 struct ocfs2_alloc_context *ac)
229 {
230--- a/fs/ocfs2/suballoc.h
231+++ b/fs/ocfs2/suballoc.h
232@@ -67,6 +67,9 @@ static inline int ocfs2_alloc_context_bi
233 int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
234 struct ocfs2_extent_list *root_el,
235 struct ocfs2_alloc_context **ac);
236+int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb,
237+ int blocks,
238+ struct ocfs2_alloc_context **ac);
239 int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
240 struct ocfs2_alloc_context **ac);
241 int ocfs2_reserve_clusters(struct ocfs2_super *osb,
242--- a/fs/ocfs2/super.c
243+++ b/fs/ocfs2/super.c
244@@ -64,6 +64,7 @@
245 #include "sysfile.h"
246 #include "uptodate.h"
247 #include "ver.h"
248+#include "xattr.h"
249
250 #include "buffer_head_io.h"
251
252@@ -154,6 +155,8 @@ enum {
253 Opt_localalloc,
254 Opt_localflocks,
255 Opt_stack,
256+ Opt_user_xattr,
257+ Opt_nouser_xattr,
258 Opt_err,
259 };
260
261@@ -173,6 +176,8 @@ static match_table_t tokens = {
262 {Opt_localalloc, "localalloc=%d"},
263 {Opt_localflocks, "localflocks"},
264 {Opt_stack, "cluster_stack=%s"},
265+ {Opt_user_xattr, "user_xattr"},
266+ {Opt_nouser_xattr, "nouser_xattr"},
267 {Opt_err, NULL}
268 };
269
270@@ -847,6 +852,12 @@ static int ocfs2_parse_options(struct su
271 case Opt_data_writeback:
272 mopt->mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK;
273 break;
274+ case Opt_user_xattr:
275+ mopt->mount_opt &= ~OCFS2_MOUNT_NOUSERXATTR;
276+ break;
277+ case Opt_nouser_xattr:
278+ mopt->mount_opt |= OCFS2_MOUNT_NOUSERXATTR;
279+ break;
280 case Opt_atime_quantum:
281 if (match_int(&args[0], &option)) {
282 status = 0;
283@@ -1132,6 +1143,7 @@ static void ocfs2_inode_init_once(void *
284 oi->ip_dir_start_lookup = 0;
285
286 init_rwsem(&oi->ip_alloc_sem);
287+ init_rwsem(&oi->ip_xattr_sem);
288 mutex_init(&oi->ip_io_mutex);
289
290 oi->ip_blkno = 0ULL;
291@@ -1375,6 +1387,7 @@ static int ocfs2_initialize_super(struct
292 sb->s_fs_info = osb;
293 sb->s_op = &ocfs2_sops;
294 sb->s_export_op = &ocfs2_export_ops;
295+ sb->s_xattr = ocfs2_xattr_handlers;
296 sb->s_time_gran = 1;
297 sb->s_flags |= MS_NOATIME;
298 /* this is needed to support O_LARGEFILE */
299@@ -1570,6 +1583,7 @@ static int ocfs2_initialize_super(struct
300 osb->first_cluster_group_blkno =
301 le64_to_cpu(di->id2.i_super.s_first_cluster_group);
302 osb->fs_generation = le32_to_cpu(di->i_fs_generation);
303+ osb->uuid_hash = le32_to_cpu(di->id2.i_super.s_uuid_hash);
304 mlog(0, "vol_label: %s\n", osb->vol_label);
305 mlog(0, "uuid: %s\n", osb->uuid_str);
306 mlog(0, "root_blkno=%llu, system_dir_blkno=%llu\n",
307--- a/fs/ocfs2/symlink.c
308+++ b/fs/ocfs2/symlink.c
309@@ -50,6 +50,7 @@
310 #include "inode.h"
311 #include "journal.h"
312 #include "symlink.h"
313+#include "xattr.h"
314
315 #include "buffer_head_io.h"
316
317@@ -168,10 +169,18 @@ const struct inode_operations ocfs2_syml
318 .follow_link = ocfs2_follow_link,
319 .getattr = ocfs2_getattr,
320 .setattr = ocfs2_setattr,
321+ .setxattr = generic_setxattr,
322+ .getxattr = generic_getxattr,
323+ .listxattr = ocfs2_listxattr,
324+ .removexattr = generic_removexattr,
325 };
326 const struct inode_operations ocfs2_fast_symlink_inode_operations = {
327 .readlink = ocfs2_readlink,
328 .follow_link = ocfs2_follow_link,
329 .getattr = ocfs2_getattr,
330 .setattr = ocfs2_setattr,
331+ .setxattr = generic_setxattr,
332+ .getxattr = generic_getxattr,
333+ .listxattr = ocfs2_listxattr,
334+ .removexattr = generic_removexattr,
335 };
336--- a/fs/ocfs2/xattr.c
337+++ b/fs/ocfs2/xattr.c
338@@ -5,6 +5,9 @@
339 *
340 * Copyright (C) 2008 Oracle. All rights reserved.
341 *
342+ * CREDITS:
343+ * Lots of code in this file is taken from ext3.
344+ *
345 * This program is free software; you can redistribute it and/or
346 * modify it under the terms of the GNU General Public
347 * License as published by the Free Software Foundation; either
348@@ -21,6 +24,19 @@
349 * Boston, MA 021110-1307, USA.
350 */
351
352+#include <linux/capability.h>
353+#include <linux/fs.h>
354+#include <linux/types.h>
355+#include <linux/slab.h>
356+#include <linux/highmem.h>
357+#include <linux/pagemap.h>
358+#include <linux/uio.h>
359+#include <linux/sched.h>
360+#include <linux/splice.h>
361+#include <linux/mount.h>
362+#include <linux/writeback.h>
363+#include <linux/falloc.h>
364+
365 #define MLOG_MASK_PREFIX ML_XATTR
366 #include <cluster/masklog.h>
367
368@@ -28,12 +44,135 @@
369 #include "alloc.h"
370 #include "dlmglue.h"
371 #include "file.h"
372+#include "symlink.h"
373+#include "sysfile.h"
374 #include "inode.h"
375 #include "journal.h"
376 #include "ocfs2_fs.h"
377 #include "suballoc.h"
378 #include "uptodate.h"
379 #include "buffer_head_io.h"
380+#include "xattr.h"
381+
382+
383+struct ocfs2_xattr_def_value_root {
384+ struct ocfs2_xattr_value_root xv;
385+ struct ocfs2_extent_rec er;
386+};
387+
388+#define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root))
389+#define OCFS2_XATTR_INLINE_SIZE 80
390+
391+static struct ocfs2_xattr_def_value_root def_xv = {
392+ .xv.xr_list.l_count = cpu_to_le16(1),
393+};
394+
395+struct xattr_handler *ocfs2_xattr_handlers[] = {
396+ &ocfs2_xattr_user_handler,
397+#ifdef CONFIG_OCFS2_FS_POSIX_ACL
398+ &ocfs2_xattr_acl_access_handler,
399+ &ocfs2_xattr_acl_default_handler,
400+#endif
401+ &ocfs2_xattr_trusted_handler,
402+#ifdef CONFIG_OCFS2_FS_SECURITY
403+ &ocfs2_xattr_security_handler,
404+#endif
405+ NULL
406+};
407+
408+static struct xattr_handler *ocfs2_xattr_handler_map[] = {
409+ [OCFS2_XATTR_INDEX_USER] = &ocfs2_xattr_user_handler,
410+#ifdef CONFIG_OCFS2_FS_POSIX_ACL
411+ [OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS]
412+ = &ocfs2_xattr_acl_access_handler,
413+ [OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT]
414+ = &ocfs2_xattr_acl_default_handler,
415+#endif
416+ [OCFS2_XATTR_INDEX_TRUSTED] = &ocfs2_xattr_trusted_handler,
417+#ifdef CONFIG_OCFS2_FS_SECURITY
418+ [OCFS2_XATTR_INDEX_SECURITY] = &ocfs2_xattr_security_handler,
419+#endif
420+};
421+
422+struct ocfs2_xattr_info {
423+ int name_index;
424+ const char *name;
425+ const void *value;
426+ size_t value_len;
427+};
428+
429+struct ocfs2_xattr_search {
430+ struct buffer_head *inode_bh;
431+ /*
432+ * xattr_bh point to the block buffer head which has extended attribute
433+ * when extended attribute in inode, xattr_bh is equal to inode_bh.
434+ */
435+ struct buffer_head *xattr_bh;
436+ struct ocfs2_xattr_header *header;
437+ void *base;
438+ void *end;
439+ struct ocfs2_xattr_entry *here;
440+ int not_found;
441+};
442+
443+static inline struct xattr_handler *ocfs2_xattr_handler(int name_index)
444+{
445+ struct xattr_handler *handler = NULL;
446+
447+ if (name_index > 0 && name_index < OCFS2_XATTR_MAX)
448+ handler = ocfs2_xattr_handler_map[name_index];
449+
450+ return handler;
451+}
452+
453+static inline u32 ocfs2_xattr_name_hash(struct inode *inode,
454+ char *prefix,
455+ int prefix_len,
456+ char *name,
457+ int name_len)
458+{
459+ /* Get hash value of uuid from super block */
460+ u32 hash = OCFS2_SB(inode->i_sb)->uuid_hash;
461+ int i;
462+
463+ /* hash extended attribute prefix */
464+ for (i = 0; i < prefix_len; i++) {
465+ hash = (hash << OCFS2_HASH_SHIFT) ^
466+ (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^
467+ *prefix++;
468+ }
469+ /* hash extended attribute name */
470+ for (i = 0; i < name_len; i++) {
471+ hash = (hash << OCFS2_HASH_SHIFT) ^
472+ (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^
473+ *name++;
474+ }
475+
476+ return hash;
477+}
478+
479+/*
480+ * ocfs2_xattr_hash_entry()
481+ *
482+ * Compute the hash of an extended attribute.
483+ */
484+static void ocfs2_xattr_hash_entry(struct inode *inode,
485+ struct ocfs2_xattr_header *header,
486+ struct ocfs2_xattr_entry *entry)
487+{
488+ u32 hash = 0;
489+ struct xattr_handler *handler =
490+ ocfs2_xattr_handler(ocfs2_xattr_get_type(entry));
491+ char *prefix = handler->prefix;
492+ char *name = (char *)header + le16_to_cpu(entry->xe_name_offset);
493+ int prefix_len = strlen(handler->prefix);
494+
495+ hash = ocfs2_xattr_name_hash(inode, prefix, prefix_len, name,
496+ entry->xe_name_len);
497+ entry->xe_name_hash = cpu_to_le32(hash);
498+
499+ return;
500+}
501
502 static int ocfs2_xattr_extend_allocation(struct inode *inode,
503 u32 clusters_to_add,
504@@ -303,3 +442,1500 @@ static int ocfs2_xattr_value_truncate(st
505
506 return ret;
507 }
508+
509+static int ocfs2_xattr_list_entries(struct inode *inode,
510+ struct ocfs2_xattr_header *header,
511+ char *buffer, size_t buffer_size)
512+{
513+ size_t rest = buffer_size;
514+ int i;
515+
516+ for (i = 0 ; i < le16_to_cpu(header->xh_count); i++) {
517+ struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
518+ struct xattr_handler *handler =
519+ ocfs2_xattr_handler(ocfs2_xattr_get_type(entry));
520+
521+ if (handler) {
522+ size_t size = handler->list(inode, buffer, rest,
523+ ((char *)header +
524+ le16_to_cpu(entry->xe_name_offset)),
525+ entry->xe_name_len);
526+ if (buffer) {
527+ if (size > rest)
528+ return -ERANGE;
529+ buffer += size;
530+ }
531+ rest -= size;
532+ }
533+ }
534+
535+ return buffer_size - rest;
536+}
537+
538+static int ocfs2_xattr_ibody_list(struct inode *inode,
539+ struct ocfs2_dinode *di,
540+ char *buffer,
541+ size_t buffer_size)
542+{
543+ struct ocfs2_xattr_header *header = NULL;
544+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
545+ int ret = 0;
546+
547+ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL))
548+ return ret;
549+
550+ header = (struct ocfs2_xattr_header *)
551+ ((void *)di + inode->i_sb->s_blocksize -
552+ le16_to_cpu(di->i_xattr_inline_size));
553+
554+ ret = ocfs2_xattr_list_entries(inode, header, buffer, buffer_size);
555+
556+ return ret;
557+}
558+
559+static int ocfs2_xattr_block_list(struct inode *inode,
560+ struct ocfs2_dinode *di,
561+ char *buffer,
562+ size_t buffer_size)
563+{
564+ struct buffer_head *blk_bh = NULL;
565+ struct ocfs2_xattr_header *header = NULL;
566+ int ret = 0;
567+
568+ if (!di->i_xattr_loc)
569+ return ret;
570+
571+ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
572+ le64_to_cpu(di->i_xattr_loc),
573+ &blk_bh, OCFS2_BH_CACHED, inode);
574+ if (ret < 0) {
575+ mlog_errno(ret);
576+ return ret;
577+ }
578+ /*Verify the signature of xattr block*/
579+ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
580+ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
581+ ret = -EFAULT;
582+ goto cleanup;
583+ }
584+
585+ header = &((struct ocfs2_xattr_block *)blk_bh->b_data)->
586+ xb_attrs.xb_header;
587+
588+ ret = ocfs2_xattr_list_entries(inode, header, buffer, buffer_size);
589+cleanup:
590+ brelse(blk_bh);
591+
592+ return ret;
593+}
594+
595+ssize_t ocfs2_listxattr(struct dentry *dentry,
596+ char *buffer,
597+ size_t size)
598+{
599+ int ret = 0, i_ret = 0, b_ret = 0;
600+ struct buffer_head *di_bh = NULL;
601+ struct ocfs2_dinode *di = NULL;
602+ struct ocfs2_inode_info *oi = OCFS2_I(dentry->d_inode);
603+
604+ if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
605+ return ret;
606+
607+ ret = ocfs2_inode_lock(dentry->d_inode, &di_bh, 0);
608+ if (ret < 0) {
609+ mlog_errno(ret);
610+ return ret;
611+ }
612+
613+ di = (struct ocfs2_dinode *)di_bh->b_data;
614+
615+ down_read(&oi->ip_xattr_sem);
616+ i_ret = ocfs2_xattr_ibody_list(dentry->d_inode, di, buffer, size);
617+ if (i_ret < 0)
618+ b_ret = 0;
619+ else {
620+ if (buffer) {
621+ buffer += i_ret;
622+ size -= i_ret;
623+ }
624+ b_ret = ocfs2_xattr_block_list(dentry->d_inode, di,
625+ buffer, size);
626+ if (b_ret < 0)
627+ i_ret = 0;
628+ }
629+ up_read(&oi->ip_xattr_sem);
630+ ocfs2_inode_unlock(dentry->d_inode, 0);
631+
632+ brelse(di_bh);
633+
634+ return i_ret + b_ret;
635+}
636+
637+static int ocfs2_xattr_find_entry(int name_index,
638+ const char *name,
639+ struct ocfs2_xattr_search *xs)
640+{
641+ struct ocfs2_xattr_entry *entry;
642+ size_t name_len;
643+ int i, cmp = 1;
644+
645+ if (name == NULL)
646+ return -EINVAL;
647+
648+ name_len = strlen(name);
649+ entry = xs->here;
650+ for (i = 0; i < le16_to_cpu(xs->header->xh_count); i++) {
651+ cmp = name_index - ocfs2_xattr_get_type(entry);
652+ if (!cmp)
653+ cmp = name_len - entry->xe_name_len;
654+ if (!cmp)
655+ cmp = memcmp(name, (xs->base +
656+ le16_to_cpu(entry->xe_name_offset)),
657+ name_len);
658+ if (cmp == 0)
659+ break;
660+ entry += 1;
661+ }
662+ xs->here = entry;
663+
664+ return cmp ? -ENODATA : 0;
665+}
666+
667+static int ocfs2_xattr_get_value_outside(struct inode *inode,
668+ struct ocfs2_xattr_search *xs,
669+ void *buffer,
670+ size_t len)
671+{
672+ u32 cpos, p_cluster, num_clusters, bpc, clusters;
673+ u64 blkno;
674+ int i, ret = 0;
675+ size_t cplen, blocksize;
676+ struct buffer_head *bh = NULL;
677+ struct ocfs2_xattr_value_root *xv;
678+ struct ocfs2_extent_list *el;
679+
680+ xv = (struct ocfs2_xattr_value_root *)
681+ (xs->base + le16_to_cpu(xs->here->xe_name_offset) +
682+ OCFS2_XATTR_SIZE(xs->here->xe_name_len));
683+ el = &xv->xr_list;
684+ clusters = le32_to_cpu(xv->xr_clusters);
685+ bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
686+ blocksize = inode->i_sb->s_blocksize;
687+
688+ cpos = 0;
689+ while (cpos < clusters) {
690+ ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
691+ &num_clusters, el);
692+ if (ret) {
693+ mlog_errno(ret);
694+ goto out;
695+ }
696+
697+ blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
698+ /* Copy ocfs2_xattr_value */
699+ for (i = 0; i < num_clusters * bpc; i++, blkno++) {
700+ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
701+ &bh, OCFS2_BH_CACHED, inode);
702+ if (ret) {
703+ mlog_errno(ret);
704+ goto out;
705+ }
706+
707+ cplen = len >= blocksize ? blocksize : len;
708+ memcpy(buffer, bh->b_data, cplen);
709+ len -= cplen;
710+ buffer += cplen;
711+
712+ brelse(bh);
713+ bh = NULL;
714+ if (len == 0)
715+ break;
716+ }
717+ cpos += num_clusters;
718+ }
719+out:
720+ return ret;
721+}
722+
723+static int ocfs2_xattr_ibody_get(struct inode *inode,
724+ int name_index,
725+ const char *name,
726+ void *buffer,
727+ size_t buffer_size,
728+ struct ocfs2_xattr_search *xs)
729+{
730+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
731+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
732+ size_t size;
733+ int ret = 0;
734+
735+ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL))
736+ return -ENODATA;
737+
738+ xs->end = (void *)di + inode->i_sb->s_blocksize;
739+ xs->header = (struct ocfs2_xattr_header *)
740+ (xs->end - le16_to_cpu(di->i_xattr_inline_size));
741+ xs->base = (void *)xs->header;
742+ xs->here = xs->header->xh_entries;
743+
744+ ret = ocfs2_xattr_find_entry(name_index, name, xs);
745+ if (ret)
746+ return ret;
747+ size = le64_to_cpu(xs->here->xe_value_size);
748+ if (buffer) {
749+ if (size > buffer_size)
750+ return -ERANGE;
751+ if (ocfs2_xattr_is_local(xs->here)) {
752+ memcpy(buffer, (void *)xs->base +
753+ le16_to_cpu(xs->here->xe_name_offset) +
754+ OCFS2_XATTR_SIZE(xs->here->xe_name_len), size);
755+ } else {
756+ ret = ocfs2_xattr_get_value_outside(inode, xs,
757+ buffer, size);
758+ if (ret < 0) {
759+ mlog_errno(ret);
760+ return ret;
761+ }
762+ }
763+ }
764+
765+ return size;
766+}
767+
768+static int ocfs2_xattr_block_get(struct inode *inode,
769+ int name_index,
770+ const char *name,
771+ void *buffer,
772+ size_t buffer_size,
773+ struct ocfs2_xattr_search *xs)
774+{
775+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
776+ struct buffer_head *blk_bh = NULL;
777+ struct ocfs2_xattr_block *xb;
778+ size_t size;
779+ int ret = -ENODATA;
780+
781+ if (!di->i_xattr_loc)
782+ return ret;
783+
784+ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
785+ le64_to_cpu(di->i_xattr_loc),
786+ &blk_bh, OCFS2_BH_CACHED, inode);
787+ if (ret < 0) {
788+ mlog_errno(ret);
789+ return ret;
790+ }
791+ /*Verify the signature of xattr block*/
792+ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
793+ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
794+ ret = -EFAULT;
795+ goto cleanup;
796+ }
797+
798+ xs->xattr_bh = blk_bh;
799+ xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
800+ xs->header = &xb->xb_attrs.xb_header;
801+ xs->base = (void *)xs->header;
802+ xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
803+ xs->here = xs->header->xh_entries;
804+
805+ ret = ocfs2_xattr_find_entry(name_index, name, xs);
806+ if (ret)
807+ goto cleanup;
808+ size = le64_to_cpu(xs->here->xe_value_size);
809+ if (buffer) {
810+ ret = -ERANGE;
811+ if (size > buffer_size)
812+ goto cleanup;
813+ if (ocfs2_xattr_is_local(xs->here)) {
814+ memcpy(buffer, (void *)xs->base +
815+ le16_to_cpu(xs->here->xe_name_offset) +
816+ OCFS2_XATTR_SIZE(xs->here->xe_name_len), size);
817+ } else {
818+ ret = ocfs2_xattr_get_value_outside(inode, xs,
819+ buffer, size);
820+ if (ret < 0) {
821+ mlog_errno(ret);
822+ goto cleanup;
823+ }
824+ }
825+ }
826+ ret = size;
827+cleanup:
828+ brelse(blk_bh);
829+
830+ return ret;
831+}
832+
833+/* ocfs2_xattr_get()
834+ *
835+ * Copy an extended attribute into the buffer provided.
836+ * Buffer is NULL to compute the size of buffer required.
837+ */
838+int ocfs2_xattr_get(struct inode *inode,
839+ int name_index,
840+ const char *name,
841+ void *buffer,
842+ size_t buffer_size)
843+{
844+ int ret;
845+ struct ocfs2_dinode *di = NULL;
846+ struct buffer_head *di_bh = NULL;
847+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
848+ struct ocfs2_xattr_search xis = {
849+ .not_found = -ENODATA,
850+ };
851+ struct ocfs2_xattr_search xbs = {
852+ .not_found = -ENODATA,
853+ };
854+
855+ if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
856+ ret = -ENODATA;
857+
858+ ret = ocfs2_inode_lock(inode, &di_bh, 0);
859+ if (ret < 0) {
860+ mlog_errno(ret);
861+ return ret;
862+ }
863+ xis.inode_bh = xbs.inode_bh = di_bh;
864+ di = (struct ocfs2_dinode *)di_bh->b_data;
865+
866+ down_read(&oi->ip_xattr_sem);
867+ ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer,
868+ buffer_size, &xis);
869+ if (ret == -ENODATA)
870+ ret = ocfs2_xattr_block_get(inode, name_index, name, buffer,
871+ buffer_size, &xbs);
872+ up_read(&oi->ip_xattr_sem);
873+ ocfs2_inode_unlock(inode, 0);
874+
875+ brelse(di_bh);
876+
877+ return ret;
878+}
879+
880+static int __ocfs2_xattr_set_value_outside(struct inode *inode,
881+ struct ocfs2_xattr_value_root *xv,
882+ const void *value,
883+ int value_len)
884+{
885+ int ret = 0, i, cp_len, credits;
886+ u16 blocksize = inode->i_sb->s_blocksize;
887+ u32 p_cluster, num_clusters;
888+ u32 cpos = 0, bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
889+ u32 clusters = ocfs2_clusters_for_bytes(inode->i_sb, value_len);
890+ u64 blkno;
891+ struct buffer_head *bh = NULL;
892+ handle_t *handle;
893+
894+ BUG_ON(clusters > le32_to_cpu(xv->xr_clusters));
895+
896+ credits = clusters * bpc;
897+ handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), credits);
898+ if (IS_ERR(handle)) {
899+ ret = PTR_ERR(handle);
900+ mlog_errno(ret);
901+ goto out;
902+ }
903+
904+ while (cpos < clusters) {
905+ ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
906+ &num_clusters, &xv->xr_list);
907+ if (ret) {
908+ mlog_errno(ret);
909+ goto out_commit;
910+ }
911+
912+ blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
913+
914+ for (i = 0; i < num_clusters * bpc; i++, blkno++) {
915+ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
916+ &bh, OCFS2_BH_CACHED, inode);
917+ if (ret) {
918+ mlog_errno(ret);
919+ goto out_commit;
920+ }
921+
922+ ret = ocfs2_journal_access(handle,
923+ inode,
924+ bh,
925+ OCFS2_JOURNAL_ACCESS_WRITE);
926+ if (ret < 0) {
927+ mlog_errno(ret);
928+ goto out_commit;
929+ }
930+
931+ cp_len = value_len > blocksize ? blocksize : value_len;
932+ memcpy(bh->b_data, value, cp_len);
933+ value_len -= cp_len;
934+ value += cp_len;
935+ if (cp_len < blocksize)
936+ memset(bh->b_data + cp_len, 0,
937+ blocksize - cp_len);
938+
939+ ret = ocfs2_journal_dirty(handle, bh);
940+ if (ret < 0) {
941+ mlog_errno(ret);
942+ goto out_commit;
943+ }
944+ brelse(bh);
945+ bh = NULL;
946+
947+ /*
948+ * XXX: do we need to empty all the following
949+ * blocks in this cluster?
950+ */
951+ if (!value_len)
952+ break;
953+ }
954+ cpos += num_clusters;
955+ }
956+out_commit:
957+ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
958+out:
959+ brelse(bh);
960+
961+ return ret;
962+}
963+
964+static int ocfs2_xattr_cleanup(struct inode *inode,
965+ struct ocfs2_xattr_info *xi,
966+ struct ocfs2_xattr_search *xs,
967+ size_t offs)
968+{
969+ handle_t *handle = NULL;
970+ int ret = 0;
971+ size_t name_len = strlen(xi->name);
972+ void *val = xs->base + offs;
973+ size_t size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
974+
975+ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
976+ OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
977+ if (IS_ERR(handle)) {
978+ ret = PTR_ERR(handle);
979+ mlog_errno(ret);
980+ goto out;
981+ }
982+ ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
983+ OCFS2_JOURNAL_ACCESS_WRITE);
984+ if (ret) {
985+ mlog_errno(ret);
986+ goto out_commit;
987+ }
988+ /* Decrease xattr count */
989+ le16_add_cpu(&xs->header->xh_count, -1);
990+ /* Remove the xattr entry and tree root which has already be set*/
991+ memset((void *)xs->here, 0, sizeof(struct ocfs2_xattr_entry));
992+ memset(val, 0, size);
993+
994+ ret = ocfs2_journal_dirty(handle, xs->xattr_bh);
995+ if (ret < 0)
996+ mlog_errno(ret);
997+out_commit:
998+ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
999+out:
1000+ return ret;
1001+}
1002+
1003+static int ocfs2_xattr_update_entry(struct inode *inode,
1004+ struct ocfs2_xattr_info *xi,
1005+ struct ocfs2_xattr_search *xs,
1006+ size_t offs)
1007+{
1008+ handle_t *handle = NULL;
1009+ int ret = 0;
1010+
1011+ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
1012+ OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
1013+ if (IS_ERR(handle)) {
1014+ ret = PTR_ERR(handle);
1015+ mlog_errno(ret);
1016+ goto out;
1017+ }
1018+ ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
1019+ OCFS2_JOURNAL_ACCESS_WRITE);
1020+ if (ret) {
1021+ mlog_errno(ret);
1022+ goto out_commit;
1023+ }
1024+
1025+ xs->here->xe_name_offset = cpu_to_le16(offs);
1026+ xs->here->xe_value_size = cpu_to_le64(xi->value_len);
1027+ if (xi->value_len <= OCFS2_XATTR_INLINE_SIZE)
1028+ ocfs2_xattr_set_local(xs->here, 1);
1029+ else
1030+ ocfs2_xattr_set_local(xs->here, 0);
1031+ ocfs2_xattr_hash_entry(inode, xs->header, xs->here);
1032+
1033+ ret = ocfs2_journal_dirty(handle, xs->xattr_bh);
1034+ if (ret < 0)
1035+ mlog_errno(ret);
1036+out_commit:
1037+ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
1038+out:
1039+ return ret;
1040+}
1041+
1042+/*
1043+ * ocfs2_xattr_set_value_outside()
1044+ *
1045+ * Set large size value in B tree.
1046+ */
1047+static int ocfs2_xattr_set_value_outside(struct inode *inode,
1048+ struct ocfs2_xattr_info *xi,
1049+ struct ocfs2_xattr_search *xs,
1050+ size_t offs)
1051+{
1052+ size_t name_len = strlen(xi->name);
1053+ void *val = xs->base + offs;
1054+ struct ocfs2_xattr_value_root *xv = NULL;
1055+ size_t size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
1056+ int ret = 0;
1057+
1058+ memset(val, 0, size);
1059+ memcpy(val, xi->name, name_len);
1060+ xv = (struct ocfs2_xattr_value_root *)
1061+ (val + OCFS2_XATTR_SIZE(name_len));
1062+ xv->xr_clusters = 0;
1063+ xv->xr_last_eb_blk = 0;
1064+ xv->xr_list.l_tree_depth = 0;
1065+ xv->xr_list.l_count = cpu_to_le16(1);
1066+ xv->xr_list.l_next_free_rec = 0;
1067+
1068+ ret = ocfs2_xattr_value_truncate(inode, xs->xattr_bh, xv,
1069+ xi->value_len);
1070+ if (ret < 0) {
1071+ mlog_errno(ret);
1072+ return ret;
1073+ }
1074+ ret = __ocfs2_xattr_set_value_outside(inode, xv, xi->value,
1075+ xi->value_len);
1076+ if (ret < 0) {
1077+ mlog_errno(ret);
1078+ return ret;
1079+ }
1080+ ret = ocfs2_xattr_update_entry(inode, xi, xs, offs);
1081+ if (ret < 0)
1082+ mlog_errno(ret);
1083+
1084+ return ret;
1085+}
1086+
1087+/*
1088+ * ocfs2_xattr_set_entry_local()
1089+ *
1090+ * Set, replace or remove extended attribute in local.
1091+ */
1092+static void ocfs2_xattr_set_entry_local(struct inode *inode,
1093+ struct ocfs2_xattr_info *xi,
1094+ struct ocfs2_xattr_search *xs,
1095+ struct ocfs2_xattr_entry *last,
1096+ size_t min_offs)
1097+{
1098+ size_t name_len = strlen(xi->name);
1099+ int i;
1100+
1101+ if (xi->value && xs->not_found) {
1102+ /* Insert the new xattr entry. */
1103+ le16_add_cpu(&xs->header->xh_count, 1);
1104+ ocfs2_xattr_set_type(last, xi->name_index);
1105+ ocfs2_xattr_set_local(last, 1);
1106+ last->xe_name_len = name_len;
1107+ } else {
1108+ void *first_val;
1109+ void *val;
1110+ size_t offs, size;
1111+
1112+ first_val = xs->base + min_offs;
1113+ offs = le16_to_cpu(xs->here->xe_name_offset);
1114+ val = xs->base + offs;
1115+
1116+ if (le64_to_cpu(xs->here->xe_value_size) >
1117+ OCFS2_XATTR_INLINE_SIZE)
1118+ size = OCFS2_XATTR_SIZE(name_len) +
1119+ OCFS2_XATTR_ROOT_SIZE;
1120+ else
1121+ size = OCFS2_XATTR_SIZE(name_len) +
1122+ OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
1123+
1124+ if (xi->value && size == OCFS2_XATTR_SIZE(name_len) +
1125+ OCFS2_XATTR_SIZE(xi->value_len)) {
1126+ /* The old and the new value have the
1127+ same size. Just replace the value. */
1128+ ocfs2_xattr_set_local(xs->here, 1);
1129+ xs->here->xe_value_size = cpu_to_le64(xi->value_len);
1130+ /* Clear value bytes. */
1131+ memset(val + OCFS2_XATTR_SIZE(name_len),
1132+ 0,
1133+ OCFS2_XATTR_SIZE(xi->value_len));
1134+ memcpy(val + OCFS2_XATTR_SIZE(name_len),
1135+ xi->value,
1136+ xi->value_len);
1137+ return;
1138+ }
1139+ /* Remove the old name+value. */
1140+ memmove(first_val + size, first_val, val - first_val);
1141+ memset(first_val, 0, size);
1142+ xs->here->xe_name_hash = 0;
1143+ xs->here->xe_name_offset = 0;
1144+ ocfs2_xattr_set_local(xs->here, 1);
1145+ xs->here->xe_value_size = 0;
1146+
1147+ min_offs += size;
1148+
1149+ /* Adjust all value offsets. */
1150+ last = xs->header->xh_entries;
1151+ for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) {
1152+ size_t o = le16_to_cpu(last->xe_name_offset);
1153+
1154+ if (o < offs)
1155+ last->xe_name_offset = cpu_to_le16(o + size);
1156+ last += 1;
1157+ }
1158+
1159+ if (!xi->value) {
1160+ /* Remove the old entry. */
1161+ last -= 1;
1162+ memmove(xs->here, xs->here + 1,
1163+ (void *)last - (void *)xs->here);
1164+ memset(last, 0, sizeof(struct ocfs2_xattr_entry));
1165+ le16_add_cpu(&xs->header->xh_count, -1);
1166+ }
1167+ }
1168+ if (xi->value) {
1169+ /* Insert the new name+value. */
1170+ size_t size = OCFS2_XATTR_SIZE(name_len) +
1171+ OCFS2_XATTR_SIZE(xi->value_len);
1172+ void *val = xs->base + min_offs - size;
1173+
1174+ xs->here->xe_name_offset = cpu_to_le16(min_offs - size);
1175+ memset(val, 0, size);
1176+ memcpy(val, xi->name, name_len);
1177+ memcpy(val + OCFS2_XATTR_SIZE(name_len),
1178+ xi->value,
1179+ xi->value_len);
1180+ xs->here->xe_value_size = cpu_to_le64(xi->value_len);
1181+ ocfs2_xattr_set_local(xs->here, 1);
1182+ ocfs2_xattr_hash_entry(inode, xs->header, xs->here);
1183+ }
1184+
1185+ return;
1186+}
1187+
1188+/*
1189+ * ocfs2_xattr_set_entry()
1190+ *
1191+ * Set extended attribute entry into inode or block.
1192+ *
1193+ * If extended attribute value size > OCFS2_XATTR_INLINE_SIZE,
1194+ * We first insert tree root(ocfs2_xattr_value_root) with set_entry_local(),
1195+ * then set value in B tree with set_value_outside().
1196+ */
1197+static int ocfs2_xattr_set_entry(struct inode *inode,
1198+ struct ocfs2_xattr_info *xi,
1199+ struct ocfs2_xattr_search *xs,
1200+ int flag)
1201+{
1202+ struct ocfs2_xattr_entry *last;
1203+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
1204+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
1205+ size_t min_offs = xs->end - xs->base, name_len = strlen(xi->name);
1206+ size_t size_l = 0;
1207+ handle_t *handle = NULL;
1208+ int free, i, ret;
1209+ struct ocfs2_xattr_info xi_l = {
1210+ .name_index = xi->name_index,
1211+ .name = xi->name,
1212+ .value = xi->value,
1213+ .value_len = xi->value_len,
1214+ };
1215+
1216+ /* Compute min_offs, last and free space. */
1217+ last = xs->header->xh_entries;
1218+
1219+ for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) {
1220+ size_t offs = le16_to_cpu(last->xe_name_offset);
1221+ if (offs < min_offs)
1222+ min_offs = offs;
1223+ last += 1;
1224+ }
1225+
1226+ free = min_offs - ((void *)last - xs->base) - sizeof(__u32);
1227+ if (free < 0)
1228+ return -EFAULT;
1229+
1230+ if (!xs->not_found) {
1231+ size_t size = 0;
1232+ if (ocfs2_xattr_is_local(xs->here))
1233+ size = OCFS2_XATTR_SIZE(name_len) +
1234+ OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
1235+ else
1236+ size = OCFS2_XATTR_SIZE(name_len) +
1237+ OCFS2_XATTR_ROOT_SIZE;
1238+ free += (size + sizeof(struct ocfs2_xattr_entry));
1239+ }
1240+ /* Check free space in inode or block */
1241+ if (xi->value && xi->value_len > OCFS2_XATTR_INLINE_SIZE) {
1242+ if (free < sizeof(struct ocfs2_xattr_entry) +
1243+ OCFS2_XATTR_SIZE(name_len) +
1244+ OCFS2_XATTR_ROOT_SIZE) {
1245+ ret = -ENOSPC;
1246+ goto out;
1247+ }
1248+ size_l = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
1249+ xi_l.value = (void *)&def_xv;
1250+ xi_l.value_len = OCFS2_XATTR_ROOT_SIZE;
1251+ } else if (xi->value) {
1252+ if (free < sizeof(struct ocfs2_xattr_entry) +
1253+ OCFS2_XATTR_SIZE(name_len) +
1254+ OCFS2_XATTR_SIZE(xi->value_len)) {
1255+ ret = -ENOSPC;
1256+ goto out;
1257+ }
1258+ }
1259+
1260+ if (!xs->not_found) {
1261+ /* For existing extended attribute */
1262+ size_t size = OCFS2_XATTR_SIZE(name_len) +
1263+ OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
1264+ size_t offs = le16_to_cpu(xs->here->xe_name_offset);
1265+ void *val = xs->base + offs;
1266+
1267+ if (ocfs2_xattr_is_local(xs->here) && size == size_l) {
1268+ /* Replace existing local xattr with tree root */
1269+ ret = ocfs2_xattr_set_value_outside(inode, xi, xs,
1270+ offs);
1271+ if (ret < 0)
1272+ mlog_errno(ret);
1273+ goto out;
1274+ } else if (!ocfs2_xattr_is_local(xs->here)) {
1275+ /* For existing xattr which has value outside */
1276+ struct ocfs2_xattr_value_root *xv = NULL;
1277+ xv = (struct ocfs2_xattr_value_root *)(val +
1278+ OCFS2_XATTR_SIZE(name_len));
1279+
1280+ if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) {
1281+ /*
1282+ * If new value need set outside also,
1283+ * first truncate old value to new value,
1284+ * then set new value with set_value_outside().
1285+ */
1286+ ret = ocfs2_xattr_value_truncate(inode,
1287+ xs->xattr_bh,
1288+ xv,
1289+ xi->value_len);
1290+ if (ret < 0) {
1291+ mlog_errno(ret);
1292+ goto out;
1293+ }
1294+
1295+ ret = __ocfs2_xattr_set_value_outside(inode,
1296+ xv,
1297+ xi->value,
1298+ xi->value_len);
1299+ if (ret < 0) {
1300+ mlog_errno(ret);
1301+ goto out;
1302+ }
1303+
1304+ ret = ocfs2_xattr_update_entry(inode,
1305+ xi,
1306+ xs,
1307+ offs);
1308+ if (ret < 0)
1309+ mlog_errno(ret);
1310+ goto out;
1311+ } else {
1312+ /*
1313+ * If new value need set in local,
1314+ * just trucate old value to zero.
1315+ */
1316+ ret = ocfs2_xattr_value_truncate(inode,
1317+ xs->xattr_bh,
1318+ xv,
1319+ 0);
1320+ if (ret < 0)
1321+ mlog_errno(ret);
1322+ }
1323+ }
1324+ }
1325+
1326+ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
1327+ OCFS2_INODE_UPDATE_CREDITS);
1328+ if (IS_ERR(handle)) {
1329+ ret = PTR_ERR(handle);
1330+ mlog_errno(ret);
1331+ goto out;
1332+ }
1333+
1334+ ret = ocfs2_journal_access(handle, inode, xs->inode_bh,
1335+ OCFS2_JOURNAL_ACCESS_WRITE);
1336+ if (ret) {
1337+ mlog_errno(ret);
1338+ goto out_commit;
1339+ }
1340+
1341+ if (!(flag & OCFS2_INLINE_XATTR_FL)) {
1342+ /*set extended attribue in external blcok*/
1343+ ret = ocfs2_extend_trans(handle,
1344+ OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
1345+ if (ret) {
1346+ mlog_errno(ret);
1347+ goto out_commit;
1348+ }
1349+ ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
1350+ OCFS2_JOURNAL_ACCESS_WRITE);
1351+ if (ret) {
1352+ mlog_errno(ret);
1353+ goto out_commit;
1354+ }
1355+ }
1356+
1357+ /*
1358+ * Set value in local, include set tree root in local.
1359+ * This is the first step for value size >INLINE_SIZE.
1360+ */
1361+ ocfs2_xattr_set_entry_local(inode, &xi_l, xs, last, min_offs);
1362+
1363+ if (!(flag & OCFS2_INLINE_XATTR_FL)) {
1364+ ret = ocfs2_journal_dirty(handle, xs->xattr_bh);
1365+ if (ret < 0) {
1366+ mlog_errno(ret);
1367+ goto out_commit;
1368+ }
1369+ }
1370+
1371+ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) &&
1372+ (flag & OCFS2_INLINE_XATTR_FL)) {
1373+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
1374+ unsigned int xattrsize = osb->s_xattr_inline_size;
1375+
1376+ /*
1377+ * Adjust extent record count or inline data size
1378+ * to reserve space for extended attribute.
1379+ */
1380+ if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
1381+ struct ocfs2_inline_data *idata = &di->id2.i_data;
1382+ le16_add_cpu(&idata->id_count, -xattrsize);
1383+ } else if (!(ocfs2_inode_is_fast_symlink(inode))) {
1384+ struct ocfs2_extent_list *el = &di->id2.i_list;
1385+ le16_add_cpu(&el->l_count, -(xattrsize /
1386+ sizeof(struct ocfs2_extent_rec)));
1387+ }
1388+ di->i_xattr_inline_size = cpu_to_le16(xattrsize);
1389+ }
1390+ /* Update xattr flag */
1391+ spin_lock(&oi->ip_lock);
1392+ oi->ip_dyn_features |= flag;
1393+ di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
1394+ spin_unlock(&oi->ip_lock);
1395+ /* Update inode ctime */
1396+ inode->i_ctime = CURRENT_TIME;
1397+ di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
1398+ di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
1399+
1400+ ret = ocfs2_journal_dirty(handle, xs->inode_bh);
1401+ if (ret < 0)
1402+ mlog_errno(ret);
1403+
1404+out_commit:
1405+ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
1406+
1407+ if (!ret && xi->value_len > OCFS2_XATTR_INLINE_SIZE) {
1408+ /*
1409+ * Set value outside in B tree.
1410+ * This is the second step for value size > INLINE_SIZE.
1411+ */
1412+ size_t offs = le16_to_cpu(xs->here->xe_name_offset);
1413+ ret = ocfs2_xattr_set_value_outside(inode, xi, xs, offs);
1414+ if (ret < 0) {
1415+ int ret2;
1416+
1417+ mlog_errno(ret);
1418+ /*
1419+ * If set value outside failed, we have to clean
1420+ * the junk tree root we have already set in local.
1421+ */
1422+ ret2 = ocfs2_xattr_cleanup(inode, xi, xs, offs);
1423+ if (ret2 < 0)
1424+ mlog_errno(ret2);
1425+ }
1426+ }
1427+out:
1428+ return ret;
1429+
1430+}
1431+
1432+static int ocfs2_xattr_free_block(handle_t *handle,
1433+ struct ocfs2_super *osb,
1434+ struct ocfs2_xattr_block *xb)
1435+{
1436+ struct inode *xb_alloc_inode;
1437+ struct buffer_head *xb_alloc_bh = NULL;
1438+ u64 blk = le64_to_cpu(xb->xb_blkno);
1439+ u16 bit = le16_to_cpu(xb->xb_suballoc_bit);
1440+ u64 bg_blkno = ocfs2_which_suballoc_group(blk, bit);
1441+ int ret = 0;
1442+
1443+ xb_alloc_inode = ocfs2_get_system_file_inode(osb,
1444+ EXTENT_ALLOC_SYSTEM_INODE,
1445+ le16_to_cpu(xb->xb_suballoc_slot));
1446+ if (!xb_alloc_inode) {
1447+ ret = -ENOMEM;
1448+ mlog_errno(ret);
1449+ goto out;
1450+ }
1451+ mutex_lock(&xb_alloc_inode->i_mutex);
1452+
1453+ ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1);
1454+ if (ret < 0) {
1455+ mlog_errno(ret);
1456+ goto out_mutex;
1457+ }
1458+ ret = ocfs2_extend_trans(handle, OCFS2_SUBALLOC_FREE);
1459+ if (ret < 0) {
1460+ mlog_errno(ret);
1461+ goto out_unlock;
1462+ }
1463+ ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh,
1464+ bit, bg_blkno, 1);
1465+ if (ret < 0)
1466+ mlog_errno(ret);
1467+out_unlock:
1468+ ocfs2_inode_unlock(xb_alloc_inode, 1);
1469+ brelse(xb_alloc_bh);
1470+out_mutex:
1471+ mutex_unlock(&xb_alloc_inode->i_mutex);
1472+ iput(xb_alloc_inode);
1473+out:
1474+ return ret;
1475+}
1476+
1477+static int ocfs2_remove_value_outside(struct inode*inode,
1478+ struct buffer_head *bh,
1479+ struct ocfs2_xattr_header *header)
1480+{
1481+ int ret = 0, i;
1482+
1483+ for (i = 0; i < le16_to_cpu(header->xh_count); i++) {
1484+ struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
1485+
1486+ if (!ocfs2_xattr_is_local(entry)) {
1487+ struct ocfs2_xattr_value_root *xv;
1488+ void *val;
1489+
1490+ val = (void *)header +
1491+ le16_to_cpu(entry->xe_name_offset);
1492+ xv = (struct ocfs2_xattr_value_root *)
1493+ (val + OCFS2_XATTR_SIZE(entry->xe_name_len));
1494+ ret = ocfs2_xattr_value_truncate(inode, bh, xv, 0);
1495+ if (ret < 0) {
1496+ mlog_errno(ret);
1497+ return ret;
1498+ }
1499+ }
1500+ }
1501+
1502+ return ret;
1503+}
1504+
1505+static int ocfs2_xattr_ibody_remove(struct inode *inode,
1506+ struct buffer_head *di_bh)
1507+{
1508+
1509+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
1510+ struct ocfs2_xattr_header *header;
1511+ int ret;
1512+
1513+ header = (struct ocfs2_xattr_header *)
1514+ ((void *)di + inode->i_sb->s_blocksize -
1515+ le16_to_cpu(di->i_xattr_inline_size));
1516+
1517+ ret = ocfs2_remove_value_outside(inode, di_bh, header);
1518+
1519+ return ret;
1520+}
1521+
1522+static int ocfs2_xattr_block_remove(struct inode *inode,
1523+ struct buffer_head *blk_bh)
1524+{
1525+ struct ocfs2_xattr_block *xb;
1526+ struct ocfs2_xattr_header *header;
1527+ int ret = 0;
1528+
1529+ xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
1530+ header = &(xb->xb_attrs.xb_header);
1531+
1532+ ret = ocfs2_remove_value_outside(inode, blk_bh, header);
1533+
1534+ return ret;
1535+}
1536+
1537+/*
1538+ * ocfs2_xattr_remove()
1539+ *
1540+ * Free extended attribute resources associated with this inode.
1541+ */
1542+int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh)
1543+{
1544+ struct ocfs2_xattr_block *xb;
1545+ struct buffer_head *blk_bh = NULL;
1546+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
1547+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
1548+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
1549+ handle_t *handle;
1550+ int ret;
1551+
1552+ if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
1553+ return 0;
1554+
1555+ if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
1556+ ret = ocfs2_xattr_ibody_remove(inode, di_bh);
1557+ if (ret < 0) {
1558+ mlog_errno(ret);
1559+ goto out;
1560+ }
1561+ }
1562+ if (di->i_xattr_loc) {
1563+ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
1564+ le64_to_cpu(di->i_xattr_loc),
1565+ &blk_bh, OCFS2_BH_CACHED, inode);
1566+ if (ret < 0) {
1567+ mlog_errno(ret);
1568+ return ret;
1569+ }
1570+ /*Verify the signature of xattr block*/
1571+ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
1572+ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
1573+ ret = -EFAULT;
1574+ goto out;
1575+ }
1576+
1577+ ret = ocfs2_xattr_block_remove(inode, blk_bh);
1578+ if (ret < 0) {
1579+ mlog_errno(ret);
1580+ goto out;
1581+ }
1582+ }
1583+
1584+ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
1585+ OCFS2_INODE_UPDATE_CREDITS);
1586+ if (IS_ERR(handle)) {
1587+ ret = PTR_ERR(handle);
1588+ mlog_errno(ret);
1589+ goto out;
1590+ }
1591+ ret = ocfs2_journal_access(handle, inode, di_bh,
1592+ OCFS2_JOURNAL_ACCESS_WRITE);
1593+ if (ret) {
1594+ mlog_errno(ret);
1595+ goto out_commit;
1596+ }
1597+
1598+ if (di->i_xattr_loc) {
1599+ xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
1600+ ocfs2_xattr_free_block(handle, osb, xb);
1601+ di->i_xattr_loc = cpu_to_le64(0);
1602+ }
1603+
1604+ spin_lock(&oi->ip_lock);
1605+ oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL);
1606+ di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
1607+ spin_unlock(&oi->ip_lock);
1608+
1609+ ret = ocfs2_journal_dirty(handle, di_bh);
1610+ if (ret < 0)
1611+ mlog_errno(ret);
1612+out_commit:
1613+ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
1614+out:
1615+ brelse(blk_bh);
1616+
1617+ return ret;
1618+}
1619+
1620+static int ocfs2_xattr_has_space_inline(struct inode *inode,
1621+ struct ocfs2_dinode *di)
1622+{
1623+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
1624+ unsigned int xattrsize = OCFS2_SB(inode->i_sb)->s_xattr_inline_size;
1625+ int free;
1626+
1627+ if (xattrsize < OCFS2_MIN_XATTR_INLINE_SIZE)
1628+ return 0;
1629+
1630+ if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
1631+ struct ocfs2_inline_data *idata = &di->id2.i_data;
1632+ free = le16_to_cpu(idata->id_count) - le64_to_cpu(di->i_size);
1633+ } else if (ocfs2_inode_is_fast_symlink(inode)) {
1634+ free = ocfs2_fast_symlink_chars(inode->i_sb) -
1635+ le64_to_cpu(di->i_size);
1636+ } else {
1637+ struct ocfs2_extent_list *el = &di->id2.i_list;
1638+ free = (le16_to_cpu(el->l_count) -
1639+ le16_to_cpu(el->l_next_free_rec)) *
1640+ sizeof(struct ocfs2_extent_rec);
1641+ }
1642+ if (free >= xattrsize)
1643+ return 1;
1644+
1645+ return 0;
1646+}
1647+
1648+/*
1649+ * ocfs2_xattr_ibody_find()
1650+ *
1651+ * Find extended attribute in inode block and
1652+ * fill search info into struct ocfs2_xattr_search.
1653+ */
1654+static int ocfs2_xattr_ibody_find(struct inode *inode,
1655+ int name_index,
1656+ const char *name,
1657+ struct ocfs2_xattr_search *xs)
1658+{
1659+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
1660+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
1661+ int ret;
1662+ int has_space = 0;
1663+
1664+ if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
1665+ return 0;
1666+
1667+ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
1668+ down_read(&oi->ip_alloc_sem);
1669+ has_space = ocfs2_xattr_has_space_inline(inode, di);
1670+ up_read(&oi->ip_alloc_sem);
1671+ if (!has_space)
1672+ return 0;
1673+ }
1674+
1675+ xs->xattr_bh = xs->inode_bh;
1676+ xs->end = (void *)di + inode->i_sb->s_blocksize;
1677+ if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)
1678+ xs->header = (struct ocfs2_xattr_header *)
1679+ (xs->end - le16_to_cpu(di->i_xattr_inline_size));
1680+ else
1681+ xs->header = (struct ocfs2_xattr_header *)
1682+ (xs->end - OCFS2_SB(inode->i_sb)->s_xattr_inline_size);
1683+ xs->base = (void *)xs->header;
1684+ xs->here = xs->header->xh_entries;
1685+
1686+ /* Find the named attribute. */
1687+ if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
1688+ ret = ocfs2_xattr_find_entry(name_index, name, xs);
1689+ if (ret && ret != -ENODATA)
1690+ return ret;
1691+ xs->not_found = ret;
1692+ }
1693+
1694+ return 0;
1695+}
1696+
1697+/*
1698+ * ocfs2_xattr_ibody_set()
1699+ *
1700+ * Set, replace or remove an extended attribute into inode block.
1701+ *
1702+ */
1703+static int ocfs2_xattr_ibody_set(struct inode *inode,
1704+ struct ocfs2_xattr_info *xi,
1705+ struct ocfs2_xattr_search *xs)
1706+{
1707+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
1708+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
1709+ int ret;
1710+
1711+ if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
1712+ return -ENOSPC;
1713+
1714+ down_write(&oi->ip_alloc_sem);
1715+ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
1716+ if (!ocfs2_xattr_has_space_inline(inode, di)) {
1717+ ret = -ENOSPC;
1718+ goto out;
1719+ }
1720+ }
1721+
1722+ ret = ocfs2_xattr_set_entry(inode, xi, xs,
1723+ (OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL));
1724+out:
1725+ up_write(&oi->ip_alloc_sem);
1726+
1727+ return ret;
1728+}
1729+
1730+/*
1731+ * ocfs2_xattr_block_find()
1732+ *
1733+ * Find extended attribute in external block and
1734+ * fill search info into struct ocfs2_xattr_search.
1735+ */
1736+static int ocfs2_xattr_block_find(struct inode *inode,
1737+ int name_index,
1738+ const char *name,
1739+ struct ocfs2_xattr_search *xs)
1740+{
1741+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
1742+ struct buffer_head *blk_bh = NULL;
1743+ int ret = 0;
1744+
1745+ if (!di->i_xattr_loc)
1746+ return ret;
1747+
1748+ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
1749+ le64_to_cpu(di->i_xattr_loc),
1750+ &blk_bh, OCFS2_BH_CACHED, inode);
1751+ if (ret < 0) {
1752+ mlog_errno(ret);
1753+ return ret;
1754+ }
1755+ /*Verify the signature of xattr block*/
1756+ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
1757+ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
1758+ ret = -EFAULT;
1759+ goto cleanup;
1760+ }
1761+
1762+ xs->xattr_bh = blk_bh;
1763+ xs->header = &((struct ocfs2_xattr_block *)blk_bh->b_data)->
1764+ xb_attrs.xb_header;
1765+ xs->base = (void *)xs->header;
1766+ xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
1767+ xs->here = xs->header->xh_entries;
1768+
1769+ ret = ocfs2_xattr_find_entry(name_index, name, xs);
1770+ if (ret && ret != -ENODATA) {
1771+ xs->xattr_bh = NULL;
1772+ goto cleanup;
1773+ }
1774+ xs->not_found = ret;
1775+ return 0;
1776+
1777+cleanup:
1778+ brelse(blk_bh);
1779+
1780+ return ret;
1781+}
1782+
1783+/*
1784+ * ocfs2_xattr_block_set()
1785+ *
1786+ * Set, replace or remove an extended attribute into external block.
1787+ *
1788+ */
1789+static int ocfs2_xattr_block_set(struct inode *inode,
1790+ struct ocfs2_xattr_info *xi,
1791+ struct ocfs2_xattr_search *xs)
1792+{
1793+ struct buffer_head *new_bh = NULL;
1794+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
1795+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
1796+ struct ocfs2_alloc_context *meta_ac = NULL;
1797+ handle_t *handle = NULL;
1798+ struct ocfs2_xattr_block *xblk = NULL;
1799+ u16 suballoc_bit_start;
1800+ u32 num_got;
1801+ u64 first_blkno;
1802+ int ret;
1803+
1804+ if (!xs->xattr_bh) {
1805+ /*
1806+ * Alloc one external block for extended attribute
1807+ * outside of inode.
1808+ */
1809+ ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac);
1810+ if (ret < 0) {
1811+ mlog_errno(ret);
1812+ goto out;
1813+ }
1814+ handle = ocfs2_start_trans(osb,
1815+ OCFS2_XATTR_BLOCK_CREATE_CREDITS);
1816+ if (IS_ERR(handle)) {
1817+ ret = PTR_ERR(handle);
1818+ mlog_errno(ret);
1819+ goto out;
1820+ }
1821+ ret = ocfs2_journal_access(handle, inode, xs->inode_bh,
1822+ OCFS2_JOURNAL_ACCESS_CREATE);
1823+ if (ret < 0) {
1824+ mlog_errno(ret);
1825+ goto out_commit;
1826+ }
1827+
1828+ ret = ocfs2_claim_metadata(osb, handle, meta_ac, 1,
1829+ &suballoc_bit_start, &num_got,
1830+ &first_blkno);
1831+ if (ret < 0) {
1832+ mlog_errno(ret);
1833+ goto out_commit;
1834+ }
1835+
1836+ new_bh = sb_getblk(inode->i_sb, first_blkno);
1837+ ocfs2_set_new_buffer_uptodate(inode, new_bh);
1838+
1839+ ret = ocfs2_journal_access(handle, inode, new_bh,
1840+ OCFS2_JOURNAL_ACCESS_CREATE);
1841+ if (ret < 0) {
1842+ mlog_errno(ret);
1843+ goto out_commit;
1844+ }
1845+
1846+ /* Initialize ocfs2_xattr_block */
1847+ xs->xattr_bh = new_bh;
1848+ xblk = (struct ocfs2_xattr_block *)new_bh->b_data;
1849+ memset(xblk, 0, inode->i_sb->s_blocksize);
1850+ strcpy((void *)xblk, OCFS2_XATTR_BLOCK_SIGNATURE);
1851+ xblk->xb_suballoc_slot = cpu_to_le16(osb->slot_num);
1852+ xblk->xb_suballoc_bit = cpu_to_le16(suballoc_bit_start);
1853+ xblk->xb_fs_generation = cpu_to_le32(osb->fs_generation);
1854+ xblk->xb_blkno = cpu_to_le64(first_blkno);
1855+
1856+ xs->header = &xblk->xb_attrs.xb_header;
1857+ xs->base = (void *)xs->header;
1858+ xs->end = (void *)xblk + inode->i_sb->s_blocksize;
1859+ xs->here = xs->header->xh_entries;
1860+
1861+
1862+ ret = ocfs2_journal_dirty(handle, new_bh);
1863+ if (ret < 0) {
1864+ mlog_errno(ret);
1865+ goto out_commit;
1866+ }
1867+ di->i_xattr_loc = cpu_to_le64(first_blkno);
1868+ ret = ocfs2_journal_dirty(handle, xs->inode_bh);
1869+ if (ret < 0)
1870+ mlog_errno(ret);
1871+out_commit:
1872+ ocfs2_commit_trans(osb, handle);
1873+out:
1874+ if (meta_ac)
1875+ ocfs2_free_alloc_context(meta_ac);
1876+ if (ret < 0)
1877+ return ret;
1878+ }
1879+
1880+ /* Set extended attribute into external block */
1881+ ret = ocfs2_xattr_set_entry(inode, xi, xs, OCFS2_HAS_XATTR_FL);
1882+
1883+ return ret;
1884+}
1885+
1886+/*
1887+ * ocfs2_xattr_set()
1888+ *
1889+ * Set, replace or remove an extended attribute for this inode.
1890+ * value is NULL to remove an existing extended attribute, else either
1891+ * create or replace an extended attribute.
1892+ */
1893+int ocfs2_xattr_set(struct inode *inode,
1894+ int name_index,
1895+ const char *name,
1896+ const void *value,
1897+ size_t value_len,
1898+ int flags)
1899+{
1900+ struct buffer_head *di_bh = NULL;
1901+ struct ocfs2_dinode *di;
1902+ int ret;
1903+
1904+ struct ocfs2_xattr_info xi = {
1905+ .name_index = name_index,
1906+ .name = name,
1907+ .value = value,
1908+ .value_len = value_len,
1909+ };
1910+
1911+ struct ocfs2_xattr_search xis = {
1912+ .not_found = -ENODATA,
1913+ };
1914+
1915+ struct ocfs2_xattr_search xbs = {
1916+ .not_found = -ENODATA,
1917+ };
1918+
1919+ ret = ocfs2_inode_lock(inode, &di_bh, 1);
1920+ if (ret < 0) {
1921+ mlog_errno(ret);
1922+ return ret;
1923+ }
1924+ xis.inode_bh = xbs.inode_bh = di_bh;
1925+ di = (struct ocfs2_dinode *)di_bh->b_data;
1926+
1927+ down_write(&OCFS2_I(inode)->ip_xattr_sem);
1928+ /*
1929+ * Scan inode and external block to find the same name
1930+ * extended attribute and collect search infomation.
1931+ */
1932+ ret = ocfs2_xattr_ibody_find(inode, name_index, name, &xis);
1933+ if (ret)
1934+ goto cleanup;
1935+ if (xis.not_found) {
1936+ ret = ocfs2_xattr_block_find(inode, name_index, name, &xbs);
1937+ if (ret)
1938+ goto cleanup;
1939+ }
1940+
1941+ if (xis.not_found && xbs.not_found) {
1942+ ret = -ENODATA;
1943+ if (flags & XATTR_REPLACE)
1944+ goto cleanup;
1945+ ret = 0;
1946+ if (!value)
1947+ goto cleanup;
1948+ } else {
1949+ ret = -EEXIST;
1950+ if (flags & XATTR_CREATE)
1951+ goto cleanup;
1952+ }
1953+
1954+ if (!value) {
1955+ /* Remove existing extended attribute */
1956+ if (!xis.not_found)
1957+ ret = ocfs2_xattr_ibody_set(inode, &xi, &xis);
1958+ else if (!xbs.not_found)
1959+ ret = ocfs2_xattr_block_set(inode, &xi, &xbs);
1960+ } else {
1961+ /* We always try to set extended attribute into inode first*/
1962+ ret = ocfs2_xattr_ibody_set(inode, &xi, &xis);
1963+ if (!ret && !xbs.not_found) {
1964+ /*
1965+ * If succeed and that extended attribute existing in
1966+ * external block, then we will remove it.
1967+ */
1968+ xi.value = NULL;
1969+ xi.value_len = 0;
1970+ ret = ocfs2_xattr_block_set(inode, &xi, &xbs);
1971+ } else if (ret == -ENOSPC) {
1972+ if (di->i_xattr_loc && !xbs.xattr_bh) {
1973+ ret = ocfs2_xattr_block_find(inode, name_index,
1974+ name, &xbs);
1975+ if (ret)
1976+ goto cleanup;
1977+ }
1978+ /*
1979+ * If no space in inode, we will set extended attribute
1980+ * into external block.
1981+ */
1982+ ret = ocfs2_xattr_block_set(inode, &xi, &xbs);
1983+ if (ret)
1984+ goto cleanup;
1985+ if (!xis.not_found) {
1986+ /*
1987+ * If succeed and that extended attribute
1988+ * existing in inode, we will remove it.
1989+ */
1990+ xi.value = NULL;
1991+ xi.value_len = 0;
1992+ ret = ocfs2_xattr_ibody_set(inode, &xi, &xis);
1993+ }
1994+ }
1995+ }
1996+cleanup:
1997+ up_write(&OCFS2_I(inode)->ip_xattr_sem);
1998+ ocfs2_inode_unlock(inode, 1);
1999+ brelse(di_bh);
2000+ brelse(xbs.xattr_bh);
2001+
2002+ return ret;
2003+}
2004+
2005--- /dev/null
2006+++ b/fs/ocfs2/xattr.h
2007@@ -0,0 +1,58 @@
2008+/* -*- mode: c; c-basic-offset: 8; -*-
2009+ * vim: noexpandtab sw=8 ts=8 sts=0:
2010+ *
2011+ * xattr.h
2012+ *
2013+ * Function prototypes
2014+ *
2015+ * Copyright (C) 2008 Oracle. All rights reserved.
2016+ *
2017+ * This program is free software; you can redistribute it and/or
2018+ * modify it under the terms of the GNU General Public
2019+ * License as published by the Free Software Foundation; either
2020+ * version 2 of the License, or (at your option) any later version.
2021+ *
2022+ * This program is distributed in the hope that it will be useful,
2023+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2024+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2025+ * General Public License for more details.
2026+ *
2027+ * You should have received a copy of the GNU General Public
2028+ * License along with this program; if not, write to the
2029+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2030+ * Boston, MA 021110-1307, USA.
2031+ */
2032+
2033+#ifndef OCFS2_XATTR_H
2034+#define OCFS2_XATTR_H
2035+
2036+#include <linux/init.h>
2037+#include <linux/xattr.h>
2038+
2039+enum ocfs2_xattr_type {
2040+ OCFS2_XATTR_INDEX_USER = 1,
2041+ OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS,
2042+ OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT,
2043+ OCFS2_XATTR_INDEX_TRUSTED,
2044+ OCFS2_XATTR_INDEX_SECURITY,
2045+ OCFS2_XATTR_MAX
2046+};
2047+
2048+extern struct xattr_handler ocfs2_xattr_user_handler;
2049+extern struct xattr_handler ocfs2_xattr_trusted_handler;
2050+#ifdef CONFIG_OCFS2_FS_POSIX_ACL
2051+extern struct xattr_handler ocfs2_xattr_acl_access_handler;
2052+extern struct xattr_handler ocfs2_xattr_acl_default_handler;
2053+#endif
2054+#ifdef CONFIG_OCFS2_FS_SECURITY
2055+extern struct xattr_handler ocfs2_xattr_security_handler;
2056+#endif
2057+
2058+extern ssize_t ocfs2_listxattr(struct dentry *, char *, size_t);
2059+extern int ocfs2_xattr_get(struct inode *, int, const char *, void *, size_t);
2060+extern int ocfs2_xattr_set(struct inode *, int, const char *, const void *,
2061+ size_t, int);
2062+extern int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh);
2063+extern struct xattr_handler *ocfs2_xattr_handlers[];
2064+
2065+#endif /* OCFS2_XATTR_H */
2066--- /dev/null
2067+++ b/fs/ocfs2/xattr_trusted.c
2068@@ -0,0 +1,82 @@
2069+/* -*- mode: c; c-basic-offset: 8; -*-
2070+ * vim: noexpandtab sw=8 ts=8 sts=0:
2071+ *
2072+ * xattr_trusted.c
2073+ *
2074+ * Copyright (C) 2008 Oracle. All rights reserved.
2075+ *
2076+ * CREDITS:
2077+ * Lots of code in this file is taken from ext3.
2078+ *
2079+ * This program is free software; you can redistribute it and/or
2080+ * modify it under the terms of the GNU General Public
2081+ * License as published by the Free Software Foundation; either
2082+ * version 2 of the License, or (at your option) any later version.
2083+ *
2084+ * This program is distributed in the hope that it will be useful,
2085+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2086+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2087+ * General Public License for more details.
2088+ *
2089+ * You should have received a copy of the GNU General Public
2090+ * License along with this program; if not, write to the
2091+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2092+ * Boston, MA 021110-1307, USA.
2093+ */
2094+
2095+#include <linux/init.h>
2096+#include <linux/module.h>
2097+#include <linux/string.h>
2098+
2099+#define MLOG_MASK_PREFIX ML_INODE
2100+#include <cluster/masklog.h>
2101+
2102+#include "ocfs2.h"
2103+#include "alloc.h"
2104+#include "dlmglue.h"
2105+#include "file.h"
2106+#include "ocfs2_fs.h"
2107+#include "xattr.h"
2108+
2109+#define XATTR_TRUSTED_PREFIX "trusted."
2110+
2111+static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list,
2112+ size_t list_size, const char *name,
2113+ size_t name_len)
2114+{
2115+ const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX) - 1;
2116+ const size_t total_len = prefix_len + name_len + 1;
2117+
2118+ if (list && total_len <= list_size) {
2119+ memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
2120+ memcpy(list + prefix_len, name, name_len);
2121+ list[prefix_len + name_len] = '\0';
2122+ }
2123+ return total_len;
2124+}
2125+
2126+static int ocfs2_xattr_trusted_get(struct inode *inode, const char *name,
2127+ void *buffer, size_t size)
2128+{
2129+ if (strcmp(name, "") == 0)
2130+ return -EINVAL;
2131+ return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_TRUSTED, name,
2132+ buffer, size);
2133+}
2134+
2135+static int ocfs2_xattr_trusted_set(struct inode *inode, const char *name,
2136+ const void *value, size_t size, int flags)
2137+{
2138+ if (strcmp(name, "") == 0)
2139+ return -EINVAL;
2140+
2141+ return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_TRUSTED, name, value,
2142+ size, flags);
2143+}
2144+
2145+struct xattr_handler ocfs2_xattr_trusted_handler = {
2146+ .prefix = XATTR_TRUSTED_PREFIX,
2147+ .list = ocfs2_xattr_trusted_list,
2148+ .get = ocfs2_xattr_trusted_get,
2149+ .set = ocfs2_xattr_trusted_set,
2150+};
2151--- /dev/null
2152+++ b/fs/ocfs2/xattr_user.c
2153@@ -0,0 +1,94 @@
2154+/* -*- mode: c; c-basic-offset: 8; -*-
2155+ * vim: noexpandtab sw=8 ts=8 sts=0:
2156+ *
2157+ * xattr_user.c
2158+ *
2159+ * Copyright (C) 2008 Oracle. All rights reserved.
2160+ *
2161+ * CREDITS:
2162+ * Lots of code in this file is taken from ext3.
2163+ *
2164+ * This program is free software; you can redistribute it and/or
2165+ * modify it under the terms of the GNU General Public
2166+ * License as published by the Free Software Foundation; either
2167+ * version 2 of the License, or (at your option) any later version.
2168+ *
2169+ * This program is distributed in the hope that it will be useful,
2170+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2171+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2172+ * General Public License for more details.
2173+ *
2174+ * You should have received a copy of the GNU General Public
2175+ * License along with this program; if not, write to the
2176+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2177+ * Boston, MA 021110-1307, USA.
2178+ */
2179+
2180+#include <linux/init.h>
2181+#include <linux/module.h>
2182+#include <linux/string.h>
2183+
2184+#define MLOG_MASK_PREFIX ML_INODE
2185+#include <cluster/masklog.h>
2186+
2187+#include "ocfs2.h"
2188+#include "alloc.h"
2189+#include "dlmglue.h"
2190+#include "file.h"
2191+#include "ocfs2_fs.h"
2192+#include "xattr.h"
2193+
2194+#define XATTR_USER_PREFIX "user."
2195+
2196+static size_t ocfs2_xattr_user_list(struct inode *inode, char *list,
2197+ size_t list_size, const char *name,
2198+ size_t name_len)
2199+{
2200+ const size_t prefix_len = sizeof(XATTR_USER_PREFIX) - 1;
2201+ const size_t total_len = prefix_len + name_len + 1;
2202+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
2203+
2204+ if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
2205+ return 0;
2206+
2207+ if (list && total_len <= list_size) {
2208+ memcpy(list, XATTR_USER_PREFIX, prefix_len);
2209+ memcpy(list + prefix_len, name, name_len);
2210+ list[prefix_len + name_len] = '\0';
2211+ }
2212+ return total_len;
2213+}
2214+
2215+static int ocfs2_xattr_user_get(struct inode *inode, const char *name,
2216+ void *buffer, size_t size)
2217+{
2218+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
2219+
2220+ if (strcmp(name, "") == 0)
2221+ return -EINVAL;
2222+ if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
2223+ return -EOPNOTSUPP;
2224+ return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_USER, name,
2225+ buffer, size);
2226+}
2227+
2228+static int ocfs2_xattr_user_set(struct inode *inode, const char *name,
2229+ const void *value, size_t size, int flags)
2230+{
2231+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
2232+
2233+ if (strcmp(name, "") == 0)
2234+ return -EINVAL;
2235+ if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
2236+ return -EOPNOTSUPP;
2237+
2238+ return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_USER, name, value,
2239+ size, flags);
2240+}
2241+
2242+struct xattr_handler ocfs2_xattr_user_handler = {
2243+ .prefix = XATTR_USER_PREFIX,
2244+ .list = ocfs2_xattr_user_list,
2245+ .get = ocfs2_xattr_user_get,
2246+ .set = ocfs2_xattr_user_set,
2247+};