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