Whamcloud - gitweb
add mount cache in sm_read_super
[fs/lustre-release.git] / lustre / smfs / super.c
1 /*
2  *  snap_current
3  *
4  *  Copyright (C) 1998 Peter J. Braam
5  *  Copyright (C) 2000 Stelias Computing, Inc.
6  *  Copyright (C) 2000 Red Hat, Inc.
7  *  Copyright (C) 2000 Mountain View Data, Inc.
8  *
9  *  Author: Peter J. Braam <braam@mountainviewdata.com>
10  */
11 #define DEBUG_SUBSYSTEM S_SNAP
12
13 #include <linux/module.h>
14 #include <linux/kmod.h>
15 #include <linux/init.h>
16 #include <linux/fs.h>
17 #include <linux/slab.h>
18 #include <linux/string.h>
19 #include <linux/loop.h>
20 #include <linux/errno.h>
21 #include "smfs_internal.h" 
22
23 /* Find the options for the clone. These consist of a cache device
24    and an index in the snaptable associated with that device. 
25 */
26 static char *smfs_options(char *options, char **devstr, char **namestr)
27 {
28         struct option *opt_value = NULL;
29         char *pos;
30         
31         while (!(get_opt(&opt_value, &pos))) {                  
32                 if (!strcmp(opt_value->opt, "dev")) {
33                         if (devstr != NULL)
34                                 *devstr = opt_value->value;
35                 } else if (!strcmp(opt_value->opt, "type")) {
36                         if (namestr != NULL)
37                                 *namestr = opt_value->value;
38                 } else {
39                         break;
40                 }
41         }
42         return pos;
43 }
44 static int get_fd(struct file *filp)
45 {
46         struct files_struct *files = current->files;    
47         int fd = 0;
48         
49         write_lock(&files->file_lock);
50         for (fd = 0; fd < files->max_fds; fd++) {
51                 if(files->fd[fd] == filp) {
52                         write_unlock(&files->file_lock);
53                         return fd;      
54                 }       
55         }
56         write_unlock(&files->file_lock);
57         RETURN(-1);
58 }
59 #define MAX_LOOP_DEVICES        256
60 static char *parse_path2dev(struct super_block *sb, char *dev_path)
61 {
62         struct file   *filp;
63         int i = 0, fd = 0, error = 0;
64         char *name = NULL;
65                 
66         filp = filp_open(dev_path, 0, 0);
67         if (!filp) 
68                 RETURN(NULL);
69
70         if (S_ISREG(filp->f_dentry->d_inode->i_mode)) {
71                 /*here we must walk through all the snap cache to 
72                  *find the loop device */
73                 for (i = 0; i < MAX_LOOP_DEVICES; i++) {
74                         fd = get_fd(filp);
75                         error = sb->s_bdev->bd_op->ioctl(filp->f_dentry->d_inode, 
76                                                  filp, LOOP_SET_FD,
77                                                  (unsigned long)&fd);
78                         if (!error) {
79                                 filp_close(filp, current->files); 
80                                 /*FIXME later, the loop file should 
81                                  *be different for different system*/
82                                 SM_ALLOC(name, strlen("/dev/loop/") + 2);
83                                 sprintf(name, "dev/loop/%d", i);
84                                 RETURN(name);                                   
85                         }
86                 }
87         }
88         SM_ALLOC(name, strlen(dev_path) + 1);
89         memcpy(name, dev_path, strlen(dev_path) + 1);
90         filp_close(filp, current->files); 
91         RETURN(name);
92 }
93 extern struct super_operations smfs_super_ops;
94
95 static int sm_mount_cache(struct super_block *sb, 
96                           char *devstr,
97                           char *typestr)
98 {
99         struct vfsmount *mnt;   
100         struct smfs_super_info *smb;
101         char *dev_name = NULL;
102         unsigned long page;
103         int     err = 0;
104         
105         dev_name = parse_path2dev(sb, devstr);
106         if (!dev_name) {
107                 GOTO(err_out, err = -ENOMEM);
108         }
109         if (!(page = __get_free_page(GFP_KERNEL))) {
110                 GOTO(err_out, err = -ENOMEM);
111         }                                                                                                                                                   
112         memset((void *)page, 0, PAGE_SIZE);
113         sprintf((char *)page, "iopen_nopriv");
114                                                                                                                                                                                                      
115         mnt = do_kern_mount(typestr, 0, dev_name, (void *)page);
116         free_page(page);
117         
118         if (IS_ERR(mnt)) {
119                 CERROR("do_kern_mount failed: rc = %d\n", err);
120                 GOTO(err_out, 0);
121         }
122         smb = S2SMI(sb); 
123         smb->smsi_sb = mnt->mnt_sb;
124         smb->smsi_mnt = mnt;
125 err_out:
126         if (dev_name) 
127                 SM_FREE(dev_name, strlen(dev_name) + 2);
128                 
129         return err;     
130 }
131
132 struct super_block *
133 smfs_read_super(
134         struct super_block *sb,
135         void *data,
136         int silent)
137 {
138         struct smfs_inode_info *smi;
139         struct dentry *bottom_root;
140         struct inode *root_inode = NULL;
141         char *devstr = NULL, *typestr = NULL;
142         char *cache_data;
143         ino_t root_ino;
144         int err = 0;
145
146         ENTRY;
147
148         CDEBUG(D_SUPER, "mount opts: %s\n", data ? (char *)data : "(none)");
149         
150         init_option(data);
151         /* read and validate options */
152         cache_data = smfs_options(data, &devstr, &typestr);
153         if (*cache_data) {
154                 CERROR("invalid mount option %s\n", (char*)data);
155                 GOTO(out_err, err=-EINVAL);
156         }
157         if (!typestr || !devstr) {
158                 CERROR("mount options name and dev mandatory\n");
159                 GOTO(out_err, err=-EINVAL);
160         }
161         
162         err = sm_mount_cache(sb, devstr, typestr);
163         if (err) {
164                 CERROR("Can not mount %s as %s\n", devstr, typestr);
165                 GOTO(out_err, 0);
166         }
167         /* set up the super block */
168         sb->s_op = &smfs_super_ops;
169
170         bottom_root = dget(S2SMI(sb)->smsi_sb->s_root);
171         if (!bottom_root) {
172                 CERROR("bottom not mounted\n");
173                 GOTO(out_err, err=-ENOENT);
174         }
175
176         root_ino = bottom_root->d_inode->i_ino;
177         smi = I2SMI(root_inode);
178         /*FIXME Intialize smi here*/
179         
180         CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
181                sb->s_op->read_inode, root_ino, root_inode);
182         
183         sb->s_root = d_alloc_root(bottom_root->d_inode);
184         
185         if (!sb->s_root) {
186                 GOTO(out_err, err=-EINVAL);
187         }
188
189         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
190                 (ulong) sb, (ulong) &sb->u.generic_sbp);
191         
192  out_err:
193         cleanup_option();
194         if (err)
195                 return NULL;
196         return sb;
197 }
198
199 static DECLARE_FSTYPE(smfs_type, "smfs", smfs_read_super, 0);
200
201 int init_smfs(void)
202 {
203         int err;
204
205         err = register_filesystem(&smfs_type);
206         if (err) {
207                 CERROR("smfs: failed in register Storage Management filesystem!\n");
208         }
209         return err;
210 }
211
212 int cleanup_smfs(void)
213 {
214         int err;
215
216         ENTRY;
217         err = unregister_filesystem(&smfs_type);
218         if (err) {
219                 CERROR("smfs: failed to unregister Storage Management filesystem!\n");
220         }
221         return 0;
222 }