Whamcloud - gitweb
add close_uuid
[fs/lustre-release.git] / lustre / obdecho / echo.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  linux/fs/obdecho/echo.c
5  *
6  * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
7  *
8  * This code is issued under the GNU General Public License.
9  * See the file COPYING in this distribution
10  *
11  * by Peter Braam <braam@clusterfs.com>
12  * and Andreas Dilger <adilger@clusterfs.com>
13  */
14
15 static char rcsid[] __attribute ((unused)) = "$Id: echo.c,v 1.32 2002/09/04 16:30:40 adilger Exp $";
16 #define OBDECHO_VERSION "$Revision: 1.32 $"
17
18 #define EXPORT_SYMTAB
19
20 #include <linux/version.h>
21 #include <linux/module.h>
22 #include <linux/fs.h>
23 #include <linux/stat.h>
24 #include <linux/locks.h>
25 #include <linux/ext2_fs.h>
26 #include <linux/quotaops.h>
27 #include <linux/proc_fs.h>
28 #include <linux/init.h>
29 #include <asm/unistd.h>
30
31 #define DEBUG_SUBSYSTEM S_ECHO
32
33 #include <linux/obd_support.h>
34 #include <linux/obd_class.h>
35 #include <linux/obd_echo.h>
36 #include <linux/lustre_debug.h>
37 #include <linux/lustre_dlm.h>
38
39 extern struct obd_device obd_dev[MAX_OBD_DEVICES];
40
41 static atomic_t echo_page_rws;
42 static atomic_t echo_getattrs;
43
44 #define ECHO_PROC_STAT "sys/obdecho"
45
46 int echo_proc_read(char *page, char **start, off_t off, int count, int *eof,
47                    void *data)
48 {
49         long long attrs = atomic_read(&echo_getattrs);
50         long long pages = atomic_read(&echo_page_rws);
51         int len;
52
53         *eof = 1;
54         if (off != 0)
55                 return (0);
56
57         len = sprintf(page, "%Ld %Ld\n", attrs, pages);
58
59         *start = page;
60         return (len);
61 }
62
63 int echo_proc_write(struct file *file, const char *ubuffer,
64                     unsigned long count, void *data)
65 {
66         /* Ignore what we've been asked to write, and just zero the counters */
67         atomic_set (&echo_page_rws, 0);
68         atomic_set (&echo_getattrs, 0);
69
70         return (count);
71 }
72
73 void echo_proc_init(void)
74 {
75         struct proc_dir_entry *entry;
76
77         entry = create_proc_entry(ECHO_PROC_STAT, S_IFREG|S_IRUGO|S_IWUSR,NULL);
78
79         if (entry == NULL) {
80                 CERROR("couldn't create proc entry %s\n", ECHO_PROC_STAT);
81                 return;
82         }
83
84         entry->data = NULL;
85         entry->read_proc = echo_proc_read;
86         entry->write_proc = echo_proc_write;
87 }
88
89 void echo_proc_fini(void)
90 {
91         remove_proc_entry(ECHO_PROC_STAT, 0);
92 }
93
94 static int echo_connect(struct lustre_handle *conn, struct obd_device *obd,
95                         char *cluuid)
96 {
97         int rc;
98
99         MOD_INC_USE_COUNT;
100         rc = class_connect(conn, obd, cluuid);
101
102         if (rc)
103                 MOD_DEC_USE_COUNT;
104
105         return rc;
106 }
107
108 static int echo_disconnect(struct lustre_handle *conn)
109 {
110         int rc;
111
112         rc = class_disconnect(conn);
113         if (!rc)
114                 MOD_DEC_USE_COUNT;
115
116         return rc;
117 }
118
119 static __u64 echo_next_id(struct obd_device *obddev)
120 {
121         obd_id id;
122
123         spin_lock(&obddev->u.echo.eo_lock);
124         id = ++obddev->u.echo.eo_lastino;
125         spin_unlock(&obddev->u.echo.eo_lock);
126
127         return id;
128 }
129
130 int echo_create(struct lustre_handle *conn, struct obdo *oa,
131                 struct lov_stripe_md **ea)
132 {
133         struct obd_device *obd = class_conn2obd(conn);
134
135         if (!obd) {
136                 CERROR("invalid client %Lx\n", conn->addr);
137                 return -EINVAL;
138         }
139
140         if (!(oa->o_mode && S_IFMT)) {
141                 CERROR("filter obd: no type!\n");
142                 return -ENOENT;
143         }
144
145         if (!(oa->o_valid & OBD_MD_FLMODE)) {
146                 CERROR("invalid o_valid %08x\n", oa->o_valid);
147                 return -EINVAL;
148         }
149
150         oa->o_id = echo_next_id(obd);
151         oa->o_valid = OBD_MD_FLID;
152         atomic_inc(&obd->u.echo.eo_create);
153
154         return 0;
155 }
156
157 int echo_destroy(struct lustre_handle *conn, struct obdo *oa,
158                  struct lov_stripe_md *ea)
159 {
160         struct obd_device *obd = class_conn2obd(conn);
161
162         if (!obd) {
163                 CERROR("invalid client "LPX64"\n", conn->addr);
164                 RETURN(-EINVAL);
165         }
166
167         if (!(oa->o_valid & OBD_MD_FLID)) {
168                 CERROR("obdo missing FLID valid flag: %08x\n", oa->o_valid);
169                 RETURN(-EINVAL);
170         }
171
172         if (oa->o_id > obd->u.echo.eo_lastino) {
173                 CERROR("bad destroy objid: %Ld\n", (long long)oa->o_id);
174                 RETURN(-EINVAL);
175         }
176
177         atomic_inc(&obd->u.echo.eo_destroy);
178
179         return 0;
180 }
181
182 static int echo_getattr(struct lustre_handle *conn, struct obdo *oa,
183                         struct lov_stripe_md *md)
184 {
185         struct obd_device *obd = class_conn2obd(conn);
186         obd_id id = oa->o_id;
187
188         if (!obd) {
189                 CERROR("invalid client "LPX64"\n", conn->addr);
190                 RETURN(-EINVAL);
191         }
192
193         if (!(oa->o_valid & OBD_MD_FLID)) {
194                 CERROR("obdo missing FLID valid flag: %08x\n", oa->o_valid);
195                 RETURN(-EINVAL);
196         }
197
198         memcpy(oa, &obd->u.echo.oa, sizeof(*oa));
199         oa->o_id = id;
200         oa->o_valid |= OBD_MD_FLID;
201
202         atomic_inc(&echo_getattrs);
203
204         return 0;
205 }
206
207 static int echo_setattr(struct lustre_handle *conn, struct obdo *oa,
208                         struct lov_stripe_md *md)
209 {
210         struct obd_device *obd = class_conn2obd(conn);
211
212         if (!obd) {
213                 CERROR("invalid client "LPX64"\n", conn->addr);
214                 RETURN(-EINVAL);
215         }
216
217         if (!(oa->o_valid & OBD_MD_FLID)) {
218                 CERROR("obdo missing FLID valid flag: %08x\n", oa->o_valid);
219                 RETURN(-EINVAL);
220         }
221
222         memcpy(&obd->u.echo.oa, oa, sizeof(*oa));
223
224         atomic_inc(&obd->u.echo.eo_setattr);
225
226         return 0;
227 }
228
229 /* This allows us to verify that desc_private is passed unmolested */
230 #define DESC_PRIV 0x10293847
231
232 int echo_preprw(int cmd, struct lustre_handle *conn, int objcount,
233                 struct obd_ioobj *obj, int niocount, struct niobuf_remote *nb,
234                 struct niobuf_local *res, void **desc_private)
235 {
236         struct obd_device *obd;
237         struct niobuf_local *r = res;
238         int rc = 0;
239         int i;
240
241         ENTRY;
242
243         obd = class_conn2obd(conn);
244         if (!obd) {
245                 CERROR("invalid client "LPX64"\n", conn->addr);
246                 RETURN(-EINVAL);
247         }
248
249         memset(res, 0, sizeof(*res) * niocount);
250
251         CDEBUG(D_PAGE, "%s %d obdos with %d IOs\n",
252                cmd == OBD_BRW_READ ? "reading" : "writing", objcount, niocount);
253
254         *desc_private = (void *)DESC_PRIV;
255
256         for (i = 0; i < objcount; i++, obj++) {
257                 int gfp_mask = (obj->ioo_id & 1) ? GFP_HIGHUSER : GFP_KERNEL;
258                 int verify = obj->ioo_id != 0;
259                 int j;
260
261                 for (j = 0 ; j < obj->ioo_bufcnt ; j++, nb++, r++) {
262                         r->page = alloc_pages(gfp_mask, 0);
263                         if (!r->page) {
264                                 CERROR("can't get page %d/%d for id "LPU64"\n",
265                                        j, obj->ioo_bufcnt, obj->ioo_id);
266                                 GOTO(preprw_cleanup, rc = -ENOMEM);
267                         }
268                         atomic_inc(&obd->u.echo.eo_prep);
269
270                         r->offset = nb->offset;
271                         r->addr = kmap(r->page);
272                         r->len = nb->len;
273
274                         CDEBUG(D_PAGE, "$$$$ get page %p, addr %p@"LPU64"\n",
275                                r->page, r->addr, r->offset);
276
277                         if (verify && cmd == OBD_BRW_READ)
278                                 page_debug_setup(r->addr, r->len, r->offset,
279                                                  obj->ioo_id);
280                         else if (verify)
281                                 page_debug_setup(r->addr, r->len,
282                                                  0xecc0ecc0ecc0ecc0,
283                                                  0xecc0ecc0ecc0ecc0);
284                 }
285         }
286         CDEBUG(D_PAGE, "%d pages allocated after prep\n",
287                atomic_read(&obd->u.echo.eo_prep));
288
289         RETURN(0);
290
291 preprw_cleanup:
292         /* It is possible that we would rather handle errors by  allow
293          * any already-set-up pages to complete, rather than tearing them
294          * all down again.  I believe that this is what the in-kernel
295          * prep/commit operations do.
296          */
297         CERROR("cleaning up %ld pages (%d obdos)\n", (long)(r - res), objcount);
298         while (r-- > res) {
299                 kunmap(r->page);
300                 __free_pages(r->page, 0);
301                 atomic_dec(&obd->u.echo.eo_prep);
302         }
303         memset(res, 0, sizeof(*res) * niocount);
304
305         return rc;
306 }
307
308 int echo_commitrw(int cmd, struct lustre_handle *conn, int objcount,
309                   struct obd_ioobj *obj, int niocount, struct niobuf_local *res,
310                   void *desc_private)
311 {
312         struct obd_device *obd;
313         struct niobuf_local *r = res;
314         int rc = 0;
315         int i;
316         ENTRY;
317
318         obd = class_conn2obd(conn);
319         if (!obd) {
320                 CERROR("invalid client "LPX64"\n", conn->addr);
321                 RETURN(-EINVAL);
322         }
323
324         if ((cmd & OBD_BRW_RWMASK) == OBD_BRW_READ) {
325                 CDEBUG(D_PAGE, "reading %d obdos with %d IOs\n",
326                        objcount, niocount);
327         } else {
328                 CDEBUG(D_PAGE, "writing %d obdos with %d IOs\n",
329                        objcount, niocount);
330         }
331
332         if (niocount && !r) {
333                 CERROR("NULL res niobuf with niocount %d\n", niocount);
334                 RETURN(-EINVAL);
335         }
336
337         LASSERT(desc_private == (void *)DESC_PRIV);
338
339         for (i = 0; i < objcount; i++, obj++) {
340                 int verify = obj->ioo_id != 0;
341                 int j;
342
343                 for (j = 0 ; j < obj->ioo_bufcnt ; j++, r++) {
344                         struct page *page = r->page;
345                         void *addr;
346
347                         if (!page || !(addr = page_address(page)) ||
348                             !kern_addr_valid(addr)) {
349
350                                 CERROR("bad page objid "LPU64":%p, buf %d/%d\n",
351                                        obj->ioo_id, page, j, obj->ioo_bufcnt);
352                                 GOTO(commitrw_cleanup, rc = -EFAULT);
353                         }
354
355                         atomic_inc(&echo_page_rws);
356
357                         CDEBUG(D_PAGE, "$$$$ use page %p, addr %p@"LPU64"\n",
358                                r->page, addr, r->offset);
359
360                         if (verify)
361                                 page_debug_check("echo", addr, r->len,
362                                                  r->offset, obj->ioo_id);
363
364                         kunmap(page);
365                         __free_pages(page, 0);
366                         atomic_dec(&obd->u.echo.eo_prep);
367                 }
368         }
369         CDEBUG(D_PAGE, "%d pages remain after commit\n",
370                atomic_read(&obd->u.echo.eo_prep));
371         RETURN(0);
372
373 commitrw_cleanup:
374         CERROR("cleaning up %ld pages (%d obdos)\n",
375                niocount - (long)(r - res) - 1, objcount);
376         while (++r < res + niocount) {
377                 struct page *page = r->page;
378
379                 kunmap(page);
380                 __free_pages(page, 0);
381                 atomic_dec(&obd->u.echo.eo_prep);
382         }
383         return rc;
384 }
385
386 static int echo_setup(struct obd_device *obddev, obd_count len, void *buf)
387 {
388         ENTRY;
389
390         obddev->obd_namespace =
391                 ldlm_namespace_new("echo-tgt", LDLM_NAMESPACE_SERVER);
392         if (obddev->obd_namespace == NULL) {
393                 LBUG();
394                 RETURN(-ENOMEM);
395         }
396
397         RETURN(0);
398 }
399
400 static int echo_cleanup(struct obd_device *obddev)
401 {
402         ENTRY;
403
404         ldlm_namespace_free(obddev->obd_namespace);
405         CERROR("%d prep/commitrw pages leaked\n",
406                atomic_read(&obddev->u.echo.eo_prep));
407
408         RETURN(0);
409 }
410
411 struct obd_ops echo_obd_ops = {
412         o_connect:      echo_connect,
413         o_disconnect:   echo_disconnect,
414         o_create:       echo_create,
415         o_destroy:      echo_destroy,
416         o_getattr:      echo_getattr,
417         o_setattr:      echo_setattr,
418         o_preprw:       echo_preprw,
419         o_commitrw:     echo_commitrw,
420         o_setup:        echo_setup,
421         o_cleanup:      echo_cleanup
422 };
423
424 static int __init obdecho_init(void)
425 {
426         printk(KERN_INFO "Echo OBD driver " OBDECHO_VERSION
427                " info@clusterfs.com\n");
428
429         echo_proc_init();
430
431         return class_register_type(&echo_obd_ops, OBD_ECHO_DEVICENAME);
432 }
433
434 static void __exit obdecho_exit(void)
435 {
436         echo_proc_fini();
437
438         class_unregister_type(OBD_ECHO_DEVICENAME);
439 }
440
441 MODULE_AUTHOR("Cluster Filesystems Inc. <info@clusterfs.com>");
442 MODULE_DESCRIPTION("Lustre Testing Echo OBD driver " OBDECHO_VERSION);
443 MODULE_LICENSE("GPL");
444
445 module_init(obdecho_init);
446 module_exit(obdecho_exit);