Whamcloud - gitweb
Land b_smallfix onto HEAD (20040330_2312)
[fs/lustre-release.git] / lustre / llite / special.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Special file handling for Lustre.
5  *
6  *  Copyright (c) 2002, 2003 Cluster File Systems, Inc.
7  *   Author: Wang Di <wangdi@clusterfs.com>
8  *   Author: Andreas Dilger <adilger@clusterfs.com>
9  *
10  *   This file is part of Lustre, http://www.lustre.org.
11  *
12  *   Lustre is free software; you can redistribute it and/or
13  *   modify it under the terms of version 2 of the GNU General Public
14  *   License as published by the Free Software Foundation.
15  *
16  *   Lustre is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with Lustre; if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 #define DEBUG_SUBSYSTEM S_LLITE
27 #include <linux/lustre_dlm.h>
28 #include <linux/lustre_lite.h>
29 #include <linux/pagemap.h>
30 #include <linux/file.h>
31 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
32 #include <linux/lustre_compat25.h>
33 #endif
34 #include <asm/poll.h>
35 #include "llite_internal.h"
36
37 #define INODE_OPS 1
38 #define FILE_OPS 2
39
40 static struct file_operations **get_save_fops(struct file* filp, int mode)
41 {
42         struct inode *inode = filp->f_dentry->d_inode;
43         struct ll_inode_info *lli = ll_i2info(inode);
44
45         if (mode == INODE_OPS) {
46                 return &(lli->ll_save_ifop);
47         } else if (mode == FILE_OPS) {
48                 if (S_ISFIFO(inode->i_mode)) {
49                         switch (filp->f_mode) {
50                         case 1: /*O_RDONLY*/
51                                 return &(lli->ll_save_ffop);
52                         case 2: /*O_WRONLY*/
53                                 return &(lli->ll_save_wfop);
54                         case 3: /* O_RDWR */
55                                 return &(lli->ll_save_wrfop);
56                         default:
57                                 return NULL;
58                         }
59                 }
60                 return &(lli->ll_save_ffop);
61         } else {
62                 CERROR("invalid special file ops %d\n", mode);
63                 LBUG();
64         }
65 }
66
67 static void save_fops(struct file *filp, struct inode *inode,
68                       struct file_operations *sfops)
69 {
70         if (sfops != filp->f_op) {
71                 struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
72
73                 *pfop = filp->f_op;
74                 if (S_ISCHR(inode->i_mode))
75                         filp->f_op = &ll_special_chr_file_fops;
76                 else if (S_ISFIFO(inode->i_mode))
77                         filp->f_op = &ll_special_fifo_file_fops;
78
79                 CWARN("saved %p, replaced with %p\n", *pfop, filp->f_op);
80                 if ((*pfop)->owner)
81                         CWARN("%p has owner %p\n", *pfop,(*pfop)->owner);
82         }
83 }
84
85 static ssize_t ll_special_file_read(struct file *filp, char *buf,
86                                     size_t count, loff_t *ppos)
87 {
88         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
89         int rc = -EINVAL;
90
91         if (pfop && *pfop && (*pfop)->read)
92                 rc = (*pfop)->read(filp, buf, count, ppos);
93
94         RETURN(rc);
95 }
96
97 static ssize_t ll_special_file_write(struct file *filp, const char *buf,
98                                      size_t count, loff_t *ppos)
99 {
100         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
101         int rc = -EINVAL;
102
103         if (pfop && *pfop && (*pfop)->write)
104                 rc = (*pfop)->write(filp, buf, count, ppos);
105
106         RETURN(rc);
107 }
108
109 static int ll_special_file_ioctl(struct inode *inode, struct file *filp,
110                                  unsigned int cmd, unsigned long arg)
111 {
112         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
113         int rc = -ENOTTY;
114
115         if (pfop && *pfop && (*pfop)->ioctl) {
116                 struct file_operations *sfops = filp->f_op;
117
118                 rc = (*pfop)->ioctl(inode, filp, cmd, arg);
119                 save_fops(filp, inode, sfops);
120         }
121         RETURN(rc);
122 }
123
124 static loff_t ll_special_file_seek(struct file *filp, loff_t offset, int origin)
125 {
126         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
127         int rc = 0;
128
129         if (pfop && *pfop && (*pfop)->llseek)
130                 rc = (*pfop)->llseek(filp, offset, origin);
131         else
132                 rc = default_llseek(filp, offset, origin);
133
134         RETURN(rc);
135 }
136
137
138 #define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
139
140 static unsigned int ll_special_file_poll(struct file *filp,
141                                          struct poll_table_struct *poll_table)
142 {
143         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
144         int rc = DEFAULT_POLLMASK;
145
146         if (pfop && *pfop && (*pfop)->poll)
147                 rc = (*pfop)->poll(filp, poll_table);
148
149         RETURN(rc);
150 }
151
152 static int ll_special_file_open(struct inode *inode, struct file *filp)
153 {
154         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
155         int rc = -EINVAL;
156
157         if (pfop && *pfop && (*pfop)->open)
158                 rc = (*pfop)->open(inode, filp);
159
160         RETURN(rc);
161 }
162
163 static ssize_t ll_special_read(struct file *filp, char *buf, size_t count,
164                                loff_t *ppos)
165 {
166         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
167         int rc = -EINVAL;
168
169         if (pfop && *pfop && (*pfop)->read)
170                 rc = (*pfop)->read(filp, buf, count, ppos);
171
172         RETURN(rc);
173 }
174
175 static ssize_t ll_special_write(struct file *filp, const char *buf,
176                                 size_t count, loff_t *ppos)
177 {
178         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
179         int rc = -EINVAL;
180
181         if (pfop && *pfop && (*pfop)->write)
182                 rc = (*pfop)->write(filp, buf, count, ppos);
183
184         RETURN(rc);
185 }
186
187 static int ll_special_ioctl(struct inode *inode, struct file *filp,
188                             unsigned int cmd, unsigned long arg)
189 {
190         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
191         int rc = -ENOTTY;
192
193         if (pfop && *pfop && (*pfop)->ioctl) {
194                 struct file_operations *sfops = filp->f_op;
195
196                 rc = (*pfop)->ioctl(inode, filp, cmd, arg);
197                 /* sometimes, file_operations will be changed in ioctl */
198                 save_fops(filp, inode, sfops);
199         }
200
201         RETURN(rc);
202 }
203
204 static int ll_special_mmap(struct file * filp, struct vm_area_struct * vma)
205 {
206         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
207         int rc = -ENODEV;
208
209         if (pfop && *pfop && (*pfop)->mmap)
210                 rc = (*pfop)->mmap(filp, vma);
211
212         RETURN(rc);
213 }
214
215 static loff_t ll_special_seek(struct file *filp, loff_t offset, int origin)
216 {
217         struct file_operations** pfop = get_save_fops (filp, INODE_OPS);
218         int    rc = 0;
219
220         if (pfop && *pfop && (*pfop)->llseek)
221                 rc = (*pfop)->llseek(filp, offset, origin);
222         else
223                 rc = default_llseek(filp, offset, origin);
224
225         RETURN(rc);
226 }
227
228 static int ll_special_fsync(struct file *filp, struct dentry *dentry, int data)
229 {
230         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
231         int rc = -EINVAL;
232
233         if (pfop && *pfop && (*pfop)->fsync)
234                 rc = (*pfop)->fsync(filp, dentry, data);
235
236         RETURN(rc);
237 }
238
239 static int ll_special_file_fasync(int fd, struct file *filp, int on)
240 {
241         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
242         int rc = -EINVAL;
243
244         if (pfop && *pfop && (*pfop)->fasync)
245                 rc = (*pfop)->fasync(fd, filp, on);
246
247         RETURN(rc);
248 }
249
250 static int ll_special_release_internal(struct inode *inode, struct file *filp,
251                                        int mode)
252 {
253        struct file_operations **pfop = get_save_fops(filp, mode);
254        struct ll_sb_info *sbi = ll_i2sbi(inode);
255        int rc = 0, err;
256        ENTRY;
257
258         if (pfop && *pfop) {
259                 if ((*pfop)->release)
260                         rc = (*pfop)->release(inode, filp);
261                 /* FIXME fops_put */
262         }
263
264         lprocfs_counter_incr(sbi->ll_stats, LPROC_LL_RELEASE);
265
266         err = ll_mdc_close(sbi->ll_mdc_exp, inode, filp);
267         if (err && rc == 0)
268                 rc = err;
269
270         RETURN(rc);
271 }
272
273 static int ll_special_open(struct inode *inode, struct file *filp)
274 {
275         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
276         struct file_operations *sfops = filp->f_op;
277         struct ptlrpc_request *req;
278         struct lookup_intent *it;
279         int rc = -EINVAL, err;
280         ENTRY;
281
282         if (pfop && *pfop) {
283                 /* FIXME fops_get */
284                 if ((*pfop)->open) {
285                         rc = (*pfop)->open(inode, filp);
286
287                         /* sometimes file_operations will be changed in open */
288                         save_fops(filp, inode, sfops);
289                 }
290         }
291
292         lprocfs_counter_incr(ll_i2sbi(inode)->ll_stats, LPROC_LL_OPEN);
293
294         it = filp->f_it;
295
296         err = ll_local_open(filp, it);
297         if (rc != 0) {
298                 CERROR("error opening special file: rc %d", rc);
299                 ll_mdc_close(ll_i2sbi(inode)->ll_mdc_exp, inode, filp);
300         } else if (err) {
301                 if (pfop && *pfop && (*pfop)->release)
302                         (*pfop)->release(inode, filp);
303                 /* FIXME fops_put */
304                 rc = err;
305         }
306
307         req = it->d.lustre.it_data;
308         if (req)
309                 ptlrpc_req_finished(req);
310
311         RETURN(rc);
312 }
313
314 static int ll_special_release(struct inode *inode, struct file *filp)
315 {
316         return ll_special_release_internal(inode, filp, INODE_OPS);
317 }
318
319 static int ll_special_file_release(struct inode *inode, struct file *filp)
320 {
321         return ll_special_release_internal(inode, filp, FILE_OPS);
322 }
323
324 struct inode_operations ll_special_inode_operations = {
325         setattr_raw:    ll_setattr_raw,
326         setattr:        ll_setattr,
327 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
328         getattr_it:     ll_getattr,
329 #else
330         revalidate_it:  ll_inode_revalidate_it,
331 #endif
332 };
333
334 struct file_operations ll_special_chr_inode_fops = {
335         owner:          THIS_MODULE,
336         open:           ll_special_open,
337 };
338
339 struct file_operations ll_special_blk_inode_fops = {
340         owner:          THIS_MODULE,
341         read:           ll_special_read,
342         write:          ll_special_write,
343         ioctl:          ll_special_ioctl,
344         open:           ll_special_open,
345         release:        ll_special_release,
346         mmap:           ll_special_mmap,
347         llseek:         ll_special_seek,
348         fsync:          ll_special_fsync,
349 };
350
351 struct file_operations ll_special_fifo_inode_fops = {
352         owner:          THIS_MODULE,
353         open:           ll_special_open,
354 };
355
356 struct file_operations ll_special_sock_inode_fops = {
357         owner:          THIS_MODULE,
358         open:           ll_special_open
359 };
360
361 struct file_operations ll_special_chr_file_fops = {
362         owner:          THIS_MODULE,
363         llseek:         ll_special_file_seek,
364         read:           ll_special_file_read,
365         write:          ll_special_file_write,
366         poll:           ll_special_file_poll,
367         ioctl:          ll_special_file_ioctl,
368         open:           ll_special_file_open,
369         release:        ll_special_file_release,
370         fasync:         ll_special_file_fasync,
371 };
372
373 struct file_operations ll_special_fifo_file_fops = {
374         owner:          THIS_MODULE,
375         llseek:         ll_special_file_seek,
376         read:           ll_special_file_read,
377         write:          ll_special_file_write,
378         poll:           ll_special_file_poll,
379         ioctl:          ll_special_file_ioctl,
380         open:           ll_special_file_open,
381         release:        ll_special_file_release,
382 };