[RFC][PATCH 5/10] Get all extents information of specified inode number

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



- Get all extents information of specified inode number to calculate
  the combination of extents which should be moved to other block group.

Signed-off-by: Takashi Sato <t-sato@xxxxxxxxxxxxx>
Signed-off-by: Akira Fujita <a-fujita@xxxxxxxxxxxxx>
---
diff -X Online-Defrag_linux-2.6.19-rc6-git/Documentation/dontdiff -upNr Online-Defrag_linux-2.6.19-rc6-git-EXTENTS_INFO/fs/ext4/extents.c Online-Defrag_linux-2.6.19-rc6-git-MOVE_VICTIM/fs/ext4/extents.c
--- Online-Defrag_linux-2.6.19-rc6-git-EXTENTS_INFO/fs/ext4/extents.c	2007-06-20 08:50:57.000000000 +0900
+++ Online-Defrag_linux-2.6.19-rc6-git-MOVE_VICTIM/fs/ext4/extents.c	2007-06-20 08:27:44.000000000 +0900
@@ -43,6 +43,12 @@
 #include <linux/ext4_fs_extents.h>
 #include <asm/uaccess.h>
 
+#define DIO_CREDITS (EXT4_RESERVE_TRANS_BLOCKS + 32)
+#define EXT_SET_EXTENT_DATA(src, dest)  do {\
+		dest.block = le32_to_cpu(src->ee_block);\
+		dest.start = ext_pblock(src);\
+		dest.len = le16_to_cpu(src->ee_len);\
+					} while (0)
 /*
  * ext_pblock:
  * combine low and high parts of physical block number into ext4_fsblk_t
@@ -2479,6 +2485,121 @@ ext4_ext_next_extent(struct inode *inode
 }
 
 /**
+ * ext4_ext_extents_info() - get extents information
+ *
+ * @ext_info:                   pointer to ext4_extents_info
+ *  @ext_info->ino              describe an inode which is used to get extent
+ *                              information
+ *  @ext_info->max_entries:     defined by DEFRAG_MAX_ENT
+ *  @ext_info->entries:	        amount of extents (output)
+ *  @ext_info->ext[]:           array of extent (output)
+ *  @ext_info->offset:          starting block offset of targeted extent
+ *                              (file relative)
+ *
+ * @sb:                         for iget()
+ *
+ * This function returns 0 if next extent(s) exists,
+ * or returns 1 if next extent doesn't exist, otherwise returns error value.
+ * Called under truncate_mutex lock.
+ */
+static int ext4_ext_extents_info(struct ext4_extents_info *ext_info,
+				struct super_block *sb)
+{
+	struct ext4_ext_path *path = NULL;
+	struct ext4_extent *ext = NULL;
+	struct inode *inode = NULL;
+	unsigned long offset = ext_info->offset;
+	int max = ext_info->max_entries;
+	int is_last_extent = 0;
+	int depth = 0;
+	int entries = 0;
+	int err = 0;
+
+	inode = iget(sb, ext_info->ino);
+	if (!inode)
+		return -EACCES;
+
+	mutex_lock(&EXT4_I(inode)->truncate_mutex);
+
+	/* if a file doesn't exist*/
+	if ((!inode->i_nlink) || (inode->i_ino < 12) ||
+			!S_ISREG(inode->i_mode)) {
+		ext_info->entries = 0;
+		err = -ENOENT;
+		goto out;
+	}
+
+	path = ext4_ext_find_extent(inode, offset, NULL);
+	if (IS_ERR(path)) {
+		err = PTR_ERR(path);
+		path = NULL;
+ 		goto out;
+	}
+	depth = ext_depth(inode);
+	ext = path[depth].p_ext;
+	EXT_SET_EXTENT_DATA(ext, ext_info->ext[entries]);
+	entries = 1;
+
+	/*
+	 * The ioctl can return 'max' ext4_extent_data per a call,
+	 * so if @inode has > 'max' extents, we must get away here.
+	 */
+	while (entries < max) {
+		is_last_extent = ext4_ext_next_extent(inode, path, &ext);
+		/* found next extent (not the last one)*/
+		if (is_last_extent == 0) {
+			EXT_SET_EXTENT_DATA(ext, ext_info->ext[entries]);
+			entries++;
+
+			/*
+			 * If @inode has > 'max' extents,
+			 * this function should be called again,
+			 * (per a call, it can resolve only 'max' extents)
+			 * next time we have to start from 'max*n+1'th extent.
+			 */
+			if (entries == max) {
+				ext_info->offset =
+						le32_to_cpu(ext->ee_block) +
+						le32_to_cpu(ext->ee_len);
+				/* check the extent is the last one or not*/
+				is_last_extent =
+					ext4_ext_next_extent(inode, path, &ext);
+				if (is_last_extent) {
+					is_last_extent = 1;
+					err = is_last_extent;
+				} else if (is_last_extent < 0) {
+					/*ERR*/
+					err = is_last_extent;
+					goto out;
+				}
+				break;
+			}
+
+		/* the extent is the last one */
+		} else if (is_last_extent == 1) {
+			ext_info->offset = 0;
+			err = is_last_extent;
+			break;
+		} else {
+			/* ERR */
+			err = is_last_extent;
+			goto out;
+		}
+	}
+
+	ext_info->entries = entries;
+
+out:
+	if (path) {
+		ext4_ext_drop_refs(path);
+		kfree(path);
+	}
+	mutex_unlock(&EXT4_I(inode)->truncate_mutex);
+	iput(inode);
+	return err;
+}
+
+/**
  * ext4_ext_fblocks_distribution - Search free block distribution
  * @filp      target file
  * @ex_info   ext4_extents_info
@@ -2653,6 +2774,20 @@ int ext4_ext_ioctl(struct inode *inode, 
 		if (!err)
 			err = copy_to_user((struct ext4_extents_info*)arg,
 				&ext_info, sizeof(ext_info));
+	} else if (cmd == EXT4_IOC_EXTENTS_INFO) {
+		struct ext4_extents_info ext_info;
+
+		if (copy_from_user(&ext_info,
+				(struct ext4_extents_info __user *)arg,
+				sizeof(ext_info)))
+			return -EFAULT;
+
+		err = ext4_ext_extents_info(&ext_info, inode->i_sb);
+		if (err >= 0) {
+			if (copy_to_user((struct ext4_extents_info __user *)arg,
+				&ext_info, sizeof(ext_info)))
+				return -EFAULT;
+		}
 	} else if (cmd == EXT4_IOC_DEFRAG) {
 		struct ext4_ext_defrag_data defrag;
 

-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux