Whamcloud - gitweb
Ignore all .mergeinfo files.
[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, FMODE_WRITE, 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 && error != -ENOENT) {
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(dev_path, LOOKUP_FOLLOW, &nd)) {
167                 error = path_walk(dev_path, &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 static void duplicate_sb(struct super_block *csb, 
194                          struct super_block *sb)
195 {
196         sb->s_blocksize = csb->s_blocksize;
197         sb->s_magic = csb->s_magic;
198         sb->s_blocksize_bits = csb->s_blocksize_bits;
199         sb->s_maxbytes = csb->s_maxbytes;
200 }
201 extern struct super_operations smfs_super_ops;
202
203 static int sm_mount_cache(struct super_block *sb, 
204                           char *devstr,
205                           char *typestr)
206 {
207         struct vfsmount *mnt;   
208         struct smfs_super_info *smb;
209         char *dev_name = NULL;
210         unsigned long page;
211         int     err = 0;
212         
213         dev_name = parse_path2dev(sb, devstr);
214         if (!dev_name) {
215                 GOTO(err_out, err = -ENOMEM);
216         }
217         if (!(page = __get_free_page(GFP_KERNEL))) {
218                 GOTO(err_out, err = -ENOMEM);
219         }                                                                                                                                                   
220         memset((void *)page, 0, PAGE_SIZE);
221         sprintf((char *)page, "iopen_nopriv");
222                                                                                                                                                                                                      
223         mnt = do_kern_mount(typestr, 0, dev_name, (void *)page);
224         free_page(page);
225         
226         if (IS_ERR(mnt)) {
227                 CERROR("do_kern_mount failed: rc = %d\n", PTR_ERR(mnt));
228                 GOTO(err_out, err = PTR_ERR(mnt));
229         }
230         smb = S2SMI(sb); 
231         smb->smsi_sb = mnt->mnt_sb;
232         smb->smsi_mnt = mnt;
233         
234         duplicate_sb(mnt->mnt_sb, sb);
235         sm_set_sb_ops(mnt->mnt_sb, sb); 
236 err_out:
237         if (dev_name) 
238                 SM_FREE(dev_name, strlen(dev_name) + 2);
239                 
240         return err;     
241 }
242 static int sm_umount_cache(struct super_block *sb)
243 {
244         struct smfs_super_info *smb = S2SMI(sb);
245         
246         mntput(smb->smsi_mnt);
247         
248         return 0;
249 }
250 void smfs_put_super(struct super_block *sb)
251 {
252         if (sb)
253                 sm_umount_cache(sb);
254         return; 
255 }
256
257 struct super_block *
258 smfs_read_super(
259         struct super_block *sb,
260         void *data,
261         int silent)
262 {
263         struct inode *root_inode = NULL;
264         char *devstr = NULL, *typestr = NULL;
265         char *cache_data;
266         ino_t root_ino;
267         int err = 0;
268
269         ENTRY;
270
271         CDEBUG(D_SUPER, "mount opts: %s\n", data ? (char *)data : "(none)");
272         
273         init_option(data);
274         /* read and validate options */
275         cache_data = smfs_options(data, &devstr, &typestr);
276         if (*cache_data) {
277                 CERROR("invalid mount option %s\n", (char*)data);
278                 GOTO(out_err, err=-EINVAL);
279         }
280         if (!typestr || !devstr) {
281                 CERROR("mount options name and dev mandatory\n");
282                 GOTO(out_err, err=-EINVAL);
283         }
284         
285         err = sm_mount_cache(sb, devstr, typestr);
286         if (err) {
287                 CERROR("Can not mount %s as %s\n", devstr, typestr);
288                 GOTO(out_err, 0);
289         }
290         dget(S2CSB(sb)->s_root);
291         root_ino = S2CSB(sb)->s_root->d_inode->i_ino;
292         root_inode = iget(sb, root_ino);
293                 
294         CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
295                sb->s_op->read_inode, root_ino, root_inode);
296         
297         sb->s_root = d_alloc_root(root_inode);
298         
299         if (!sb->s_root) {
300                 GOTO(out_err, err=-EINVAL);
301         }
302         
303         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
304                 (ulong) sb, (ulong) &sb->u.generic_sbp);
305         
306 out_err:
307         cleanup_option();
308         if (err)
309                 return NULL;
310         return sb;
311 }
312
313 static DECLARE_FSTYPE(smfs_type, "smfs", smfs_read_super, 0);
314
315 int init_smfs(void)
316 {
317         int err = 0;
318
319         err = register_filesystem(&smfs_type);
320         if (err) {
321                 CERROR("smfs: failed in register Storage Management filesystem!\n");
322         }
323         init_smfs_cache();              
324         return err;
325 }
326
327 int cleanup_smfs(void)
328 {
329         int err = 0;
330
331         ENTRY;
332         err = unregister_filesystem(&smfs_type);
333         if (err) {
334                 CERROR("smfs: failed to unregister Storage Management filesystem!\n");
335         }
336         cleanup_smfs_cache();           
337         return 0;
338 }