Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
super.c
Go to the documentation of this file.
1 /*
2  * linux/fs/hfsplus/super.c
3  *
4  * Copyright (C) 2001
5  * Brad Boyer ([email protected])
6  * (C) 2003 Ardis Technologies <[email protected]>
7  *
8  */
9 
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/pagemap.h>
13 #include <linux/blkdev.h>
14 #include <linux/fs.h>
15 #include <linux/slab.h>
16 #include <linux/vfs.h>
17 #include <linux/nls.h>
18 
19 static struct inode *hfsplus_alloc_inode(struct super_block *sb);
20 static void hfsplus_destroy_inode(struct inode *inode);
21 
22 #include "hfsplus_fs.h"
23 
24 static int hfsplus_system_read_inode(struct inode *inode)
25 {
26  struct hfsplus_vh *vhdr = HFSPLUS_SB(inode->i_sb)->s_vhdr;
27 
28  switch (inode->i_ino) {
29  case HFSPLUS_EXT_CNID:
30  hfsplus_inode_read_fork(inode, &vhdr->ext_file);
31  inode->i_mapping->a_ops = &hfsplus_btree_aops;
32  break;
33  case HFSPLUS_CAT_CNID:
34  hfsplus_inode_read_fork(inode, &vhdr->cat_file);
35  inode->i_mapping->a_ops = &hfsplus_btree_aops;
36  break;
37  case HFSPLUS_ALLOC_CNID:
38  hfsplus_inode_read_fork(inode, &vhdr->alloc_file);
39  inode->i_mapping->a_ops = &hfsplus_aops;
40  break;
41  case HFSPLUS_START_CNID:
42  hfsplus_inode_read_fork(inode, &vhdr->start_file);
43  break;
44  case HFSPLUS_ATTR_CNID:
45  hfsplus_inode_read_fork(inode, &vhdr->attr_file);
46  inode->i_mapping->a_ops = &hfsplus_btree_aops;
47  break;
48  default:
49  return -EIO;
50  }
51 
52  return 0;
53 }
54 
55 struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
56 {
57  struct hfs_find_data fd;
58  struct inode *inode;
59  int err;
60 
61  inode = iget_locked(sb, ino);
62  if (!inode)
63  return ERR_PTR(-ENOMEM);
64  if (!(inode->i_state & I_NEW))
65  return inode;
66 
67  INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
68  mutex_init(&HFSPLUS_I(inode)->extents_lock);
69  HFSPLUS_I(inode)->flags = 0;
70  HFSPLUS_I(inode)->extent_state = 0;
71  HFSPLUS_I(inode)->rsrc_inode = NULL;
72  atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
73 
74  if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
75  inode->i_ino == HFSPLUS_ROOT_CNID) {
76  err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
77  if (!err) {
78  err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
79  if (!err)
80  err = hfsplus_cat_read_inode(inode, &fd);
81  hfs_find_exit(&fd);
82  }
83  } else {
84  err = hfsplus_system_read_inode(inode);
85  }
86 
87  if (err) {
88  iget_failed(inode);
89  return ERR_PTR(err);
90  }
91 
92  unlock_new_inode(inode);
93  return inode;
94 }
95 
96 static int hfsplus_system_write_inode(struct inode *inode)
97 {
98  struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
99  struct hfsplus_vh *vhdr = sbi->s_vhdr;
100  struct hfsplus_fork_raw *fork;
101  struct hfs_btree *tree = NULL;
102 
103  switch (inode->i_ino) {
104  case HFSPLUS_EXT_CNID:
105  fork = &vhdr->ext_file;
106  tree = sbi->ext_tree;
107  break;
108  case HFSPLUS_CAT_CNID:
109  fork = &vhdr->cat_file;
110  tree = sbi->cat_tree;
111  break;
112  case HFSPLUS_ALLOC_CNID:
113  fork = &vhdr->alloc_file;
114  break;
115  case HFSPLUS_START_CNID:
116  fork = &vhdr->start_file;
117  break;
118  case HFSPLUS_ATTR_CNID:
119  fork = &vhdr->attr_file;
120  tree = sbi->attr_tree;
121  default:
122  return -EIO;
123  }
124 
125  if (fork->total_size != cpu_to_be64(inode->i_size)) {
128  }
129  hfsplus_inode_write_fork(inode, fork);
130  if (tree)
131  hfs_btree_write(tree);
132  return 0;
133 }
134 
135 static int hfsplus_write_inode(struct inode *inode,
136  struct writeback_control *wbc)
137 {
138  int err;
139 
140  dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
141 
142  err = hfsplus_ext_write_extent(inode);
143  if (err)
144  return err;
145 
146  if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
147  inode->i_ino == HFSPLUS_ROOT_CNID)
148  return hfsplus_cat_write_inode(inode);
149  else
150  return hfsplus_system_write_inode(inode);
151 }
152 
153 static void hfsplus_evict_inode(struct inode *inode)
154 {
155  dprint(DBG_INODE, "hfsplus_evict_inode: %lu\n", inode->i_ino);
156  truncate_inode_pages(&inode->i_data, 0);
157  clear_inode(inode);
158  if (HFSPLUS_IS_RSRC(inode)) {
159  HFSPLUS_I(HFSPLUS_I(inode)->rsrc_inode)->rsrc_inode = NULL;
160  iput(HFSPLUS_I(inode)->rsrc_inode);
161  }
162 }
163 
164 static int hfsplus_sync_fs(struct super_block *sb, int wait)
165 {
166  struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
167  struct hfsplus_vh *vhdr = sbi->s_vhdr;
168  int write_backup = 0;
169  int error, error2;
170 
171  if (!wait)
172  return 0;
173 
174  dprint(DBG_SUPER, "hfsplus_sync_fs\n");
175 
176  /*
177  * Explicitly write out the special metadata inodes.
178  *
179  * While these special inodes are marked as hashed and written
180  * out peridocically by the flusher threads we redirty them
181  * during writeout of normal inodes, and thus the life lock
182  * prevents us from getting the latest state to disk.
183  */
184  error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
185  error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
186  if (!error)
187  error = error2;
188  error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
189  if (!error)
190  error = error2;
191 
192  mutex_lock(&sbi->vh_mutex);
193  mutex_lock(&sbi->alloc_mutex);
194  vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
195  vhdr->next_cnid = cpu_to_be32(sbi->next_cnid);
196  vhdr->folder_count = cpu_to_be32(sbi->folder_count);
197  vhdr->file_count = cpu_to_be32(sbi->file_count);
198 
200  memcpy(sbi->s_backup_vhdr, sbi->s_vhdr, sizeof(*sbi->s_vhdr));
201  write_backup = 1;
202  }
203 
204  error2 = hfsplus_submit_bio(sb,
206  sbi->s_vhdr_buf, NULL, WRITE_SYNC);
207  if (!error)
208  error = error2;
209  if (!write_backup)
210  goto out;
211 
212  error2 = hfsplus_submit_bio(sb,
213  sbi->part_start + sbi->sect_count - 2,
215  if (!error)
216  error2 = error;
217 out:
218  mutex_unlock(&sbi->alloc_mutex);
219  mutex_unlock(&sbi->vh_mutex);
220 
221  if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
223 
224  return error;
225 }
226 
227 static void delayed_sync_fs(struct work_struct *work)
228 {
229  struct hfsplus_sb_info *sbi;
230 
231  sbi = container_of(work, struct hfsplus_sb_info, sync_work.work);
232 
233  spin_lock(&sbi->work_lock);
234  sbi->work_queued = 0;
235  spin_unlock(&sbi->work_lock);
236 
237  hfsplus_sync_fs(sbi->alloc_file->i_sb, 1);
238 }
239 
241 {
242  struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
243  unsigned long delay;
244 
245  if (sb->s_flags & MS_RDONLY)
246  return;
247 
248  spin_lock(&sbi->work_lock);
249  if (!sbi->work_queued) {
252  sbi->work_queued = 1;
253  }
254  spin_unlock(&sbi->work_lock);
255 }
256 
257 static void hfsplus_put_super(struct super_block *sb)
258 {
259  struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
260 
261  dprint(DBG_SUPER, "hfsplus_put_super\n");
262 
264 
265  if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
266  struct hfsplus_vh *vhdr = sbi->s_vhdr;
267 
268  vhdr->modify_date = hfsp_now2mt();
271 
272  hfsplus_sync_fs(sb, 1);
273  }
274 
277  iput(sbi->alloc_file);
278  iput(sbi->hidden_dir);
279  kfree(sbi->s_vhdr_buf);
280  kfree(sbi->s_backup_vhdr_buf);
281  unload_nls(sbi->nls);
282  kfree(sb->s_fs_info);
283  sb->s_fs_info = NULL;
284 }
285 
286 static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
287 {
288  struct super_block *sb = dentry->d_sb;
289  struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
290  u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
291 
293  buf->f_bsize = sb->s_blocksize;
294  buf->f_blocks = sbi->total_blocks << sbi->fs_shift;
295  buf->f_bfree = sbi->free_blocks << sbi->fs_shift;
296  buf->f_bavail = buf->f_bfree;
297  buf->f_files = 0xFFFFFFFF;
298  buf->f_ffree = 0xFFFFFFFF - sbi->next_cnid;
299  buf->f_fsid.val[0] = (u32)id;
300  buf->f_fsid.val[1] = (u32)(id >> 32);
302 
303  return 0;
304 }
305 
306 static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
307 {
308  if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
309  return 0;
310  if (!(*flags & MS_RDONLY)) {
311  struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr;
312  int force = 0;
313 
314  if (!hfsplus_parse_options_remount(data, &force))
315  return -EINVAL;
316 
317  if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
318  printk(KERN_WARNING "hfs: filesystem was "
319  "not cleanly unmounted, "
320  "running fsck.hfsplus is recommended. "
321  "leaving read-only.\n");
322  sb->s_flags |= MS_RDONLY;
323  *flags |= MS_RDONLY;
324  } else if (force) {
325  /* nothing */
326  } else if (vhdr->attributes &
328  printk(KERN_WARNING "hfs: filesystem is marked locked, "
329  "leaving read-only.\n");
330  sb->s_flags |= MS_RDONLY;
331  *flags |= MS_RDONLY;
332  } else if (vhdr->attributes &
334  printk(KERN_WARNING "hfs: filesystem is "
335  "marked journaled, "
336  "leaving read-only.\n");
337  sb->s_flags |= MS_RDONLY;
338  *flags |= MS_RDONLY;
339  }
340  }
341  return 0;
342 }
343 
344 static const struct super_operations hfsplus_sops = {
345  .alloc_inode = hfsplus_alloc_inode,
346  .destroy_inode = hfsplus_destroy_inode,
347  .write_inode = hfsplus_write_inode,
348  .evict_inode = hfsplus_evict_inode,
349  .put_super = hfsplus_put_super,
350  .sync_fs = hfsplus_sync_fs,
351  .statfs = hfsplus_statfs,
352  .remount_fs = hfsplus_remount,
353  .show_options = hfsplus_show_options,
354 };
355 
356 static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
357 {
358  struct hfsplus_vh *vhdr;
359  struct hfsplus_sb_info *sbi;
360  hfsplus_cat_entry entry;
361  struct hfs_find_data fd;
362  struct inode *root, *inode;
363  struct qstr str;
364  struct nls_table *nls = NULL;
365  u64 last_fs_block, last_fs_page;
366  int err;
367 
368  err = -ENOMEM;
369  sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
370  if (!sbi)
371  goto out;
372 
373  sb->s_fs_info = sbi;
374  mutex_init(&sbi->alloc_mutex);
375  mutex_init(&sbi->vh_mutex);
376  spin_lock_init(&sbi->work_lock);
377  INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs);
379 
380  err = -EINVAL;
381  if (!hfsplus_parse_options(data, sbi)) {
382  printk(KERN_ERR "hfs: unable to parse mount options\n");
383  goto out_unload_nls;
384  }
385 
386  /* temporarily use utf8 to correctly find the hidden dir below */
387  nls = sbi->nls;
388  sbi->nls = load_nls("utf8");
389  if (!sbi->nls) {
390  printk(KERN_ERR "hfs: unable to load nls for utf8\n");
391  goto out_unload_nls;
392  }
393 
394  /* Grab the volume header */
395  if (hfsplus_read_wrapper(sb)) {
396  if (!silent)
397  printk(KERN_WARNING "hfs: unable to find HFS+ superblock\n");
398  goto out_unload_nls;
399  }
400  vhdr = sbi->s_vhdr;
401 
402  /* Copy parts of the volume header into the superblock */
404  if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION ||
406  printk(KERN_ERR "hfs: wrong filesystem version\n");
407  goto out_free_vhdr;
408  }
409  sbi->total_blocks = be32_to_cpu(vhdr->total_blocks);
410  sbi->free_blocks = be32_to_cpu(vhdr->free_blocks);
411  sbi->next_cnid = be32_to_cpu(vhdr->next_cnid);
412  sbi->file_count = be32_to_cpu(vhdr->file_count);
413  sbi->folder_count = be32_to_cpu(vhdr->folder_count);
414  sbi->data_clump_blocks =
416  if (!sbi->data_clump_blocks)
417  sbi->data_clump_blocks = 1;
418  sbi->rsrc_clump_blocks =
420  if (!sbi->rsrc_clump_blocks)
421  sbi->rsrc_clump_blocks = 1;
422 
423  err = -EFBIG;
424  last_fs_block = sbi->total_blocks - 1;
425  last_fs_page = (last_fs_block << sbi->alloc_blksz_shift) >>
427 
428  if ((last_fs_block > (sector_t)(~0ULL) >> (sbi->alloc_blksz_shift - 9)) ||
429  (last_fs_page > (pgoff_t)(~0ULL))) {
430  printk(KERN_ERR "hfs: filesystem size too large.\n");
431  goto out_free_vhdr;
432  }
433 
434  /* Set up operations so we can load metadata */
435  sb->s_op = &hfsplus_sops;
436  sb->s_maxbytes = MAX_LFS_FILESIZE;
437 
438  if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
439  printk(KERN_WARNING "hfs: Filesystem was "
440  "not cleanly unmounted, "
441  "running fsck.hfsplus is recommended. "
442  "mounting read-only.\n");
443  sb->s_flags |= MS_RDONLY;
444  } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) {
445  /* nothing */
446  } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
447  printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n");
448  sb->s_flags |= MS_RDONLY;
449  } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) &&
450  !(sb->s_flags & MS_RDONLY)) {
451  printk(KERN_WARNING "hfs: write access to "
452  "a journaled filesystem is not supported, "
453  "use the force option at your own risk, "
454  "mounting read-only.\n");
455  sb->s_flags |= MS_RDONLY;
456  }
457 
458  err = -EINVAL;
459 
460  /* Load metadata objects (B*Trees) */
462  if (!sbi->ext_tree) {
463  printk(KERN_ERR "hfs: failed to load extents file\n");
464  goto out_free_vhdr;
465  }
467  if (!sbi->cat_tree) {
468  printk(KERN_ERR "hfs: failed to load catalog file\n");
469  goto out_close_ext_tree;
470  }
471 
472  inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID);
473  if (IS_ERR(inode)) {
474  printk(KERN_ERR "hfs: failed to load allocation file\n");
475  err = PTR_ERR(inode);
476  goto out_close_cat_tree;
477  }
478  sbi->alloc_file = inode;
479 
480  /* Load the root directory */
481  root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID);
482  if (IS_ERR(root)) {
483  printk(KERN_ERR "hfs: failed to load root directory\n");
484  err = PTR_ERR(root);
485  goto out_put_alloc_file;
486  }
487 
489  sb->s_root = d_make_root(root);
490  if (!sb->s_root) {
491  err = -ENOMEM;
492  goto out_put_alloc_file;
493  }
494 
495  str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
496  str.name = HFSP_HIDDENDIR_NAME;
497  err = hfs_find_init(sbi->cat_tree, &fd);
498  if (err)
499  goto out_put_root;
500  hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
501  if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
502  hfs_find_exit(&fd);
503  if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
504  goto out_put_root;
505  inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
506  if (IS_ERR(inode)) {
507  err = PTR_ERR(inode);
508  goto out_put_root;
509  }
510  sbi->hidden_dir = inode;
511  } else
512  hfs_find_exit(&fd);
513 
514  if (!(sb->s_flags & MS_RDONLY)) {
515  /*
516  * H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused
517  * all three are registered with Apple for our use
518  */
520  vhdr->modify_date = hfsp_now2mt();
521  be32_add_cpu(&vhdr->write_count, 1);
524  hfsplus_sync_fs(sb, 1);
525 
526  if (!sbi->hidden_dir) {
527  mutex_lock(&sbi->vh_mutex);
529  if (!sbi->hidden_dir) {
530  mutex_unlock(&sbi->vh_mutex);
531  err = -ENOMEM;
532  goto out_put_root;
533  }
534  err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root,
535  &str, sbi->hidden_dir);
536  mutex_unlock(&sbi->vh_mutex);
537  if (err)
538  goto out_put_hidden_dir;
539 
540  hfsplus_mark_inode_dirty(sbi->hidden_dir,
542  }
543  }
544 
545  unload_nls(sbi->nls);
546  sbi->nls = nls;
547  return 0;
548 
549 out_put_hidden_dir:
550  iput(sbi->hidden_dir);
551 out_put_root:
552  dput(sb->s_root);
553  sb->s_root = NULL;
554 out_put_alloc_file:
555  iput(sbi->alloc_file);
556 out_close_cat_tree:
558 out_close_ext_tree:
560 out_free_vhdr:
561  kfree(sbi->s_vhdr_buf);
562  kfree(sbi->s_backup_vhdr_buf);
563 out_unload_nls:
564  unload_nls(sbi->nls);
565  unload_nls(nls);
566  kfree(sbi);
567 out:
568  return err;
569 }
570 
571 MODULE_AUTHOR("Brad Boyer");
572 MODULE_DESCRIPTION("Extended Macintosh Filesystem");
573 MODULE_LICENSE("GPL");
574 
575 static struct kmem_cache *hfsplus_inode_cachep;
576 
577 static struct inode *hfsplus_alloc_inode(struct super_block *sb)
578 {
579  struct hfsplus_inode_info *i;
580 
581  i = kmem_cache_alloc(hfsplus_inode_cachep, GFP_KERNEL);
582  return i ? &i->vfs_inode : NULL;
583 }
584 
585 static void hfsplus_i_callback(struct rcu_head *head)
586 {
587  struct inode *inode = container_of(head, struct inode, i_rcu);
588 
589  kmem_cache_free(hfsplus_inode_cachep, HFSPLUS_I(inode));
590 }
591 
592 static void hfsplus_destroy_inode(struct inode *inode)
593 {
594  call_rcu(&inode->i_rcu, hfsplus_i_callback);
595 }
596 
597 #define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info)
598 
599 static struct dentry *hfsplus_mount(struct file_system_type *fs_type,
600  int flags, const char *dev_name, void *data)
601 {
602  return mount_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super);
603 }
604 
605 static struct file_system_type hfsplus_fs_type = {
606  .owner = THIS_MODULE,
607  .name = "hfsplus",
608  .mount = hfsplus_mount,
609  .kill_sb = kill_block_super,
610  .fs_flags = FS_REQUIRES_DEV,
611 };
612 
613 static void hfsplus_init_once(void *p)
614 {
615  struct hfsplus_inode_info *i = p;
616 
618 }
619 
620 static int __init init_hfsplus_fs(void)
621 {
622  int err;
623 
624  hfsplus_inode_cachep = kmem_cache_create("hfsplus_icache",
626  hfsplus_init_once);
627  if (!hfsplus_inode_cachep)
628  return -ENOMEM;
629  err = register_filesystem(&hfsplus_fs_type);
630  if (err)
631  kmem_cache_destroy(hfsplus_inode_cachep);
632  return err;
633 }
634 
635 static void __exit exit_hfsplus_fs(void)
636 {
637  unregister_filesystem(&hfsplus_fs_type);
638 
639  /*
640  * Make sure all delayed rcu free inodes are flushed before we
641  * destroy cache.
642  */
643  rcu_barrier();
644  kmem_cache_destroy(hfsplus_inode_cachep);
645 }
646 
647 module_init(init_hfsplus_fs)
648 module_exit(exit_hfsplus_fs)