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