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