~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/btrfs/inode-item.c

Version: ~ [ linux-5.13-rc5 ] ~ [ linux-5.12.9 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.42 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.124 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.193 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.235 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.271 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.271 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (C) 2007 Oracle.  All rights reserved.
  3  *
  4  * This program is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU General Public
  6  * License v2 as published by the Free Software Foundation.
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 11  * General Public License for more details.
 12  *
 13  * You should have received a copy of the GNU General Public
 14  * License along with this program; if not, write to the
 15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 16  * Boston, MA 021110-1307, USA.
 17  */
 18 
 19 #include "ctree.h"
 20 #include "disk-io.h"
 21 #include "hash.h"
 22 #include "transaction.h"
 23 #include "print-tree.h"
 24 
 25 int btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot,
 26                                const char *name,
 27                                int name_len, struct btrfs_inode_ref **ref_ret)
 28 {
 29         struct btrfs_inode_ref *ref;
 30         unsigned long ptr;
 31         unsigned long name_ptr;
 32         u32 item_size;
 33         u32 cur_offset = 0;
 34         int len;
 35 
 36         item_size = btrfs_item_size_nr(leaf, slot);
 37         ptr = btrfs_item_ptr_offset(leaf, slot);
 38         while (cur_offset < item_size) {
 39                 ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
 40                 len = btrfs_inode_ref_name_len(leaf, ref);
 41                 name_ptr = (unsigned long)(ref + 1);
 42                 cur_offset += len + sizeof(*ref);
 43                 if (len != name_len)
 44                         continue;
 45                 if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) {
 46                         if (ref_ret)
 47                                 *ref_ret = ref;
 48                         return 1;
 49                 }
 50         }
 51         return 0;
 52 }
 53 
 54 int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot,
 55                                    u64 ref_objectid,
 56                                    const char *name, int name_len,
 57                                    struct btrfs_inode_extref **extref_ret)
 58 {
 59         struct btrfs_inode_extref *extref;
 60         unsigned long ptr;
 61         unsigned long name_ptr;
 62         u32 item_size;
 63         u32 cur_offset = 0;
 64         int ref_name_len;
 65 
 66         item_size = btrfs_item_size_nr(leaf, slot);
 67         ptr = btrfs_item_ptr_offset(leaf, slot);
 68 
 69         /*
 70          * Search all extended backrefs in this item. We're only
 71          * looking through any collisions so most of the time this is
 72          * just going to compare against one buffer. If all is well,
 73          * we'll return success and the inode ref object.
 74          */
 75         while (cur_offset < item_size) {
 76                 extref = (struct btrfs_inode_extref *) (ptr + cur_offset);
 77                 name_ptr = (unsigned long)(&extref->name);
 78                 ref_name_len = btrfs_inode_extref_name_len(leaf, extref);
 79 
 80                 if (ref_name_len == name_len &&
 81                     btrfs_inode_extref_parent(leaf, extref) == ref_objectid &&
 82                     (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)) {
 83                         if (extref_ret)
 84                                 *extref_ret = extref;
 85                         return 1;
 86                 }
 87 
 88                 cur_offset += ref_name_len + sizeof(*extref);
 89         }
 90         return 0;
 91 }
 92 
 93 /* Returns NULL if no extref found */
 94 struct btrfs_inode_extref *
 95 btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
 96                           struct btrfs_root *root,
 97                           struct btrfs_path *path,
 98                           const char *name, int name_len,
 99                           u64 inode_objectid, u64 ref_objectid, int ins_len,
100                           int cow)
101 {
102         int ret;
103         struct btrfs_key key;
104         struct btrfs_inode_extref *extref;
105 
106         key.objectid = inode_objectid;
107         key.type = BTRFS_INODE_EXTREF_KEY;
108         key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
109 
110         ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
111         if (ret < 0)
112                 return ERR_PTR(ret);
113         if (ret > 0)
114                 return NULL;
115         if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],
116                                             ref_objectid, name, name_len,
117                                             &extref))
118                 return NULL;
119         return extref;
120 }
121 
122 static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
123                                   struct btrfs_root *root,
124                                   const char *name, int name_len,
125                                   u64 inode_objectid, u64 ref_objectid,
126                                   u64 *index)
127 {
128         struct btrfs_path *path;
129         struct btrfs_key key;
130         struct btrfs_inode_extref *extref;
131         struct extent_buffer *leaf;
132         int ret;
133         int del_len = name_len + sizeof(*extref);
134         unsigned long ptr;
135         unsigned long item_start;
136         u32 item_size;
137 
138         key.objectid = inode_objectid;
139         key.type = BTRFS_INODE_EXTREF_KEY;
140         key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
141 
142         path = btrfs_alloc_path();
143         if (!path)
144                 return -ENOMEM;
145 
146         path->leave_spinning = 1;
147 
148         ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
149         if (ret > 0)
150                 ret = -ENOENT;
151         if (ret < 0)
152                 goto out;
153 
154         /*
155          * Sanity check - did we find the right item for this name?
156          * This should always succeed so error here will make the FS
157          * readonly.
158          */
159         if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],
160                                             ref_objectid,
161                                             name, name_len, &extref)) {
162                 btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL);
163                 ret = -EROFS;
164                 goto out;
165         }
166 
167         leaf = path->nodes[0];
168         item_size = btrfs_item_size_nr(leaf, path->slots[0]);
169         if (index)
170                 *index = btrfs_inode_extref_index(leaf, extref);
171 
172         if (del_len == item_size) {
173                 /*
174                  * Common case only one ref in the item, remove the
175                  * whole item.
176                  */
177                 ret = btrfs_del_item(trans, root, path);
178                 goto out;
179         }
180 
181         ptr = (unsigned long)extref;
182         item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
183 
184         memmove_extent_buffer(leaf, ptr, ptr + del_len,
185                               item_size - (ptr + del_len - item_start));
186 
187         btrfs_truncate_item(root->fs_info, path, item_size - del_len, 1);
188 
189 out:
190         btrfs_free_path(path);
191 
192         return ret;
193 }
194 
195 int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
196                         struct btrfs_root *root,
197                         const char *name, int name_len,
198                         u64 inode_objectid, u64 ref_objectid, u64 *index)
199 {
200         struct btrfs_path *path;
201         struct btrfs_key key;
202         struct btrfs_inode_ref *ref;
203         struct extent_buffer *leaf;
204         unsigned long ptr;
205         unsigned long item_start;
206         u32 item_size;
207         u32 sub_item_len;
208         int ret;
209         int search_ext_refs = 0;
210         int del_len = name_len + sizeof(*ref);
211 
212         key.objectid = inode_objectid;
213         key.offset = ref_objectid;
214         key.type = BTRFS_INODE_REF_KEY;
215 
216         path = btrfs_alloc_path();
217         if (!path)
218                 return -ENOMEM;
219 
220         path->leave_spinning = 1;
221 
222         ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
223         if (ret > 0) {
224                 ret = -ENOENT;
225                 search_ext_refs = 1;
226                 goto out;
227         } else if (ret < 0) {
228                 goto out;
229         }
230         if (!btrfs_find_name_in_backref(path->nodes[0], path->slots[0],
231                                         name, name_len, &ref)) {
232                 ret = -ENOENT;
233                 search_ext_refs = 1;
234                 goto out;
235         }
236         leaf = path->nodes[0];
237         item_size = btrfs_item_size_nr(leaf, path->slots[0]);
238 
239         if (index)
240                 *index = btrfs_inode_ref_index(leaf, ref);
241 
242         if (del_len == item_size) {
243                 ret = btrfs_del_item(trans, root, path);
244                 goto out;
245         }
246         ptr = (unsigned long)ref;
247         sub_item_len = name_len + sizeof(*ref);
248         item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
249         memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
250                               item_size - (ptr + sub_item_len - item_start));
251         btrfs_truncate_item(root->fs_info, path, item_size - sub_item_len, 1);
252 out:
253         btrfs_free_path(path);
254 
255         if (search_ext_refs) {
256                 /*
257                  * No refs were found, or we could not find the
258                  * name in our ref array. Find and remove the extended
259                  * inode ref then.
260                  */
261                 return btrfs_del_inode_extref(trans, root, name, name_len,
262                                               inode_objectid, ref_objectid, index);
263         }
264 
265         return ret;
266 }
267 
268 /*
269  * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree.
270  *
271  * The caller must have checked against BTRFS_LINK_MAX already.
272  */
273 static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
274                                      struct btrfs_root *root,
275                                      const char *name, int name_len,
276                                      u64 inode_objectid, u64 ref_objectid, u64 index)
277 {
278         struct btrfs_inode_extref *extref;
279         int ret;
280         int ins_len = name_len + sizeof(*extref);
281         unsigned long ptr;
282         struct btrfs_path *path;
283         struct btrfs_key key;
284         struct extent_buffer *leaf;
285         struct btrfs_item *item;
286 
287         key.objectid = inode_objectid;
288         key.type = BTRFS_INODE_EXTREF_KEY;
289         key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
290 
291         path = btrfs_alloc_path();
292         if (!path)
293                 return -ENOMEM;
294 
295         path->leave_spinning = 1;
296         ret = btrfs_insert_empty_item(trans, root, path, &key,
297                                       ins_len);
298         if (ret == -EEXIST) {
299                 if (btrfs_find_name_in_ext_backref(path->nodes[0],
300                                                    path->slots[0],
301                                                    ref_objectid,
302                                                    name, name_len, NULL))
303                         goto out;
304 
305                 btrfs_extend_item(root->fs_info, path, ins_len);
306                 ret = 0;
307         }
308         if (ret < 0)
309                 goto out;
310 
311         leaf = path->nodes[0];
312         item = btrfs_item_nr(path->slots[0]);
313         ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char);
314         ptr += btrfs_item_size(leaf, item) - ins_len;
315         extref = (struct btrfs_inode_extref *)ptr;
316 
317         btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len);
318         btrfs_set_inode_extref_index(path->nodes[0], extref, index);
319         btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid);
320 
321         ptr = (unsigned long)&extref->name;
322         write_extent_buffer(path->nodes[0], name, ptr, name_len);
323         btrfs_mark_buffer_dirty(path->nodes[0]);
324 
325 out:
326         btrfs_free_path(path);
327         return ret;
328 }
329 
330 /* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
331 int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
332                            struct btrfs_root *root,
333                            const char *name, int name_len,
334                            u64 inode_objectid, u64 ref_objectid, u64 index)
335 {
336         struct btrfs_fs_info *fs_info = root->fs_info;
337         struct btrfs_path *path;
338         struct btrfs_key key;
339         struct btrfs_inode_ref *ref;
340         unsigned long ptr;
341         int ret;
342         int ins_len = name_len + sizeof(*ref);
343 
344         key.objectid = inode_objectid;
345         key.offset = ref_objectid;
346         key.type = BTRFS_INODE_REF_KEY;
347 
348         path = btrfs_alloc_path();
349         if (!path)
350                 return -ENOMEM;
351 
352         path->leave_spinning = 1;
353         path->skip_release_on_error = 1;
354         ret = btrfs_insert_empty_item(trans, root, path, &key,
355                                       ins_len);
356         if (ret == -EEXIST) {
357                 u32 old_size;
358 
359                 if (btrfs_find_name_in_backref(path->nodes[0], path->slots[0],
360                                                name, name_len, &ref))
361                         goto out;
362 
363                 old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
364                 btrfs_extend_item(fs_info, path, ins_len);
365                 ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
366                                      struct btrfs_inode_ref);
367                 ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
368                 btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
369                 btrfs_set_inode_ref_index(path->nodes[0], ref, index);
370                 ptr = (unsigned long)(ref + 1);
371                 ret = 0;
372         } else if (ret < 0) {
373                 if (ret == -EOVERFLOW) {
374                         if (btrfs_find_name_in_backref(path->nodes[0],
375                                                        path->slots[0],
376                                                        name, name_len, &ref))
377                                 ret = -EEXIST;
378                         else
379                                 ret = -EMLINK;
380                 }
381                 goto out;
382         } else {
383                 ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
384                                      struct btrfs_inode_ref);
385                 btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
386                 btrfs_set_inode_ref_index(path->nodes[0], ref, index);
387                 ptr = (unsigned long)(ref + 1);
388         }
389         write_extent_buffer(path->nodes[0], name, ptr, name_len);
390         btrfs_mark_buffer_dirty(path->nodes[0]);
391 
392 out:
393         btrfs_free_path(path);
394 
395         if (ret == -EMLINK) {
396                 struct btrfs_super_block *disk_super = fs_info->super_copy;
397                 /* We ran out of space in the ref array. Need to
398                  * add an extended ref. */
399                 if (btrfs_super_incompat_flags(disk_super)
400                     & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
401                         ret = btrfs_insert_inode_extref(trans, root, name,
402                                                         name_len,
403                                                         inode_objectid,
404                                                         ref_objectid, index);
405         }
406 
407         return ret;
408 }
409 
410 int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
411                              struct btrfs_root *root,
412                              struct btrfs_path *path, u64 objectid)
413 {
414         struct btrfs_key key;
415         int ret;
416         key.objectid = objectid;
417         key.type = BTRFS_INODE_ITEM_KEY;
418         key.offset = 0;
419 
420         ret = btrfs_insert_empty_item(trans, root, path, &key,
421                                       sizeof(struct btrfs_inode_item));
422         return ret;
423 }
424 
425 int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
426                        *root, struct btrfs_path *path,
427                        struct btrfs_key *location, int mod)
428 {
429         int ins_len = mod < 0 ? -1 : 0;
430         int cow = mod != 0;
431         int ret;
432         int slot;
433         struct extent_buffer *leaf;
434         struct btrfs_key found_key;
435 
436         ret = btrfs_search_slot(trans, root, location, path, ins_len, cow);
437         if (ret > 0 && location->type == BTRFS_ROOT_ITEM_KEY &&
438             location->offset == (u64)-1 && path->slots[0] != 0) {
439                 slot = path->slots[0] - 1;
440                 leaf = path->nodes[0];
441                 btrfs_item_key_to_cpu(leaf, &found_key, slot);
442                 if (found_key.objectid == location->objectid &&
443                     found_key.type == location->type) {
444                         path->slots[0]--;
445                         return 0;
446                 }
447         }
448         return ret;
449 }
450 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp