Whamcloud - gitweb
e209697baf564a68f365a1d7a373958129ddc98d
[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                 return NULL;
65         }
66 }
67
68 static void save_fops(struct file *filp, struct inode *inode,
69                       struct file_operations *sfops)
70 {
71         if (sfops != filp->f_op) {
72                 struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
73
74                 *pfop = filp->f_op;
75                 if (S_ISCHR(inode->i_mode))
76                         filp->f_op = &ll_special_chr_file_fops;
77                 else if (S_ISFIFO(inode->i_mode))
78                         filp->f_op = &ll_special_fifo_file_fops;
79
80                 CWARN("saved %p, replaced with %p\n", *pfop, filp->f_op);
81                 if ((*pfop)->owner)
82                         CWARN("%p has owner %p\n", *pfop,(*pfop)->owner);
83         }
84 }
85
86 static ssize_t ll_special_file_read(struct file *filp, char *buf,
87                                     size_t count, loff_t *ppos)
88 {
89         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
90         int rc = -EINVAL;
91
92         if (pfop && *pfop && (*pfop)->read)
93                 rc = (*pfop)->read(filp, buf, count, ppos);
94
95         RETURN(rc);
96 }
97
98 static ssize_t ll_special_file_write(struct file *filp, const char *buf,
99                                      size_t count, loff_t *ppos)
100 {
101         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
102         int rc = -EINVAL;
103
104         if (pfop && *pfop && (*pfop)->write)
105                 rc = (*pfop)->write(filp, buf, count, ppos);
106
107         RETURN(rc);
108 }
109
110 static int ll_special_file_ioctl(struct inode *inode, struct file *filp,
111                                  unsigned int cmd, unsigned long arg)
112 {
113         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
114         int rc = -ENOTTY;
115
116         if (pfop && *pfop && (*pfop)->ioctl) {
117                 struct file_operations *sfops = filp->f_op;
118
119                 rc = (*pfop)->ioctl(inode, filp, cmd, arg);
120                 save_fops(filp, inode, sfops);
121         }
122         RETURN(rc);
123 }
124
125 static loff_t ll_special_file_seek(struct file *filp, loff_t offset, int origin)
126 {
127         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
128         int rc = 0;
129
130         if (pfop && *pfop && (*pfop)->llseek)
131                 rc = (*pfop)->llseek(filp, offset, origin);
132         else
133                 rc = default_llseek(filp, offset, origin);
134
135         RETURN(rc);
136 }
137
138
139 #define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
140
141 static unsigned int ll_special_file_poll(struct file *filp,
142                                          struct poll_table_struct *poll_table)
143 {
144         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
145         int rc = DEFAULT_POLLMASK;
146
147         if (pfop && *pfop && (*pfop)->poll)
148                 rc = (*pfop)->poll(filp, poll_table);
149
150         RETURN(rc);
151 }
152
153 static int ll_special_file_open(struct inode *inode, struct file *filp)
154 {
155         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
156         int rc = -EINVAL;
157
158         if (pfop && *pfop && (*pfop)->open)
159                 rc = (*pfop)->open(inode, filp);
160
161         RETURN(rc);
162 }
163
164 static ssize_t ll_special_read(struct file *filp, char *buf, size_t count,
165                                loff_t *ppos)
166 {
167         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
168         int rc = -EINVAL;
169
170         if (pfop && *pfop && (*pfop)->read)
171                 rc = (*pfop)->read(filp, buf, count, ppos);
172
173         RETURN(rc);
174 }
175
176 static ssize_t ll_special_write(struct file *filp, const char *buf,
177                                 size_t count, loff_t *ppos)
178 {
179         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
180         int rc = -EINVAL;
181
182         if (pfop && *pfop && (*pfop)->write)
183                 rc = (*pfop)->write(filp, buf, count, ppos);
184
185         RETURN(rc);
186 }
187
188 static int ll_special_ioctl(struct inode *inode, struct file *filp,
189                             unsigned int cmd, unsigned long arg)
190 {
191         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
192         int rc = -ENOTTY;
193
194         if (pfop && *pfop && (*pfop)->ioctl) {
195                 struct file_operations *sfops = filp->f_op;
196                         
197                 rc = (*pfop)->ioctl(inode, filp, cmd, arg);
198                 /* sometimes, file_operations will be changed in ioctl */
199                 save_fops(filp, inode, sfops);
200         }
201
202         RETURN(rc);
203 }
204
205 static int ll_special_mmap(struct file * filp, struct vm_area_struct * vma)
206 {
207         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
208         int rc = -ENODEV;
209
210         if (pfop && *pfop && (*pfop)->mmap)
211                 rc = (*pfop)->mmap(filp, vma);
212
213         RETURN(rc);
214 }
215
216 static loff_t ll_special_seek(struct file *filp, loff_t offset, int origin)
217 {
218         struct file_operations** pfop = get_save_fops (filp, INODE_OPS);
219         int    rc = 0;
220
221         if (pfop && *pfop && (*pfop)->llseek)
222                 rc = (*pfop)->llseek(filp, offset, origin);
223         else
224                 rc = default_llseek(filp, offset, origin);
225
226         RETURN(rc);
227 }
228
229 static int ll_special_fsync(struct file *filp, struct dentry *dentry, int data)
230 {
231         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
232         int rc = -EINVAL;
233
234         if (pfop && *pfop && (*pfop)->fsync)
235                 rc = (*pfop)->fsync(filp, dentry, data);
236
237         RETURN(rc);
238 }
239
240 static int ll_special_file_fasync(int fd, struct file *filp, int on)
241 {
242         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
243         int rc = -EINVAL;
244
245         if (pfop && *pfop && (*pfop)->fasync)
246                 rc = (*pfop)->fasync(fd, filp, on);
247
248         RETURN(rc);
249 }
250
251 static int ll_special_release_internal(struct inode *inode, struct file *filp,
252                                        int mode)
253 {
254        struct file_operations **pfop = get_save_fops(filp, mode);
255        struct ll_sb_info *sbi = ll_i2sbi(inode);
256        int rc = 0, err;
257        ENTRY;
258
259         if (pfop && *pfop) {
260                 if ((*pfop)->release)
261                         rc = (*pfop)->release(inode, filp);
262                 /* FIXME fops_put */
263         }
264
265         lprocfs_counter_incr(sbi->ll_stats, LPROC_LL_RELEASE);
266
267         err = ll_mdc_close(sbi->ll_mdc_exp, inode, filp);
268         if (err && rc == 0)
269                 rc = err;
270
271         RETURN(rc);
272 }
273
274 static int ll_special_open(struct inode *inode, struct file *filp)
275 {
276         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
277         struct file_operations *sfops = filp->f_op;
278         struct ptlrpc_request *req;
279         struct lookup_intent *it;
280         int rc = -EINVAL, err;
281         ENTRY;
282
283         if (pfop && *pfop) {
284                 /* FIXME fops_get */
285                 if ((*pfop)->open) {
286                         rc = (*pfop)->open(inode, filp);
287
288                         /* sometimes file_operations will be changed in open */
289                         save_fops(filp, inode, sfops);
290                 }
291         }
292
293         lprocfs_counter_incr(ll_i2sbi(inode)->ll_stats, LPROC_LL_OPEN);
294
295         it = filp->f_it;
296
297         err = ll_local_open(filp, it);
298         if (rc != 0) {
299                 CERROR("error opening special file: rc %d", rc);
300                 ll_mdc_close(ll_i2sbi(inode)->ll_mdc_exp, inode, filp);
301         } else if (err) {
302                 if (pfop && *pfop && (*pfop)->release)
303                         (*pfop)->release(inode, filp);
304                 /* FIXME fops_put */
305                 rc = err;
306         }
307
308         req = it->d.lustre.it_data;
309         if (req)
310                 ptlrpc_req_finished(req);
311
312         RETURN(rc);
313 }
314
315 static int ll_special_release(struct inode *inode, struct file *filp)
316 {
317         return ll_special_release_internal(inode, filp, INODE_OPS);
318 }
319
320 static int ll_special_file_release(struct inode *inode, struct file *filp)
321 {
322         return ll_special_release_internal(inode, filp, FILE_OPS);
323 }
324
325 struct inode_operations ll_special_inode_operations = {
326         setattr_raw:    ll_setattr_raw,
327         setattr:        ll_setattr,
328 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
329         getattr_it:     ll_getattr,
330 #else
331         revalidate_it:  ll_inode_revalidate_it,
332 #endif
333 };
334
335 struct file_operations ll_special_chr_inode_fops = {
336         owner:          THIS_MODULE,
337         open:           ll_special_open,
338 };
339
340 struct file_operations ll_special_blk_inode_fops = {
341         owner:          THIS_MODULE,
342         read:           ll_special_read,
343         write:          ll_special_write,
344         ioctl:          ll_special_ioctl,
345         open:           ll_special_open,
346         release:        ll_special_release,
347         mmap:           ll_special_mmap,
348         llseek:         ll_special_seek,
349         fsync:          ll_special_fsync,
350 };
351
352 struct file_operations ll_special_fifo_inode_fops = {
353         owner:          THIS_MODULE,
354         open:           ll_special_open,
355 };
356
357 struct file_operations ll_special_sock_inode_fops = {
358         owner:          THIS_MODULE,
359         open:           ll_special_open
360 };
361
362 struct file_operations ll_special_chr_file_fops = {
363         owner:          THIS_MODULE,
364         llseek:         ll_special_file_seek,
365         read:           ll_special_file_read,
366         write:          ll_special_file_write,
367         poll:           ll_special_file_poll,
368         ioctl:          ll_special_file_ioctl,
369         open:           ll_special_file_open,
370         release:        ll_special_file_release,
371         fasync:         ll_special_file_fasync,
372 };
373
374 struct file_operations ll_special_fifo_file_fops = {
375         owner:          THIS_MODULE,
376         llseek:         ll_special_file_seek,
377         read:           ll_special_file_read,
378         write:          ll_special_file_write,
379         poll:           ll_special_file_poll,
380         ioctl:          ll_special_file_ioctl,
381         open:           ll_special_file_open,
382         release:        ll_special_file_release,
383 };