All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Morton <akpm@linux-foundation.org>
To: Chris Mason <chris.mason@oracle.com>
Cc: torvalds@linux-foundation.org, linux-fsdevel@vger.kernel.org
Subject: Re: [PATCH 01/35] Btrfs xattr code
Date: Mon, 12 Jan 2009 20:59:04 -0800	[thread overview]
Message-ID: <20090112205904.c9e11d85.akpm@linux-foundation.org> (raw)
In-Reply-To: <1231387045-27838-2-git-send-email-chris.mason@oracle.com>

On Wed,  7 Jan 2009 22:56:51 -0500 Chris Mason <chris.mason@oracle.com> wrote:

> Xattrs in btrfs are stored in the btree close to the inode item.  They use an
> indexing scheme very similar to directories.
> 
> The max size of a btrfs xattr is limited by the size of a btree item,
> or about 4k.  A future version will support larger items.
> 
>
> ...
>
> +ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
> +				void *buffer, size_t size)
> +{
> +	struct btrfs_dir_item *di;
> +	struct btrfs_root *root = BTRFS_I(inode)->root;
> +	struct btrfs_path *path;
> +	struct extent_buffer *leaf;
> +	int ret = 0;
> +	unsigned long data_ptr;
> +
> +	path = btrfs_alloc_path();
> +	if (!path)
> +		return -ENOMEM;
> +
> +	/* lookup the xattr by name */
> +	di = btrfs_lookup_xattr(NULL, root, path, inode->i_ino, name,
> +				strlen(name), 0);
> +	if (!di || IS_ERR(di)) {

This seems quite bad.  An error return from btrfs_lookup_xattr() can
arise from (I assume) OOM, corrupted filesystem, I/O error, etc.

Yet here we treat such errors as being the same as "not found".  This
seems grossly misleading to userspace and possible a security problem?

(I'm kind of guessing here, and might be wrong and wasting everyone's
time, because the semantics of the btrfs_lookup_xattr() and
btrfs_getxattr() return values aren't documented).

> +		ret = -ENODATA;
> +		goto out;
> +	}
> +
> +	leaf = path->nodes[0];
> +	/* if size is 0, that means we want the size of the attr */
> +	if (!size) {
> +		ret = btrfs_dir_data_len(leaf, di);
> +		goto out;
> +	}
> +
> +	/* now get the data out of our dir_item */
> +	if (btrfs_dir_data_len(leaf, di) > size) {

OK, where did we hide the btrfs_dir_data_len() definition?

> +		ret = -ERANGE;
> +		goto out;
> +	}
> +	data_ptr = (unsigned long)((char *)(di + 1) +
> +				   btrfs_dir_name_len(leaf, di));
> +	read_extent_buffer(leaf, buffer, data_ptr,
> +			   btrfs_dir_data_len(leaf, di));

Please document read_extent_buffer().

Please rename read_extent_buffer() to something more appropriate to a
kernel-wide symbol.

<spies map_private_extent_buffer as well>

Please review all kernel-wide identifiers in btrfs for appropriateness.

I'm scratching my head wondering about this `data_ptr' thing.  Is it a
disk offset?  Is it really a pointer to kernel memory?  According to
this code it is indeed a kernel pointer, but it then gets stuffed into
an unsigned long (wtf?) and then passed to the mysterious
read_extent_buffer().

<reviewer throws in the towel on this part of the code>

> +	ret = btrfs_dir_data_len(leaf, di);
> +
> +out:
> +	btrfs_free_path(path);
> +	return ret;
> +}
> +
> +int __btrfs_setxattr(struct inode *inode, const char *name,
> +			    const void *value, size_t size, int flags)
> +{
> +	struct btrfs_dir_item *di;
> +	struct btrfs_root *root = BTRFS_I(inode)->root;
> +	struct btrfs_trans_handle *trans;
> +	struct btrfs_path *path;
> +	int ret = 0, mod = 0;
> +
> +	path = btrfs_alloc_path();
> +	if (!path)
> +		return -ENOMEM;
> +
> +	trans = btrfs_start_transaction(root, 1);
> +	btrfs_set_trans_block_group(trans, inode);
> +
> +	/* first lets see if we already have this xattr */

let's :)

> +	di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name,
> +				strlen(name), -1);

<wonders what the -1 does>

<goes to the btrfs_lookup_xattr() definition site>

<towel goes flying again>

> +	if (IS_ERR(di)) {
> +		ret = PTR_ERR(di);
> +		goto out;
> +	}
> +
> +	/* ok we already have this xattr, lets remove it */
> +	if (di) {
> +		/* if we want create only exit */
> +		if (flags & XATTR_CREATE) {
> +			ret = -EEXIST;
> +			goto out;
> +		}
> +
> +		ret = btrfs_delete_one_dir_name(trans, root, path, di);
> +		if (ret)
> +			goto out;
> +		btrfs_release_path(root, path);
> +
> +		/* if we don't have a value then we are removing the xattr */
> +		if (!value) {
> +			mod = 1;
> +			goto out;
> +		}
> +	} else {
> +		btrfs_release_path(root, path);
> +
> +		if (flags & XATTR_REPLACE) {
> +			/* we couldn't find the attr to replace */
> +			ret = -ENODATA;
> +			goto out;
> +		}
> +	}
> +
> +	/* ok we have to create a completely new xattr */
> +	ret = btrfs_insert_xattr_item(trans, root, name, strlen(name),
> +				      value, size, inode->i_ino);
> +	if (ret)
> +		goto out;
> +	mod = 1;
> +
> +out:
> +	if (mod) {
> +		inode->i_ctime = CURRENT_TIME;
> +		ret = btrfs_update_inode(trans, root, inode);
> +	}
> +
> +	btrfs_end_transaction(trans, root);
> +	btrfs_free_path(path);
> +	return ret;
> +}
> +
> +ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
> +{
> +	struct btrfs_key key, found_key;
> +	struct inode *inode = dentry->d_inode;
> +	struct btrfs_root *root = BTRFS_I(inode)->root;
> +	struct btrfs_path *path;
> +	struct btrfs_item *item;
> +	struct extent_buffer *leaf;
> +	struct btrfs_dir_item *di;
> +	int ret = 0, slot, advance;
> +	size_t total_size = 0, size_left = size;
> +	unsigned long name_ptr;
> +	size_t name_len;
> +	u32 nritems;
> +
> +	/*
> +	 * ok we want all objects associated with this id.
> +	 * NOTE: we set key.offset = 0; because we want to start with the
> +	 * first xattr that we find and walk forward
> +	 */
> +	key.objectid = inode->i_ino;
> +	btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
> +	key.offset = 0;
> +
> +	path = btrfs_alloc_path();
> +	if (!path)
> +		return -ENOMEM;
> +	path->reada = 2;

<gets interested in btrfs_path.reada>

<greps for a while>

It's snowing towels in here!

	path->reada = 2;

gack!

<greps some more>

	int direction = path->reada;

	...

		if (direction < 0) {
			if (nr == 0)
				break;
			nr--;
		} else if (direction > 0) {
			nr++;
			if (nr >= nritems)
				break;
		}

<delicately moves on...>

> +	/* search for our xattrs */
> +	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
> +	if (ret < 0)
> +		goto err;
> +	ret = 0;

this statement isn't needed.

> +	advance = 0;
> +	while (1) {
> +		leaf = path->nodes[0];
> +		nritems = btrfs_header_nritems(leaf);
> +		slot = path->slots[0];
> +
> +		/* this is where we start walking through the path */
> +		if (advance || slot >= nritems) {
> +			/*
> +			 * if we've reached the last slot in this leaf we need
> +			 * to go to the next leaf and reset everything
> +			 */
> +			if (slot >= nritems-1) {
> +				ret = btrfs_next_leaf(root, path);
> +				if (ret)
> +					break;
> +				leaf = path->nodes[0];
> +				nritems = btrfs_header_nritems(leaf);
> +				slot = path->slots[0];
> +			} else {
> +				/*
> +				 * just walking through the slots on this leaf
> +				 */
> +				slot++;
> +				path->slots[0]++;
> +			}
> +		}
> +		advance = 1;
> +
> +		item = btrfs_item_nr(leaf, slot);
> +		btrfs_item_key_to_cpu(leaf, &found_key, slot);
> +
> +		/* check to make sure this item is what we want */
> +		if (found_key.objectid != key.objectid)
> +			break;
> +		if (btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY)
> +			break;
> +
> +		di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
> +
> +		name_len = btrfs_dir_name_len(leaf, di);
> +		total_size += name_len + 1;
> +
> +		/* we are just looking for how big our buffer needs to be */
> +		if (!size)
> +			continue;
> +
> +		if (!buffer || (name_len + 1) > size_left) {
> +			ret = -ERANGE;
> +			goto err;
> +		}
> +
> +		name_ptr = (unsigned long)(di + 1);
> +		read_extent_buffer(leaf, buffer, name_ptr, name_len);
> +		buffer[name_len] = '\0';
> +
> +		size_left -= name_len + 1;
> +		buffer += name_len + 1;
> +	}
> +	ret = total_size;
> +
> +err:
> +	btrfs_free_path(path);
> +
> +	return ret;
> +}
>
> ...
>


  reply	other threads:[~2009-01-13  4:59 UTC|newest]

Thread overview: 58+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-08  3:56 [PATCH 00/35] Btrfs for review Chris Mason
2009-01-08  3:56 ` [PATCH 01/35] Btrfs xattr code Chris Mason
2009-01-13  4:59   ` Andrew Morton [this message]
2009-01-13 12:56     ` Josef Bacik
2009-01-13 14:37     ` Chris Mason
2009-01-08  3:56 ` [PATCH 02/35] Btrfs multi-device code Chris Mason
2009-01-13  6:23   ` Andrew Morton
2009-01-13 16:36     ` Chris Mason
2009-01-13 17:52       ` Andrew Morton
2009-01-13 17:58         ` Chris Mason
2009-01-30 15:09     ` Andy Whitcroft
2009-01-08  3:56 ` [PATCH 03/35] Btrfs tree logging (fsync optimizations) Chris Mason
2009-01-08  3:56 ` [PATCH 04/35] Btrfs transaction code Chris Mason
2009-01-08  3:56 ` [PATCH 05/35] Btrfs btree leaf reference cache Chris Mason
2009-01-08  3:56 ` [PATCH 06/35] Btrfs tree printk debugging Chris Mason
2009-01-08  3:56 ` [PATCH 07/35] Btrfs ordered data processing Chris Mason
2009-01-08  3:56 ` [PATCH 08/35] Btrfs btree locking helpers Chris Mason
2009-01-08  3:56 ` [PATCH 09/35] Btrfs zlib helpers Chris Mason
2009-01-08  3:57 ` [PATCH 10/35] Btrfs online btree defragging Chris Mason
2009-01-08  3:57 ` [PATCH 11/35] Btrfs sysfs routines Chris Mason
2009-01-08  3:57 ` [PATCH 12/35] Btrfs super operations Chris Mason
2009-01-08  3:57 ` [PATCH 13/35] Btrfs metadata access routines Chris Mason
2009-01-08  3:57 ` [PATCH 14/35] Btrfs tree of tree roots code Chris Mason
2009-01-08  3:57 ` [PATCH 15/35] Btrfs Orphan prevention Chris Mason
2009-01-08  3:57 ` [PATCH 16/35] Btrfs free inode allocation Chris Mason
2009-01-08  3:57 ` [PATCH 17/35] Btrfs inode item routines Chris Mason
2009-01-08  3:57 ` [PATCH 19/35] Btrfs directory name hashing Chris Mason
2009-01-08  3:57 ` [PATCH 20/35] Btrfs free space caching Chris Mason
2009-01-08  3:57 ` [PATCH 21/35] Btrfs file-item and checksumming routines Chris Mason
2009-01-08  3:57 ` [PATCH 22/35] Btrfs file write routines Chris Mason
2009-01-08  3:57 ` [PATCH 24/35] Btrfs directory item routines Chris Mason
2009-01-08  3:57 ` [PATCH 25/35] Btrfs main metadata header file Chris Mason
2009-01-08  3:57 ` [PATCH 27/35] Btrfs in-memory inode.h Chris Mason
2009-01-08  3:57 ` [PATCH 28/35] Btrfs acl implementation Chris Mason
2009-01-08  3:57 ` [PATCH 29/35] Btrfs ioctl code Chris Mason
2009-01-15 18:29   ` Ryusuke Konishi
2009-01-15 20:17     ` Linus Torvalds
2009-01-15 20:28       ` Chris Mason
2009-01-15 20:44         ` Linus Torvalds
2009-01-15 20:49           ` Chris Mason
2009-01-16 17:23       ` Chris Mason
2009-01-17  4:16         ` Ryusuke Konishi
2009-01-08  3:57 ` [PATCH 30/35] Btrfs extent_map: per-file extent lookup cache Chris Mason
2009-01-08  3:57 ` [PATCH 32/35] Btrfs NFS exporting routines Chris Mason
2009-01-08  3:57 ` [PATCH 33/35] Btrfs metadata disk-io routines Chris Mason
2009-01-08  3:57 ` [PATCH 34/35] Btrfs compression routines Chris Mason
2009-01-08  3:57 ` [PATCH 35/35] Async thread routines Chris Mason
2009-01-08 16:01 ` [PATCH 18.1/35] Btrfs inode operations Chris Mason
2009-01-08 16:04 ` [PATCH 18.2/35] Btrfs inode extent_io hooks Chris Mason
2009-01-08 16:06 ` [PATCH 23.1/35] Btrfs extent allocation code Chris Mason
2009-01-08 16:07 ` [PATCH 23.2/35] Btrfs snapshot deletion Chris Mason
2009-01-08 16:08 ` [PATCH 23.3/35] Btrfs extent relocation Chris Mason
2009-01-08 16:10 ` [PATCH 26.1/35] Btrfs btree core Chris Mason
2009-01-08 16:11 ` [PATCH 26.2/35] Btrfs btree item routines Chris Mason
2009-01-08 16:12 ` [PATCH 31.1/35] Btrfs extent io operations Chris Mason
2009-01-08 16:13 ` [PATCH 31.2/35] Btrfs extent_buffer code Chris Mason
2009-01-09  2:28 ` [PATCH 00/35] Btrfs for review Andi Kleen
2009-01-09 21:13   ` Chris Mason

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090112205904.c9e11d85.akpm@linux-foundation.org \
    --to=akpm@linux-foundation.org \
    --cc=chris.mason@oracle.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.