Whamcloud - gitweb
- landed b_hd_cray_merge3
[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                 CDEBUG(D_INFO,"saved %p, replaced with %p\n", *pfop,filp->f_op);
81                 if ((*pfop)->owner)
82                         CDEBUG(D_INFO,"%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) {
159                 fops_get(*pfop);
160
161                 if ((*pfop)->open)
162                         rc = (*pfop)->open(inode, filp);
163
164                 if (rc)
165                         fops_put(*pfop);
166         }
167
168         RETURN(rc);
169 }
170
171 static ssize_t ll_special_read(struct file *filp, char *buf, size_t count,
172                                loff_t *ppos)
173 {
174         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
175         int rc = -EINVAL;
176
177         if (pfop && *pfop && (*pfop)->read)
178                 rc = (*pfop)->read(filp, buf, count, ppos);
179
180         RETURN(rc);
181 }
182
183 static ssize_t ll_special_write(struct file *filp, const char *buf,
184                                 size_t count, loff_t *ppos)
185 {
186         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
187         int rc = -EINVAL;
188
189         if (pfop && *pfop && (*pfop)->write)
190                 rc = (*pfop)->write(filp, buf, count, ppos);
191
192         RETURN(rc);
193 }
194
195 static int ll_special_ioctl(struct inode *inode, struct file *filp,
196                             unsigned int cmd, unsigned long arg)
197 {
198         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
199         int rc = -ENOTTY;
200
201         if (pfop && *pfop && (*pfop)->ioctl) {
202                 struct file_operations *sfops = filp->f_op;
203                         
204                 rc = (*pfop)->ioctl(inode, filp, cmd, arg);
205
206                 /* sometimes, file_operations will be changed in ioctl */
207                 save_fops(filp, inode, sfops);
208         }
209
210         RETURN(rc);
211 }
212
213 static int ll_special_mmap(struct file * filp, struct vm_area_struct * vma)
214 {
215         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
216         int rc = -ENODEV;
217
218         if (pfop && *pfop && (*pfop)->mmap)
219                 rc = (*pfop)->mmap(filp, vma);
220
221         RETURN(rc);
222 }
223
224 static loff_t ll_special_seek(struct file *filp, loff_t offset, int origin)
225 {
226         struct file_operations** pfop = get_save_fops (filp, INODE_OPS);
227         int    rc = 0;
228
229         if (pfop && *pfop && (*pfop)->llseek)
230                 rc = (*pfop)->llseek(filp, offset, origin);
231         else
232                 rc = default_llseek(filp, offset, origin);
233
234         RETURN(rc);
235 }
236
237 static int ll_special_fsync(struct file *filp, struct dentry *dentry, int data)
238 {
239         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
240         int rc = -EINVAL;
241
242         if (pfop && *pfop && (*pfop)->fsync)
243                 rc = (*pfop)->fsync(filp, dentry, data);
244
245         RETURN(rc);
246 }
247
248 static int ll_special_file_fasync(int fd, struct file *filp, int on)
249 {
250         struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
251         int rc = -EINVAL;
252
253         if (pfop && *pfop && (*pfop)->fasync)
254                 rc = (*pfop)->fasync(fd, filp, on);
255
256         RETURN(rc);
257 }
258
259 static int ll_special_release_internal(struct inode *inode, struct file *filp,
260                                        int mode)
261 {
262        struct file_operations **pfop = get_save_fops(filp, mode);
263        struct ll_sb_info *sbi = ll_i2sbi(inode);
264        int rc = 0, err;
265        ENTRY;
266
267         if (pfop && *pfop) {
268                 if ((*pfop)->release)
269                         rc = (*pfop)->release(inode, filp);
270                 fops_put(*pfop);
271         }
272
273         lprocfs_counter_incr(sbi->ll_stats, LPROC_LL_RELEASE);
274         err = ll_md_close(sbi->ll_md_exp, inode, filp);
275
276         if (err && rc == 0)
277                 rc = err;
278
279         RETURN(rc);
280 }
281
282 static int ll_special_open(struct inode *inode, struct file *filp)
283 {
284         struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
285         struct file_operations *sfops = filp->f_op;
286         struct ll_inode_info *lli = ll_i2info(inode);
287         struct ptlrpc_request *req;
288         struct lookup_intent *it;
289         int rc = -EINVAL, err;
290         struct obd_client_handle **och_p;
291         __u64 *och_usecount;
292         ENTRY;
293
294         it = filp->f_it;
295
296         if (LUSTRE_IT(it)->it_disposition) {
297                 err = it_open_error(DISP_OPEN_OPEN, it);
298                 if (err)
299                         RETURN(err);
300         }
301
302         if (pfop && *pfop) {
303                 /* mostly we will have @def_blk_fops here and it is not in a
304                  * module but we do this just to be sure. */
305                 fops_get(*pfop);
306
307                 if ((*pfop)->open) {
308                         rc = (*pfop)->open(inode, filp);
309
310                         if (rc)
311                                 fops_put(*pfop);
312                         else    /* sometimes ops will be changed in open */
313                                 save_fops(filp, inode, sfops);
314                 }
315         }
316
317         /* Let's see if we have file open on MDS already. */
318         if (it->it_flags & FMODE_WRITE) {
319                 och_p = &lli->lli_mds_write_och;
320                 och_usecount = &lli->lli_open_fd_write_count;
321         } else if (it->it_flags & FMODE_EXEC) {
322                 och_p = &lli->lli_mds_exec_och;
323                 och_usecount = &lli->lli_open_fd_exec_count;
324          } else {
325                 och_p = &lli->lli_mds_read_och;
326                 och_usecount = &lli->lli_open_fd_read_count;
327         }
328
329         lprocfs_counter_incr(ll_i2sbi(inode)->ll_stats, LPROC_LL_OPEN);
330
331         down(&lli->lli_och_sem);
332         if (*och_p) { /* Open handle is present */
333                 if (LUSTRE_IT(it)->it_disposition) {
334                         struct obd_client_handle *och;
335                         /* Well, there's extra open request that we do not need,
336                            let's close it somehow*/
337                         OBD_ALLOC(och, sizeof (struct obd_client_handle));
338                         if (!och) {
339                                 /* XXX We leak open fd and open OPEN connectioni
340                                    to server here */
341                                 up(&lli->lli_och_sem);
342                                 RETURN(-ENOMEM);
343                         }
344                         ll_och_fill(inode, it, och);
345                         /* ll_md_och_close() will free och */
346                         ll_md_och_close(ll_i2mdexp(inode), inode, och);
347                 }       
348                 (*och_usecount)++;        
349
350                 err = ll_local_open(filp, it, NULL);
351         } else {
352                 LASSERT(*och_usecount == 0);
353                 OBD_ALLOC(*och_p, sizeof (struct obd_client_handle));
354                 if (!*och_p) {
355                         // XXX Same as above
356                         up(&lli->lli_och_sem);
357                         RETURN(-ENOMEM);
358                 }
359                 (*och_usecount)++;
360
361                 err = ll_local_open(filp, it, *och_p);
362         }
363         up(&lli->lli_och_sem);
364
365         if (rc != 0) {
366                 CERROR("error opening special file: rc %d\n", rc);
367                 ll_md_close(ll_i2sbi(inode)->ll_md_exp, inode, filp);
368         } else if (err) {
369                 if (pfop && *pfop) {
370                         if ((*pfop)->release)
371                                 (*pfop)->release(inode, filp);
372                         fops_put(*pfop);
373                 }
374                 rc = err;
375         }
376
377         req = LUSTRE_IT(it)->it_data;
378         if (req)
379                 ptlrpc_req_finished(req);
380
381         RETURN(rc);
382 }
383
384 static int ll_special_release(struct inode *inode, struct file *filp)
385 {
386         return ll_special_release_internal(inode, filp, INODE_OPS);
387 }
388
389 static int ll_special_file_release(struct inode *inode, struct file *filp)
390 {
391         return ll_special_release_internal(inode, filp, FILE_OPS);
392 }
393
394 struct inode_operations ll_special_inode_operations = {
395         .setattr        = ll_setattr,
396 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
397         .getattr        = ll_getattr,
398 #else
399         .revalidate_it  = ll_inode_revalidate_it,
400 #endif
401         .setxattr       = ll_setxattr,
402         .getxattr       = ll_getxattr,
403         .listxattr      = ll_listxattr,
404         .removexattr    = ll_removexattr,
405         .permission     = ll_inode_permission,
406         
407 };
408
409 struct file_operations ll_special_chr_inode_fops = {
410         //FIXME .owner          = THIS_MODULE,
411         .open           = ll_special_open,
412 };
413
414 struct file_operations ll_special_blk_inode_fops = {
415         //FIXME .owner          = THIS_MODULE,
416         .read           = ll_special_read,
417         .write          = ll_special_write,
418         .ioctl          = ll_special_ioctl,
419         .open           = ll_special_open,
420         .release        = ll_special_release,
421         .mmap           = ll_special_mmap,
422         .llseek         = ll_special_seek,
423         .fsync          = ll_special_fsync,
424 };
425
426 struct file_operations ll_special_fifo_inode_fops = {
427         //FIXME .owner          = THIS_MODULE,
428         .open           = ll_special_open,
429 };
430
431 struct file_operations ll_special_sock_inode_fops = {
432         //FIXME .owner          = THIS_MODULE,
433         .open           = ll_special_open
434 };
435
436 struct file_operations ll_special_chr_file_fops = {
437         //FIXME .owner          = THIS_MODULE,
438         .llseek         = ll_special_file_seek,
439         .read           = ll_special_file_read,
440         .write          = ll_special_file_write,
441         .poll           = ll_special_file_poll,
442         .ioctl          = ll_special_file_ioctl,
443         .open           = ll_special_file_open,
444         .release        = ll_special_file_release,
445         .fasync         = ll_special_file_fasync,
446 };
447
448 struct file_operations ll_special_fifo_file_fops = {
449         //FIXME .owner          = THIS_MODULE,
450         .llseek         = ll_special_file_seek,
451         .read           = ll_special_file_read,
452         .write          = ll_special_file_write,
453         .poll           = ll_special_file_poll,
454         .ioctl          = ll_special_file_ioctl,
455         .open           = ll_special_file_open,
456         .release        = ll_special_file_release,
457 };
458