Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Jan 2010 15:28:05 +0000 (07:28 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Jan 2010 15:28:05 +0000 (07:28 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable:
  Btrfs: fix possible panic on unmount
  Btrfs: deal with NULL acl sent to btrfs_set_acl
  Btrfs: fix regression in orphan cleanup
  Btrfs: Fix race in btrfs_mark_extent_written
  Btrfs, fix memory leaks in error paths
  Btrfs: align offsets for btrfs_ordered_update_i_size
  btrfs: fix missing last-entry in readdir(3)

1  2 
fs/btrfs/acl.c
fs/btrfs/file.c

diff --combined fs/btrfs/acl.c
@@@ -73,13 -73,13 +73,13 @@@ static struct posix_acl *btrfs_get_acl(
        return acl;
  }
  
 -static int btrfs_xattr_get_acl(struct inode *inode, int type,
 -                             void *value, size_t size)
 +static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name,
 +              void *value, size_t size, int type)
  {
        struct posix_acl *acl;
        int ret = 0;
  
 -      acl = btrfs_get_acl(inode, type);
 +      acl = btrfs_get_acl(dentry->d_inode, type);
  
        if (IS_ERR(acl))
                return PTR_ERR(acl);
@@@ -112,12 -112,14 +112,14 @@@ static int btrfs_set_acl(struct btrfs_t
        switch (type) {
        case ACL_TYPE_ACCESS:
                mode = inode->i_mode;
-               ret = posix_acl_equiv_mode(acl, &mode);
-               if (ret < 0)
-                       return ret;
-               ret = 0;
-               inode->i_mode = mode;
                name = POSIX_ACL_XATTR_ACCESS;
+               if (acl) {
+                       ret = posix_acl_equiv_mode(acl, &mode);
+                       if (ret < 0)
+                               return ret;
+                       inode->i_mode = mode;
+               }
+               ret = 0;
                break;
        case ACL_TYPE_DEFAULT:
                if (!S_ISDIR(inode->i_mode))
@@@ -151,8 -153,8 +153,8 @@@ out
        return ret;
  }
  
 -static int btrfs_xattr_set_acl(struct inode *inode, int type,
 -                             const void *value, size_t size)
 +static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
 +              const void *value, size_t size, int flags, int type)
  {
        int ret;
        struct posix_acl *acl = NULL;
                }
        }
  
 -      ret = btrfs_set_acl(NULL, inode, acl, type);
 +      ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type);
  
        posix_acl_release(acl);
  
        return ret;
  }
  
 -
 -static int btrfs_xattr_acl_access_get(struct inode *inode, const char *name,
 -                                    void *value, size_t size)
 -{
 -      return btrfs_xattr_get_acl(inode, ACL_TYPE_ACCESS, value, size);
 -}
 -
 -static int btrfs_xattr_acl_access_set(struct inode *inode, const char *name,
 -                                    const void *value, size_t size, int flags)
 -{
 -      return btrfs_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
 -}
 -
 -static int btrfs_xattr_acl_default_get(struct inode *inode, const char *name,
 -                                     void *value, size_t size)
 -{
 -      return btrfs_xattr_get_acl(inode, ACL_TYPE_DEFAULT, value, size);
 -}
 -
 -static int btrfs_xattr_acl_default_set(struct inode *inode, const char *name,
 -                             const void *value, size_t size, int flags)
 -{
 -      return btrfs_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
 -}
 -
  int btrfs_check_acl(struct inode *inode, int mask)
  {
        struct posix_acl *acl;
@@@ -280,16 -307,14 +282,16 @@@ int btrfs_acl_chmod(struct inode *inode
  
  struct xattr_handler btrfs_xattr_acl_default_handler = {
        .prefix = POSIX_ACL_XATTR_DEFAULT,
 -      .get    = btrfs_xattr_acl_default_get,
 -      .set    = btrfs_xattr_acl_default_set,
 +      .flags  = ACL_TYPE_DEFAULT,
 +      .get    = btrfs_xattr_acl_get,
 +      .set    = btrfs_xattr_acl_set,
  };
  
  struct xattr_handler btrfs_xattr_acl_access_handler = {
        .prefix = POSIX_ACL_XATTR_ACCESS,
 -      .get    = btrfs_xattr_acl_access_get,
 -      .set    = btrfs_xattr_acl_access_set,
 +      .flags  = ACL_TYPE_ACCESS,
 +      .get    = btrfs_xattr_acl_get,
 +      .set    = btrfs_xattr_acl_set,
  };
  
  #else /* CONFIG_BTRFS_FS_POSIX_ACL */
diff --combined fs/btrfs/file.c
@@@ -506,7 -506,8 +506,8 @@@ next_slot
  }
  
  static int extent_mergeable(struct extent_buffer *leaf, int slot,
-                           u64 objectid, u64 bytenr, u64 *start, u64 *end)
+                           u64 objectid, u64 bytenr, u64 orig_offset,
+                           u64 *start, u64 *end)
  {
        struct btrfs_file_extent_item *fi;
        struct btrfs_key key;
        fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
        if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG ||
            btrfs_file_extent_disk_bytenr(leaf, fi) != bytenr ||
+           btrfs_file_extent_offset(leaf, fi) != key.offset - orig_offset ||
            btrfs_file_extent_compression(leaf, fi) ||
            btrfs_file_extent_encryption(leaf, fi) ||
            btrfs_file_extent_other_encoding(leaf, fi))
@@@ -561,6 -563,7 +563,7 @@@ int btrfs_mark_extent_written(struct bt
        u64 split;
        int del_nr = 0;
        int del_slot = 0;
+       int recow;
        int ret;
  
        btrfs_drop_extent_cache(inode, start, end - 1, 0);
        path = btrfs_alloc_path();
        BUG_ON(!path);
  again:
+       recow = 0;
        split = start;
        key.objectid = inode->i_ino;
        key.type = BTRFS_EXTENT_DATA_KEY;
        bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
        num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
        orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi);
+       memcpy(&new_key, &key, sizeof(new_key));
+       if (start == key.offset && end < extent_end) {
+               other_start = 0;
+               other_end = start;
+               if (extent_mergeable(leaf, path->slots[0] - 1,
+                                    inode->i_ino, bytenr, orig_offset,
+                                    &other_start, &other_end)) {
+                       new_key.offset = end;
+                       btrfs_set_item_key_safe(trans, root, path, &new_key);
+                       fi = btrfs_item_ptr(leaf, path->slots[0],
+                                           struct btrfs_file_extent_item);
+                       btrfs_set_file_extent_num_bytes(leaf, fi,
+                                                       extent_end - end);
+                       btrfs_set_file_extent_offset(leaf, fi,
+                                                    end - orig_offset);
+                       fi = btrfs_item_ptr(leaf, path->slots[0] - 1,
+                                           struct btrfs_file_extent_item);
+                       btrfs_set_file_extent_num_bytes(leaf, fi,
+                                                       end - other_start);
+                       btrfs_mark_buffer_dirty(leaf);
+                       goto out;
+               }
+       }
+       if (start > key.offset && end == extent_end) {
+               other_start = end;
+               other_end = 0;
+               if (extent_mergeable(leaf, path->slots[0] + 1,
+                                    inode->i_ino, bytenr, orig_offset,
+                                    &other_start, &other_end)) {
+                       fi = btrfs_item_ptr(leaf, path->slots[0],
+                                           struct btrfs_file_extent_item);
+                       btrfs_set_file_extent_num_bytes(leaf, fi,
+                                                       start - key.offset);
+                       path->slots[0]++;
+                       new_key.offset = start;
+                       btrfs_set_item_key_safe(trans, root, path, &new_key);
+                       fi = btrfs_item_ptr(leaf, path->slots[0],
+                                           struct btrfs_file_extent_item);
+                       btrfs_set_file_extent_num_bytes(leaf, fi,
+                                                       other_end - start);
+                       btrfs_set_file_extent_offset(leaf, fi,
+                                                    start - orig_offset);
+                       btrfs_mark_buffer_dirty(leaf);
+                       goto out;
+               }
+       }
  
        while (start > key.offset || end < extent_end) {
                if (key.offset == start)
                        split = end;
  
-               memcpy(&new_key, &key, sizeof(new_key));
                new_key.offset = split;
                ret = btrfs_duplicate_item(trans, root, path, &new_key);
                if (ret == -EAGAIN) {
                        path->slots[0]--;
                        extent_end = end;
                }
+               recow = 1;
        }
  
-       fi = btrfs_item_ptr(leaf, path->slots[0],
-                           struct btrfs_file_extent_item);
        other_start = end;
        other_end = 0;
-       if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino,
-                            bytenr, &other_start, &other_end)) {
+       if (extent_mergeable(leaf, path->slots[0] + 1,
+                            inode->i_ino, bytenr, orig_offset,
+                            &other_start, &other_end)) {
+               if (recow) {
+                       btrfs_release_path(root, path);
+                       goto again;
+               }
                extent_end = other_end;
                del_slot = path->slots[0] + 1;
                del_nr++;
        }
        other_start = 0;
        other_end = start;
-       if (extent_mergeable(leaf, path->slots[0] - 1, inode->i_ino,
-                            bytenr, &other_start, &other_end)) {
+       if (extent_mergeable(leaf, path->slots[0] - 1,
+                            inode->i_ino, bytenr, orig_offset,
+                            &other_start, &other_end)) {
+               if (recow) {
+                       btrfs_release_path(root, path);
+                       goto again;
+               }
                key.offset = other_start;
                del_slot = path->slots[0];
                del_nr++;
                                        inode->i_ino, orig_offset);
                BUG_ON(ret);
        }
+       fi = btrfs_item_ptr(leaf, path->slots[0],
+                          struct btrfs_file_extent_item);
        if (del_nr == 0) {
                btrfs_set_file_extent_type(leaf, fi,
                                           BTRFS_FILE_EXTENT_REG);
                btrfs_mark_buffer_dirty(leaf);
-               goto out;
-       }
-       fi = btrfs_item_ptr(leaf, del_slot - 1,
-                           struct btrfs_file_extent_item);
-       btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
-       btrfs_set_file_extent_num_bytes(leaf, fi,
-                                       extent_end - key.offset);
-       btrfs_mark_buffer_dirty(leaf);
+       } else {
+               btrfs_set_file_extent_type(leaf, fi,
+                                          BTRFS_FILE_EXTENT_REG);
+               btrfs_set_file_extent_num_bytes(leaf, fi,
+                                               extent_end - key.offset);
+               btrfs_mark_buffer_dirty(leaf);
  
-       ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
-       BUG_ON(ret);
+               ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
+               BUG_ON(ret);
+       }
  out:
        btrfs_free_path(path);
        return 0;
@@@ -772,7 -832,7 +832,7 @@@ static ssize_t btrfs_file_write(struct 
        unsigned long last_index;
        int will_write;
  
 -      will_write = ((file->f_flags & O_SYNC) || IS_SYNC(inode) ||
 +      will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) ||
                      (file->f_flags & O_DIRECT));
  
        nrptrs = min((count + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE,
@@@ -939,7 -999,7 +999,7 @@@ out_nolock
                if (err)
                        num_written = err;
  
 -              if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) {
 +              if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
                        trans = btrfs_start_transaction(root, 1);
                        ret = btrfs_log_dentry_safe(trans, root,
                                                    file->f_dentry);