Whamcloud - gitweb
merge b_devel into HEAD. Includes:
[fs/lustre-release.git] / lustre / ptlbd / blk.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 2002, 2003 Cluster File Systems, Inc.
5  *   Author: Zach Brown <zab@clusterfs.com>
6  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22 #include <linux/module.h>
23 #include <linux/major.h>
24 #include <linux/smp.h>
25
26 #define DEBUG_SUBSYSTEM S_PTLBD
27
28 #include <linux/lustre_lite.h>
29 #include <linux/lustre_ha.h>
30 #include <linux/obd_support.h>
31 #include <linux/lustre_idl.h>
32 #include <linux/obd_ptlbd.h>
33
34 /*
35  * todo:
36  *   assign proper major number
37  *   allow more minors
38  *   discover actual block sizes?
39  *   allow more than one sector per io
40  *   think about vary-io
41  *   restrict single ops to sequential block io
42  *   ddn target addresses need to be 32 bit
43  *   cant get to addresses after 0xFFFF0000
44  */
45
46 #define PTLBD_MAJOR 253
47 #define PTLBD_MAX_MINOR 1
48
49 #define MAJOR_NR PTLBD_MAJOR
50 #define LOCAL_END_REQUEST
51 #include <linux/blk.h>
52 #include <linux/blkdev.h>
53 #include <linux/blkpg.h>
54 #include <linux/devfs_fs_kernel.h>
55
56 static int ptlbd_size_size[PTLBD_MAX_MINOR];
57 static int ptlbd_size[PTLBD_MAX_MINOR];
58 static int ptlbd_hardsect_size[PTLBD_MAX_MINOR];
59 static int ptlbd_max_sectors[PTLBD_MAX_MINOR];
60 //RHism static char ptlbd_dev_varyio[PTLBD_MAX_MINOR];
61
62 /*
63  * per minor state, indexed by minor.
64  */
65
66 static struct ptlbd_obd *one_for_now;
67
68 void ptlbd_blk_register(struct ptlbd_obd *ptlbd)
69 {
70         ENTRY;
71         one_for_now = ptlbd;
72         EXIT;
73 }
74
75 static struct ptlbd_obd * ptlbd_get_minor(int minor)
76 {
77         ENTRY;
78         if ( minor >= PTLBD_MAX_MINOR ) 
79                 RETURN( ERR_PTR(-ENODEV) );
80         RETURN(one_for_now);
81 }
82
83 static struct ptlbd_obd * ptlbd_get_inode(struct inode  *inode)
84 {
85         ENTRY;
86
87         if ( inode == NULL ) /* can this really happen? */
88                 RETURN( ERR_PTR(-EINVAL) );
89
90         return ptlbd_get_minor(MINOR(inode->i_rdev));
91 }
92
93 static int ptlbd_open(struct inode *inode, struct file  *file)
94 {
95         struct ptlbd_obd *ptlbd = ptlbd_get_inode(inode);
96         ENTRY;
97
98         if ( IS_ERR(ptlbd) )
99                 RETURN(PTR_ERR(ptlbd));
100         if ( ptlbd->bd_import.imp_connection == NULL )
101                 RETURN(-ENODEV);
102
103         ptlbd->refcount++;
104         RETURN(0);
105 }
106
107 static int ptlbd_ioctl(struct inode *inode, struct file *file,
108                 unsigned int cmd, unsigned long arg)
109 {
110         struct ptlbd_obd *ptlbd;
111         int ret;
112
113         if ( ! capable(CAP_SYS_ADMIN) )
114                 RETURN(-EPERM);
115
116         ptlbd = ptlbd_get_inode(inode);
117         if ( IS_ERR(ptlbd) )
118                 RETURN( PTR_ERR(ptlbd) );
119
120         switch(cmd) {
121                 case BLKFLSBUF:
122                         ret = blk_ioctl(inode->i_rdev, cmd, arg);
123                         break;
124                 default:
125                         ret = -EINVAL;
126                         break;
127         }
128
129         RETURN(ret);
130 }
131
132 static int ptlbd_release(struct inode *inode, struct file *file)
133 {
134         struct ptlbd_obd *ptlbd = ptlbd_get_inode(inode);
135         ENTRY;
136
137         if ( IS_ERR(ptlbd) ) 
138                 RETURN( PTR_ERR(ptlbd) );
139
140         ptlbd->refcount--;
141         RETURN(0);
142 }
143
144 static void ptlbd_end_request_havelock(struct request *req)
145 {
146         struct buffer_head *bh;
147         int uptodate = 1;
148
149         if ( req->errors )
150                 uptodate = 0;
151
152         while( (bh = req->bh) != NULL ) {
153                 blk_finished_io(bh->b_size >> 9);
154                 req->bh = bh->b_reqnext;
155                 bh->b_reqnext = NULL;
156                 bh->b_end_io(bh, uptodate);
157         }
158         blkdev_release_request(req);
159 }
160
161 #if 0
162 static void ptlbd_end_request_getlock(struct request *req)
163 {
164         unsigned long flags;
165
166         spin_lock_irqsave(&io_request_lock, flags);
167         ptlbd_end_request_havelock(req);
168         spin_unlock_irqrestore(&io_request_lock, flags);
169 }
170 #endif
171
172 static void ptlbd_request(request_queue_t *q)
173 {
174         struct ptlbd_obd *ptlbd;
175         struct request *req;
176         ptlbd_cmd_t cmd;
177         ENTRY;
178
179         while ( !QUEUE_EMPTY ) {
180                 req = CURRENT;
181                 ptlbd = ptlbd_get_minor(MINOR(req->rq_dev));
182
183                 blkdev_dequeue_request(req);
184
185                 if ( ptlbd->refcount <= 0 ) {
186                         req->errors++;
187                         ptlbd_end_request_havelock(req);
188                         return;
189                 }
190
191                 spin_unlock_irq(&io_request_lock);
192
193                 /* XXX dunno if we're supposed to get this or not.. */
194                 /* __make_request() changes READA to READ - Kris */
195                 LASSERT(req->cmd != READA);
196
197                 if ( req->cmd == READ )
198                         cmd = PTLBD_READ;
199                 else 
200                         cmd = PTLBD_WRITE;
201
202                 ptlbd_send_req(ptlbd, cmd, req);
203
204                 spin_lock_irq(&io_request_lock);
205
206                 ptlbd_end_request_havelock(req);
207         }
208 }
209
210 static struct block_device_operations ptlbd_ops = {
211         .owner = THIS_MODULE,
212         .open = ptlbd_open,
213         .release = ptlbd_release,
214         .ioctl = ptlbd_ioctl,
215 };
216
217 int ptlbd_blk_init(void)
218 {
219         int ret;
220         int i;
221         ENTRY;
222
223         ret = register_blkdev(PTLBD_MAJOR, "ptlbd", &ptlbd_ops);
224         if ( ret < 0 ) 
225                 RETURN(ret);
226
227         blk_size[PTLBD_MAJOR] = ptlbd_size;
228         blksize_size[PTLBD_MAJOR] = ptlbd_size_size;
229         hardsect_size[PTLBD_MAJOR] = ptlbd_hardsect_size;
230         max_sectors[PTLBD_MAJOR] = ptlbd_max_sectors;
231         //RHism blkdev_varyio[PTLBD_MAJOR] = ptlbd_dev_varyio;
232
233         blk_init_queue(BLK_DEFAULT_QUEUE(PTLBD_MAJOR), ptlbd_request);
234         blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
235
236         for ( i = 0 ; i < PTLBD_MAX_MINOR ; i++) {
237                 ptlbd_size_size[i] = 4096;
238                 /* avoid integer overflow */
239                 ptlbd_size[i] = (16*1024*((1024*1024) >> BLOCK_SIZE_BITS));
240                 ptlbd_hardsect_size[i] = 4096;
241                 ptlbd_max_sectors[i] = 2;
242                 //RHism ptlbd_dev_varyio[i] = 0;
243                 /* XXX register_disk? */
244         }
245
246         return 0;
247 }
248
249 void ptlbd_blk_exit(void)
250 {
251         ENTRY;
252         blk_cleanup_queue(BLK_DEFAULT_QUEUE(PTLBD_MAJOR));
253         unregister_blkdev(PTLBD_MAJOR, "ptlbd");
254 }
255
256 #undef MAJOR_NR