diff options
Diffstat (limited to 'fs/autofs4/root.c')
-rw-r--r-- | fs/autofs4/root.c | 149 |
1 files changed, 16 insertions, 133 deletions
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 87352654ff4e..51c873ca8e8d 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -25,8 +25,6 @@ static int autofs4_dir_rmdir(struct inode *,struct dentry *); | |||
25 | static int autofs4_dir_mkdir(struct inode *,struct dentry *,int); | 25 | static int autofs4_dir_mkdir(struct inode *,struct dentry *,int); |
26 | static int autofs4_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long); | 26 | static int autofs4_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long); |
27 | static int autofs4_dir_open(struct inode *inode, struct file *file); | 27 | static int autofs4_dir_open(struct inode *inode, struct file *file); |
28 | static int autofs4_dir_close(struct inode *inode, struct file *file); | ||
29 | static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir); | ||
30 | static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir); | 28 | static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir); |
31 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); | 29 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); |
32 | static void *autofs4_follow_link(struct dentry *, struct nameidata *); | 30 | static void *autofs4_follow_link(struct dentry *, struct nameidata *); |
@@ -44,9 +42,9 @@ const struct file_operations autofs4_root_operations = { | |||
44 | 42 | ||
45 | const struct file_operations autofs4_dir_operations = { | 43 | const struct file_operations autofs4_dir_operations = { |
46 | .open = autofs4_dir_open, | 44 | .open = autofs4_dir_open, |
47 | .release = autofs4_dir_close, | 45 | .release = dcache_dir_close, |
48 | .read = generic_read_dir, | 46 | .read = generic_read_dir, |
49 | .readdir = autofs4_dir_readdir, | 47 | .readdir = dcache_readdir, |
50 | }; | 48 | }; |
51 | 49 | ||
52 | const struct inode_operations autofs4_indirect_root_inode_operations = { | 50 | const struct inode_operations autofs4_indirect_root_inode_operations = { |
@@ -98,17 +96,7 @@ static int autofs4_root_readdir(struct file *file, void *dirent, | |||
98 | static int autofs4_dir_open(struct inode *inode, struct file *file) | 96 | static int autofs4_dir_open(struct inode *inode, struct file *file) |
99 | { | 97 | { |
100 | struct dentry *dentry = file->f_path.dentry; | 98 | struct dentry *dentry = file->f_path.dentry; |
101 | struct vfsmount *mnt = file->f_path.mnt; | ||
102 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 99 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
103 | struct dentry *cursor; | ||
104 | int status; | ||
105 | |||
106 | status = dcache_dir_open(inode, file); | ||
107 | if (status) | ||
108 | goto out; | ||
109 | |||
110 | cursor = file->private_data; | ||
111 | cursor->d_fsdata = NULL; | ||
112 | 100 | ||
113 | DPRINTK("file=%p dentry=%p %.*s", | 101 | DPRINTK("file=%p dentry=%p %.*s", |
114 | file, dentry, dentry->d_name.len, dentry->d_name.name); | 102 | file, dentry, dentry->d_name.len, dentry->d_name.name); |
@@ -116,129 +104,24 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
116 | if (autofs4_oz_mode(sbi)) | 104 | if (autofs4_oz_mode(sbi)) |
117 | goto out; | 105 | goto out; |
118 | 106 | ||
119 | if (autofs4_ispending(dentry)) { | 107 | /* |
120 | DPRINTK("dentry busy"); | 108 | * An empty directory in an autofs file system is always a |
121 | dcache_dir_close(inode, file); | 109 | * mount point. The daemon must have failed to mount this |
122 | status = -EBUSY; | 110 | * during lookup so it doesn't exist. This can happen, for |
123 | goto out; | 111 | * example, if user space returns an incorrect status for a |
124 | } | 112 | * mount request. Otherwise we're doing a readdir on the |
125 | 113 | * autofs file system so just let the libfs routines handle | |
126 | status = -ENOENT; | 114 | * it. |
127 | if (!d_mountpoint(dentry) && dentry->d_op && dentry->d_op->d_revalidate) { | 115 | */ |
128 | struct nameidata nd; | 116 | spin_lock(&dcache_lock); |
129 | int empty, ret; | 117 | if (!d_mountpoint(dentry) && __simple_empty(dentry)) { |
130 | |||
131 | /* In case there are stale directory dentrys from a failed mount */ | ||
132 | spin_lock(&dcache_lock); | ||
133 | empty = list_empty(&dentry->d_subdirs); | ||
134 | spin_unlock(&dcache_lock); | 118 | spin_unlock(&dcache_lock); |
135 | 119 | return -ENOENT; | |
136 | if (!empty) | ||
137 | d_invalidate(dentry); | ||
138 | |||
139 | nd.flags = LOOKUP_DIRECTORY; | ||
140 | ret = (dentry->d_op->d_revalidate)(dentry, &nd); | ||
141 | |||
142 | if (ret <= 0) { | ||
143 | if (ret < 0) | ||
144 | status = ret; | ||
145 | dcache_dir_close(inode, file); | ||
146 | goto out; | ||
147 | } | ||
148 | } | 120 | } |
121 | spin_unlock(&dcache_lock); | ||
149 | 122 | ||
150 | if (d_mountpoint(dentry)) { | ||
151 | struct file *fp = NULL; | ||
152 | struct path fp_path = { .dentry = dentry, .mnt = mnt }; | ||
153 | |||
154 | path_get(&fp_path); | ||
155 | |||
156 | if (!autofs4_follow_mount(&fp_path.mnt, &fp_path.dentry)) { | ||
157 | path_put(&fp_path); | ||
158 | dcache_dir_close(inode, file); | ||
159 | goto out; | ||
160 | } | ||
161 | |||
162 | fp = dentry_open(fp_path.dentry, fp_path.mnt, file->f_flags); | ||
163 | status = PTR_ERR(fp); | ||
164 | if (IS_ERR(fp)) { | ||
165 | dcache_dir_close(inode, file); | ||
166 | goto out; | ||
167 | } | ||
168 | cursor->d_fsdata = fp; | ||
169 | } | ||
170 | return 0; | ||
171 | out: | ||
172 | return status; | ||
173 | } | ||
174 | |||
175 | static int autofs4_dir_close(struct inode *inode, struct file *file) | ||
176 | { | ||
177 | struct dentry *dentry = file->f_path.dentry; | ||
178 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
179 | struct dentry *cursor = file->private_data; | ||
180 | int status = 0; | ||
181 | |||
182 | DPRINTK("file=%p dentry=%p %.*s", | ||
183 | file, dentry, dentry->d_name.len, dentry->d_name.name); | ||
184 | |||
185 | if (autofs4_oz_mode(sbi)) | ||
186 | goto out; | ||
187 | |||
188 | if (autofs4_ispending(dentry)) { | ||
189 | DPRINTK("dentry busy"); | ||
190 | status = -EBUSY; | ||
191 | goto out; | ||
192 | } | ||
193 | |||
194 | if (d_mountpoint(dentry)) { | ||
195 | struct file *fp = cursor->d_fsdata; | ||
196 | if (!fp) { | ||
197 | status = -ENOENT; | ||
198 | goto out; | ||
199 | } | ||
200 | filp_close(fp, current->files); | ||
201 | } | ||
202 | out: | ||
203 | dcache_dir_close(inode, file); | ||
204 | return status; | ||
205 | } | ||
206 | |||
207 | static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldir) | ||
208 | { | ||
209 | struct dentry *dentry = file->f_path.dentry; | ||
210 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
211 | struct dentry *cursor = file->private_data; | ||
212 | int status; | ||
213 | |||
214 | DPRINTK("file=%p dentry=%p %.*s", | ||
215 | file, dentry, dentry->d_name.len, dentry->d_name.name); | ||
216 | |||
217 | if (autofs4_oz_mode(sbi)) | ||
218 | goto out; | ||
219 | |||
220 | if (autofs4_ispending(dentry)) { | ||
221 | DPRINTK("dentry busy"); | ||
222 | return -EBUSY; | ||
223 | } | ||
224 | |||
225 | if (d_mountpoint(dentry)) { | ||
226 | struct file *fp = cursor->d_fsdata; | ||
227 | |||
228 | if (!fp) | ||
229 | return -ENOENT; | ||
230 | |||
231 | if (!fp->f_op || !fp->f_op->readdir) | ||
232 | goto out; | ||
233 | |||
234 | status = vfs_readdir(fp, filldir, dirent); | ||
235 | file->f_pos = fp->f_pos; | ||
236 | if (status) | ||
237 | autofs4_copy_atime(file, fp); | ||
238 | return status; | ||
239 | } | ||
240 | out: | 123 | out: |
241 | return dcache_readdir(file, dirent, filldir); | 124 | return dcache_dir_open(inode, file); |
242 | } | 125 | } |
243 | 126 | ||
244 | static int try_to_fill_dentry(struct dentry *dentry, int flags) | 127 | static int try_to_fill_dentry(struct dentry *dentry, int flags) |