Blame view
fs/ext2/namei.c
9.86 KB
1da177e4c
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/* * linux/fs/ext2/namei.c * * Rewrite to pagecache. Almost all code had been changed, so blame me * if the things go wrong. Please, send bug reports to * viro@parcelfarce.linux.theplanet.co.uk * * Stuff here is basically a glue between the VFS and generic UNIXish * filesystem that keeps everything in pagecache. All knowledge of the * directory layout is in fs/ext2/dir.c - it turned out to be easily separatable * and it's easier to debug that way. In principle we might want to * generalize that a bit and turn it into a library. Or not. * * The only non-static object here is ext2_dir_inode_operations. * * TODO: get rid of kmap() use, add readahead. * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) * Laboratoire MASI - Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * * from * * linux/fs/minix/namei.c * * Copyright (C) 1991, 1992 Linus Torvalds * * Big-endian to little-endian byte-swapping/bitmaps by * David S. Miller (davem@caip.rutgers.edu), 1995 */ #include <linux/pagemap.h> |
907f4554e
|
34 |
#include <linux/quotaops.h> |
1da177e4c
|
35 36 37 |
#include "ext2.h" #include "xattr.h" #include "acl.h" |
1da177e4c
|
38 39 40 41 |
static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode) { int err = ext2_add_link(dentry, inode); if (!err) { |
41080b5a2
|
42 |
unlock_new_inode(inode); |
8fc37ec54
|
43 |
d_instantiate(dentry, inode); |
1da177e4c
|
44 45 |
return 0; } |
a513b035e
|
46 |
inode_dec_link_count(inode); |
41080b5a2
|
47 |
unlock_new_inode(inode); |
1da177e4c
|
48 49 50 51 52 53 54 |
iput(inode); return err; } /* * Methods themselves. */ |
00cd8dd3b
|
55 |
static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags) |
1da177e4c
|
56 57 58 59 60 61 |
{ struct inode * inode; ino_t ino; if (dentry->d_name.len > EXT2_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); |
a9885444f
|
62 |
ino = ext2_inode_by_name(dir, &dentry->d_name); |
1da177e4c
|
63 64 |
inode = NULL; if (ino) { |
52fcf7032
|
65 |
inode = ext2_iget(dir->i_sb, ino); |
a9049376e
|
66 67 68 69 70 |
if (inode == ERR_PTR(-ESTALE)) { ext2_error(dir->i_sb, __func__, "deleted inode referenced: %lu", (unsigned long) ino); return ERR_PTR(-EIO); |
4d6c13f87
|
71 |
} |
1da177e4c
|
72 |
} |
082a05c6f
|
73 |
return d_splice_alias(inode, dentry); |
1da177e4c
|
74 75 76 77 |
} struct dentry *ext2_get_parent(struct dentry *child) { |
26fe57502
|
78 |
struct qstr dotdot = QSTR_INIT("..", 2); |
2b0143b5c
|
79 |
unsigned long ino = ext2_inode_by_name(d_inode(child), &dotdot); |
1da177e4c
|
80 81 |
if (!ino) return ERR_PTR(-ENOENT); |
fc64005c9
|
82 |
return d_obtain_alias(ext2_iget(child->d_sb, ino)); |
1da177e4c
|
83 84 85 86 87 88 89 90 91 92 |
} /* * By the time this is called, we already have created * the directory cache entry for the new file, but it * is so far negative - it has no inode. * * If the create succeeds, we fill in the inode information * with d_instantiate(). */ |
ebfc3b49a
|
93 |
static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, bool excl) |
1da177e4c
|
94 |
{ |
907f4554e
|
95 |
struct inode *inode; |
c2edb305d
|
96 |
int err; |
907f4554e
|
97 |
|
c2edb305d
|
98 99 100 |
err = dquot_initialize(dir); if (err) return err; |
907f4554e
|
101 |
|
2a7dba391
|
102 |
inode = ext2_new_inode(dir, mode, &dentry->d_name); |
907f4554e
|
103 104 105 106 |
if (IS_ERR(inode)) return PTR_ERR(inode); inode->i_op = &ext2_file_inode_operations; |
be64f884b
|
107 |
if (test_opt(inode->i_sb, NOBH)) { |
907f4554e
|
108 109 110 111 112 |
inode->i_mapping->a_ops = &ext2_nobh_aops; inode->i_fop = &ext2_file_operations; } else { inode->i_mapping->a_ops = &ext2_aops; inode->i_fop = &ext2_file_operations; |
1da177e4c
|
113 |
} |
907f4554e
|
114 115 |
mark_inode_dirty(inode); return ext2_add_nondir(dentry, inode); |
1da177e4c
|
116 |
} |
60545d0d4
|
117 118 119 120 121 122 123 |
static int ext2_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode = ext2_new_inode(dir, mode, NULL); if (IS_ERR(inode)) return PTR_ERR(inode); inode->i_op = &ext2_file_inode_operations; |
be64f884b
|
124 |
if (test_opt(inode->i_sb, NOBH)) { |
60545d0d4
|
125 126 127 128 129 130 131 132 133 134 135 |
inode->i_mapping->a_ops = &ext2_nobh_aops; inode->i_fop = &ext2_file_operations; } else { inode->i_mapping->a_ops = &ext2_aops; inode->i_fop = &ext2_file_operations; } mark_inode_dirty(inode); d_tmpfile(dentry, inode); unlock_new_inode(inode); return 0; } |
1a67aafb5
|
136 |
static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev) |
1da177e4c
|
137 138 139 |
{ struct inode * inode; int err; |
c2edb305d
|
140 141 142 |
err = dquot_initialize(dir); if (err) return err; |
907f4554e
|
143 |
|
2a7dba391
|
144 |
inode = ext2_new_inode (dir, mode, &dentry->d_name); |
1da177e4c
|
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
err = PTR_ERR(inode); if (!IS_ERR(inode)) { init_special_inode(inode, inode->i_mode, rdev); #ifdef CONFIG_EXT2_FS_XATTR inode->i_op = &ext2_special_inode_operations; #endif mark_inode_dirty(inode); err = ext2_add_nondir(dentry, inode); } return err; } static int ext2_symlink (struct inode * dir, struct dentry * dentry, const char * symname) { struct super_block * sb = dir->i_sb; int err = -ENAMETOOLONG; unsigned l = strlen(symname)+1; struct inode * inode; if (l > sb->s_blocksize) goto out; |
c2edb305d
|
167 168 169 |
err = dquot_initialize(dir); if (err) goto out; |
907f4554e
|
170 |
|
2a7dba391
|
171 |
inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO, &dentry->d_name); |
1da177e4c
|
172 173 174 175 176 177 178 |
err = PTR_ERR(inode); if (IS_ERR(inode)) goto out; if (l > sizeof (EXT2_I(inode)->i_data)) { /* slow symlink */ inode->i_op = &ext2_symlink_inode_operations; |
21fc61c73
|
179 |
inode_nohighmem(inode); |
1da177e4c
|
180 181 182 183 184 185 186 187 188 189 |
if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_nobh_aops; else inode->i_mapping->a_ops = &ext2_aops; err = page_symlink(inode, symname, l); if (err) goto out_fail; } else { /* fast symlink */ inode->i_op = &ext2_fast_symlink_inode_operations; |
cbe0fa385
|
190 191 |
inode->i_link = (char*)EXT2_I(inode)->i_data; memcpy(inode->i_link, symname, l); |
1da177e4c
|
192 193 194 195 196 197 198 199 200 |
inode->i_size = l-1; } mark_inode_dirty(inode); err = ext2_add_nondir(dentry, inode); out: return err; out_fail: |
a513b035e
|
201 |
inode_dec_link_count(inode); |
41080b5a2
|
202 |
unlock_new_inode(inode); |
1da177e4c
|
203 204 205 206 207 208 209 |
iput (inode); goto out; } static int ext2_link (struct dentry * old_dentry, struct inode * dir, struct dentry *dentry) { |
2b0143b5c
|
210 |
struct inode *inode = d_inode(old_dentry); |
41080b5a2
|
211 |
int err; |
1da177e4c
|
212 |
|
c2edb305d
|
213 214 215 |
err = dquot_initialize(dir); if (err) return err; |
907f4554e
|
216 |
|
02027d42c
|
217 |
inode->i_ctime = current_time(inode); |
a513b035e
|
218 |
inode_inc_link_count(inode); |
7de9c6ee3
|
219 |
ihold(inode); |
1da177e4c
|
220 |
|
41080b5a2
|
221 222 223 224 225 226 227 228 |
err = ext2_add_link(dentry, inode); if (!err) { d_instantiate(dentry, inode); return 0; } inode_dec_link_count(inode); iput(inode); return err; |
1da177e4c
|
229 |
} |
18bb1db3e
|
230 |
static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) |
1da177e4c
|
231 232 |
{ struct inode * inode; |
8de527787
|
233 |
int err; |
1da177e4c
|
234 |
|
c2edb305d
|
235 236 237 |
err = dquot_initialize(dir); if (err) return err; |
907f4554e
|
238 |
|
a513b035e
|
239 |
inode_inc_link_count(dir); |
1da177e4c
|
240 |
|
2a7dba391
|
241 |
inode = ext2_new_inode(dir, S_IFDIR | mode, &dentry->d_name); |
1da177e4c
|
242 243 244 245 246 247 248 249 250 251 |
err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_dir; inode->i_op = &ext2_dir_inode_operations; inode->i_fop = &ext2_dir_operations; if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_nobh_aops; else inode->i_mapping->a_ops = &ext2_aops; |
a513b035e
|
252 |
inode_inc_link_count(inode); |
1da177e4c
|
253 254 255 256 257 258 259 260 |
err = ext2_make_empty(inode, dir); if (err) goto out_fail; err = ext2_add_link(dentry, inode); if (err) goto out_fail; |
41080b5a2
|
261 |
unlock_new_inode(inode); |
8fc37ec54
|
262 |
d_instantiate(dentry, inode); |
1da177e4c
|
263 264 265 266 |
out: return err; out_fail: |
a513b035e
|
267 268 |
inode_dec_link_count(inode); inode_dec_link_count(inode); |
41080b5a2
|
269 |
unlock_new_inode(inode); |
1da177e4c
|
270 271 |
iput(inode); out_dir: |
a513b035e
|
272 |
inode_dec_link_count(dir); |
1da177e4c
|
273 274 275 276 277 |
goto out; } static int ext2_unlink(struct inode * dir, struct dentry *dentry) { |
2b0143b5c
|
278 |
struct inode * inode = d_inode(dentry); |
1da177e4c
|
279 280 |
struct ext2_dir_entry_2 * de; struct page * page; |
c2edb305d
|
281 |
int err; |
1da177e4c
|
282 |
|
c2edb305d
|
283 284 285 |
err = dquot_initialize(dir); if (err) goto out; |
907f4554e
|
286 |
|
a9885444f
|
287 |
de = ext2_find_entry (dir, &dentry->d_name, &page); |
c2edb305d
|
288 289 |
if (!de) { err = -ENOENT; |
1da177e4c
|
290 |
goto out; |
c2edb305d
|
291 |
} |
1da177e4c
|
292 293 294 295 296 297 |
err = ext2_delete_entry (de, page); if (err) goto out; inode->i_ctime = dir->i_ctime; |
a513b035e
|
298 |
inode_dec_link_count(inode); |
1da177e4c
|
299 300 301 302 303 304 305 |
err = 0; out: return err; } static int ext2_rmdir (struct inode * dir, struct dentry *dentry) { |
2b0143b5c
|
306 |
struct inode * inode = d_inode(dentry); |
1da177e4c
|
307 308 309 310 311 312 |
int err = -ENOTEMPTY; if (ext2_empty_dir(inode)) { err = ext2_unlink(dir, dentry); if (!err) { inode->i_size = 0; |
a513b035e
|
313 314 |
inode_dec_link_count(inode); inode_dec_link_count(dir); |
1da177e4c
|
315 316 317 318 319 320 |
} } return err; } static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, |
f03b8ad8d
|
321 322 |
struct inode * new_dir, struct dentry * new_dentry, unsigned int flags) |
1da177e4c
|
323 |
{ |
2b0143b5c
|
324 325 |
struct inode * old_inode = d_inode(old_dentry); struct inode * new_inode = d_inode(new_dentry); |
1da177e4c
|
326 327 328 329 |
struct page * dir_page = NULL; struct ext2_dir_entry_2 * dir_de = NULL; struct page * old_page; struct ext2_dir_entry_2 * old_de; |
c2edb305d
|
330 |
int err; |
1da177e4c
|
331 |
|
f03b8ad8d
|
332 333 |
if (flags & ~RENAME_NOREPLACE) return -EINVAL; |
c2edb305d
|
334 335 336 337 338 339 340 |
err = dquot_initialize(old_dir); if (err) goto out; err = dquot_initialize(new_dir); if (err) goto out; |
907f4554e
|
341 |
|
a9885444f
|
342 |
old_de = ext2_find_entry (old_dir, &old_dentry->d_name, &old_page); |
c2edb305d
|
343 344 |
if (!old_de) { err = -ENOENT; |
1da177e4c
|
345 |
goto out; |
c2edb305d
|
346 |
} |
1da177e4c
|
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
if (S_ISDIR(old_inode->i_mode)) { err = -EIO; dir_de = ext2_dotdot(old_inode, &dir_page); if (!dir_de) goto out_old; } if (new_inode) { struct page *new_page; struct ext2_dir_entry_2 *new_de; err = -ENOTEMPTY; if (dir_de && !ext2_empty_dir (new_inode)) goto out_dir; err = -ENOENT; |
a9885444f
|
364 |
new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page); |
1da177e4c
|
365 366 |
if (!new_de) goto out_dir; |
39fe7557b
|
367 |
ext2_set_link(new_dir, new_de, new_page, old_inode, 1); |
02027d42c
|
368 |
new_inode->i_ctime = current_time(new_inode); |
1da177e4c
|
369 |
if (dir_de) |
9a53c3a78
|
370 |
drop_nlink(new_inode); |
a513b035e
|
371 |
inode_dec_link_count(new_inode); |
1da177e4c
|
372 |
} else { |
1da177e4c
|
373 |
err = ext2_add_link(new_dentry, old_inode); |
e8a80c6f7
|
374 |
if (err) |
1da177e4c
|
375 |
goto out_dir; |
1da177e4c
|
376 |
if (dir_de) |
a513b035e
|
377 |
inode_inc_link_count(new_dir); |
1da177e4c
|
378 379 380 381 382 |
} /* * Like most other Unix systems, set the ctime for inodes on a * rename. |
1da177e4c
|
383 |
*/ |
02027d42c
|
384 |
old_inode->i_ctime = current_time(old_inode); |
e8a80c6f7
|
385 |
mark_inode_dirty(old_inode); |
1da177e4c
|
386 387 |
ext2_delete_entry (old_de, old_page); |
1da177e4c
|
388 389 |
if (dir_de) { |
39fe7557b
|
390 391 |
if (old_dir != new_dir) ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0); |
9de6886ec
|
392 393 |
else { kunmap(dir_page); |
09cbfeaf1
|
394 |
put_page(dir_page); |
9de6886ec
|
395 |
} |
a513b035e
|
396 |
inode_dec_link_count(old_dir); |
1da177e4c
|
397 398 399 400 401 402 403 |
} return 0; out_dir: if (dir_de) { kunmap(dir_page); |
09cbfeaf1
|
404 |
put_page(dir_page); |
1da177e4c
|
405 406 407 |
} out_old: kunmap(old_page); |
09cbfeaf1
|
408 |
put_page(old_page); |
1da177e4c
|
409 410 411 |
out: return err; } |
754661f14
|
412 |
const struct inode_operations ext2_dir_inode_operations = { |
1da177e4c
|
413 414 415 416 417 418 419 420 421 422 |
.create = ext2_create, .lookup = ext2_lookup, .link = ext2_link, .unlink = ext2_unlink, .symlink = ext2_symlink, .mkdir = ext2_mkdir, .rmdir = ext2_rmdir, .mknod = ext2_mknod, .rename = ext2_rename, #ifdef CONFIG_EXT2_FS_XATTR |
1da177e4c
|
423 |
.listxattr = ext2_listxattr, |
1da177e4c
|
424 425 |
#endif .setattr = ext2_setattr, |
4e34e719e
|
426 |
.get_acl = ext2_get_acl, |
64e178a71
|
427 |
.set_acl = ext2_set_acl, |
60545d0d4
|
428 |
.tmpfile = ext2_tmpfile, |
1da177e4c
|
429 |
}; |
754661f14
|
430 |
const struct inode_operations ext2_special_inode_operations = { |
1da177e4c
|
431 |
#ifdef CONFIG_EXT2_FS_XATTR |
1da177e4c
|
432 |
.listxattr = ext2_listxattr, |
1da177e4c
|
433 434 |
#endif .setattr = ext2_setattr, |
4e34e719e
|
435 |
.get_acl = ext2_get_acl, |
64e178a71
|
436 |
.set_acl = ext2_set_acl, |
1da177e4c
|
437 |
}; |