Module Name: src Committed By: agc Date: Thu Jun 25 13:48:42 UTC 2009
Added Files: src/external/bsd/iscsi/dist/src/osd: osd-target.c osd.c osdfs.c start_osd stop_osd Log Message: Put the OSD sources in their own directory To generate a diff of this commit: cvs rdiff -u -r0 -r1.1 src/external/bsd/iscsi/dist/src/osd/osd-target.c \ src/external/bsd/iscsi/dist/src/osd/osd.c \ src/external/bsd/iscsi/dist/src/osd/osdfs.c \ src/external/bsd/iscsi/dist/src/osd/start_osd \ src/external/bsd/iscsi/dist/src/osd/stop_osd Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Added files: Index: src/external/bsd/iscsi/dist/src/osd/osd-target.c diff -u /dev/null src/external/bsd/iscsi/dist/src/osd/osd-target.c:1.1 --- /dev/null Thu Jun 25 13:48:42 2009 +++ src/external/bsd/iscsi/dist/src/osd/osd-target.c Thu Jun 25 13:48:42 2009 @@ -0,0 +1,181 @@ +/* $NetBSD: osd-target.c,v 1.1 2009/06/25 13:48:42 agc Exp $ */ + +/* + * Copyright © 2006 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <sys/cdefs.h> + +#ifndef lint +__COPYRIGHT("@(#) Copyright © 2006 \ + The NetBSD Foundation, Inc. All rights reserved."); +__RCSID("$NetBSD: osd-target.c,v 1.1 2009/06/25 13:48:42 agc Exp $"); +#endif +#include "config.h" + +#define EXTERN + +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif + +#include <stdio.h> +#include <stdlib.h> + +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#include <unistd.h> + +#include "iscsi.h" +#include "iscsiutil.h" +#include "target.h" +#include "device.h" + +#include "conffile.h" +#include "storage.h" + +/* + * Globals + */ + +static int g_main_pid; +static globals_t g; + +/* + * Control-C handler + */ + +/* ARGSUSED0 */ +static void +handler(int s) +{ + if (ISCSI_GETPID != g_main_pid) + return; + if (target_shutdown(&g) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "target_shutdown() failed\n"); + return; + } + return; +} + +int +main(int argc, char **argv) +{ + const char *cf; + targv_t tv; + devv_t dv; + extv_t ev; + char TargetName[1024]; + int detach_me_harder; + int i; + + (void) memset(&g, 0x0, sizeof(g)); + (void) memset(&tv, 0x0, sizeof(tv)); + (void) memset(&dv, 0x0, sizeof(dv)); + (void) memset(&ev, 0x0, sizeof(ev)); + + /* set defaults */ + (void) strlcpy(TargetName, DEFAULT_TARGET_NAME, sizeof(TargetName)); + g.port = ISCSI_PORT; + detach_me_harder = 1; + + cf = _PATH_OSD_TARGETS; + + while ((i = getopt(argc, argv, "Dd:p:t:v:")) != -1) { + switch (i) { + case 'D': + detach_me_harder = 0; + break; + case 'd': + device_set_var("directory", optarg); + break; + case 'f': + cf = optarg; + break; + case 'p': + g.port = (uint16_t) atoi(optarg); + break; + case 't': + (void) strlcpy(TargetName, optarg, sizeof(TargetName)); + break; + case 'v': + if (strcmp(optarg, "net") == 0) { + set_debug("net"); + } else if (strcmp(optarg, "iscsi") == 0) { + set_debug("iscsi"); + } else if (strcmp(optarg, "scsi") == 0) { + set_debug("scsi"); + } else if (strcmp(optarg, "osd") == 0) { + set_debug("osd"); + } else if (strcmp(optarg, "all") == 0) { + set_debug("all"); + } + break; + } + } + + if (!read_conf_file(cf, &tv, &dv, &ev)) { + (void) fprintf(stderr, "Error: can't open `%s'\n", cf); + return EXIT_FAILURE; + } + + (void) signal(SIGPIPE, SIG_IGN); + + (void) signal(SIGINT, handler); + g_main_pid = ISCSI_GETPID; + + if (tv.c == 0) { + (void) fprintf(stderr, "No targets to initialise\n"); + return EXIT_FAILURE; + } + /* Initialize target */ + for (i = optind ; i < argc ; i++) { + if (target_init(&g, &tv, TargetName, i) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "target_init() failed\n"); + exit(EXIT_FAILURE); + } + } + +#ifdef HAVE_DAEMON + /* if we are supposed to be a daemon, detach from controlling tty */ + if (detach_me_harder && daemon(0, 0) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "daemon() failed\n"); + exit(EXIT_FAILURE); + } +#endif + + /* write pid to a file */ + write_pid_file(_PATH_OSD_PID_FILE); + + /* Wait for connections */ + if (target_listen(&g) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "target_listen() failed\n"); + } + + return EXIT_SUCCESS; +} Index: src/external/bsd/iscsi/dist/src/osd/osd.c diff -u /dev/null src/external/bsd/iscsi/dist/src/osd/osd.c:1.1 --- /dev/null Thu Jun 25 13:48:42 2009 +++ src/external/bsd/iscsi/dist/src/osd/osd.c Thu Jun 25 13:48:42 2009 @@ -0,0 +1,662 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include <sys/types.h> + +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +#ifdef HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +#ifdef HAVE_SYS_VFS_H +#include <sys/vfs.h> +#endif + +#include <stdio.h> +#include <stdlib.h> + +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#include <unistd.h> + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +#include <unistd.h> + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#ifdef HAVE_UTIME_H +#include <utime.h> +#endif + +#include "scsi_cmd_codes.h" + +#include "iscsi.h" +#include "iscsiutil.h" +#include "device.h" +#include "osd.h" + +/* + * Globals + */ + +static int osd_luns = CONFIG_OSD_LUNS_DFLT; +static uint64_t osd_capacity = CONFIG_OSD_CAPACITY_DFLT * 1048576; +static char base_dir[64] = CONFIG_OSD_BASEDIR_DFLT; + +#ifndef __KERNEL__ +void +device_set_var(const char *var, char *arg) +{ + if (strcmp(var, "capacity") == 0) { + osd_capacity = strtoll(arg, (char **) NULL, 10) * 1048576; + } else if (strcmp(var, "luns") == 0) { + osd_luns = atoi(arg); + } else if (strcmp(var, "directory") == 0) { + (void) strlcpy(base_dir, arg, sizeof(base_dir)); + } else { + (void) fprintf(stderr, "Unrecognised variable: `%s'\n", var); + } +} +#endif + +int +device_init(globals_t *gp, char *dev) +{ + struct stat st; + char FileName[1024]; + int i; + + if (stat(base_dir, &st) < 0) { + + /* Create directory for OSD */ + + if (mkdir(base_dir, 0755) != 0) { + if (errno != EEXIST) { + iscsi_trace_error(__FILE__, __LINE__, "error creating directory \"%s\" for OSD: errno %d\n", base_dir, errno); + return -1; + } + } + /* Create directory for LU */ + + for (i = 0; i < osd_luns; i++) { + sprintf(FileName, "%s/lun_%d", base_dir, i); + if (mkdir(FileName, 0755) != 0) { + if (errno != EEXIST) { + iscsi_trace_error(__FILE__, __LINE__, "error creating \"%s\" for LU %d: errno %d\n", FileName, i, errno); + return -1; + } + } + } + } + /* Display LU info */ + + return 0; +} + +int +osd_read_callback(void *arg) +{ + struct iovec *sg = (struct iovec *) arg; + int i = 0; + + while (sg[i].iov_base != NULL) { + iscsi_free_atomic(sg[i].iov_base); + i++; + } + return 0; +} + +int +device_command(target_session_t * sess, target_cmd_t * cmd) +{ + iscsi_scsi_cmd_args_t *args = cmd->scsi_cmd; + uint8_t *data; + char FileName[1024]; + uint8_t *write_data = NULL; + uint8_t *read_data = NULL; + uint8_t *set_list = NULL; + uint8_t *get_list = NULL; + struct iovec sg[3]; + int sg_len = 0; + int rc; + osd_args_t osd_args; + uint32_t GroupID = 0; + uint64_t UserID = 0; + char string[1024]; + uint8_t *get_data = NULL; + uint32_t page = 0; + uint32_t index = 0; + int attr_len = 0; + + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "SCSI op 0x%x (lun %llu)\n", args->cdb[0], args->lun); + + if (args->lun >= osd_luns) { + iscsi_trace(TRACE_SCSI_DEBUG, __FILE__, __LINE__, "invalid lun: %llu\n", args->lun); + args->status = 0x01; + return 0; + } + args->status = 1; + + switch (args->cdb[0]) { + + case TEST_UNIT_READY: + + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "TEST_UNIT_READY(lun %llu)\n", args->lun); + args->status = 0; + args->length = 0; + break; + + case INQUIRY: + + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "INQUIRY(lun %llu)\n", args->lun); + data = args->send_data; + memset(data, 0, args->cdb[4]); /* Clear allocated buffer */ + data[0] = 0x0e; /* Peripheral Device Type */ + /* data[1] |= 0x80; // Removable Bit */ + data[2] |= 0x02;/* ANSI-approved version */ + /* data[3] |= 0x80; // AENC */ + /* data[3] |= 0x40; // TrmIOP */ + /* data[3] |= 0x20; // NormACA */ + data[4] = args->cdb[4] - 4; /* Additional length */ + /* + * data[7] |= 0x80; // Relative + * addressing + */ + data[7] |= 0x40;/* WBus32 */ + data[7] |= 0x20;/* WBus16 */ + /* data[7] |= 0x10; // Sync */ + /* data[7] |= 0x08; // Linked Commands */ + /* data[7] |= 0x04; // TransDis */ + /* + * data[7] |= 0x02; // Tagged Command + * Queueing + */ + /* data[7] |= 0x01; // SftRe */ + (void) memset(data + 8, 0x0, 32); + strlcpy(data + 8, OSD_VENDOR, 8); /* Vendor */ + strlcpy(data + 16, OSD_PRODUCT, 16); /* Product ID */ + (void) snprintf(data + 32, 8, "%d", OSD_VERSION); /* Product Revision */ + args->input = 1; + args->length = args->cdb[4] + 1; + args->status = 0; + + break; + + case 0x7F: + + OSD_DECAP_CDB(args->cdb, args->ext_cdb, &osd_args); + /* OSD_PRINT_CDB(args->cdb, args->ext_cdb); */ + GroupID = osd_args.GroupID; + UserID = osd_args.UserID; + + /* + * Transfer all data + */ + + if (osd_args.set_attributes_list_length) { + if ((set_list = iscsi_malloc_atomic(osd_args.set_attributes_list_length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + goto done; + } + sg[sg_len].iov_base = set_list; + sg[sg_len].iov_len = osd_args.set_attributes_list_length; + sg_len++; + } + if (osd_args.get_attributes_list_length) { + if ((get_list = iscsi_malloc_atomic(osd_args.get_attributes_list_length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + goto done; + } + sg[sg_len].iov_base = get_list; + sg[sg_len].iov_len = osd_args.get_attributes_list_length; + sg_len++; + } + if (osd_args.service_action == OSD_WRITE) { + if ((write_data = iscsi_malloc_atomic(osd_args.length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + goto done; + } + sg[sg_len].iov_base = write_data; + sg[sg_len].iov_len = osd_args.length; + sg_len++; + } + if (sg_len) { + if (target_transfer_data(sess, args, sg, sg_len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "target_transfer_data() failed\n"); + goto done; + } + } + /* + * Set any attributes + */ + + if (osd_args.set_attributes_list_length) { + uint32_t page, attr; + uint16_t len; + int i; + + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_SET_ATTR(lun %llu, GroupID 0x%x, UserID 0x%llx)\n", args->lun, osd_args.GroupID, osd_args.UserID); + for (i = 0; i < osd_args.set_attributes_list_length;) { + page = ISCSI_NTOHL(*((uint32_t *) (&(set_list[i])))); + i += 4; + attr = ISCSI_NTOHL(*((uint32_t *) (&(set_list[i])))); + i += 4; + len = ISCSI_NTOHS(*((uint16_t *) (&(set_list[i])))); + i += 2; + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx.0x%x.%u", + base_dir, args->lun, osd_args.GroupID, osd_args.UserID, page, attr); + if ((rc = open(FileName, O_WRONLY | O_CREAT, 0644)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); + goto done; + } + if (write(rc, set_list + i, len) != len) { + iscsi_trace_error(__FILE__, __LINE__, "write() failed\n"); + } + close(rc); + i += len; + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "SET(0x%x,%u,%u>\n", page, attr, len); + } + } + args->send_sg_len = 0; + sg_len = 0; + + switch (osd_args.service_action) { + + case OSD_CREATE_GROUP: + + do { + GroupID = rand() % 1048576 * 1024 + 1; + sprintf(FileName, "%s/lun_%llu/0x%x", base_dir, args->lun, GroupID); + rc = mkdir(FileName, 0755); + } while (rc == -1 && errno == EEXIST); + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_CREATE_GROUP(lun %llu) --> 0x%x\n", args->lun, GroupID); + args->status = 0; + break; + + case OSD_REMOVE_GROUP: + + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_REMOVE_GROUP(lun %llu, 0x%x)\n", args->lun, osd_args.GroupID); + sprintf(FileName, "%s/lun_%llu/0x%x", base_dir, args->lun, osd_args.GroupID); + if ((rc = rmdir(FileName)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "rmdir(\"%s\") failed: errno %d\n", FileName, errno); + goto done; + } + args->status = 0; + break; + + case OSD_CREATE: + + UserID = rand() % 1048576 * 1024 + 1; +create_user_again: + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx", + base_dir, args->lun, osd_args.GroupID, UserID); + rc = open(FileName, O_CREAT | O_EXCL | O_RDWR, 0644); + if ((rc == -1) && (errno == EEXIST)) { + UserID = rand() % 1048576 * 1024 + 1; + goto create_user_again; + } + close(rc); + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_CREATE(lun %llu, GroupID 0x%x) --> 0x%llx\n", args->lun, osd_args.GroupID, UserID); + args->status = 0; + + break; + + case OSD_REMOVE: + + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_REMOVE(lun %llu, 0x%llx)\n", args->lun, osd_args.UserID); + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx", + base_dir, args->lun, osd_args.GroupID, osd_args.UserID); + if ((rc = unlink(FileName)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "unlink(\"%s\") failed: errno %d\n", FileName, errno); + goto done; + } + sprintf(string, "rm -f %s/lun_%llu/0x%x/0x%llx.*", base_dir, args->lun, osd_args.GroupID, osd_args.UserID); + if (system(string) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "\"%s\" failed\n", string); + return -1; + } + args->status = 0; + break; + + case OSD_WRITE: + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_WRITE(lun %llu, GroupID 0x%x, UserID 0x%llx, length %llu, offset %llu)\n", + args->lun, osd_args.GroupID, osd_args.UserID, osd_args.length, osd_args.offset); + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx", + base_dir, args->lun, osd_args.GroupID, osd_args.UserID); + if ((rc = open(FileName, O_WRONLY, 0644)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); + goto write_done; + } + if (lseek(rc, osd_args.offset, SEEK_SET) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error seeking \"%s\": errno %d\n", FileName, errno); + goto write_done; + } + if (write(rc, write_data, osd_args.length) != osd_args.length) { + iscsi_trace_error(__FILE__, __LINE__, "write() failed\n"); + goto write_done; + } + close(rc); + args->status = 0; +write_done: + break; + + case OSD_READ: + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_READ(lun %llu, GroupID 0x%x, UserID 0x%llx, length %llu, offset %llu)\n", + args->lun, osd_args.GroupID, osd_args.UserID, osd_args.length, osd_args.offset); + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx", + base_dir, args->lun, osd_args.GroupID, osd_args.UserID); + if ((rc = open(FileName, O_RDONLY, 0644)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); + goto read_done; + } + if ((read_data = iscsi_malloc_atomic(osd_args.length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + goto read_done; + } + if (lseek(rc, osd_args.offset, SEEK_SET) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error seeking \"%s\": errno %d\n", FileName, errno); + goto read_done; + } + if (read(rc, read_data, osd_args.length) != osd_args.length) { + iscsi_trace_error(__FILE__, __LINE__, "read() failed\n"); + goto read_done; + } + close(rc); + args->status = 0; +read_done: + if (args->status == 0) { + args->input = 1; + sg[0].iov_base = read_data; + sg[0].iov_len = osd_args.length; + sg[1].iov_base = NULL; + sg[1].iov_len = 0; + args->send_data = (void *) sg; + args->send_sg_len = 1; + sg_len++; + cmd->callback = osd_read_callback; + cmd->callback_arg = sg; + } else { + if (read_data) + iscsi_free_atomic(read_data); + args->length = 0; /* Need a better way of + * specifying an error.. */ + } + break; + + case OSD_GET_ATTR: + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_GET_ATTR(lun %llu, GroupID 0x%x, UserID 0x%llx)\n", + args->lun, osd_args.GroupID, osd_args.UserID); + args->status = 0; + break; + + case OSD_SET_ATTR: + args->status = 0; + break; + } + + if (args->status) + goto done; + + /* + * Send back requested attributes + */ + + if (osd_args.get_attributes_list_length || osd_args.get_attributes_page) { + if ((get_data = iscsi_malloc_atomic(osd_args.get_attributes_allocation_length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + goto done; + } + } + if (osd_args.get_attributes_list_length) { + int i; + + for (i = 0; i < osd_args.get_attributes_list_length;) { + page = ISCSI_NTOHL(*((uint32_t *) (&(get_list[i])))); + i += 4; + index = ISCSI_NTOHL(*((uint32_t *) (&(get_list[i])))); + i += 4; + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "GET(0x%x,%u)\n", page, index); + + switch (page) { + case 0x40000001: + switch (index) { + case 0x1: + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(4); + attr_len += 2; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(GroupID); + attr_len += 4; + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "unknown attr index %u\n", index); + goto done; + } + break; + case 0x00000001: + switch (index) { + case 0x1: + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(4); + attr_len += 2; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(GroupID); + attr_len += 4; + break; + case 0x2: + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(8); + attr_len += 2; + *((uint64_t *) & get_data[attr_len]) = ISCSI_HTONLL(UserID); + attr_len += 8; + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "unknown attr index %u\n", index); + goto done; + } + break; + + /* Vendor-specific */ + + case 0x30000000: + switch (index) { + case 0x1: + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(480); + attr_len += 2; + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx.0x%x.%u", + base_dir, args->lun, osd_args.GroupID, osd_args.UserID, page, index); + if ((rc = open(FileName, O_RDONLY, 0644)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); + } + if (read(rc, get_data + attr_len, 480) != 480) { + iscsi_trace_error(__FILE__, __LINE__, "read() failed\n"); + goto done; + } + close(rc); + attr_len += 480; + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "unknown vendor attr index %u\n", index); + goto done; + } + break; + + default: + iscsi_trace_error(__FILE__, __LINE__, "unknown page 0x%x\n", page); + goto done; + } + } + } + if (osd_args.get_attributes_page) { + + /* + * Right now, if we get a request for an entire page, + * we return only one attribute. + */ + + page = osd_args.get_attributes_page; + + switch (osd_args.get_attributes_page) { + case 0x40000001: + index = 1; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(4); + attr_len += 2; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(GroupID); + attr_len += 4; + break; + + case 0x00000001: + index = 2; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(8); + attr_len += 2; + *((uint64_t *) & get_data[attr_len]) = ISCSI_HTONLL(UserID); + attr_len += 8; + break; + + case 0x30000000: + index = 1; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(480); + attr_len += 2; + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx.0x%x.%u", + base_dir, args->lun, osd_args.GroupID, osd_args.UserID, page, index); + if ((rc = open(FileName, O_RDONLY, 0644)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); + } + if (read(rc, get_data + attr_len, 480) != 480) { + iscsi_trace_error(__FILE__, __LINE__, "read() failed\n"); + goto done; + } + close(rc); + attr_len += 480; + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "page not yet supported\n"); + goto done; + } + } + if (attr_len) { + if (attr_len != osd_args.get_attributes_allocation_length) { + iscsi_trace_error(__FILE__, __LINE__, "allocation lengths differ: got %u, expected %u\n", + osd_args.get_attributes_allocation_length, attr_len); + goto done; + } + if (!args->status) { + args->input = 1; + sg[sg_len].iov_base = get_data; + sg[sg_len].iov_len = osd_args.get_attributes_allocation_length; + sg_len++; + sg[sg_len].iov_base = NULL; + sg[sg_len].iov_len = 0; + args->send_data = (void *) sg; + args->send_sg_len++; + cmd->callback = osd_read_callback; + cmd->callback_arg = sg; + } else { + if (get_data) + iscsi_free_atomic(get_data); + } + } + break; + + default: + iscsi_trace_error(__FILE__, __LINE__, "UNKNOWN OPCODE 0x%x\n", args->cdb[0]); + args->status = 0x01; + break; + } + + +done: + iscsi_trace(TRACE_SCSI_DEBUG, __FILE__, __LINE__, "SCSI op 0x%x: done (status 0x%x)\n", args->cdb[0], args->status); + if (set_list) { + iscsi_free_atomic(set_list); + } + if (get_list) { + iscsi_free_atomic(get_list); + } + if (write_data) { + iscsi_free_atomic(write_data); + } + return 0; +} + +/* ARGSUSED */ +int +device_shutdown(target_session_t *sess) +{ + return 0; +} Index: src/external/bsd/iscsi/dist/src/osd/osdfs.c diff -u /dev/null src/external/bsd/iscsi/dist/src/osd/osdfs.c:1.1 --- /dev/null Thu Jun 25 13:48:42 2009 +++ src/external/bsd/iscsi/dist/src/osd/osdfs.c Thu Jun 25 13:48:42 2009 @@ -0,0 +1,1076 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2002, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Object-Based Storage Devices (OSD) Filesystem for Linux + */ + + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/pagemap.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/locks.h> +#include <asm/uaccess.h> +#include <endian.h> +#include <linux/blkdev.h> +#include <scsi.h> +#include "osd.h" +#include "osd_ops.h" +#include "iscsiutil.h" +#include "util.c" + + +/* + * Contants + */ + + +#define OSDFS_MAGIC 0xabcdef01 +#define MAX_INODES 32768 +#define MAX_NAME_LEN 32 + + +/* + * Types + */ + + +typedef struct osdfs_link_t { + char name[MAX_NAME_LEN]; + struct osdfs_link_t* next; +} osdfs_link_t; + +typedef struct osdfs_inode_t { + osdfs_link_t *link; +} osdfs_inode_t; + +typedef struct osdfs_metadata_t { + uint64_t ObjectID; + int used; +} osdfs_metadata_t; + + +/* + * Prototypes + */ + +static int osdfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev); + + +/* + * Globals + */ + + +static struct super_operations osdfs_ops; +static struct address_space_operations osdfs_aops; +static struct file_operations osdfs_dir_operations; +static struct file_operations osdfs_file_operations; +static struct inode_operations osdfs_dir_inode_operations; +static uint32_t root_gid; +static uint64_t root_uid; +static iscsi_mutex_t g_mutex; + + +/* + * SCSI transport function for OSD + */ + + +int osd_exec_via_scsi(void *dev, osd_args_t *args, OSD_OPS_MEM *m) { + Scsi_Request *SRpnt; + Scsi_Device *SDpnt; + unsigned char cdb[256]; + kdev_t kdev = *((kdev_t *) dev); + void *ptr = NULL; + int len = 0; + + if (m->send_sg||m->recv_sg) { + iscsi_trace_error("scatter/gather not yet implemented!\n"); + return -1; + } + + SDpnt = blk_dev[MAJOR(kdev)].queue(kdev)->queuedata; + SRpnt = scsi_allocate_request(SDpnt); + SRpnt->sr_cmd_len = CONFIG_OSD_CDB_LEN; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_sense_buffer[2] = 0; + switch(args->service_action) { + case OSD_WRITE: + case OSD_SET_ATTR: + len = m->send_len; + ptr = m->send_data; + SRpnt->sr_data_direction = SCSI_DATA_WRITE; + break; + case OSD_CREATE: + case OSD_CREATE_GROUP: + case OSD_READ: + case OSD_GET_ATTR: + len = m->recv_len; + ptr = m->recv_data; + SRpnt->sr_data_direction = SCSI_DATA_READ; + break; + case OSD_REMOVE: + case OSD_REMOVE_GROUP: + SRpnt->sr_data_direction = 0; + break; + default: + iscsi_trace_error("unsupported OSD service action 0x%x\n", args->service_action); + return -1; + } + OSD_ENCAP_CDB(args, cdb); + + /* Exec SCSI command */ + + scsi_wait_req(SRpnt, cdb, ptr, len, 5*HZ, 5); + if (SRpnt->sr_result!=0) { + iscsi_trace_error("SCSI command failed (result %u)\n", SRpnt->sr_result); + scsi_release_request(SRpnt); + SRpnt = NULL; + return -1; + } + scsi_release_request(SRpnt); + SRpnt = NULL; + + return 0; +} + +/* + * Internal OSDFS functions + */ + + +/* Directory operations */ + +static int entries_get(kdev_t dev, uint64_t uid, char **entries, uint32_t *num, uint64_t *size) { + struct inode inode; + uint16_t len; + + if (osd_get_one_attr((void *)&dev, root_gid, uid, 0x30000000, 0x0, sizeof(struct inode), &osd_exec_via_scsi, &len, (void *) &inode)!=0) { + iscsi_trace_error("osd_get_one_attr() failed\n"); + return -1; + } + *num = 0; + if ((*size=inode.i_size)) { + char *ptr, *ptr2; + int n = 0; + + if ((*entries=vmalloc(*size+1))==NULL) { + iscsi_trace_error("vmalloc() failed\n"); + return -1; + } + if (osd_read((void *)&dev, root_gid, uid, 0, *size, *entries, 0, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_read() failed\n"); + vfree(*entries); + return -1; + } + (*entries)[*size] = 0x0; + ptr = *entries; + do { + n++; + if ((ptr2=strchr(ptr, '\n'))!=NULL) { + n++; + if ((ptr2 = strchr(ptr2+1, '\n'))==NULL) { + iscsi_trace_error("directory 0x%llx corrupted (line %i)\n", uid, n); + return -1; + } + (*num)++; + } else { + iscsi_trace_error("directory 0x%llx corrupted (line %i)\n", uid, n); + return -1; + } + ptr = ptr2+1; + } while (*ptr); + } + + return 0; +} + +static int entry_add(kdev_t dev, ino_t dir_ino, ino_t entry_ino, + const char *name, uint64_t *new_size) { + char entry[MAX_NAME_LEN+16]; + uint64_t uid = dir_ino; + struct inode inode; + uint16_t len; + + /* Get size of directory */ + + if (osd_get_one_attr((void *)&dev, root_gid, uid, 0x30000000, 0x0, sizeof(struct inode), &osd_exec_via_scsi, &len, (void *) &inode)!=0) { + iscsi_trace_error("osd_get_one_attr() failed\n"); + return -1; + } + + /* Write entry at end */ + + sprintf(entry, "%s\n", name); + sprintf(entry+strlen(entry), "%li\n", entry_ino); + if (osd_write((void *)&dev, root_gid, uid, inode.i_size, strlen(entry), entry, 0, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_write() failed\n"); + return -1; + } + *new_size += strlen(entry); + + return 0; +} + +static int entry_del(kdev_t dev, ino_t dir_ino, ino_t ino, const char *name, uint64_t *new_size) { + char *entries; + uint32_t num_entries; + uint64_t size; + uint64_t dir_uid = (unsigned) dir_ino; + + /* Read */ + + if (entries_get(dev, dir_ino, &entries, &num_entries, &size)!=0) { + iscsi_trace_error("entries_get() failed\n"); + return -1; + } + entries[size] = 0x0; + + iscsi_trace(TRACE_OSDFS, "dir_ino 0x%llx has %u entries\n", dir_uid, num_entries); + if (num_entries) { + char *ptr = entries; + char *tmp = NULL; + char *nl; + int n = 0; + + do { + n++; + if ((nl=strchr(ptr, '\n'))==NULL) { + iscsi_trace_error("directory 0x%llx corrupted (line %i)\n", dir_uid, n); + return -1; + } + *nl = 0x0; + if (!strcmp(ptr, name)) { + tmp = ptr; + } + *nl = '\n'; + n++; + if ((ptr=strchr(nl+1, '\n'))==NULL) { + iscsi_trace_error("directory 0x%llx corrupted (line %i)\n", dir_uid, n); + return -1; + } + ptr++; + } while (!tmp && *ptr); + + if (!tmp) { + iscsi_trace_error("entry \"%s\" not found in dir 0x%llx\n", name, dir_uid); + return -1; + } + if (entries+size-ptr) { + iscsi_trace(TRACE_OSDFS, "writing remaining %u directory bytes at offset %u\n", + entries+size-ptr, tmp-entries); + if (osd_write((void *)&dev, root_gid, dir_uid, tmp-entries, entries+size-ptr, ptr, 0, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_write() failed\n"); + return -1; + } + } + *new_size = size-(ptr-tmp); + vfree(entries); + } else { + iscsi_trace_error("dir 0x%llx has no entries\n", dir_uid); + return -1; + } + + return 0; +} + +static int entry_num(kdev_t dev, ino_t ino) { + char *entries; + uint32_t num_entries; + uint64_t size; + + if (entries_get(dev, ino, &entries, &num_entries, &size)!=0) { + iscsi_trace_error("entries_get() failed\n"); + return -1; + } + iscsi_trace(TRACE_OSDFS, "ino %li has %i entries\n", ino, num_entries); + if (num_entries) vfree(entries); + return num_entries; +} + +/* Inode operations */ + +static void osdfs_set_ops(struct inode *inode) { + switch (inode->i_mode & S_IFMT) { + case S_IFREG: + inode->i_fop = &osdfs_file_operations; + break; + case S_IFDIR: + inode->i_op = &osdfs_dir_inode_operations; + inode->i_fop = &osdfs_dir_operations; + break; + case S_IFLNK: + inode->i_op = &page_symlink_inode_operations; + break; + default: + iscsi_trace_error("UNKNOWN MODE\n"); + } + inode->i_mapping->a_ops = &osdfs_aops; +} + +static struct inode *osdfs_get_inode(struct super_block *sb, int mode, int dev, const char *name, + uint64_t ObjectID) { + struct inode *inode; + ino_t ino = ObjectID; + + iscsi_trace(TRACE_OSDFS, "osdfs_get_inode(\"%s\", mode %i (%s))\n", name, mode, + S_ISDIR(mode)?"DIR":(S_ISREG(mode)?"REG":"LNK")); + + /* iget() gets a free VFS inode and subsequently call */ + /* osdfds_read_inode() to fill the inode structure. */ + + if ((inode=iget(sb, ino))==NULL) { + iscsi_trace_error("iget() failed\n"); + return NULL; + } + + return inode; +} + + +/* + * Super Operations + */ + + +static void osdfs_read_inode(struct inode *inode) { + ino_t ino = inode->i_ino; + kdev_t dev = inode->i_sb->s_dev; + uint64_t uid = ino; + unsigned char *attr; + uint16_t len; + + iscsi_trace(TRACE_OSDFS, "osdfs_read_inode(ino 0x%x, major %i, minor %i)\n", + (unsigned) ino, MAJOR(dev), MINOR(dev)); + + /* Get object attributes for rest of inode */ + + if ((attr=iscsi_malloc_atomic(sizeof(struct inode)))==NULL) { + iscsi_trace_error("iscsi_malloc_atomic() failed\n"); + } + if (osd_get_one_attr((void *)&dev, root_gid, uid, 0x30000000, 0x0, sizeof(struct inode), &osd_exec_via_scsi, &len, attr)!=0) { + iscsi_trace_error("osd_get_one_attr() failed\n"); + return; + } + + inode->i_size = ((struct inode *)(attr))->i_size; + inode->i_mode = ((struct inode *)(attr))->i_mode; + inode->i_nlink = ((struct inode *)(attr))->i_nlink; + inode->i_gid = ((struct inode *)(attr))->i_gid; + inode->i_uid = ((struct inode *)(attr))->i_uid; + inode->i_ctime = ((struct inode *)(attr))->i_ctime; + inode->i_atime = ((struct inode *)(attr))->i_atime; + inode->i_mtime = ((struct inode *)(attr))->i_mtime; + + iscsi_free_atomic(attr); + + osdfs_set_ops(inode); +} + +void osdfs_dirty_inode(struct inode *inode) { + iscsi_trace(TRACE_OSDFS, "osdfs_dirty_inode(ino 0x%x)\n", (unsigned) inode->i_ino); +} + +void osdfs_write_inode(struct inode *inode, int sync) { + ino_t ino = inode->i_ino; + kdev_t dev = inode->i_sb->s_dev; + uint64_t uid = ino; + + iscsi_trace(TRACE_OSDFS, "osdfs_write_inode(0x%llx)\n", uid); + + if (osd_set_one_attr((void *)&dev, root_gid, uid, 0x30000000, 0x1, sizeof(struct inode), (void *) inode, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_set_one_attr() failed\n"); + } + inode->i_state &= ~I_DIRTY; +} + +void osdfs_put_inode(struct inode *inode) { + iscsi_trace(TRACE_OSDFS, "osdfs_put_inode(0x%x)\n", (unsigned) inode->i_ino); +} + +void osdfs_delete_inode(struct inode *inode) { + iscsi_trace(TRACE_OSDFS, "osdfs_delete_inode(%lu)\n", inode->i_ino); + clear_inode(inode); +} + +void osdfs_put_super(struct super_block *sb) { + iscsi_trace_error("osdfs_put_super() not implemented\n"); +} + +void osdfs_write_super(struct super_block *sb) { + iscsi_trace_error("osdfs_write_super() not implemented\n"); +} + +void osdfs_write_super_lockfs(struct super_block *sb) { + iscsi_trace_error("osdfs_write_super_lockfs() not implemented\n"); +} + +void osdfs_unlockfs(struct super_block *sb) { + iscsi_trace_error("osdfs_unlockfs() not implemented\n"); +} + +int osdfs_statfs(struct super_block *sb, struct statfs *buff) { + iscsi_trace(TRACE_OSDFS, "statfs()\n"); + buff->f_type = OSDFS_MAGIC; + buff->f_bsize = PAGE_CACHE_SIZE; + buff->f_blocks = 256; + buff->f_bfree = 128; + buff->f_bavail = 64; + buff->f_files = 0; + buff->f_ffree = 0; + buff->f_namelen = MAX_NAME_LEN; + + return 0; +} + +int osdfs_remount_fs(struct super_block *sb, int *i, char *c) { + iscsi_trace_error("osdfs_remount_fs() not implemented\n"); + + return -1; +} + +void osdfs_clear_inode(struct inode *inode) { + iscsi_trace(TRACE_OSDFS, "osdfs_clear_inode(ino %lu)\n", inode->i_ino); +} + +void osdfs_umount_begin(struct super_block *sb) { + iscsi_trace_error("osdfs_unmount_begin() not implemented\n"); +} + +static struct super_operations osdfs_ops = { + read_inode: osdfs_read_inode, + dirty_inode: osdfs_dirty_inode, + write_inode: osdfs_write_inode, + put_inode: osdfs_put_inode, + delete_inode: osdfs_delete_inode, + put_super: osdfs_put_super, + write_super: osdfs_write_super, + write_super_lockfs: osdfs_write_super_lockfs, + unlockfs: osdfs_unlockfs, + statfs: osdfs_statfs, + remount_fs: osdfs_remount_fs, + clear_inode: osdfs_clear_inode, + umount_begin: osdfs_umount_begin +}; + + +/* + * Inode operations for directories + */ + + +static int osdfs_create(struct inode *dir, struct dentry *dentry, int mode) { + + iscsi_trace(TRACE_OSDFS, "osdfs_create(\"%s\")\n", dentry->d_name.name); + if (osdfs_mknod(dir, dentry, mode | S_IFREG, 0)!=0) { + iscsi_trace_error("osdfs_mknod() failed\n"); + return -1; + } + iscsi_trace(TRACE_OSDFS, "file \"%s\" is inode 0x%x\n", dentry->d_name.name, (unsigned) dentry->d_inode->i_ino); + + return 0; +} + +static struct dentry * osdfs_lookup(struct inode *dir, struct dentry *dentry) { + const char *name = dentry->d_name.name; + struct inode *inode = NULL; + ino_t ino; + kdev_t dev = dir->i_sb->s_dev; + uint64_t uid = dir->i_ino; + char *entries; + uint32_t num_entries; + uint64_t size; + + iscsi_trace(TRACE_OSDFS, "osdfs_lookup(\"%s\" in dir ino %lu)\n", name, dir->i_ino); + + /* Get directory entries */ + + ISCSI_LOCK(&g_mutex, return NULL); + if (entries_get(dev, uid, &entries, &num_entries, &size)!=0) { + iscsi_trace_error("entries_get() failed\n"); + ISCSI_UNLOCK(&g_mutex, return NULL); + return NULL; + } + ISCSI_UNLOCK(&g_mutex, return NULL); + iscsi_trace(TRACE_OSDFS, "ino %li has %i entries\n", dir->i_ino, num_entries); + + /* Search for this entry */ + + if (num_entries) { + char *ptr = entries; + char *ptr2; + + do { + if ((ptr2=strchr(ptr, '\n'))!=NULL) { + *ptr2 = 0x0; + ptr2 = strchr(ptr2+1, '\n'); + if (!strcmp(ptr, name)) { + sscanf(ptr+strlen(ptr)+1, "%li", &ino); + iscsi_trace(TRACE_OSDFS, "found \"%s\" at ino %li\n", name, ino); + if ((inode=iget(dir->i_sb, ino))==NULL) { + iscsi_trace_error("iget() failed\n"); + return NULL; + } + } + } + } while (ptr2&&(ptr=ptr2+1)); + vfree(entries); + } + if (!inode) { + iscsi_trace(TRACE_OSDFS, "\"%s\" not found\n", name); + } + d_add(dentry, inode); + + return NULL; +} + +static int osdfs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry) { + struct inode *inode = old_dentry->d_inode; + kdev_t dev = dir->i_sb->s_dev; + ino_t dir_ino = dir->i_ino; + ino_t ino = inode->i_ino; + const char *name = dentry->d_name.name; + + if (S_ISDIR(inode->i_mode)) return -EPERM; + iscsi_trace(TRACE_OSDFS, "osdfs_link(%lu, \"%s\")\n", ino, name); + ISCSI_LOCK(&g_mutex, return -1); + if (entry_add(dev, dir_ino, ino, name, &dir->i_size)!=0) { + iscsi_trace_error("entry_add() failed\n"); + return -1; + } + inode->i_nlink++; + atomic_inc(&inode->i_count); + osdfs_write_inode(inode, 0); + osdfs_write_inode(dir, 0); + d_instantiate(dentry, inode); + ISCSI_UNLOCK(&g_mutex, return -1); + + return 0; +} + +static int osdfs_unlink(struct inode * dir, struct dentry *dentry) { + kdev_t dev = dir->i_sb->s_dev; + struct inode *inode = dentry->d_inode; + ino_t dir_ino = dir->i_ino; + ino_t ino = dentry->d_inode->i_ino; + const char *name = dentry->d_name.name; + + iscsi_trace(TRACE_OSDFS, "osdfs_unlink(\"%s\", ino 0x%x)\n", name, (unsigned) ino); + ISCSI_LOCK(&g_mutex, return -1); + switch (inode->i_mode & S_IFMT) { + case S_IFREG: + case S_IFLNK: + break; + case S_IFDIR: + if (entry_num(dev, ino)) { + iscsi_trace_error("directory 0x%x still has %i entries\n", + (unsigned) ino, entry_num(dev, ino)); + ISCSI_UNLOCK(&g_mutex, return -1); + return -ENOTEMPTY; + } + } + if (entry_del(dev, dir_ino, ino, name, &(dir->i_size))!=0) { + iscsi_trace_error("entry_del() failed\n"); + ISCSI_UNLOCK(&g_mutex, return -1); + return -1; + } + osdfs_write_inode(dir, 0); + if (--inode->i_nlink) { + iscsi_trace(TRACE_OSDFS, "ino 0x%x still has %i links\n", (unsigned) ino, inode->i_nlink); + osdfs_write_inode(inode, 0); + } else { + iscsi_trace(TRACE_OSDFS, "ino 0x%x link count reached 0, removing object\n", (unsigned) ino); + if (osd_remove((void *)&dev, root_gid, ino, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_remove() failed\n"); + return -1; + } + } + ISCSI_UNLOCK(&g_mutex, return -1); + + return 0; +} + +static int osdfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) { + struct inode *inode; + + iscsi_trace(TRACE_OSDFS, "osdfs_symlink(\"%s\"->\"%s\")\n", dentry->d_name.name, symname); + if (osdfs_mknod(dir, dentry, S_IRWXUGO | S_IFLNK, 0)!=0) { + iscsi_trace_error("osdfs_mknod() failed\n"); + return -1; + } + inode = dentry->d_inode; + if (block_symlink(inode, symname, strlen(symname)+1)!=0) { + iscsi_trace_error("block_symlink() failed\n"); + return -1; + } + iscsi_trace(TRACE_OSDFS, "symbolic link \"%s\" is inode %lu\n", dentry->d_name.name, inode->i_ino); + + return 0; +} + +static int osdfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) { + + iscsi_trace(TRACE_OSDFS, "osdfs_mkdir(\"%s\")\n", dentry->d_name.name); + if (osdfs_mknod(dir, dentry, mode | S_IFDIR, 0)!=0) { + iscsi_trace_error("osdfs_mkdir() failed\n"); + } + + return 0; +} + +static int osdfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev_in) { + struct inode *inode = NULL; + uint64_t uid; + struct inode attr; + kdev_t dev = dir->i_sb->s_dev; + const char *name = dentry->d_name.name; + + iscsi_trace(TRACE_OSDFS, "osdfs_mknod(\"%s\")\n", dentry->d_name.name); + + /* Create object */ + + if (osd_create((void *)&dev, root_gid, &osd_exec_via_scsi, &uid)!=0) { + iscsi_trace_error("osd_create() failed\n"); + return -1; + } + + /* Initialize object attributes */ + + memset(&attr, 0, sizeof(struct inode)); + attr.i_mode = mode; + attr.i_uid = current->fsuid; + attr.i_gid = current->fsgid; + attr.i_ctime = CURRENT_TIME; + attr.i_atime = CURRENT_TIME; + attr.i_mtime = CURRENT_TIME; + attr.i_nlink = 1; + if (osd_set_one_attr((void *)&dir->i_sb->s_dev, root_gid, uid, 0x30000000, 0x1, sizeof(struct inode), + &attr, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_set_one_attr() failed\n"); + return -1; + } + + /* Assign to an inode */ + + if ((inode = osdfs_get_inode(dir->i_sb, mode, dev, name, uid))==NULL) { + iscsi_trace_error("osdfs_get_inode() failed\n"); + return -ENOSPC; + } + d_instantiate(dentry, inode); + + /* Add entry to parent directory */ + + if (inode->i_ino != 1) { + ISCSI_LOCK(&g_mutex, return -1); + if (entry_add(dev, dir->i_ino, inode->i_ino, name, &dir->i_size)!=0) { + iscsi_trace_error("entry_add() failed\n"); + return -1; + } + osdfs_write_inode(dir, 0); + ISCSI_UNLOCK(&g_mutex, return -1); + } + + return 0; +} + +static int osdfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { + kdev_t dev = old_dir->i_sb->s_dev; + ino_t old_dir_ino = old_dir->i_ino; + ino_t new_dir_ino = new_dir->i_ino; + ino_t old_ino = old_dentry->d_inode->i_ino; + ino_t new_ino = new_dentry->d_inode?new_dentry->d_inode->i_ino:old_ino; + const char *old_name = old_dentry->d_name.name; + const char *new_name = new_dentry->d_name.name; + + iscsi_trace(TRACE_OSDFS, "old_dir = 0x%p (ino 0x%x)\n", old_dir, (unsigned) old_dir_ino); + iscsi_trace(TRACE_OSDFS, "new_dir = 0x%p (ino 0x%x)\n", new_dir, (unsigned) new_dir_ino); + iscsi_trace(TRACE_OSDFS, "old_dentry = 0x%p (ino 0x%x)\n", old_dentry, (unsigned) old_ino); + iscsi_trace(TRACE_OSDFS, "new_dentry = 0x%p (ino 0x%x)\n", new_dentry, (unsigned) new_ino); + + /* + * If we return -1, the VFS will implement a rename with a combination + * of osdfs_unlink() and osdfs_create(). + */ + + /* Delete entry from old directory */ + + ISCSI_LOCK(&g_mutex, return -1); + if (entry_del(dev, old_dir_ino, old_ino, old_name, &old_dir->i_size)!=0) { + iscsi_trace_error("error deleting old entry \"%s\"\n", old_name); + ISCSI_UNLOCK(&g_mutex, return -1); + return -1; + } + osdfs_write_inode(old_dir, 0); + ISCSI_UNLOCK(&g_mutex, return -1); + + /* Unlink entry from new directory */ + + if (new_dentry->d_inode) { + iscsi_trace(TRACE_OSDFS, "unlinking existing file\n"); + if (osdfs_unlink(new_dir, new_dentry)!=0) { + iscsi_trace_error("osdfs_unlink() failed\n"); + return -1; + } + } + + /* Add entry to new directory (might be the same dir) */ + + ISCSI_LOCK(&g_mutex, return -1); + if (entry_add(dev, new_dir_ino, new_ino, new_name, &new_dir->i_size)!=0) { + iscsi_trace_error("error adding new entry \"%s\"\n", new_name); + ISCSI_UNLOCK(&g_mutex, return -1); + return -1; + } + osdfs_write_inode(new_dir, 0); + ISCSI_UNLOCK(&g_mutex, return -1); + + return 0; +} + +static struct inode_operations osdfs_dir_inode_operations = { + create: osdfs_create, + lookup: osdfs_lookup, + link: osdfs_link, + unlink: osdfs_unlink, + symlink: osdfs_symlink, + mkdir: osdfs_mkdir, + rmdir: osdfs_unlink, + mknod: osdfs_mknod, + rename: osdfs_rename, +}; + + +/* + * File operations (regular files) + */ + + +static int osdfs_sync_file(struct file * file, struct dentry *dentry, int datasync) { + iscsi_trace_error("osdfs_syncfile() not implemented\n"); + return -1; +} + +static struct file_operations osdfs_file_operations = { + read: generic_file_read, + write: generic_file_write, + mmap: generic_file_mmap, + fsync: osdfs_sync_file, +}; + + +/* + * File operations (directories) + */ + + +static int osdfs_readdir(struct file * filp, void * dirent, filldir_t filldir) { + struct dentry *dentry = filp->f_dentry; + const char *name; + ino_t ino = dentry->d_inode->i_ino; + kdev_t dev = dentry->d_inode->i_sb->s_dev; + int offset = filp->f_pos; + char *entries, *ptr, *ptr2; + uint32_t num_entries; + uint64_t size; + uint64_t uid = ino; + + name = dentry->d_name.name; + iscsi_trace(TRACE_OSDFS, "osdfs_readdir(\"%s\", ino 0x%x, offset %i)\n", + name, (unsigned) ino, offset); + ISCSI_LOCK(&g_mutex, return -1); + if (entries_get(dev, uid, &entries, &num_entries, &size)!=0) { + iscsi_trace_error("entries_get() failed\n"); + ISCSI_UNLOCK(&g_mutex, return -1); + return -1; + } + ISCSI_UNLOCK(&g_mutex, return -1); + + /* Update the offset if our number of entries has changed since the last */ + /* call to osdfs_readdir(). filp->private_data stores the number of */ + /* entries this directory had on the last call. */ + + if (offset) { + if (((int)filp->private_data)>num_entries) { + filp->f_pos = offset -= (((int)filp->private_data)-num_entries); + filp->private_data = (void *) num_entries; + } + } else { + filp->private_data = (void *) num_entries; + } + + switch (offset) { + + case 0: + + iscsi_trace(TRACE_OSDFS, "adding \".\" (ino 0x%x)\n", (unsigned) ino); + if (filldir(dirent, ".", 1, filp->f_pos++, ino, DT_DIR) < 0) { + iscsi_trace_error("filldir() failed for \".\"??\n"); + vfree(entries); + return -1; + } + + case 1: + + iscsi_trace(TRACE_OSDFS, "adding \"..\" (ino 0x%x)\n", (unsigned) dentry->d_parent->d_inode->i_ino); + if (filldir(dirent, "..", 2, filp->f_pos++, dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { + iscsi_trace_error("filldir() failed for \"..\"??\n"); + vfree(entries); + return -1; + } + + default: + + if (!num_entries) return 0; + ptr = entries; + offset -= 2; + do { + if ((ptr2=strchr(ptr, '\n'))!=NULL) { + *ptr2 = 0x0; + ptr2 = strchr(ptr2+1, '\n'); + if (offset>0) { + offset--; + } else { + sscanf(ptr+strlen(ptr)+1, "%li", &ino); + iscsi_trace(TRACE_OSDFS, "adding \"%s\" (ino 0x%x)\n", ptr, (unsigned) ino); + if (filldir(dirent, ptr, strlen(ptr), filp->f_pos++, ino, DT_UNKNOWN) < 0) { + vfree(entries); + return 0; + } + } + } + } while (ptr2&&(ptr=ptr2+1)); + } + if (num_entries) vfree(entries); + + return 0; +} + +static struct file_operations osdfs_dir_operations = { + read: generic_read_dir, + readdir: osdfs_readdir, + fsync: osdfs_sync_file, +}; + + +/* + * Address space operations + */ + + +static int osdfs_readpage(struct file *file, struct page * page) { + uint64_t Offset = page->index<<PAGE_CACHE_SHIFT; + uint64_t Length = 1<<PAGE_CACHE_SHIFT; + struct inode *inode = page->mapping->host; + kdev_t dev = inode->i_sb->s_dev; + ino_t ino = inode->i_ino; + uint64_t len; + uint64_t uid = ino; + + iscsi_trace(TRACE_OSDFS, "osdfs_readpage(ino %lu, Offset %llu, Length %llu)\n", ino, Offset, Length); + if (Offset+Length>inode->i_size) { + len = inode->i_size-Offset; + } else { + len = Length; + } + if (!Page_Uptodate(page)) { + memset(kmap(page), 0, PAGE_CACHE_SIZE); + if (osd_read((void *)&dev, root_gid, uid, Offset, len, page->virtual, 0, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_read() failed\n"); + UnlockPage(page); + return -1;; + } + kunmap(page); + flush_dcache_page(page); + SetPageUptodate(page); + } else { + iscsi_trace_error("The page IS up to date???\n"); + } + UnlockPage(page); + + return 0; +} + +static int osdfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) { + iscsi_trace(TRACE_OSDFS, "osdfs_prepare_write(ino %lu, offset %u, to %u)\n", page->mapping->host->i_ino, offset, to); + return 0; +} + +static int osdfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) { + uint64_t Offset = (page->index<<PAGE_CACHE_SHIFT)+offset; + uint64_t Length = to-offset; + struct inode *inode = page->mapping->host; + kdev_t dev = inode->i_sb->s_dev; + ino_t ino = inode->i_ino; + uint64_t uid = ino; + + iscsi_trace(TRACE_OSDFS, "osdfs_commit_write(ino %lu, offset %u, to %u, Offset %llu, Length %llu)\n", + ino, offset, to, Offset, Length); + if (osd_write((void *)&dev, root_gid, uid, Offset, Length, page->virtual+offset, 0, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_write() failed\n"); + return -1; + } + if (Offset+Length>inode->i_size) { + inode->i_size = Offset+Length; + } + osdfs_write_inode(inode, 0); + + return 0; +} + +static struct address_space_operations osdfs_aops = { + readpage: osdfs_readpage, + writepage: NULL, + prepare_write: osdfs_prepare_write, + commit_write: osdfs_commit_write +}; + + +/* + * Superblock operations + */ + + +static struct super_block *osdfs_read_super(struct super_block *sb, void *data, int silent) { + char opt[64]; + char *ptr, *ptr2; + struct inode attr; + struct inode *inode; + + iscsi_trace(TRACE_OSDFS, "osdfs_read_super(major %i minor %i)\n", MAJOR(sb->s_dev), MINOR(sb->s_dev)); + + root_gid = root_uid = 0; + + /* Parse options */ + + ptr = (char *)data; + while (ptr&&strlen(ptr)) { + if ((ptr2=strchr(ptr, ','))) { + strncpy(opt, ptr, ptr2-ptr); + opt[ptr2-ptr] = 0x0; + ptr = ptr2+1; + } else { + strcpy(opt, ptr); + ptr = 0x0; + } + if (!strncmp(opt, "uid=", 3)) { + if (sscanf(opt, "uid=0x%Lx", &root_uid)!=1) { + iscsi_trace_error("malformed option \"%s\"\n", opt); + return NULL; + } + } else if (!strncmp(opt, "gid=", 3)) { + if (sscanf(opt, "gid=0x%x", &root_gid)!=1) { + iscsi_trace_error("malformed option \"%s\"\n", opt); + return NULL; + } + } else { + iscsi_trace_error("unknown option \"%s\"\n", opt); + return NULL; + } + } + + /* Initialize superblock */ + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = OSDFS_MAGIC; + sb->s_op = &osdfs_ops; + + if ((root_uid==0)||(root_gid==0)) { + + /* Create group object for root directory */ + + if (osd_create_group((void *)&sb->s_dev, &osd_exec_via_scsi, &root_gid)!=0) { + iscsi_trace_error("osd_create_group() failed\n"); + return NULL; + } + printf("** ROOT DIRECTORY GROUP OBJECT IS 0x%x **\n", root_gid); + + /* Create user object for root directory */ + + if (osd_create((void *)&sb->s_dev, root_gid, &osd_exec_via_scsi, &root_uid)!=0) { + iscsi_trace_error("osd_create() failed\n"); + return NULL; + } + printf("** ROOT DIRECTORY USER OBJECT IS 0x%llx **\n", root_uid); + + /* Initialize Attributes */ + + memset(&attr, 0, sizeof(struct inode)); + attr.i_mode = S_IFDIR | 0755; + if (osd_set_one_attr((void *)&sb->s_dev, root_gid, root_uid, 0x30000000, 0x1, sizeof(struct inode), (void *) &attr, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_set_one_attr() failed\n"); + return NULL; + } + } else { + iscsi_trace(TRACE_OSDFS, "using root directory in 0x%x:0x%llx\n", root_gid, root_uid); + } + + /* Create inode for root directory */ + + if ((inode=osdfs_get_inode(sb, S_IFDIR | 0755, 0, "/", root_uid))==NULL) { + iscsi_trace_error("osdfs_get_inode() failed\n"); + return NULL; + } + if ((sb->s_root=d_alloc_root(inode))==NULL) { + iscsi_trace_error("d_alloc_root() failed\n"); + iput(inode); + return NULL; + } + + return sb; +} + +static DECLARE_FSTYPE_DEV(osdfs_fs_type, "osdfs", osdfs_read_super); + + +/* + * Module operations + */ + + +static int __init init_osdfs_fs(void) { + iscsi_trace(TRACE_OSDFS, "init_osdfs_fs()\n"); + ISCSI_MUTEX_INIT(&g_mutex, return -1); + return register_filesystem(&osdfs_fs_type); +} + +static void __exit exit_osdfs_fs(void) { + iscsi_trace(TRACE_OSDFS, "exit_osdfs_fs()\n"); + ISCSI_MUTEX_DESTROY(&g_mutex, printk("mutex_destroy() failed\n")); + unregister_filesystem(&osdfs_fs_type); +} + +module_init(init_osdfs_fs) +module_exit(exit_osdfs_fs) Index: src/external/bsd/iscsi/dist/src/osd/start_osd diff -u /dev/null src/external/bsd/iscsi/dist/src/osd/start_osd:1.1 --- /dev/null Thu Jun 25 13:48:42 2009 +++ src/external/bsd/iscsi/dist/src/osd/start_osd Thu Jun 25 13:48:42 2009 @@ -0,0 +1,5 @@ +#!/bin/sh +insmod ./so.o +insmod ./intel_iscsi.o +insmod ./osdfs.o +mount -t osdfs /dev/so0 /mnt -o gid=0x2d159c01 -o uid=0x2c8f1801 Index: src/external/bsd/iscsi/dist/src/osd/stop_osd diff -u /dev/null src/external/bsd/iscsi/dist/src/osd/stop_osd:1.1 --- /dev/null Thu Jun 25 13:48:42 2009 +++ src/external/bsd/iscsi/dist/src/osd/stop_osd Thu Jun 25 13:48:42 2009 @@ -0,0 +1,5 @@ +#!/bin/sh +umount /mnt +rmmod osdfs +rmmod intel_iscsi +rmmod so