aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-04-06 22:01:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-07 11:31:15 -0400
commitd25006523d0b9e49fd097b2e974e7c8c05bd7f54 (patch)
treeff251f5854012ba8b6000745a24d50eda7e3dbd8 /fs
parent2ba466d74ed74f073257f86e61519cb8f8f46184 (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')
-rw-r--r--fs/nilfs2/namei.c446
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
45static 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
61static struct dentry *
62nilfs_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
80struct 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 */
107static 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
130static int
131nilfs_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
154static 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);
186out:
187 err2 = nilfs_transaction_end(dir->i_sb, !err);
188 return err ? : err2;
189
190out_fail:
191 inode_dec_link_count(inode);
192 iput(inode);
193 goto out;
194}
195
196static 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
219static 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);
254out:
255 err2 = nilfs_transaction_end(dir->i_sb, !err);
256 return err ? : err2;
257
258out_fail:
259 inode_dec_link_count(inode);
260 inode_dec_link_count(inode);
261 iput(inode);
262out_dir:
263 inode_dec_link_count(dir);
264 goto out;
265}
266
267static 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;
302out:
303 err2 = nilfs_transaction_end(dir->i_sb, !err);
304 return err ? : err2;
305}
306
307static 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
330static 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
410out_dir:
411 if (dir_de) {
412 kunmap(dir_page);
413 page_cache_release(dir_page);
414 }
415out_old:
416 kunmap(old_page);
417 page_cache_release(old_page);
418out:
419 nilfs_transaction_end(old_dir->i_sb, 0);
420 return err;
421}
422
423struct 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
437struct inode_operations nilfs_special_inode_operations = {
438 .setattr = nilfs_setattr,
439 .permission = nilfs_permission,
440};
441
442struct inode_operations nilfs_symlink_inode_operations = {
443 .readlink = generic_readlink,
444 .follow_link = page_follow_link_light,
445 .put_link = page_put_link,
446};