Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * (C) 2001 Clemson University and The University of Chicago
  3 *
  4 * See COPYING in top-level directory.
  5 */
  6
  7/*
  8 *  Linux VFS extended attribute operations.
  9 */
 10
 11#include "protocol.h"
 12#include "orangefs-kernel.h"
 13#include "orangefs-bufmap.h"
 14#include <linux/posix_acl_xattr.h>
 15#include <linux/xattr.h>
 16
 17
 18#define SYSTEM_ORANGEFS_KEY "system.pvfs2."
 19#define SYSTEM_ORANGEFS_KEY_LEN 13
 20
 21/*
 22 * this function returns
 23 *   0 if the key corresponding to name is not meant to be printed as part
 24 *     of a listxattr.
 25 *   1 if the key corresponding to name is meant to be returned as part of
 26 *     a listxattr.
 27 * The ones that start SYSTEM_ORANGEFS_KEY are the ones to avoid printing.
 28 */
 29static int is_reserved_key(const char *key, size_t size)
 30{
 31
 32	if (size < SYSTEM_ORANGEFS_KEY_LEN)
 33		return 1;
 34
 35	return strncmp(key, SYSTEM_ORANGEFS_KEY, SYSTEM_ORANGEFS_KEY_LEN) ?  1 : 0;
 36}
 37
 38static inline int convert_to_internal_xattr_flags(int setxattr_flags)
 39{
 40	int internal_flag = 0;
 41
 42	if (setxattr_flags & XATTR_REPLACE) {
 43		/* Attribute must exist! */
 44		internal_flag = ORANGEFS_XATTR_REPLACE;
 45	} else if (setxattr_flags & XATTR_CREATE) {
 46		/* Attribute must not exist */
 47		internal_flag = ORANGEFS_XATTR_CREATE;
 48	}
 49	return internal_flag;
 50}
 51
 52
 53/*
 54 * Tries to get a specified key's attributes of a given
 55 * file into a user-specified buffer. Note that the getxattr
 56 * interface allows for the users to probe the size of an
 57 * extended attribute by passing in a value of 0 to size.
 58 * Thus our return value is always the size of the attribute
 59 * unless the key does not exist for the file and/or if
 60 * there were errors in fetching the attribute value.
 61 */
 62ssize_t orangefs_inode_getxattr(struct inode *inode, const char *prefix,
 63		const char *name, void *buffer, size_t size)
 64{
 65	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
 66	struct orangefs_kernel_op_s *new_op = NULL;
 67	ssize_t ret = -ENOMEM;
 68	ssize_t length = 0;
 69	int fsuid;
 70	int fsgid;
 71
 72	gossip_debug(GOSSIP_XATTR_DEBUG,
 73		     "%s: prefix %s name %s, buffer_size %zd\n",
 74		     __func__, prefix, name, size);
 75
 76	if ((strlen(name) + strlen(prefix)) >= ORANGEFS_MAX_XATTR_NAMELEN) {
 77		gossip_err("Invalid key length (%d)\n",
 78			   (int)(strlen(name) + strlen(prefix)));
 79		return -EINVAL;
 80	}
 81
 82	fsuid = from_kuid(current_user_ns(), current_fsuid());
 83	fsgid = from_kgid(current_user_ns(), current_fsgid());
 84
 85	gossip_debug(GOSSIP_XATTR_DEBUG,
 86		     "getxattr on inode %pU, name %s "
 87		     "(uid %o, gid %o)\n",
 88		     get_khandle_from_ino(inode),
 89		     name,
 90		     fsuid,
 91		     fsgid);
 92
 93	down_read(&orangefs_inode->xattr_sem);
 94
 95	new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR);
 96	if (!new_op)
 97		goto out_unlock;
 98
 99	new_op->upcall.req.getxattr.refn = orangefs_inode->refn;
100	ret = snprintf((char *)new_op->upcall.req.getxattr.key,
101		       ORANGEFS_MAX_XATTR_NAMELEN, "%s%s", prefix, name);
102
103	/*
104	 * NOTE: Although keys are meant to be NULL terminated textual
105	 * strings, I am going to explicitly pass the length just in case
106	 * we change this later on...
107	 */
108	new_op->upcall.req.getxattr.key_sz = ret + 1;
109
110	ret = service_operation(new_op, "orangefs_inode_getxattr",
111				get_interruptible_flag(inode));
112	if (ret != 0) {
113		if (ret == -ENOENT) {
114			ret = -ENODATA;
115			gossip_debug(GOSSIP_XATTR_DEBUG,
116				     "orangefs_inode_getxattr: inode %pU key %s"
117				     " does not exist!\n",
118				     get_khandle_from_ino(inode),
119				     (char *)new_op->upcall.req.getxattr.key);
120		}
121		goto out_release_op;
122	}
123
124	/*
125	 * Length returned includes null terminator.
126	 */
127	length = new_op->downcall.resp.getxattr.val_sz;
128
129	/*
130	 * Just return the length of the queried attribute.
131	 */
132	if (size == 0) {
133		ret = length;
134		goto out_release_op;
135	}
136
137	/*
138	 * Check to see if key length is > provided buffer size.
139	 */
140	if (length > size) {
141		ret = -ERANGE;
142		goto out_release_op;
143	}
144
145	memcpy(buffer, new_op->downcall.resp.getxattr.val, length);
146	memset(buffer + length, 0, size - length);
147	gossip_debug(GOSSIP_XATTR_DEBUG,
148	     "orangefs_inode_getxattr: inode %pU "
149	     "key %s key_sz %d, val_len %d\n",
150	     get_khandle_from_ino(inode),
151	     (char *)new_op->
152		upcall.req.getxattr.key,
153		     (int)new_op->
154		upcall.req.getxattr.key_sz,
155	     (int)ret);
156
157	ret = length;
158
159out_release_op:
160	op_release(new_op);
161out_unlock:
162	up_read(&orangefs_inode->xattr_sem);
163	return ret;
164}
165
166static int orangefs_inode_removexattr(struct inode *inode,
167			    const char *prefix,
168			    const char *name,
169			    int flags)
170{
171	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
172	struct orangefs_kernel_op_s *new_op = NULL;
173	int ret = -ENOMEM;
174
175	down_write(&orangefs_inode->xattr_sem);
176	new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR);
177	if (!new_op)
178		goto out_unlock;
179
180	new_op->upcall.req.removexattr.refn = orangefs_inode->refn;
181	/*
182	 * NOTE: Although keys are meant to be NULL terminated
183	 * textual strings, I am going to explicitly pass the
184	 * length just in case we change this later on...
185	 */
186	ret = snprintf((char *)new_op->upcall.req.removexattr.key,
187		       ORANGEFS_MAX_XATTR_NAMELEN,
188		       "%s%s",
189		       (prefix ? prefix : ""),
190		       name);
191	new_op->upcall.req.removexattr.key_sz = ret + 1;
192
193	gossip_debug(GOSSIP_XATTR_DEBUG,
194		     "orangefs_inode_removexattr: key %s, key_sz %d\n",
195		     (char *)new_op->upcall.req.removexattr.key,
196		     (int)new_op->upcall.req.removexattr.key_sz);
197
198	ret = service_operation(new_op,
199				"orangefs_inode_removexattr",
200				get_interruptible_flag(inode));
201	if (ret == -ENOENT) {
202		/*
203		 * Request to replace a non-existent attribute is an error.
204		 */
205		if (flags & XATTR_REPLACE)
206			ret = -ENODATA;
207		else
208			ret = 0;
209	}
210
211	gossip_debug(GOSSIP_XATTR_DEBUG,
212		     "orangefs_inode_removexattr: returning %d\n", ret);
213
214	op_release(new_op);
215out_unlock:
216	up_write(&orangefs_inode->xattr_sem);
217	return ret;
218}
219
220/*
221 * Tries to set an attribute for a given key on a file.
222 *
223 * Returns a -ve number on error and 0 on success.  Key is text, but value
224 * can be binary!
225 */
226int orangefs_inode_setxattr(struct inode *inode, const char *prefix,
227		const char *name, const void *value, size_t size, int flags)
228{
229	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
230	struct orangefs_kernel_op_s *new_op;
231	int internal_flag = 0;
232	int ret = -ENOMEM;
233
234	gossip_debug(GOSSIP_XATTR_DEBUG,
235		     "%s: prefix %s, name %s, buffer_size %zd\n",
236		     __func__, prefix, name, size);
237
238	if (size >= ORANGEFS_MAX_XATTR_VALUELEN ||
239	    flags < 0) {
240		gossip_err("orangefs_inode_setxattr: bogus values of size(%d), flags(%d)\n",
241			   (int)size,
242			   flags);
243		return -EINVAL;
244	}
245
246	internal_flag = convert_to_internal_xattr_flags(flags);
247
248	if (prefix) {
249		if (strlen(name) + strlen(prefix) >= ORANGEFS_MAX_XATTR_NAMELEN) {
250			gossip_err
251			    ("orangefs_inode_setxattr: bogus key size (%d)\n",
252			     (int)(strlen(name) + strlen(prefix)));
253			return -EINVAL;
254		}
255	} else {
256		if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) {
257			gossip_err
258			    ("orangefs_inode_setxattr: bogus key size (%d)\n",
259			     (int)(strlen(name)));
260			return -EINVAL;
261		}
262	}
263
264	/* This is equivalent to a removexattr */
265	if (size == 0 && value == NULL) {
266		gossip_debug(GOSSIP_XATTR_DEBUG,
267			     "removing xattr (%s%s)\n",
268			     prefix,
269			     name);
270		return orangefs_inode_removexattr(inode, prefix, name, flags);
271	}
272
273	gossip_debug(GOSSIP_XATTR_DEBUG,
274		     "setxattr on inode %pU, name %s\n",
275		     get_khandle_from_ino(inode),
276		     name);
277
278	down_write(&orangefs_inode->xattr_sem);
279	new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR);
280	if (!new_op)
281		goto out_unlock;
282
283
284	new_op->upcall.req.setxattr.refn = orangefs_inode->refn;
285	new_op->upcall.req.setxattr.flags = internal_flag;
286	/*
287	 * NOTE: Although keys are meant to be NULL terminated textual
288	 * strings, I am going to explicitly pass the length just in
289	 * case we change this later on...
290	 */
291	ret = snprintf((char *)new_op->upcall.req.setxattr.keyval.key,
292		       ORANGEFS_MAX_XATTR_NAMELEN,
293		       "%s%s",
294		       prefix, name);
295	new_op->upcall.req.setxattr.keyval.key_sz = ret + 1;
296	memcpy(new_op->upcall.req.setxattr.keyval.val, value, size);
297	new_op->upcall.req.setxattr.keyval.val_sz = size;
298
299	gossip_debug(GOSSIP_XATTR_DEBUG,
300		     "orangefs_inode_setxattr: key %s, key_sz %d "
301		     " value size %zd\n",
302		     (char *)new_op->upcall.req.setxattr.keyval.key,
303		     (int)new_op->upcall.req.setxattr.keyval.key_sz,
304		     size);
305
306	ret = service_operation(new_op,
307				"orangefs_inode_setxattr",
308				get_interruptible_flag(inode));
309
310	gossip_debug(GOSSIP_XATTR_DEBUG,
311		     "orangefs_inode_setxattr: returning %d\n",
312		     ret);
313
314	/* when request is serviced properly, free req op struct */
315	op_release(new_op);
316out_unlock:
317	up_write(&orangefs_inode->xattr_sem);
318	return ret;
319}
320
321/*
322 * Tries to get a specified object's keys into a user-specified buffer of a
323 * given size.  Note that like the previous instances of xattr routines, this
324 * also allows you to pass in a NULL pointer and 0 size to probe the size for
325 * subsequent memory allocations. Thus our return value is always the size of
326 * all the keys unless there were errors in fetching the keys!
327 */
328ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size)
329{
330	struct inode *inode = dentry->d_inode;
331	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
332	struct orangefs_kernel_op_s *new_op;
333	__u64 token = ORANGEFS_ITERATE_START;
334	ssize_t ret = -ENOMEM;
335	ssize_t total = 0;
336	int count_keys = 0;
337	int key_size;
338	int i = 0;
339	int returned_count = 0;
340
341	if (size > 0 && buffer == NULL) {
342		gossip_err("%s: bogus NULL pointers\n", __func__);
343		return -EINVAL;
344	}
345
346	down_read(&orangefs_inode->xattr_sem);
347	new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR);
348	if (!new_op)
349		goto out_unlock;
350
351	if (buffer && size > 0)
352		memset(buffer, 0, size);
353
354try_again:
355	key_size = 0;
356	new_op->upcall.req.listxattr.refn = orangefs_inode->refn;
357	new_op->upcall.req.listxattr.token = token;
358	new_op->upcall.req.listxattr.requested_count =
359	    (size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN;
360	ret = service_operation(new_op, __func__,
361				get_interruptible_flag(inode));
362	if (ret != 0)
363		goto done;
364
365	if (size == 0) {
366		/*
367		 * This is a bit of a big upper limit, but I did not want to
368		 * spend too much time getting this correct, since users end
369		 * up allocating memory rather than us...
370		 */
371		total = new_op->downcall.resp.listxattr.returned_count *
372			ORANGEFS_MAX_XATTR_NAMELEN;
373		goto done;
374	}
375
376	returned_count = new_op->downcall.resp.listxattr.returned_count;
377	if (returned_count < 0 ||
378	    returned_count >= ORANGEFS_MAX_XATTR_LISTLEN) {
379		gossip_err("%s: impossible value for returned_count:%d:\n",
380		__func__,
381		returned_count);
382		ret = -EIO;
383		goto done;
384	}
385
386	/*
387	 * Check to see how much can be fit in the buffer. Fit only whole keys.
388	 */
389	for (i = 0; i < returned_count; i++) {
390		if (new_op->downcall.resp.listxattr.lengths[i] < 0 ||
391		    new_op->downcall.resp.listxattr.lengths[i] >
392		    ORANGEFS_MAX_XATTR_NAMELEN) {
393			gossip_err("%s: impossible value for lengths[%d]\n",
394			    __func__,
395			    new_op->downcall.resp.listxattr.lengths[i]);
396			ret = -EIO;
397			goto done;
398		}
399		if (total + new_op->downcall.resp.listxattr.lengths[i] > size)
400			goto done;
401
402		/*
403		 * Since many dumb programs try to setxattr() on our reserved
404		 * xattrs this is a feeble attempt at defeating those by not
405		 * listing them in the output of listxattr.. sigh
406		 */
407		if (is_reserved_key(new_op->downcall.resp.listxattr.key +
408				    key_size,
409				    new_op->downcall.resp.
410					listxattr.lengths[i])) {
411			gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n",
412					i, new_op->downcall.resp.listxattr.key +
413						key_size);
414			memcpy(buffer + total,
415				new_op->downcall.resp.listxattr.key + key_size,
416				new_op->downcall.resp.listxattr.lengths[i]);
417			total += new_op->downcall.resp.listxattr.lengths[i];
418			count_keys++;
419		} else {
420			gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n",
421					i, new_op->downcall.resp.listxattr.key +
422						key_size);
423		}
424		key_size += new_op->downcall.resp.listxattr.lengths[i];
425	}
426
427	/*
428	 * Since the buffer was large enough, we might have to continue
429	 * fetching more keys!
430	 */
431	token = new_op->downcall.resp.listxattr.token;
432	if (token != ORANGEFS_ITERATE_END)
433		goto try_again;
434
435done:
436	gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d"
437		     " [size of buffer %ld] (filled in %d keys)\n",
438		     __func__,
439		     ret ? (int)ret : (int)total,
440		     (long)size,
441		     count_keys);
442	op_release(new_op);
443	if (ret == 0)
444		ret = total;
445out_unlock:
446	up_read(&orangefs_inode->xattr_sem);
447	return ret;
448}
449
450static int orangefs_xattr_set_default(const struct xattr_handler *handler,
451				      struct dentry *dentry,
452				      const char *name,
453				      const void *buffer,
454				      size_t size,
455				      int flags)
456{
457	return orangefs_inode_setxattr(dentry->d_inode,
458				    ORANGEFS_XATTR_NAME_DEFAULT_PREFIX,
459				    name,
460				    buffer,
461				    size,
462				    flags);
463}
464
465static int orangefs_xattr_get_default(const struct xattr_handler *handler,
466				      struct dentry *dentry,
467				      const char *name,
468				      void *buffer,
469				      size_t size)
470{
471	return orangefs_inode_getxattr(dentry->d_inode,
472				    ORANGEFS_XATTR_NAME_DEFAULT_PREFIX,
473				    name,
474				    buffer,
475				    size);
476
477}
478
479static int orangefs_xattr_set_trusted(const struct xattr_handler *handler,
480				     struct dentry *dentry,
481				     const char *name,
482				     const void *buffer,
483				     size_t size,
484				     int flags)
485{
486	return orangefs_inode_setxattr(dentry->d_inode,
487				    ORANGEFS_XATTR_NAME_TRUSTED_PREFIX,
488				    name,
489				    buffer,
490				    size,
491				    flags);
492}
493
494static int orangefs_xattr_get_trusted(const struct xattr_handler *handler,
495				      struct dentry *dentry,
496				      const char *name,
497				      void *buffer,
498				      size_t size)
499{
500	return orangefs_inode_getxattr(dentry->d_inode,
501				    ORANGEFS_XATTR_NAME_TRUSTED_PREFIX,
502				    name,
503				    buffer,
504				    size);
505}
506
507static struct xattr_handler orangefs_xattr_trusted_handler = {
508	.prefix = ORANGEFS_XATTR_NAME_TRUSTED_PREFIX,
509	.get = orangefs_xattr_get_trusted,
510	.set = orangefs_xattr_set_trusted,
511};
512
513static struct xattr_handler orangefs_xattr_default_handler = {
514	/*
515	 * NOTE: this is set to be the empty string.
516	 * so that all un-prefixed xattrs keys get caught
517	 * here!
518	 */
519	.prefix = ORANGEFS_XATTR_NAME_DEFAULT_PREFIX,
520	.get = orangefs_xattr_get_default,
521	.set = orangefs_xattr_set_default,
522};
523
524const struct xattr_handler *orangefs_xattr_handlers[] = {
525	&posix_acl_access_xattr_handler,
526	&posix_acl_default_xattr_handler,
527	&orangefs_xattr_trusted_handler,
528	&orangefs_xattr_default_handler,
529	NULL
530};