VFS: mounts KFS, shell functions
[akaros.git] / kern / src / vfs.c
1 /* Copyright (c) 2009, 2010 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Default implementations and global values for the VFS. */
6
7 #include <vfs.h> // keep this first
8 #include <sys/queue.h>
9 #include <assert.h>
10 #include <stdio.h>
11 #include <atomic.h>
12 #include <slab.h>
13 #include <kmalloc.h>
14 #include <kfs.h>
15
16 struct sb_tailq super_blocks = TAILQ_HEAD_INITIALIZER(super_blocks);
17 spinlock_t super_blocks_lock = SPINLOCK_INITIALIZER;
18 struct fs_type_tailq file_systems = TAILQ_HEAD_INITIALIZER(file_systems);
19 struct namespace default_ns;
20 // TODO: temp dcache, holds all dentries ever for now
21 struct dentry_slist dcache = SLIST_HEAD_INITIALIZER(dcache);
22 spinlock_t dcache_lock = SPINLOCK_INITIALIZER;
23
24 struct kmem_cache *dentry_kcache; // not to be confused with the dcache
25 struct kmem_cache *inode_kcache;
26 struct kmem_cache *file_kcache;
27
28 /* Mounts fs from dev_name at mnt_pt in namespace ns.  There could be no mnt_pt,
29  * such as with the root of (the default) namespace.  Not sure how it would work
30  * with multiple namespaces on the same FS yet.  Note if you mount the same FS
31  * multiple times, you only have one FS still (and one SB).  If we ever support
32  * that... */
33 struct vfsmount *mount_fs(struct fs_type *fs, char *dev_name,
34                           struct dentry *mnt_pt, int flags,
35                           struct namespace *ns)
36 {
37         struct super_block *sb;
38         struct vfsmount *vmnt = kmalloc(sizeof(struct vfsmount), 0);
39
40         /* Build the vfsmount, if there is no mnt_pt, mnt is the root vfsmount (for now).
41          * fields related to the actual FS, like the sb and the mnt_root are set in
42          * the fs-specific get_sb() call. */
43         if (!mnt_pt) {
44                 vmnt->mnt_parent = NULL;
45                 vmnt->mnt_mountpoint = NULL;
46         } else { /* common case, but won't be tested til we try to mount another FS */
47                 mnt_pt->d_mount_point = TRUE;
48                 mnt_pt->d_mounted_fs = vmnt;
49                 atomic_inc(&vmnt->mnt_refcnt); /* held by mnt_pt */
50                 vmnt->mnt_parent = mnt_pt->d_sb->s_mount;
51                 vmnt->mnt_mountpoint = mnt_pt;
52         }
53         TAILQ_INIT(&vmnt->mnt_child_mounts);
54         vmnt->mnt_flags = flags;
55         vmnt->mnt_devname = dev_name;
56         vmnt->mnt_namespace = ns;
57         atomic_inc(&ns->refcnt); /* held by vmnt */
58         atomic_set(&vmnt->mnt_refcnt, 1); /* for the ref in the NS tailq below */
59
60         /* Read in / create the SB */
61         sb = fs->get_sb(fs, flags, dev_name, vmnt);
62         if (!sb)
63                 panic("You're FS sucks");
64
65         /* TODO: consider moving this into get_sb or something, in case the SB
66          * already exists (mounting again) (if we support that) */
67         spin_lock(&super_blocks_lock);
68         TAILQ_INSERT_TAIL(&super_blocks, sb, s_list); /* storing a ref here... */
69         spin_unlock(&super_blocks_lock);
70
71         /* Update holding NS */
72         spin_lock(&ns->lock);
73         TAILQ_INSERT_TAIL(&ns->vfsmounts, vmnt, mnt_list);
74         spin_unlock(&ns->lock);
75         /* note to self: so, right after this point, the NS points to the root FS
76          * mount (we return the mnt, which gets assigned), the root mnt has a dentry
77          * for /, backed by an inode, with a SB prepped and in memory. */
78         return vmnt;
79 }
80
81 void vfs_init(void)
82 {
83         struct fs_type *fs;
84
85         dentry_kcache = kmem_cache_create("dentry", sizeof(struct dentry),
86                                           __alignof__(struct dentry), 0, 0, 0);
87         inode_kcache = kmem_cache_create("inode", sizeof(struct inode),
88                                          __alignof__(struct inode), 0, 0, 0);
89         file_kcache = kmem_cache_create("file", sizeof(struct file),
90                                         __alignof__(struct file), 0, 0, 0);
91
92         atomic_set(&default_ns.refcnt, 1); // default NS never dies, +1 to exist
93         spinlock_init(&default_ns.lock);
94         default_ns.root = NULL;
95         TAILQ_INIT(&default_ns.vfsmounts);
96
97         /* build list of all FS's in the system.  put yours here.  if this is ever
98          * done on the fly, we'll need to lock. */
99         TAILQ_INSERT_TAIL(&file_systems, &kfs_fs_type, list);
100         TAILQ_FOREACH(fs, &file_systems, list)
101                 printk("Supports the %s Filesystem\n", fs->name);
102
103         /* mounting KFS at the root (/), pending root= parameters */
104         // TODO: linux creates a temp root_fs, then mounts the real root onto that
105         default_ns.root = mount_fs(&kfs_fs_type, "RAM", NULL, 0, &default_ns);
106
107         printk("vfs_init() completed\n");
108         /*
109         put structs and friends in struct proc, and init in proc init
110         */
111         // LOOKUP: follow_mount, follow_link, etc
112         // pains in the ass for having .. or . in the middle of the path
113 }
114
115 /* Builds / populates the qstr of a dentry based on its d_iname.  If there is an
116  * l_name, (long), it will use that instead of the inline name.  This will
117  * probably change a bit. */
118 void qstr_builder(struct dentry *dentry, char *l_name)
119 {
120         dentry->d_name.name = l_name ? l_name : dentry->d_iname;
121         // TODO: pending what we actually do in d_hash
122         //dentry->d_name.hash = dentry->d_op->d_hash(dentry, &dentry->d_name); 
123         dentry->d_name.hash = 0xcafebabe;
124         dentry->d_name.len = strnlen(dentry->d_name.name, MAX_FILENAME_SZ);
125 }
126
127 /* Helper to alloc and initialize a generic superblock.  This handles all the
128  * VFS related things, like lists.  Each FS will need to handle its own things
129  * in it's *_get_sb(), usually involving reading off the disc. */
130 struct super_block *get_sb(void)
131 {
132         struct super_block *sb = kmalloc(sizeof(struct super_block), 0);
133         sb->s_dirty = FALSE;
134         spinlock_init(&sb->s_lock);
135         atomic_set(&sb->s_refcnt, 1); // for the ref passed out
136         TAILQ_INIT(&sb->s_inodes);
137         TAILQ_INIT(&sb->s_dirty_i);
138         TAILQ_INIT(&sb->s_io_wb);
139         SLIST_INIT(&sb->s_anon_d);
140         TAILQ_INIT(&sb->s_files);
141         sb->s_fs_info = 0; // can override somewhere else
142         return sb;
143 }
144
145 /* Final stages of initializing a super block, including creating and linking
146  * the root dentry, root inode, vmnt, and sb.  The d_op and root_ino are
147  * FS-specific, but otherwise it's FS-independent, tricky, and not worth having
148  * around multiple times.
149  *
150  * Not the world's best interface, so it's subject to change. */
151 void init_sb(struct super_block *sb, struct vfsmount *vmnt,
152              struct dentry_operations *d_op, unsigned long root_ino)
153 {
154         /* Build and init the first dentry / inode */
155         struct dentry *d_root = get_dentry(sb); /* ref held by vfsmount's mnt_root*/
156         strlcpy(d_root->d_iname, "/", MAX_FILENAME_SZ); /* probably right */
157         qstr_builder(d_root, 0);                                /* sets d_name */
158         /* a lot of here on down is normally done in lookup() */
159         d_root->d_op = d_op;
160         struct inode *inode = sb->s_op->alloc_inode(sb);
161         if (!inode)
162                 panic("This FS sucks!");
163         d_root->d_inode = inode;
164         TAILQ_INSERT_TAIL(&inode->i_dentry, d_root, d_child);
165         atomic_inc(&d_root->d_refcnt);                  /* held by the inode */
166         inode->i_ino = root_ino;
167         /* TODO: add the inode to the appropriate list (off i_list) */
168         /* TODO: do we need to read in the inode?  can we do this on demand? */
169         /* if this FS is already mounted, we'll need to do something different. */
170         sb->s_op->read_inode(inode);
171         /* Link the dentry and SB to the VFS mount */
172         vmnt->mnt_root = d_root;                                /* refcnt'd above */
173         vmnt->mnt_sb = sb;
174         /* If there is no mount point, there is no parent.  This is true only for
175          * the rootfs. */
176         if (vmnt->mnt_mountpoint) {
177                 d_root->d_parent = vmnt->mnt_mountpoint;        /* dentry of the root */
178                 atomic_inc(&vmnt->mnt_mountpoint->d_refcnt);/* held by d_root */
179         }
180         /* insert the dentry into the dentry cache.  when's the earliest we can?
181          * when's the earliest we should?  what about concurrent accesses to the
182          * same dentry?  should be locking the dentry... */
183         dcache_put(d_root);
184 }
185
186 /* Helper to alloc and initialize a generic dentry */
187 struct dentry *get_dentry(struct super_block *sb)
188 {
189         struct dentry *dentry = kmem_cache_alloc(dentry_kcache, 0);
190         //memset(dentry, 0, sizeof(struct dentry));
191         atomic_set(&dentry->d_refcnt, 1); // this ref is returned
192         spinlock_init(&dentry->d_lock);
193         TAILQ_INIT(&dentry->d_subdirs);
194         dentry->d_time = 0;
195         dentry->d_sb = sb; // storing a ref here...
196         dentry->d_mount_point = FALSE;
197         dentry->d_mounted_fs = 0;
198         dentry->d_parent = 0;
199         dentry->d_flags = 0; // related to its dcache state
200         dentry->d_fs_info = 0;
201         SLIST_INIT(&dentry->d_bucket);
202         return dentry;
203 }
204
205 /* Adds a dentry to the dcache. */
206 void dcache_put(struct dentry *dentry)
207 {
208         // TODO: prob should do something with the dentry flags
209         spin_lock(&dcache_lock);
210         SLIST_INSERT_HEAD(&dcache, dentry, d_hash);
211         spin_unlock(&dcache_lock);
212 }