Whamcloud - gitweb
Updated snapshot files for new obdo methods. No testing yet.
[fs/lustre-release.git] / lustre / obdclass / genops.c
1 /*
2  *  linux/fs/ext2_obd/sim_obd.c
3  *
4  * These are the only exported functions; they provide the simulated object-
5  * oriented disk.
6  *
7  */
8
9 #include <linux/config.h>
10 #include <linux/kernel.h>
11 #include <linux/mm.h>
12 #include <linux/string.h>
13 #include <linux/stat.h>
14 #include <linux/errno.h>
15 #include <linux/locks.h>
16 #include <linux/unistd.h>
17
18 #include <asm/system.h>
19 #include <asm/uaccess.h>
20
21 #include <linux/fs.h>
22 #include <linux/stat.h>
23 #include <asm/uaccess.h>
24 #include <linux/vmalloc.h>
25 #include <asm/segment.h>
26 #include <linux/mm.h>
27 #include <linux/pagemap.h>
28 #include <linux/smp_lock.h>
29
30 #include <linux/obd_support.h>
31 #include <linux/obd_class.h>
32
33
34 extern struct obd_device obd_dev[MAX_OBD_DEVICES];
35 kmem_cache_t *obdo_cachep = NULL;
36
37 int obd_init_obdo_cache(void)
38 {
39         ENTRY;
40         if (obdo_cachep == NULL) {
41                 CDEBUG(D_INODE, "allocating obdo_cache\n");
42                 obdo_cachep = kmem_cache_create("obdo_cache",
43                                                 sizeof(struct obdo),
44                                                 0, SLAB_HWCACHE_ALIGN,
45                                                 NULL, NULL);
46                 if (obdo_cachep == NULL) {
47                         EXIT;
48                         return -ENOMEM;
49                 } else {
50                         CDEBUG(D_INODE, "allocated cache at %p\n", obdo_cachep);
51                 }
52         } else {
53                 CDEBUG(D_INODE, "using existing cache at %p\n", obdo_cachep);
54         }
55         EXIT;
56         return 0;
57 }
58
59 void obd_cleanup_obdo_cache(void)
60 {
61         ENTRY;
62         if (obdo_cachep != NULL) {
63                 /*
64                 CDEBUG(D_INODE, "shrinking obdo_cache at %p\n", obdo_cachep);
65                 if (kmem_cache_shrink(obdo_cachep))
66                         printk(KERN_INFO "obd_cleanup_obdo_cache: unable to free all of cache\n");
67                 */
68         } else
69                 printk(KERN_INFO "obd_cleanup_obdo_cache: called with NULL cache pointer\n");
70
71         EXIT;
72 }
73
74
75 /* map connection to client */
76 struct obd_client *gen_client(struct obd_conn *conn)
77 {
78         struct obd_device * obddev = conn->oc_dev;
79         struct list_head * lh, * next;
80         struct obd_client * cli;
81
82         lh = next = &obddev->obd_gen_clients;
83         while ((lh = lh->next) != &obddev->obd_gen_clients) {
84                 cli = list_entry(lh, struct obd_client, cli_chain);
85                 
86                 if (cli->cli_id == conn->oc_id)
87                         return cli;
88         }
89
90         return NULL;
91 } /* obd_client */
92
93
94 /* a connection defines a context in which preallocation can be managed. */ 
95 int gen_connect (struct obd_conn *conn)
96 {
97         struct obd_client * cli;
98
99         OBD_ALLOC(cli, struct obd_client *, sizeof(struct obd_client));
100         if ( !cli ) {
101                 printk("obd_connect (minor %d): no memory!\n", 
102                        conn->oc_dev->obd_minor);
103                 return -ENOMEM;
104         }
105
106         INIT_LIST_HEAD(&cli->cli_prealloc_inodes);
107         /* XXX this should probably spinlocked? */
108         cli->cli_id = ++conn->oc_dev->obd_gen_last_id;
109         cli->cli_prealloc_quota = 0;
110         cli->cli_obd = conn->oc_dev;
111         list_add(&(cli->cli_chain), conn->oc_dev->obd_gen_clients.prev);
112
113         CDEBUG(D_IOCTL, "connect: new ID %u\n", cli->cli_id);
114         conn->oc_id = cli->cli_id;
115         return 0;
116 } /* gen_obd_connect */
117
118
119 int gen_disconnect(struct obd_conn *conn)
120 {
121         struct obd_client * cli;
122         ENTRY;
123
124         if (!(cli = gen_client(conn))) {
125                 CDEBUG(D_IOCTL, "disconnect: attempting to free "
126                        "nonexistent client %u\n", conn->oc_id);
127                 return -EINVAL;
128         }
129
130
131         list_del(&(cli->cli_chain));
132         OBD_FREE(cli, sizeof(struct obd_client));
133
134         CDEBUG(D_IOCTL, "disconnect: ID %u\n", conn->oc_id);
135
136         EXIT;
137         return 0;
138 } /* gen_obd_disconnect */
139
140
141 /* 
142  *   raid1 defines a number of connections to child devices,
143  *   used to make calls to these devices.
144  *   data holds nothing
145  */ 
146 int gen_multi_setup(struct obd_device *obddev, uint32_t len, void *data)
147 {
148         int i;
149
150         for (i = 0 ; i < obddev->obd_multi_count ; i++ ) {
151                 int rc;
152                 struct obd_conn *ch_conn = &obddev->obd_multi_conn[i];
153                 rc  = OBP(ch_conn->oc_dev, connect)(ch_conn);
154
155                 if ( rc != 0 ) {
156                         /* XXX disconnect others */
157                         return -EINVAL;
158                 }
159         }               
160         return 0;
161 }
162
163
164 #if 0
165 int gen_multi_attach(struct obd_device *obddev, int len, void *data)
166 {
167         int i;
168         int count;
169         struct obd_device *rdev = obddev->obd_multi_dev[0];
170
171         count = len/sizeof(int);
172         obddev->obd_multi_count = count;
173         for (i=0 ; i<count ; i++) {
174                 rdev = &obd_dev[*((int *)data + i)];
175                 rdev = rdev + 1;
176                 CDEBUG(D_IOCTL, "OBD RAID1: replicator %d is of type %s\n", i,
177                        (rdev + i)->obd_type->typ_name);
178         }
179         return 0;
180 }
181 #endif
182
183
184 /*
185  *    remove all connections to this device
186  *    close all connections to lower devices
187  *    needed for forced unloads of OBD client drivers
188  */
189 int gen_multi_cleanup(struct obd_device *obddev)
190 {
191         int i;
192
193         for (i = 0 ; i < obddev->obd_multi_count ; i++ ) {
194                 struct obd_conn *ch_conn = &obddev->obd_multi_conn[i];
195                 int rc;
196                 rc  = OBP(ch_conn->oc_dev, disconnect)(ch_conn);
197
198                 if ( rc != 0 ) {
199                         printk("OBD multi cleanup dev: disconnect failure %d\n", ch_conn->oc_dev->obd_minor);
200                 }
201         }               
202         return 0;
203 } /* gen_multi_cleanup_device */
204
205
206 /*
207  *    forced cleanup of the device:
208  *    - remove connections from the device
209  *    - cleanup the device afterwards
210  */
211 int gen_cleanup(struct obd_device * obddev)
212 {
213         struct list_head * lh, * tmp;
214         struct obd_client * cli;
215
216         ENTRY;
217
218         lh = tmp = &obddev->obd_gen_clients;
219         while ((tmp = tmp->next) != lh) {
220                 cli = list_entry(tmp, struct obd_client, cli_chain);
221                 CDEBUG(D_IOCTL, "Disconnecting obd_connection %d, at %p\n",
222                        cli->cli_id, cli);
223         }
224         return 0;
225 } /* sim_cleanup_device */
226
227 void ___wait_on_page(struct page *page)
228 {
229         struct task_struct *tsk = current;
230         DECLARE_WAITQUEUE(wait, tsk);
231
232         add_wait_queue(&page->wait, &wait);
233         do {
234                 run_task_queue(&tq_disk);
235                 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
236                 if (!PageLocked(page))
237                         break;
238                 schedule();
239         } while (PageLocked(page));
240         tsk->state = TASK_RUNNING;
241         remove_wait_queue(&page->wait, &wait);
242 }
243
244 void lck_page(struct page *page)
245 {
246         while (TryLockPage(page))
247                 ___wait_on_page(page);
248 }
249
250 int gen_copy_data(struct obd_conn *dst_conn, struct obdo *dst,
251                   struct obd_conn *src_conn, struct obdo *src,
252                   obd_size count, obd_off offset)
253 {
254         struct page *page;
255         unsigned long index = 0;
256         int err = 0;
257
258         ENTRY;
259         CDEBUG(D_INODE, "src: ino %Ld blocks %Ld, size %Ld, dst: ino %Ld\n", 
260                src->o_id, src->o_blocks, src->o_size, dst->o_id);
261         page = alloc_page(GFP_USER);
262         if ( !page ) {
263                 EXIT;
264                 return -ENOMEM;
265         }
266         
267         lck_page(page);
268         
269         while (index < ((src->o_size + PAGE_SIZE - 1) >> PAGE_SHIFT)) {
270                 obd_size brw_count;
271                 
272                 brw_count = PAGE_SIZE;
273
274                 page->index = index;
275                 err = OBP(src_conn->oc_dev, brw)
276                         (READ, src_conn, src, (char *)page_address(page), 
277                          &brw_count, (page->index) << PAGE_SHIFT, 0);
278
279                 if ( err ) {
280                         EXIT;
281                         break;
282                 }
283                 CDEBUG(D_INODE, "Read page %ld ...\n", page->index);
284
285                 err = OBP(dst_conn->oc_dev, brw)
286                         (WRITE, dst_conn, dst, (char *)page_address(page), 
287                          &brw_count, (page->index) << PAGE_SHIFT, 1);
288
289                 /* XXX should handle dst->o_size, dst->o_blocks here */
290                 if ( err ) {
291                         EXIT;
292                         break;
293                 }
294
295                 CDEBUG(D_INODE, "Wrote page %ld ...\n", page->index);
296                 
297                 index++;
298         }
299         dst->o_size = src->o_size;
300         dst->o_blocks = src->o_blocks;
301         dst->o_valid |= (OBD_MD_FLSIZE | OBD_MD_FLBLOCKS);
302         UnlockPage(page);
303         __free_page(page);
304
305         EXIT;
306         return err;
307 }