Blame view

fs/ceph/xattr.c 27.5 KB
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
1
  #include <linux/ceph/ceph_debug.h>
25e6bae35   Yan, Zheng   ceph: use pagelis...
2
  #include <linux/ceph/pagelist.h>
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
3

355da1eb7   Sage Weil   ceph: inode opera...
4
  #include "super.h"
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
5
6
7
  #include "mds_client.h"
  
  #include <linux/ceph/decode.h>
355da1eb7   Sage Weil   ceph: inode opera...
8
9
  
  #include <linux/xattr.h>
4db658ea0   Linus Torvalds   ceph: Fix up afte...
10
  #include <linux/posix_acl_xattr.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
355da1eb7   Sage Weil   ceph: inode opera...
12

228919071   Alex Elder   ceph: use a symbo...
13
14
  #define XATTR_CEPH_PREFIX "ceph."
  #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1)
bcdfeb2eb   Yan, Zheng   ceph: remove xatt...
15
16
  static int __remove_xattr(struct ceph_inode_info *ci,
  			  struct ceph_inode_xattr *xattr);
5130ccea7   Wei Yongjun   ceph: fix non sta...
17
  static const struct xattr_handler ceph_other_xattr_handler;
2cdeb1e47   Andreas Gruenbacher   ceph: Switch to g...
18

7221fe4c2   Guangliang Zhao   ceph: add acl for...
19
20
21
22
23
24
  /*
   * List of handlers for synthetic system.* attributes. Other
   * attributes are handled directly.
   */
  const struct xattr_handler *ceph_xattr_handlers[] = {
  #ifdef CONFIG_CEPH_FS_POSIX_ACL
4db658ea0   Linus Torvalds   ceph: Fix up afte...
25
26
  	&posix_acl_access_xattr_handler,
  	&posix_acl_default_xattr_handler,
7221fe4c2   Guangliang Zhao   ceph: add acl for...
27
  #endif
2cdeb1e47   Andreas Gruenbacher   ceph: Switch to g...
28
  	&ceph_other_xattr_handler,
7221fe4c2   Guangliang Zhao   ceph: add acl for...
29
30
  	NULL,
  };
355da1eb7   Sage Weil   ceph: inode opera...
31
32
  static bool ceph_is_valid_xattr(const char *name)
  {
228919071   Alex Elder   ceph: use a symbo...
33
  	return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) ||
1a7562789   Sage Weil   ceph: use ceph. p...
34
  	       !strncmp(name, XATTR_SECURITY_PREFIX,
355da1eb7   Sage Weil   ceph: inode opera...
35
36
37
38
39
40
41
42
43
  			XATTR_SECURITY_PREFIX_LEN) ||
  	       !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
  	       !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
  }
  
  /*
   * These define virtual xattrs exposing the recursive directory
   * statistics and layout metadata.
   */
881a5fa20   Alex Elder   ceph: drop "_cb" ...
44
  struct ceph_vxattr {
355da1eb7   Sage Weil   ceph: inode opera...
45
  	char *name;
3ce6cd123   Alex Elder   ceph: avoid repea...
46
  	size_t name_size;	/* strlen(name) + 1 (for '\0') */
355da1eb7   Sage Weil   ceph: inode opera...
47
48
  	size_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val,
  			      size_t size);
8860147a0   Sage Weil   ceph: support hid...
49
  	bool readonly, hidden;
f36e44729   Sage Weil   ceph: add exists_...
50
  	bool (*exists_cb)(struct ceph_inode_info *ci);
355da1eb7   Sage Weil   ceph: inode opera...
51
  };
32ab0bd78   Sage Weil   ceph: change ceph...
52
53
54
55
  /* layouts */
  
  static bool ceph_vxattrcb_layout_exists(struct ceph_inode_info *ci)
  {
779fe0fb8   Yan, Zheng   ceph: rados pool ...
56
57
58
59
  	struct ceph_file_layout *fl = &ci->i_layout;
  	return (fl->stripe_unit > 0 || fl->stripe_count > 0 ||
  		fl->object_size > 0 || fl->pool_id >= 0 ||
  		rcu_dereference_raw(fl->pool_ns) != NULL);
32ab0bd78   Sage Weil   ceph: change ceph...
60
61
62
  }
  
  static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
1e5c6649f   Yan, Zheng   ceph: check buffe...
63
  				   size_t size)
32ab0bd78   Sage Weil   ceph: change ceph...
64
  {
32ab0bd78   Sage Weil   ceph: change ceph...
65
66
  	struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb);
  	struct ceph_osd_client *osdc = &fsc->client->osdc;
779fe0fb8   Yan, Zheng   ceph: rados pool ...
67
  	struct ceph_string *pool_ns;
7627151ea   Yan, Zheng   libceph: define n...
68
  	s64 pool = ci->i_layout.pool_id;
32ab0bd78   Sage Weil   ceph: change ceph...
69
  	const char *pool_name;
779fe0fb8   Yan, Zheng   ceph: rados pool ...
70
  	const char *ns_field = " pool_namespace=";
1e5c6649f   Yan, Zheng   ceph: check buffe...
71
  	char buf[128];
779fe0fb8   Yan, Zheng   ceph: rados pool ...
72
73
74
75
  	size_t len, total_len = 0;
  	int ret;
  
  	pool_ns = ceph_try_get_string(ci->i_layout.pool_ns);
32ab0bd78   Sage Weil   ceph: change ceph...
76
77
78
  
  	dout("ceph_vxattrcb_layout %p
  ", &ci->vfs_inode);
5aea3dcd5   Ilya Dryomov   libceph: a major ...
79
  	down_read(&osdc->lock);
32ab0bd78   Sage Weil   ceph: change ceph...
80
  	pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool);
1e5c6649f   Yan, Zheng   ceph: check buffe...
81
  	if (pool_name) {
779fe0fb8   Yan, Zheng   ceph: rados pool ...
82
  		len = snprintf(buf, sizeof(buf),
7627151ea   Yan, Zheng   libceph: define n...
83
84
85
  		"stripe_unit=%u stripe_count=%u object_size=%u pool=",
  		ci->i_layout.stripe_unit, ci->i_layout.stripe_count,
  	        ci->i_layout.object_size);
779fe0fb8   Yan, Zheng   ceph: rados pool ...
86
  		total_len = len + strlen(pool_name);
1e5c6649f   Yan, Zheng   ceph: check buffe...
87
  	} else {
779fe0fb8   Yan, Zheng   ceph: rados pool ...
88
  		len = snprintf(buf, sizeof(buf),
7627151ea   Yan, Zheng   libceph: define n...
89
90
91
  		"stripe_unit=%u stripe_count=%u object_size=%u pool=%lld",
  		ci->i_layout.stripe_unit, ci->i_layout.stripe_count,
  	        ci->i_layout.object_size, (unsigned long long)pool);
779fe0fb8   Yan, Zheng   ceph: rados pool ...
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  		total_len = len;
  	}
  
  	if (pool_ns)
  		total_len += strlen(ns_field) + pool_ns->len;
  
  	if (!size) {
  		ret = total_len;
  	} else if (total_len > size) {
  		ret = -ERANGE;
  	} else {
  		memcpy(val, buf, len);
  		ret = len;
  		if (pool_name) {
  			len = strlen(pool_name);
  			memcpy(val + ret, pool_name, len);
  			ret += len;
  		}
  		if (pool_ns) {
  			len = strlen(ns_field);
  			memcpy(val + ret, ns_field, len);
  			ret += len;
  			memcpy(val + ret, pool_ns->str, pool_ns->len);
  			ret += pool_ns->len;
1e5c6649f   Yan, Zheng   ceph: check buffe...
116
117
  		}
  	}
5aea3dcd5   Ilya Dryomov   libceph: a major ...
118
  	up_read(&osdc->lock);
779fe0fb8   Yan, Zheng   ceph: rados pool ...
119
  	ceph_put_string(pool_ns);
32ab0bd78   Sage Weil   ceph: change ceph...
120
121
  	return ret;
  }
695b71193   Sage Weil   ceph: implement h...
122
123
124
  static size_t ceph_vxattrcb_layout_stripe_unit(struct ceph_inode_info *ci,
  					       char *val, size_t size)
  {
7627151ea   Yan, Zheng   libceph: define n...
125
  	return snprintf(val, size, "%u", ci->i_layout.stripe_unit);
695b71193   Sage Weil   ceph: implement h...
126
127
128
129
130
  }
  
  static size_t ceph_vxattrcb_layout_stripe_count(struct ceph_inode_info *ci,
  						char *val, size_t size)
  {
7627151ea   Yan, Zheng   libceph: define n...
131
  	return snprintf(val, size, "%u", ci->i_layout.stripe_count);
695b71193   Sage Weil   ceph: implement h...
132
133
134
135
136
  }
  
  static size_t ceph_vxattrcb_layout_object_size(struct ceph_inode_info *ci,
  					       char *val, size_t size)
  {
7627151ea   Yan, Zheng   libceph: define n...
137
  	return snprintf(val, size, "%u", ci->i_layout.object_size);
695b71193   Sage Weil   ceph: implement h...
138
139
140
141
142
143
144
145
  }
  
  static size_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci,
  					char *val, size_t size)
  {
  	int ret;
  	struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb);
  	struct ceph_osd_client *osdc = &fsc->client->osdc;
7627151ea   Yan, Zheng   libceph: define n...
146
  	s64 pool = ci->i_layout.pool_id;
695b71193   Sage Weil   ceph: implement h...
147
  	const char *pool_name;
5aea3dcd5   Ilya Dryomov   libceph: a major ...
148
  	down_read(&osdc->lock);
695b71193   Sage Weil   ceph: implement h...
149
150
151
152
153
  	pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool);
  	if (pool_name)
  		ret = snprintf(val, size, "%s", pool_name);
  	else
  		ret = snprintf(val, size, "%lld", (unsigned long long)pool);
5aea3dcd5   Ilya Dryomov   libceph: a major ...
154
  	up_read(&osdc->lock);
695b71193   Sage Weil   ceph: implement h...
155
156
  	return ret;
  }
779fe0fb8   Yan, Zheng   ceph: rados pool ...
157
158
159
160
161
162
163
164
165
166
167
  static size_t ceph_vxattrcb_layout_pool_namespace(struct ceph_inode_info *ci,
  						  char *val, size_t size)
  {
  	int ret = 0;
  	struct ceph_string *ns = ceph_try_get_string(ci->i_layout.pool_ns);
  	if (ns) {
  		ret = snprintf(val, size, "%.*s", (int)ns->len, ns->str);
  		ceph_put_string(ns);
  	}
  	return ret;
  }
355da1eb7   Sage Weil   ceph: inode opera...
168
  /* directories */
aa4066ed7   Alex Elder   ceph: encode type...
169
  static size_t ceph_vxattrcb_dir_entries(struct ceph_inode_info *ci, char *val,
355da1eb7   Sage Weil   ceph: inode opera...
170
171
172
173
  					size_t size)
  {
  	return snprintf(val, size, "%lld", ci->i_files + ci->i_subdirs);
  }
aa4066ed7   Alex Elder   ceph: encode type...
174
  static size_t ceph_vxattrcb_dir_files(struct ceph_inode_info *ci, char *val,
355da1eb7   Sage Weil   ceph: inode opera...
175
176
177
178
  				      size_t size)
  {
  	return snprintf(val, size, "%lld", ci->i_files);
  }
aa4066ed7   Alex Elder   ceph: encode type...
179
  static size_t ceph_vxattrcb_dir_subdirs(struct ceph_inode_info *ci, char *val,
355da1eb7   Sage Weil   ceph: inode opera...
180
181
182
183
  					size_t size)
  {
  	return snprintf(val, size, "%lld", ci->i_subdirs);
  }
aa4066ed7   Alex Elder   ceph: encode type...
184
  static size_t ceph_vxattrcb_dir_rentries(struct ceph_inode_info *ci, char *val,
355da1eb7   Sage Weil   ceph: inode opera...
185
186
187
188
  					 size_t size)
  {
  	return snprintf(val, size, "%lld", ci->i_rfiles + ci->i_rsubdirs);
  }
aa4066ed7   Alex Elder   ceph: encode type...
189
  static size_t ceph_vxattrcb_dir_rfiles(struct ceph_inode_info *ci, char *val,
355da1eb7   Sage Weil   ceph: inode opera...
190
191
192
193
  				       size_t size)
  {
  	return snprintf(val, size, "%lld", ci->i_rfiles);
  }
aa4066ed7   Alex Elder   ceph: encode type...
194
  static size_t ceph_vxattrcb_dir_rsubdirs(struct ceph_inode_info *ci, char *val,
355da1eb7   Sage Weil   ceph: inode opera...
195
196
197
198
  					 size_t size)
  {
  	return snprintf(val, size, "%lld", ci->i_rsubdirs);
  }
aa4066ed7   Alex Elder   ceph: encode type...
199
  static size_t ceph_vxattrcb_dir_rbytes(struct ceph_inode_info *ci, char *val,
355da1eb7   Sage Weil   ceph: inode opera...
200
201
202
203
  				       size_t size)
  {
  	return snprintf(val, size, "%lld", ci->i_rbytes);
  }
aa4066ed7   Alex Elder   ceph: encode type...
204
  static size_t ceph_vxattrcb_dir_rctime(struct ceph_inode_info *ci, char *val,
355da1eb7   Sage Weil   ceph: inode opera...
205
206
  				       size_t size)
  {
3489b42a7   Alex Elder   ceph: fix three b...
207
  	return snprintf(val, size, "%ld.09%ld", (long)ci->i_rctime.tv_sec,
355da1eb7   Sage Weil   ceph: inode opera...
208
209
  			(long)ci->i_rctime.tv_nsec);
  }
32ab0bd78   Sage Weil   ceph: change ceph...
210

eb7880844   Alex Elder   ceph: use macros ...
211
  #define CEPH_XATTR_NAME(_type, _name)	XATTR_CEPH_PREFIX #_type "." #_name
695b71193   Sage Weil   ceph: implement h...
212
213
  #define CEPH_XATTR_NAME2(_type, _name, _name2)	\
  	XATTR_CEPH_PREFIX #_type "." #_name "." #_name2
eb7880844   Alex Elder   ceph: use macros ...
214

8860147a0   Sage Weil   ceph: support hid...
215
216
217
218
219
220
221
  #define XATTR_NAME_CEPH(_type, _name)					\
  	{								\
  		.name = CEPH_XATTR_NAME(_type, _name),			\
  		.name_size = sizeof (CEPH_XATTR_NAME(_type, _name)), \
  		.getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \
  		.readonly = true,				\
  		.hidden = false,				\
f36e44729   Sage Weil   ceph: add exists_...
222
  		.exists_cb = NULL,			\
8860147a0   Sage Weil   ceph: support hid...
223
  	}
695b71193   Sage Weil   ceph: implement h...
224
225
226
227
228
229
230
231
232
  #define XATTR_LAYOUT_FIELD(_type, _name, _field)			\
  	{								\
  		.name = CEPH_XATTR_NAME2(_type, _name, _field),	\
  		.name_size = sizeof (CEPH_XATTR_NAME2(_type, _name, _field)), \
  		.getxattr_cb = ceph_vxattrcb_ ## _name ## _ ## _field, \
  		.readonly = false,				\
  		.hidden = true,			\
  		.exists_cb = ceph_vxattrcb_layout_exists,	\
  	}
eb7880844   Alex Elder   ceph: use macros ...
233

881a5fa20   Alex Elder   ceph: drop "_cb" ...
234
  static struct ceph_vxattr ceph_dir_vxattrs[] = {
1f08f2b05   Sage Weil   ceph: add ceph.di...
235
236
237
238
239
  	{
  		.name = "ceph.dir.layout",
  		.name_size = sizeof("ceph.dir.layout"),
  		.getxattr_cb = ceph_vxattrcb_layout,
  		.readonly = false,
cc48c3e85   Yan, Zheng   ceph: don't inclu...
240
  		.hidden = true,
1f08f2b05   Sage Weil   ceph: add ceph.di...
241
242
  		.exists_cb = ceph_vxattrcb_layout_exists,
  	},
695b71193   Sage Weil   ceph: implement h...
243
244
245
246
  	XATTR_LAYOUT_FIELD(dir, layout, stripe_unit),
  	XATTR_LAYOUT_FIELD(dir, layout, stripe_count),
  	XATTR_LAYOUT_FIELD(dir, layout, object_size),
  	XATTR_LAYOUT_FIELD(dir, layout, pool),
779fe0fb8   Yan, Zheng   ceph: rados pool ...
247
  	XATTR_LAYOUT_FIELD(dir, layout, pool_namespace),
eb7880844   Alex Elder   ceph: use macros ...
248
249
250
251
252
253
254
255
  	XATTR_NAME_CEPH(dir, entries),
  	XATTR_NAME_CEPH(dir, files),
  	XATTR_NAME_CEPH(dir, subdirs),
  	XATTR_NAME_CEPH(dir, rentries),
  	XATTR_NAME_CEPH(dir, rfiles),
  	XATTR_NAME_CEPH(dir, rsubdirs),
  	XATTR_NAME_CEPH(dir, rbytes),
  	XATTR_NAME_CEPH(dir, rctime),
2c3dd4ff5   Alex Elder   ceph: eliminate s...
256
  	{ .name = NULL, 0 }	/* Required table terminator */
355da1eb7   Sage Weil   ceph: inode opera...
257
  };
3ce6cd123   Alex Elder   ceph: avoid repea...
258
  static size_t ceph_dir_vxattrs_name_size;	/* total size of all names */
355da1eb7   Sage Weil   ceph: inode opera...
259
260
  
  /* files */
881a5fa20   Alex Elder   ceph: drop "_cb" ...
261
  static struct ceph_vxattr ceph_file_vxattrs[] = {
32ab0bd78   Sage Weil   ceph: change ceph...
262
263
264
265
266
  	{
  		.name = "ceph.file.layout",
  		.name_size = sizeof("ceph.file.layout"),
  		.getxattr_cb = ceph_vxattrcb_layout,
  		.readonly = false,
cc48c3e85   Yan, Zheng   ceph: don't inclu...
267
  		.hidden = true,
32ab0bd78   Sage Weil   ceph: change ceph...
268
269
  		.exists_cb = ceph_vxattrcb_layout_exists,
  	},
695b71193   Sage Weil   ceph: implement h...
270
271
272
273
  	XATTR_LAYOUT_FIELD(file, layout, stripe_unit),
  	XATTR_LAYOUT_FIELD(file, layout, stripe_count),
  	XATTR_LAYOUT_FIELD(file, layout, object_size),
  	XATTR_LAYOUT_FIELD(file, layout, pool),
779fe0fb8   Yan, Zheng   ceph: rados pool ...
274
  	XATTR_LAYOUT_FIELD(file, layout, pool_namespace),
2c3dd4ff5   Alex Elder   ceph: eliminate s...
275
  	{ .name = NULL, 0 }	/* Required table terminator */
355da1eb7   Sage Weil   ceph: inode opera...
276
  };
3ce6cd123   Alex Elder   ceph: avoid repea...
277
  static size_t ceph_file_vxattrs_name_size;	/* total size of all names */
355da1eb7   Sage Weil   ceph: inode opera...
278

881a5fa20   Alex Elder   ceph: drop "_cb" ...
279
  static struct ceph_vxattr *ceph_inode_vxattrs(struct inode *inode)
355da1eb7   Sage Weil   ceph: inode opera...
280
281
282
283
284
285
286
  {
  	if (S_ISDIR(inode->i_mode))
  		return ceph_dir_vxattrs;
  	else if (S_ISREG(inode->i_mode))
  		return ceph_file_vxattrs;
  	return NULL;
  }
3ce6cd123   Alex Elder   ceph: avoid repea...
287
288
289
290
291
292
  static size_t ceph_vxattrs_name_size(struct ceph_vxattr *vxattrs)
  {
  	if (vxattrs == ceph_dir_vxattrs)
  		return ceph_dir_vxattrs_name_size;
  	if (vxattrs == ceph_file_vxattrs)
  		return ceph_file_vxattrs_name_size;
0abb43dca   Yan, Zheng   ceph: fix llistxa...
293
  	BUG_ON(vxattrs);
3ce6cd123   Alex Elder   ceph: avoid repea...
294
295
296
297
298
299
300
301
302
303
304
305
306
  	return 0;
  }
  
  /*
   * Compute the aggregate size (including terminating '\0') of all
   * virtual extended attribute names in the given vxattr table.
   */
  static size_t __init vxattrs_name_size(struct ceph_vxattr *vxattrs)
  {
  	struct ceph_vxattr *vxattr;
  	size_t size = 0;
  
  	for (vxattr = vxattrs; vxattr->name; vxattr++)
8860147a0   Sage Weil   ceph: support hid...
307
308
  		if (!vxattr->hidden)
  			size += vxattr->name_size;
3ce6cd123   Alex Elder   ceph: avoid repea...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  
  	return size;
  }
  
  /* Routines called at initialization and exit time */
  
  void __init ceph_xattr_init(void)
  {
  	ceph_dir_vxattrs_name_size = vxattrs_name_size(ceph_dir_vxattrs);
  	ceph_file_vxattrs_name_size = vxattrs_name_size(ceph_file_vxattrs);
  }
  
  void ceph_xattr_exit(void)
  {
  	ceph_dir_vxattrs_name_size = 0;
  	ceph_file_vxattrs_name_size = 0;
  }
881a5fa20   Alex Elder   ceph: drop "_cb" ...
326
  static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode,
355da1eb7   Sage Weil   ceph: inode opera...
327
328
  						const char *name)
  {
881a5fa20   Alex Elder   ceph: drop "_cb" ...
329
  	struct ceph_vxattr *vxattr = ceph_inode_vxattrs(inode);
06476a69d   Alex Elder   ceph: pass inode ...
330
331
332
333
334
335
336
337
  
  	if (vxattr) {
  		while (vxattr->name) {
  			if (!strcmp(vxattr->name, name))
  				return vxattr;
  			vxattr++;
  		}
  	}
355da1eb7   Sage Weil   ceph: inode opera...
338
339
340
341
342
343
  	return NULL;
  }
  
  static int __set_xattr(struct ceph_inode_info *ci,
  			   const char *name, int name_len,
  			   const char *val, int val_len,
fbc0b970d   Yan, Zheng   ceph: properly ha...
344
  			   int flags, int update_xattr,
355da1eb7   Sage Weil   ceph: inode opera...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
  			   struct ceph_inode_xattr **newxattr)
  {
  	struct rb_node **p;
  	struct rb_node *parent = NULL;
  	struct ceph_inode_xattr *xattr = NULL;
  	int c;
  	int new = 0;
  
  	p = &ci->i_xattrs.index.rb_node;
  	while (*p) {
  		parent = *p;
  		xattr = rb_entry(parent, struct ceph_inode_xattr, node);
  		c = strncmp(name, xattr->name, min(name_len, xattr->name_len));
  		if (c < 0)
  			p = &(*p)->rb_left;
  		else if (c > 0)
  			p = &(*p)->rb_right;
  		else {
  			if (name_len == xattr->name_len)
  				break;
  			else if (name_len < xattr->name_len)
  				p = &(*p)->rb_left;
  			else
  				p = &(*p)->rb_right;
  		}
  		xattr = NULL;
  	}
fbc0b970d   Yan, Zheng   ceph: properly ha...
372
373
374
375
376
377
378
379
380
381
382
  	if (update_xattr) {
  		int err = 0;
  		if (xattr && (flags & XATTR_CREATE))
  			err = -EEXIST;
  		else if (!xattr && (flags & XATTR_REPLACE))
  			err = -ENODATA;
  		if (err) {
  			kfree(name);
  			kfree(val);
  			return err;
  		}
bcdfeb2eb   Yan, Zheng   ceph: remove xatt...
383
384
385
386
387
388
  		if (update_xattr < 0) {
  			if (xattr)
  				__remove_xattr(ci, xattr);
  			kfree(name);
  			return 0;
  		}
fbc0b970d   Yan, Zheng   ceph: properly ha...
389
  	}
355da1eb7   Sage Weil   ceph: inode opera...
390
391
392
393
394
  	if (!xattr) {
  		new = 1;
  		xattr = *newxattr;
  		xattr->name = name;
  		xattr->name_len = name_len;
fbc0b970d   Yan, Zheng   ceph: properly ha...
395
  		xattr->should_free_name = update_xattr;
355da1eb7   Sage Weil   ceph: inode opera...
396
397
398
399
400
401
402
403
404
  
  		ci->i_xattrs.count++;
  		dout("__set_xattr count=%d
  ", ci->i_xattrs.count);
  	} else {
  		kfree(*newxattr);
  		*newxattr = NULL;
  		if (xattr->should_free_val)
  			kfree((void *)xattr->val);
fbc0b970d   Yan, Zheng   ceph: properly ha...
405
  		if (update_xattr) {
355da1eb7   Sage Weil   ceph: inode opera...
406
407
408
409
410
411
  			kfree((void *)name);
  			name = xattr->name;
  		}
  		ci->i_xattrs.names_size -= xattr->name_len;
  		ci->i_xattrs.vals_size -= xattr->val_len;
  	}
355da1eb7   Sage Weil   ceph: inode opera...
412
413
414
415
416
417
418
419
  	ci->i_xattrs.names_size += name_len;
  	ci->i_xattrs.vals_size += val_len;
  	if (val)
  		xattr->val = val;
  	else
  		xattr->val = "";
  
  	xattr->val_len = val_len;
fbc0b970d   Yan, Zheng   ceph: properly ha...
420
421
  	xattr->dirty = update_xattr;
  	xattr->should_free_val = (val && update_xattr);
355da1eb7   Sage Weil   ceph: inode opera...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  
  	if (new) {
  		rb_link_node(&xattr->node, parent, p);
  		rb_insert_color(&xattr->node, &ci->i_xattrs.index);
  		dout("__set_xattr_val p=%p
  ", p);
  	}
  
  	dout("__set_xattr_val added %llx.%llx xattr %p %s=%.*s
  ",
  	     ceph_vinop(&ci->vfs_inode), xattr, name, val_len, val);
  
  	return 0;
  }
  
  static struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci,
  			   const char *name)
  {
  	struct rb_node **p;
  	struct rb_node *parent = NULL;
  	struct ceph_inode_xattr *xattr = NULL;
17db143fc   Sage Weil   ceph: fix xattr r...
443
  	int name_len = strlen(name);
355da1eb7   Sage Weil   ceph: inode opera...
444
445
446
447
448
449
450
  	int c;
  
  	p = &ci->i_xattrs.index.rb_node;
  	while (*p) {
  		parent = *p;
  		xattr = rb_entry(parent, struct ceph_inode_xattr, node);
  		c = strncmp(name, xattr->name, xattr->name_len);
17db143fc   Sage Weil   ceph: fix xattr r...
451
452
  		if (c == 0 && name_len > xattr->name_len)
  			c = 1;
355da1eb7   Sage Weil   ceph: inode opera...
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
  		if (c < 0)
  			p = &(*p)->rb_left;
  		else if (c > 0)
  			p = &(*p)->rb_right;
  		else {
  			dout("__get_xattr %s: found %.*s
  ", name,
  			     xattr->val_len, xattr->val);
  			return xattr;
  		}
  	}
  
  	dout("__get_xattr %s: not found
  ", name);
  
  	return NULL;
  }
  
  static void __free_xattr(struct ceph_inode_xattr *xattr)
  {
  	BUG_ON(!xattr);
  
  	if (xattr->should_free_name)
  		kfree((void *)xattr->name);
  	if (xattr->should_free_val)
  		kfree((void *)xattr->val);
  
  	kfree(xattr);
  }
  
  static int __remove_xattr(struct ceph_inode_info *ci,
  			  struct ceph_inode_xattr *xattr)
  {
  	if (!xattr)
524186ace   Yan, Zheng   ceph: fix ceph_re...
487
  		return -ENODATA;
355da1eb7   Sage Weil   ceph: inode opera...
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
  
  	rb_erase(&xattr->node, &ci->i_xattrs.index);
  
  	if (xattr->should_free_name)
  		kfree((void *)xattr->name);
  	if (xattr->should_free_val)
  		kfree((void *)xattr->val);
  
  	ci->i_xattrs.names_size -= xattr->name_len;
  	ci->i_xattrs.vals_size -= xattr->val_len;
  	ci->i_xattrs.count--;
  	kfree(xattr);
  
  	return 0;
  }
355da1eb7   Sage Weil   ceph: inode opera...
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
  static char *__copy_xattr_names(struct ceph_inode_info *ci,
  				char *dest)
  {
  	struct rb_node *p;
  	struct ceph_inode_xattr *xattr = NULL;
  
  	p = rb_first(&ci->i_xattrs.index);
  	dout("__copy_xattr_names count=%d
  ", ci->i_xattrs.count);
  
  	while (p) {
  		xattr = rb_entry(p, struct ceph_inode_xattr, node);
  		memcpy(dest, xattr->name, xattr->name_len);
  		dest[xattr->name_len] = '\0';
  
  		dout("dest=%s %p (%s) (%d/%d)
  ", dest, xattr, xattr->name,
  		     xattr->name_len, ci->i_xattrs.names_size);
  
  		dest += xattr->name_len + 1;
  		p = rb_next(p);
  	}
  
  	return dest;
  }
  
  void __ceph_destroy_xattrs(struct ceph_inode_info *ci)
  {
  	struct rb_node *p, *tmp;
  	struct ceph_inode_xattr *xattr = NULL;
  
  	p = rb_first(&ci->i_xattrs.index);
  
  	dout("__ceph_destroy_xattrs p=%p
  ", p);
  
  	while (p) {
  		xattr = rb_entry(p, struct ceph_inode_xattr, node);
  		tmp = p;
  		p = rb_next(tmp);
  		dout("__ceph_destroy_xattrs next p=%p (%.*s)
  ", p,
  		     xattr->name_len, xattr->name);
  		rb_erase(tmp, &ci->i_xattrs.index);
  
  		__free_xattr(xattr);
  	}
  
  	ci->i_xattrs.names_size = 0;
  	ci->i_xattrs.vals_size = 0;
  	ci->i_xattrs.index_version = 0;
  	ci->i_xattrs.count = 0;
  	ci->i_xattrs.index = RB_ROOT;
  }
  
  static int __build_xattrs(struct inode *inode)
be655596b   Sage Weil   ceph: use i_ceph_...
559
560
  	__releases(ci->i_ceph_lock)
  	__acquires(ci->i_ceph_lock)
355da1eb7   Sage Weil   ceph: inode opera...
561
562
563
564
565
566
567
568
569
  {
  	u32 namelen;
  	u32 numattr = 0;
  	void *p, *end;
  	u32 len;
  	const char *name, *val;
  	struct ceph_inode_info *ci = ceph_inode(inode);
  	int xattr_version;
  	struct ceph_inode_xattr **xattrs = NULL;
63ff78b25   Sage Weil   ceph: fix uniniti...
570
  	int err = 0;
355da1eb7   Sage Weil   ceph: inode opera...
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
  	int i;
  
  	dout("__build_xattrs() len=%d
  ",
  	     ci->i_xattrs.blob ? (int)ci->i_xattrs.blob->vec.iov_len : 0);
  
  	if (ci->i_xattrs.index_version >= ci->i_xattrs.version)
  		return 0; /* already built */
  
  	__ceph_destroy_xattrs(ci);
  
  start:
  	/* updated internal xattr rb tree */
  	if (ci->i_xattrs.blob && ci->i_xattrs.blob->vec.iov_len > 4) {
  		p = ci->i_xattrs.blob->vec.iov_base;
  		end = p + ci->i_xattrs.blob->vec.iov_len;
  		ceph_decode_32_safe(&p, end, numattr, bad);
  		xattr_version = ci->i_xattrs.version;
be655596b   Sage Weil   ceph: use i_ceph_...
589
  		spin_unlock(&ci->i_ceph_lock);
355da1eb7   Sage Weil   ceph: inode opera...
590

7e8a29529   Ilya Dryomov   ceph: fix sizeof(...
591
  		xattrs = kcalloc(numattr, sizeof(struct ceph_inode_xattr *),
355da1eb7   Sage Weil   ceph: inode opera...
592
593
594
595
  				 GFP_NOFS);
  		err = -ENOMEM;
  		if (!xattrs)
  			goto bad_lock;
1a295bd8c   Ilya Dryomov   ceph: remove redu...
596

355da1eb7   Sage Weil   ceph: inode opera...
597
598
599
600
601
602
  		for (i = 0; i < numattr; i++) {
  			xattrs[i] = kmalloc(sizeof(struct ceph_inode_xattr),
  					    GFP_NOFS);
  			if (!xattrs[i])
  				goto bad_lock;
  		}
be655596b   Sage Weil   ceph: use i_ceph_...
603
  		spin_lock(&ci->i_ceph_lock);
355da1eb7   Sage Weil   ceph: inode opera...
604
605
606
607
608
  		if (ci->i_xattrs.version != xattr_version) {
  			/* lost a race, retry */
  			for (i = 0; i < numattr; i++)
  				kfree(xattrs[i]);
  			kfree(xattrs);
21ec6ffa4   Alan Cox   ceph: fix potenti...
609
  			xattrs = NULL;
355da1eb7   Sage Weil   ceph: inode opera...
610
611
612
613
614
615
616
617
618
619
620
621
622
  			goto start;
  		}
  		err = -EIO;
  		while (numattr--) {
  			ceph_decode_32_safe(&p, end, len, bad);
  			namelen = len;
  			name = p;
  			p += len;
  			ceph_decode_32_safe(&p, end, len, bad);
  			val = p;
  			p += len;
  
  			err = __set_xattr(ci, name, namelen, val, len,
fbc0b970d   Yan, Zheng   ceph: properly ha...
623
  					  0, 0, &xattrs[numattr]);
355da1eb7   Sage Weil   ceph: inode opera...
624
625
626
627
628
629
630
631
632
633
634
  
  			if (err < 0)
  				goto bad;
  		}
  		kfree(xattrs);
  	}
  	ci->i_xattrs.index_version = ci->i_xattrs.version;
  	ci->i_xattrs.dirty = false;
  
  	return err;
  bad_lock:
be655596b   Sage Weil   ceph: use i_ceph_...
635
  	spin_lock(&ci->i_ceph_lock);
355da1eb7   Sage Weil   ceph: inode opera...
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
  bad:
  	if (xattrs) {
  		for (i = 0; i < numattr; i++)
  			kfree(xattrs[i]);
  		kfree(xattrs);
  	}
  	ci->i_xattrs.names_size = 0;
  	return err;
  }
  
  static int __get_required_blob_size(struct ceph_inode_info *ci, int name_size,
  				    int val_size)
  {
  	/*
  	 * 4 bytes for the length, and additional 4 bytes per each xattr name,
  	 * 4 bytes per each value
  	 */
  	int size = 4 + ci->i_xattrs.count*(4 + 4) +
  			     ci->i_xattrs.names_size +
  			     ci->i_xattrs.vals_size;
  	dout("__get_required_blob_size c=%d names.size=%d vals.size=%d
  ",
  	     ci->i_xattrs.count, ci->i_xattrs.names_size,
  	     ci->i_xattrs.vals_size);
  
  	if (name_size)
  		size += 4 + 4 + name_size + val_size;
  
  	return size;
  }
  
  /*
   * If there are dirty xattrs, reencode xattrs into the prealloc_blob
   * and swap into place.
   */
  void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
  {
  	struct rb_node *p;
  	struct ceph_inode_xattr *xattr = NULL;
  	void *dest;
  
  	dout("__build_xattrs_blob %p
  ", &ci->vfs_inode);
  	if (ci->i_xattrs.dirty) {
  		int need = __get_required_blob_size(ci, 0, 0);
  
  		BUG_ON(need > ci->i_xattrs.prealloc_blob->alloc_len);
  
  		p = rb_first(&ci->i_xattrs.index);
  		dest = ci->i_xattrs.prealloc_blob->vec.iov_base;
  
  		ceph_encode_32(&dest, ci->i_xattrs.count);
  		while (p) {
  			xattr = rb_entry(p, struct ceph_inode_xattr, node);
  
  			ceph_encode_32(&dest, xattr->name_len);
  			memcpy(dest, xattr->name, xattr->name_len);
  			dest += xattr->name_len;
  			ceph_encode_32(&dest, xattr->val_len);
  			memcpy(dest, xattr->val, xattr->val_len);
  			dest += xattr->val_len;
  
  			p = rb_next(p);
  		}
  
  		/* adjust buffer len; it may be larger than we need */
  		ci->i_xattrs.prealloc_blob->vec.iov_len =
  			dest - ci->i_xattrs.prealloc_blob->vec.iov_base;
b6c1d5b81   Sage Weil   ceph: simplify ce...
704
705
  		if (ci->i_xattrs.blob)
  			ceph_buffer_put(ci->i_xattrs.blob);
355da1eb7   Sage Weil   ceph: inode opera...
706
707
708
  		ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob;
  		ci->i_xattrs.prealloc_blob = NULL;
  		ci->i_xattrs.dirty = false;
4a625be47   Sage Weil   ceph: include dir...
709
  		ci->i_xattrs.version++;
355da1eb7   Sage Weil   ceph: inode opera...
710
711
  	}
  }
315f24088   Yan, Zheng   ceph: fix securit...
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
  static inline int __get_request_mask(struct inode *in) {
  	struct ceph_mds_request *req = current->journal_info;
  	int mask = 0;
  	if (req && req->r_target_inode == in) {
  		if (req->r_op == CEPH_MDS_OP_LOOKUP ||
  		    req->r_op == CEPH_MDS_OP_LOOKUPINO ||
  		    req->r_op == CEPH_MDS_OP_LOOKUPPARENT ||
  		    req->r_op == CEPH_MDS_OP_GETATTR) {
  			mask = le32_to_cpu(req->r_args.getattr.mask);
  		} else if (req->r_op == CEPH_MDS_OP_OPEN ||
  			   req->r_op == CEPH_MDS_OP_CREATE) {
  			mask = le32_to_cpu(req->r_args.open.mask);
  		}
  	}
  	return mask;
  }
7221fe4c2   Guangliang Zhao   ceph: add acl for...
728
  ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
355da1eb7   Sage Weil   ceph: inode opera...
729
730
  		      size_t size)
  {
355da1eb7   Sage Weil   ceph: inode opera...
731
  	struct ceph_inode_info *ci = ceph_inode(inode);
355da1eb7   Sage Weil   ceph: inode opera...
732
  	struct ceph_inode_xattr *xattr;
881a5fa20   Alex Elder   ceph: drop "_cb" ...
733
  	struct ceph_vxattr *vxattr = NULL;
315f24088   Yan, Zheng   ceph: fix securit...
734
735
  	int req_mask;
  	int err;
355da1eb7   Sage Weil   ceph: inode opera...
736

0bee82fb4   Sage Weil   ceph: fix getxatt...
737
738
  	/* let's see if a virtual xattr was requested */
  	vxattr = ceph_match_vxattr(inode, name);
29dccfa5a   Yan, Zheng   ceph: don't reque...
739
740
741
742
  	if (vxattr) {
  		err = -ENODATA;
  		if (!(vxattr->exists_cb && !vxattr->exists_cb(ci)))
  			err = vxattr->getxattr_cb(ci, value, size);
a1dc19373   majianpeng   ceph: fix sleepin...
743
  		return err;
0bee82fb4   Sage Weil   ceph: fix getxatt...
744
  	}
315f24088   Yan, Zheng   ceph: fix securit...
745
  	req_mask = __get_request_mask(inode);
a1dc19373   majianpeng   ceph: fix sleepin...
746
747
748
749
  	spin_lock(&ci->i_ceph_lock);
  	dout("getxattr %p ver=%lld index_ver=%lld
  ", inode,
  	     ci->i_xattrs.version, ci->i_xattrs.index_version);
508b32d86   Yan, Zheng   ceph: request xat...
750
  	if (ci->i_xattrs.version == 0 ||
315f24088   Yan, Zheng   ceph: fix securit...
751
752
  	    !((req_mask & CEPH_CAP_XATTR_SHARED) ||
  	      __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1))) {
be655596b   Sage Weil   ceph: use i_ceph_...
753
  		spin_unlock(&ci->i_ceph_lock);
315f24088   Yan, Zheng   ceph: fix securit...
754
755
756
757
758
759
760
761
  
  		/* security module gets xattr while filling trace */
  		if (current->journal_info != NULL) {
  			pr_warn_ratelimited("sync getxattr %p "
  					    "during filling trace
  ", inode);
  			return -EBUSY;
  		}
355da1eb7   Sage Weil   ceph: inode opera...
762
  		/* get xattrs from mds (if we don't already have them) */
508b32d86   Yan, Zheng   ceph: request xat...
763
  		err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true);
355da1eb7   Sage Weil   ceph: inode opera...
764
765
  		if (err)
  			return err;
508b32d86   Yan, Zheng   ceph: request xat...
766
  		spin_lock(&ci->i_ceph_lock);
355da1eb7   Sage Weil   ceph: inode opera...
767
  	}
355da1eb7   Sage Weil   ceph: inode opera...
768
769
770
  	err = __build_xattrs(inode);
  	if (err < 0)
  		goto out;
355da1eb7   Sage Weil   ceph: inode opera...
771
772
  	err = -ENODATA;  /* == ENOATTR */
  	xattr = __get_xattr(ci, name);
0bee82fb4   Sage Weil   ceph: fix getxatt...
773
  	if (!xattr)
355da1eb7   Sage Weil   ceph: inode opera...
774
  		goto out;
355da1eb7   Sage Weil   ceph: inode opera...
775
776
777
778
779
780
781
782
783
784
  
  	err = -ERANGE;
  	if (size && size < xattr->val_len)
  		goto out;
  
  	err = xattr->val_len;
  	if (size == 0)
  		goto out;
  
  	memcpy(value, xattr->val, xattr->val_len);
315f24088   Yan, Zheng   ceph: fix securit...
785
786
787
  	if (current->journal_info != NULL &&
  	    !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN))
  		ci->i_ceph_flags |= CEPH_I_SEC_INITED;
355da1eb7   Sage Weil   ceph: inode opera...
788
  out:
be655596b   Sage Weil   ceph: use i_ceph_...
789
  	spin_unlock(&ci->i_ceph_lock);
355da1eb7   Sage Weil   ceph: inode opera...
790
791
792
793
794
  	return err;
  }
  
  ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
  {
2b0143b5c   David Howells   VFS: normal files...
795
  	struct inode *inode = d_inode(dentry);
355da1eb7   Sage Weil   ceph: inode opera...
796
  	struct ceph_inode_info *ci = ceph_inode(inode);
881a5fa20   Alex Elder   ceph: drop "_cb" ...
797
  	struct ceph_vxattr *vxattrs = ceph_inode_vxattrs(inode);
355da1eb7   Sage Weil   ceph: inode opera...
798
799
800
801
802
  	u32 vir_namelen = 0;
  	u32 namelen;
  	int err;
  	u32 len;
  	int i;
be655596b   Sage Weil   ceph: use i_ceph_...
803
  	spin_lock(&ci->i_ceph_lock);
355da1eb7   Sage Weil   ceph: inode opera...
804
805
806
  	dout("listxattr %p ver=%lld index_ver=%lld
  ", inode,
  	     ci->i_xattrs.version, ci->i_xattrs.index_version);
508b32d86   Yan, Zheng   ceph: request xat...
807
808
  	if (ci->i_xattrs.version == 0 ||
  	    !__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1)) {
be655596b   Sage Weil   ceph: use i_ceph_...
809
  		spin_unlock(&ci->i_ceph_lock);
508b32d86   Yan, Zheng   ceph: request xat...
810
  		err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true);
355da1eb7   Sage Weil   ceph: inode opera...
811
812
  		if (err)
  			return err;
508b32d86   Yan, Zheng   ceph: request xat...
813
  		spin_lock(&ci->i_ceph_lock);
355da1eb7   Sage Weil   ceph: inode opera...
814
  	}
355da1eb7   Sage Weil   ceph: inode opera...
815
816
817
  	err = __build_xattrs(inode);
  	if (err < 0)
  		goto out;
3ce6cd123   Alex Elder   ceph: avoid repea...
818
819
820
821
822
  	/*
  	 * Start with virtual dir xattr names (if any) (including
  	 * terminating '\0' characters for each).
  	 */
  	vir_namelen = ceph_vxattrs_name_size(vxattrs);
355da1eb7   Sage Weil   ceph: inode opera...
823
  	/* adding 1 byte per each variable due to the null termination */
b65917dd2   Sage Weil   ceph: fix listxat...
824
  	namelen = ci->i_xattrs.names_size + ci->i_xattrs.count;
355da1eb7   Sage Weil   ceph: inode opera...
825
  	err = -ERANGE;
b65917dd2   Sage Weil   ceph: fix listxat...
826
  	if (size && vir_namelen + namelen > size)
355da1eb7   Sage Weil   ceph: inode opera...
827
  		goto out;
b65917dd2   Sage Weil   ceph: fix listxat...
828
  	err = namelen + vir_namelen;
355da1eb7   Sage Weil   ceph: inode opera...
829
830
831
832
833
834
  	if (size == 0)
  		goto out;
  
  	names = __copy_xattr_names(ci, names);
  
  	/* virtual xattr names, too */
b65917dd2   Sage Weil   ceph: fix listxat...
835
836
  	err = namelen;
  	if (vxattrs) {
355da1eb7   Sage Weil   ceph: inode opera...
837
  		for (i = 0; vxattrs[i].name; i++) {
b65917dd2   Sage Weil   ceph: fix listxat...
838
839
840
841
842
843
844
  			if (!vxattrs[i].hidden &&
  			    !(vxattrs[i].exists_cb &&
  			      !vxattrs[i].exists_cb(ci))) {
  				len = sprintf(names, "%s", vxattrs[i].name);
  				names += len + 1;
  				err += len + 1;
  			}
355da1eb7   Sage Weil   ceph: inode opera...
845
  		}
b65917dd2   Sage Weil   ceph: fix listxat...
846
  	}
355da1eb7   Sage Weil   ceph: inode opera...
847
848
  
  out:
be655596b   Sage Weil   ceph: use i_ceph_...
849
  	spin_unlock(&ci->i_ceph_lock);
355da1eb7   Sage Weil   ceph: inode opera...
850
851
  	return err;
  }
a26feccab   Andreas Gruenbacher   ceph: Get rid of ...
852
  static int ceph_sync_setxattr(struct inode *inode, const char *name,
355da1eb7   Sage Weil   ceph: inode opera...
853
854
  			      const char *value, size_t size, int flags)
  {
a26feccab   Andreas Gruenbacher   ceph: Get rid of ...
855
  	struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb);
355da1eb7   Sage Weil   ceph: inode opera...
856
  	struct ceph_inode_info *ci = ceph_inode(inode);
355da1eb7   Sage Weil   ceph: inode opera...
857
  	struct ceph_mds_request *req;
3d14c5d2b   Yehuda Sadeh   ceph: factor out ...
858
  	struct ceph_mds_client *mdsc = fsc->mdsc;
25e6bae35   Yan, Zheng   ceph: use pagelis...
859
  	struct ceph_pagelist *pagelist = NULL;
04303d8ad   Yan, Zheng   ceph: use CEPH_MD...
860
  	int op = CEPH_MDS_OP_SETXATTR;
355da1eb7   Sage Weil   ceph: inode opera...
861
  	int err;
25e6bae35   Yan, Zheng   ceph: use pagelis...
862

0aeff37ab   Yan, Zheng   ceph: fix setting...
863
  	if (size > 0) {
25e6bae35   Yan, Zheng   ceph: use pagelis...
864
865
866
  		/* copy value into pagelist */
  		pagelist = kmalloc(sizeof(*pagelist), GFP_NOFS);
  		if (!pagelist)
355da1eb7   Sage Weil   ceph: inode opera...
867
  			return -ENOMEM;
25e6bae35   Yan, Zheng   ceph: use pagelis...
868
869
870
871
872
  
  		ceph_pagelist_init(pagelist);
  		err = ceph_pagelist_append(pagelist, value, size);
  		if (err)
  			goto out;
0aeff37ab   Yan, Zheng   ceph: fix setting...
873
  	} else if (!value) {
04303d8ad   Yan, Zheng   ceph: use CEPH_MD...
874
875
876
877
  		if (flags & CEPH_XATTR_REPLACE)
  			op = CEPH_MDS_OP_RMXATTR;
  		else
  			flags |= CEPH_XATTR_REMOVE;
355da1eb7   Sage Weil   ceph: inode opera...
878
879
880
881
882
883
  	}
  
  	dout("setxattr value=%.*s
  ", (int)size, value);
  
  	/* do request */
04303d8ad   Yan, Zheng   ceph: use CEPH_MD...
884
  	req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
60d877334   Julia Lawall   fs/ceph: introduc...
885
886
887
888
  	if (IS_ERR(req)) {
  		err = PTR_ERR(req);
  		goto out;
  	}
a149bb9a2   Sanidhya Kashyap   ceph: kstrdup() m...
889

355da1eb7   Sage Weil   ceph: inode opera...
890
  	req->r_path2 = kstrdup(name, GFP_NOFS);
a149bb9a2   Sanidhya Kashyap   ceph: kstrdup() m...
891
892
893
894
895
  	if (!req->r_path2) {
  		ceph_mdsc_put_request(req);
  		err = -ENOMEM;
  		goto out;
  	}
355da1eb7   Sage Weil   ceph: inode opera...
896

04303d8ad   Yan, Zheng   ceph: use CEPH_MD...
897
898
899
900
901
  	if (op == CEPH_MDS_OP_SETXATTR) {
  		req->r_args.setxattr.flags = cpu_to_le32(flags);
  		req->r_pagelist = pagelist;
  		pagelist = NULL;
  	}
355da1eb7   Sage Weil   ceph: inode opera...
902

a149bb9a2   Sanidhya Kashyap   ceph: kstrdup() m...
903
904
905
906
  	req->r_inode = inode;
  	ihold(inode);
  	req->r_num_caps = 1;
  	req->r_inode_drop = CEPH_CAP_XATTR_SHARED;
355da1eb7   Sage Weil   ceph: inode opera...
907
908
  	dout("xattr.ver (before): %lld
  ", ci->i_xattrs.version);
752c8bdcf   Sage Weil   ceph: do not chai...
909
  	err = ceph_mdsc_do_request(mdsc, NULL, req);
355da1eb7   Sage Weil   ceph: inode opera...
910
911
912
913
914
  	ceph_mdsc_put_request(req);
  	dout("xattr.ver (after): %lld
  ", ci->i_xattrs.version);
  
  out:
25e6bae35   Yan, Zheng   ceph: use pagelis...
915
916
  	if (pagelist)
  		ceph_pagelist_release(pagelist);
355da1eb7   Sage Weil   ceph: inode opera...
917
918
  	return err;
  }
a26feccab   Andreas Gruenbacher   ceph: Get rid of ...
919
  int __ceph_setxattr(struct inode *inode, const char *name,
7221fe4c2   Guangliang Zhao   ceph: add acl for...
920
  			const void *value, size_t size, int flags)
355da1eb7   Sage Weil   ceph: inode opera...
921
  {
881a5fa20   Alex Elder   ceph: drop "_cb" ...
922
  	struct ceph_vxattr *vxattr;
355da1eb7   Sage Weil   ceph: inode opera...
923
  	struct ceph_inode_info *ci = ceph_inode(inode);
a26feccab   Andreas Gruenbacher   ceph: Get rid of ...
924
  	struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
f66fd9f09   Yan, Zheng   ceph: pre-allocat...
925
  	struct ceph_cap_flush *prealloc_cf = NULL;
18fa8b3fe   Alex Elder   ceph: make ceph_s...
926
  	int issued;
355da1eb7   Sage Weil   ceph: inode opera...
927
  	int err;
fbc0b970d   Yan, Zheng   ceph: properly ha...
928
  	int dirty = 0;
355da1eb7   Sage Weil   ceph: inode opera...
929
930
931
932
933
  	int name_len = strlen(name);
  	int val_len = size;
  	char *newname = NULL;
  	char *newval = NULL;
  	struct ceph_inode_xattr *xattr = NULL;
355da1eb7   Sage Weil   ceph: inode opera...
934
  	int required_blob_size;
604d1b024   Yan, Zheng   ceph: take snap_r...
935
  	bool lock_snap_rwsem = false;
355da1eb7   Sage Weil   ceph: inode opera...
936

2cdeb1e47   Andreas Gruenbacher   ceph: Switch to g...
937
938
  	if (ceph_snap(inode) != CEPH_NOSNAP)
  		return -EROFS;
355da1eb7   Sage Weil   ceph: inode opera...
939

06476a69d   Alex Elder   ceph: pass inode ...
940
941
942
  	vxattr = ceph_match_vxattr(inode, name);
  	if (vxattr && vxattr->readonly)
  		return -EOPNOTSUPP;
355da1eb7   Sage Weil   ceph: inode opera...
943

3adf654dd   Sage Weil   ceph: pass unhand...
944
945
946
  	/* pass any unhandled ceph.* xattrs through to the MDS */
  	if (!strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN))
  		goto do_sync_unlocked;
355da1eb7   Sage Weil   ceph: inode opera...
947
948
  	/* preallocate memory for xattr name, value, index node */
  	err = -ENOMEM;
61413c2f5   Julia Lawall   fs/ceph/xattr.c: ...
949
  	newname = kmemdup(name, name_len + 1, GFP_NOFS);
355da1eb7   Sage Weil   ceph: inode opera...
950
951
  	if (!newname)
  		goto out;
355da1eb7   Sage Weil   ceph: inode opera...
952
953
  
  	if (val_len) {
b829c1954   Alex Elder   ceph: don't null-...
954
  		newval = kmemdup(value, val_len, GFP_NOFS);
355da1eb7   Sage Weil   ceph: inode opera...
955
956
  		if (!newval)
  			goto out;
355da1eb7   Sage Weil   ceph: inode opera...
957
958
959
960
961
  	}
  
  	xattr = kmalloc(sizeof(struct ceph_inode_xattr), GFP_NOFS);
  	if (!xattr)
  		goto out;
f66fd9f09   Yan, Zheng   ceph: pre-allocat...
962
963
964
  	prealloc_cf = ceph_alloc_cap_flush();
  	if (!prealloc_cf)
  		goto out;
be655596b   Sage Weil   ceph: use i_ceph_...
965
  	spin_lock(&ci->i_ceph_lock);
355da1eb7   Sage Weil   ceph: inode opera...
966
967
  retry:
  	issued = __ceph_caps_issued(ci, NULL);
508b32d86   Yan, Zheng   ceph: request xat...
968
  	if (ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL))
355da1eb7   Sage Weil   ceph: inode opera...
969
  		goto do_sync;
604d1b024   Yan, Zheng   ceph: take snap_r...
970
971
972
973
974
975
976
977
978
979
980
981
982
  
  	if (!lock_snap_rwsem && !ci->i_head_snapc) {
  		lock_snap_rwsem = true;
  		if (!down_read_trylock(&mdsc->snap_rwsem)) {
  			spin_unlock(&ci->i_ceph_lock);
  			down_read(&mdsc->snap_rwsem);
  			spin_lock(&ci->i_ceph_lock);
  			goto retry;
  		}
  	}
  
  	dout("setxattr %p issued %s
  ", inode, ceph_cap_string(issued));
355da1eb7   Sage Weil   ceph: inode opera...
983
984
985
986
987
988
  	__build_xattrs(inode);
  
  	required_blob_size = __get_required_blob_size(ci, name_len, val_len);
  
  	if (!ci->i_xattrs.prealloc_blob ||
  	    required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
18fa8b3fe   Alex Elder   ceph: make ceph_s...
989
  		struct ceph_buffer *blob;
355da1eb7   Sage Weil   ceph: inode opera...
990

be655596b   Sage Weil   ceph: use i_ceph_...
991
  		spin_unlock(&ci->i_ceph_lock);
355da1eb7   Sage Weil   ceph: inode opera...
992
993
  		dout(" preaallocating new blob size=%d
  ", required_blob_size);
b6c1d5b81   Sage Weil   ceph: simplify ce...
994
  		blob = ceph_buffer_new(required_blob_size, GFP_NOFS);
355da1eb7   Sage Weil   ceph: inode opera...
995
  		if (!blob)
604d1b024   Yan, Zheng   ceph: take snap_r...
996
  			goto do_sync_unlocked;
be655596b   Sage Weil   ceph: use i_ceph_...
997
  		spin_lock(&ci->i_ceph_lock);
b6c1d5b81   Sage Weil   ceph: simplify ce...
998
999
  		if (ci->i_xattrs.prealloc_blob)
  			ceph_buffer_put(ci->i_xattrs.prealloc_blob);
355da1eb7   Sage Weil   ceph: inode opera...
1000
1001
1002
  		ci->i_xattrs.prealloc_blob = blob;
  		goto retry;
  	}
bcdfeb2eb   Yan, Zheng   ceph: remove xatt...
1003
1004
  	err = __set_xattr(ci, newname, name_len, newval, val_len,
  			  flags, value ? 1 : -1, &xattr);
18fa8b3fe   Alex Elder   ceph: make ceph_s...
1005

fbc0b970d   Yan, Zheng   ceph: properly ha...
1006
  	if (!err) {
f66fd9f09   Yan, Zheng   ceph: pre-allocat...
1007
1008
  		dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL,
  					       &prealloc_cf);
fbc0b970d   Yan, Zheng   ceph: properly ha...
1009
  		ci->i_xattrs.dirty = true;
c2050a454   Deepa Dinamani   fs: Replace curre...
1010
  		inode->i_ctime = current_time(inode);
fbc0b970d   Yan, Zheng   ceph: properly ha...
1011
  	}
18fa8b3fe   Alex Elder   ceph: make ceph_s...
1012

be655596b   Sage Weil   ceph: use i_ceph_...
1013
  	spin_unlock(&ci->i_ceph_lock);
604d1b024   Yan, Zheng   ceph: take snap_r...
1014
1015
  	if (lock_snap_rwsem)
  		up_read(&mdsc->snap_rwsem);
fca65b4ad   Sage Weil   ceph: do not call...
1016
1017
  	if (dirty)
  		__mark_inode_dirty(inode, dirty);
f66fd9f09   Yan, Zheng   ceph: pre-allocat...
1018
  	ceph_free_cap_flush(prealloc_cf);
355da1eb7   Sage Weil   ceph: inode opera...
1019
1020
1021
  	return err;
  
  do_sync:
be655596b   Sage Weil   ceph: use i_ceph_...
1022
  	spin_unlock(&ci->i_ceph_lock);
3adf654dd   Sage Weil   ceph: pass unhand...
1023
  do_sync_unlocked:
604d1b024   Yan, Zheng   ceph: take snap_r...
1024
1025
  	if (lock_snap_rwsem)
  		up_read(&mdsc->snap_rwsem);
315f24088   Yan, Zheng   ceph: fix securit...
1026
1027
1028
1029
1030
1031
1032
1033
  
  	/* security module set xattr while filling trace */
  	if (current->journal_info != NULL) {
  		pr_warn_ratelimited("sync setxattr %p "
  				    "during filling trace
  ", inode);
  		err = -EBUSY;
  	} else {
a26feccab   Andreas Gruenbacher   ceph: Get rid of ...
1034
  		err = ceph_sync_setxattr(inode, name, value, size, flags);
315f24088   Yan, Zheng   ceph: fix securit...
1035
  	}
355da1eb7   Sage Weil   ceph: inode opera...
1036
  out:
f66fd9f09   Yan, Zheng   ceph: pre-allocat...
1037
  	ceph_free_cap_flush(prealloc_cf);
355da1eb7   Sage Weil   ceph: inode opera...
1038
1039
1040
1041
1042
  	kfree(newname);
  	kfree(newval);
  	kfree(xattr);
  	return err;
  }
2cdeb1e47   Andreas Gruenbacher   ceph: Switch to g...
1043
1044
1045
  static int ceph_get_xattr_handler(const struct xattr_handler *handler,
  				  struct dentry *dentry, struct inode *inode,
  				  const char *name, void *value, size_t size)
7221fe4c2   Guangliang Zhao   ceph: add acl for...
1046
  {
2cdeb1e47   Andreas Gruenbacher   ceph: Switch to g...
1047
1048
1049
1050
  	if (!ceph_is_valid_xattr(name))
  		return -EOPNOTSUPP;
  	return __ceph_getxattr(inode, name, value, size);
  }
7221fe4c2   Guangliang Zhao   ceph: add acl for...
1051

2cdeb1e47   Andreas Gruenbacher   ceph: Switch to g...
1052
  static int ceph_set_xattr_handler(const struct xattr_handler *handler,
593012268   Al Viro   switch xattr_hand...
1053
1054
1055
  				  struct dentry *unused, struct inode *inode,
  				  const char *name, const void *value,
  				  size_t size, int flags)
2cdeb1e47   Andreas Gruenbacher   ceph: Switch to g...
1056
1057
1058
  {
  	if (!ceph_is_valid_xattr(name))
  		return -EOPNOTSUPP;
593012268   Al Viro   switch xattr_hand...
1059
  	return __ceph_setxattr(inode, name, value, size, flags);
7221fe4c2   Guangliang Zhao   ceph: add acl for...
1060
  }
315f24088   Yan, Zheng   ceph: fix securit...
1061

5130ccea7   Wei Yongjun   ceph: fix non sta...
1062
  static const struct xattr_handler ceph_other_xattr_handler = {
2cdeb1e47   Andreas Gruenbacher   ceph: Switch to g...
1063
1064
1065
1066
  	.prefix = "",  /* match any name => handlers called with full name */
  	.get = ceph_get_xattr_handler,
  	.set = ceph_set_xattr_handler,
  };
315f24088   Yan, Zheng   ceph: fix securit...
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
  #ifdef CONFIG_SECURITY
  bool ceph_security_xattr_wanted(struct inode *in)
  {
  	return in->i_security != NULL;
  }
  
  bool ceph_security_xattr_deadlock(struct inode *in)
  {
  	struct ceph_inode_info *ci;
  	bool ret;
  	if (in->i_security == NULL)
  		return false;
  	ci = ceph_inode(in);
  	spin_lock(&ci->i_ceph_lock);
  	ret = !(ci->i_ceph_flags & CEPH_I_SEC_INITED) &&
  	      !(ci->i_xattrs.version > 0 &&
  		__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0));
  	spin_unlock(&ci->i_ceph_lock);
  	return ret;
  }
  #endif