diff options
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r-- | fs/fuse/dev.c | 88 |
1 files changed, 84 insertions, 4 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index fe3adf589174..ae26f37e53a1 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -76,6 +76,13 @@ static void __fuse_put_request(struct fuse_req *req) | |||
76 | atomic_dec(&req->count); | 76 | atomic_dec(&req->count); |
77 | } | 77 | } |
78 | 78 | ||
79 | static void fuse_req_init_context(struct fuse_req *req) | ||
80 | { | ||
81 | req->in.h.uid = current->fsuid; | ||
82 | req->in.h.gid = current->fsgid; | ||
83 | req->in.h.pid = current->pid; | ||
84 | } | ||
85 | |||
79 | struct fuse_req *fuse_get_req(struct fuse_conn *fc) | 86 | struct fuse_req *fuse_get_req(struct fuse_conn *fc) |
80 | { | 87 | { |
81 | struct fuse_req *req; | 88 | struct fuse_req *req; |
@@ -100,9 +107,7 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc) | |||
100 | if (!req) | 107 | if (!req) |
101 | goto out; | 108 | goto out; |
102 | 109 | ||
103 | req->in.h.uid = current->fsuid; | 110 | fuse_req_init_context(req); |
104 | req->in.h.gid = current->fsgid; | ||
105 | req->in.h.pid = current->pid; | ||
106 | req->waiting = 1; | 111 | req->waiting = 1; |
107 | return req; | 112 | return req; |
108 | 113 | ||
@@ -111,12 +116,87 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc) | |||
111 | return ERR_PTR(err); | 116 | return ERR_PTR(err); |
112 | } | 117 | } |
113 | 118 | ||
119 | /* | ||
120 | * Return request in fuse_file->reserved_req. However that may | ||
121 | * currently be in use. If that is the case, wait for it to become | ||
122 | * available. | ||
123 | */ | ||
124 | static struct fuse_req *get_reserved_req(struct fuse_conn *fc, | ||
125 | struct file *file) | ||
126 | { | ||
127 | struct fuse_req *req = NULL; | ||
128 | struct fuse_file *ff = file->private_data; | ||
129 | |||
130 | do { | ||
131 | wait_event(fc->blocked_waitq, ff->reserved_req); | ||
132 | spin_lock(&fc->lock); | ||
133 | if (ff->reserved_req) { | ||
134 | req = ff->reserved_req; | ||
135 | ff->reserved_req = NULL; | ||
136 | get_file(file); | ||
137 | req->stolen_file = file; | ||
138 | } | ||
139 | spin_unlock(&fc->lock); | ||
140 | } while (!req); | ||
141 | |||
142 | return req; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Put stolen request back into fuse_file->reserved_req | ||
147 | */ | ||
148 | static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req) | ||
149 | { | ||
150 | struct file *file = req->stolen_file; | ||
151 | struct fuse_file *ff = file->private_data; | ||
152 | |||
153 | spin_lock(&fc->lock); | ||
154 | fuse_request_init(req); | ||
155 | BUG_ON(ff->reserved_req); | ||
156 | ff->reserved_req = req; | ||
157 | wake_up(&fc->blocked_waitq); | ||
158 | spin_unlock(&fc->lock); | ||
159 | fput(file); | ||
160 | } | ||
161 | |||
162 | /* | ||
163 | * Gets a requests for a file operation, always succeeds | ||
164 | * | ||
165 | * This is used for sending the FLUSH request, which must get to | ||
166 | * userspace, due to POSIX locks which may need to be unlocked. | ||
167 | * | ||
168 | * If allocation fails due to OOM, use the reserved request in | ||
169 | * fuse_file. | ||
170 | * | ||
171 | * This is very unlikely to deadlock accidentally, since the | ||
172 | * filesystem should not have it's own file open. If deadlock is | ||
173 | * intentional, it can still be broken by "aborting" the filesystem. | ||
174 | */ | ||
175 | struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file) | ||
176 | { | ||
177 | struct fuse_req *req; | ||
178 | |||
179 | atomic_inc(&fc->num_waiting); | ||
180 | wait_event(fc->blocked_waitq, !fc->blocked); | ||
181 | req = fuse_request_alloc(); | ||
182 | if (!req) | ||
183 | req = get_reserved_req(fc, file); | ||
184 | |||
185 | fuse_req_init_context(req); | ||
186 | req->waiting = 1; | ||
187 | return req; | ||
188 | } | ||
189 | |||
114 | void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) | 190 | void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) |
115 | { | 191 | { |
116 | if (atomic_dec_and_test(&req->count)) { | 192 | if (atomic_dec_and_test(&req->count)) { |
117 | if (req->waiting) | 193 | if (req->waiting) |
118 | atomic_dec(&fc->num_waiting); | 194 | atomic_dec(&fc->num_waiting); |
119 | fuse_request_free(req); | 195 | |
196 | if (req->stolen_file) | ||
197 | put_reserved_req(fc, req); | ||
198 | else | ||
199 | fuse_request_free(req); | ||
120 | } | 200 | } |
121 | } | 201 | } |
122 | 202 | ||