Whamcloud - gitweb
snap/snap.c: fixed check for snap_create() to test for correct
[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 <asm/uaccess.h>
10 #include <linux/sched.h>
11 #include <linux/stat.h>
12 #include <linux/string.h>
13 #include <linux/locks.h>
14 #include <linux/quotaops.h>
15 #include <linux/list.h>
16 #include <linux/file.h>
17 #include <linux/iobuf.h>
18 #include <asm/bitops.h>
19 #include <asm/byteorder.h>
20 #include <linux/obd_support.h>
21 #include <linux/obd_class.h>
22
23
24 extern struct obd_device obd_dev[MAX_OBD_DEVICES];
25
26 /* map connection to client */
27 struct obd_client *gen_client(struct obd_conn *conn)
28 {
29         struct obd_device * obddev = conn->oc_dev;
30         struct list_head * lh, * next;
31         struct obd_client * cli;
32
33         lh = next = &obddev->obd_gen_clients;
34         while ((lh = lh->next) != &obddev->obd_gen_clients) {
35                 cli = list_entry(lh, struct obd_client, cli_chain);
36                 
37                 if (cli->cli_id == conn->oc_id)
38                         return cli;
39         }
40
41         return NULL;
42 } /* obd_client */
43
44
45
46 /* a connection defines a context in which preallocation can be managed. */ 
47 int gen_connect (struct obd_conn *conn)
48 {
49         struct obd_client * cli;
50
51         OBD_ALLOC(cli, struct obd_client *, sizeof(struct obd_client));
52         if ( !cli ) {
53                 printk("obd_connect (minor %d): no memory!\n", 
54                        conn->oc_dev->obd_minor);
55                 return -ENOMEM;
56         }
57
58         INIT_LIST_HEAD(&cli->cli_prealloc_inodes);
59         /* this should probably spinlocked? */
60         cli->cli_id = ++conn->oc_dev->obd_gen_last_id;
61         cli->cli_prealloc_quota = 0;
62         cli->cli_obd = conn->oc_dev;
63         list_add(&(cli->cli_chain), conn->oc_dev->obd_gen_clients.prev);
64
65         CDEBUG(D_IOCTL, "connect: new ID %u\n", cli->cli_id);
66         conn->oc_id = cli->cli_id;
67         return 0;
68 } /* gen_obd_connect */
69
70
71 int gen_disconnect(struct obd_conn *conn)
72 {
73         struct obd_client * cli;
74         ENTRY;
75
76         if (!(cli = gen_client(conn))) {
77                 CDEBUG(D_IOCTL, "disconnect: attempting to free "
78                        "nonexistent client %u\n", conn->oc_id);
79                 return -EINVAL;
80         }
81
82
83         list_del(&(cli->cli_chain));
84         OBD_FREE(cli, sizeof(struct obd_client));
85
86         CDEBUG(D_IOCTL, "disconnect: ID %u\n", conn->oc_id);
87
88         EXIT;
89         return 0;
90 } /* gen_obd_disconnect */
91
92
93 /* 
94  *   raid1 defines a number of connections to child devices,
95  *   used to make calls to these devices.
96  *   data holds nothing
97  */ 
98 int gen_multi_setup(struct obd_device *obddev, int len, void *data)
99 {
100         int i;
101
102         for (i = 0 ; i < obddev->obd_multi_count ; i++ ) {
103                 int rc;
104                 struct obd_conn *ch_conn = &obddev->obd_multi_conn[i];
105                 rc  = OBP(ch_conn->oc_dev, connect)(ch_conn);
106
107                 if ( rc != 0 ) {
108                         /* XXX disconnect others */
109                         return -EINVAL;
110                 }
111         }               
112         return 0;
113 }
114
115
116 #if 0
117 int gen_multi_attach(struct obd_device *obddev, int len, void *data)
118 {
119         int i;
120         int count;
121         struct obd_device *rdev = obddev->obd_multi_dev[0];
122
123         count = len/sizeof(int);
124         obddev->obd_multi_count = count;
125         for (i=0 ; i<count ; i++) {
126                 rdev = &obd_dev[*((int *)data + i)];
127                 rdev = rdev + 1;
128                 CDEBUG(D_IOCTL, "OBD RAID1: replicator %d is of type %s\n", i,
129                        (rdev + i)->obd_type->typ_name);
130         }
131         return 0;
132 }
133 #endif
134
135
136 /*
137  *    remove all connections to this device
138  *    close all connections to lower devices
139  *    needed for forced unloads of OBD client drivers
140  */
141 int gen_multi_cleanup(struct obd_device *obddev)
142 {
143         int i;
144
145         for (i = 0 ; i < obddev->obd_multi_count ; i++ ) {
146                 struct obd_conn *ch_conn = &obddev->obd_multi_conn[i];
147                 int rc;
148                 rc  = OBP(ch_conn->oc_dev, disconnect)(ch_conn);
149
150                 if ( rc != 0 ) {
151                         printk("OBD multi cleanup dev: disconnect failure %d\n", ch_conn->oc_dev->obd_minor);
152                 }
153         }               
154         return 0;
155 } /* gen_multi_cleanup_device */
156
157
158 /*
159  *    forced cleanup of the device:
160  *    - remove connections from the device
161  *    - cleanup the device afterwards
162  */
163 int gen_cleanup(struct obd_device * obddev)
164 {
165         struct list_head * lh, * tmp;
166         struct obd_client * cli;
167
168         ENTRY;
169
170         lh = tmp = &obddev->obd_gen_clients;
171         while ((tmp = tmp->next) != lh) {
172                 cli = list_entry(tmp, struct obd_client, cli_chain);
173                 CDEBUG(D_IOCTL, "Disconnecting obd_connection %d, at %p\n",
174                        cli->cli_id, cli);
175         }
176         return 0;
177 } /* sim_cleanup_device */
178
179 void ___wait_on_page(struct page *page)
180 {
181         struct task_struct *tsk = current;
182         DECLARE_WAITQUEUE(wait, tsk);
183
184         add_wait_queue(&page->wait, &wait);
185         do {
186                 run_task_queue(&tq_disk);
187                 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
188                 if (!PageLocked(page))
189                         break;
190                 schedule();
191         } while (PageLocked(page));
192         tsk->state = TASK_RUNNING;
193         remove_wait_queue(&page->wait, &wait);
194 }
195
196 void lck_page(struct page *page)
197 {
198         while (TryLockPage(page))
199                 ___wait_on_page(page);
200 }
201
202 /* XXX this should return errors correctly, so should migrate!!! */
203 int gen_copy_data(struct obd_conn *conn, obdattr *tgt, obdattr *src)
204 {
205         struct page *page;
206         unsigned long index = 0;
207         int rc;
208         ENTRY;
209
210         CDEBUG(D_INODE, "src: ino %ld blocks %ld, size %Ld, dst: ino %ld\n", 
211                src->i_ino, src->i_blocks, src->i_size, dst->i_ino);
212         page = alloc_page(GFP_USER);
213         if ( !page ) {
214                 EXIT;
215                 return -ENOMEM;
216         }
217         
218         lck_page(page);
219         
220         while (index < ((src->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT)) {
221                 
222                 page->index = index;
223                 rc = OBP(conn->oc_dev, brw)(READ, conn, src, page, 0);
224
225                 if ( rc != PAGE_SIZE ) 
226                         break;
227
228                 rc = OBP(conn->oc_dev,brw)(WRITE, conn, tgt, page, 1);
229                 if ( rc != PAGE_SIZE)
230                         break;
231
232                 CDEBUG(D_INODE, "Copied page %d ...\n", index);
233                 
234                 index ++;
235         }
236         tgt->i_size = src->i_size;
237         tgt->i_blocks = src->i_blocks;
238         UnlockPage(page);
239         __free_page(page);
240
241         EXIT;
242         return 0;
243 }