aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfsplus/xattr.c
diff options
context:
space:
mode:
authorVyacheslav Dubeyko <slava@dubeyko.com>2013-11-12 18:11:09 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-12 22:09:32 -0500
commit95e0d7dbb9b28ab0dfad7c7316066b05e1f1d4cd (patch)
tree09f42df8169a4fbf3e2f60cb1b36c1e83c8d9019 /fs/hfsplus/xattr.c
parent099e9245e04d50bb12ed621b4fa61df0a4c9dba9 (diff)
hfsplus: implement attributes file creation functionality
Implement 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). Signed-off-by: Vyacheslav Dubeyko <slava@dubeyko.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Christoph Hellwig <hch@infradead.org> Acked-by: Hin-Tak Leung <htl10@users.sourceforge.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/hfsplus/xattr.c')
-rw-r--r--fs/hfsplus/xattr.c142
1 files changed, 140 insertions, 2 deletions
diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c
index 568a45cb1145..efc85b1377cc 100644
--- a/fs/hfsplus/xattr.c
+++ b/fs/hfsplus/xattr.c
@@ -192,6 +192,143 @@ static void hfsplus_init_header_node(struct inode *attr_file,
192 *--rec_offsets = cpu_to_be16(offset); 192 *--rec_offsets = cpu_to_be16(offset);
193} 193}
194 194
195static int hfsplus_create_attributes_file(struct super_block *sb)
196{
197 int err = 0;
198 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
199 struct inode *attr_file;
200 struct hfsplus_inode_info *hip;
201 u32 clump_size;
202 u16 node_size = HFSPLUS_ATTR_TREE_NODE_SIZE;
203 char *buf;
204 int index, written;
205 struct address_space *mapping;
206 struct page *page;
207 int old_state = HFSPLUS_EMPTY_ATTR_TREE;
208
209 hfs_dbg(ATTR_MOD, "create_attr_file: ino %d\n", HFSPLUS_ATTR_CNID);
210
211check_attr_tree_state_again:
212 switch (atomic_read(&sbi->attr_tree_state)) {
213 case HFSPLUS_EMPTY_ATTR_TREE:
214 if (old_state != atomic_cmpxchg(&sbi->attr_tree_state,
215 old_state,
216 HFSPLUS_CREATING_ATTR_TREE))
217 goto check_attr_tree_state_again;
218 break;
219 case HFSPLUS_CREATING_ATTR_TREE:
220 /*
221 * This state means that another thread is in process
222 * of AttributesFile creation. Theoretically, it is
223 * possible to be here. But really __setxattr() method
224 * first of all calls hfs_find_init() for lookup in
225 * B-tree of CatalogFile. This method locks mutex of
226 * CatalogFile's B-tree. As a result, if some thread
227 * is inside AttributedFile creation operation then
228 * another threads will be waiting unlocking of
229 * CatalogFile's B-tree's mutex. However, if code will
230 * change then we will return error code (-EAGAIN) from
231 * here. Really, it means that first try to set of xattr
232 * fails with error but second attempt will have success.
233 */
234 return -EAGAIN;
235 case HFSPLUS_VALID_ATTR_TREE:
236 return 0;
237 case HFSPLUS_FAILED_ATTR_TREE:
238 return -EOPNOTSUPP;
239 default:
240 BUG();
241 }
242
243 attr_file = hfsplus_iget(sb, HFSPLUS_ATTR_CNID);
244 if (IS_ERR(attr_file)) {
245 pr_err("failed to load attributes file\n");
246 return PTR_ERR(attr_file);
247 }
248
249 BUG_ON(i_size_read(attr_file) != 0);
250
251 hip = HFSPLUS_I(attr_file);
252
253 clump_size = hfsplus_calc_btree_clump_size(sb->s_blocksize,
254 node_size,
255 sbi->sect_count,
256 HFSPLUS_ATTR_CNID);
257
258 mutex_lock(&hip->extents_lock);
259 hip->clump_blocks = clump_size >> sbi->alloc_blksz_shift;
260 mutex_unlock(&hip->extents_lock);
261
262 if (sbi->free_blocks <= (hip->clump_blocks << 1)) {
263 err = -ENOSPC;
264 goto end_attr_file_creation;
265 }
266
267 while (hip->alloc_blocks < hip->clump_blocks) {
268 err = hfsplus_file_extend(attr_file);
269 if (unlikely(err)) {
270 pr_err("failed to extend attributes file\n");
271 goto end_attr_file_creation;
272 }
273 hip->phys_size = attr_file->i_size =
274 (loff_t)hip->alloc_blocks << sbi->alloc_blksz_shift;
275 hip->fs_blocks = hip->alloc_blocks << sbi->fs_shift;
276 inode_set_bytes(attr_file, attr_file->i_size);
277 }
278
279 buf = kzalloc(node_size, GFP_NOFS);
280 if (!buf) {
281 pr_err("failed to allocate memory for header node\n");
282 err = -ENOMEM;
283 goto end_attr_file_creation;
284 }
285
286 hfsplus_init_header_node(attr_file, clump_size, buf, node_size);
287
288 mapping = attr_file->i_mapping;
289
290 index = 0;
291 written = 0;
292 for (; written < node_size; index++, written += PAGE_CACHE_SIZE) {
293 void *kaddr;
294
295 page = read_mapping_page(mapping, index, NULL);
296 if (IS_ERR(page)) {
297 err = PTR_ERR(page);
298 goto failed_header_node_init;
299 }
300
301 kaddr = kmap_atomic(page);
302 memcpy(kaddr, buf + written,
303 min_t(size_t, PAGE_CACHE_SIZE, node_size - written));
304 kunmap_atomic(kaddr);
305
306 set_page_dirty(page);
307 page_cache_release(page);
308 }
309
310 hfsplus_mark_inode_dirty(attr_file, HFSPLUS_I_ATTR_DIRTY);
311
312 sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID);
313 if (!sbi->attr_tree)
314 pr_err("failed to load attributes file\n");
315
316failed_header_node_init:
317 kfree(buf);
318
319end_attr_file_creation:
320 iput(attr_file);
321
322 if (!err)
323 atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE);
324 else if (err == -ENOSPC)
325 atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE);
326 else
327 atomic_set(&sbi->attr_tree_state, HFSPLUS_FAILED_ATTR_TREE);
328
329 return err;
330}
331
195int __hfsplus_setxattr(struct inode *inode, const char *name, 332int __hfsplus_setxattr(struct inode *inode, const char *name,
196 const void *value, size_t size, int flags) 333 const void *value, size_t size, int flags)
197{ 334{
@@ -276,8 +413,9 @@ int __hfsplus_setxattr(struct inode *inode, const char *name,
276 } 413 }
277 414
278 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) { 415 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) {
279 err = -EOPNOTSUPP; 416 err = hfsplus_create_attributes_file(inode->i_sb);
280 goto end_setxattr; 417 if (unlikely(err))
418 goto end_setxattr;
281 } 419 }
282 420
283 if (hfsplus_attr_exists(inode, name)) { 421 if (hfsplus_attr_exists(inode, name)) {