don't put symlink bodies in pagecache into highmem
[deliverable/linux.git] / fs / btrfs / inode.c
index 0e4f2bfcc37d083da90f381c0cfeeeb28f643cd2..70f98bfde27757e50b20433a402b12f852a18f6e 100644 (file)
@@ -1304,8 +1304,14 @@ next_slot:
                num_bytes = 0;
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
 
-               if (found_key.objectid > ino ||
-                   found_key.type > BTRFS_EXTENT_DATA_KEY ||
+               if (found_key.objectid > ino)
+                       break;
+               if (WARN_ON_ONCE(found_key.objectid < ino) ||
+                   found_key.type < BTRFS_EXTENT_DATA_KEY) {
+                       path->slots[0]++;
+                       goto next_slot;
+               }
+               if (found_key.type > BTRFS_EXTENT_DATA_KEY ||
                    found_key.offset > end)
                        break;
 
@@ -3768,6 +3774,7 @@ cache_acl:
                break;
        case S_IFLNK:
                inode->i_op = &btrfs_symlink_inode_operations;
+               inode_nohighmem(inode);
                inode->i_mapping->a_ops = &btrfs_symlink_aops;
                break;
        default:
@@ -4040,9 +4047,7 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
  */
 static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir)
 {
-       struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(dir)->root;
-       int ret;
 
        /*
         * 1 for the possible orphan item
@@ -4051,27 +4056,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir)
         * 1 for the inode ref
         * 1 for the inode
         */
-       trans = btrfs_start_transaction(root, 5);
-       if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC)
-               return trans;
-
-       if (PTR_ERR(trans) == -ENOSPC) {
-               u64 num_bytes = btrfs_calc_trans_metadata_size(root, 5);
-
-               trans = btrfs_start_transaction(root, 0);
-               if (IS_ERR(trans))
-                       return trans;
-               ret = btrfs_cond_migrate_bytes(root->fs_info,
-                                              &root->fs_info->trans_block_rsv,
-                                              num_bytes, 5);
-               if (ret) {
-                       btrfs_end_transaction(trans, root);
-                       return ERR_PTR(ret);
-               }
-               trans->block_rsv = &root->fs_info->trans_block_rsv;
-               trans->bytes_reserved = num_bytes;
-       }
-       return trans;
+       return btrfs_start_transaction_fallback_global_rsv(root, 5, 5);
 }
 
 static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
@@ -7503,6 +7488,28 @@ struct btrfs_dio_data {
        u64 reserve;
 };
 
+static void adjust_dio_outstanding_extents(struct inode *inode,
+                                          struct btrfs_dio_data *dio_data,
+                                          const u64 len)
+{
+       unsigned num_extents;
+
+       num_extents = (unsigned) div64_u64(len + BTRFS_MAX_EXTENT_SIZE - 1,
+                                          BTRFS_MAX_EXTENT_SIZE);
+       /*
+        * If we have an outstanding_extents count still set then we're
+        * within our reservation, otherwise we need to adjust our inode
+        * counter appropriately.
+        */
+       if (dio_data->outstanding_extents) {
+               dio_data->outstanding_extents -= num_extents;
+       } else {
+               spin_lock(&BTRFS_I(inode)->lock);
+               BTRFS_I(inode)->outstanding_extents += num_extents;
+               spin_unlock(&BTRFS_I(inode)->lock);
+       }
+}
+
 static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
                                   struct buffer_head *bh_result, int create)
 {
@@ -7538,8 +7545,11 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
         * If this errors out it's because we couldn't invalidate pagecache for
         * this range and we need to fallback to buffered.
         */
-       if (lock_extent_direct(inode, lockstart, lockend, &cached_state, create))
-               return -ENOTBLK;
+       if (lock_extent_direct(inode, lockstart, lockend, &cached_state,
+                              create)) {
+               ret = -ENOTBLK;
+               goto err;
+       }
 
        em = btrfs_get_extent(inode, NULL, 0, start, len, 0);
        if (IS_ERR(em)) {
@@ -7657,19 +7667,7 @@ unlock:
                if (start + len > i_size_read(inode))
                        i_size_write(inode, start + len);
 
-               /*
-                * If we have an outstanding_extents count still set then we're
-                * within our reservation, otherwise we need to adjust our inode
-                * counter appropriately.
-                */
-               if (dio_data->outstanding_extents) {
-                       (dio_data->outstanding_extents)--;
-               } else {
-                       spin_lock(&BTRFS_I(inode)->lock);
-                       BTRFS_I(inode)->outstanding_extents++;
-                       spin_unlock(&BTRFS_I(inode)->lock);
-               }
-
+               adjust_dio_outstanding_extents(inode, dio_data, len);
                btrfs_free_reserved_data_space(inode, start, len);
                WARN_ON(dio_data->reserve < len);
                dio_data->reserve -= len;
@@ -7696,8 +7694,17 @@ unlock:
 unlock_err:
        clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
                         unlock_bits, 1, 0, &cached_state, GFP_NOFS);
+err:
        if (dio_data)
                current->journal_info = dio_data;
+       /*
+        * Compensate the delalloc release we do in btrfs_direct_IO() when we
+        * write less data then expected, so that we don't underflow our inode's
+        * outstanding extents counter.
+        */
+       if (create && dio_data)
+               adjust_dio_outstanding_extents(inode, dio_data, len);
+
        return ret;
 }
 
@@ -9699,6 +9706,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
        btrfs_free_path(path);
 
        inode->i_op = &btrfs_symlink_inode_operations;
+       inode_nohighmem(inode);
        inode->i_mapping->a_ops = &btrfs_symlink_aops;
        inode_set_bytes(inode, name_len);
        btrfs_i_size_write(inode, name_len);
This page took 0.029752 seconds and 5 git commands to generate.