diff mbox

BTRFS_IOC_TREE_SEARCH: store and use the last key found

Message ID 201012142005.51289.kreijack@libero.it (mailing list archive)
State New, archived
Headers show

Commit Message

Goffredo Baroncelli Dec. 14, 2010, 7:05 p.m. UTC
None
diff mbox

Patch

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index f87552a..52075ed 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1134,11 +1134,11 @@  advance_key:
 	if (key->offset < (u64)-1 && key->offset < sk->max_offset)
 		key->offset++;
 	else if (key->type < (u8)-1 && key->type < sk->max_type) {
-		key->offset = 0;
+		key->offset = sk->min_offset;
 		key->type++;
 	} else if (key->objectid < (u64)-1 && key->objectid < sk-
>max_objectid) {
-		key->offset = 0;
-		key->type = 0;
+		key->offset = sk->min_offset;
+		key->type = sk->min_type;
 		key->objectid++;
 	} else
 		ret = 1;
@@ -1180,9 +1180,9 @@  static noinline int search_ioctl(struct inode *inode,
 		}
 	}
 
-	key.objectid = sk->min_objectid;
-	key.type = sk->min_type;
-	key.offset = sk->min_offset;
+	key.objectid = max(sk->start_objectid, sk->min_objectid);
+	key.type = max(sk->start_type,sk->min_type);
+	key.offset = max(sk->start_offset, sk->min_offset);
 
 	max_key.objectid = sk->max_objectid;
 	max_key.type = sk->max_type;
@@ -1207,6 +1207,11 @@  static noinline int search_ioctl(struct inode *inode,
 	}
 	ret = 0;
 err:
+	/* save the key for an hypothetic next iteration */
+	sk->start_objectid = key.objectid;
+	sk->start_type = key.type;
+	sk->start_offset = key.offset;
+
 	sk->nr_items = num_found;
 	btrfs_free_path(path);
 	return ret;
@@ -1234,6 +1239,39 @@  static noinline int btrfs_ioctl_tree_search(struct file 
*file,
 	return ret;
 }
 
+static noinline int btrfs_ioctl_tree_search_old(struct file *file,
+					   void __user *argp)
+{
+	struct btrfs_ioctl_search_args *args;
+	struct inode *inode;
+	int ret;
+
+	printk(KERN_WARNING "BTRFS: Pid=%d(%s) is using the buggy "
+			"BTRFS_IOC_TREE_SEARCH_V0 ioctl\n", 
+			current->pid, current->comm);
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	args = memdup_user(argp, sizeof(*args));
+	if (IS_ERR(args))
+		return PTR_ERR(args);
+
+	inode = fdentry(file)->d_inode;
+
+	/* for compatibility */
+	args->key.start_objectid = 0;
+	args->key.start_type = 0;
+	args->key.start_offset = 0;
+
+	ret = search_ioctl(inode, args);
+	if (ret == 0 && copy_to_user(argp, args, sizeof(*args)))
+		ret = -EFAULT;
+	kfree(args);
+	return ret;
+}
+
+
 /*
  * Search INODE_REFs to identify path name of 'dirid' directory
  * in a 'tree_id' tree. and sets path name to 'name'.
@@ -2286,6 +2324,8 @@  long btrfs_ioctl(struct file *file, unsigned int
 		return btrfs_ioctl_trans_start(file);
 	case BTRFS_IOC_TRANS_END:
 		return btrfs_ioctl_trans_end(file);
+	case BTRFS_IOC_TREE_SEARCH_V0:
+		return btrfs_ioctl_tree_search_old(file, argp);
 	case BTRFS_IOC_TREE_SEARCH:
 		return btrfs_ioctl_tree_search(file, argp);
 	case BTRFS_IOC_INO_LOOKUP:
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index c344d12..41dfde8 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -74,12 +74,12 @@  struct btrfs_ioctl_search_key {
 	 */
 	__u32 nr_items;
 
-	/* align to 64 bits */
-	__u32 unused;
+	/* starting search key fields */
+	__u32 start_type;
+	__u64 start_objectid;
+	__u64 start_offset;
 
 	/* some extra for later */
-	__u64 unused1;
-	__u64 unused2;
 	__u64 unused3;
 	__u64 unused4;
 };
@@ -182,7 +182,12 @@  struct btrfs_ioctl_space_args {
 				struct btrfs_ioctl_vol_args)
 #define BTRFS_IOC_DEFRAG_RANGE _IOW(BTRFS_IOCTL_MAGIC, 16, \
 				struct btrfs_ioctl_defrag_range_args)
-#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
+
+/* buggy, don't use */
+
+#define BTRFS_IOC_TREE_SEARCH_V0 _IOWR(BTRFS_IOCTL_MAGIC, 17, \
+				   struct btrfs_ioctl_search_args)
+#define BTRFS_IOC_TREE_SEARCH_V1 _IOWR(BTRFS_IOCTL_MAGIC, 25, \
 				   struct btrfs_ioctl_search_args)
 #define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
 				   struct btrfs_ioctl_ino_lookup_args)