lkml.org 
[lkml]   [2001]   [Dec]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: Current NBD 'stuff'
    On 3 Dec 2001, Edward Muller wrote:

    > Anyone know where I can find the latest NBD stuff? Esp. client/server
    > code?

    I have the same question. Maybe the user-level stuff is not being
    actively maintained?

    However, since we couldn't find current versions of this stuff,
    my colleagues and I patched nbd-server and the nbd kernel module
    to fix a few bugs and to make them a little more robust. I'll
    attach my versions of those files (which I think are derived from
    Pavel's .14.tar.gz versions).


    > Oh ... And one more question what's the best 2.4.X kernel to use with
    > nbd?

    You'll want at least 2.4.4 (you'll probably want later than that for
    other reasons anyway) -- I think before that NBD was badly broken.

    --
    Paul Clements
    Paul.Clements@SteelEye.com

    Index: linux/2.4/drivers/block/nbd.c
    diff -u linux/2.4/drivers/block/nbd.c:1.1.1.9 linux/2.4/drivers/block/nbd.c:1.1.1.9.4.3
    --- linux/2.4/drivers/block/nbd.c:1.1.1.9 Fri Jun 29 16:31:25 2001
    +++ linux/2.4/drivers/block/nbd.c Tue Oct 2 13:34:03 2001
    @@ -91,17 +91,18 @@
    int result;
    struct msghdr msg;
    struct iovec iov;
    - unsigned long flags;
    - sigset_t oldset;
    + //unsigned long flags;
    + //sigset_t oldset;

    oldfs = get_fs();
    set_fs(get_ds());

    - spin_lock_irqsave(&current->sigmask_lock, flags);
    - oldset = current->blocked;
    - sigfillset(&current->blocked);
    - recalc_sigpending(current);
    - spin_unlock_irqrestore(&current->sigmask_lock, flags);
    + // JEJB: Allow signal interception
    + //spin_lock_irqsave(&current->sigmask_lock, flags);
    + //oldset = current->blocked;
    + //sigfillset(&current->blocked);
    + //recalc_sigpending(current);
    + //spin_unlock_irqrestore(&current->sigmask_lock, flags);


    do {
    @@ -122,6 +123,13 @@
    else
    result = sock_recvmsg(sock, &msg, size, 0);

    + // JEJB: Detect signal issue here
    + if(signal_pending(current)) {
    + printk(KERN_WARNING "NBD caught signal\n");
    + result = -EINTR;
    + break;
    + }
    +
    if (result <= 0) {
    #ifdef PARANOIA
    printk(KERN_ERR "NBD: %s - sock=%ld at buf=%ld, size=%d returned %d.\n",
    @@ -133,10 +141,11 @@
    buf += result;
    } while (size > 0);

    - spin_lock_irqsave(&current->sigmask_lock, flags);
    - current->blocked = oldset;
    - recalc_sigpending(current);
    - spin_unlock_irqrestore(&current->sigmask_lock, flags);
    + //JEJB: didn't modify signal mask, so no need to restore it
    + //spin_lock_irqsave(&current->sigmask_lock, flags);
    + //current->blocked = oldset;
    + //recalc_sigpending(current);
    + //spin_unlock_irqrestore(&current->sigmask_lock, flags);

    set_fs(oldfs);
    return result;
    @@ -333,8 +342,27 @@
    spin_unlock_irq(&io_request_lock);

    down (&lo->queue_lock);
    + if(!lo->file) {
    + up(&lo->queue_lock);
    + spin_lock_irq(&io_request_lock);
    + printk(KERN_ERR "NBD: FAIL BETWEEN ACCEPT AND SEMAPHORE, FILE LOST\n");
    + req->errors++;
    + nbd_end_request(req);
    + continue;
    + }
    +
    list_add(&req->queue, &lo->queue_head);
    nbd_send_req(lo->sock, req); /* Why does this block? */
    + if(req->errors) {
    + printk(KERN_ERR "NBD: NBD_SEND_REQ FAILED\n");
    + list_del(&req->queue);
    +
    + up(&lo->queue_lock);
    + spin_lock_irq(&io_request_lock);
    + nbd_end_request(req);
    +
    + continue;
    + }
    up (&lo->queue_lock);

    spin_lock_irq(&io_request_lock);
    @@ -384,12 +412,14 @@
    printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n");
    return -EBUSY;
    }
    - up(&lo->queue_lock);
    file = lo->file;
    - if (!file)
    + if (!file) {
    + up(&lo->queue_lock);
    return -EINVAL;
    + }
    lo->file = NULL;
    lo->sock = NULL;
    + up(&lo->queue_lock);
    fput(file);
    return 0;
    case NBD_SET_SOCK:
    @@ -430,9 +460,29 @@
    if (!lo->file)
    return -EINVAL;
    nbd_do_it(lo);
    + /* on return tidy up in case we have a signal */
    + printk(KERN_WARNING "NBD: nbd_do_it returned\n");
    + /* Forcibly shutdown the socket causing all listeners
    + * to error
    + *
    + * FIXME: This code is duplicated from sys_shutdown, but
    + * there should be a more generic interface rather than
    + * calling socket ops directly here */
    + lo->sock->ops->shutdown(lo->sock, 2);
    + down(&lo->queue_lock);
    + printk(KERN_WARNING "NBD: lock acquired\n");
    + nbd_clear_que(lo);
    + file = lo->file;
    + lo->file = NULL;
    + lo->sock = NULL;
    + up(&lo->queue_lock);
    + if(file)
    + fput(file);
    return lo->harderror;
    case NBD_CLEAR_QUE:
    + down(&lo->queue_lock);
    nbd_clear_que(lo);
    + up(&lo->queue_lock);
    return 0;
    #ifdef PARANOIA
    case NBD_PRINT_DEBUG:
    @@ -492,7 +542,7 @@
    return -EIO;
    }
    #ifdef MODULE
    - printk("nbd: registered device at major %d\n", MAJOR_NR);
    + printk("nbd: (version Steeleye-8) registered device at major %d\n", MAJOR_NR);
    #endif
    blksize_size[MAJOR_NR] = nbd_blksizes;
    blk_size[MAJOR_NR] = nbd_sizes;
    @@ -507,7 +557,7 @@
    init_MUTEX(&nbd_dev[i].queue_lock);
    nbd_blksizes[i] = 1024;
    nbd_blksize_bits[i] = 10;
    - nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */
    + nbd_bytesizes[i] = ((u64)0x7ffffc00) << 10; /* 2TB */
    nbd_sizes[i] = nbd_bytesizes[i] >> BLOCK_SIZE_BITS;
    register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops,
    nbd_bytesizes[i]>>9);/*
    * Network Block Device - server
    *
    * Copyright 1996-1998 Pavel Machek, distribute under GPL
    * <pavel@atrey.karlin.mff.cuni.cz>
    *
    * Version 1.0 - hopefully 64-bit-clean
    * Version 1.1 - merging enhancements from Josh Parsons, <josh@coombs.anu.edu.au>
    * Version 1.2 - autodetect size of block devices, thanx to Peter T. Breuer" <ptb@it.uc3m.es>
    */

    #define VERSION "1.3"
    #define GIGA (1*1024*1024*1024)

    /* use lseek64 exclusively */
    #define _LARGEFILE_SOURCE // Some more functions for correct standard I/O.
    #define _LARGEFILE64_SOURCE // Additional functionality from LFS for large files

    #include <sys/socket.h>
    #include <sys/stat.h>
    #include <netinet/tcp.h>
    #include <netinet/in.h> /* sockaddr_in, htons, in_addr */
    #include <netdb.h> /* hostent, gethostby*, getservby* */
    #include <syslog.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <arpa/inet.h>

    #define _IO(a,b)
    #define ISSERVER
    #define MY_NAME "nbd_server"
    #include "cliserv.h"
    #undef _IO
    /* Deep magic: ioctl.h defines _IO macro (at least on linux) */

    #include <sys/ioctl.h>
    #include <sys/mount.h> /* For BLKGETSIZE */

    // #define DODBG
    // #define DEBUG( a... ) printf( a )
    #define DEBUG( a... ) do { } while(0)


    inline void readit(int f, void *buf, int len)
    {
    int res;
    while (len > 0) {
    DEBUG("*");
    if ((res = read(f, buf, len)) <= 0)
    err("Read failed: %m");
    len -= res;
    buf += res;
    }
    }

    inline void writeit(int f, void *buf, int len)
    {
    int res;
    while (len > 0) {
    DEBUG("+");
    if ((res = write(f, buf, len)) <= 0)
    err("Write failed: %m");
    len -= res;
    buf += res;
    }
    }

    int port; /* Port I'm listening at */
    char *exportname; /* File I'm exporting */
    u64 exportsize = ~0, hunksize = ~0; /* ...and its length */
    int flags = 0;
    int export[1024];
    #define F_READONLY 1
    #define F_MULTIFILE 2

    void cmdline(int argc, char *argv[])
    {
    int i;

    if (argc < 3) {
    printf("This is nbd-server version " VERSION "\n");
    printf("Usage: port file_to_export [size][kKmM] [-r]\n"
    " -r read only\n"
    " if port is set to 0, stdin is used (for running from inetd)\n"
    " if file_to_export contains '%%s', it is substituted with IP\n"
    " address of machine trying to connect\n" );
    exit(0);
    }
    port = atoi(argv[1]);
    for (i = 3; i < argc; i++) {
    if (*argv[i] == '-') {
    switch (argv[i][1]) {
    case 'r':
    flags |= F_READONLY;
    break;
    case 'm':
    flags |= F_MULTIFILE;
    hunksize = 1*GIGA;
    break;
    }
    } else {
    u64 es;
    int last = strlen(argv[i])-1;
    char suffix = argv[i][last];
    if (suffix == 'k' || suffix == 'K' ||
    suffix == 'm' || suffix == 'M')
    argv[i][last] = '\0';
    es = (u64)atol(argv[i]);
    switch (suffix) {
    case 'm':
    case 'M': es <<= 10;
    case 'k':
    case 'K': es <<= 10;
    default : break;
    }
    exportsize = es;
    }
    }

    exportname = argv[2];
    }

    int connectme(int port)
    {
    struct sockaddr_in addrin;
    int addrinlen = sizeof(addrin);
    int net, sock;
    int size = 1;

    if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    err("socket: %m");
    // SteelEye change - reuse the port number
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &size, sizeof(int)) < 0)
    err("setsockopt: %m");

    DEBUG("Waiting for connections... bind, ");
    addrin.sin_family = AF_INET;
    addrin.sin_port = htons(port);
    addrin.sin_addr.s_addr = 0;
    if (bind(sock, (struct sockaddr *) &addrin, addrinlen) < 0)
    err("bind: %m");
    DEBUG("listen, ");
    if (listen(sock, 1) < 0)
    err("listen: %m");
    DEBUG("accept, ");
    if ((net = accept(sock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
    err("accept: %m");

    return net;
    }

    #define SEND writeit( net, &reply, sizeof( reply ));
    #define ERROR { reply.error = htonl(-1); SEND; reply.error = 0; lastpoint = -1; }

    u64 lastpoint = -1;

    void maybeseek(int handle, u64 a)
    {
    if (a > exportsize)
    err("Can not happen\n");
    if (lastpoint != a) {
    if (lseek64(handle, a, SEEK_SET) < 0)
    err("Can not seek locally!\n");
    lastpoint = a;
    } else {
    DEBUG("@");
    }
    }

    int expread(u64 a, char *buf, int len)
    {
    maybeseek(export[a/hunksize], a%hunksize);
    return (read(export[a/hunksize], buf, len) != len);
    }

    int expwrite(u64 a, char *buf, int len)
    {
    maybeseek(export[a/hunksize], a%hunksize);
    return (write(export[a/hunksize], buf, len) != len);
    }

    int mainloop(int net)
    {
    struct nbd_request request;
    struct nbd_reply reply;
    char zeros[300];
    int i = 0;
    u64 size_host;

    bzero(zeros, 290);
    if (write(net, INIT_PASSWD, 8) < 0)
    err("Negotiation failed: %m");
    cliserv_magic = htonll(cliserv_magic);
    if (write(net, &cliserv_magic, sizeof(cliserv_magic)) < 0)
    err("Negotiation failed: %m");
    size_host = htonll(exportsize);
    if (write(net, &size_host, 8) < 0)
    err("Negotiation failed: %m");
    if (write(net, zeros, 128) < 0)
    err("Negotiation failed: %m");

    DEBUG("Entering request loop!\n");
    reply.magic = htonl(NBD_REPLY_MAGIC);
    reply.error = 0;
    while (1) {
    /* SteelEye change - need dynamic buffer to work with elevator */
    static long max_nbd_request=131072; /* 128K */
    static char *buf=NULL;
    int len;

    #ifdef DODBG
    i++;
    printf("%d: ", i);
    #endif

    readit(net, &request, sizeof(request));
    request.from = ntohll(request.from);
    request.type = ntohl(request.type);
    len = ntohl(request.len);

    if (request.magic != htonl(NBD_REQUEST_MAGIC))
    err("Not enough magic.");

    DEBUG("request len: %d bytes\n", len);

    while (len > max_nbd_request || !buf) {
    /* SteelEye change - (re)allocate the buffer */
    if (buf)
    free(buf);
    if (len > max_nbd_request)
    max_nbd_request = len;
    buf=malloc(max_nbd_request);
    if (!buf)
    DEBUG("failed to allocate %d byte buffer\n", max_nbd_request);
    }
    #ifdef DODBG
    printf("%s from %d (%d) len %d, ", (request.type ? "WRITE" : "READ"),
    (int) request.from, (int) request.from / 512, len);
    #endif
    memcpy(reply.handle, request.handle, sizeof(reply.handle));
    if (((request.from + len) > exportsize) ||
    ((flags & F_READONLY) && request.type)) {
    DEBUG("[RANGE!]");
    ERROR;
    continue;
    }
    if (request.type) { /* WRITE */
    DEBUG("wr: net->buf, ");
    readit(net, buf, len);
    DEBUG("buf->exp, ");
    if (expwrite(request.from, buf, len)) {
    DEBUG("Write failed: %m" );
    ERROR;
    continue;
    }
    lastpoint += len;
    SEND;
    continue;
    }
    /* READ */

    DEBUG("exp->buf, ");
    if (expread(request.from, buf + sizeof(struct nbd_reply), len)) {
    lastpoint = -1;
    DEBUG("Read failed: %m");
    ERROR;
    continue;
    }
    lastpoint += len;

    DEBUG("buf->net, ");
    memcpy(buf, &reply, sizeof(struct nbd_reply));
    writeit(net, buf, len + sizeof(struct nbd_reply));
    DEBUG("OK!\n");
    }
    }

    char exportname2[1024];

    void set_peername(int net)
    {
    struct sockaddr_in addrin;
    int addrinlen = sizeof( addrin );
    char *peername;

    if (getpeername( net, (struct sockaddr *) &addrin, &addrinlen ) < 0)
    err("getsockname failed: %m");
    peername = inet_ntoa(addrin.sin_addr);
    sprintf(exportname2, exportname, peername);

    syslog(LOG_INFO, "connect from %s, assigned file is %s", peername, exportname2);
    }

    u64 size_autodetect(int export)
    {
    u64 es;
    DEBUG("looking for export size with lseek SEEK_END\n");
    if ((es = lseek64(export, 0, SEEK_END)) == MINUS_ONE_64 || es == 0) {
    struct stat stat_buf = { 0, } ;
    int error;
    DEBUG("looking for export size with fstat\n");
    if ((error = fstat(export, &stat_buf)) == -1 || stat_buf.st_size == 0 ) {
    DEBUG("looking for export size with ioctl BLKGETSIZE\n");
    #ifdef BLKGETSIZE
    if(ioctl(export, BLKGETSIZE, &es) || es == 0) {
    #else
    if(1){
    #endif
    err("Could not find size of exported block device: %m");
    } else {
    es *= 512; /* assume blocksize 512 */
    }
    } else {
    es = stat_buf.st_size;
    }
    }
    return es;
    }

    int main(int argc, char *argv[])
    {
    int net;
    u64 i;

    if (sizeof( struct nbd_request )!=28)
    err("Bad size of structure. Alignment problems?");

    logging();
    cmdline(argc, argv);

    if (port)
    net = connectme(port);
    else
    net = 0;
    set_peername(net);

    for (i=0; i<exportsize; i+=hunksize) {
    char exportname3[1024];

    sprintf(exportname3, exportname2, i/hunksize);
    printf( "Opening %s\n", exportname3 );
    if ((export[i/hunksize] = open(exportname3, (flags & F_READONLY) ? O_RDONLY : O_RDWR)) == -1)
    err("Could not open exported file: %m");
    }

    if (exportsize == ~0) {
    exportsize = size_autodetect(export[0]);
    }
    if (exportsize > (~0UL >> 1))
    if ((exportsize >> 10) > (~0UL >> 1))
    syslog(LOG_INFO, "size of exported file/device is %luMB",
    (unsigned long)(exportsize >> 20));
    else
    syslog(LOG_INFO, "size of exported file/device is %luKB",
    (unsigned long)(exportsize >> 10));
    else
    syslog(LOG_INFO, "size of exported file/device is %lu",
    (unsigned long)exportsize);
    setmysockopt(net);

    mainloop(net);
    return 0;
    }
    /* This header file is shared by client & server. They really have
    * something to share...
    * */

    /* Client/server protocol is as follows:
    Send INIT_PASSWD
    Send 64-bit cliserv_magic
    Send 64-bit size of exported device
    Send 128 bytes of zeros (reserved for future use)
    */

    #include "config.h"
    #include <errno.h>
    #include <string.h>
    #include <netdb.h>

    #if SIZEOF_UNSIGNED_SHORT_INT==4
    typedef unsigned short u32;
    #elif SIZEOF_UNSIGNED_INT==4
    typedef unsigned int u32;
    #elif SIZEOF_UNSIGNED_LONG_INT==4
    typedef unsigned long u32;
    #else
    #error I need at least some 32-bit type
    #endif

    #if SIZEOF_UNSIGNED_INT==8
    typedef unsigned int u64;
    #define MINUS_ONE_64 (-1U)
    #elif SIZEOF_UNSIGNED_LONG_INT==8
    typedef unsigned long u64;
    #define MINUS_ONE_64 (-1UL)
    #elif SIZEOF_UNSIGNED_LONG_LONG_INT==8
    typedef unsigned long long u64;
    #define MINUS_ONE_64 (-1ULL)
    #else
    #error I need at least some 64-bit type
    #endif

    #include "nbd.h"

    u64 cliserv_magic = 0x00420281861253LL;
    #define INIT_PASSWD "NBDMAGIC"

    #define INFO(a) do { } while(0)

    void setmysockopt(int sock)
    {
    int size = 1;
    #if 0
    if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0)
    INFO("(no sockopt/1: %m)");
    #endif
    size = 1;
    if (setsockopt(sock, SOL_TCP, TCP_NODELAY, &size, sizeof(int)) < 0)
    INFO("(no sockopt/2: %m)");
    #if 0
    size = 1024;
    if (setsockopt(sock, SOL_TCP, TCP_MAXSEG, &size, sizeof(int)) < 0)
    INFO("(no sockopt/3: %m)");
    #endif
    }

    void err(const char *s)
    {
    const int maxlen = 150;
    char s1[maxlen], *s2;
    int n = 0;

    strncpy(s1, s, maxlen);
    if (s2 = strstr(s, "%m")) {
    strcpy(s1 + (s2 - s), sys_errlist[errno]);
    s2 += 2;
    strcpy(s1 + strlen(s1), s2);
    }
    else if (s2 = strstr(s, "%h")) {
    strcpy(s1 + (s2 - s), hstrerror(h_errno));
    s2 += 2;
    strcpy(s1 + strlen(s1), s2);
    }

    s1[maxlen-1] = '\0';
    #ifdef ISSERVER
    syslog(LOG_ERR, s1);
    #else
    fprintf(stderr, "Error: %s\n", s1);
    #endif
    exit(1);
    }

    void logging(void)
    {
    #ifdef ISSERVER
    openlog(MY_NAME, LOG_PID, LOG_DAEMON);
    #endif
    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stderr, NULL, _IONBF, 0);
    }

    #ifdef WORDS_BIGENDIAN
    u64 ntohll(u64 a)
    {
    return a;
    }
    #else
    u64 ntohll(u64 a)
    {
    u32 lo = a & 0xffffffff;
    u32 hi = a >> 32U;
    lo = ntohl(lo);
    hi = ntohl(hi);
    return ((u64) lo) << 32U | hi;
    }
    #endif
    #define htonll ntohll
    \
     
     \ /
      Last update: 2005-03-22 13:13    [W:0.068 / U:151.312 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site