int btrfs_truncate_item(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct btrfs_path *path,
-                       u32 new_size)
+                       u32 new_size, int from_end)
 {
        int ret = 0;
        int slot;
 
        slot_orig = path->slots[0];
        leaf = path->nodes[0];
+       slot = path->slots[0];
+
+       old_size = btrfs_item_size_nr(leaf, slot);
+       if (old_size == new_size)
+               return 0;
 
        nritems = btrfs_header_nritems(leaf);
        data_end = leaf_data_end(root, leaf);
 
-       slot = path->slots[0];
        old_data_start = btrfs_item_offset_nr(leaf, slot);
-       old_size = btrfs_item_size_nr(leaf, slot); BUG_ON(old_size <= new_size);
+
        size_diff = old_size - new_size;
 
        BUG_ON(slot < 0);
        }
 
        /* shift the data */
-       memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +
-                     data_end + size_diff, btrfs_leaf_data(leaf) +
-                     data_end, old_data_start + new_size - data_end);
+       if (from_end) {
+               memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +
+                             data_end + size_diff, btrfs_leaf_data(leaf) +
+                             data_end, old_data_start + new_size - data_end);
+       } else {
+               struct btrfs_disk_key disk_key;
+               u64 offset;
+
+               btrfs_item_key(leaf, &disk_key, slot);
+
+               if (btrfs_disk_key_type(&disk_key) == BTRFS_EXTENT_DATA_KEY) {
+                       unsigned long ptr;
+                       struct btrfs_file_extent_item *fi;
+
+                       fi = btrfs_item_ptr(leaf, slot,
+                                           struct btrfs_file_extent_item);
+                       fi = (struct btrfs_file_extent_item *)(
+                            (unsigned long)fi - size_diff);
+
+                       if (btrfs_file_extent_type(leaf, fi) ==
+                           BTRFS_FILE_EXTENT_INLINE) {
+                               ptr = btrfs_item_ptr_offset(leaf, slot);
+                               memmove_extent_buffer(leaf, ptr,
+                                       (unsigned long)fi,
+                                       offsetof(struct btrfs_file_extent_item,
+                                                disk_bytenr));
+                       }
+               }
+
+               memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +
+                             data_end + size_diff, btrfs_leaf_data(leaf) +
+                             data_end, old_data_start - data_end);
+
+               offset = btrfs_disk_key_offset(&disk_key);
+               btrfs_set_disk_key_offset(&disk_key, offset + size_diff);
+               btrfs_set_item_key(leaf, &disk_key, slot);
+               if (slot == 0)
+                       fixup_low_keys(trans, root, path, &disk_key, 1);
+       }
 
        item = btrfs_item_nr(leaf, slot);
        btrfs_set_item_size(leaf, item, new_size);
 
 int btrfs_truncate_item(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct btrfs_path *path,
-                       u32 new_size);
+                       u32 new_size, int from_end);
 int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, struct btrfs_key *key, struct btrfs_path *p, int
                      ins_len, int cow);
 
                memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
                        item_len - (ptr + sub_item_len - start));
                ret = btrfs_truncate_item(trans, root, path,
-                                         item_len - sub_item_len);
+                                         item_len - sub_item_len, 1);
        }
        return 0;
 }
 
                if (prev && prev->end + 1 == em->start &&
                    ((em->block_start == EXTENT_MAP_HOLE &&
                      prev->block_start == EXTENT_MAP_HOLE) ||
-                            (em->block_start == prev->block_end + 1))) {
+                    (em->block_start == EXTENT_MAP_INLINE &&
+                     prev->block_start == EXTENT_MAP_INLINE) ||
+                    (em->block_start == EXTENT_MAP_DELALLOC &&
+                     prev->block_start == EXTENT_MAP_DELALLOC) ||
+                    (em->block_start < EXTENT_MAP_DELALLOC - 1 &&
+                     em->block_start == prev->block_end + 1))) {
                        em->start = prev->start;
                        em->block_start = prev->block_start;
                        rb_erase(&prev->rb_node, &tree->map);
        u64 extent_offset;
        u64 last_byte = i_size_read(inode);
        u64 block_start;
+       u64 iosize;
        sector_t sector;
        struct extent_map *em;
        struct block_device *bdev;
        int ret;
        int nr = 0;
        size_t page_offset = 0;
-       size_t iosize;
        size_t blocksize;
        loff_t i_size = i_size_read(inode);
        unsigned long end_index = i_size >> PAGE_CACHE_SHIFT;
                        clear_extent_dirty(tree, cur, page_end, GFP_NOFS);
                        break;
                }
-               em = get_extent(inode, page, page_offset, cur, end, 0);
+               em = get_extent(inode, page, page_offset, cur, end, 1);
                if (IS_ERR(em) || !em) {
                        SetPageError(page);
                        break;
 
  * page->private values.  Every page that is controlled by the extent
  * map has page->private set to one.
  */
-
 #define EXTENT_PAGE_PRIVATE 1
 #define EXTENT_PAGE_PRIVATE_FIRST_PAGE 3
 
 
        new_item_size = blocks * BTRFS_CRC32_SIZE;
        if (new_item_size >= btrfs_item_size_nr(leaf, slot))
                return 0;
-       ret = btrfs_truncate_item(trans, root, path, new_item_size);
+       ret = btrfs_truncate_item(trans, root, path, new_item_size, 1);
        BUG_ON(ret);
        return ret;
 }
 
                goto fail;
        }
        if (ret == 1) {
+               struct btrfs_key found_key;
+
+               if (path->slots[0] == 0)
+                       goto insert;
+
                path->slots[0]--;
                leaf = path->nodes[0];
+               btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
+
+               if (found_key.objectid != inode->i_ino)
+                       goto insert;
+
+               if (found_key.type != BTRFS_EXTENT_DATA_KEY)
+                       goto insert;
                ei = btrfs_item_ptr(leaf, path->slots[0],
                                    struct btrfs_file_extent_item);
 
                        ret = btrfs_search_slot(trans, root, &key, path,
                                                offset + size - found_end, 1);
                        BUG_ON(ret != 0);
+
                        ret = btrfs_extend_item(trans, root, path,
                                                offset + size - found_end);
                        if (ret) {
         */
        inline_size = end_pos;
        if (isize >= BTRFS_MAX_INLINE_DATA_SIZE(root) ||
-           inline_size > 8192 ||
+           inline_size > 32768 ||
            inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root)) {
                u64 last_end;
 
                aligned_end = (pos + write_bytes + root->sectorsize - 1) &
                        ~((u64)root->sectorsize - 1);
                err = btrfs_drop_extents(trans, root, inode, start_pos,
-                                        aligned_end, end_pos, &hint_byte);
+                                        aligned_end, aligned_end, &hint_byte);
                if (err)
                        goto failed;
                err = insert_inline_extent(trans, root, inode, start_pos,
                        goto next_slot;
                }
 
-               /* FIXME, there's only one inline extent allowed right now */
                if (found_inline) {
                        u64 mask = root->sectorsize - 1;
                        search_start = (extent_end + mask) & ~mask;
                } else
                        search_start = extent_end;
 
+               if (end <= extent_end && start >= key.offset && found_inline) {
+                       *hint_byte = EXTENT_MAP_INLINE;
+               }
                if (end < extent_end && end >= key.offset) {
                        if (found_extent) {
                                u64 disk_bytenr =
                                        BUG_ON(ret);
                                }
                        }
-                       if (!found_inline)
-                               bookend = 1;
+                       bookend = 1;
+                       if (found_inline && start <= key.offset &&
+                           inline_end < extent_end)
+                               keep = 1;
                }
                /* truncate existing extent */
                if (start > key.offset) {
                                new_size = btrfs_file_extent_calc_inline_size(
                                                   inline_end - key.offset);
                                btrfs_truncate_item(trans, root, path,
-                                                   new_size);
+                                                   new_size, 1);
                        }
                }
                /* delete the entire extent */
                        if (!bookend)
                                continue;
                }
+               if (bookend && found_inline && start <= key.offset &&
+                   inline_end < extent_end) {
+                       u32 new_size;
+                       new_size = btrfs_file_extent_calc_inline_size(
+                                                  extent_end - inline_end);
+                       btrfs_truncate_item(trans, root, path, new_size, 0);
+               }
                /* create bookend, splitting the extent in two */
                if (bookend && found_extent) {
                        struct btrfs_key ins;
 
        ret = btrfs_drop_extents(trans, root, inode,
                                 start, start + num_bytes, start, &alloc_hint);
 
+       if (alloc_hint == EXTENT_MAP_INLINE)
+               goto out;
+
        ret = btrfs_alloc_extent(trans, root, inode->i_ino, num_bytes, 0,
                                 alloc_hint, (u64)-1, &ins, 1);
        if (ret) {
        u64 item_end = 0;
        int found_extent;
        int del_item;
+       int extent_type = -1;
 
        btrfs_drop_extent_cache(inode, inode->i_size, (u64)-1);
        path = btrfs_alloc_path();
                if (found_type == BTRFS_EXTENT_DATA_KEY) {
                        fi = btrfs_item_ptr(leaf, path->slots[0],
                                            struct btrfs_file_extent_item);
-                       if (btrfs_file_extent_type(leaf, fi) !=
-                           BTRFS_FILE_EXTENT_INLINE) {
+                       extent_type = btrfs_file_extent_type(leaf, fi);
+                       if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
                                item_end +=
                                    btrfs_file_extent_num_bytes(leaf, fi);
+                       } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
+                               struct btrfs_item *item = btrfs_item_nr(leaf,
+                                                               path->slots[0]);
+                               item_end += btrfs_file_extent_inline_len(leaf,
+                                                                        item);
                        }
                }
                if (found_type == BTRFS_CSUM_ITEM_KEY) {
                                                  inode->i_size);
                        BUG_ON(ret);
                }
-               if (item_end < inode->i_size) {
+               if (item_end <= inode->i_size) {
                        if (found_type == BTRFS_DIR_ITEM_KEY) {
                                found_type = BTRFS_INODE_ITEM_KEY;
                        } else if (found_type == BTRFS_EXTENT_ITEM_KEY) {
                found_extent = 0;
 
                /* FIXME, shrink the extent if the ref count is only 1 */
-               if (found_type == BTRFS_EXTENT_DATA_KEY &&
-                          btrfs_file_extent_type(leaf, fi) !=
-                          BTRFS_FILE_EXTENT_INLINE) {
+               if (found_type != BTRFS_EXTENT_DATA_KEY)
+                       goto delete;
+
+               if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
                        u64 num_dec;
                        extent_start = btrfs_file_extent_disk_bytenr(leaf, fi);
                        if (!del_item) {
                                        inode->i_blocks -= num_dec;
                                }
                        }
+               } else if (extent_type == BTRFS_FILE_EXTENT_INLINE &&
+                          !del_item) {
+                       u32 newsize = inode->i_size - found_key.offset;
+                       newsize = btrfs_file_extent_calc_inline_size(newsize);
+                       ret = btrfs_truncate_item(trans, root, path,
+                                                 newsize, 1);
+                       BUG_ON(ret);
                }
+delete:
                if (del_item) {
                        ret = btrfs_del_item(trans, root, path);
                        if (ret)
                u64 pos = (inode->i_size + mask) & ~mask;
                u64 block_end = attr->ia_size | mask;
                u64 hole_size;
-               u64 alloc_hint;
+               u64 alloc_hint = 0;
 
                if (attr->ia_size <= pos)
                        goto out;
                                         pos, pos + hole_size, pos,
                                         &alloc_hint);
 
-               err = btrfs_insert_file_extent(trans, root, inode->i_ino,
-                                              pos, 0, 0, hole_size);
+               if (alloc_hint != EXTENT_MAP_INLINE) {
+                       err = btrfs_insert_file_extent(trans, root,
+                                                      inode->i_ino,
+                                                      pos, 0, 0, hole_size);
+               }
                btrfs_end_transaction(trans, root);
                mutex_unlock(&root->fs_info->fs_mutex);
                unlock_extent(em_tree, pos, block_end, GFP_NOFS);
                em->end = EXTENT_MAP_HOLE;
        }
        em->bdev = inode->i_sb->s_bdev;
-       ret = btrfs_lookup_file_extent(NULL, root, path,
-                                      objectid, start, 0);
+       ret = btrfs_lookup_file_extent(trans, root, path,
+                                      objectid, start, trans != NULL);
        if (ret < 0) {
                err = ret;
                goto out;
                        ((u64)root->sectorsize -1);
                map = kmap(page);
                ptr = btrfs_file_extent_inline_start(item) + extent_offset;
-               read_extent_buffer(leaf, map + page_offset, ptr, copy_size);
-               
-               if (em->start + copy_size <= em->end) {
-                       size = min_t(u64, em->end + 1 - em->start,
-                               PAGE_CACHE_SIZE - page_offset) - copy_size;
-                       memset(map + page_offset + copy_size, 0, size);
+               if (create == 0 && !PageUptodate(page)) {
+                       read_extent_buffer(leaf, map + page_offset, ptr,
+                                          copy_size);
+                       flush_dcache_page(page);
+               } else if (create && PageUptodate(page)) {
+                       if (!trans) {
+                               kunmap(page);
+                               free_extent_map(em);
+                               em = NULL;
+                               btrfs_release_path(root, path);
+                               trans = btrfs_start_transaction(root, 1);
+                               goto again;
+                       }
+                       write_extent_buffer(leaf, map + page_offset, ptr,
+                                           copy_size);
+                       btrfs_mark_buffer_dirty(leaf);
                }
-
-               flush_dcache_page(page);
                kunmap(page);
                set_extent_uptodate(em_tree, em->start, em->end, GFP_NOFS);
                goto insert;