Commit 9c976399 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] nbd: enhanced diagnostics support

From: Lou Langholtz <ldl@aros.net>

This third patch (for enhancing diagnostics support) applies incrementally
after my last LKML'd patch (for cosmetic changes).  These changes introduce
configurable KERN_DEBUG level printk output for a variety of different
things that the driver does and provides the framework for enhanced future
debugging support as well.
parent 52fa6e21
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
* memory corruption from module removal and possible memory corruption * memory corruption from module removal and possible memory corruption
* from sending/receiving disk data. <ldl@aros.net> * from sending/receiving disk data. <ldl@aros.net>
* 03-06-23 Cosmetic changes. <ldl@aros.net> * 03-06-23 Cosmetic changes. <ldl@aros.net>
* 03-06-23 Enhance diagnostics support. <ldl@aros.net>
* *
* possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
* why not: would need verify_area and friends, would share yet another * why not: would need verify_area and friends, would share yet another
...@@ -65,6 +66,23 @@ ...@@ -65,6 +66,23 @@
#define LO_MAGIC 0x68797548 #define LO_MAGIC 0x68797548
#ifdef NDEBUG
#define dprintk(flags, fmt...)
#else /* NDEBUG */
#define dprintk(flags, fmt...) do { \
if (debugflags & (flags)) printk(KERN_DEBUG fmt); \
} while (0)
#define DBG_OPEN 0x0001
#define DBG_RELEASE 0x0002
#define DBG_IOCTL 0x0004
#define DBG_INIT 0x0010
#define DBG_EXIT 0x0020
#define DBG_BLKDEV 0x0100
#define DBG_RX 0x0200
#define DBG_TX 0x0400
static unsigned int debugflags;
#endif /* NDEBUG */
static struct nbd_device nbd_dev[MAX_NBD]; static struct nbd_device nbd_dev[MAX_NBD];
/* /*
...@@ -79,19 +97,47 @@ static struct nbd_device nbd_dev[MAX_NBD]; ...@@ -79,19 +97,47 @@ static struct nbd_device nbd_dev[MAX_NBD];
*/ */
static spinlock_t nbd_lock = SPIN_LOCK_UNLOCKED; static spinlock_t nbd_lock = SPIN_LOCK_UNLOCKED;
#define DEBUG( s )
/* #define DEBUG( s ) printk( s )
*/
static int requests_in; static int requests_in;
static int requests_out; static int requests_out;
#ifndef NDEBUG
static const char *ioctl_cmd_to_ascii(int cmd)
{
switch (cmd) {
case NBD_SET_SOCK: return "set-sock";
case NBD_SET_BLKSIZE: return "set-blksize";
case NBD_SET_SIZE: return "set-size";
case NBD_DO_IT: return "do-it";
case NBD_CLEAR_SOCK: return "clear-sock";
case NBD_CLEAR_QUE: return "clear-que";
case NBD_PRINT_DEBUG: return "print-debug";
case NBD_SET_SIZE_BLOCKS: return "set-size-blocks";
case NBD_DISCONNECT: return "disconnect";
case BLKROSET: return "set-read-only";
case BLKFLSBUF: return "flush-buffer-cache";
}
return "unknown";
}
static const char *nbdcmd_to_ascii(int cmd)
{
switch (cmd) {
case NBD_CMD_READ: return "read";
case NBD_CMD_WRITE: return "write";
case NBD_CMD_DISC: return "disconnect";
}
return "invalid";
}
#endif /* NDEBUG */
static void nbd_end_request(struct request *req) static void nbd_end_request(struct request *req)
{ {
int uptodate = (req->errors == 0) ? 1 : 0; int uptodate = (req->errors == 0) ? 1 : 0;
request_queue_t *q = req->q; request_queue_t *q = req->q;
unsigned long flags; unsigned long flags;
dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name,
req, uptodate? "done": "failed");
#ifdef PARANOIA #ifdef PARANOIA
requests_out++; requests_out++;
#endif #endif
...@@ -193,8 +239,6 @@ void nbd_send_req(struct nbd_device *lo, struct request *req) ...@@ -193,8 +239,6 @@ void nbd_send_req(struct nbd_device *lo, struct request *req)
unsigned long size = req->nr_sectors << 9; unsigned long size = req->nr_sectors << 9;
struct socket *sock = lo->sock; struct socket *sock = lo->sock;
DEBUG("nbd: sending control, ");
request.magic = htonl(NBD_REQUEST_MAGIC); request.magic = htonl(NBD_REQUEST_MAGIC);
request.type = htonl(nbd_cmd(req)); request.type = htonl(nbd_cmd(req));
request.from = cpu_to_be64((u64) req->sector << 9); request.from = cpu_to_be64((u64) req->sector << 9);
...@@ -204,15 +248,19 @@ void nbd_send_req(struct nbd_device *lo, struct request *req) ...@@ -204,15 +248,19 @@ void nbd_send_req(struct nbd_device *lo, struct request *req)
down(&lo->tx_lock); down(&lo->tx_lock);
if (!sock || !lo->sock) { if (!sock || !lo->sock) {
printk(KERN_ERR "%s: Attempted sendmsg to closed socket\n", printk(KERN_ERR "%s: Attempted send on closed socket\n",
lo->disk->disk_name); lo->disk->disk_name);
goto error_out; goto error_out;
} }
dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n",
lo->disk->disk_name, req,
nbdcmd_to_ascii(nbd_cmd(req)),
req->sector << 9, req->nr_sectors << 9);
result = sock_xmit(sock, 1, &request, sizeof(request), result = sock_xmit(sock, 1, &request, sizeof(request),
(nbd_cmd(req) == NBD_CMD_WRITE)? MSG_MORE: 0); (nbd_cmd(req) == NBD_CMD_WRITE)? MSG_MORE: 0);
if (result <= 0) { if (result <= 0) {
printk(KERN_ERR "%s: Sendmsg failed for control (result %d)\n", printk(KERN_ERR "%s: Send control failed (result %d)\n",
lo->disk->disk_name, result); lo->disk->disk_name, result);
goto error_out; goto error_out;
} }
...@@ -229,7 +277,9 @@ void nbd_send_req(struct nbd_device *lo, struct request *req) ...@@ -229,7 +277,9 @@ void nbd_send_req(struct nbd_device *lo, struct request *req)
flags = 0; flags = 0;
if ((i < (bio->bi_vcnt - 1)) || bio->bi_next) if ((i < (bio->bi_vcnt - 1)) || bio->bi_next)
flags = MSG_MORE; flags = MSG_MORE;
DEBUG("data, "); dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n",
lo->disk->disk_name, req,
bvec->bv_len);
result = sock_send_bvec(sock, bvec, flags); result = sock_send_bvec(sock, bvec, flags);
if (result <= 0) { if (result <= 0) {
printk(KERN_ERR "%s: Send data failed (result %d)\n", printk(KERN_ERR "%s: Send data failed (result %d)\n",
...@@ -287,56 +337,57 @@ struct request *nbd_read_stat(struct nbd_device *lo) ...@@ -287,56 +337,57 @@ struct request *nbd_read_stat(struct nbd_device *lo)
struct request *req; struct request *req;
struct socket *sock = lo->sock; struct socket *sock = lo->sock;
DEBUG("reading control, ");
reply.magic = 0; reply.magic = 0;
result = sock_xmit(sock, 0, &reply, sizeof(reply), MSG_WAITALL); result = sock_xmit(sock, 0, &reply, sizeof(reply), MSG_WAITALL);
if (result <= 0) { if (result <= 0) {
printk(KERN_ERR "%s: Recv control failed (result %d)\n", printk(KERN_ERR "%s: Receive control failed (result %d)\n",
lo->disk->disk_name, result); lo->disk->disk_name, result);
lo->harderror = result; lo->harderror = result;
return NULL; return NULL;
} }
req = nbd_find_request(lo, reply.handle); req = nbd_find_request(lo, reply.handle);
if (req == NULL) { if (req == NULL) {
printk(KERN_ERR "%s: Unexpected reply (result %d)\n", printk(KERN_ERR "%s: Unexpected reply (%p)\n",
lo->disk->disk_name, result); lo->disk->disk_name, reply.handle);
lo->harderror = result; lo->harderror = result;
return NULL; return NULL;
} }
DEBUG("ok, ");
if (ntohl(reply.magic) != NBD_REPLY_MAGIC) { if (ntohl(reply.magic) != NBD_REPLY_MAGIC) {
printk(KERN_ERR "%s: Not enough magic (result %d)\n", printk(KERN_ERR "%s: Wrong magic (0x%lx)\n",
lo->disk->disk_name, result); lo->disk->disk_name,
(unsigned long)ntohl(reply.magic));
lo->harderror = result; lo->harderror = result;
return NULL; return NULL;
} }
if (ntohl(reply.error)) { if (ntohl(reply.error)) {
printk(KERN_ERR "%s: Other side returned error (result %d)\n", printk(KERN_ERR "%s: Other side returned error (%d)\n",
lo->disk->disk_name, result); lo->disk->disk_name, ntohl(reply.error));
req->errors++; req->errors++;
return req; return req;
} }
dprintk(DBG_RX, "%s: request %p: got reply\n",
lo->disk->disk_name, req);
if (nbd_cmd(req) == NBD_CMD_READ) { if (nbd_cmd(req) == NBD_CMD_READ) {
int i; int i;
struct bio *bio; struct bio *bio;
DEBUG("data, ");
rq_for_each_bio(bio, req) { rq_for_each_bio(bio, req) {
struct bio_vec *bvec; struct bio_vec *bvec;
bio_for_each_segment(bvec, bio, i) { bio_for_each_segment(bvec, bio, i) {
result = sock_recv_bvec(sock, bvec); result = sock_recv_bvec(sock, bvec);
if (result <= 0) { if (result <= 0) {
printk(KERN_ERR "%s: Recv data failed (result %d)\n", printk(KERN_ERR "%s: Receive data failed (result %d)\n",
lo->disk->disk_name, lo->disk->disk_name,
result); result);
lo->harderror = result; lo->harderror = result;
return NULL; return NULL;
} }
dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
lo->disk->disk_name, req, bvec->bv_len);
} }
} }
} }
DEBUG("done.\n");
return req; return req;
} }
...@@ -347,7 +398,7 @@ void nbd_do_it(struct nbd_device *lo) ...@@ -347,7 +398,7 @@ void nbd_do_it(struct nbd_device *lo)
BUG_ON(lo->magic != LO_MAGIC); BUG_ON(lo->magic != LO_MAGIC);
while ((req = nbd_read_stat(lo)) != NULL) while ((req = nbd_read_stat(lo)) != NULL)
nbd_end_request(req); nbd_end_request(req);
printk(KERN_ALERT "%s: req should never be null\n", printk(KERN_NOTICE "%s: req should never be null\n",
lo->disk->disk_name); lo->disk->disk_name);
return; return;
} }
...@@ -388,6 +439,8 @@ static void do_nbd_request(request_queue_t * q) ...@@ -388,6 +439,8 @@ static void do_nbd_request(request_queue_t * q)
struct nbd_device *lo; struct nbd_device *lo;
blkdev_dequeue_request(req); blkdev_dequeue_request(req);
dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%lx)\n",
req->rq_disk->disk_name, req, req->flags);
if (!(req->flags & REQ_CMD)) if (!(req->flags & REQ_CMD))
goto error_out; goto error_out;
...@@ -431,7 +484,7 @@ static void do_nbd_request(request_queue_t * q) ...@@ -431,7 +484,7 @@ static void do_nbd_request(request_queue_t * q)
nbd_send_req(lo, req); nbd_send_req(lo, req);
if (req->errors) { if (req->errors) {
printk(KERN_ERR "%s: nbd_send_req failed\n", printk(KERN_ERR "%s: Request send failed\n",
lo->disk->disk_name); lo->disk->disk_name);
spin_lock(&lo->queue_lock); spin_lock(&lo->queue_lock);
list_del_init(&req->queuelist); list_del_init(&req->queuelist);
...@@ -456,6 +509,9 @@ static void do_nbd_request(request_queue_t * q) ...@@ -456,6 +509,9 @@ static void do_nbd_request(request_queue_t * q)
static int nbd_open(struct inode *inode, struct file *file) static int nbd_open(struct inode *inode, struct file *file)
{ {
struct nbd_device *lo = inode->i_bdev->bd_disk->private_data; struct nbd_device *lo = inode->i_bdev->bd_disk->private_data;
dprintk(DBG_OPEN, "%s: nbd_open refcnt=%d\n", lo->disk->disk_name,
lo->refcnt);
lo->refcnt++; lo->refcnt++;
return 0; return 0;
} }
...@@ -463,11 +519,15 @@ static int nbd_open(struct inode *inode, struct file *file) ...@@ -463,11 +519,15 @@ static int nbd_open(struct inode *inode, struct file *file)
static int nbd_release(struct inode *inode, struct file *file) static int nbd_release(struct inode *inode, struct file *file)
{ {
struct nbd_device *lo = inode->i_bdev->bd_disk->private_data; struct nbd_device *lo = inode->i_bdev->bd_disk->private_data;
if (lo->refcnt <= 0)
printk(KERN_ALERT "%s: %s: refcount(%d) <= 0\n", if (lo->refcnt <= 0) {
lo->disk->disk_name, __FUNCTION__, lo->refcnt); printk(KERN_ALERT "%s: nbd_release: refcount(%d) <= 0\n",
lo->disk->disk_name, lo->refcnt);
BUG();
}
lo->refcnt--; lo->refcnt--;
/* N.B. Doesn't lo->file need an fput?? */ dprintk(DBG_RELEASE, "%s: nbd_release: refcnt=%d\n",
lo->disk->disk_name, lo->refcnt);
return 0; return 0;
} }
...@@ -479,6 +539,8 @@ static int nbd_ioctl(struct inode *inode, struct file *file, ...@@ -479,6 +539,8 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
struct request sreq ; struct request sreq ;
/* Anyone capable of this syscall can do *real bad* things */ /* Anyone capable of this syscall can do *real bad* things */
dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
...@@ -487,6 +549,13 @@ static int nbd_ioctl(struct inode *inode, struct file *file, ...@@ -487,6 +549,13 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name);
sreq.flags = REQ_SPECIAL; sreq.flags = REQ_SPECIAL;
nbd_cmd(&sreq) = NBD_CMD_DISC; nbd_cmd(&sreq) = NBD_CMD_DISC;
/*
* Set these to sane values in case server implementation
* fails to check the request type first and also to keep
* debugging output cleaner.
*/
sreq.sector = 0;
sreq.nr_sectors = 0;
if (!lo->sock) if (!lo->sock)
return -EINVAL; return -EINVAL;
nbd_send_req(lo, &sreq); nbd_send_req(lo, &sreq);
...@@ -607,7 +676,7 @@ static int __init nbd_init(void) ...@@ -607,7 +676,7 @@ static int __init nbd_init(void)
int i; int i;
if (sizeof(struct nbd_request) != 28) { if (sizeof(struct nbd_request) != 28) {
printk(KERN_CRIT "Sizeof nbd_request needs to be 28 in order to work!\n" ); printk(KERN_CRIT "nbd: Sizeof nbd_request needs to be 28 in order to work!\n" );
return -EIO; return -EIO;
} }
...@@ -633,9 +702,10 @@ static int __init nbd_init(void) ...@@ -633,9 +702,10 @@ static int __init nbd_init(void)
err = -EIO; err = -EIO;
goto out; goto out;
} }
#ifdef MODULE
printk("nbd: registered device at major %d\n", NBD_MAJOR); printk(KERN_INFO "nbd: registered device at major %d\n", NBD_MAJOR);
#endif dprintk(DBG_INIT, "nbd: debugflags=0x%x\n", debugflags);
devfs_mk_dir("nbd"); devfs_mk_dir("nbd");
for (i = 0; i < MAX_NBD; i++) { for (i = 0; i < MAX_NBD; i++) {
struct gendisk *disk = nbd_dev[i].disk; struct gendisk *disk = nbd_dev[i].disk;
...@@ -685,9 +755,7 @@ static void __exit nbd_cleanup(void) ...@@ -685,9 +755,7 @@ static void __exit nbd_cleanup(void)
} }
devfs_remove("nbd"); devfs_remove("nbd");
unregister_blkdev(NBD_MAJOR, "nbd"); unregister_blkdev(NBD_MAJOR, "nbd");
#ifdef MODULE printk(KERN_INFO "nbd: unregistered device at major %d\n", NBD_MAJOR);
printk("nbd: unregistered device at major %d\n", NBD_MAJOR);
#endif
} }
module_init(nbd_init); module_init(nbd_init);
...@@ -696,4 +764,7 @@ module_exit(nbd_cleanup); ...@@ -696,4 +764,7 @@ module_exit(nbd_cleanup);
MODULE_DESCRIPTION("Network Block Device"); MODULE_DESCRIPTION("Network Block Device");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#ifndef NDEBUG
MODULE_PARM(debugflags, "i");
MODULE_PARM_DESC(debugflags, "flags for controlling debug output");
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment