Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
inode.c
Go to the documentation of this file.
1 /*
2  * linux/fs/hfsplus/inode.c
3  *
4  * Copyright (C) 2001
5  * Brad Boyer ([email protected])
6  * (C) 2003 Ardis Technologies <[email protected]>
7  *
8  * Inode handling routines
9  */
10 
11 #include <linux/blkdev.h>
12 #include <linux/mm.h>
13 #include <linux/fs.h>
14 #include <linux/pagemap.h>
15 #include <linux/mpage.h>
16 #include <linux/sched.h>
17 
18 #include "hfsplus_fs.h"
19 #include "hfsplus_raw.h"
20 
21 static int hfsplus_readpage(struct file *file, struct page *page)
22 {
24 }
25 
26 static int hfsplus_writepage(struct page *page, struct writeback_control *wbc)
27 {
28  return block_write_full_page(page, hfsplus_get_block, wbc);
29 }
30 
31 static int hfsplus_write_begin(struct file *file, struct address_space *mapping,
32  loff_t pos, unsigned len, unsigned flags,
33  struct page **pagep, void **fsdata)
34 {
35  int ret;
36 
37  *pagep = NULL;
38  ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
40  &HFSPLUS_I(mapping->host)->phys_size);
41  if (unlikely(ret)) {
42  loff_t isize = mapping->host->i_size;
43  if (pos + len > isize)
44  vmtruncate(mapping->host, isize);
45  }
46 
47  return ret;
48 }
49 
50 static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block)
51 {
52  return generic_block_bmap(mapping, block, hfsplus_get_block);
53 }
54 
55 static int hfsplus_releasepage(struct page *page, gfp_t mask)
56 {
57  struct inode *inode = page->mapping->host;
58  struct super_block *sb = inode->i_sb;
59  struct hfs_btree *tree;
60  struct hfs_bnode *node;
61  u32 nidx;
62  int i, res = 1;
63 
64  switch (inode->i_ino) {
65  case HFSPLUS_EXT_CNID:
66  tree = HFSPLUS_SB(sb)->ext_tree;
67  break;
68  case HFSPLUS_CAT_CNID:
69  tree = HFSPLUS_SB(sb)->cat_tree;
70  break;
71  case HFSPLUS_ATTR_CNID:
72  tree = HFSPLUS_SB(sb)->attr_tree;
73  break;
74  default:
75  BUG();
76  return 0;
77  }
78  if (!tree)
79  return 0;
80  if (tree->node_size >= PAGE_CACHE_SIZE) {
81  nidx = page->index >>
83  spin_lock(&tree->hash_lock);
84  node = hfs_bnode_findhash(tree, nidx);
85  if (!node)
86  ;
87  else if (atomic_read(&node->refcnt))
88  res = 0;
89  if (res && node) {
90  hfs_bnode_unhash(node);
91  hfs_bnode_free(node);
92  }
93  spin_unlock(&tree->hash_lock);
94  } else {
95  nidx = page->index <<
97  i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
98  spin_lock(&tree->hash_lock);
99  do {
100  node = hfs_bnode_findhash(tree, nidx++);
101  if (!node)
102  continue;
103  if (atomic_read(&node->refcnt)) {
104  res = 0;
105  break;
106  }
107  hfs_bnode_unhash(node);
108  hfs_bnode_free(node);
109  } while (--i && nidx < tree->node_count);
110  spin_unlock(&tree->hash_lock);
111  }
112  return res ? try_to_free_buffers(page) : 0;
113 }
114 
115 static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb,
116  const struct iovec *iov, loff_t offset, unsigned long nr_segs)
117 {
118  struct file *file = iocb->ki_filp;
119  struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
120  ssize_t ret;
121 
122  ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
124 
125  /*
126  * In case of error extending write may have instantiated a few
127  * blocks outside i_size. Trim these off again.
128  */
129  if (unlikely((rw & WRITE) && ret < 0)) {
130  loff_t isize = i_size_read(inode);
131  loff_t end = offset + iov_length(iov, nr_segs);
132 
133  if (end > isize)
134  vmtruncate(inode, isize);
135  }
136 
137  return ret;
138 }
139 
140 static int hfsplus_writepages(struct address_space *mapping,
141  struct writeback_control *wbc)
142 {
143  return mpage_writepages(mapping, wbc, hfsplus_get_block);
144 }
145 
147  .readpage = hfsplus_readpage,
148  .writepage = hfsplus_writepage,
149  .write_begin = hfsplus_write_begin,
150  .write_end = generic_write_end,
151  .bmap = hfsplus_bmap,
152  .releasepage = hfsplus_releasepage,
153 };
154 
156  .readpage = hfsplus_readpage,
157  .writepage = hfsplus_writepage,
158  .write_begin = hfsplus_write_begin,
159  .write_end = generic_write_end,
160  .bmap = hfsplus_bmap,
161  .direct_IO = hfsplus_direct_IO,
162  .writepages = hfsplus_writepages,
163 };
164 
166  .d_hash = hfsplus_hash_dentry,
167  .d_compare = hfsplus_compare_dentry,
168 };
169 
170 static struct dentry *hfsplus_file_lookup(struct inode *dir,
171  struct dentry *dentry, unsigned int flags)
172 {
173  struct hfs_find_data fd;
174  struct super_block *sb = dir->i_sb;
175  struct inode *inode = NULL;
176  struct hfsplus_inode_info *hip;
177  int err;
178 
179  if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc"))
180  goto out;
181 
182  inode = HFSPLUS_I(dir)->rsrc_inode;
183  if (inode)
184  goto out;
185 
186  inode = new_inode(sb);
187  if (!inode)
188  return ERR_PTR(-ENOMEM);
189 
190  hip = HFSPLUS_I(inode);
191  inode->i_ino = dir->i_ino;
192  INIT_LIST_HEAD(&hip->open_dir_list);
193  mutex_init(&hip->extents_lock);
194  hip->extent_state = 0;
195  hip->flags = 0;
196  hip->userflags = 0;
197  set_bit(HFSPLUS_I_RSRC, &hip->flags);
198 
199  err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
200  if (!err) {
201  err = hfsplus_find_cat(sb, dir->i_ino, &fd);
202  if (!err)
203  err = hfsplus_cat_read_inode(inode, &fd);
204  hfs_find_exit(&fd);
205  }
206  if (err) {
207  iput(inode);
208  return ERR_PTR(err);
209  }
210  hip->rsrc_inode = dir;
211  HFSPLUS_I(dir)->rsrc_inode = inode;
212  igrab(dir);
213 
214  /*
215  * __mark_inode_dirty expects inodes to be hashed. Since we don't
216  * want resource fork inodes in the regular inode space, we make them
217  * appear hashed, but do not put on any lists. hlist_del()
218  * will work fine and require no locking.
219  */
220  hlist_add_fake(&inode->i_hash);
221 
222  mark_inode_dirty(inode);
223 out:
224  d_add(dentry, inode);
225  return NULL;
226 }
227 
228 static void hfsplus_get_perms(struct inode *inode,
229  struct hfsplus_perm *perms, int dir)
230 {
231  struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
232  u16 mode;
233 
234  mode = be16_to_cpu(perms->mode);
235 
236  i_uid_write(inode, be32_to_cpu(perms->owner));
237  if (!i_uid_read(inode) && !mode)
238  inode->i_uid = sbi->uid;
239 
240  i_gid_write(inode, be32_to_cpu(perms->group));
241  if (!i_gid_read(inode) && !mode)
242  inode->i_gid = sbi->gid;
243 
244  if (dir) {
245  mode = mode ? (mode & S_IALLUGO) : (S_IRWXUGO & ~(sbi->umask));
246  mode |= S_IFDIR;
247  } else if (!mode)
248  mode = S_IFREG | ((S_IRUGO|S_IWUGO) & ~(sbi->umask));
249  inode->i_mode = mode;
250 
251  HFSPLUS_I(inode)->userflags = perms->userflags;
252  if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE)
253  inode->i_flags |= S_IMMUTABLE;
254  else
255  inode->i_flags &= ~S_IMMUTABLE;
256  if (perms->rootflags & HFSPLUS_FLG_APPEND)
257  inode->i_flags |= S_APPEND;
258  else
259  inode->i_flags &= ~S_APPEND;
260 }
261 
262 static int hfsplus_file_open(struct inode *inode, struct file *file)
263 {
264  if (HFSPLUS_IS_RSRC(inode))
265  inode = HFSPLUS_I(inode)->rsrc_inode;
266  if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
267  return -EOVERFLOW;
268  atomic_inc(&HFSPLUS_I(inode)->opencnt);
269  return 0;
270 }
271 
272 static int hfsplus_file_release(struct inode *inode, struct file *file)
273 {
274  struct super_block *sb = inode->i_sb;
275 
276  if (HFSPLUS_IS_RSRC(inode))
277  inode = HFSPLUS_I(inode)->rsrc_inode;
278  if (atomic_dec_and_test(&HFSPLUS_I(inode)->opencnt)) {
279  mutex_lock(&inode->i_mutex);
280  hfsplus_file_truncate(inode);
281  if (inode->i_flags & S_DEAD) {
282  hfsplus_delete_cat(inode->i_ino,
283  HFSPLUS_SB(sb)->hidden_dir, NULL);
284  hfsplus_delete_inode(inode);
285  }
286  mutex_unlock(&inode->i_mutex);
287  }
288  return 0;
289 }
290 
291 static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
292 {
293  struct inode *inode = dentry->d_inode;
294  int error;
295 
296  error = inode_change_ok(inode, attr);
297  if (error)
298  return error;
299 
300  if ((attr->ia_valid & ATTR_SIZE) &&
301  attr->ia_size != i_size_read(inode)) {
302  inode_dio_wait(inode);
303 
304  error = vmtruncate(inode, attr->ia_size);
305  if (error)
306  return error;
307  }
308 
309  setattr_copy(inode, attr);
310  mark_inode_dirty(inode);
311  return 0;
312 }
313 
314 int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
315  int datasync)
316 {
317  struct inode *inode = file->f_mapping->host;
318  struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
319  struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
320  int error = 0, error2;
321 
322  error = filemap_write_and_wait_range(inode->i_mapping, start, end);
323  if (error)
324  return error;
325  mutex_lock(&inode->i_mutex);
326 
327  /*
328  * Sync inode metadata into the catalog and extent trees.
329  */
330  sync_inode_metadata(inode, 1);
331 
332  /*
333  * And explicitly write out the btrees.
334  */
336  error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
337 
339  error2 =
340  filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
341  if (!error)
342  error = error2;
343  }
344 
346  error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
347  if (!error)
348  error = error2;
349  }
350 
351  if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
352  blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
353 
354  mutex_unlock(&inode->i_mutex);
355 
356  return error;
357 }
358 
359 static const struct inode_operations hfsplus_file_inode_operations = {
360  .lookup = hfsplus_file_lookup,
361  .truncate = hfsplus_file_truncate,
362  .setattr = hfsplus_setattr,
363  .setxattr = hfsplus_setxattr,
364  .getxattr = hfsplus_getxattr,
365  .listxattr = hfsplus_listxattr,
366 };
367 
368 static const struct file_operations hfsplus_file_operations = {
369  .llseek = generic_file_llseek,
370  .read = do_sync_read,
371  .aio_read = generic_file_aio_read,
372  .write = do_sync_write,
373  .aio_write = generic_file_aio_write,
374  .mmap = generic_file_mmap,
375  .splice_read = generic_file_splice_read,
376  .fsync = hfsplus_file_fsync,
377  .open = hfsplus_file_open,
378  .release = hfsplus_file_release,
379  .unlocked_ioctl = hfsplus_ioctl,
380 };
381 
382 struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
383 {
384  struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
385  struct inode *inode = new_inode(sb);
386  struct hfsplus_inode_info *hip;
387 
388  if (!inode)
389  return NULL;
390 
391  inode->i_ino = sbi->next_cnid++;
392  inode->i_mode = mode;
393  inode->i_uid = current_fsuid();
394  inode->i_gid = current_fsgid();
395  set_nlink(inode, 1);
396  inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
397 
398  hip = HFSPLUS_I(inode);
399  INIT_LIST_HEAD(&hip->open_dir_list);
400  mutex_init(&hip->extents_lock);
401  atomic_set(&hip->opencnt, 0);
402  hip->extent_state = 0;
403  hip->flags = 0;
404  hip->userflags = 0;
405  memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
406  memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
407  hip->alloc_blocks = 0;
408  hip->first_blocks = 0;
409  hip->cached_start = 0;
410  hip->cached_blocks = 0;
411  hip->phys_size = 0;
412  hip->fs_blocks = 0;
413  hip->rsrc_inode = NULL;
414  if (S_ISDIR(inode->i_mode)) {
415  inode->i_size = 2;
416  sbi->folder_count++;
418  inode->i_fop = &hfsplus_dir_operations;
419  } else if (S_ISREG(inode->i_mode)) {
420  sbi->file_count++;
421  inode->i_op = &hfsplus_file_inode_operations;
422  inode->i_fop = &hfsplus_file_operations;
423  inode->i_mapping->a_ops = &hfsplus_aops;
424  hip->clump_blocks = sbi->data_clump_blocks;
425  } else if (S_ISLNK(inode->i_mode)) {
426  sbi->file_count++;
428  inode->i_mapping->a_ops = &hfsplus_aops;
429  hip->clump_blocks = 1;
430  } else
431  sbi->file_count++;
432  insert_inode_hash(inode);
433  mark_inode_dirty(inode);
435 
436  return inode;
437 }
438 
439 void hfsplus_delete_inode(struct inode *inode)
440 {
441  struct super_block *sb = inode->i_sb;
442 
443  if (S_ISDIR(inode->i_mode)) {
444  HFSPLUS_SB(sb)->folder_count--;
446  return;
447  }
448  HFSPLUS_SB(sb)->file_count--;
449  if (S_ISREG(inode->i_mode)) {
450  if (!inode->i_nlink) {
451  inode->i_size = 0;
452  hfsplus_file_truncate(inode);
453  }
454  } else if (S_ISLNK(inode->i_mode)) {
455  inode->i_size = 0;
456  hfsplus_file_truncate(inode);
457  }
459 }
460 
461 void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
462 {
463  struct super_block *sb = inode->i_sb;
464  struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
465  struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
466  u32 count;
467  int i;
468 
469  memcpy(&hip->first_extents, &fork->extents, sizeof(hfsplus_extent_rec));
470  for (count = 0, i = 0; i < 8; i++)
471  count += be32_to_cpu(fork->extents[i].block_count);
472  hip->first_blocks = count;
473  memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
474  hip->cached_start = 0;
475  hip->cached_blocks = 0;
476 
477  hip->alloc_blocks = be32_to_cpu(fork->total_blocks);
478  hip->phys_size = inode->i_size = be64_to_cpu(fork->total_size);
479  hip->fs_blocks =
480  (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
481  inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
482  hip->clump_blocks =
484  if (!hip->clump_blocks) {
485  hip->clump_blocks = HFSPLUS_IS_RSRC(inode) ?
486  sbi->rsrc_clump_blocks :
487  sbi->data_clump_blocks;
488  }
489 }
490 
491 void hfsplus_inode_write_fork(struct inode *inode,
492  struct hfsplus_fork_raw *fork)
493 {
494  memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents,
495  sizeof(hfsplus_extent_rec));
496  fork->total_size = cpu_to_be64(inode->i_size);
497  fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode)->alloc_blocks);
498 }
499 
500 int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
501 {
502  hfsplus_cat_entry entry;
503  int res = 0;
504  u16 type;
505 
506  type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
507 
508  HFSPLUS_I(inode)->linkid = 0;
509  if (type == HFSPLUS_FOLDER) {
510  struct hfsplus_cat_folder *folder = &entry.folder;
511 
512  if (fd->entrylength < sizeof(struct hfsplus_cat_folder))
513  /* panic? */;
514  hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
515  sizeof(struct hfsplus_cat_folder));
516  hfsplus_get_perms(inode, &folder->permissions, 1);
517  set_nlink(inode, 1);
518  inode->i_size = 2 + be32_to_cpu(folder->valence);
519  inode->i_atime = hfsp_mt2ut(folder->access_date);
520  inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
521  inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
522  HFSPLUS_I(inode)->create_date = folder->create_date;
523  HFSPLUS_I(inode)->fs_blocks = 0;
525  inode->i_fop = &hfsplus_dir_operations;
526  } else if (type == HFSPLUS_FILE) {
527  struct hfsplus_cat_file *file = &entry.file;
528 
529  if (fd->entrylength < sizeof(struct hfsplus_cat_file))
530  /* panic? */;
531  hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
532  sizeof(struct hfsplus_cat_file));
533 
535  &file->rsrc_fork : &file->data_fork);
536  hfsplus_get_perms(inode, &file->permissions, 0);
537  set_nlink(inode, 1);
538  if (S_ISREG(inode->i_mode)) {
539  if (file->permissions.dev)
540  set_nlink(inode,
541  be32_to_cpu(file->permissions.dev));
542  inode->i_op = &hfsplus_file_inode_operations;
543  inode->i_fop = &hfsplus_file_operations;
544  inode->i_mapping->a_ops = &hfsplus_aops;
545  } else if (S_ISLNK(inode->i_mode)) {
547  inode->i_mapping->a_ops = &hfsplus_aops;
548  } else {
549  init_special_inode(inode, inode->i_mode,
550  be32_to_cpu(file->permissions.dev));
551  }
552  inode->i_atime = hfsp_mt2ut(file->access_date);
553  inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
554  inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date);
555  HFSPLUS_I(inode)->create_date = file->create_date;
556  } else {
557  printk(KERN_ERR "hfs: bad catalog entry used to create inode\n");
558  res = -EIO;
559  }
560  return res;
561 }
562 
563 int hfsplus_cat_write_inode(struct inode *inode)
564 {
565  struct inode *main_inode = inode;
566  struct hfs_find_data fd;
567  hfsplus_cat_entry entry;
568 
569  if (HFSPLUS_IS_RSRC(inode))
570  main_inode = HFSPLUS_I(inode)->rsrc_inode;
571 
572  if (!main_inode->i_nlink)
573  return 0;
574 
575  if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd))
576  /* panic? */
577  return -EIO;
578 
579  if (hfsplus_find_cat(main_inode->i_sb, main_inode->i_ino, &fd))
580  /* panic? */
581  goto out;
582 
583  if (S_ISDIR(main_inode->i_mode)) {
584  struct hfsplus_cat_folder *folder = &entry.folder;
585 
586  if (fd.entrylength < sizeof(struct hfsplus_cat_folder))
587  /* panic? */;
588  hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
589  sizeof(struct hfsplus_cat_folder));
590  /* simple node checks? */
591  hfsplus_cat_set_perms(inode, &folder->permissions);
592  folder->access_date = hfsp_ut2mt(inode->i_atime);
593  folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
594  folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
595  folder->valence = cpu_to_be32(inode->i_size - 2);
596  hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
597  sizeof(struct hfsplus_cat_folder));
598  } else if (HFSPLUS_IS_RSRC(inode)) {
599  struct hfsplus_cat_file *file = &entry.file;
600  hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
601  sizeof(struct hfsplus_cat_file));
602  hfsplus_inode_write_fork(inode, &file->rsrc_fork);
603  hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
604  sizeof(struct hfsplus_cat_file));
605  } else {
606  struct hfsplus_cat_file *file = &entry.file;
607 
608  if (fd.entrylength < sizeof(struct hfsplus_cat_file))
609  /* panic? */;
610  hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
611  sizeof(struct hfsplus_cat_file));
612  hfsplus_inode_write_fork(inode, &file->data_fork);
613  hfsplus_cat_set_perms(inode, &file->permissions);
615  (file->permissions.rootflags |
616  file->permissions.userflags))
618  else
620  file->access_date = hfsp_ut2mt(inode->i_atime);
621  file->content_mod_date = hfsp_ut2mt(inode->i_mtime);
622  file->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
623  hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
624  sizeof(struct hfsplus_cat_file));
625  }
626 
627  set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
628 out:
629  hfs_find_exit(&fd);
630  return 0;
631 }