xref: /netbsd-src/external/bsd/iscsi/dist/src/osd/osdfs.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
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 
69 typedef struct osdfs_link_t {
70   char name[MAX_NAME_LEN];
71   struct osdfs_link_t* next;
72 } osdfs_link_t;
73 
74 typedef struct osdfs_inode_t {
75   osdfs_link_t  *link;
76 } osdfs_inode_t;
77 
78 typedef struct osdfs_metadata_t {
79   uint64_t ObjectID;
80   int      used;
81 } osdfs_metadata_t;
82 
83 
84 /*
85  * Prototypes
86  */
87 
88 static int osdfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev);
89 
90 
91 /*
92  * Globals
93  */
94 
95 
96 static struct super_operations osdfs_ops;
97 static struct address_space_operations osdfs_aops;
98 static struct file_operations osdfs_dir_operations;
99 static struct file_operations osdfs_file_operations;
100 static struct inode_operations osdfs_dir_inode_operations;
101 static uint32_t root_gid;
102 static uint64_t root_uid;
103 static iscsi_mutex_t g_mutex;
104 
105 
106 /*
107  * SCSI transport function for OSD
108  */
109 
110 
111 int 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 
176 static 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 
220 static 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 
247 static 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 
309 static 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 
325 static 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 
343 static 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 
368 static 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 
402 void osdfs_dirty_inode(struct inode *inode) {
403   iscsi_trace(TRACE_OSDFS, "osdfs_dirty_inode(ino 0x%x)\n", (unsigned) inode->i_ino);
404 }
405 
406 void 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 
419 void osdfs_put_inode(struct inode *inode) {
420   iscsi_trace(TRACE_OSDFS, "osdfs_put_inode(0x%x)\n", (unsigned) inode->i_ino);
421 }
422 
423 void 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 
428 void osdfs_put_super(struct super_block *sb) {
429   iscsi_err("osdfs_put_super() not implemented\n");
430 }
431 
432 void osdfs_write_super(struct super_block *sb) {
433   iscsi_err("osdfs_write_super() not implemented\n");
434 }
435 
436 void osdfs_write_super_lockfs(struct super_block *sb) {
437   iscsi_err("osdfs_write_super_lockfs() not implemented\n");
438 }
439 
440 void osdfs_unlockfs(struct super_block *sb) {
441   iscsi_err("osdfs_unlockfs() not implemented\n");
442 }
443 
444 int 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 
458 int 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 
464 void osdfs_clear_inode(struct inode *inode) {
465   iscsi_trace(TRACE_OSDFS, "osdfs_clear_inode(ino %lu)\n", inode->i_ino);
466 }
467 
468 void osdfs_umount_begin(struct super_block *sb) {
469   iscsi_err("osdfs_unmount_begin() not implemented\n");
470 }
471 
472 static 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 
494 static 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 
506 static 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 
559 static 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 
583 static 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 
625 static 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 
643 static 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 
653 static 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 
708 static 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 
762 static 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 
780 static 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 
785 static 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 
798 static 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 
880 static 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 
892 static 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 
925 static 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 
930 static 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 
952 static 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 
965 static 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 
1055 static DECLARE_FSTYPE_DEV(osdfs_fs_type, "osdfs", osdfs_read_super);
1056 
1057 
1058 /*
1059  * Module operations
1060  */
1061 
1062 
1063 static 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 
1069 static 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 
1075 module_init(init_osdfs_fs)
1076 module_exit(exit_osdfs_fs)
1077