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