1/* 2 * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or 3 * using the software you agree to this license. If you do not agree to this license, do not download, install, 4 * copy or use the software. 5 * 6 * Intel License Agreement 7 * 8 * Copyright (c) 2002, Intel Corporation 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that 12 * the following conditions are met: 13 * 14 * -Redistributions of source code must retain the above copyright notice, this list of conditions and the 15 * following disclaimer. 16 * 17 * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 18 * following disclaimer in the documentation and/or other materials provided with the distribution. 19 * 20 * -The name of Intel Corporation may not be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/* 34 * Object-Based Storage Devices (OSD) Filesystem for Linux 35 */ 36 37 38#include <linux/module.h> 39#include <linux/fs.h> 40#include <linux/pagemap.h> 41#include <linux/init.h> 42#include <linux/string.h> 43#include <linux/locks.h> 44#include <asm/uaccess.h> 45#include <endian.h> 46#include <linux/blkdev.h> 47#include <scsi.h> 48#include "osd.h" 49#include "osd_ops.h" 50#include "iscsiutil.h" 51#include "util.c" 52 53 54/* 55 * Contants 56 */ 57 58 59#define OSDFS_MAGIC 0xabcdef01 60#define MAX_INODES 32768 61#define MAX_NAME_LEN 32 62 63 64/* 65 * Types 66 */ 67 68 69typedef struct osdfs_link_t { 70 char name[MAX_NAME_LEN]; 71 struct osdfs_link_t* next; 72} osdfs_link_t; 73 74typedef struct osdfs_inode_t { 75 osdfs_link_t *link; 76} osdfs_inode_t; 77 78typedef struct osdfs_metadata_t { 79 uint64_t ObjectID; 80 int used; 81} osdfs_metadata_t; 82 83 84/* 85 * Prototypes 86 */ 87 88static int osdfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev); 89 90 91/* 92 * Globals 93 */ 94 95 96static struct super_operations osdfs_ops; 97static struct address_space_operations osdfs_aops; 98static struct file_operations osdfs_dir_operations; 99static struct file_operations osdfs_file_operations; 100static struct inode_operations osdfs_dir_inode_operations; 101static uint32_t root_gid; 102static uint64_t root_uid; 103static iscsi_mutex_t g_mutex; 104 105 106/* 107 * SCSI transport function for OSD 108 */ 109 110 111int osd_exec_via_scsi(void *dev, osd_args_t *args, OSD_OPS_MEM *m) { 112 Scsi_Request *SRpnt; 113 Scsi_Device *SDpnt; 114 unsigned char cdb[256]; 115 kdev_t kdev = *((kdev_t *) dev); 116 void *ptr = NULL; 117 int len = 0; 118 119 if (m->send_sg||m->recv_sg) { 120 iscsi_err("scatter/gather not yet implemented!\n"); 121 return -1; 122 } 123 124 SDpnt = blk_dev[MAJOR(kdev)].queue(kdev)->queuedata; 125 SRpnt = scsi_allocate_request(SDpnt); 126 SRpnt->sr_cmd_len = CONFIG_OSD_CDB_LEN; 127 SRpnt->sr_sense_buffer[0] = 0; 128 SRpnt->sr_sense_buffer[2] = 0; 129 switch(args->service_action) { 130 case OSD_WRITE: 131 case OSD_SET_ATTR: 132 len = m->send_len; 133 ptr = m->send_data; 134 SRpnt->sr_data_direction = SCSI_DATA_WRITE; 135 break; 136 case OSD_CREATE: 137 case OSD_CREATE_GROUP: 138 case OSD_READ: 139 case OSD_GET_ATTR: 140 len = m->recv_len; 141 ptr = m->recv_data; 142 SRpnt->sr_data_direction = SCSI_DATA_READ; 143 break; 144 case OSD_REMOVE: 145 case OSD_REMOVE_GROUP: 146 SRpnt->sr_data_direction = 0; 147 break; 148 default: 149 iscsi_err("unsupported OSD service action 0x%x\n", args->service_action); 150 return -1; 151 } 152 OSD_ENCAP_CDB(args, cdb); 153 154 /* Exec SCSI command */ 155 156 scsi_wait_req(SRpnt, cdb, ptr, len, 5*HZ, 5); 157 if (SRpnt->sr_result!=0) { 158 iscsi_err("SCSI command failed (result %u)\n", SRpnt->sr_result); 159 scsi_release_request(SRpnt); 160 SRpnt = NULL; 161 return -1; 162 } 163 scsi_release_request(SRpnt); 164 SRpnt = NULL; 165 166 return 0; 167} 168 169/* 170 * Internal OSDFS functions 171 */ 172 173 174/* Directory operations */ 175 176static int entries_get(kdev_t dev, uint64_t uid, char **entries, uint32_t *num, uint64_t *size) { 177 struct inode inode; 178 uint16_t len; 179 180 if (osd_get_one_attr((void *)&dev, root_gid, uid, 0x30000000, 0x0, sizeof(struct inode), &osd_exec_via_scsi, &len, (void *) &inode)!=0) { 181 iscsi_err("osd_get_one_attr() failed\n"); 182 return -1; 183 } 184 *num = 0; 185 if ((*size=inode.i_size)) { 186 char *ptr, *ptr2; 187 int n = 0; 188 189 if ((*entries=vmalloc(*size+1))==NULL) { 190 iscsi_err("vmalloc() failed\n"); 191 return -1; 192 } 193 if (osd_read((void *)&dev, root_gid, uid, 0, *size, *entries, 0, &osd_exec_via_scsi)!=0) { 194 iscsi_err("osd_read() failed\n"); 195 vfree(*entries); 196 return -1; 197 } 198 (*entries)[*size] = 0x0; 199 ptr = *entries; 200 do { 201 n++; 202 if ((ptr2=strchr(ptr, '\n'))!=NULL) { 203 n++; 204 if ((ptr2 = strchr(ptr2+1, '\n'))==NULL) { 205 iscsi_err("directory 0x%llx corrupted (line %i)\n", uid, n); 206 return -1; 207 } 208 (*num)++; 209 } else { 210 iscsi_err("directory 0x%llx corrupted (line %i)\n", uid, n); 211 return -1; 212 } 213 ptr = ptr2+1; 214 } while (*ptr); 215 } 216 217 return 0; 218} 219 220static int entry_add(kdev_t dev, ino_t dir_ino, ino_t entry_ino, 221 const char *name, uint64_t *new_size) { 222 char entry[MAX_NAME_LEN+16]; 223 uint64_t uid = dir_ino; 224 struct inode inode; 225 uint16_t len; 226 227 /* Get size of directory */ 228 229 if (osd_get_one_attr((void *)&dev, root_gid, uid, 0x30000000, 0x0, sizeof(struct inode), &osd_exec_via_scsi, &len, (void *) &inode)!=0) { 230 iscsi_err("osd_get_one_attr() failed\n"); 231 return -1; 232 } 233 234 /* Write entry at end */ 235 236 sprintf(entry, "%s\n", name); 237 sprintf(entry+strlen(entry), "%li\n", entry_ino); 238 if (osd_write((void *)&dev, root_gid, uid, inode.i_size, strlen(entry), entry, 0, &osd_exec_via_scsi)!=0) { 239 iscsi_err("osd_write() failed\n"); 240 return -1; 241 } 242 *new_size += strlen(entry); 243 244 return 0; 245} 246 247static int entry_del(kdev_t dev, ino_t dir_ino, ino_t ino, const char *name, uint64_t *new_size) { 248 char *entries; 249 uint32_t num_entries; 250 uint64_t size; 251 uint64_t dir_uid = (unsigned) dir_ino; 252 253 /* Read */ 254 255 if (entries_get(dev, dir_ino, &entries, &num_entries, &size)!=0) { 256 iscsi_err("entries_get() failed\n"); 257 return -1; 258 } 259 entries[size] = 0x0; 260 261 iscsi_trace(TRACE_OSDFS, "dir_ino 0x%llx has %u entries\n", dir_uid, num_entries); 262 if (num_entries) { 263 char *ptr = entries; 264 char *tmp = NULL; 265 char *nl; 266 int n = 0; 267 268 do { 269 n++; 270 if ((nl=strchr(ptr, '\n'))==NULL) { 271 iscsi_err("directory 0x%llx corrupted (line %i)\n", dir_uid, n); 272 return -1; 273 } 274 *nl = 0x0; 275 if (!strcmp(ptr, name)) { 276 tmp = ptr; 277 } 278 *nl = '\n'; 279 n++; 280 if ((ptr=strchr(nl+1, '\n'))==NULL) { 281 iscsi_err("directory 0x%llx corrupted (line %i)\n", dir_uid, n); 282 return -1; 283 } 284 ptr++; 285 } while (!tmp && *ptr); 286 287 if (!tmp) { 288 iscsi_err("entry \"%s\" not found in dir 0x%llx\n", name, dir_uid); 289 return -1; 290 } 291 if (entries+size-ptr) { 292 iscsi_trace(TRACE_OSDFS, "writing remaining %u directory bytes at offset %u\n", 293 entries+size-ptr, tmp-entries); 294 if (osd_write((void *)&dev, root_gid, dir_uid, tmp-entries, entries+size-ptr, ptr, 0, &osd_exec_via_scsi)!=0) { 295 iscsi_err("osd_write() failed\n"); 296 return -1; 297 } 298 } 299 *new_size = size-(ptr-tmp); 300 vfree(entries); 301 } else { 302 iscsi_err("dir 0x%llx has no entries\n", dir_uid); 303 return -1; 304 } 305 306 return 0; 307} 308 309static int entry_num(kdev_t dev, ino_t ino) { 310 char *entries; 311 uint32_t num_entries; 312 uint64_t size; 313 314 if (entries_get(dev, ino, &entries, &num_entries, &size)!=0) { 315 iscsi_err("entries_get() failed\n"); 316 return -1; 317 } 318 iscsi_trace(TRACE_OSDFS, "ino %li has %i entries\n", ino, num_entries); 319 if (num_entries) vfree(entries); 320 return num_entries; 321} 322 323/* Inode operations */ 324 325static void osdfs_set_ops(struct inode *inode) { 326 switch (inode->i_mode & S_IFMT) { 327 case S_IFREG: 328 inode->i_fop = &osdfs_file_operations; 329 break; 330 case S_IFDIR: 331 inode->i_op = &osdfs_dir_inode_operations; 332 inode->i_fop = &osdfs_dir_operations; 333 break; 334 case S_IFLNK: 335 inode->i_op = &page_symlink_inode_operations; 336 break; 337 default: 338 iscsi_err("UNKNOWN MODE\n"); 339 } 340 inode->i_mapping->a_ops = &osdfs_aops; 341} 342 343static struct inode *osdfs_get_inode(struct super_block *sb, int mode, int dev, const char *name, 344 uint64_t ObjectID) { 345 struct inode *inode; 346 ino_t ino = ObjectID; 347 348 iscsi_trace(TRACE_OSDFS, "osdfs_get_inode(\"%s\", mode %i (%s))\n", name, mode, 349 S_ISDIR(mode)?"DIR":(S_ISREG(mode)?"REG":"LNK")); 350 351 /* iget() gets a free VFS inode and subsequently call */ 352 /* osdfds_read_inode() to fill the inode structure. */ 353 354 if ((inode=iget(sb, ino))==NULL) { 355 iscsi_err("iget() failed\n"); 356 return NULL; 357 } 358 359 return inode; 360} 361 362 363/* 364 * Super Operations 365 */ 366 367 368static void osdfs_read_inode(struct inode *inode) { 369 ino_t ino = inode->i_ino; 370 kdev_t dev = inode->i_sb->s_dev; 371 uint64_t uid = ino; 372 unsigned char *attr; 373 uint16_t len; 374 375 iscsi_trace(TRACE_OSDFS, "osdfs_read_inode(ino 0x%x, major %i, minor %i)\n", 376 (unsigned) ino, MAJOR(dev), MINOR(dev)); 377 378 /* Get object attributes for rest of inode */ 379 380 if ((attr=iscsi_malloc_atomic(sizeof(struct inode)))==NULL) { 381 iscsi_err("iscsi_malloc_atomic() failed\n"); 382 } 383 if (osd_get_one_attr((void *)&dev, root_gid, uid, 0x30000000, 0x0, sizeof(struct inode), &osd_exec_via_scsi, &len, attr)!=0) { 384 iscsi_err("osd_get_one_attr() failed\n"); 385 return; 386 } 387 388 inode->i_size = ((struct inode *)(attr))->i_size; 389 inode->i_mode = ((struct inode *)(attr))->i_mode; 390 inode->i_nlink = ((struct inode *)(attr))->i_nlink; 391 inode->i_gid = ((struct inode *)(attr))->i_gid; 392 inode->i_uid = ((struct inode *)(attr))->i_uid; 393 inode->i_ctime = ((struct inode *)(attr))->i_ctime; 394 inode->i_atime = ((struct inode *)(attr))->i_atime; 395 inode->i_mtime = ((struct inode *)(attr))->i_mtime; 396 397 iscsi_free_atomic(attr); 398 399 osdfs_set_ops(inode); 400} 401 402void osdfs_dirty_inode(struct inode *inode) { 403 iscsi_trace(TRACE_OSDFS, "osdfs_dirty_inode(ino 0x%x)\n", (unsigned) inode->i_ino); 404} 405 406void osdfs_write_inode(struct inode *inode, int sync) { 407 ino_t ino = inode->i_ino; 408 kdev_t dev = inode->i_sb->s_dev; 409 uint64_t uid = ino; 410 411 iscsi_trace(TRACE_OSDFS, "osdfs_write_inode(0x%llx)\n", uid); 412 413 if (osd_set_one_attr((void *)&dev, root_gid, uid, 0x30000000, 0x1, sizeof(struct inode), (void *) inode, &osd_exec_via_scsi)!=0) { 414 iscsi_err("osd_set_one_attr() failed\n"); 415 } 416 inode->i_state &= ~I_DIRTY; 417} 418 419void osdfs_put_inode(struct inode *inode) { 420 iscsi_trace(TRACE_OSDFS, "osdfs_put_inode(0x%x)\n", (unsigned) inode->i_ino); 421} 422 423void osdfs_delete_inode(struct inode *inode) { 424 iscsi_trace(TRACE_OSDFS, "osdfs_delete_inode(%lu)\n", inode->i_ino); 425 clear_inode(inode); 426} 427 428void osdfs_put_super(struct super_block *sb) { 429 iscsi_err("osdfs_put_super() not implemented\n"); 430} 431 432void osdfs_write_super(struct super_block *sb) { 433 iscsi_err("osdfs_write_super() not implemented\n"); 434} 435 436void osdfs_write_super_lockfs(struct super_block *sb) { 437 iscsi_err("osdfs_write_super_lockfs() not implemented\n"); 438} 439 440void osdfs_unlockfs(struct super_block *sb) { 441 iscsi_err("osdfs_unlockfs() not implemented\n"); 442} 443 444int osdfs_statfs(struct super_block *sb, struct statfs *buff) { 445 iscsi_trace(TRACE_OSDFS, "statfs()\n"); 446 buff->f_type = OSDFS_MAGIC; 447 buff->f_bsize = PAGE_CACHE_SIZE; 448 buff->f_blocks = 256; 449 buff->f_bfree = 128; 450 buff->f_bavail = 64; 451 buff->f_files = 0; 452 buff->f_ffree = 0; 453 buff->f_namelen = MAX_NAME_LEN; 454 455 return 0; 456} 457 458int osdfs_remount_fs(struct super_block *sb, int *i, char *c) { 459 iscsi_err("osdfs_remount_fs() not implemented\n"); 460 461 return -1; 462} 463 464void osdfs_clear_inode(struct inode *inode) { 465 iscsi_trace(TRACE_OSDFS, "osdfs_clear_inode(ino %lu)\n", inode->i_ino); 466} 467 468void osdfs_umount_begin(struct super_block *sb) { 469 iscsi_err("osdfs_unmount_begin() not implemented\n"); 470} 471 472static struct super_operations osdfs_ops = { 473 read_inode: osdfs_read_inode, 474 dirty_inode: osdfs_dirty_inode, 475 write_inode: osdfs_write_inode, 476 put_inode: osdfs_put_inode, 477 delete_inode: osdfs_delete_inode, 478 put_super: osdfs_put_super, 479 write_super: osdfs_write_super, 480 write_super_lockfs: osdfs_write_super_lockfs, 481 unlockfs: osdfs_unlockfs, 482 statfs: osdfs_statfs, 483 remount_fs: osdfs_remount_fs, 484 clear_inode: osdfs_clear_inode, 485 umount_begin: osdfs_umount_begin 486}; 487 488 489/* 490 * Inode operations for directories 491 */ 492 493 494static int osdfs_create(struct inode *dir, struct dentry *dentry, int mode) { 495 496 iscsi_trace(TRACE_OSDFS, "osdfs_create(\"%s\")\n", dentry->d_name.name); 497 if (osdfs_mknod(dir, dentry, mode | S_IFREG, 0)!=0) { 498 iscsi_err("osdfs_mknod() failed\n"); 499 return -1; 500 } 501 iscsi_trace(TRACE_OSDFS, "file \"%s\" is inode 0x%x\n", dentry->d_name.name, (unsigned) dentry->d_inode->i_ino); 502 503 return 0; 504} 505 506static struct dentry * osdfs_lookup(struct inode *dir, struct dentry *dentry) { 507 const char *name = dentry->d_name.name; 508 struct inode *inode = NULL; 509 ino_t ino; 510 kdev_t dev = dir->i_sb->s_dev; 511 uint64_t uid = dir->i_ino; 512 char *entries; 513 uint32_t num_entries; 514 uint64_t size; 515 516 iscsi_trace(TRACE_OSDFS, "osdfs_lookup(\"%s\" in dir ino %lu)\n", name, dir->i_ino); 517 518 /* Get directory entries */ 519 520 ISCSI_LOCK(&g_mutex, return NULL); 521 if (entries_get(dev, uid, &entries, &num_entries, &size)!=0) { 522 iscsi_err("entries_get() failed\n"); 523 ISCSI_UNLOCK(&g_mutex, return NULL); 524 return NULL; 525 } 526 ISCSI_UNLOCK(&g_mutex, return NULL); 527 iscsi_trace(TRACE_OSDFS, "ino %li has %i entries\n", dir->i_ino, num_entries); 528 529 /* Search for this entry */ 530 531 if (num_entries) { 532 char *ptr = entries; 533 char *ptr2; 534 535 do { 536 if ((ptr2=strchr(ptr, '\n'))!=NULL) { 537 *ptr2 = 0x0; 538 ptr2 = strchr(ptr2+1, '\n'); 539 if (!strcmp(ptr, name)) { 540 sscanf(ptr+strlen(ptr)+1, "%li", &ino); 541 iscsi_trace(TRACE_OSDFS, "found \"%s\" at ino %li\n", name, ino); 542 if ((inode=iget(dir->i_sb, ino))==NULL) { 543 iscsi_err("iget() failed\n"); 544 return NULL; 545 } 546 } 547 } 548 } while (ptr2&&(ptr=ptr2+1)); 549 vfree(entries); 550 } 551 if (!inode) { 552 iscsi_trace(TRACE_OSDFS, "\"%s\" not found\n", name); 553 } 554 d_add(dentry, inode); 555 556 return NULL; 557} 558 559static int osdfs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry) { 560 struct inode *inode = old_dentry->d_inode; 561 kdev_t dev = dir->i_sb->s_dev; 562 ino_t dir_ino = dir->i_ino; 563 ino_t ino = inode->i_ino; 564 const char *name = dentry->d_name.name; 565 566 if (S_ISDIR(inode->i_mode)) return -EPERM; 567 iscsi_trace(TRACE_OSDFS, "osdfs_link(%lu, \"%s\")\n", ino, name); 568 ISCSI_LOCK(&g_mutex, return -1); 569 if (entry_add(dev, dir_ino, ino, name, &dir->i_size)!=0) { 570 iscsi_err("entry_add() failed\n"); 571 return -1; 572 } 573 inode->i_nlink++; 574 atomic_inc(&inode->i_count); 575 osdfs_write_inode(inode, 0); 576 osdfs_write_inode(dir, 0); 577 d_instantiate(dentry, inode); 578 ISCSI_UNLOCK(&g_mutex, return -1); 579 580 return 0; 581} 582 583static int osdfs_unlink(struct inode * dir, struct dentry *dentry) { 584 kdev_t dev = dir->i_sb->s_dev; 585 struct inode *inode = dentry->d_inode; 586 ino_t dir_ino = dir->i_ino; 587 ino_t ino = dentry->d_inode->i_ino; 588 const char *name = dentry->d_name.name; 589 590 iscsi_trace(TRACE_OSDFS, "osdfs_unlink(\"%s\", ino 0x%x)\n", name, (unsigned) ino); 591 ISCSI_LOCK(&g_mutex, return -1); 592 switch (inode->i_mode & S_IFMT) { 593 case S_IFREG: 594 case S_IFLNK: 595 break; 596 case S_IFDIR: 597 if (entry_num(dev, ino)) { 598 iscsi_err("directory 0x%x still has %i entries\n", 599 (unsigned) ino, entry_num(dev, ino)); 600 ISCSI_UNLOCK(&g_mutex, return -1); 601 return -ENOTEMPTY; 602 } 603 } 604 if (entry_del(dev, dir_ino, ino, name, &(dir->i_size))!=0) { 605 iscsi_err("entry_del() failed\n"); 606 ISCSI_UNLOCK(&g_mutex, return -1); 607 return -1; 608 } 609 osdfs_write_inode(dir, 0); 610 if (--inode->i_nlink) { 611 iscsi_trace(TRACE_OSDFS, "ino 0x%x still has %i links\n", (unsigned) ino, inode->i_nlink); 612 osdfs_write_inode(inode, 0); 613 } else { 614 iscsi_trace(TRACE_OSDFS, "ino 0x%x link count reached 0, removing object\n", (unsigned) ino); 615 if (osd_remove((void *)&dev, root_gid, ino, &osd_exec_via_scsi)!=0) { 616 iscsi_err("osd_remove() failed\n"); 617 return -1; 618 } 619 } 620 ISCSI_UNLOCK(&g_mutex, return -1); 621 622 return 0; 623} 624 625static int osdfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) { 626 struct inode *inode; 627 628 iscsi_trace(TRACE_OSDFS, "osdfs_symlink(\"%s\"->\"%s\")\n", dentry->d_name.name, symname); 629 if (osdfs_mknod(dir, dentry, S_IRWXUGO | S_IFLNK, 0)!=0) { 630 iscsi_err("osdfs_mknod() failed\n"); 631 return -1; 632 } 633 inode = dentry->d_inode; 634 if (block_symlink(inode, symname, strlen(symname)+1)!=0) { 635 iscsi_err("block_symlink() failed\n"); 636 return -1; 637 } 638 iscsi_trace(TRACE_OSDFS, "symbolic link \"%s\" is inode %lu\n", dentry->d_name.name, inode->i_ino); 639 640 return 0; 641} 642 643static int osdfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) { 644 645 iscsi_trace(TRACE_OSDFS, "osdfs_mkdir(\"%s\")\n", dentry->d_name.name); 646 if (osdfs_mknod(dir, dentry, mode | S_IFDIR, 0)!=0) { 647 iscsi_err("osdfs_mkdir() failed\n"); 648 } 649 650 return 0; 651} 652 653static int osdfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev_in) { 654 struct inode *inode = NULL; 655 uint64_t uid; 656 struct inode attr; 657 kdev_t dev = dir->i_sb->s_dev; 658 const char *name = dentry->d_name.name; 659 660 iscsi_trace(TRACE_OSDFS, "osdfs_mknod(\"%s\")\n", dentry->d_name.name); 661 662 /* Create object */ 663 664 if (osd_create((void *)&dev, root_gid, &osd_exec_via_scsi, &uid)!=0) { 665 iscsi_err("osd_create() failed\n"); 666 return -1; 667 } 668 669 /* Initialize object attributes */ 670 671 memset(&attr, 0, sizeof(struct inode)); 672 attr.i_mode = mode; 673 attr.i_uid = current->fsuid; 674 attr.i_gid = current->fsgid; 675 attr.i_ctime = CURRENT_TIME; 676 attr.i_atime = CURRENT_TIME; 677 attr.i_mtime = CURRENT_TIME; 678 attr.i_nlink = 1; 679 if (osd_set_one_attr((void *)&dir->i_sb->s_dev, root_gid, uid, 0x30000000, 0x1, sizeof(struct inode), 680 &attr, &osd_exec_via_scsi)!=0) { 681 iscsi_err("osd_set_one_attr() failed\n"); 682 return -1; 683 } 684 685 /* Assign to an inode */ 686 687 if ((inode = osdfs_get_inode(dir->i_sb, mode, dev, name, uid))==NULL) { 688 iscsi_err("osdfs_get_inode() failed\n"); 689 return -ENOSPC; 690 } 691 d_instantiate(dentry, inode); 692 693 /* Add entry to parent directory */ 694 695 if (inode->i_ino != 1) { 696 ISCSI_LOCK(&g_mutex, return -1); 697 if (entry_add(dev, dir->i_ino, inode->i_ino, name, &dir->i_size)!=0) { 698 iscsi_err("entry_add() failed\n"); 699 return -1; 700 } 701 osdfs_write_inode(dir, 0); 702 ISCSI_UNLOCK(&g_mutex, return -1); 703 } 704 705 return 0; 706} 707 708static int osdfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { 709 kdev_t dev = old_dir->i_sb->s_dev; 710 ino_t old_dir_ino = old_dir->i_ino; 711 ino_t new_dir_ino = new_dir->i_ino; 712 ino_t old_ino = old_dentry->d_inode->i_ino; 713 ino_t new_ino = new_dentry->d_inode?new_dentry->d_inode->i_ino:old_ino; 714 const char *old_name = old_dentry->d_name.name; 715 const char *new_name = new_dentry->d_name.name; 716 717 iscsi_trace(TRACE_OSDFS, "old_dir = 0x%p (ino 0x%x)\n", old_dir, (unsigned) old_dir_ino); 718 iscsi_trace(TRACE_OSDFS, "new_dir = 0x%p (ino 0x%x)\n", new_dir, (unsigned) new_dir_ino); 719 iscsi_trace(TRACE_OSDFS, "old_dentry = 0x%p (ino 0x%x)\n", old_dentry, (unsigned) old_ino); 720 iscsi_trace(TRACE_OSDFS, "new_dentry = 0x%p (ino 0x%x)\n", new_dentry, (unsigned) new_ino); 721 722 /* 723 * If we return -1, the VFS will implement a rename with a combination 724 * of osdfs_unlink() and osdfs_create(). 725 */ 726 727 /* Delete entry from old directory */ 728 729 ISCSI_LOCK(&g_mutex, return -1); 730 if (entry_del(dev, old_dir_ino, old_ino, old_name, &old_dir->i_size)!=0) { 731 iscsi_err("error deleting old entry \"%s\"\n", old_name); 732 ISCSI_UNLOCK(&g_mutex, return -1); 733 return -1; 734 } 735 osdfs_write_inode(old_dir, 0); 736 ISCSI_UNLOCK(&g_mutex, return -1); 737 738 /* Unlink entry from new directory */ 739 740 if (new_dentry->d_inode) { 741 iscsi_trace(TRACE_OSDFS, "unlinking existing file\n"); 742 if (osdfs_unlink(new_dir, new_dentry)!=0) { 743 iscsi_err("osdfs_unlink() failed\n"); 744 return -1; 745 } 746 } 747 748 /* Add entry to new directory (might be the same dir) */ 749 750 ISCSI_LOCK(&g_mutex, return -1); 751 if (entry_add(dev, new_dir_ino, new_ino, new_name, &new_dir->i_size)!=0) { 752 iscsi_err("error adding new entry \"%s\"\n", new_name); 753 ISCSI_UNLOCK(&g_mutex, return -1); 754 return -1; 755 } 756 osdfs_write_inode(new_dir, 0); 757 ISCSI_UNLOCK(&g_mutex, return -1); 758 759 return 0; 760} 761 762static struct inode_operations osdfs_dir_inode_operations = { 763 create: osdfs_create, 764 lookup: osdfs_lookup, 765 link: osdfs_link, 766 unlink: osdfs_unlink, 767 symlink: osdfs_symlink, 768 mkdir: osdfs_mkdir, 769 rmdir: osdfs_unlink, 770 mknod: osdfs_mknod, 771 rename: osdfs_rename, 772}; 773 774 775/* 776 * File operations (regular files) 777 */ 778 779 780static int osdfs_sync_file(struct file * file, struct dentry *dentry, int datasync) { 781 iscsi_err("osdfs_syncfile() not implemented\n"); 782 return -1; 783} 784 785static struct file_operations osdfs_file_operations = { 786 read: generic_file_read, 787 write: generic_file_write, 788 mmap: generic_file_mmap, 789 fsync: osdfs_sync_file, 790}; 791 792 793/* 794 * File operations (directories) 795 */ 796 797 798static int osdfs_readdir(struct file * filp, void * dirent, filldir_t filldir) { 799 struct dentry *dentry = filp->f_dentry; 800 const char *name; 801 ino_t ino = dentry->d_inode->i_ino; 802 kdev_t dev = dentry->d_inode->i_sb->s_dev; 803 int offset = filp->f_pos; 804 char *entries, *ptr, *ptr2; 805 uint32_t num_entries; 806 uint64_t size; 807 uint64_t uid = ino; 808 809 name = dentry->d_name.name; 810 iscsi_trace(TRACE_OSDFS, "osdfs_readdir(\"%s\", ino 0x%x, offset %i)\n", 811 name, (unsigned) ino, offset); 812 ISCSI_LOCK(&g_mutex, return -1); 813 if (entries_get(dev, uid, &entries, &num_entries, &size)!=0) { 814 iscsi_err("entries_get() failed\n"); 815 ISCSI_UNLOCK(&g_mutex, return -1); 816 return -1; 817 } 818 ISCSI_UNLOCK(&g_mutex, return -1); 819 820 /* Update the offset if our number of entries has changed since the last */ 821 /* call to osdfs_readdir(). filp->private_data stores the number of */ 822 /* entries this directory had on the last call. */ 823 824 if (offset) { 825 if (((int)filp->private_data)>num_entries) { 826 filp->f_pos = offset -= (((int)filp->private_data)-num_entries); 827 filp->private_data = (void *) num_entries; 828 } 829 } else { 830 filp->private_data = (void *) num_entries; 831 } 832 833 switch (offset) { 834 835 case 0: 836 837 iscsi_trace(TRACE_OSDFS, "adding \".\" (ino 0x%x)\n", (unsigned) ino); 838 if (filldir(dirent, ".", 1, filp->f_pos++, ino, DT_DIR) < 0) { 839 iscsi_err("filldir() failed for \".\"??\n"); 840 vfree(entries); 841 return -1; 842 } 843 844 case 1: 845 846 iscsi_trace(TRACE_OSDFS, "adding \"..\" (ino 0x%x)\n", (unsigned) dentry->d_parent->d_inode->i_ino); 847 if (filldir(dirent, "..", 2, filp->f_pos++, dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { 848 iscsi_err("filldir() failed for \"..\"??\n"); 849 vfree(entries); 850 return -1; 851 } 852 853 default: 854 855 if (!num_entries) return 0; 856 ptr = entries; 857 offset -= 2; 858 do { 859 if ((ptr2=strchr(ptr, '\n'))!=NULL) { 860 *ptr2 = 0x0; 861 ptr2 = strchr(ptr2+1, '\n'); 862 if (offset>0) { 863 offset--; 864 } else { 865 sscanf(ptr+strlen(ptr)+1, "%li", &ino); 866 iscsi_trace(TRACE_OSDFS, "adding \"%s\" (ino 0x%x)\n", ptr, (unsigned) ino); 867 if (filldir(dirent, ptr, strlen(ptr), filp->f_pos++, ino, DT_UNKNOWN) < 0) { 868 vfree(entries); 869 return 0; 870 } 871 } 872 } 873 } while (ptr2&&(ptr=ptr2+1)); 874 } 875 if (num_entries) vfree(entries); 876 877 return 0; 878} 879 880static struct file_operations osdfs_dir_operations = { 881 read: generic_read_dir, 882 readdir: osdfs_readdir, 883 fsync: osdfs_sync_file, 884}; 885 886 887/* 888 * Address space operations 889 */ 890 891 892static int osdfs_readpage(struct file *file, struct page * page) { 893 uint64_t Offset = page->index<<PAGE_CACHE_SHIFT; 894 uint64_t Length = 1<<PAGE_CACHE_SHIFT; 895 struct inode *inode = page->mapping->host; 896 kdev_t dev = inode->i_sb->s_dev; 897 ino_t ino = inode->i_ino; 898 uint64_t len; 899 uint64_t uid = ino; 900 901 iscsi_trace(TRACE_OSDFS, "osdfs_readpage(ino %lu, Offset %llu, Length %llu)\n", ino, Offset, Length); 902 if (Offset+Length>inode->i_size) { 903 len = inode->i_size-Offset; 904 } else { 905 len = Length; 906 } 907 if (!Page_Uptodate(page)) { 908 memset(kmap(page), 0, PAGE_CACHE_SIZE); 909 if (osd_read((void *)&dev, root_gid, uid, Offset, len, page->virtual, 0, &osd_exec_via_scsi)!=0) { 910 iscsi_err("osd_read() failed\n"); 911 UnlockPage(page); 912 return -1;; 913 } 914 kunmap(page); 915 flush_dcache_page(page); 916 SetPageUptodate(page); 917 } else { 918 iscsi_err("The page IS up to date???\n"); 919 } 920 UnlockPage(page); 921 922 return 0; 923} 924 925static int osdfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) { 926 iscsi_trace(TRACE_OSDFS, "osdfs_prepare_write(ino %lu, offset %u, to %u)\n", page->mapping->host->i_ino, offset, to); 927 return 0; 928} 929 930static int osdfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) { 931 uint64_t Offset = (page->index<<PAGE_CACHE_SHIFT)+offset; 932 uint64_t Length = to-offset; 933 struct inode *inode = page->mapping->host; 934 kdev_t dev = inode->i_sb->s_dev; 935 ino_t ino = inode->i_ino; 936 uint64_t uid = ino; 937 938 iscsi_trace(TRACE_OSDFS, "osdfs_commit_write(ino %lu, offset %u, to %u, Offset %llu, Length %llu)\n", 939 ino, offset, to, Offset, Length); 940 if (osd_write((void *)&dev, root_gid, uid, Offset, Length, page->virtual+offset, 0, &osd_exec_via_scsi)!=0) { 941 iscsi_err("osd_write() failed\n"); 942 return -1; 943 } 944 if (Offset+Length>inode->i_size) { 945 inode->i_size = Offset+Length; 946 } 947 osdfs_write_inode(inode, 0); 948 949 return 0; 950} 951 952static struct address_space_operations osdfs_aops = { 953 readpage: osdfs_readpage, 954 writepage: NULL, 955 prepare_write: osdfs_prepare_write, 956 commit_write: osdfs_commit_write 957}; 958 959 960/* 961 * Superblock operations 962 */ 963 964 965static struct super_block *osdfs_read_super(struct super_block *sb, void *data, int silent) { 966 char opt[64]; 967 char *ptr, *ptr2; 968 struct inode attr; 969 struct inode *inode; 970 971 iscsi_trace(TRACE_OSDFS, "osdfs_read_super(major %i minor %i)\n", MAJOR(sb->s_dev), MINOR(sb->s_dev)); 972 973 root_gid = root_uid = 0; 974 975 /* Parse options */ 976 977 ptr = (char *)data; 978 while (ptr&&strlen(ptr)) { 979 if ((ptr2=strchr(ptr, ','))) { 980 strncpy(opt, ptr, ptr2-ptr); 981 opt[ptr2-ptr] = 0x0; 982 ptr = ptr2+1; 983 } else { 984 strcpy(opt, ptr); 985 ptr = 0x0; 986 } 987 if (!strncmp(opt, "uid=", 3)) { 988 if (sscanf(opt, "uid=0x%Lx", &root_uid)!=1) { 989 iscsi_err("malformed option \"%s\"\n", opt); 990 return NULL; 991 } 992 } else if (!strncmp(opt, "gid=", 3)) { 993 if (sscanf(opt, "gid=0x%x", &root_gid)!=1) { 994 iscsi_err("malformed option \"%s\"\n", opt); 995 return NULL; 996 } 997 } else { 998 iscsi_err("unknown option \"%s\"\n", opt); 999 return NULL; 1000 } 1001 } 1002 1003 /* Initialize superblock */ 1004 1005 sb->s_blocksize = PAGE_CACHE_SIZE; 1006 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 1007 sb->s_magic = OSDFS_MAGIC; 1008 sb->s_op = &osdfs_ops; 1009 1010 if ((root_uid==0)||(root_gid==0)) { 1011 1012 /* Create group object for root directory */ 1013 1014 if (osd_create_group((void *)&sb->s_dev, &osd_exec_via_scsi, &root_gid)!=0) { 1015 iscsi_err("osd_create_group() failed\n"); 1016 return NULL; 1017 } 1018 printf("** ROOT DIRECTORY GROUP OBJECT IS 0x%x **\n", root_gid); 1019 1020 /* Create user object for root directory */ 1021 1022 if (osd_create((void *)&sb->s_dev, root_gid, &osd_exec_via_scsi, &root_uid)!=0) { 1023 iscsi_err("osd_create() failed\n"); 1024 return NULL; 1025 } 1026 printf("** ROOT DIRECTORY USER OBJECT IS 0x%llx **\n", root_uid); 1027 1028 /* Initialize Attributes */ 1029 1030 memset(&attr, 0, sizeof(struct inode)); 1031 attr.i_mode = S_IFDIR | 0755; 1032 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) { 1033 iscsi_err("osd_set_one_attr() failed\n"); 1034 return NULL; 1035 } 1036 } else { 1037 iscsi_trace(TRACE_OSDFS, "using root directory in 0x%x:0x%llx\n", root_gid, root_uid); 1038 } 1039 1040 /* Create inode for root directory */ 1041 1042 if ((inode=osdfs_get_inode(sb, S_IFDIR | 0755, 0, "/", root_uid))==NULL) { 1043 iscsi_err("osdfs_get_inode() failed\n"); 1044 return NULL; 1045 } 1046 if ((sb->s_root=d_alloc_root(inode))==NULL) { 1047 iscsi_err("d_alloc_root() failed\n"); 1048 iput(inode); 1049 return NULL; 1050 } 1051 1052 return sb; 1053} 1054 1055static DECLARE_FSTYPE_DEV(osdfs_fs_type, "osdfs", osdfs_read_super); 1056 1057 1058/* 1059 * Module operations 1060 */ 1061 1062 1063static int __init init_osdfs_fs(void) { 1064 iscsi_trace(TRACE_OSDFS, "init_osdfs_fs()\n"); 1065 ISCSI_MUTEX_INIT(&g_mutex, return -1); 1066 return register_filesystem(&osdfs_fs_type); 1067} 1068 1069static void __exit exit_osdfs_fs(void) { 1070 iscsi_trace(TRACE_OSDFS, "exit_osdfs_fs()\n"); 1071 ISCSI_MUTEX_DESTROY(&g_mutex, printk("mutex_destroy() failed\n")); 1072 unregister_filesystem(&osdfs_fs_type); 1073} 1074 1075module_init(init_osdfs_fs) 1076module_exit(exit_osdfs_fs) 1077