diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2009-04-06 22:01:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-07 11:31:15 -0400 |
commit | d25006523d0b9e49fd097b2e974e7c8c05bd7f54 (patch) | |
tree | ff251f5854012ba8b6000745a24d50eda7e3dbd8 /fs/nilfs2/namei.c | |
parent | 2ba466d74ed74f073257f86e61519cb8f8f46184 (diff) |
nilfs2: pathname operations
This adds pathname operations, most of which comes from the ext2 file
system.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/nilfs2/namei.c')
-rw-r--r-- | fs/nilfs2/namei.c | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c new file mode 100644 index 000000000000..95d1b29bff3c --- /dev/null +++ b/fs/nilfs2/namei.c | |||
@@ -0,0 +1,446 @@ | |||
1 | /* | ||
2 | * namei.c - NILFS pathname lookup operations. | ||
3 | * | ||
4 | * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
19 | * | ||
20 | * Modified for NILFS by Amagai Yoshiji <amagai@osrg.net>, | ||
21 | * Ryusuke Konishi <ryusuke@osrg.net> | ||
22 | */ | ||
23 | /* | ||
24 | * linux/fs/ext2/namei.c | ||
25 | * | ||
26 | * Copyright (C) 1992, 1993, 1994, 1995 | ||
27 | * Remy Card (card@masi.ibp.fr) | ||
28 | * Laboratoire MASI - Institut Blaise Pascal | ||
29 | * Universite Pierre et Marie Curie (Paris VI) | ||
30 | * | ||
31 | * from | ||
32 | * | ||
33 | * linux/fs/minix/namei.c | ||
34 | * | ||
35 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
36 | * | ||
37 | * Big-endian to little-endian byte-swapping/bitmaps by | ||
38 | * David S. Miller (davem@caip.rutgers.edu), 1995 | ||
39 | */ | ||
40 | |||
41 | #include <linux/pagemap.h> | ||
42 | #include "nilfs.h" | ||
43 | |||
44 | |||
45 | static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) | ||
46 | { | ||
47 | int err = nilfs_add_link(dentry, inode); | ||
48 | if (!err) { | ||
49 | d_instantiate(dentry, inode); | ||
50 | return 0; | ||
51 | } | ||
52 | inode_dec_link_count(inode); | ||
53 | iput(inode); | ||
54 | return err; | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * Methods themselves. | ||
59 | */ | ||
60 | |||
61 | static struct dentry * | ||
62 | nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | ||
63 | { | ||
64 | struct inode *inode; | ||
65 | ino_t ino; | ||
66 | |||
67 | if (dentry->d_name.len > NILFS_NAME_LEN) | ||
68 | return ERR_PTR(-ENAMETOOLONG); | ||
69 | |||
70 | ino = nilfs_inode_by_name(dir, dentry); | ||
71 | inode = NULL; | ||
72 | if (ino) { | ||
73 | inode = nilfs_iget(dir->i_sb, ino); | ||
74 | if (IS_ERR(inode)) | ||
75 | return ERR_CAST(inode); | ||
76 | } | ||
77 | return d_splice_alias(inode, dentry); | ||
78 | } | ||
79 | |||
80 | struct dentry *nilfs_get_parent(struct dentry *child) | ||
81 | { | ||
82 | unsigned long ino; | ||
83 | struct inode *inode; | ||
84 | struct dentry dotdot; | ||
85 | |||
86 | dotdot.d_name.name = ".."; | ||
87 | dotdot.d_name.len = 2; | ||
88 | |||
89 | ino = nilfs_inode_by_name(child->d_inode, &dotdot); | ||
90 | if (!ino) | ||
91 | return ERR_PTR(-ENOENT); | ||
92 | |||
93 | inode = nilfs_iget(child->d_inode->i_sb, ino); | ||
94 | if (IS_ERR(inode)) | ||
95 | return ERR_CAST(inode); | ||
96 | return d_obtain_alias(inode); | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * By the time this is called, we already have created | ||
101 | * the directory cache entry for the new file, but it | ||
102 | * is so far negative - it has no inode. | ||
103 | * | ||
104 | * If the create succeeds, we fill in the inode information | ||
105 | * with d_instantiate(). | ||
106 | */ | ||
107 | static int nilfs_create(struct inode *dir, struct dentry *dentry, int mode, | ||
108 | struct nameidata *nd) | ||
109 | { | ||
110 | struct inode *inode; | ||
111 | struct nilfs_transaction_info ti; | ||
112 | int err, err2; | ||
113 | |||
114 | err = nilfs_transaction_begin(dir->i_sb, &ti, 1); | ||
115 | if (err) | ||
116 | return err; | ||
117 | inode = nilfs_new_inode(dir, mode); | ||
118 | err = PTR_ERR(inode); | ||
119 | if (!IS_ERR(inode)) { | ||
120 | inode->i_op = &nilfs_file_inode_operations; | ||
121 | inode->i_fop = &nilfs_file_operations; | ||
122 | inode->i_mapping->a_ops = &nilfs_aops; | ||
123 | mark_inode_dirty(inode); | ||
124 | err = nilfs_add_nondir(dentry, inode); | ||
125 | } | ||
126 | err2 = nilfs_transaction_end(dir->i_sb, !err); | ||
127 | return err ? : err2; | ||
128 | } | ||
129 | |||
130 | static int | ||
131 | nilfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | ||
132 | { | ||
133 | struct inode *inode; | ||
134 | struct nilfs_transaction_info ti; | ||
135 | int err, err2; | ||
136 | |||
137 | if (!new_valid_dev(rdev)) | ||
138 | return -EINVAL; | ||
139 | |||
140 | err = nilfs_transaction_begin(dir->i_sb, &ti, 1); | ||
141 | if (err) | ||
142 | return err; | ||
143 | inode = nilfs_new_inode(dir, mode); | ||
144 | err = PTR_ERR(inode); | ||
145 | if (!IS_ERR(inode)) { | ||
146 | init_special_inode(inode, inode->i_mode, rdev); | ||
147 | mark_inode_dirty(inode); | ||
148 | err = nilfs_add_nondir(dentry, inode); | ||
149 | } | ||
150 | err2 = nilfs_transaction_end(dir->i_sb, !err); | ||
151 | return err ? : err2; | ||
152 | } | ||
153 | |||
154 | static int nilfs_symlink(struct inode *dir, struct dentry *dentry, | ||
155 | const char *symname) | ||
156 | { | ||
157 | struct nilfs_transaction_info ti; | ||
158 | struct super_block *sb = dir->i_sb; | ||
159 | unsigned l = strlen(symname)+1; | ||
160 | struct inode *inode; | ||
161 | int err, err2; | ||
162 | |||
163 | if (l > sb->s_blocksize) | ||
164 | return -ENAMETOOLONG; | ||
165 | |||
166 | err = nilfs_transaction_begin(dir->i_sb, &ti, 1); | ||
167 | if (err) | ||
168 | return err; | ||
169 | |||
170 | inode = nilfs_new_inode(dir, S_IFLNK | S_IRWXUGO); | ||
171 | err = PTR_ERR(inode); | ||
172 | if (IS_ERR(inode)) | ||
173 | goto out; | ||
174 | |||
175 | /* slow symlink */ | ||
176 | inode->i_op = &nilfs_symlink_inode_operations; | ||
177 | inode->i_mapping->a_ops = &nilfs_aops; | ||
178 | err = page_symlink(inode, symname, l); | ||
179 | if (err) | ||
180 | goto out_fail; | ||
181 | |||
182 | /* mark_inode_dirty(inode); */ | ||
183 | /* nilfs_new_inode() and page_symlink() do this */ | ||
184 | |||
185 | err = nilfs_add_nondir(dentry, inode); | ||
186 | out: | ||
187 | err2 = nilfs_transaction_end(dir->i_sb, !err); | ||
188 | return err ? : err2; | ||
189 | |||
190 | out_fail: | ||
191 | inode_dec_link_count(inode); | ||
192 | iput(inode); | ||
193 | goto out; | ||
194 | } | ||
195 | |||
196 | static int nilfs_link(struct dentry *old_dentry, struct inode *dir, | ||
197 | struct dentry *dentry) | ||
198 | { | ||
199 | struct inode *inode = old_dentry->d_inode; | ||
200 | struct nilfs_transaction_info ti; | ||
201 | int err, err2; | ||
202 | |||
203 | if (inode->i_nlink >= NILFS_LINK_MAX) | ||
204 | return -EMLINK; | ||
205 | |||
206 | err = nilfs_transaction_begin(dir->i_sb, &ti, 1); | ||
207 | if (err) | ||
208 | return err; | ||
209 | |||
210 | inode->i_ctime = CURRENT_TIME; | ||
211 | inode_inc_link_count(inode); | ||
212 | atomic_inc(&inode->i_count); | ||
213 | |||
214 | err = nilfs_add_nondir(dentry, inode); | ||
215 | err2 = nilfs_transaction_end(dir->i_sb, !err); | ||
216 | return err ? : err2; | ||
217 | } | ||
218 | |||
219 | static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | ||
220 | { | ||
221 | struct inode *inode; | ||
222 | struct nilfs_transaction_info ti; | ||
223 | int err, err2; | ||
224 | |||
225 | if (dir->i_nlink >= NILFS_LINK_MAX) | ||
226 | return -EMLINK; | ||
227 | |||
228 | err = nilfs_transaction_begin(dir->i_sb, &ti, 1); | ||
229 | if (err) | ||
230 | return err; | ||
231 | |||
232 | inode_inc_link_count(dir); | ||
233 | |||
234 | inode = nilfs_new_inode(dir, S_IFDIR | mode); | ||
235 | err = PTR_ERR(inode); | ||
236 | if (IS_ERR(inode)) | ||
237 | goto out_dir; | ||
238 | |||
239 | inode->i_op = &nilfs_dir_inode_operations; | ||
240 | inode->i_fop = &nilfs_dir_operations; | ||
241 | inode->i_mapping->a_ops = &nilfs_aops; | ||
242 | |||
243 | inode_inc_link_count(inode); | ||
244 | |||
245 | err = nilfs_make_empty(inode, dir); | ||
246 | if (err) | ||
247 | goto out_fail; | ||
248 | |||
249 | err = nilfs_add_link(dentry, inode); | ||
250 | if (err) | ||
251 | goto out_fail; | ||
252 | |||
253 | d_instantiate(dentry, inode); | ||
254 | out: | ||
255 | err2 = nilfs_transaction_end(dir->i_sb, !err); | ||
256 | return err ? : err2; | ||
257 | |||
258 | out_fail: | ||
259 | inode_dec_link_count(inode); | ||
260 | inode_dec_link_count(inode); | ||
261 | iput(inode); | ||
262 | out_dir: | ||
263 | inode_dec_link_count(dir); | ||
264 | goto out; | ||
265 | } | ||
266 | |||
267 | static int nilfs_unlink(struct inode *dir, struct dentry *dentry) | ||
268 | { | ||
269 | struct inode *inode; | ||
270 | struct nilfs_dir_entry *de; | ||
271 | struct page *page; | ||
272 | struct nilfs_transaction_info ti; | ||
273 | int err, err2; | ||
274 | |||
275 | err = nilfs_transaction_begin(dir->i_sb, &ti, 0); | ||
276 | if (err) | ||
277 | return err; | ||
278 | |||
279 | err = -ENOENT; | ||
280 | de = nilfs_find_entry(dir, dentry, &page); | ||
281 | if (!de) | ||
282 | goto out; | ||
283 | |||
284 | inode = dentry->d_inode; | ||
285 | err = -EIO; | ||
286 | if (le64_to_cpu(de->inode) != inode->i_ino) | ||
287 | goto out; | ||
288 | |||
289 | if (!inode->i_nlink) { | ||
290 | nilfs_warning(inode->i_sb, __func__, | ||
291 | "deleting nonexistent file (%lu), %d\n", | ||
292 | inode->i_ino, inode->i_nlink); | ||
293 | inode->i_nlink = 1; | ||
294 | } | ||
295 | err = nilfs_delete_entry(de, page); | ||
296 | if (err) | ||
297 | goto out; | ||
298 | |||
299 | inode->i_ctime = dir->i_ctime; | ||
300 | inode_dec_link_count(inode); | ||
301 | err = 0; | ||
302 | out: | ||
303 | err2 = nilfs_transaction_end(dir->i_sb, !err); | ||
304 | return err ? : err2; | ||
305 | } | ||
306 | |||
307 | static int nilfs_rmdir(struct inode *dir, struct dentry *dentry) | ||
308 | { | ||
309 | struct inode *inode = dentry->d_inode; | ||
310 | struct nilfs_transaction_info ti; | ||
311 | int err, err2; | ||
312 | |||
313 | err = nilfs_transaction_begin(dir->i_sb, &ti, 0); | ||
314 | if (err) | ||
315 | return err; | ||
316 | |||
317 | err = -ENOTEMPTY; | ||
318 | if (nilfs_empty_dir(inode)) { | ||
319 | err = nilfs_unlink(dir, dentry); | ||
320 | if (!err) { | ||
321 | inode->i_size = 0; | ||
322 | inode_dec_link_count(inode); | ||
323 | inode_dec_link_count(dir); | ||
324 | } | ||
325 | } | ||
326 | err2 = nilfs_transaction_end(dir->i_sb, !err); | ||
327 | return err ? : err2; | ||
328 | } | ||
329 | |||
330 | static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry, | ||
331 | struct inode *new_dir, struct dentry *new_dentry) | ||
332 | { | ||
333 | struct inode *old_inode = old_dentry->d_inode; | ||
334 | struct inode *new_inode = new_dentry->d_inode; | ||
335 | struct page *dir_page = NULL; | ||
336 | struct nilfs_dir_entry *dir_de = NULL; | ||
337 | struct page *old_page; | ||
338 | struct nilfs_dir_entry *old_de; | ||
339 | struct nilfs_transaction_info ti; | ||
340 | int err; | ||
341 | |||
342 | err = nilfs_transaction_begin(old_dir->i_sb, &ti, 1); | ||
343 | if (unlikely(err)) | ||
344 | return err; | ||
345 | |||
346 | err = -ENOENT; | ||
347 | old_de = nilfs_find_entry(old_dir, old_dentry, &old_page); | ||
348 | if (!old_de) | ||
349 | goto out; | ||
350 | |||
351 | if (S_ISDIR(old_inode->i_mode)) { | ||
352 | err = -EIO; | ||
353 | dir_de = nilfs_dotdot(old_inode, &dir_page); | ||
354 | if (!dir_de) | ||
355 | goto out_old; | ||
356 | } | ||
357 | |||
358 | if (new_inode) { | ||
359 | struct page *new_page; | ||
360 | struct nilfs_dir_entry *new_de; | ||
361 | |||
362 | err = -ENOTEMPTY; | ||
363 | if (dir_de && !nilfs_empty_dir(new_inode)) | ||
364 | goto out_dir; | ||
365 | |||
366 | err = -ENOENT; | ||
367 | new_de = nilfs_find_entry(new_dir, new_dentry, &new_page); | ||
368 | if (!new_de) | ||
369 | goto out_dir; | ||
370 | inode_inc_link_count(old_inode); | ||
371 | nilfs_set_link(new_dir, new_de, new_page, old_inode); | ||
372 | new_inode->i_ctime = CURRENT_TIME; | ||
373 | if (dir_de) | ||
374 | drop_nlink(new_inode); | ||
375 | inode_dec_link_count(new_inode); | ||
376 | } else { | ||
377 | if (dir_de) { | ||
378 | err = -EMLINK; | ||
379 | if (new_dir->i_nlink >= NILFS_LINK_MAX) | ||
380 | goto out_dir; | ||
381 | } | ||
382 | inode_inc_link_count(old_inode); | ||
383 | err = nilfs_add_link(new_dentry, old_inode); | ||
384 | if (err) { | ||
385 | inode_dec_link_count(old_inode); | ||
386 | goto out_dir; | ||
387 | } | ||
388 | if (dir_de) | ||
389 | inode_inc_link_count(new_dir); | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * Like most other Unix systems, set the ctime for inodes on a | ||
394 | * rename. | ||
395 | * inode_dec_link_count() will mark the inode dirty. | ||
396 | */ | ||
397 | old_inode->i_ctime = CURRENT_TIME; | ||
398 | |||
399 | nilfs_delete_entry(old_de, old_page); | ||
400 | inode_dec_link_count(old_inode); | ||
401 | |||
402 | if (dir_de) { | ||
403 | nilfs_set_link(old_inode, dir_de, dir_page, new_dir); | ||
404 | inode_dec_link_count(old_dir); | ||
405 | } | ||
406 | |||
407 | err = nilfs_transaction_end(old_dir->i_sb, 1); | ||
408 | return err; | ||
409 | |||
410 | out_dir: | ||
411 | if (dir_de) { | ||
412 | kunmap(dir_page); | ||
413 | page_cache_release(dir_page); | ||
414 | } | ||
415 | out_old: | ||
416 | kunmap(old_page); | ||
417 | page_cache_release(old_page); | ||
418 | out: | ||
419 | nilfs_transaction_end(old_dir->i_sb, 0); | ||
420 | return err; | ||
421 | } | ||
422 | |||
423 | struct inode_operations nilfs_dir_inode_operations = { | ||
424 | .create = nilfs_create, | ||
425 | .lookup = nilfs_lookup, | ||
426 | .link = nilfs_link, | ||
427 | .unlink = nilfs_unlink, | ||
428 | .symlink = nilfs_symlink, | ||
429 | .mkdir = nilfs_mkdir, | ||
430 | .rmdir = nilfs_rmdir, | ||
431 | .mknod = nilfs_mknod, | ||
432 | .rename = nilfs_rename, | ||
433 | .setattr = nilfs_setattr, | ||
434 | .permission = nilfs_permission, | ||
435 | }; | ||
436 | |||
437 | struct inode_operations nilfs_special_inode_operations = { | ||
438 | .setattr = nilfs_setattr, | ||
439 | .permission = nilfs_permission, | ||
440 | }; | ||
441 | |||
442 | struct inode_operations nilfs_symlink_inode_operations = { | ||
443 | .readlink = generic_readlink, | ||
444 | .follow_link = page_follow_link_light, | ||
445 | .put_link = page_put_link, | ||
446 | }; | ||