No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / iscsi / dist / src / osd / osdfs.c
blob0a053d755084e3237bbcc17792ca2b89b82e3d1b
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.
6 * Intel License Agreement
8 * Copyright (c) 2002, Intel Corporation
9 * All rights reserved.
11 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
12 * the following conditions are met:
14 * -Redistributions of source code must retain the above copyright notice, this list of conditions and the
15 * following disclaimer.
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.
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.
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.
34 * Object-Based Storage Devices (OSD) Filesystem for Linux
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"
55 * Contants
59 #define OSDFS_MAGIC 0xabcdef01
60 #define MAX_INODES 32768
61 #define MAX_NAME_LEN 32
65 * Types
69 typedef struct osdfs_link_t {
70 char name[MAX_NAME_LEN];
71 struct osdfs_link_t* next;
72 } osdfs_link_t;
74 typedef struct osdfs_inode_t {
75 osdfs_link_t *link;
76 } osdfs_inode_t;
78 typedef struct osdfs_metadata_t {
79 uint64_t ObjectID;
80 int used;
81 } osdfs_metadata_t;
85 * Prototypes
88 static int osdfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev);
92 * Globals
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;
107 * SCSI transport function for OSD
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;
119 if (m->send_sg||m->recv_sg) {
120 iscsi_err("scatter/gather not yet implemented!\n");
121 return -1;
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;
152 OSD_ENCAP_CDB(args, cdb);
154 /* Exec SCSI command */
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;
163 scsi_release_request(SRpnt);
164 SRpnt = NULL;
166 return 0;
170 * Internal OSDFS functions
174 /* Directory operations */
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;
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;
184 *num = 0;
185 if ((*size=inode.i_size)) {
186 char *ptr, *ptr2;
187 int n = 0;
189 if ((*entries=vmalloc(*size+1))==NULL) {
190 iscsi_err("vmalloc() failed\n");
191 return -1;
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;
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;
208 (*num)++;
209 } else {
210 iscsi_err("directory 0x%llx corrupted (line %i)\n", uid, n);
211 return -1;
213 ptr = ptr2+1;
214 } while (*ptr);
217 return 0;
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;
227 /* Get size of directory */
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;
234 /* Write entry at end */
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;
242 *new_size += strlen(entry);
244 return 0;
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;
253 /* Read */
255 if (entries_get(dev, dir_ino, &entries, &num_entries, &size)!=0) {
256 iscsi_err("entries_get() failed\n");
257 return -1;
259 entries[size] = 0x0;
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;
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;
274 *nl = 0x0;
275 if (!strcmp(ptr, name)) {
276 tmp = ptr;
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;
284 ptr++;
285 } while (!tmp && *ptr);
287 if (!tmp) {
288 iscsi_err("entry \"%s\" not found in dir 0x%llx\n", name, dir_uid);
289 return -1;
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;
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;
306 return 0;
309 static int entry_num(kdev_t dev, ino_t ino) {
310 char *entries;
311 uint32_t num_entries;
312 uint64_t size;
314 if (entries_get(dev, ino, &entries, &num_entries, &size)!=0) {
315 iscsi_err("entries_get() failed\n");
316 return -1;
318 iscsi_trace(TRACE_OSDFS, "ino %li has %i entries\n", ino, num_entries);
319 if (num_entries) vfree(entries);
320 return num_entries;
323 /* Inode operations */
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");
340 inode->i_mapping->a_ops = &osdfs_aops;
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;
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"));
351 /* iget() gets a free VFS inode and subsequently call */
352 /* osdfds_read_inode() to fill the inode structure. */
354 if ((inode=iget(sb, ino))==NULL) {
355 iscsi_err("iget() failed\n");
356 return NULL;
359 return inode;
364 * Super Operations
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;
375 iscsi_trace(TRACE_OSDFS, "osdfs_read_inode(ino 0x%x, major %i, minor %i)\n",
376 (unsigned) ino, MAJOR(dev), MINOR(dev));
378 /* Get object attributes for rest of inode */
380 if ((attr=iscsi_malloc_atomic(sizeof(struct inode)))==NULL) {
381 iscsi_err("iscsi_malloc_atomic() failed\n");
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;
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;
397 iscsi_free_atomic(attr);
399 osdfs_set_ops(inode);
402 void osdfs_dirty_inode(struct inode *inode) {
403 iscsi_trace(TRACE_OSDFS, "osdfs_dirty_inode(ino 0x%x)\n", (unsigned) inode->i_ino);
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;
411 iscsi_trace(TRACE_OSDFS, "osdfs_write_inode(0x%llx)\n", uid);
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");
416 inode->i_state &= ~I_DIRTY;
419 void osdfs_put_inode(struct inode *inode) {
420 iscsi_trace(TRACE_OSDFS, "osdfs_put_inode(0x%x)\n", (unsigned) inode->i_ino);
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);
428 void osdfs_put_super(struct super_block *sb) {
429 iscsi_err("osdfs_put_super() not implemented\n");
432 void osdfs_write_super(struct super_block *sb) {
433 iscsi_err("osdfs_write_super() not implemented\n");
436 void osdfs_write_super_lockfs(struct super_block *sb) {
437 iscsi_err("osdfs_write_super_lockfs() not implemented\n");
440 void osdfs_unlockfs(struct super_block *sb) {
441 iscsi_err("osdfs_unlockfs() not implemented\n");
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;
455 return 0;
458 int osdfs_remount_fs(struct super_block *sb, int *i, char *c) {
459 iscsi_err("osdfs_remount_fs() not implemented\n");
461 return -1;
464 void osdfs_clear_inode(struct inode *inode) {
465 iscsi_trace(TRACE_OSDFS, "osdfs_clear_inode(ino %lu)\n", inode->i_ino);
468 void osdfs_umount_begin(struct super_block *sb) {
469 iscsi_err("osdfs_unmount_begin() not implemented\n");
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
490 * Inode operations for directories
494 static int osdfs_create(struct inode *dir, struct dentry *dentry, int mode) {
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;
501 iscsi_trace(TRACE_OSDFS, "file \"%s\" is inode 0x%x\n", dentry->d_name.name, (unsigned) dentry->d_inode->i_ino);
503 return 0;
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;
516 iscsi_trace(TRACE_OSDFS, "osdfs_lookup(\"%s\" in dir ino %lu)\n", name, dir->i_ino);
518 /* Get directory entries */
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;
526 ISCSI_UNLOCK(&g_mutex, return NULL);
527 iscsi_trace(TRACE_OSDFS, "ino %li has %i entries\n", dir->i_ino, num_entries);
529 /* Search for this entry */
531 if (num_entries) {
532 char *ptr = entries;
533 char *ptr2;
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;
548 } while (ptr2&&(ptr=ptr2+1));
549 vfree(entries);
551 if (!inode) {
552 iscsi_trace(TRACE_OSDFS, "\"%s\" not found\n", name);
554 d_add(dentry, inode);
556 return NULL;
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;
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;
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);
580 return 0;
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;
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;
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;
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;
620 ISCSI_UNLOCK(&g_mutex, return -1);
622 return 0;
625 static int osdfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) {
626 struct inode *inode;
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;
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;
638 iscsi_trace(TRACE_OSDFS, "symbolic link \"%s\" is inode %lu\n", dentry->d_name.name, inode->i_ino);
640 return 0;
643 static int osdfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) {
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");
650 return 0;
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;
660 iscsi_trace(TRACE_OSDFS, "osdfs_mknod(\"%s\")\n", dentry->d_name.name);
662 /* Create object */
664 if (osd_create((void *)&dev, root_gid, &osd_exec_via_scsi, &uid)!=0) {
665 iscsi_err("osd_create() failed\n");
666 return -1;
669 /* Initialize object attributes */
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;
685 /* Assign to an inode */
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;
691 d_instantiate(dentry, inode);
693 /* Add entry to parent directory */
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;
701 osdfs_write_inode(dir, 0);
702 ISCSI_UNLOCK(&g_mutex, return -1);
705 return 0;
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;
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);
723 * If we return -1, the VFS will implement a rename with a combination
724 * of osdfs_unlink() and osdfs_create().
727 /* Delete entry from old directory */
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;
735 osdfs_write_inode(old_dir, 0);
736 ISCSI_UNLOCK(&g_mutex, return -1);
738 /* Unlink entry from new directory */
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;
748 /* Add entry to new directory (might be the same dir) */
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;
756 osdfs_write_inode(new_dir, 0);
757 ISCSI_UNLOCK(&g_mutex, return -1);
759 return 0;
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,
776 * File operations (regular files)
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;
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,
794 * File operations (directories)
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;
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;
818 ISCSI_UNLOCK(&g_mutex, return -1);
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. */
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;
829 } else {
830 filp->private_data = (void *) num_entries;
833 switch (offset) {
835 case 0:
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;
844 case 1:
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;
853 default:
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;
873 } while (ptr2&&(ptr=ptr2+1));
875 if (num_entries) vfree(entries);
877 return 0;
880 static struct file_operations osdfs_dir_operations = {
881 read: generic_read_dir,
882 readdir: osdfs_readdir,
883 fsync: osdfs_sync_file,
888 * Address space operations
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;
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;
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;;
914 kunmap(page);
915 flush_dcache_page(page);
916 SetPageUptodate(page);
917 } else {
918 iscsi_err("The page IS up to date???\n");
920 UnlockPage(page);
922 return 0;
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;
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;
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;
944 if (Offset+Length>inode->i_size) {
945 inode->i_size = Offset+Length;
947 osdfs_write_inode(inode, 0);
949 return 0;
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
961 * Superblock operations
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;
971 iscsi_trace(TRACE_OSDFS, "osdfs_read_super(major %i minor %i)\n", MAJOR(sb->s_dev), MINOR(sb->s_dev));
973 root_gid = root_uid = 0;
975 /* Parse options */
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;
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;
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;
997 } else {
998 iscsi_err("unknown option \"%s\"\n", opt);
999 return NULL;
1003 /* Initialize superblock */
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;
1010 if ((root_uid==0)||(root_gid==0)) {
1012 /* Create group object for root directory */
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;
1018 printf("** ROOT DIRECTORY GROUP OBJECT IS 0x%x **\n", root_gid);
1020 /* Create user object for root directory */
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;
1026 printf("** ROOT DIRECTORY USER OBJECT IS 0x%llx **\n", root_uid);
1028 /* Initialize Attributes */
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;
1036 } else {
1037 iscsi_trace(TRACE_OSDFS, "using root directory in 0x%x:0x%llx\n", root_gid, root_uid);
1040 /* Create inode for root directory */
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;
1046 if ((sb->s_root=d_alloc_root(inode))==NULL) {
1047 iscsi_err("d_alloc_root() failed\n");
1048 iput(inode);
1049 return NULL;
1052 return sb;
1055 static DECLARE_FSTYPE_DEV(osdfs_fs_type, "osdfs", osdfs_read_super);
1059 * Module operations
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);
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);
1075 module_init(init_osdfs_fs)
1076 module_exit(exit_osdfs_fs)