Whamcloud - gitweb
This adds most of the metadata infrastructure: I think that all commands
[fs/lustre-release.git] / lustre / mds / mds_reint.c
1 /*
2  *  linux/mds/mds_reint.c
3  *  
4  *  Lustre Metadata Server (mds) reintegration routines
5  * 
6  *  Copyright (C) 2002  Cluster File Systems, Inc.
7  *  author: Peter Braam <braam@clusterfs.com>
8  *
9  *  This code is issued under the GNU General Public License.
10  *  See the file COPYING in this distribution
11  *
12  */
13
14 // XXX - add transaction sequence numbers
15
16 #define EXPORT_SYMTAB
17
18 #include <linux/version.h>
19 #include <linux/module.h>
20 #include <linux/fs.h>
21 #include <linux/stat.h>
22 #include <linux/locks.h>
23 #include <linux/ext2_fs.h>
24 #include <linux/quotaops.h>
25 #include <asm/unistd.h>
26 #include <asm/uaccess.h>
27 #include <linux/obd_support.h>
28 #include <linux/obd.h>
29 #include <linux/lustre_lib.h>
30 #include <linux/lustre_idl.h>
31 #include <linux/lustre_mds.h>
32 #include <linux/obd_class.h>
33
34 extern struct ptlrpc_request *mds_prep_req(int size, int opcode, int namelen, char *name, int tgtlen, char *tgt);
35
36 static int mds_reint_setattr(struct mds_update_record *rec, struct ptlrpc_request *req)
37 {
38         struct vfsmount *mnt;
39         struct dentry *de;
40
41         de = mds_fid2dentry(req->rq_obd, rec->ur_fid1, &mnt);
42         if (IS_ERR(de)) { 
43                 req->rq_rephdr->status = -ESTALE;
44                 return 0;
45         }
46
47         printk("mds_setattr: ino %ld\n", de->d_inode->i_ino);
48         if ( de->d_inode->i_op->setattr ) {
49                 req->rq_rephdr->status =
50                         de->d_inode->i_op->setattr(de, &rec->ur_iattr);
51         } else { 
52                 req->rq_rephdr->status =
53                         inode_setattr(de->d_inode, &rec->ur_iattr);
54         }
55
56         l_dput(de);
57         EXIT;
58         return 0;
59 }
60
61 /* 
62    XXX nasty hack: store the object id in the first two
63    direct block spots 
64 */
65 static inline void mds_store_objid(struct inode *inode, __u64 *id)
66 {
67         memcpy(&inode->u.ext2_i.i_data, id, sizeof(*id));
68 }
69
70
71 static int mds_reint_create(struct mds_update_record *rec, 
72                             struct ptlrpc_request *req)
73 {
74         struct vfsmount *mnt;
75         int type = rec->ur_mode & S_IFMT;
76         struct dentry *de;
77         struct mds_rep *rep = req->rq_rep.mds;
78         struct dentry *dchild; 
79         int rc;
80         ENTRY;
81
82         de = mds_fid2dentry(req->rq_obd, rec->ur_fid1, &mnt);
83         if (IS_ERR(de)) { 
84                 req->rq_rephdr->status = -ESTALE;
85                 EXIT;
86                 return 0;
87         }
88         printk("mds_reint_create: ino %ld\n", de->d_inode->i_ino);
89
90         dchild = lookup_one_len(rec->ur_name, de, rec->ur_namelen - 1);
91         rc = PTR_ERR(dchild);
92         if (IS_ERR(dchild)) { 
93                 printk(__FUNCTION__ "child lookup error %d\n", rc);
94                 dput(de); 
95                 req->rq_rephdr->status = -ESTALE;
96                 EXIT;
97                 return 0;
98         }
99
100         if (dchild->d_inode) {
101                 printk(__FUNCTION__ "child exists (dir %ld, name %s\n", 
102                        de->d_inode->i_ino, rec->ur_name);
103                 dput(de); 
104                 req->rq_rephdr->status = -ESTALE;
105                 EXIT;
106                 return 0;
107         }
108
109         switch (type) {
110         case S_IFREG: { 
111                 rc = vfs_create(de->d_inode, dchild, rec->ur_mode);
112                 
113                 EXIT;
114                 break;
115         }
116         case S_IFDIR: { 
117                 rc = vfs_mkdir(de->d_inode, dchild, rec->ur_mode);
118                 EXIT;
119                 break;
120         } 
121         case S_IFLNK: { 
122                 rc = vfs_symlink(de->d_inode, dchild, rec->ur_tgt);
123                 EXIT;
124                 break;
125         } 
126         case S_IFCHR:
127         case S_IFBLK:
128         case S_IFIFO:
129         case S_IFSOCK: { 
130                 int rdev = rec->ur_id;
131                 rc = vfs_mknod(de->d_inode, dchild, rec->ur_mode, rdev); 
132                 EXIT;
133                 break;
134         }
135         }
136
137         req->rq_rephdr->status = rc;
138         if (!rc) { 
139                 if (type == S_IFREG)
140                         mds_store_objid(dchild->d_inode, &rec->ur_id); 
141                 dchild->d_inode->i_atime = rec->ur_time;
142                 dchild->d_inode->i_ctime = rec->ur_time;
143                 dchild->d_inode->i_mtime = rec->ur_time;
144                 dchild->d_inode->i_uid = rec->ur_uid;
145                 dchild->d_inode->i_gid = rec->ur_gid;
146                 rep->ino = dchild->d_inode->i_ino;
147         }
148
149         dput(de);
150         dput(dchild); 
151         EXIT;
152         return 0;
153 }
154
155 static int mds_reint_unlink(struct mds_update_record *rec, 
156                             struct ptlrpc_request *req)
157 {
158         struct vfsmount *mnt;
159         struct dentry *de;
160         struct dentry *dchild; 
161         int rc;
162         ENTRY;
163
164         de = mds_fid2dentry(req->rq_obd, rec->ur_fid1, &mnt);
165         if (IS_ERR(de)) { 
166                 req->rq_rephdr->status = -ESTALE;
167                 EXIT;
168                 return 0;
169         }
170         printk("mds_reint_create: ino %ld\n", de->d_inode->i_ino);
171
172         dchild = lookup_one_len(rec->ur_name, de, rec->ur_namelen - 1);
173         rc = PTR_ERR(dchild);
174         if (IS_ERR(dchild)) { 
175                 printk(__FUNCTION__ ": child lookup error %d\n", rc);
176                 dput(de); 
177                 req->rq_rephdr->status = -ESTALE;
178                 EXIT;
179                 return 0;
180         }
181
182         if (!dchild->d_inode) {
183                 printk(__FUNCTION__ ": child doesn't exist (dir %ld, name %s\n", 
184                        de->d_inode->i_ino, rec->ur_name);
185                 dput(de); 
186                 req->rq_rephdr->status = -ESTALE;
187                 EXIT;
188                 return 0;
189         }
190
191         switch (de->d_inode->i_mode & S_IFMT) {
192         case S_IFDIR:
193                 rc = vfs_rmdir(de->d_inode, dchild);
194                 EXIT;
195                 break;
196         default:
197                 rc = vfs_unlink(de->d_inode, dchild);
198                 
199                 EXIT;
200                 break;
201         }
202
203         req->rq_rephdr->status = rc;
204         dput(de);
205         dput(dchild); 
206         EXIT;
207         return 0;
208 }
209
210 static int mds_reint_link(struct mds_update_record *rec, 
211                             struct ptlrpc_request *req)
212 {
213         struct vfsmount *mnt;
214         struct dentry *de_src = NULL;
215         struct dentry *de_tgt_dir = NULL;
216         struct dentry *dchild = NULL; 
217         int rc;
218         ENTRY;
219
220         rc = -ESTALE;
221         de_src = mds_fid2dentry(req->rq_obd, rec->ur_fid1, &mnt);
222         if (IS_ERR(de_src)) { 
223                 EXIT;
224                 goto out_link;
225         }
226
227         de_tgt_dir = mds_fid2dentry(req->rq_obd, rec->ur_fid2, &mnt);
228         if (IS_ERR(de_tgt_dir)) { 
229                 rc = -ESTALE;
230                 EXIT;
231                 goto out_link;
232         }
233
234         dchild = lookup_one_len(rec->ur_name, de_tgt_dir, rec->ur_namelen - 1);
235         if (IS_ERR(dchild)) { 
236                 printk(__FUNCTION__ ": child lookup error %d\n", rc);
237                 req->rq_rephdr->status = -ESTALE;
238                 goto out_link;
239         }
240
241         if (dchild->d_inode) {
242                 printk(__FUNCTION__ ": child exists (dir %ld, name %s\n", 
243                        de_tgt_dir->d_inode->i_ino, rec->ur_name);
244                 EXIT;
245                 goto out_link;
246         }
247
248         rc = vfs_link(de_src, de_tgt_dir->d_inode, dchild); 
249
250  out_link:
251         req->rq_rephdr->status = rc;
252         l_dput(de_src);
253         l_dput(de_tgt_dir); 
254         l_dput(dchild); 
255         EXIT;
256         return 0;
257 }
258
259
260 static int mds_reint_rename(struct mds_update_record *rec, 
261                             struct ptlrpc_request *req)
262 {
263         struct vfsmount *mnt;
264         struct dentry *de_srcdir = NULL;
265         struct dentry *de_tgtdir = NULL;
266         struct dentry *de_old = NULL; 
267         struct dentry *de_new = NULL; 
268         int rc;
269         ENTRY;
270
271         rc = -ESTALE;
272         de_srcdir = mds_fid2dentry(req->rq_obd, rec->ur_fid1, &mnt);
273         if (IS_ERR(de_srcdir)) { 
274                 EXIT;
275                 goto out_rename;
276         }
277
278         de_tgtdir = mds_fid2dentry(req->rq_obd, rec->ur_fid2, &mnt);
279         if (IS_ERR(de_tgtdir)) { 
280                 rc = -ESTALE;
281                 EXIT;
282                 goto out_rename;
283         }
284
285         de_old = lookup_one_len(rec->ur_name, de_srcdir, rec->ur_namelen - 1);
286         if (IS_ERR(de_old)) { 
287                 printk(__FUNCTION__ "child lookup error %d\n", rc);
288                 goto out_rename;
289         }
290
291         de_new = lookup_one_len(rec->ur_tgt, de_tgtdir, rec->ur_tgtlen - 1);
292         if (IS_ERR(de_new)) { 
293                 printk(__FUNCTION__ "child lookup error %d\n", rc);
294                 goto out_rename;
295         }
296
297         rc = vfs_rename(de_srcdir->d_inode, de_old, de_tgtdir->d_inode, de_new);
298
299  out_rename:
300         req->rq_rephdr->status = rc;
301         l_dput(de_new);
302         l_dput(de_old); 
303         l_dput(de_tgtdir); 
304         l_dput(de_srcdir); 
305         EXIT;
306         return 0;
307 }
308
309 typedef int (*mds_reinter)(struct mds_update_record *, struct ptlrpc_request*); 
310
311 static mds_reinter  reinters[REINT_MAX+1] = { 
312         [REINT_SETATTR]   mds_reint_setattr, 
313         [REINT_CREATE]    mds_reint_create,
314         [REINT_UNLINK]    mds_reint_unlink, 
315         [REINT_LINK]      mds_reint_link,
316         [REINT_RENAME]    mds_reint_rename
317 };
318
319 int mds_reint_rec(struct mds_update_record *rec, struct ptlrpc_request *req)
320 {
321         int rc; 
322
323         if (rec->ur_opcode < 0 || rec->ur_opcode > REINT_MAX) { 
324                 printk(__FUNCTION__ "opcode %d not valid\n", 
325                        rec->ur_opcode); 
326                 rc = req->rq_status = -EINVAL;
327                 return rc;
328         }
329
330         rc = mds_pack_rep(NULL, 0, NULL, 0, &req->rq_rephdr, &req->rq_rep.mds, 
331                           &req->rq_replen, &req->rq_repbuf);
332         if (rc) { 
333                 EXIT;
334                 printk("mds: out of memory\n");
335                 rc = req->rq_status = -ENOMEM;
336                 return rc;
337         }
338         req->rq_rephdr->seqno = req->rq_reqhdr->seqno;
339
340         rc = reinters[rec->ur_opcode](rec, req); 
341         req->rq_status = rc;
342
343         return rc;
344
345