]> git.proxmox.com Git - mirror_spl.git/blob - modules/spl/spl-file.c
Initial pass at a file API getf/releasef hooks
[mirror_spl.git] / modules / spl / spl-file.c
1 #include <sys/sysmacros.h>
2 #include <sys/file.h>
3 #include "config.h"
4
5 /* File interface */
6
7 static spinlock_t file_lock = SPIN_LOCK_UNLOCKED;
8 static LIST_HEAD(file_list);
9 static kmem_cache_t *file_cache;
10
11 /* Function must be called while holding the file_lock */
12 static file_t *
13 file_find(int fd)
14 {
15 file_t *fp;
16
17 BUG_ON(!spin_is_locked(&file_lock));
18
19 list_for_each_entry(fp, &file_list, f_list) {
20 if (fd == fp->f_fd) {
21 BUG_ON(atomic_read(&fp->f_ref) == 0);
22 return fp;
23 }
24 }
25
26 return NULL;
27 } /* file_find() */
28
29 file_t *
30 getf(int fd)
31 {
32 file_t *fp;
33
34 /* Already open just take an extra reference */
35 spin_lock(&file_lock);
36
37 fp = file_find(fd);
38 if (fp) {
39 atomic_inc(&fp->f_ref);
40 spin_unlock(&file_lock);
41 return fp;
42 }
43
44 spin_unlock(&file_lock);
45
46 /* File was not yet opened via the SPL layer create needed bits */
47 fp = kmem_cache_alloc(file_cache, 0);
48 if (fp == NULL)
49 goto out;
50
51 mutex_enter(&fp->f_lock);
52
53 fp->f_vnode = vn_alloc(KM_SLEEP);
54 if (fp->f_vnode == NULL)
55 goto out_mutex;
56
57 /* XXX: Setup needed vnode stop, open file etc */
58
59 fp->f_file = fget(fd);
60 if (fp->f_file == NULL)
61 goto out_vnode;
62
63 fp->f_fd = fd;
64 atomic_inc(&fp->f_ref);
65
66 spin_lock(&file_lock);
67 list_add(&fp->f_list, &file_list);
68 spin_unlock(&file_lock);
69
70 mutex_exit(&fp->f_lock);
71 return fp;
72
73 out_vnode:
74 vn_free(fp->f_vnode);
75 out_mutex:
76 mutex_exit(&fp->f_lock);
77 kmem_cache_free(file_cache, fp);
78 out:
79 return NULL;
80 } /* getf() */
81 EXPORT_SYMBOL(getf);
82
83 static void releasef_locked(file_t *fp)
84 {
85 BUG_ON(fp->f_file == NULL);
86 BUG_ON(fp->f_vnode == NULL);
87
88 /* Unlinked from list, no refs, safe to free outside mutex */
89 fput(fp->f_file);
90 vn_free(fp->f_vnode);
91
92 kmem_cache_free(file_cache, fp);
93 }
94
95 void
96 releasef(int fd)
97 {
98 file_t *fp;
99
100 spin_lock(&file_lock);
101
102 fp = file_find(fd);
103 if (fp) {
104 atomic_dec(&fp->f_ref);
105
106 if (atomic_read(&fp->f_ref) > 0) {
107 spin_unlock(&file_lock);
108 return;
109 }
110
111 list_del(&fp->f_list);
112 spin_unlock(&file_lock);
113 releasef_locked(fp);
114 }
115
116 return;
117 } /* releasef() */
118 EXPORT_SYMBOL(releasef);
119
120 static int
121 file_cache_constructor(void *buf, void *cdrarg, int kmflags)
122 {
123 file_t *fp = buf;
124
125 atomic_set(&fp->f_ref, 0);
126 mutex_init(&fp->f_lock, NULL, MUTEX_DEFAULT, NULL);
127
128 return (0);
129 } /* file_cache_constructor() */
130
131 static void
132 file_cache_destructor(void *buf, void *cdrarg)
133 {
134 file_t *fp = buf;
135
136 mutex_destroy(&fp->f_lock);
137 } /* file_cache_destructor() */
138
139 int
140 file_init(void)
141 {
142 file_cache = kmem_cache_create("spl_file_cache", sizeof(file_t), 64,
143 file_cache_constructor,
144 file_cache_destructor,
145 NULL, NULL, NULL, 0);
146 return 0;
147 } /* file_init() */
148
149 void file_fini(void)
150 {
151 file_t *fp, *next_fp;
152 int leaked = 0;
153
154 spin_lock(&file_lock);
155
156 list_for_each_entry_safe(fp, next_fp, &file_list, f_list) {
157 list_del(&fp->f_list);
158 releasef_locked(fp);
159 leaked++;
160 }
161
162 kmem_cache_destroy(file_cache);
163 file_cache = NULL;
164 spin_unlock(&file_lock);
165
166 if (leaked > 0)
167 printk("Warning: %d files leaked\n", leaked);
168
169 } /* file_fini() */