1 /*-
2 * Copyright (c) 2010 Isilon Systems, Inc.
3 * Copyright (c) 2010 iX Systems, Inc.
4 * Copyright (c) 2010 Panasas, Inc.
5 * Copyright (c) 2013 Mellanox Technologies, Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice unmodified, this list of conditions, and the following
13 * disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #ifndef _LINUX_FILE_H_
30 #define _LINUX_FILE_H_
31
32 #include <sys/param.h>
33 #include <sys/file.h>
34 #include <sys/filedesc.h>
35 #include <sys/refcount.h>
36 #include <sys/proc.h>
37
38 #include <linux/fs.h>
39
40 struct linux_file;
41
42 #undef file
43
44 extern struct fileops linuxfileops;
45
46 static inline struct linux_file *
linux_fget(unsigned int fd)47 linux_fget(unsigned int fd)
48 {
49 struct file *file;
50
51 file = fget_unlocked(curthread->td_proc->p_fd, fd);
52 return (struct linux_file *)file->f_data;
53 }
54
55 static inline void
fput(struct linux_file * filp)56 fput(struct linux_file *filp)
57 {
58 if (filp->_file == NULL) {
59 kfree(filp);
60 return;
61 }
62 if (refcount_release(&filp->_file->f_count)) {
63 _fdrop(filp->_file, curthread);
64 kfree(filp);
65 }
66 }
67
68 static inline void
put_unused_fd(unsigned int fd)69 put_unused_fd(unsigned int fd)
70 {
71 struct file *file;
72
73 file = fget_unlocked(curthread->td_proc->p_fd, fd);
74 if (file == NULL)
75 return;
76 /*
77 * NOTE: We should only get here when the "fd" has not been
78 * installed, so no need to free the associated Linux file
79 * structure.
80 */
81 fdclose(curthread->td_proc->p_fd, file, fd, curthread);
82
83 /* drop extra reference */
84 fdrop(file, curthread);
85 }
86
87 static inline void
fd_install(unsigned int fd,struct linux_file * filp)88 fd_install(unsigned int fd, struct linux_file *filp)
89 {
90 struct file *file;
91
92 file = fget_unlocked(curthread->td_proc->p_fd, fd);
93 if (file == NULL) {
94 filp->_file = NULL;
95 } else {
96 filp->_file = file;
97 finit(file, filp->f_mode, DTYPE_DEV, filp, &linuxfileops);
98 }
99
100 /* drop the extra reference */
101 fput(filp);
102 }
103
104 static inline int
get_unused_fd(void)105 get_unused_fd(void)
106 {
107 struct file *file;
108 int error;
109 int fd;
110
111 error = falloc(curthread, &file, &fd, 0);
112 if (error)
113 return -error;
114 /* drop the extra reference */
115 fdrop(file, curthread);
116 return fd;
117 }
118
119 static inline struct linux_file *
alloc_file(int mode,const struct file_operations * fops)120 alloc_file(int mode, const struct file_operations *fops)
121 {
122 struct linux_file *filp;
123
124 filp = kzalloc(sizeof(*filp), GFP_KERNEL);
125 if (filp == NULL)
126 return (NULL);
127 filp->f_op = fops;
128 filp->f_mode = mode;
129
130 return filp;
131 }
132
133 struct fd {
134 struct linux_file *linux_file;
135 };
136
fdput(struct fd fd)137 static inline void fdput(struct fd fd)
138 {
139 fput(fd.linux_file);
140 }
141
fdget(unsigned int fd)142 static inline struct fd fdget(unsigned int fd)
143 {
144 struct linux_file *f = linux_fget(fd);
145 return (struct fd){f};
146 }
147
148 #define file linux_file
149 #define fget linux_fget
150
151 #endif /* _LINUX_FILE_H_ */
152