Re: [PATCH] btrfs orphan support

2008-07-10 Thread Chris Mason
On Wed, 2008-07-09 at 14:43 -0400, Josef Bacik wrote:
 Hello,
 
 This patch makes it so btrfs can handle unlink's and truncates that are
 interrupted.  On unlink/truncate an orphan item is added with the location of
 the inode.  When the truncation/deletion is completed the orphan item is
 removed.  If a crash happens in between the orphaned inodes are processed at
 root lookup time.  This also catches the case where the inode deletion may 
 have
 occured but the orphan item wasn't removed.  Tested with a bunch of stuff to
 make sure everything is working.  Thank you,
 

Fantastic, thanks Josef.  A few comments below.
 d so it also defines (optimal)
 @@ -621,6 +625,10 @@ struct btrfs_root {
  
   /* the dirty list is only used by non-reference counted roots */
   struct list_head dirty_list;
 +
 + /* orphan crap */

Crap is worse than no comments at all ;)

  
 +int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
 +  struct btrfs_root *root, u64 offset,
 +  struct btrfs_key *location)
 +{
 + struct btrfs_disk_key disk_key;
 + struct btrfs_dir_item *dir_item;
 + struct btrfs_path *path;
 + struct btrfs_key key;
 + struct extent_buffer *leaf;
 + int ret = 0;
 + u32 data_size;
 +
 + key.objectid = BTRFS_ORPHAN_OBJECTID;
 + btrfs_set_key_type(key, BTRFS_ORPHAN_ITEM_KEY);
 + key.offset = offset;
 +
 + path = btrfs_alloc_path();
 + if (!path)
 + return -ENOMEM;
 +
 + data_size = sizeof(*dir_item);
 + dir_item = insert_with_overflow(trans, root, path, key,
 + data_size, , 0);

I thought your plan to move away from dir items would use a new item
type completely.

We only really need to store the objectid of the inode, which is already
encoded in the key offset field.  So, you could try an 0 length item and
we can fix up any problems that result in the btree code (I think it'll
tolerate this).

 +int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
 +{
 + struct btrfs_root *root = BTRFS_I(inode)-root;
 + struct btrfs_key key;
 + int ret = 0;
 +
 + mutex_lock(root-orphan_mutex);

This orphan mutex is going to serialize things pretty badly, since you
could be doing IO with it held.  Could you please make this a spin lock
held only during list manipulation?

The inode i_mutex should protect us from inserting/removing the same
inode at the same time into the orphan index.

Thanks again, this is great.

-chris


--
To unsubscribe from this list: send the line unsubscribe linux-btrfs in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] btrfs orphan support

2008-07-09 Thread Josef Bacik
Hello,

This patch makes it so btrfs can handle unlink's and truncates that are
interrupted.  On unlink/truncate an orphan item is added with the location of
the inode.  When the truncation/deletion is completed the orphan item is
removed.  If a crash happens in between the orphaned inodes are processed at
root lookup time.  This also catches the case where the inode deletion may have
occured but the orphan item wasn't removed.  Tested with a bunch of stuff to
make sure everything is working.  Thank you,

Signed-off-by: Josef Bacik [EMAIL PROTECTED]


diff -r 4c1c1ae077ef btrfs_inode.h
--- a/btrfs_inode.h Tue Jul 08 21:08:39 2008 -0400
+++ b/btrfs_inode.h Wed Jul 09 21:45:44 2008 -0400
@@ -37,6 +37,9 @@ struct btrfs_inode {
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
 
+   /* for keeping track of orphaned inodes */
+   struct list_head i_orphan;
+
u64 ordered_trans;
/*
 * transid of the trans_handle that last modified this inode
diff -r 4c1c1ae077ef ctree.h
--- a/ctree.h   Tue Jul 08 21:08:39 2008 -0400
+++ b/ctree.h   Wed Jul 09 21:45:44 2008 -0400
@@ -68,6 +68,9 @@ extern struct kmem_cache *btrfs_path_cac
 /* directory objectid inside the root tree */
 #define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL
 
+/* orhpan objectid for tracking unlinked/truncated files */
+#define BTRFS_ORPHAN_OBJECTID -5ULL
+
 /*
  * All files have objectids higher than this.
  */
@@ -102,7 +105,8 @@ extern struct kmem_cache *btrfs_path_cac
 #define BTRFS_FT_SOCK  6
 #define BTRFS_FT_SYMLINK   7
 #define BTRFS_FT_XATTR 8
-#define BTRFS_FT_MAX   9
+#define BTRFS_FT_ORPHAN9
+#define BTRFS_FT_MAX   10
 
 /*
  * the key defines the order in the tree, and so it also defines (optimal)
@@ -621,6 +625,10 @@ struct btrfs_root {
 
/* the dirty list is only used by non-reference counted roots */
struct list_head dirty_list;
+
+   /* orphan crap */
+   struct mutex orphan_mutex;
+   struct list_head orphan_list;
 };
 
 /*
@@ -632,6 +640,7 @@ struct btrfs_root {
 #define BTRFS_INODE_ITEM_KEY   1
 #define BTRFS_INODE_REF_KEY2
 #define BTRFS_XATTR_ITEM_KEY   8
+#define BTRFS_ORPHAN_ITEM_KEY  9
 /* reserve 2-15 close to the inode for later flexibility */
 
 /*
@@ -1523,6 +1532,15 @@ struct btrfs_dir_item *btrfs_lookup_xatt
  struct btrfs_path *path, u64 dir,
  const char *name, u16 name_len,
  int mod);
+int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
+struct btrfs_root *root, u64 offset,
+struct btrfs_key *location);
+struct btrfs_dir_item *btrfs_lookup_orphan_item(struct btrfs_trans_handle
+   *trans,
+   struct btrfs_root *root,
+   struct btrfs_path *path,
+   u64 offset, int mod);
+
 /* inode-map.c */
 int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
 struct btrfs_root *fs_root,
@@ -1617,6 +1635,7 @@ int btrfs_update_inode(struct btrfs_tran
 int btrfs_update_inode(struct btrfs_trans_handle *trans,
  struct btrfs_root *root,
  struct inode *inode);
+struct inode *btrfs_lookup_orphan_dir(struct btrfs_root *root);
 
 /* ioctl.c */
 long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
diff -r 4c1c1ae077ef dir-item.c
--- a/dir-item.cTue Jul 08 21:08:39 2008 -0400
+++ b/dir-item.cWed Jul 09 21:45:44 2008 -0400
@@ -181,6 +181,84 @@ out:
return 0;
 }
 
+int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
+struct btrfs_root *root, u64 offset,
+struct btrfs_key *location)
+{
+   struct btrfs_disk_key disk_key;
+   struct btrfs_dir_item *dir_item;
+   struct btrfs_path *path;
+   struct btrfs_key key;
+   struct extent_buffer *leaf;
+   int ret = 0;
+   u32 data_size;
+
+   key.objectid = BTRFS_ORPHAN_OBJECTID;
+   btrfs_set_key_type(key, BTRFS_ORPHAN_ITEM_KEY);
+   key.offset = offset;
+
+   path = btrfs_alloc_path();
+   if (!path)
+   return -ENOMEM;
+
+   data_size = sizeof(*dir_item);
+   dir_item = insert_with_overflow(trans, root, path, key,
+   data_size, , 0);
+   if (IS_ERR(dir_item)) {
+   ret = PTR_ERR(dir_item);
+   goto out;
+   }
+
+   leaf = path-nodes[0];
+   btrfs_cpu_key_to_disk(disk_key, location);
+   btrfs_set_dir_item_key(leaf, dir_item, disk_key);
+   btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_ORPHAN);
+