Whamcloud - gitweb
New files:
[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 /* VFS super_block ops */
36
37 /* returns the page unlocked, but with a reference */
38 int obdfs_readpage(struct file *file, struct page *page)
39 {
40         struct obdfs_sb_info *sbi;
41         struct super_block *sb = file->f_dentry->d_inode->i_sb;
42         int rc;
43
44         ENTRY;
45
46         /* XXX flush stuff */
47         sbi = sb->u.generic_sbp;
48         PDEBUG(page, "READ");
49         rc =  sbi->osi_ops->o_brw(READ, sbi->osi_conn_info.conn_id, 
50                       file->f_dentry->d_inode->i_ino, page, 0);
51         if (rc == PAGE_SIZE ) {
52                 SetPageUptodate(page);
53                 UnlockPage(page);
54         } 
55         PDEBUG(page, "READ");
56         if ( rc == PAGE_SIZE ) 
57                 rc = 0;
58         return rc;
59
60 }
61
62 /*
63  * This does the "real" work of the write. The generic routine has
64  * allocated the page, locked it, done all the page alignment stuff
65  * calculations etc. Now we should just copy the data from user
66  * space and write it back to the real medium..
67  *
68  * If the writer ends up delaying the write, the writer needs to
69  * increment the page use counts until he is done with the page.
70  */
71 int obdfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
72 {
73         long status;
74         struct obdfs_sb_info *sbi = file->f_dentry->d_inode->i_sb->u.generic_sbp;
75
76         ENTRY;
77         if ( !Page_Uptodate(page) ) {
78                 status =  sbi->osi_ops->o_brw(READ, 
79                                               sbi->osi_conn_info.conn_id, 
80                                               file->f_dentry->d_inode->i_ino, 
81                                               page, 1);
82                 if (status == PAGE_SIZE ) {
83                         SetPageUptodate(page);
84                 } else { 
85                         return status;
86                 }
87         }
88         bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
89         status = -EFAULT;
90
91         if (bytes) {
92                 lock_kernel();
93                 status = obdfs_writepage(file, page);
94                 unlock_kernel();
95         }
96         EXIT;
97         if ( status != PAGE_SIZE ) 
98                 return status;
99         else
100                 return bytes;
101 }
102
103
104
105
106 /* returns the page unlocked, but with a reference */
107 int obdfs_writepage(struct file *file, struct page *page)
108 {
109         struct obdfs_sb_info *sbi = file->f_dentry->d_inode->i_sb->u.generic_sbp;
110         int rc;
111
112         ENTRY;
113         PDEBUG(page, "WRITEPAGE");
114         /* XXX flush stuff */
115
116         rc = sbi->osi_ops->o_brw(WRITE, sbi->osi_conn_info.conn_id, 
117                       file->f_dentry->d_inode->i_ino, page, 1);
118         SetPageUptodate(page);
119         PDEBUG(page,"WRITEPAGE");
120         return rc;
121 }
122
123
124 /* 
125    page is returned unlocked, with the up to date flag set, 
126    and held, i.e. caller must do a page_put
127 */
128 struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create, int locked)
129 {
130         unsigned long new_page;
131         struct page ** hash;
132         struct page * page; 
133         struct obdfs_sb_info *sbi;
134         struct super_block *sb = inode->i_sb;
135
136         ENTRY;
137
138         sbi = sb->u.generic_sbp;
139         
140         page = find_lock_page(inode, offset); 
141         if (page && Page_Uptodate(page)) { 
142                 PDEBUG(page,"GETPAGE");
143                 if (!locked)
144                         UnlockPage(page);
145                 EXIT;
146                 return page;
147         } 
148                 
149         if (page && !Page_Uptodate(page) ) {
150                 CDEBUG(D_INODE, "Page found but not up to date\n");
151         }
152
153         /* page_cache_alloc returns the VM address of page */
154         new_page = page_cache_alloc();
155         if (!new_page)
156                 return NULL;
157         
158         /* corresponding struct page in the mmap */
159         hash = page_hash(inode, offset);
160         page = page_cache_entry(new_page);
161         if (!add_to_page_cache_unique(page, inode, offset, hash)) {
162                 CDEBUG(D_INODE, "Page not found. Reading it.\n");
163                 PDEBUG(page,"GETPAGE - before reading");
164                 sbi->osi_ops->o_brw(READ, sbi->osi_conn_info.conn_id, 
165                                     inode->i_ino, page, create);
166                 if ( !locked )
167                         UnlockPage(page);
168                 SetPageUptodate(page);
169                 PDEBUG(page,"GETPAGE - after reading");
170                 EXIT;
171                 return page;
172         }
173         /*
174          * We arrive here in the unlikely event that someone 
175          * raced with us and added our page to the cache first.
176          */
177         CDEBUG(D_INODE, "Page not found. Someone raced us.\n");
178         PDEBUG(page,"GETPAGE");
179         EXIT;
180         return page;
181 }
182
183
184
185 struct file_operations obdfs_file_ops = {
186         NULL,                   /* lseek - default */
187         generic_file_read,      /* read */
188         obdfs_file_write,     /* write - bad */
189         obdfs_readdir,          /* readdir */
190         NULL,                   /* poll - default */
191         NULL,                   /* ioctl */
192         NULL,                   /* mmap */
193         NULL,                   /* no special open code */
194         NULL,                   /* flush */
195         NULL,                   /* no special release code */
196         NULL,                   /* fsync */
197         NULL,                   /* fasync */
198         NULL,                   /* check_media_change */
199         NULL                    /* revalidate */
200 };
201
202 struct inode_operations obdfs_inode_ops = {
203         &obdfs_file_ops,        /* default directory file-ops */
204         obdfs_create,   /* create */
205         obdfs_lookup,   /* lookup */
206         obdfs_link,     /* link */
207         obdfs_unlink,   /* unlink */
208         obdfs_symlink,  /* symlink */
209         obdfs_mkdir,    /* mkdir */
210         obdfs_rmdir,    /* rmdir */
211         obdfs_mknod,    /* mknod */
212         obdfs_rename,   /* rename */
213         NULL,           /* readlink */
214         NULL,           /* follow_link */
215         NULL,           /* get_block */
216         obdfs_readpage, /* readpage */
217         obdfs_writepage, /* writepage */
218         NULL,           /* flushpage */
219         NULL,           /* truncate */
220         NULL,           /* permission */
221         NULL,           /* smap */
222         NULL            /* revalidate */
223 };