diff options
Diffstat (limited to 'fs/autofs4/waitq.c')
-rw-r--r-- | fs/autofs4/waitq.c | 86 |
1 files changed, 45 insertions, 41 deletions
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 75e5955c3f6d..5208cfb1df4e 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -36,8 +36,10 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi) | |||
36 | while (wq) { | 36 | while (wq) { |
37 | nwq = wq->next; | 37 | nwq = wq->next; |
38 | wq->status = -ENOENT; /* Magic is gone - report failure */ | 38 | wq->status = -ENOENT; /* Magic is gone - report failure */ |
39 | kfree(wq->name); | 39 | if (wq->name.name) { |
40 | wq->name = NULL; | 40 | kfree(wq->name.name); |
41 | wq->name.name = NULL; | ||
42 | } | ||
41 | wake_up_interruptible(&wq->queue); | 43 | wake_up_interruptible(&wq->queue); |
42 | wq = nwq; | 44 | wq = nwq; |
43 | } | 45 | } |
@@ -92,7 +94,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, | |||
92 | size_t pktsz; | 94 | size_t pktsz; |
93 | 95 | ||
94 | DPRINTK("wait id = 0x%08lx, name = %.*s, type=%d", | 96 | DPRINTK("wait id = 0x%08lx, name = %.*s, type=%d", |
95 | wq->wait_queue_token, wq->len, wq->name, type); | 97 | wq->wait_queue_token, wq->name.len, wq->name.name, type); |
96 | 98 | ||
97 | memset(&pkt,0,sizeof pkt); /* For security reasons */ | 99 | memset(&pkt,0,sizeof pkt); /* For security reasons */ |
98 | 100 | ||
@@ -107,9 +109,9 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, | |||
107 | pktsz = sizeof(*mp); | 109 | pktsz = sizeof(*mp); |
108 | 110 | ||
109 | mp->wait_queue_token = wq->wait_queue_token; | 111 | mp->wait_queue_token = wq->wait_queue_token; |
110 | mp->len = wq->len; | 112 | mp->len = wq->name.len; |
111 | memcpy(mp->name, wq->name, wq->len); | 113 | memcpy(mp->name, wq->name.name, wq->name.len); |
112 | mp->name[wq->len] = '\0'; | 114 | mp->name[wq->name.len] = '\0'; |
113 | break; | 115 | break; |
114 | } | 116 | } |
115 | case autofs_ptype_expire_multi: | 117 | case autofs_ptype_expire_multi: |
@@ -119,9 +121,9 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, | |||
119 | pktsz = sizeof(*ep); | 121 | pktsz = sizeof(*ep); |
120 | 122 | ||
121 | ep->wait_queue_token = wq->wait_queue_token; | 123 | ep->wait_queue_token = wq->wait_queue_token; |
122 | ep->len = wq->len; | 124 | ep->len = wq->name.len; |
123 | memcpy(ep->name, wq->name, wq->len); | 125 | memcpy(ep->name, wq->name.name, wq->name.len); |
124 | ep->name[wq->len] = '\0'; | 126 | ep->name[wq->name.len] = '\0'; |
125 | break; | 127 | break; |
126 | } | 128 | } |
127 | /* | 129 | /* |
@@ -138,9 +140,9 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, | |||
138 | pktsz = sizeof(*packet); | 140 | pktsz = sizeof(*packet); |
139 | 141 | ||
140 | packet->wait_queue_token = wq->wait_queue_token; | 142 | packet->wait_queue_token = wq->wait_queue_token; |
141 | packet->len = wq->len; | 143 | packet->len = wq->name.len; |
142 | memcpy(packet->name, wq->name, wq->len); | 144 | memcpy(packet->name, wq->name.name, wq->name.len); |
143 | packet->name[wq->len] = '\0'; | 145 | packet->name[wq->name.len] = '\0'; |
144 | packet->dev = wq->dev; | 146 | packet->dev = wq->dev; |
145 | packet->ino = wq->ino; | 147 | packet->ino = wq->ino; |
146 | packet->uid = wq->uid; | 148 | packet->uid = wq->uid; |
@@ -191,15 +193,15 @@ static int autofs4_getpath(struct autofs_sb_info *sbi, | |||
191 | } | 193 | } |
192 | 194 | ||
193 | static struct autofs_wait_queue * | 195 | static struct autofs_wait_queue * |
194 | autofs4_find_wait(struct autofs_sb_info *sbi, | 196 | autofs4_find_wait(struct autofs_sb_info *sbi, struct qstr *qstr) |
195 | char *name, unsigned int hash, unsigned int len) | ||
196 | { | 197 | { |
197 | struct autofs_wait_queue *wq; | 198 | struct autofs_wait_queue *wq; |
198 | 199 | ||
199 | for (wq = sbi->queues; wq; wq = wq->next) { | 200 | for (wq = sbi->queues; wq; wq = wq->next) { |
200 | if (wq->hash == hash && | 201 | if (wq->name.hash == qstr->hash && |
201 | wq->len == len && | 202 | wq->name.len == qstr->len && |
202 | wq->name && !memcmp(wq->name, name, len)) | 203 | wq->name.name && |
204 | !memcmp(wq->name.name, qstr->name, qstr->len)) | ||
203 | break; | 205 | break; |
204 | } | 206 | } |
205 | return wq; | 207 | return wq; |
@@ -210,9 +212,8 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
210 | { | 212 | { |
211 | struct autofs_info *ino; | 213 | struct autofs_info *ino; |
212 | struct autofs_wait_queue *wq; | 214 | struct autofs_wait_queue *wq; |
215 | struct qstr qstr; | ||
213 | char *name; | 216 | char *name; |
214 | unsigned int len = 0; | ||
215 | unsigned int hash = 0; | ||
216 | int status, type; | 217 | int status, type; |
217 | 218 | ||
218 | /* In catatonic mode, we don't wait for nobody */ | 219 | /* In catatonic mode, we don't wait for nobody */ |
@@ -225,22 +226,23 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
225 | 226 | ||
226 | /* If this is a direct mount request create a dummy name */ | 227 | /* If this is a direct mount request create a dummy name */ |
227 | if (IS_ROOT(dentry) && (sbi->type & AUTOFS_TYPE_DIRECT)) | 228 | if (IS_ROOT(dentry) && (sbi->type & AUTOFS_TYPE_DIRECT)) |
228 | len = sprintf(name, "%p", dentry); | 229 | qstr.len = sprintf(name, "%p", dentry); |
229 | else { | 230 | else { |
230 | len = autofs4_getpath(sbi, dentry, &name); | 231 | qstr.len = autofs4_getpath(sbi, dentry, &name); |
231 | if (!len) { | 232 | if (!qstr.len) { |
232 | kfree(name); | 233 | kfree(name); |
233 | return -ENOENT; | 234 | return -ENOENT; |
234 | } | 235 | } |
235 | } | 236 | } |
236 | hash = full_name_hash(name, len); | 237 | qstr.name = name; |
238 | qstr.hash = full_name_hash(name, qstr.len); | ||
237 | 239 | ||
238 | if (mutex_lock_interruptible(&sbi->wq_mutex)) { | 240 | if (mutex_lock_interruptible(&sbi->wq_mutex)) { |
239 | kfree(name); | 241 | kfree(qstr.name); |
240 | return -EINTR; | 242 | return -EINTR; |
241 | } | 243 | } |
242 | 244 | ||
243 | wq = autofs4_find_wait(sbi, name, hash, len); | 245 | wq = autofs4_find_wait(sbi, &qstr); |
244 | ino = autofs4_dentry_ino(dentry); | 246 | ino = autofs4_dentry_ino(dentry); |
245 | if (!wq && ino && notify == NFY_NONE) { | 247 | if (!wq && ino && notify == NFY_NONE) { |
246 | /* | 248 | /* |
@@ -254,10 +256,10 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
254 | mutex_unlock(&sbi->wq_mutex); | 256 | mutex_unlock(&sbi->wq_mutex); |
255 | schedule_timeout_interruptible(HZ/10); | 257 | schedule_timeout_interruptible(HZ/10); |
256 | if (mutex_lock_interruptible(&sbi->wq_mutex)) { | 258 | if (mutex_lock_interruptible(&sbi->wq_mutex)) { |
257 | kfree(name); | 259 | kfree(qstr.name); |
258 | return -EINTR; | 260 | return -EINTR; |
259 | } | 261 | } |
260 | wq = autofs4_find_wait(sbi, name, hash, len); | 262 | wq = autofs4_find_wait(sbi, &qstr); |
261 | if (wq) | 263 | if (wq) |
262 | break; | 264 | break; |
263 | } | 265 | } |
@@ -268,7 +270,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
268 | * return status of the wait. | 270 | * return status of the wait. |
269 | */ | 271 | */ |
270 | if (!wq) { | 272 | if (!wq) { |
271 | kfree(name); | 273 | kfree(qstr.name); |
272 | mutex_unlock(&sbi->wq_mutex); | 274 | mutex_unlock(&sbi->wq_mutex); |
273 | return 0; | 275 | return 0; |
274 | } | 276 | } |
@@ -278,7 +280,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
278 | /* Create a new wait queue */ | 280 | /* Create a new wait queue */ |
279 | wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); | 281 | wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); |
280 | if (!wq) { | 282 | if (!wq) { |
281 | kfree(name); | 283 | kfree(qstr.name); |
282 | mutex_unlock(&sbi->wq_mutex); | 284 | mutex_unlock(&sbi->wq_mutex); |
283 | return -ENOMEM; | 285 | return -ENOMEM; |
284 | } | 286 | } |
@@ -289,9 +291,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
289 | wq->next = sbi->queues; | 291 | wq->next = sbi->queues; |
290 | sbi->queues = wq; | 292 | sbi->queues = wq; |
291 | init_waitqueue_head(&wq->queue); | 293 | init_waitqueue_head(&wq->queue); |
292 | wq->hash = hash; | 294 | memcpy(&wq->name, &qstr, sizeof(struct qstr)); |
293 | wq->name = name; | ||
294 | wq->len = len; | ||
295 | wq->dev = autofs4_get_dev(sbi); | 295 | wq->dev = autofs4_get_dev(sbi); |
296 | wq->ino = autofs4_get_ino(sbi); | 296 | wq->ino = autofs4_get_ino(sbi); |
297 | wq->uid = current->uid; | 297 | wq->uid = current->uid; |
@@ -319,16 +319,18 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
319 | } | 319 | } |
320 | 320 | ||
321 | DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n", | 321 | DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n", |
322 | (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); | 322 | (unsigned long) wq->wait_queue_token, wq->name.len, |
323 | wq->name.name, notify); | ||
323 | 324 | ||
324 | /* autofs4_notify_daemon() may block */ | 325 | /* autofs4_notify_daemon() may block */ |
325 | autofs4_notify_daemon(sbi, wq, type); | 326 | autofs4_notify_daemon(sbi, wq, type); |
326 | } else { | 327 | } else { |
327 | atomic_inc(&wq->wait_ctr); | 328 | atomic_inc(&wq->wait_ctr); |
328 | mutex_unlock(&sbi->wq_mutex); | 329 | mutex_unlock(&sbi->wq_mutex); |
329 | kfree(name); | 330 | kfree(qstr.name); |
330 | DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", | 331 | DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", |
331 | (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); | 332 | (unsigned long) wq->wait_queue_token, wq->name.len, |
333 | wq->name.name, notify); | ||
332 | } | 334 | } |
333 | 335 | ||
334 | /* wq->name is NULL if and only if the lock is already released */ | 336 | /* wq->name is NULL if and only if the lock is already released */ |
@@ -336,11 +338,13 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
336 | if (sbi->catatonic) { | 338 | if (sbi->catatonic) { |
337 | /* We might have slept, so check again for catatonic mode */ | 339 | /* We might have slept, so check again for catatonic mode */ |
338 | wq->status = -ENOENT; | 340 | wq->status = -ENOENT; |
339 | kfree(wq->name); | 341 | if (wq->name.name) { |
340 | wq->name = NULL; | 342 | kfree(wq->name.name); |
343 | wq->name.name = NULL; | ||
344 | } | ||
341 | } | 345 | } |
342 | 346 | ||
343 | if (wq->name) { | 347 | if (wq->name.name) { |
344 | /* Block all but "shutdown" signals while waiting */ | 348 | /* Block all but "shutdown" signals while waiting */ |
345 | sigset_t oldset; | 349 | sigset_t oldset; |
346 | unsigned long irqflags; | 350 | unsigned long irqflags; |
@@ -351,7 +355,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
351 | recalc_sigpending(); | 355 | recalc_sigpending(); |
352 | spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); | 356 | spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); |
353 | 357 | ||
354 | wait_event_interruptible(wq->queue, wq->name == NULL); | 358 | wait_event_interruptible(wq->queue, wq->name.name == NULL); |
355 | 359 | ||
356 | spin_lock_irqsave(¤t->sighand->siglock, irqflags); | 360 | spin_lock_irqsave(¤t->sighand->siglock, irqflags); |
357 | current->blocked = oldset; | 361 | current->blocked = oldset; |
@@ -388,8 +392,8 @@ int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_tok | |||
388 | 392 | ||
389 | *wql = wq->next; /* Unlink from chain */ | 393 | *wql = wq->next; /* Unlink from chain */ |
390 | mutex_unlock(&sbi->wq_mutex); | 394 | mutex_unlock(&sbi->wq_mutex); |
391 | kfree(wq->name); | 395 | kfree(wq->name.name); |
392 | wq->name = NULL; /* Do not wait on this queue */ | 396 | wq->name.name = NULL; /* Do not wait on this queue */ |
393 | 397 | ||
394 | wq->status = status; | 398 | wq->status = status; |
395 | 399 | ||