lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Thu, 16 Dec 2010 23:01:13 +0800
From:	Hillf Danton <dhillf@...il.com>
To:	linux-kernel@...r.kernel.org
Subject: [PATCH] replace idr in block layer SCSI generic (bsg) driver with
 kzalloced buffer

Kernel library, idr, is used in bsg for storing and managing minors of
registered block queue.

In this work idr is replaced with kzalloced buffer, storing and managing
minors with cached info. The advantage looks that
1) it is not monstrous, and
2) it is faster when allocating, looking up and removing minors.

And disadvantage is that is not old.

Signed-off-by: Hillf Danton <dhillf@...il.com>
---

--- a/block/bsg.c	2010-11-01 19:54:12.000000000 +0800
+++ b/block/bsg.c	2010-12-16 22:14:54.000000000 +0800
@@ -18,7 +18,6 @@
 #include <linux/jiffies.h>
 #include <linux/percpu.h>
 #include <linux/uio.h>
-#include <linux/idr.h>
 #include <linux/bsg.h>
 #include <linux/slab.h>

@@ -64,7 +63,6 @@ enum {
 #endif

 static DEFINE_MUTEX(bsg_mutex);
-static DEFINE_IDR(bsg_minor_idr);

 #define BSG_LIST_ARRAY_SIZE	8
 static struct hlist_head bsg_device_list[BSG_LIST_ARRAY_SIZE];
@@ -88,6 +86,25 @@ struct bsg_command {
 	char sense[SCSI_SENSE_BUFFERSIZE];
 };

+struct bsg_idr {
+	/* cached info of freed minors */
+	int	left, right;
+	/* pointer for getting new minor from buf */
+	int	index;
+	/* house-keeping info buf */
+	int	used, alloc;
+	/* kzalloced buffer for storing registered minors */
+	void	**buf;
+};
+
+static struct bsg_idr	bsg_minor_idr;
+
+/* methods of bsg idr */
+static void *bsg_idr_find(struct bsg_idr *, unsigned);
+static void bsg_idr_remove(struct bsg_idr *, int);
+static int bsg_idr_get_new(struct bsg_idr *, void *);
+
+
 static void bsg_free_command(struct bsg_command *bc)
 {
 	struct bsg_device *bd = bc->bd;
@@ -819,7 +836,7 @@ static struct bsg_device *bsg_get_device
 	 * find the class device
 	 */
 	mutex_lock(&bsg_mutex);
-	bcd = idr_find(&bsg_minor_idr, iminor(inode));
+	bcd = bsg_idr_find(&bsg_minor_idr, iminor(inode));
 	if (bcd)
 		kref_get(&bcd->ref);
 	mutex_unlock(&bsg_mutex);
@@ -968,6 +985,77 @@ static const struct file_operations bsg_
 	.llseek		=	default_llseek,
 };

+static void *bsg_idr_find(struct bsg_idr *idr, unsigned minor)
+{
+	if (minor < (idr->alloc / sizeof(void *)))
+		return idr->buf[minor];
+
+	return NULL;
+}
+
+static void bsg_idr_remove(struct bsg_idr idr*, int minor)
+{
+	if (idr->left == BSG_MAX_DEVS)
+		idr->left = minor;
+	else if (idr->right == BSG_MAX_DEVS)
+		idr->right = minor;
+
+	idr->used--;
+	idr->buf[minor] = 0;
+}
+
+static int bsg_idr_get_new(struct bsg_idr *idr, void *bcd)
+{
+	int minor;
+
+	if (idr->used >= BSG_MAX_DEVS)
+		return -ENOSPC;
+
+	if (idr->used >= (idr->alloc / sizeof(void *))) {
+		void **buf;
+
+		buf = kzalloc(idr->alloc + PAGE_SIZE, GFP_KERNEL);
+		if (! buf)
+			return -ENOMEM;
+
+		memcpy(buf, idr->buf, idr->alloc);
+		kfree(idr->buf);
+		idr->buf = buf;
+		idr->alloc += PAGE_SIZE;
+	}
+
+	if (idr->left != BSG_MAX_DEVS) {
+		minor = idr->left;
+		idr->left = BSG_MAX_DEVS;
+	}
+	else if (idr->right != BSG_MAX_DEVS) {
+		minor = idr->right;
+		idr->right = BSG_MAX_DEVS;
+	}
+	else {
+		int i;
+		int cnt = idr->alloc / sizeof(void *);
+
+		for (minor = idr->index, i = 0; i < cnt; i++) {
+			if (minor == cnt)
+				minor = 1;
+			if (! idr->buf[minor])
+				break;
+			minor++;
+		}
+
+		if (i == cnt)
+			return -ENOSPC;
+
+		idr->index = minor + 1;
+	}
+
+	idr->used++;
+	idr->buf[minor] = bcd;
+
+	return minor;
+}
+
 void bsg_unregister_queue(struct request_queue *q)
 {
 	struct bsg_class_device *bcd = &q->bsg_dev;
@@ -976,7 +1064,7 @@ void bsg_unregister_queue(struct request
 		return;

 	mutex_lock(&bsg_mutex);
-	idr_remove(&bsg_minor_idr, bcd->minor);
+	bsg_idr_remove(&bsg_minor_idr, bcd->minor);
 	sysfs_remove_link(&q->kobj, "bsg");
 	device_unregister(bcd->class_dev);
 	bcd->class_dev = NULL;
@@ -1010,22 +1098,10 @@ int bsg_register_queue(struct request_qu

 	mutex_lock(&bsg_mutex);

-	ret = idr_pre_get(&bsg_minor_idr, GFP_KERNEL);
-	if (!ret) {
-		ret = -ENOMEM;
-		goto unlock;
-	}
-
-	ret = idr_get_new(&bsg_minor_idr, bcd, &minor);
+	minor = ret = bsg_idr_get_new(&bsg_minor_idr, bcd);
 	if (ret < 0)
 		goto unlock;

-	if (minor >= BSG_MAX_DEVS) {
-		printk(KERN_ERR "bsg: too many bsg devices\n");
-		ret = -EINVAL;
-		goto remove_idr;
-	}
-
 	bcd->minor = minor;
 	bcd->queue = q;
 	bcd->parent = get_device(parent);
@@ -1052,8 +1128,7 @@ unregister_class_dev:
 	device_unregister(class_dev);
 put_dev:
 	put_device(parent);
-remove_idr:
-	idr_remove(&bsg_minor_idr, minor);
+	bsg_idr_remove(&bsg_minor_idr, minor);
 unlock:
 	mutex_unlock(&bsg_mutex);
 	return ret;
@@ -1067,16 +1142,36 @@ static char *bsg_devnode(struct device *
 	return kasprintf(GFP_KERNEL, "bsg/%s", dev_name(dev));
 }

+static int __init bsg_init_idr(struct bsg_idr *idr)
+{
+	idr->buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (! idr->buf)
+		return -ENOMEM;
+
+	idr->alloc = PAGE_SIZE;
+	idr->used = 0;
+	idr->left = 1;
+	idr->right = 2;
+	idr->index = 3;
+
+	return 0;
+}
+
 static int __init bsg_init(void)
 {
 	int ret, i;
 	dev_t devid;

+	ret = bsg_init_idr(&bsg_minor_idr);
+	if (ret)
+		return ret;
+
 	bsg_cmd_cachep = kmem_cache_create("bsg_cmd",
 				sizeof(struct bsg_command), 0, 0, NULL);
 	if (!bsg_cmd_cachep) {
 		printk(KERN_ERR "bsg: failed creating slab cache\n");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto destroy_idr;
 	}

 	for (i = 0; i < BSG_LIST_ARRAY_SIZE; i++)
@@ -1109,6 +1204,8 @@ destroy_bsg_class:
 	class_destroy(bsg_class);
 destroy_kmemcache:
 	kmem_cache_destroy(bsg_cmd_cachep);
+destroy_idr:
+	kfree(bsg_minor_idr.buf);
 	return ret;
 }
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ