aoeblk.c 7.1 KB
Newer Older
1
/* Copyright (c) 2012 Coraid, Inc.  See COPYING for GPL terms. */
L
Linus Torvalds 已提交
2 3 4 5 6
/*
 * aoeblk.c
 * block device routines
 */

7
#include <linux/kernel.h>
L
Linus Torvalds 已提交
8 9
#include <linux/hdreg.h>
#include <linux/blkdev.h>
10
#include <linux/backing-dev.h>
L
Linus Torvalds 已提交
11 12
#include <linux/fs.h>
#include <linux/ioctl.h>
13
#include <linux/slab.h>
14
#include <linux/ratelimit.h>
L
Linus Torvalds 已提交
15 16
#include <linux/genhd.h>
#include <linux/netdevice.h>
17
#include <linux/mutex.h>
18
#include <linux/export.h>
19
#include <linux/moduleparam.h>
L
Linus Torvalds 已提交
20 21
#include "aoe.h"

22
static DEFINE_MUTEX(aoeblk_mutex);
23
static struct kmem_cache *buf_pool_cache;
L
Linus Torvalds 已提交
24

25 26 27 28 29 30
/* GPFS needs a larger value than the default. */
static int aoe_maxsectors;
module_param(aoe_maxsectors, int, 0644);
MODULE_PARM_DESC(aoe_maxsectors,
	"When nonzero, set the maximum number of sectors per I/O request");

31 32
static ssize_t aoedisk_show_state(struct device *dev,
				  struct device_attribute *attr, char *page)
L
Linus Torvalds 已提交
33
{
34
	struct gendisk *disk = dev_to_disk(dev);
L
Linus Torvalds 已提交
35 36 37 38 39
	struct aoedev *d = disk->private_data;

	return snprintf(page, PAGE_SIZE,
			"%s%s\n",
			(d->flags & DEVFL_UP) ? "up" : "down",
40
			(d->flags & DEVFL_KICKME) ? ",kickme" :
41 42
			(d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : "");
	/* I'd rather see nopen exported so we can ditch closewait */
L
Linus Torvalds 已提交
43
}
44 45
static ssize_t aoedisk_show_mac(struct device *dev,
				struct device_attribute *attr, char *page)
L
Linus Torvalds 已提交
46
{
47
	struct gendisk *disk = dev_to_disk(dev);
L
Linus Torvalds 已提交
48
	struct aoedev *d = disk->private_data;
49
	struct aoetgt *t = d->targets[0];
L
Linus Torvalds 已提交
50

51 52
	if (t == NULL)
		return snprintf(page, PAGE_SIZE, "none\n");
53
	return snprintf(page, PAGE_SIZE, "%pm\n", t->addr);
L
Linus Torvalds 已提交
54
}
55 56
static ssize_t aoedisk_show_netif(struct device *dev,
				  struct device_attribute *attr, char *page)
L
Linus Torvalds 已提交
57
{
58
	struct gendisk *disk = dev_to_disk(dev);
L
Linus Torvalds 已提交
59
	struct aoedev *d = disk->private_data;
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
	struct net_device *nds[8], **nd, **nnd, **ne;
	struct aoetgt **t, **te;
	struct aoeif *ifp, *e;
	char *p;

	memset(nds, 0, sizeof nds);
	nd = nds;
	ne = nd + ARRAY_SIZE(nds);
	t = d->targets;
	te = t + NTARGETS;
	for (; t < te && *t; t++) {
		ifp = (*t)->ifs;
		e = ifp + NAOEIFS;
		for (; ifp < e && ifp->nd; ifp++) {
			for (nnd = nds; nnd < nd; nnd++)
				if (*nnd == ifp->nd)
					break;
			if (nnd == nd && nd != ne)
				*nd++ = ifp->nd;
		}
	}
L
Linus Torvalds 已提交
81

82 83 84 85 86 87 88 89 90
	ne = nd;
	nd = nds;
	if (*nd == NULL)
		return snprintf(page, PAGE_SIZE, "none\n");
	for (p = page; nd < ne; nd++)
		p += snprintf(p, PAGE_SIZE - (p-page), "%s%s",
			p == page ? "" : ",", (*nd)->name);
	p += snprintf(p, PAGE_SIZE - (p-page), "\n");
	return p-page;
L
Linus Torvalds 已提交
91
}
92
/* firmware version */
93 94
static ssize_t aoedisk_show_fwver(struct device *dev,
				  struct device_attribute *attr, char *page)
95
{
96
	struct gendisk *disk = dev_to_disk(dev);
97 98 99 100
	struct aoedev *d = disk->private_data;

	return snprintf(page, PAGE_SIZE, "0x%04x\n", (unsigned int) d->fw_ver);
}
L
Linus Torvalds 已提交
101

102 103 104 105
static DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL);
static DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL);
static DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL);
static struct device_attribute dev_attr_firmware_version = {
106
	.attr = { .name = "firmware-version", .mode = S_IRUGO },
107
	.show = aoedisk_show_fwver,
108
};
L
Linus Torvalds 已提交
109

110
static struct attribute *aoe_attrs[] = {
111 112 113 114 115
	&dev_attr_state.attr,
	&dev_attr_mac.attr,
	&dev_attr_netif.attr,
	&dev_attr_firmware_version.attr,
	NULL,
116 117 118 119 120 121 122
};

static const struct attribute_group attr_group = {
	.attrs = aoe_attrs,
};

static int
L
Linus Torvalds 已提交
123 124
aoedisk_add_sysfs(struct aoedev *d)
{
125
	return sysfs_create_group(&disk_to_dev(d->gd)->kobj, &attr_group);
L
Linus Torvalds 已提交
126 127 128 129
}
void
aoedisk_rm_sysfs(struct aoedev *d)
{
130
	sysfs_remove_group(&disk_to_dev(d->gd)->kobj, &attr_group);
L
Linus Torvalds 已提交
131 132 133
}

static int
A
Al Viro 已提交
134
aoeblk_open(struct block_device *bdev, fmode_t mode)
L
Linus Torvalds 已提交
135
{
A
Al Viro 已提交
136
	struct aoedev *d = bdev->bd_disk->private_data;
L
Linus Torvalds 已提交
137 138
	ulong flags;

139
	mutex_lock(&aoeblk_mutex);
L
Linus Torvalds 已提交
140 141 142 143
	spin_lock_irqsave(&d->lock, flags);
	if (d->flags & DEVFL_UP) {
		d->nopen++;
		spin_unlock_irqrestore(&d->lock, flags);
144
		mutex_unlock(&aoeblk_mutex);
L
Linus Torvalds 已提交
145 146 147
		return 0;
	}
	spin_unlock_irqrestore(&d->lock, flags);
148
	mutex_unlock(&aoeblk_mutex);
L
Linus Torvalds 已提交
149 150 151 152
	return -ENODEV;
}

static int
A
Al Viro 已提交
153
aoeblk_release(struct gendisk *disk, fmode_t mode)
L
Linus Torvalds 已提交
154
{
A
Al Viro 已提交
155
	struct aoedev *d = disk->private_data;
L
Linus Torvalds 已提交
156 157 158 159
	ulong flags;

	spin_lock_irqsave(&d->lock, flags);

160
	if (--d->nopen == 0) {
L
Linus Torvalds 已提交
161 162 163 164 165 166 167 168 169
		spin_unlock_irqrestore(&d->lock, flags);
		aoecmd_cfg(d->aoemajor, d->aoeminor);
		return 0;
	}
	spin_unlock_irqrestore(&d->lock, flags);

	return 0;
}

170
static void
171
aoeblk_request(struct request_queue *q)
L
Linus Torvalds 已提交
172 173
{
	struct aoedev *d;
174
	struct request *rq;
L
Linus Torvalds 已提交
175

176
	d = q->queuedata;
L
Linus Torvalds 已提交
177
	if ((d->flags & DEVFL_UP) == 0) {
178
		pr_info_ratelimited("aoe: device %ld.%d is not up\n",
E
Ed L. Cashin 已提交
179
			d->aoemajor, d->aoeminor);
180 181 182 183
		while ((rq = blk_peek_request(q))) {
			blk_start_request(rq);
			aoe_end_request(d, rq, 1);
		}
184
		return;
L
Linus Torvalds 已提交
185
	}
186
	aoecmd_work(d);
L
Linus Torvalds 已提交
187 188 189
}

static int
190
aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
L
Linus Torvalds 已提交
191
{
192
	struct aoedev *d = bdev->bd_disk->private_data;
L
Linus Torvalds 已提交
193 194

	if ((d->flags & DEVFL_UP) == 0) {
E
Ed L. Cashin 已提交
195
		printk(KERN_ERR "aoe: disk not up\n");
L
Linus Torvalds 已提交
196 197 198
		return -ENODEV;
	}

199 200 201 202
	geo->cylinders = d->geo.cylinders;
	geo->heads = d->geo.heads;
	geo->sectors = d->geo.sectors;
	return 0;
L
Linus Torvalds 已提交
203 204
}

205
static const struct block_device_operations aoe_bdops = {
A
Al Viro 已提交
206 207
	.open = aoeblk_open,
	.release = aoeblk_release,
208
	.getgeo = aoeblk_getgeo,
L
Linus Torvalds 已提交
209 210 211 212 213 214 215 216 217
	.owner = THIS_MODULE,
};

/* alloc_disk and add_disk can sleep */
void
aoeblk_gdalloc(void *vp)
{
	struct aoedev *d = vp;
	struct gendisk *gd;
218 219 220
	mempool_t *mp;
	struct request_queue *q;
	enum { KB = 1024, MB = KB * KB, READ_AHEAD = 2 * MB, };
L
Linus Torvalds 已提交
221 222 223 224
	ulong flags;

	gd = alloc_disk(AOE_PARTITIONS);
	if (gd == NULL) {
225
		pr_err("aoe: cannot allocate disk structure for %ld.%d\n",
E
Ed L. Cashin 已提交
226
			d->aoemajor, d->aoeminor);
227
		goto err;
L
Linus Torvalds 已提交
228 229
	}

230 231 232
	mp = mempool_create(MIN_BUFS, mempool_alloc_slab, mempool_free_slab,
		buf_pool_cache);
	if (mp == NULL) {
233
		printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%d\n",
E
Ed L. Cashin 已提交
234
			d->aoemajor, d->aoeminor);
235
		goto err_disk;
L
Linus Torvalds 已提交
236
	}
237 238 239 240 241 242 243
	q = blk_init_queue(aoeblk_request, &d->lock);
	if (q == NULL) {
		pr_err("aoe: cannot allocate block queue for %ld.%d\n",
			d->aoemajor, d->aoeminor);
		mempool_destroy(mp);
		goto err_disk;
	}
L
Linus Torvalds 已提交
244

245 246
	d->blkq = blk_alloc_queue(GFP_KERNEL);
	if (!d->blkq)
247
		goto err_mempool;
248
	d->blkq->backing_dev_info.name = "aoe";
249 250
	if (bdi_init(&d->blkq->backing_dev_info))
		goto err_blkq;
251
	spin_lock_irqsave(&d->lock, flags);
252
	blk_queue_max_hw_sectors(d->blkq, BLK_DEF_MAX_SECTORS);
253 254 255 256 257
	q->backing_dev_info.ra_pages = READ_AHEAD / PAGE_CACHE_SIZE;
	d->bufpool = mp;
	d->blkq = gd->queue = q;
	q->queuedata = d;
	d->gd = gd;
258 259
	if (aoe_maxsectors)
		blk_queue_max_hw_sectors(q, aoe_maxsectors);
L
Linus Torvalds 已提交
260
	gd->major = AOE_MAJOR;
261
	gd->first_minor = d->sysminor;
L
Linus Torvalds 已提交
262 263
	gd->fops = &aoe_bdops;
	gd->private_data = d;
264
	set_capacity(gd, d->ssize);
265
	snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d",
L
Linus Torvalds 已提交
266 267
		d->aoemajor, d->aoeminor);

268
	d->flags &= ~DEVFL_GDALLOC;
L
Linus Torvalds 已提交
269 270 271 272 273 274
	d->flags |= DEVFL_UP;

	spin_unlock_irqrestore(&d->lock, flags);

	add_disk(gd);
	aoedisk_add_sysfs(d);
275 276
	return;

277 278 279
err_blkq:
	blk_cleanup_queue(d->blkq);
	d->blkq = NULL;
280 281 282 283 284 285 286 287
err_mempool:
	mempool_destroy(d->bufpool);
err_disk:
	put_disk(gd);
err:
	spin_lock_irqsave(&d->lock, flags);
	d->flags &= ~DEVFL_GDALLOC;
	spin_unlock_irqrestore(&d->lock, flags);
L
Linus Torvalds 已提交
288 289 290 291 292 293 294 295 296 297 298
}

void
aoeblk_exit(void)
{
	kmem_cache_destroy(buf_pool_cache);
}

int __init
aoeblk_init(void)
{
299
	buf_pool_cache = kmem_cache_create("aoe_bufs",
L
Linus Torvalds 已提交
300
					   sizeof(struct buf),
301
					   0, 0, NULL);
L
Linus Torvalds 已提交
302 303 304 305 306 307
	if (buf_pool_cache == NULL)
		return -ENOMEM;

	return 0;
}