Whamcloud - gitweb
update smfs. 1)fix bugs in sm_read_super 2) add some methods in symlink ops
[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 close_fd(int fd)
49 {
50         struct files_struct *files = current->files;    
51         
52         write_lock(&files->file_lock);
53        
54         files->fd[fd] = NULL;
55         __put_unused_fd(files, fd); 
56         
57         write_unlock(&files->file_lock);
58         return 0;
59 }
60 static int set_loop_fd(char *dev_path, char *loop_dev)
61 {
62         struct loop_info loopinfo;
63         struct nameidata nd;
64         struct dentry *dentry;
65         struct block_device_operations *bd_ops;
66         struct file   *filp;
67         int    fd = 0, error = 0;
68         
69         fd = get_unused_fd();
70
71         if (!fd) RETURN(-EINVAL);
72         
73         filp = filp_open(dev_path, 0, 0);
74         if (!filp || !S_ISREG(filp->f_dentry->d_inode->i_mode)) 
75                 RETURN(-EINVAL);
76         
77         fd_install(fd, filp);           
78
79         if (path_init(loop_dev, LOOKUP_FOLLOW, &nd)) {
80                 error = path_walk(loop_dev, &nd);
81                 if (error) {
82                         path_release(&nd);
83                         filp_close(filp, current->files); 
84                         RETURN(-EINVAL);
85                 }
86         } else {
87                 path_release(&nd);
88                 filp_close(filp, current->files); 
89                 RETURN(-EINVAL);
90         }                                                                                                                                                                    
91         dentry = nd.dentry;
92         bd_ops = get_blkfops(LOOP_MAJOR); 
93         
94         error = bd_ops->ioctl(dentry->d_inode, filp, LOOP_SET_FD,
95                               (unsigned long)fd);
96         if (error) {
97                 path_release(&nd);
98                 filp_close(filp, current->files); 
99                 RETURN(-EINVAL);
100         }
101         memset(&loopinfo, 0, sizeof(struct loop_info));
102
103         error = bd_ops->ioctl(dentry->d_inode, filp, LOOP_SET_STATUS,
104                               (unsigned long)(&loopinfo));
105         path_release(&nd);
106         RETURN(error);  
107 }
108
109 #define SIZE(a) (sizeof(a)/sizeof(a[0]))
110 static char *find_unused_and_set_loop_device(char *dev_path)
111 {
112         char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
113         struct loop_info loopinfo;
114         struct nameidata nd;
115         struct dentry *dentry;
116         char *dev = NULL;
117         int i, j, error;
118                                                                                                                                                                                              
119         for (j = 0; j < SIZE(loop_formats); j++) {
120                 SM_ALLOC(dev, strlen(loop_formats[i]) + 1);
121                 for(i = 0; i < 256; i++) {
122                         struct block_device_operations *bd_ops;
123
124                         sprintf(dev, loop_formats[j], i);
125                         
126                         if (path_init(dev, LOOKUP_FOLLOW, &nd)) {
127                                 error = path_walk(dev, &nd);
128                                 if (error) {
129                                         path_release(&nd);
130                                         SM_FREE(dev, strlen(loop_formats[i]) + 1); 
131                                         RETURN(NULL);
132                                 }
133                         } else {
134                                 SM_FREE(dev, strlen(loop_formats[i]) + 1); 
135                                 RETURN(NULL);
136                         }      
137                         dentry = nd.dentry;
138                         bd_ops = get_blkfops(LOOP_MAJOR); 
139                         error = bd_ops->ioctl(dentry->d_inode, NULL, LOOP_GET_STATUS, 
140                                               (unsigned long)&loopinfo);
141                         path_release(&nd);
142                         
143                         if (error == ENXIO) {
144                                 /*find unused loop and set dev_path to loopdev*/
145                                 error = set_loop_fd(dev_path, dev);
146                                 if (error) {
147                                         SM_FREE(dev, strlen(loop_formats[i]) + 1);
148                                         dev = NULL;             
149                                 }
150                                 return dev;/* probably free */
151                         }
152                 }
153                 SM_FREE(dev, strlen(loop_formats[i]) + 1);
154         }
155         RETURN(NULL);
156 }
157
158 #define MAX_LOOP_DEVICES        256
159 static char *parse_path2dev(struct super_block *sb, char *dev_path)
160 {
161         struct dentry *dentry;
162         struct nameidata nd;
163         char *name = NULL;
164         int  error = 0;
165
166         if (path_init(name, LOOKUP_FOLLOW, &nd)) {
167                 error = path_walk(name, &nd);
168                 if (error) {
169                         path_release(&nd);
170                         RETURN(NULL);
171                 }
172         } else {
173                 RETURN(NULL);
174         }      
175         dentry = nd.dentry;
176
177         if (!dentry->d_inode || is_bad_inode(dentry->d_inode) || 
178             (!S_ISBLK(dentry->d_inode->i_mode) && 
179              !S_ISREG(dentry->d_inode->i_mode))){
180                 path_release(&nd);
181                 RETURN(NULL);
182         }
183                 
184         if (S_ISREG(dentry->d_inode->i_mode)) {
185                 name = find_unused_and_set_loop_device(dev_path);
186                 path_release(&nd);
187                 RETURN(name);                   
188         }
189         SM_ALLOC(name, strlen(dev_path) + 1);
190         memcpy(name, dev_path, strlen(dev_path) + 1);
191         RETURN(name);
192 }
193 extern struct super_operations smfs_super_ops;
194
195 static int sm_mount_cache(struct super_block *sb, 
196                           char *devstr,
197                           char *typestr)
198 {
199         struct vfsmount *mnt;   
200         struct smfs_super_info *smb;
201         char *dev_name = NULL;
202         unsigned long page;
203         int     err = 0;
204         
205         dev_name = parse_path2dev(sb, devstr);
206         if (!dev_name) {
207                 GOTO(err_out, err = -ENOMEM);
208         }
209         if (!(page = __get_free_page(GFP_KERNEL))) {
210                 GOTO(err_out, err = -ENOMEM);
211         }                                                                                                                                                   
212         memset((void *)page, 0, PAGE_SIZE);
213         sprintf((char *)page, "iopen_nopriv");
214                                                                                                                                                                                                      
215         mnt = do_kern_mount(typestr, 0, dev_name, (void *)page);
216         free_page(page);
217         
218         if (IS_ERR(mnt)) {
219                 CERROR("do_kern_mount failed: rc = %d\n", err);
220                 GOTO(err_out, 0);
221         }
222         smb = S2SMI(sb); 
223         smb->smsi_sb = mnt->mnt_sb;
224         smb->smsi_mnt = mnt;
225         sm_set_sb_ops(mnt->mnt_sb, sb); 
226 err_out:
227         if (dev_name) 
228                 SM_FREE(dev_name, strlen(dev_name) + 2);
229                 
230         return err;     
231 }
232 static int sm_umount_cache(struct super_block *sb)
233 {
234         struct smfs_super_info *smb = S2SMI(sb);
235         
236         mntput(smb->smsi_mnt);
237         return 0;
238 }
239 void smfs_put_super(struct super_block *sb)
240 {
241         if (sb)
242                 sm_umount_cache(sb);
243         return; 
244 }
245
246 struct super_block *
247 smfs_read_super(
248         struct super_block *sb,
249         void *data,
250         int silent)
251 {
252         struct smfs_inode_info *smi;
253         struct dentry *bottom_root;
254         struct inode *root_inode = NULL;
255         char *devstr = NULL, *typestr = NULL;
256         char *cache_data;
257         ino_t root_ino;
258         int err = 0;
259
260         ENTRY;
261
262         CDEBUG(D_SUPER, "mount opts: %s\n", data ? (char *)data : "(none)");
263         
264         init_option(data);
265         /* read and validate options */
266         cache_data = smfs_options(data, &devstr, &typestr);
267         if (*cache_data) {
268                 CERROR("invalid mount option %s\n", (char*)data);
269                 GOTO(out_err, err=-EINVAL);
270         }
271         if (!typestr || !devstr) {
272                 CERROR("mount options name and dev mandatory\n");
273                 GOTO(out_err, err=-EINVAL);
274         }
275         
276         err = sm_mount_cache(sb, devstr, typestr);
277         if (err) {
278                 CERROR("Can not mount %s as %s\n", devstr, typestr);
279                 GOTO(out_err, 0);
280         }
281         /* set up the super block */
282
283         bottom_root = dget(S2SMI(sb)->smsi_sb->s_root);
284         if (!bottom_root) {
285                 CERROR("bottom not mounted\n");
286                 GOTO(out_err, err=-ENOENT);
287         }
288
289         root_ino = bottom_root->d_inode->i_ino;
290         smi = I2SMI(root_inode);
291         /*FIXME Intialize smi here*/
292         
293         CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
294                sb->s_op->read_inode, root_ino, root_inode);
295         
296         sb->s_root = d_alloc_root(bottom_root->d_inode);
297         
298         if (!sb->s_root) {
299                 GOTO(out_err, err=-EINVAL);
300         }
301
302         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
303                 (ulong) sb, (ulong) &sb->u.generic_sbp);
304         
305  out_err:
306         cleanup_option();
307         if (err)
308                 return NULL;
309         return sb;
310 }
311
312 static DECLARE_FSTYPE(smfs_type, "smfs", smfs_read_super, 0);
313
314 int init_smfs(void)
315 {
316         int err = 0;
317
318         err = register_filesystem(&smfs_type);
319         if (err) {
320                 CERROR("smfs: failed in register Storage Management filesystem!\n");
321         }
322         init_smfs_cache();              
323         return err;
324 }
325
326 int cleanup_smfs(void)
327 {
328         int err = 0;
329
330         ENTRY;
331         err = unregister_filesystem(&smfs_type);
332         if (err) {
333                 CERROR("smfs: failed to unregister Storage Management filesystem!\n");
334         }
335         cleanup_smfs_cache();           
336         return 0;
337 }