2 * linux/fs/ext2_obd/sim_obd.c
3 * Copyright (C) 2001 Cluster File Systems, Inc.
5 * This code is issued under the GNU General Public License.
6 * See the file COPYING in this distribution
8 * These are the only exported functions; they provide the simulated object-
13 #define DEBUG_SUBSYSTEM S_CLASS
15 #include <linux/obd_class.h>
16 #include <linux/random.h>
17 #include <linux/slab.h>
19 extern struct obd_device obd_dev[MAX_OBD_DEVICES];
20 kmem_cache_t *obdo_cachep = NULL;
21 kmem_cache_t *export_cachep = NULL;
22 kmem_cache_t *import_cachep = NULL;
24 void obd_cleanup_caches(void)
29 rc = kmem_cache_destroy(obdo_cachep);
31 CERROR("Cannot destory obdo_cachep\n");
35 rc = kmem_cache_destroy(import_cachep);
37 CERROR("Cannot destory import_cachep\n");
41 rc = kmem_cache_destroy(export_cachep);
43 CERROR("Cannot destory import_cachep\n");
49 int obd_init_caches(void)
52 if (obdo_cachep == NULL) {
53 obdo_cachep = kmem_cache_create("obdo_cache",
55 0, SLAB_HWCACHE_ALIGN,
57 if (obdo_cachep == NULL)
61 if (export_cachep == NULL) {
62 export_cachep = kmem_cache_create("export_cache",
63 sizeof(struct obd_export),
64 0, SLAB_HWCACHE_ALIGN,
66 if (export_cachep == NULL)
70 if (import_cachep == NULL) {
71 import_cachep = kmem_cache_create("import_cache",
72 sizeof(struct obd_import),
73 0, SLAB_HWCACHE_ALIGN,
75 if (import_cachep == NULL)
86 /* map connection to client */
87 struct obd_export *gen_client(struct obd_conn *conn)
89 struct obd_export * export;
94 if (!conn->addr || conn->addr == -1 ) {
99 export = (struct obd_export *) (unsigned long)conn->addr;
100 if (!kmem_cache_validate(export_cachep, (void *)export))
103 if (export->export_cookie != conn->cookie)
108 struct obd_device *gen_conn2obd(struct obd_conn *conn)
110 struct obd_export *export;
111 export = gen_client(conn);
113 return export->export_obd;
118 /* a connection defines a context in which preallocation can be managed. */
119 int gen_connect (struct obd_conn *conn, struct obd_device *obd)
121 struct obd_export * export;
123 export = kmem_cache_alloc(export_cachep, GFP_KERNEL);
125 CERROR("no memory! (minor %d)\n", obd->obd_minor);
129 memset(export, 0, sizeof(*export));
130 get_random_bytes(&export->export_cookie, sizeof(__u64));
131 /* XXX this should probably spinlocked? */
132 export->export_id = ++obd->obd_gen_last_id;
133 export->export_obd = obd;
134 export->export_import.addr = conn->addr;
135 export->export_import.cookie = conn->cookie;
137 list_add(&(export->export_chain), export->export_obd->obd_exports.prev);
139 CDEBUG(D_INFO, "connect: new ID %u\n", export->export_id);
140 conn->addr = (__u64) (unsigned long)export;
141 conn->cookie = export->export_cookie;
146 int gen_disconnect(struct obd_conn *conn)
148 struct obd_export * export;
151 if (!(export = gen_client(conn))) {
153 CDEBUG(D_IOCTL, "disconnect: attempting to free "
154 "nonexistent client %Lx\n", conn->addr);
157 list_del(&export->export_chain);
158 kmem_cache_free(export_cachep, export);
161 } /* gen_obd_disconnect */
163 /* FIXME: Data is a space- or comma-separated list of device IDs. This will
165 int gen_multi_setup(struct obd_device *obddev, uint32_t len, void *data)
171 for (p = data, count = 0; p < (char *)data + len; count++) {
173 int tmp = simple_strtoul(p, &end, 0);
176 CERROR("invalid device ID starting at: %s\n", p);
177 GOTO(err_disconnect, rc = -EINVAL);
180 if (tmp < 0 || tmp >= MAX_OBD_DEVICES) {
181 CERROR("Trying to sub dev %d - dev no too large\n",
183 GOTO(err_disconnect, rc);
186 rc = obd_connect(&obddev->obd_multi_conn[count], &obd_dev[tmp]);
188 CERROR("cannot connect to device %d: rc = %d\n", tmp,
190 GOTO(err_disconnect, rc);
193 CDEBUG(D_INFO, "target OBD %d is of type %s\n", count,
194 obd_dev[tmp].obd_type->typ_name);
199 obddev->obd_multi_count = count;
204 for (count--; count >= 0; count--)
205 obd_disconnect(&obddev->obd_multi_conn[count]);
210 * remove all connections to this device
211 * close all connections to lower devices
212 * needed for forced unloads of OBD client drivers
214 int gen_multi_cleanup(struct obd_device *obddev)
218 for (i = 0; i < obddev->obd_multi_count; i++) {
220 struct obd_device *obd = gen_conn2obd(&obddev->obd_multi_conn[i]);
223 CERROR("no such device [i %d]\n", i);
227 rc = obd_disconnect(&obddev->obd_multi_conn[i]);
229 CERROR("disconnect failure %d\n", obd->obd_minor);
236 * forced cleanup of the device:
237 * - remove connections from the device
238 * - cleanup the device afterwards
240 int gen_cleanup(struct obd_device * obddev)
242 struct list_head * lh, * tmp;
243 struct obd_export * export;
247 lh = tmp = &obddev->obd_exports;
248 while ((tmp = tmp->next) != lh) {
249 export = list_entry(tmp, struct obd_export, export_chain);
250 CDEBUG(D_INFO, "Disconnecting obd_connection %d, at %p\n",
251 export->export_id, export);
254 } /* sim_cleanup_device */
256 void lck_page(struct page *page)
258 while (TryLockPage(page))
259 ___wait_on_page(page);
262 int gen_copy_data(struct obd_conn *dst_conn, struct obdo *dst,
263 struct obd_conn *src_conn, struct obdo *src,
264 obd_size count, obd_off offset)
267 unsigned long index = 0;
271 CDEBUG(D_INFO, "src: ino %Ld blocks %Ld, size %Ld, dst: ino %Ld\n",
272 (unsigned long long)src->o_id, (unsigned long long)src->o_blocks,
273 (unsigned long long)src->o_size, (unsigned long long)dst->o_id);
274 page = alloc_page(GFP_USER);
280 /* XXX with brw vector I/O, we could batch up reads and writes here,
281 * all we need to do is allocate multiple pages to handle the I/Os
282 * and arrays to handle the request parameters.
284 while (index < ((src->o_size + PAGE_SIZE - 1) >> PAGE_SHIFT)) {
285 obd_count num_oa = 1;
286 obd_count num_buf = 1;
287 obd_size brw_count = PAGE_SIZE;
288 obd_off brw_offset = (page->index) << PAGE_SHIFT;
290 obd_flag flagw = OBD_BRW_CREATE;
293 err = obd_brw(OBD_BRW_READ, src_conn, num_oa, &src, &num_buf,
294 &page, &brw_count, &brw_offset, &flagr, NULL);
300 CDEBUG(D_INFO, "Read page %ld ...\n", page->index);
302 err = obd_brw(OBD_BRW_WRITE, dst_conn, num_oa, &dst, &num_buf,
303 &page, &brw_count, &brw_offset, &flagw, NULL);
305 /* XXX should handle dst->o_size, dst->o_blocks here */
311 CDEBUG(D_INFO, "Wrote page %ld ...\n", page->index);
315 dst->o_size = src->o_size;
316 dst->o_blocks = src->o_blocks;
317 dst->o_valid |= (OBD_MD_FLSIZE | OBD_MD_FLBLOCKS);