Merge branch 'btrfs-3.0' into for-linus
authorChris Mason <chris.mason@oracle.com>
Thu, 18 Aug 2011 14:38:03 +0000 (10:38 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 18 Aug 2011 14:38:03 +0000 (10:38 -0400)
1  2 
fs/btrfs/ctree.h
fs/btrfs/file.c
fs/btrfs/ioctl.c

diff --combined fs/btrfs/ctree.h
@@@ -1224,7 -1224,7 +1224,7 @@@ struct btrfs_root 
         * right now this just gets used so that a root has its own devid
         * for stat.  It may be used for more later
         */
 -      struct super_block anon_super;
 +      dev_t anon_dev;
  };
  
  struct btrfs_ioctl_defrag_range_args {
@@@ -1415,17 -1415,15 +1415,15 @@@ void btrfs_set_##name(struct extent_buf
  #define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits)           \
  static inline u##bits btrfs_##name(struct extent_buffer *eb)          \
  {                                                                     \
-       type *p = kmap_atomic(eb->first_page, KM_USER0);                \
+       type *p = page_address(eb->first_page);                         \
        u##bits res = le##bits##_to_cpu(p->member);                     \
-       kunmap_atomic(p, KM_USER0);                                     \
        return res;                                                     \
  }                                                                     \
  static inline void btrfs_set_##name(struct extent_buffer *eb,         \
                                    u##bits val)                        \
  {                                                                     \
-       type *p = kmap_atomic(eb->first_page, KM_USER0);                \
+       type *p = page_address(eb->first_page);                         \
        p->member = cpu_to_le##bits(val);                               \
-       kunmap_atomic(p, KM_USER0);                                     \
  }
  
  #define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits)            \
@@@ -2367,8 -2365,8 +2365,8 @@@ static inline int btrfs_insert_empty_it
  int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
  int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
  int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
int btrfs_drop_snapshot(struct btrfs_root *root,
-                       struct btrfs_block_rsv *block_rsv, int update_ref);
void btrfs_drop_snapshot(struct btrfs_root *root,
+                        struct btrfs_block_rsv *block_rsv, int update_ref);
  int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct extent_buffer *node,
@@@ -2512,9 -2510,6 +2510,9 @@@ int btrfs_csum_truncate(struct btrfs_tr
  int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
                             struct list_head *list, int search_commit);
  /* inode.c */
 +struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
 +                                         size_t pg_offset, u64 start, u64 len,
 +                                         int create);
  
  /* RHEL and EL kernels have a patch that renames PG_checked to FsMisc */
  #if defined(ClearPageFsMisc) && !defined(ClearPageChecked)
@@@ -2612,7 -2607,7 +2610,7 @@@ int btrfs_defrag_file(struct inode *ino
  int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
                           struct inode *inode);
  int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info);
 -int btrfs_sync_file(struct file *file, int datasync);
 +int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
  int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                            int skip_pinned);
  extern const struct file_operations btrfs_file_operations;
@@@ -2652,12 -2647,12 +2650,12 @@@ do {                                                         
  
  /* acl.c */
  #ifdef CONFIG_BTRFS_FS_POSIX_ACL
 -int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags);
 +struct posix_acl *btrfs_get_acl(struct inode *inode, int type);
  int btrfs_init_acl(struct btrfs_trans_handle *trans,
                   struct inode *inode, struct inode *dir);
  int btrfs_acl_chmod(struct inode *inode);
  #else
 -#define btrfs_check_acl NULL
 +#define btrfs_get_acl NULL
  static inline int btrfs_init_acl(struct btrfs_trans_handle *trans,
                                 struct inode *inode, struct inode *dir)
  {
diff --combined fs/btrfs/file.c
@@@ -150,6 -150,8 +150,8 @@@ int btrfs_add_inode_defrag(struct btrfs
        spin_lock(&root->fs_info->defrag_inodes_lock);
        if (!BTRFS_I(inode)->in_defrag)
                __btrfs_add_inode_defrag(inode, defrag);
+       else
+               kfree(defrag);
        spin_unlock(&root->fs_info->defrag_inodes_lock);
        return 0;
  }
@@@ -1452,7 -1454,7 +1454,7 @@@ int btrfs_release_file(struct inode *in
   * important optimization for directories because holding the mutex prevents
   * new operations on the dir while we write to disk.
   */
 -int btrfs_sync_file(struct file *file, int datasync)
 +int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
  {
        struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = dentry->d_inode;
  
        trace_btrfs_sync_file(file, datasync);
  
 +      ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
 +      if (ret)
 +              return ret;
 +      mutex_lock(&inode->i_mutex);
 +
        /* we wait first, since the writeback may change the inode */
        root->log_batch++;
 -      /* the VFS called filemap_fdatawrite for us */
        btrfs_wait_ordered_range(inode, 0, (u64)-1);
        root->log_batch++;
  
         * check the transaction that last modified this inode
         * and see if its already been committed
         */
 -      if (!BTRFS_I(inode)->last_trans)
 +      if (!BTRFS_I(inode)->last_trans) {
 +              mutex_unlock(&inode->i_mutex);
                goto out;
 +      }
  
        /*
         * if the last transaction that changed this file was before
        if (BTRFS_I(inode)->last_trans <=
            root->fs_info->last_trans_committed) {
                BTRFS_I(inode)->last_trans = 0;
 +              mutex_unlock(&inode->i_mutex);
                goto out;
        }
  
        trans = btrfs_start_transaction(root, 0);
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
 +              mutex_unlock(&inode->i_mutex);
                goto out;
        }
  
        ret = btrfs_log_dentry_safe(trans, root, dentry);
 -      if (ret < 0)
 +      if (ret < 0) {
 +              mutex_unlock(&inode->i_mutex);
                goto out;
 +      }
  
        /* we've logged all the items and now have a consistent
         * version of the file in the log.  It is possible that
         * file again, but that will end up using the synchronization
         * inside btrfs_sync_log to keep things safe.
         */
 -      mutex_unlock(&dentry->d_inode->i_mutex);
 +      mutex_unlock(&inode->i_mutex);
  
        if (ret != BTRFS_NO_LOG_SYNC) {
                if (ret > 0) {
        } else {
                ret = btrfs_end_transaction(trans, root);
        }
 -      mutex_lock(&dentry->d_inode->i_mutex);
  out:
        return ret > 0 ? -EIO : ret;
  }
@@@ -1638,11 -1631,15 +1640,15 @@@ static long btrfs_fallocate(struct fil
  
        cur_offset = alloc_start;
        while (1) {
+               u64 actual_end;
                em = btrfs_get_extent(inode, NULL, 0, cur_offset,
                                      alloc_end - cur_offset, 0);
                BUG_ON(IS_ERR_OR_NULL(em));
                last_byte = min(extent_map_end(em), alloc_end);
+               actual_end = min_t(u64, extent_map_end(em), offset + len);
                last_byte = (last_byte + mask) & ~mask;
                if (em->block_start == EXTENT_MAP_HOLE ||
                    (cur_offset >= inode->i_size &&
                     !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
                                free_extent_map(em);
                                break;
                        }
+               } else if (actual_end > inode->i_size &&
+                          !(mode & FALLOC_FL_KEEP_SIZE)) {
+                       /*
+                        * We didn't need to allocate any more space, but we
+                        * still extended the size of the file so we need to
+                        * update i_size.
+                        */
+                       inode->i_ctime = CURRENT_TIME;
+                       i_size_write(inode, actual_end);
+                       btrfs_ordered_update_i_size(inode, actual_end, NULL);
                }
                free_extent_map(em);
  
        return ret;
  }
  
 +static int find_desired_extent(struct inode *inode, loff_t *offset, int origin)
 +{
 +      struct btrfs_root *root = BTRFS_I(inode)->root;
 +      struct extent_map *em;
 +      struct extent_state *cached_state = NULL;
 +      u64 lockstart = *offset;
 +      u64 lockend = i_size_read(inode);
 +      u64 start = *offset;
 +      u64 orig_start = *offset;
 +      u64 len = i_size_read(inode);
 +      u64 last_end = 0;
 +      int ret = 0;
 +
 +      lockend = max_t(u64, root->sectorsize, lockend);
 +      if (lockend <= lockstart)
 +              lockend = lockstart + root->sectorsize;
 +
 +      len = lockend - lockstart + 1;
 +
 +      len = max_t(u64, len, root->sectorsize);
 +      if (inode->i_size == 0)
 +              return -ENXIO;
 +
 +      lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, 0,
 +                       &cached_state, GFP_NOFS);
 +
 +      /*
 +       * Delalloc is such a pain.  If we have a hole and we have pending
 +       * delalloc for a portion of the hole we will get back a hole that
 +       * exists for the entire range since it hasn't been actually written
 +       * yet.  So to take care of this case we need to look for an extent just
 +       * before the position we want in case there is outstanding delalloc
 +       * going on here.
 +       */
 +      if (origin == SEEK_HOLE && start != 0) {
 +              if (start <= root->sectorsize)
 +                      em = btrfs_get_extent_fiemap(inode, NULL, 0, 0,
 +                                                   root->sectorsize, 0);
 +              else
 +                      em = btrfs_get_extent_fiemap(inode, NULL, 0,
 +                                                   start - root->sectorsize,
 +                                                   root->sectorsize, 0);
 +              if (IS_ERR(em)) {
 +                      ret = -ENXIO;
 +                      goto out;
 +              }
 +              last_end = em->start + em->len;
 +              if (em->block_start == EXTENT_MAP_DELALLOC)
 +                      last_end = min_t(u64, last_end, inode->i_size);
 +              free_extent_map(em);
 +      }
 +
 +      while (1) {
 +              em = btrfs_get_extent_fiemap(inode, NULL, 0, start, len, 0);
 +              if (IS_ERR(em)) {
 +                      ret = -ENXIO;
 +                      break;
 +              }
 +
 +              if (em->block_start == EXTENT_MAP_HOLE) {
 +                      if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
 +                              if (last_end <= orig_start) {
 +                                      free_extent_map(em);
 +                                      ret = -ENXIO;
 +                                      break;
 +                              }
 +                      }
 +
 +                      if (origin == SEEK_HOLE) {
 +                              *offset = start;
 +                              free_extent_map(em);
 +                              break;
 +                      }
 +              } else {
 +                      if (origin == SEEK_DATA) {
 +                              if (em->block_start == EXTENT_MAP_DELALLOC) {
 +                                      if (start >= inode->i_size) {
 +                                              free_extent_map(em);
 +                                              ret = -ENXIO;
 +                                              break;
 +                                      }
 +                              }
 +
 +                              *offset = start;
 +                              free_extent_map(em);
 +                              break;
 +                      }
 +              }
 +
 +              start = em->start + em->len;
 +              last_end = em->start + em->len;
 +
 +              if (em->block_start == EXTENT_MAP_DELALLOC)
 +                      last_end = min_t(u64, last_end, inode->i_size);
 +
 +              if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
 +                      free_extent_map(em);
 +                      ret = -ENXIO;
 +                      break;
 +              }
 +              free_extent_map(em);
 +              cond_resched();
 +      }
 +      if (!ret)
 +              *offset = min(*offset, inode->i_size);
 +out:
 +      unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
 +                           &cached_state, GFP_NOFS);
 +      return ret;
 +}
 +
 +static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin)
 +{
 +      struct inode *inode = file->f_mapping->host;
 +      int ret;
 +
 +      mutex_lock(&inode->i_mutex);
 +      switch (origin) {
 +      case SEEK_END:
 +      case SEEK_CUR:
 +              offset = generic_file_llseek_unlocked(file, offset, origin);
 +              goto out;
 +      case SEEK_DATA:
 +      case SEEK_HOLE:
 +              ret = find_desired_extent(inode, &offset, origin);
 +              if (ret) {
 +                      mutex_unlock(&inode->i_mutex);
 +                      return ret;
 +              }
 +      }
 +
 +      if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) {
 +              ret = -EINVAL;
 +              goto out;
 +      }
 +      if (offset > inode->i_sb->s_maxbytes) {
 +              ret = -EINVAL;
 +              goto out;
 +      }
 +
 +      /* Special lock needed here? */
 +      if (offset != file->f_pos) {
 +              file->f_pos = offset;
 +              file->f_version = 0;
 +      }
 +out:
 +      mutex_unlock(&inode->i_mutex);
 +      return offset;
 +}
 +
  const struct file_operations btrfs_file_operations = {
 -      .llseek         = generic_file_llseek,
 +      .llseek         = btrfs_file_llseek,
        .read           = do_sync_read,
        .write          = do_sync_write,
        .aio_read       = generic_file_aio_read,
diff --combined fs/btrfs/ioctl.c
@@@ -323,7 -323,7 +323,7 @@@ static noinline int create_subvol(struc
        struct btrfs_inode_item *inode_item;
        struct extent_buffer *leaf;
        struct btrfs_root *new_root;
 -      struct dentry *parent = dget_parent(dentry);
 +      struct dentry *parent = dentry->d_parent;
        struct inode *dir;
        int ret;
        int err;
        u64 index = 0;
  
        ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid);
 -      if (ret) {
 -              dput(parent);
 +      if (ret)
                return ret;
 -      }
  
        dir = parent->d_inode;
  
         * 2 - dir items
         */
        trans = btrfs_start_transaction(root, 6);
 -      if (IS_ERR(trans)) {
 -              dput(parent);
 +      if (IS_ERR(trans))
                return PTR_ERR(trans);
 -      }
  
        leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
                                      0, objectid, NULL, 0, 0, 0);
  
        d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
  fail:
 -      dput(parent);
        if (async_transid) {
                *async_transid = trans->transid;
                err = btrfs_commit_transaction_async(trans, root, 1);
@@@ -451,6 -456,7 +451,6 @@@ static int create_snapshot(struct btrfs
                           bool readonly)
  {
        struct inode *inode;
 -      struct dentry *parent;
        struct btrfs_pending_snapshot *pending_snapshot;
        struct btrfs_trans_handle *trans;
        int ret;
        if (ret)
                goto fail;
  
 -      parent = dget_parent(dentry);
 -      inode = btrfs_lookup_dentry(parent->d_inode, dentry);
 -      dput(parent);
 +      inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
        if (IS_ERR(inode)) {
                ret = PTR_ERR(inode);
                goto fail;
@@@ -2236,6 -2244,10 +2236,10 @@@ static noinline long btrfs_ioctl_clone(
                btrfs_wait_ordered_range(src, off, len);
        }
  
+       /* truncate page cache pages from target inode range */
+       truncate_inode_pages_range(&inode->i_data, off,
+                                  ALIGN(off + len, PAGE_CACHE_SIZE) - 1);
        /* clone data */
        key.objectid = btrfs_ino(src);
        key.type = BTRFS_EXTENT_DATA_KEY;