diff options
author | Ian Kent <raven@themaw.net> | 2006-03-27 04:14:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-27 11:44:40 -0500 |
commit | 34ca959cfc15cf09ad4da4f31ab034691e51af78 (patch) | |
tree | 83bbe0a2b94ca58f39c65b1e605f44d421b9564b | |
parent | 051d381259eb57d6074d02a6ba6e90e744f1a29f (diff) |
[PATCH] autofs4: add v5 follow_link mount trigger method
This patch adds a follow_link inode method for the root of an autofs direct
mount trigger. It also adds the corresponding mount options and updates the
show_mount method.
Signed-off-by: Ian Kent <raven@themaw.net>
Cc: Al Viro <viro@ftp.linux.org.uk>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/autofs4/autofs_i.h | 8 | ||||
-rw-r--r-- | fs/autofs4/inode.c | 52 | ||||
-rw-r--r-- | fs/autofs4/root.c | 64 |
3 files changed, 103 insertions, 21 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index bc1b0543d2b6..ed388a1d8fc4 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -3,6 +3,7 @@ | |||
3 | * linux/fs/autofs/autofs_i.h | 3 | * linux/fs/autofs/autofs_i.h |
4 | * | 4 | * |
5 | * Copyright 1997-1998 Transmeta Corporation - All Rights Reserved | 5 | * Copyright 1997-1998 Transmeta Corporation - All Rights Reserved |
6 | * Copyright 2005-2006 Ian Kent <raven@themaw.net> | ||
6 | * | 7 | * |
7 | * This file is part of the Linux kernel and is made available under | 8 | * This file is part of the Linux kernel and is made available under |
8 | * the terms of the GNU General Public License, version 2, or at your | 9 | * the terms of the GNU General Public License, version 2, or at your |
@@ -84,6 +85,10 @@ struct autofs_wait_queue { | |||
84 | 85 | ||
85 | #define AUTOFS_SBI_MAGIC 0x6d4a556d | 86 | #define AUTOFS_SBI_MAGIC 0x6d4a556d |
86 | 87 | ||
88 | #define AUTOFS_TYP_INDIRECT 0x0001 | ||
89 | #define AUTOFS_TYP_DIRECT 0x0002 | ||
90 | #define AUTOFS_TYP_OFFSET 0x0004 | ||
91 | |||
87 | struct autofs_sb_info { | 92 | struct autofs_sb_info { |
88 | u32 magic; | 93 | u32 magic; |
89 | struct dentry *root; | 94 | struct dentry *root; |
@@ -96,6 +101,7 @@ struct autofs_sb_info { | |||
96 | int min_proto; | 101 | int min_proto; |
97 | int max_proto; | 102 | int max_proto; |
98 | unsigned long exp_timeout; | 103 | unsigned long exp_timeout; |
104 | unsigned int type; | ||
99 | int reghost_enabled; | 105 | int reghost_enabled; |
100 | int needs_reghost; | 106 | int needs_reghost; |
101 | struct super_block *sb; | 107 | struct super_block *sb; |
@@ -162,6 +168,8 @@ int autofs4_expire_multi(struct super_block *, struct vfsmount *, | |||
162 | extern struct inode_operations autofs4_symlink_inode_operations; | 168 | extern struct inode_operations autofs4_symlink_inode_operations; |
163 | extern struct inode_operations autofs4_dir_inode_operations; | 169 | extern struct inode_operations autofs4_dir_inode_operations; |
164 | extern struct inode_operations autofs4_root_inode_operations; | 170 | extern struct inode_operations autofs4_root_inode_operations; |
171 | extern struct inode_operations autofs4_indirect_root_inode_operations; | ||
172 | extern struct inode_operations autofs4_direct_root_inode_operations; | ||
165 | extern struct file_operations autofs4_dir_operations; | 173 | extern struct file_operations autofs4_dir_operations; |
166 | extern struct file_operations autofs4_root_operations; | 174 | extern struct file_operations autofs4_root_operations; |
167 | 175 | ||
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index d9a71dab40fc..3801bed94e45 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * linux/fs/autofs/inode.c | 3 | * linux/fs/autofs/inode.c |
4 | * | 4 | * |
5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved | 5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved |
6 | * Copyright 2005-2006 Ian Kent <raven@themaw.net> | ||
6 | * | 7 | * |
7 | * This file is part of the Linux kernel and is made available under | 8 | * This file is part of the Linux kernel and is made available under |
8 | * the terms of the GNU General Public License, version 2, or at your | 9 | * the terms of the GNU General Public License, version 2, or at your |
@@ -177,6 +178,13 @@ static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
177 | seq_printf(m, ",minproto=%d", sbi->min_proto); | 178 | seq_printf(m, ",minproto=%d", sbi->min_proto); |
178 | seq_printf(m, ",maxproto=%d", sbi->max_proto); | 179 | seq_printf(m, ",maxproto=%d", sbi->max_proto); |
179 | 180 | ||
181 | if (sbi->type & AUTOFS_TYP_OFFSET) | ||
182 | seq_printf(m, ",offset"); | ||
183 | else if (sbi->type & AUTOFS_TYP_DIRECT) | ||
184 | seq_printf(m, ",direct"); | ||
185 | else | ||
186 | seq_printf(m, ",indirect"); | ||
187 | |||
180 | return 0; | 188 | return 0; |
181 | } | 189 | } |
182 | 190 | ||
@@ -186,7 +194,8 @@ static struct super_operations autofs4_sops = { | |||
186 | .show_options = autofs4_show_options, | 194 | .show_options = autofs4_show_options, |
187 | }; | 195 | }; |
188 | 196 | ||
189 | enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto}; | 197 | enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto, |
198 | Opt_indirect, Opt_direct, Opt_offset}; | ||
190 | 199 | ||
191 | static match_table_t tokens = { | 200 | static match_table_t tokens = { |
192 | {Opt_fd, "fd=%u"}, | 201 | {Opt_fd, "fd=%u"}, |
@@ -195,11 +204,15 @@ static match_table_t tokens = { | |||
195 | {Opt_pgrp, "pgrp=%u"}, | 204 | {Opt_pgrp, "pgrp=%u"}, |
196 | {Opt_minproto, "minproto=%u"}, | 205 | {Opt_minproto, "minproto=%u"}, |
197 | {Opt_maxproto, "maxproto=%u"}, | 206 | {Opt_maxproto, "maxproto=%u"}, |
207 | {Opt_indirect, "indirect"}, | ||
208 | {Opt_direct, "direct"}, | ||
209 | {Opt_offset, "offset"}, | ||
198 | {Opt_err, NULL} | 210 | {Opt_err, NULL} |
199 | }; | 211 | }; |
200 | 212 | ||
201 | static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, | 213 | static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, |
202 | pid_t *pgrp, int *minproto, int *maxproto) | 214 | pid_t *pgrp, unsigned int *type, |
215 | int *minproto, int *maxproto) | ||
203 | { | 216 | { |
204 | char *p; | 217 | char *p; |
205 | substring_t args[MAX_OPT_ARGS]; | 218 | substring_t args[MAX_OPT_ARGS]; |
@@ -253,6 +266,15 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, | |||
253 | return 1; | 266 | return 1; |
254 | *maxproto = option; | 267 | *maxproto = option; |
255 | break; | 268 | break; |
269 | case Opt_indirect: | ||
270 | *type = AUTOFS_TYP_INDIRECT; | ||
271 | break; | ||
272 | case Opt_direct: | ||
273 | *type = AUTOFS_TYP_DIRECT; | ||
274 | break; | ||
275 | case Opt_offset: | ||
276 | *type = AUTOFS_TYP_DIRECT | AUTOFS_TYP_OFFSET; | ||
277 | break; | ||
256 | default: | 278 | default: |
257 | return 1; | 279 | return 1; |
258 | } | 280 | } |
@@ -271,6 +293,11 @@ static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi) | |||
271 | return ino; | 293 | return ino; |
272 | } | 294 | } |
273 | 295 | ||
296 | void autofs4_dentry_release(struct dentry *); | ||
297 | static struct dentry_operations autofs4_sb_dentry_operations = { | ||
298 | .d_release = autofs4_dentry_release, | ||
299 | }; | ||
300 | |||
274 | int autofs4_fill_super(struct super_block *s, void *data, int silent) | 301 | int autofs4_fill_super(struct super_block *s, void *data, int silent) |
275 | { | 302 | { |
276 | struct inode * root_inode; | 303 | struct inode * root_inode; |
@@ -297,6 +324,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
297 | sbi->sb = s; | 324 | sbi->sb = s; |
298 | sbi->version = 0; | 325 | sbi->version = 0; |
299 | sbi->sub_version = 0; | 326 | sbi->sub_version = 0; |
327 | sbi->type = 0; | ||
300 | sbi->min_proto = 0; | 328 | sbi->min_proto = 0; |
301 | sbi->max_proto = 0; | 329 | sbi->max_proto = 0; |
302 | mutex_init(&sbi->wq_mutex); | 330 | mutex_init(&sbi->wq_mutex); |
@@ -315,27 +343,31 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
315 | if (!ino) | 343 | if (!ino) |
316 | goto fail_free; | 344 | goto fail_free; |
317 | root_inode = autofs4_get_inode(s, ino); | 345 | root_inode = autofs4_get_inode(s, ino); |
318 | kfree(ino); | ||
319 | if (!root_inode) | 346 | if (!root_inode) |
320 | goto fail_free; | 347 | goto fail_ino; |
321 | 348 | ||
322 | root_inode->i_op = &autofs4_root_inode_operations; | ||
323 | root_inode->i_fop = &autofs4_root_operations; | ||
324 | root = d_alloc_root(root_inode); | 349 | root = d_alloc_root(root_inode); |
325 | pipe = NULL; | ||
326 | |||
327 | if (!root) | 350 | if (!root) |
328 | goto fail_iput; | 351 | goto fail_iput; |
352 | pipe = NULL; | ||
353 | |||
354 | root->d_op = &autofs4_sb_dentry_operations; | ||
355 | root->d_fsdata = ino; | ||
329 | 356 | ||
330 | /* Can this call block? */ | 357 | /* Can this call block? */ |
331 | if (parse_options(data, &pipefd, | 358 | if (parse_options(data, &pipefd, |
332 | &root_inode->i_uid, &root_inode->i_gid, | 359 | &root_inode->i_uid, &root_inode->i_gid, |
333 | &sbi->oz_pgrp, | 360 | &sbi->oz_pgrp, &sbi->type, |
334 | &sbi->min_proto, &sbi->max_proto)) { | 361 | &sbi->min_proto, &sbi->max_proto)) { |
335 | printk("autofs: called with bogus options\n"); | 362 | printk("autofs: called with bogus options\n"); |
336 | goto fail_dput; | 363 | goto fail_dput; |
337 | } | 364 | } |
338 | 365 | ||
366 | root_inode->i_fop = &autofs4_root_operations; | ||
367 | root_inode->i_op = sbi->type & AUTOFS_TYP_DIRECT ? | ||
368 | &autofs4_direct_root_inode_operations : | ||
369 | &autofs4_indirect_root_inode_operations; | ||
370 | |||
339 | /* Couldn't this be tested earlier? */ | 371 | /* Couldn't this be tested earlier? */ |
340 | if (sbi->max_proto < AUTOFS_MIN_PROTO_VERSION || | 372 | if (sbi->max_proto < AUTOFS_MIN_PROTO_VERSION || |
341 | sbi->min_proto > AUTOFS_MAX_PROTO_VERSION) { | 373 | sbi->min_proto > AUTOFS_MAX_PROTO_VERSION) { |
@@ -391,6 +423,8 @@ fail_dput: | |||
391 | fail_iput: | 423 | fail_iput: |
392 | printk("autofs: get root dentry failed\n"); | 424 | printk("autofs: get root dentry failed\n"); |
393 | iput(root_inode); | 425 | iput(root_inode); |
426 | fail_ino: | ||
427 | kfree(ino); | ||
394 | fail_free: | 428 | fail_free: |
395 | kfree(sbi); | 429 | kfree(sbi); |
396 | fail_unlock: | 430 | fail_unlock: |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 26eb1f024866..3f0048582248 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * | 4 | * |
5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved | 5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved |
6 | * Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org> | 6 | * Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org> |
7 | * Copyright 2001-2003 Ian Kent <raven@themaw.net> | 7 | * Copyright 2001-2006 Ian Kent <raven@themaw.net> |
8 | * | 8 | * |
9 | * This file is part of the Linux kernel and is made available under | 9 | * This file is part of the Linux kernel and is made available under |
10 | * the terms of the GNU General Public License, version 2, or at your | 10 | * the terms of the GNU General Public License, version 2, or at your |
@@ -30,6 +30,7 @@ static int autofs4_dir_close(struct inode *inode, struct file *file); | |||
30 | static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir); | 30 | static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir); |
31 | static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir); | 31 | static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir); |
32 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); | 32 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); |
33 | static void *autofs4_follow_link(struct dentry *, struct nameidata *); | ||
33 | 34 | ||
34 | struct file_operations autofs4_root_operations = { | 35 | struct file_operations autofs4_root_operations = { |
35 | .open = dcache_dir_open, | 36 | .open = dcache_dir_open, |
@@ -46,7 +47,7 @@ struct file_operations autofs4_dir_operations = { | |||
46 | .readdir = autofs4_dir_readdir, | 47 | .readdir = autofs4_dir_readdir, |
47 | }; | 48 | }; |
48 | 49 | ||
49 | struct inode_operations autofs4_root_inode_operations = { | 50 | struct inode_operations autofs4_indirect_root_inode_operations = { |
50 | .lookup = autofs4_lookup, | 51 | .lookup = autofs4_lookup, |
51 | .unlink = autofs4_dir_unlink, | 52 | .unlink = autofs4_dir_unlink, |
52 | .symlink = autofs4_dir_symlink, | 53 | .symlink = autofs4_dir_symlink, |
@@ -54,6 +55,11 @@ struct inode_operations autofs4_root_inode_operations = { | |||
54 | .rmdir = autofs4_dir_rmdir, | 55 | .rmdir = autofs4_dir_rmdir, |
55 | }; | 56 | }; |
56 | 57 | ||
58 | struct inode_operations autofs4_direct_root_inode_operations = { | ||
59 | .lookup = autofs4_lookup, | ||
60 | .follow_link = autofs4_follow_link, | ||
61 | }; | ||
62 | |||
57 | struct inode_operations autofs4_dir_inode_operations = { | 63 | struct inode_operations autofs4_dir_inode_operations = { |
58 | .lookup = autofs4_lookup, | 64 | .lookup = autofs4_lookup, |
59 | .unlink = autofs4_dir_unlink, | 65 | .unlink = autofs4_dir_unlink, |
@@ -252,7 +258,7 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags) | |||
252 | */ | 258 | */ |
253 | status = d_invalidate(dentry); | 259 | status = d_invalidate(dentry); |
254 | if (status != -EBUSY) | 260 | if (status != -EBUSY) |
255 | return 0; | 261 | return -ENOENT; |
256 | } | 262 | } |
257 | 263 | ||
258 | DPRINTK("dentry=%p %.*s ino=%p", | 264 | DPRINTK("dentry=%p %.*s ino=%p", |
@@ -271,17 +277,17 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags) | |||
271 | DPRINTK("mount done status=%d", status); | 277 | DPRINTK("mount done status=%d", status); |
272 | 278 | ||
273 | if (status && dentry->d_inode) | 279 | if (status && dentry->d_inode) |
274 | return 0; /* Try to get the kernel to invalidate this dentry */ | 280 | return status; /* Try to get the kernel to invalidate this dentry */ |
275 | 281 | ||
276 | /* Turn this into a real negative dentry? */ | 282 | /* Turn this into a real negative dentry? */ |
277 | if (status == -ENOENT) { | 283 | if (status == -ENOENT) { |
278 | spin_lock(&dentry->d_lock); | 284 | spin_lock(&dentry->d_lock); |
279 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | 285 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; |
280 | spin_unlock(&dentry->d_lock); | 286 | spin_unlock(&dentry->d_lock); |
281 | return 0; | 287 | return status; |
282 | } else if (status) { | 288 | } else if (status) { |
283 | /* Return a negative dentry, but leave it "pending" */ | 289 | /* Return a negative dentry, but leave it "pending" */ |
284 | return 0; | 290 | return status; |
285 | } | 291 | } |
286 | /* Trigger mount for path component or follow link */ | 292 | /* Trigger mount for path component or follow link */ |
287 | } else if (flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) || | 293 | } else if (flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) || |
@@ -300,7 +306,7 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags) | |||
300 | spin_lock(&dentry->d_lock); | 306 | spin_lock(&dentry->d_lock); |
301 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | 307 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; |
302 | spin_unlock(&dentry->d_lock); | 308 | spin_unlock(&dentry->d_lock); |
303 | return 0; | 309 | return status; |
304 | } | 310 | } |
305 | } | 311 | } |
306 | 312 | ||
@@ -311,7 +317,41 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags) | |||
311 | spin_lock(&dentry->d_lock); | 317 | spin_lock(&dentry->d_lock); |
312 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | 318 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; |
313 | spin_unlock(&dentry->d_lock); | 319 | spin_unlock(&dentry->d_lock); |
314 | return 1; | 320 | return status; |
321 | } | ||
322 | |||
323 | /* For autofs direct mounts the follow link triggers the mount */ | ||
324 | static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
325 | { | ||
326 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
327 | int oz_mode = autofs4_oz_mode(sbi); | ||
328 | unsigned int lookup_type; | ||
329 | int status; | ||
330 | |||
331 | DPRINTK("dentry=%p %.*s oz_mode=%d nd->flags=%d", | ||
332 | dentry, dentry->d_name.len, dentry->d_name.name, oz_mode, | ||
333 | nd->flags); | ||
334 | |||
335 | /* If it's our master or we shouldn't trigger a mount we're done */ | ||
336 | lookup_type = nd->flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY); | ||
337 | if (oz_mode || !lookup_type) | ||
338 | goto done; | ||
339 | |||
340 | status = try_to_fill_dentry(dentry, 0); | ||
341 | if (status) | ||
342 | goto out_error; | ||
343 | |||
344 | if (!autofs4_follow_mount(&nd->mnt, &nd->dentry)) { | ||
345 | status = -ENOENT; | ||
346 | goto out_error; | ||
347 | } | ||
348 | |||
349 | done: | ||
350 | return NULL; | ||
351 | |||
352 | out_error: | ||
353 | path_release(nd); | ||
354 | return ERR_PTR(status); | ||
315 | } | 355 | } |
316 | 356 | ||
317 | /* | 357 | /* |
@@ -326,13 +366,13 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
326 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 366 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
327 | int oz_mode = autofs4_oz_mode(sbi); | 367 | int oz_mode = autofs4_oz_mode(sbi); |
328 | int flags = nd ? nd->flags : 0; | 368 | int flags = nd ? nd->flags : 0; |
329 | int status = 1; | 369 | int status = 0; |
330 | 370 | ||
331 | /* Pending dentry */ | 371 | /* Pending dentry */ |
332 | if (autofs4_ispending(dentry)) { | 372 | if (autofs4_ispending(dentry)) { |
333 | if (!oz_mode) | 373 | if (!oz_mode) |
334 | status = try_to_fill_dentry(dentry, flags); | 374 | status = try_to_fill_dentry(dentry, flags); |
335 | return status; | 375 | return !status; |
336 | } | 376 | } |
337 | 377 | ||
338 | /* Negative dentry.. invalidate if "old" */ | 378 | /* Negative dentry.. invalidate if "old" */ |
@@ -349,14 +389,14 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
349 | spin_unlock(&dcache_lock); | 389 | spin_unlock(&dcache_lock); |
350 | if (!oz_mode) | 390 | if (!oz_mode) |
351 | status = try_to_fill_dentry(dentry, flags); | 391 | status = try_to_fill_dentry(dentry, flags); |
352 | return status; | 392 | return !status; |
353 | } | 393 | } |
354 | spin_unlock(&dcache_lock); | 394 | spin_unlock(&dcache_lock); |
355 | 395 | ||
356 | return 1; | 396 | return 1; |
357 | } | 397 | } |
358 | 398 | ||
359 | static void autofs4_dentry_release(struct dentry *de) | 399 | void autofs4_dentry_release(struct dentry *de) |
360 | { | 400 | { |
361 | struct autofs_info *inf; | 401 | struct autofs_info *inf; |
362 | 402 | ||