Whamcloud - gitweb
Over of the changes:
[fs/lustre-release.git] / lustre / obdfs / rw.c
1 /*
2  * OBDFS Super operations
3  *
4  * Copryright (C) 1999 Stelias Computing Inc, 
5  *                (author Peter J. Braam <braam@stelias.com>)
6  * Copryright (C) 1999 Seagate Technology Inc.
7  */
8
9
10 #include <linux/config.h>
11 #include <linux/kernel.h>
12 #include <linux/mm.h>
13 #include <linux/string.h>
14 #include <linux/stat.h>
15 #include <linux/errno.h>
16 #include <linux/locks.h>
17 #include <linux/unistd.h>
18
19 #include <asm/system.h>
20 #include <asm/uaccess.h>
21
22 #include <linux/fs.h>
23 #include <linux/stat.h>
24 #include <asm/uaccess.h>
25 #include <linux/vmalloc.h>
26 #include <asm/segment.h>
27 #include <linux/mm.h>
28 #include <linux/pagemap.h>
29 #include <linux/smp_lock.h>
30
31 #include <../obd/linux/obd_support.h>
32 #include <../obd/linux/obd_sim.h>
33 #include <obdfs.h>
34
35 int console_loglevel;
36
37 /* VFS super_block ops */
38
39 /* returns the page unlocked, but with a reference */
40 int obdfs_readpage(struct file *file, struct page *page)
41 {
42         struct obdfs_sb_info *sbi;
43         struct super_block *sb = file->f_dentry->d_inode->i_sb;
44         int rc;
45
46         ENTRY;
47
48         /* XXX flush stuff */
49         sbi = sb->u.generic_sbp;
50         PDEBUG(page, "READ");
51         rc =  sbi->osi_ops->o_brw(READ, sbi->osi_conn_info.conn_id, 
52                       file->f_dentry->d_inode, page, 0);
53         if (rc == PAGE_SIZE ) {
54                 SetPageUptodate(page);
55                 UnlockPage(page);
56         } 
57         PDEBUG(page, "READ");
58         if ( rc == PAGE_SIZE ) 
59                 rc = 0;
60         return rc;
61
62 }
63
64 /*
65  * This does the "real" work of the write. The generic routine has
66  * allocated the page, locked it, done all the page alignment stuff
67  * calculations etc. Now we should just copy the data from user
68  * space and write it back to the real medium..
69  *
70  * If the writer ends up delaying the write, the writer needs to
71  * increment the page use counts until he is done with the page.
72  */
73 int obdfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
74 {
75         long status;
76         struct obdfs_sb_info *sbi = file->f_dentry->d_inode->i_sb->u.generic_sbp;
77
78         ENTRY;
79         if ( !Page_Uptodate(page) ) {
80                 status =  sbi->osi_ops->o_brw(READ, 
81                                               sbi->osi_conn_info.conn_id, 
82                                               file->f_dentry->d_inode, 
83                                               page, 1);
84                 if (status == PAGE_SIZE ) {
85                         SetPageUptodate(page);
86                 } else { 
87                         return status;
88                 }
89         }
90         bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
91         status = -EFAULT;
92
93         if (bytes) {
94
95                 lock_kernel();
96                 status = obdfs_writepage(file, page);
97                 unlock_kernel();
98         }
99         EXIT;
100         if ( status != PAGE_SIZE ) 
101                 return status;
102         else
103                 return bytes;
104 }
105
106
107
108
109 /* returns the page unlocked, but with a reference */
110 int obdfs_writepage(struct file *file, struct page *page)
111 {
112         struct obdfs_sb_info *sbi = file->f_dentry->d_inode->i_sb->u.generic_sbp;
113         int rc;
114
115         ENTRY;
116         PDEBUG(page, "WRITEPAGE");
117         /* XXX flush stuff */
118
119         rc = sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id, 
120                       file->f_dentry->d_inode, page, 1);
121
122         SetPageUptodate(page);
123         PDEBUG(page,"WRITEPAGE");
124         return rc;
125 }
126
127
128 void report_inode(struct page * page) {
129         struct inode *inode = (struct inode *)0;
130         int offset = (int)&inode->i_data;
131         inode = (struct inode *)( (char *)page->mapping - offset);
132         if ( inode->i_sb->s_magic == 0x4711 )
133                 printk("----> ino %ld , dev %d\n", inode->i_ino, inode->i_dev);
134 }
135
136 /* 
137    return an up to date page:
138     - if locked is true then is returned locked
139     - if create is true the corresponding disk blocks are created 
140     - page is held, i.e. caller must release the page
141
142    modeled on NFS code.
143 */
144 struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create, int locked)
145 {
146         struct page *page_cache;
147         struct page ** hash;
148         struct page * page;
149         struct obdfs_sb_info *sbi;
150         struct super_block *sb = inode->i_sb;
151         int rc;
152
153         ENTRY;
154
155         offset = offset & PAGE_CACHE_MASK;
156         sbi = sb->u.generic_sbp;
157         CDEBUG(D_INODE, "\n");
158         
159         page = NULL;
160         page_cache = page_cache_alloc();
161         if ( ! page_cache ) 
162                 return NULL;
163         CDEBUG(D_INODE, "page_cache %p\n", page_cache);
164
165         hash = page_hash(&inode->i_data, offset);
166  repeat:
167         CDEBUG(D_INODE, "Finding page\n");
168         IDEBUG(inode);
169
170         page = __find_lock_page(&inode->i_data, offset, hash); 
171         if ( page ) {
172                 CDEBUG(D_INODE, "Page found freeing\n");
173                 page_cache_free(page_cache);
174         } else {
175                 page = page_cache;
176                 if ( page->buffers ) {
177                         PDEBUG(page, "GETPAGE: buffers bug\n");
178                         UnlockPage(page);
179                         return NULL;
180                 }
181                 if (add_to_page_cache_unique(page, &inode->i_data, offset, hash)) {
182                         page_cache_release(page);
183                         CDEBUG(D_INODE, "Someone raced: try again\n");
184                         goto repeat;
185                 }
186         }
187
188         PDEBUG(page, "GETPAGE: got page - before reading\n");
189         /* now check if the data in the page is up to date */
190         if ( Page_Uptodate(page)) { 
191                 if (!locked)
192                         UnlockPage(page);
193                 EXIT;
194                 return page;
195         } 
196
197         /* it's not: read it */
198         if (! page) {
199             printk("get_page_map says no dice ...\n");
200             return 0;
201             }
202
203
204
205         rc = sbi->osi_ops->o_brw(READ, sbi->osi_conn_info.conn_id, 
206                                     inode, page, create);
207         if ( rc != PAGE_SIZE ) {
208                 SetPageError(page);
209                 UnlockPage(page);
210                 return page;
211         }
212
213         if ( !locked )
214                 UnlockPage(page);
215         SetPageUptodate(page);
216         PDEBUG(page,"GETPAGE - after reading");
217         EXIT;
218         return page;
219 }
220
221
222 struct file_operations obdfs_file_ops = {
223         NULL,                   /* lseek - default */
224         generic_file_read,      /* read */
225         obdfs_file_write,     /* write - bad */
226         obdfs_readdir,          /* readdir */
227         NULL,                   /* poll - default */
228         NULL,                   /* ioctl */
229         NULL,                   /* mmap */
230         NULL,                   /* no special open code */
231         NULL,                   /* flush */
232         NULL,                   /* no special release code */
233         NULL,                   /* fsync */
234         NULL,                   /* fasync */
235         NULL,                   /* check_media_change */
236         NULL                    /* revalidate */
237 };
238
239 struct inode_operations obdfs_inode_ops = {
240         &obdfs_file_ops,        /* default directory file-ops */
241         obdfs_create,   /* create */
242         obdfs_lookup,   /* lookup */
243         obdfs_link,     /* link */
244         obdfs_unlink,   /* unlink */
245         obdfs_symlink,  /* symlink */
246         obdfs_mkdir,    /* mkdir */
247         obdfs_rmdir,    /* rmdir */
248         obdfs_mknod,    /* mknod */
249         obdfs_rename,   /* rename */
250         NULL,           /* readlink */
251         NULL,           /* follow_link */
252         NULL,           /* get_block */
253         obdfs_readpage, /* readpage */
254         obdfs_writepage, /* writepage */
255         NULL,           /* flushpage */
256         NULL,           /* truncate */
257         NULL,           /* permission */
258         NULL,           /* smap */
259         NULL            /* revalidate */
260 };