linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Andrew Morton <akpm@linux-foundation.org>
To: slava@dubeyko.com
Cc: Linux FS devel list <linux-fsdevel@vger.kernel.org>,
	Al Viro <viro@zeniv.linux.org.uk>,
	Christoph Hellwig <hch@infradead.org>,
	Hin-Tak Leung <htl10@users.sourceforge.net>
Subject: Re: [PATCH 3/3] hfsplus: implement attributes file creation functionality
Date: Wed, 25 Sep 2013 16:02:15 -0700	[thread overview]
Message-ID: <20130925160215.014aec22c63d6bce2d270ac8@linux-foundation.org> (raw)
In-Reply-To: <1379671462.2280.29.camel@slavad-ubuntu>

On Fri, 20 Sep 2013 14:04:22 +0400 Vyacheslav Dubeyko <slava@dubeyko.com> wrote:

> From: Vyacheslav Dubeyko <slava@dubeyko.com>
> Subject: [PATCH 3/3] hfsplus: implement attributes file creation functionality
> 
> This patch implements functionality of creation AttributesFile
> metadata file on HFS+ volume in the case of absence of it.
> 
> It makes trying to open AttributesFile's B-tree during mount of
> HFS+ volume. If HFS+ volume hasn't AttributesFile then a pointer
> on AttributesFile's B-tree keeps as NULL. Thereby, when it is
> discovered absence of AttributesFile on HFS+ volume in the begin
> of xattr creation operation then AttributesFile will be created.
> 
> The creation of AttributesFile will have success in the case of
> availability (2 * clump) free blocks on HFS+ volume. Otherwise,
> creation operation is ended with error (-ENOSPC).
> 
> ...
>
> --- a/fs/hfsplus/hfsplus_fs.h
> +++ b/fs/hfsplus/hfsplus_fs.h
> @@ -127,6 +127,14 @@ struct hfs_bnode {
>  #define HFS_BNODE_DELETED	4
>  
>  /*
> + * Attributes file states
> + */
> +#define HFSPLUS_EMPTY_ATTR_TREE		0
> +#define HFSPLUS_CREATING_ATTR_TREE	1
> +#define HFSPLUS_VALID_ATTR_TREE		2
> +#define HFSPLUS_FAILED_ATTR_TREE	3
> +
> +/*
>   * HFS+ superblock info (built from Volume Header on disk)
>   */
>  
> @@ -141,6 +149,7 @@ struct hfsplus_sb_info {
>  	struct hfs_btree *ext_tree;
>  	struct hfs_btree *cat_tree;
>  	struct hfs_btree *attr_tree;
> +	atomic_t attr_tree_state;
>  	struct inode *alloc_file;
>  	struct inode *hidden_dir;
>  	struct nls_table *nls;
> diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
> index 4c4d142..80875aa 100644
> --- a/fs/hfsplus/super.c
> +++ b/fs/hfsplus/super.c
> @@ -474,12 +474,14 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
>  		pr_err("failed to load catalog file\n");
>  		goto out_close_ext_tree;
>  	}
> +	atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE);
>  	if (vhdr->attr_file.total_blocks != 0) {
>  		sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID);
>  		if (!sbi->attr_tree) {
>  			pr_err("failed to load attributes file\n");
>  			goto out_close_cat_tree;
>  		}
> +		atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE);
>  	}
>  	sb->s_xattr = hfsplus_xattr_handlers;
>  
> diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c
> index 31f70f5..c3d829c 100644
> --- a/fs/hfsplus/xattr.c
> +++ b/fs/hfsplus/xattr.c
> @@ -190,6 +190,129 @@ static void hfsplus_init_header_node(struct inode *attr_file,
>  	SETOFFSET(buf, node_size, offset, 4);
>  }
>  
> +static int hfsplus_create_attributes_file(struct super_block *sb)
> +{
> +	int err = 0;
> +	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
> +	struct inode *attr_file;
> +	struct hfsplus_inode_info *hip;
> +	u32 clump_size;
> +	u16 node_size = HFSPLUS_ATTR_TREE_NODE_SIZE;
> +	char *buf;
> +	int index, written;
> +	struct address_space *mapping;
> +	struct page *page;
> +	int old_state = HFSPLUS_EMPTY_ATTR_TREE;
> +
> +	hfs_dbg(ATTR_MOD, "create_attr_file: ino %d\n", HFSPLUS_ATTR_CNID);
> +
> +check_attr_tree_state_again:
> +	switch (atomic_read(&sbi->attr_tree_state)) {
> +	case HFSPLUS_EMPTY_ATTR_TREE:
> +		if (old_state != atomic_cmpxchg(&sbi->attr_tree_state,
> +						old_state,
> +						HFSPLUS_CREATING_ATTR_TREE))
> +			goto check_attr_tree_state_again;
> +		break;
> +	case HFSPLUS_CREATING_ATTR_TREE:
> +		schedule_timeout_uninterruptible(HZ);

Use of msleep(1000) would be preferred.

Also, what on earth is this delay doing in the middle of filesystem
code??  It should either be removed in favour of a proper fix, or very
clearly explained in code comments.  Simply sticking it in there
unexplained will not fly!

> +		goto check_attr_tree_state_again;
> +		break;

The `break' is obviously unreachable and I suggest simply removing it.

> +	case HFSPLUS_VALID_ATTR_TREE:
> +		return 0;
> +	case HFSPLUS_FAILED_ATTR_TREE:
> +		return -EOPNOTSUPP;
> +	default:
> +		BUG();
> +	}
> +
> +	attr_file = hfsplus_iget(sb, HFSPLUS_ATTR_CNID);
> +	if (IS_ERR(attr_file)) {
> +		pr_err("failed to load attributes file\n");
> +		return PTR_ERR(attr_file);
> +	}
> +
> +	BUG_ON(i_size_read(attr_file) != 0);
> +
> +	hip = HFSPLUS_I(attr_file);
> +
> +	clump_size = hfsplus_calc_btree_clump_size(sb->s_blocksize,
> +						    node_size,
> +						    sbi->sect_count,
> +						    HFSPLUS_ATTR_CNID);
> +
> +	mutex_lock(&hip->extents_lock);
> +	hip->clump_blocks = clump_size >> sbi->alloc_blksz_shift;
> +	mutex_unlock(&hip->extents_lock);
> +
> +	if (sbi->free_blocks <= (hip->clump_blocks << 1)) {
> +		err = -ENOSPC;
> +		goto end_attr_file_creation;
> +	}
> +
> +	while (hip->alloc_blocks < hip->clump_blocks) {
> +		err = hfsplus_file_extend(attr_file);
> +		if (unlikely(err)) {
> +			pr_err("failed to extend attributes file\n");
> +			goto end_attr_file_creation;
> +		}
> +		hip->phys_size = attr_file->i_size =
> +			(loff_t)hip->alloc_blocks << sbi->alloc_blksz_shift;
> +		hip->fs_blocks = hip->alloc_blocks << sbi->fs_shift;
> +		inode_set_bytes(attr_file, attr_file->i_size);
> +	}
> +
> +	buf = kzalloc(node_size, GFP_NOFS);
> +	if (!buf) {
> +		pr_err("failed to allocate memory for header node\n");
> +		err = -ENOMEM;
> +		goto end_attr_file_creation;
> +	}
> +
> +	hfsplus_init_header_node(attr_file, clump_size, buf, node_size);
> +
> +	mapping = attr_file->i_mapping;
> +
> +	index = 0;
> +	written = 0;
> +	for (; written < node_size; index++, written += PAGE_CACHE_SIZE) {
> +		void *kaddr;
> +
> +		page = read_mapping_page(mapping, index, NULL);
> +		if (IS_ERR(page))
> +			goto failed_header_node_init;

Forgot to set `err' here, which looks to me like a bug.

> +		kaddr = kmap_atomic(page);
> +		memcpy(kaddr, buf + written,
> +			min_t(size_t, PAGE_CACHE_SIZE, node_size - written));
> +		kunmap_atomic(kaddr);
> +
> +		set_page_dirty(page);
> +		page_cache_release(page);
> +	}
> +
> +	hfsplus_mark_inode_dirty(attr_file, HFSPLUS_I_ATTR_DIRTY);
> +
> +	sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID);
> +	if (!sbi->attr_tree)
> +		pr_err("failed to load attributes file\n");
> +
> +failed_header_node_init:
> +	kfree(buf);
> +
> +end_attr_file_creation:
> +	iput(attr_file);
> +
> +	if (!err)
> +		atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE);
> +	else if (err == -ENOSPC)
> +		atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE);
> +	else
> +		atomic_set(&sbi->attr_tree_state, HFSPLUS_FAILED_ATTR_TREE);
> +
> +	return err;
> +}
> +
>  int __hfsplus_setxattr(struct inode *inode, const char *name,
>  			const void *value, size_t size, int flags)
>  {
> @@ -274,8 +397,9 @@ int __hfsplus_setxattr(struct inode *inode, const char *name,
>  	}
>  
>  	if (!HFSPLUS_SB(inode->i_sb)->attr_tree) {
> -		err = -EOPNOTSUPP;
> -		goto end_setxattr;
> +		err = hfsplus_create_attributes_file(inode->i_sb);
> +		if (unlikely(err))
> +			goto end_setxattr;
>  	}
>  
>  	if (hfsplus_attr_exists(inode, name)) {


  parent reply	other threads:[~2013-09-25 23:02 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-09-20 10:04 [PATCH 3/3] hfsplus: implement attributes file creation functionality Vyacheslav Dubeyko
2013-09-20 22:30 ` Hin-Tak Leung
2013-09-23  6:33   ` Vyacheslav Dubeyko
2013-09-25 23:02 ` Andrew Morton [this message]
  -- strict thread matches above, loose matches on Subject: below --
2013-09-24 11:40 Hin-Tak Leung
2013-09-24 12:04 ` Vyacheslav Dubeyko

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=20130925160215.014aec22c63d6bce2d270ac8@linux-foundation.org \
    --to=akpm@linux-foundation.org \
    --cc=hch@infradead.org \
    --cc=htl10@users.sourceforge.net \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=slava@dubeyko.com \
    --cc=viro@zeniv.linux.org.uk \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).