2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public
4 * License v2 as published by the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 * General Public License for more details.
11 * You should have received a copy of the GNU General Public
12 * License along with this program; if not, write to the
13 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14 * Boston, MA 021110-1307, USA.
21 #include "transaction.h"
23 #include "check/common.h"
26 * Search in csum tree to find how many bytes of range [@start, @start + @len)
27 * has the corresponding csum item.
31 * @found: return value of found csum bytes
34 int count_csum_range(struct btrfs_fs_info *fs_info, u64 start,
38 struct btrfs_path path;
39 struct extent_buffer *leaf;
44 u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
46 btrfs_init_path(&path);
48 key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
50 key.type = BTRFS_EXTENT_CSUM_KEY;
52 ret = btrfs_search_slot(NULL, fs_info->csum_root,
56 if (ret > 0 && path.slots[0] > 0) {
58 btrfs_item_key_to_cpu(leaf, &key, path.slots[0] - 1);
59 if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID &&
60 key.type == BTRFS_EXTENT_CSUM_KEY)
66 if (path.slots[0] >= btrfs_header_nritems(leaf)) {
67 ret = btrfs_next_leaf(fs_info->csum_root, &path);
75 btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
76 if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
77 key.type != BTRFS_EXTENT_CSUM_KEY)
80 btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
81 if (key.offset >= start + len)
84 if (key.offset > start)
87 size = btrfs_item_size_nr(leaf, path.slots[0]);
88 csum_end = key.offset + (size / csum_size) *
90 if (csum_end > start) {
91 size = min(csum_end - start, len);
100 btrfs_release_path(&path);
107 * Wrapper to insert one inode item into given @root
108 * Timestamp will be set to current time.
110 * @root: the root to insert inode item into
113 * @nbytes: nbytes (real used size, without hole)
114 * @nlink: number of links
115 * @mode: file mode, including S_IF* bits
117 int insert_inode_item(struct btrfs_trans_handle *trans,
118 struct btrfs_root *root, u64 ino, u64 size,
119 u64 nbytes, u64 nlink, u32 mode)
121 struct btrfs_inode_item ii;
122 time_t now = time(NULL);
125 btrfs_set_stack_inode_size(&ii, size);
126 btrfs_set_stack_inode_nbytes(&ii, nbytes);
127 btrfs_set_stack_inode_nlink(&ii, nlink);
128 btrfs_set_stack_inode_mode(&ii, mode);
129 btrfs_set_stack_inode_generation(&ii, trans->transid);
130 btrfs_set_stack_timespec_nsec(&ii.atime, 0);
131 btrfs_set_stack_timespec_sec(&ii.ctime, now);
132 btrfs_set_stack_timespec_nsec(&ii.ctime, 0);
133 btrfs_set_stack_timespec_sec(&ii.mtime, now);
134 btrfs_set_stack_timespec_nsec(&ii.mtime, 0);
135 btrfs_set_stack_timespec_sec(&ii.otime, 0);
136 btrfs_set_stack_timespec_nsec(&ii.otime, 0);
138 ret = btrfs_insert_inode(trans, root, ino, &ii);
141 warning("root %llu inode %llu recreating inode item, this may "
142 "be incomplete, please check permissions and content after "
143 "the fsck completes.\n", (unsigned long long)root->objectid,
144 (unsigned long long)ino);
149 static int get_highest_inode(struct btrfs_trans_handle *trans,
150 struct btrfs_root *root, struct btrfs_path *path,
153 struct btrfs_key key, found_key;
156 btrfs_init_path(path);
157 key.objectid = BTRFS_LAST_FREE_OBJECTID;
159 key.type = BTRFS_INODE_ITEM_KEY;
160 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
162 btrfs_item_key_to_cpu(path->nodes[0], &found_key,
164 *highest_ino = found_key.objectid;
167 if (*highest_ino >= BTRFS_LAST_FREE_OBJECTID)
169 btrfs_release_path(path);
174 * Link inode to dir 'lost+found'. Increase @ref_count.
176 * Returns 0 means success.
177 * Returns <0 means failure.
179 int link_inode_to_lostfound(struct btrfs_trans_handle *trans,
180 struct btrfs_root *root,
181 struct btrfs_path *path,
182 u64 ino, char *namebuf, u32 name_len,
183 u8 filetype, u64 *ref_count)
185 char *dir_name = "lost+found";
190 btrfs_release_path(path);
191 ret = get_highest_inode(trans, root, path, &lost_found_ino);
196 ret = btrfs_mkdir(trans, root, dir_name, strlen(dir_name),
197 BTRFS_FIRST_FREE_OBJECTID, &lost_found_ino,
200 error("failed to create '%s' dir: %s", dir_name, strerror(-ret));
203 ret = btrfs_add_link(trans, root, ino, lost_found_ino,
204 namebuf, name_len, filetype, NULL, 1, 0);
206 * Add ".INO" suffix several times to handle case where
207 * "FILENAME.INO" is already taken by another file.
209 while (ret == -EEXIST) {
211 * Conflicting file name, add ".INO" as suffix * +1 for '.'
213 if (name_len + count_digits(ino) + 1 > BTRFS_NAME_LEN) {
217 snprintf(namebuf + name_len, BTRFS_NAME_LEN - name_len,
219 name_len += count_digits(ino) + 1;
220 ret = btrfs_add_link(trans, root, ino, lost_found_ino, namebuf,
221 name_len, filetype, NULL, 1, 0);
224 error("failed to link the inode %llu to %s dir: %s",
225 ino, dir_name, strerror(-ret));
230 printf("Moving file '%.*s' to '%s' dir since it has no valid backref\n",
231 name_len, namebuf, dir_name);
233 btrfs_release_path(path);
235 error("failed to move file '%.*s' to '%s' dir", name_len,