Whamcloud - gitweb
update smfs
[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_SM
12
13 #include <linux/config.h>
14 #include <linux/module.h>
15 #include <linux/kmod.h>
16 #include <linux/init.h>
17 #include <linux/fs.h>
18 #include <linux/string.h>
19 #include <linux/mm.h>
20 #include <linux/utime.h>
21 #include <linux/file.h>
22 #include <linux/slab.h>
23 #include <linux/loop.h>
24 #include <linux/errno.h>
25 #include "smfs_internal.h" 
26
27 /* Find the options for the clone. These consist of a cache device
28    and an index in the snaptable associated with that device. 
29 */
30 static char *smfs_options(char *options, char **devstr, char **namestr)
31 {
32         struct option *opt_value = NULL;
33         char *pos;
34         
35         while (!(get_opt(&opt_value, &pos))) {                  
36                 if (!strcmp(opt_value->opt, "dev")) {
37                         if (devstr != NULL)
38                                 *devstr = opt_value->value;
39                 } else if (!strcmp(opt_value->opt, "type")) {
40                         if (namestr != NULL)
41                                 *namestr = opt_value->value;
42                 } else {
43                         break;
44                 }
45         }
46         return pos;
47 }
48 static int get_fd(struct file *filp)
49 {
50         struct files_struct *files = current->files;    
51         int fd = 0;
52         
53         write_lock(&files->file_lock);
54         for (fd = 0; fd < files->max_fds; fd++) {
55                 if(files->fd[fd] == filp) {
56                         write_unlock(&files->file_lock);
57                         return fd;      
58                 }       
59         }
60         write_unlock(&files->file_lock);
61         RETURN(-1);
62 }
63 static int close_fd(int fd)
64 {
65         struct files_struct *files = current->files;    
66         
67         write_lock(&files->file_lock);
68        
69         files->fd[fd] = NULL;
70         __put_unused_fd(files, fd); 
71         
72         write_unlock(&files->file_lock);
73         return 0;
74 }
75
76 #define MAX_LOOP_DEVICES        256
77 static char *parse_path2dev(struct super_block *sb, char *dev_path)
78 {
79         struct file   *filp;
80         int i = 0, fd = 0, error = 0;
81         char *name = NULL;
82                 
83         filp = filp_open(dev_path, 0, 0);
84         if (!filp) 
85                 RETURN(NULL);
86         if (S_ISREG(filp->f_dentry->d_inode->i_mode)) {
87                 /*here we must walk through all the snap cache to 
88                  *find the loop device */
89                 
90                 fd = get_unused_fd();
91                 if (!fd) RETURN(NULL);
92
93                 fd_install(fd, filp);           
94                 SM_ALLOC(name, strlen("/dev/loop/") + 2);
95         
96                 for (i = 0; i < MAX_LOOP_DEVICES; i++) {
97                         fd = get_fd(filp);
98                         if (fd > 0) {
99                                 struct block_device_operations *bd_ops;
100                                 struct dentry *dentry;
101                                 struct nameidata nd;
102                                 /*FIXME later, the loop file should 
103                                  *be different for different system*/
104                                                                                                                                                              
105                                 sprintf(name, "/dev/loop/%d", i);
106                         
107                                 if (path_init(name, LOOKUP_FOLLOW, &nd)) {
108                                         error = path_walk(name, &nd);
109                                         if (error) {
110                                                 path_release(&nd);
111                                                 SM_FREE(name, sizeof(name) + 1); 
112                                                 RETURN(NULL);
113                                         }
114                                 } else {
115                                         SM_FREE(name, sizeof(name) + 1); 
116                                         RETURN(NULL);
117                                 }                                                                                                                                                                    
118                                 dentry = nd.dentry;
119                                 bd_ops = get_blkfops(LOOP_MAJOR); 
120                                 error = bd_ops->ioctl(dentry->d_inode, 
121                                                       filp, LOOP_SET_FD,
122                                                       (unsigned long)fd);
123                                 path_release(&nd);
124                                 if (!error) {
125                                         filp_close(filp, current->files); 
126                                         RETURN(name);                                   
127                                 }
128                         }
129                 }
130         }
131         SM_ALLOC(name, strlen(dev_path) + 1);
132         memcpy(name, dev_path, strlen(dev_path) + 1);
133         filp_close(filp, current->files); 
134         RETURN(name);
135 }
136 extern struct super_operations smfs_super_ops;
137
138 static int sm_mount_cache(struct super_block *sb, 
139                           char *devstr,
140                           char *typestr)
141 {
142         struct vfsmount *mnt;   
143         struct smfs_super_info *smb;
144         char *dev_name = NULL;
145         unsigned long page;
146         int     err = 0;
147         
148         dev_name = parse_path2dev(sb, devstr);
149         if (!dev_name) {
150                 GOTO(err_out, err = -ENOMEM);
151         }
152         if (!(page = __get_free_page(GFP_KERNEL))) {
153                 GOTO(err_out, err = -ENOMEM);
154         }                                                                                                                                                   
155         memset((void *)page, 0, PAGE_SIZE);
156         sprintf((char *)page, "iopen_nopriv");
157                                                                                                                                                                                                      
158         mnt = do_kern_mount(typestr, 0, dev_name, (void *)page);
159         free_page(page);
160         
161         if (IS_ERR(mnt)) {
162                 CERROR("do_kern_mount failed: rc = %d\n", err);
163                 GOTO(err_out, 0);
164         }
165         smb = S2SMI(sb); 
166         smb->smsi_sb = mnt->mnt_sb;
167         smb->smsi_mnt = mnt;
168         sm_set_sb_ops(mnt->mnt_sb, sb); 
169 err_out:
170         if (dev_name) 
171                 SM_FREE(dev_name, strlen(dev_name) + 2);
172                 
173         return err;     
174 }
175 static int sm_umount_cache(struct super_block *sb)
176 {
177         struct smfs_super_info *smb = S2SMI(sb);
178         
179         mntput(smb->smsi_mnt);
180         return 0;
181 }
182 void smfs_put_super(struct super_block *sb)
183 {
184         if (sb)
185                 sm_umount_cache(sb);
186         return; 
187 }
188
189 struct super_block *
190 smfs_read_super(
191         struct super_block *sb,
192         void *data,
193         int silent)
194 {
195         struct smfs_inode_info *smi;
196         struct dentry *bottom_root;
197         struct inode *root_inode = NULL;
198         char *devstr = NULL, *typestr = NULL;
199         char *cache_data;
200         ino_t root_ino;
201         int err = 0;
202
203         ENTRY;
204
205         CDEBUG(D_SUPER, "mount opts: %s\n", data ? (char *)data : "(none)");
206         
207         init_option(data);
208         /* read and validate options */
209         cache_data = smfs_options(data, &devstr, &typestr);
210         if (*cache_data) {
211                 CERROR("invalid mount option %s\n", (char*)data);
212                 GOTO(out_err, err=-EINVAL);
213         }
214         if (!typestr || !devstr) {
215                 CERROR("mount options name and dev mandatory\n");
216                 GOTO(out_err, err=-EINVAL);
217         }
218         
219         err = sm_mount_cache(sb, devstr, typestr);
220         if (err) {
221                 CERROR("Can not mount %s as %s\n", devstr, typestr);
222                 GOTO(out_err, 0);
223         }
224         /* set up the super block */
225
226         bottom_root = dget(S2SMI(sb)->smsi_sb->s_root);
227         if (!bottom_root) {
228                 CERROR("bottom not mounted\n");
229                 GOTO(out_err, err=-ENOENT);
230         }
231
232         root_ino = bottom_root->d_inode->i_ino;
233         smi = I2SMI(root_inode);
234         /*FIXME Intialize smi here*/
235         
236         CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
237                sb->s_op->read_inode, root_ino, root_inode);
238         
239         sb->s_root = d_alloc_root(bottom_root->d_inode);
240         
241         if (!sb->s_root) {
242                 GOTO(out_err, err=-EINVAL);
243         }
244
245         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
246                 (ulong) sb, (ulong) &sb->u.generic_sbp);
247         
248  out_err:
249         cleanup_option();
250         if (err)
251                 return NULL;
252         return sb;
253 }
254
255 static DECLARE_FSTYPE(smfs_type, "smfs", smfs_read_super, 0);
256
257 int init_smfs(void)
258 {
259         int err = 0;
260
261         err = register_filesystem(&smfs_type);
262         if (err) {
263                 CERROR("smfs: failed in register Storage Management filesystem!\n");
264         }
265         init_smfs_cache();              
266         return err;
267 }
268
269 int cleanup_smfs(void)
270 {
271         int err = 0;
272
273         ENTRY;
274         err = unregister_filesystem(&smfs_type);
275         if (err) {
276                 CERROR("smfs: failed to unregister Storage Management filesystem!\n");
277         }
278         cleanup_smfs_cache();           
279         return 0;
280 }