Blame view
fs/ext2/namei.c
9.49 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" |
6d79125bb
|
38 |
#include "xip.h" |
1da177e4c
|
39 |
|
1da177e4c
|
40 41 42 43 44 |
static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode) { int err = ext2_add_link(dentry, inode); if (!err) { d_instantiate(dentry, inode); |
41080b5a2
|
45 |
unlock_new_inode(inode); |
1da177e4c
|
46 47 |
return 0; } |
a513b035e
|
48 |
inode_dec_link_count(inode); |
41080b5a2
|
49 |
unlock_new_inode(inode); |
1da177e4c
|
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
iput(inode); return err; } /* * Methods themselves. */ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode; ino_t ino; if (dentry->d_name.len > EXT2_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); |
a9885444f
|
65 |
ino = ext2_inode_by_name(dir, &dentry->d_name); |
1da177e4c
|
66 67 |
inode = NULL; if (ino) { |
52fcf7032
|
68 |
inode = ext2_iget(dir->i_sb, ino); |
a9049376e
|
69 70 71 72 73 |
if (inode == ERR_PTR(-ESTALE)) { ext2_error(dir->i_sb, __func__, "deleted inode referenced: %lu", (unsigned long) ino); return ERR_PTR(-EIO); |
4d6c13f87
|
74 |
} |
1da177e4c
|
75 |
} |
082a05c6f
|
76 |
return d_splice_alias(inode, dentry); |
1da177e4c
|
77 78 79 80 |
} struct dentry *ext2_get_parent(struct dentry *child) { |
a9885444f
|
81 82 |
struct qstr dotdot = {.name = "..", .len = 2}; unsigned long ino = ext2_inode_by_name(child->d_inode, &dotdot); |
1da177e4c
|
83 84 |
if (!ino) return ERR_PTR(-ENOENT); |
440037287
|
85 |
return d_obtain_alias(ext2_iget(child->d_inode->i_sb, ino)); |
1da177e4c
|
86 87 88 89 90 91 92 93 94 95 96 97 |
} /* * 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(). */ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd) { |
907f4554e
|
98 |
struct inode *inode; |
871a29315
|
99 |
dquot_initialize(dir); |
907f4554e
|
100 |
|
2a7dba391
|
101 |
inode = ext2_new_inode(dir, mode, &dentry->d_name); |
907f4554e
|
102 103 104 105 106 107 108 109 110 111 112 113 114 |
if (IS_ERR(inode)) return PTR_ERR(inode); inode->i_op = &ext2_file_inode_operations; if (ext2_use_xip(inode->i_sb)) { inode->i_mapping->a_ops = &ext2_aops_xip; inode->i_fop = &ext2_xip_file_operations; } else if (test_opt(inode->i_sb, NOBH)) { 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
|
115 |
} |
907f4554e
|
116 117 |
mark_inode_dirty(inode); return ext2_add_nondir(dentry, inode); |
1da177e4c
|
118 119 120 121 122 123 124 125 126 |
} static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev) { struct inode * inode; int err; if (!new_valid_dev(rdev)) return -EINVAL; |
871a29315
|
127 |
dquot_initialize(dir); |
907f4554e
|
128 |
|
2a7dba391
|
129 |
inode = ext2_new_inode (dir, mode, &dentry->d_name); |
1da177e4c
|
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
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; |
871a29315
|
152 |
dquot_initialize(dir); |
907f4554e
|
153 |
|
2a7dba391
|
154 |
inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO, &dentry->d_name); |
1da177e4c
|
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
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; 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; memcpy((char*)(EXT2_I(inode)->i_data),symname,l); inode->i_size = l-1; } mark_inode_dirty(inode); err = ext2_add_nondir(dentry, inode); out: return err; out_fail: |
a513b035e
|
182 |
inode_dec_link_count(inode); |
41080b5a2
|
183 |
unlock_new_inode(inode); |
1da177e4c
|
184 185 186 187 188 189 190 191 |
iput (inode); goto out; } static int ext2_link (struct dentry * old_dentry, struct inode * dir, struct dentry *dentry) { struct inode *inode = old_dentry->d_inode; |
41080b5a2
|
192 |
int err; |
1da177e4c
|
193 194 195 |
if (inode->i_nlink >= EXT2_LINK_MAX) return -EMLINK; |
871a29315
|
196 |
dquot_initialize(dir); |
907f4554e
|
197 |
|
1da177e4c
|
198 |
inode->i_ctime = CURRENT_TIME_SEC; |
a513b035e
|
199 |
inode_inc_link_count(inode); |
7de9c6ee3
|
200 |
ihold(inode); |
1da177e4c
|
201 |
|
41080b5a2
|
202 203 204 205 206 207 208 209 |
err = ext2_add_link(dentry, inode); if (!err) { d_instantiate(dentry, inode); return 0; } inode_dec_link_count(inode); iput(inode); return err; |
1da177e4c
|
210 211 212 213 214 215 216 217 218 |
} static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode) { struct inode * inode; int err = -EMLINK; if (dir->i_nlink >= EXT2_LINK_MAX) goto out; |
871a29315
|
219 |
dquot_initialize(dir); |
907f4554e
|
220 |
|
a513b035e
|
221 |
inode_inc_link_count(dir); |
1da177e4c
|
222 |
|
2a7dba391
|
223 |
inode = ext2_new_inode(dir, S_IFDIR | mode, &dentry->d_name); |
1da177e4c
|
224 225 226 227 228 229 230 231 232 233 |
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
|
234 |
inode_inc_link_count(inode); |
1da177e4c
|
235 236 237 238 239 240 241 242 243 244 |
err = ext2_make_empty(inode, dir); if (err) goto out_fail; err = ext2_add_link(dentry, inode); if (err) goto out_fail; d_instantiate(dentry, inode); |
41080b5a2
|
245 |
unlock_new_inode(inode); |
1da177e4c
|
246 247 248 249 |
out: return err; out_fail: |
a513b035e
|
250 251 |
inode_dec_link_count(inode); inode_dec_link_count(inode); |
41080b5a2
|
252 |
unlock_new_inode(inode); |
1da177e4c
|
253 254 |
iput(inode); out_dir: |
a513b035e
|
255 |
inode_dec_link_count(dir); |
1da177e4c
|
256 257 258 259 260 261 262 263 264 |
goto out; } static int ext2_unlink(struct inode * dir, struct dentry *dentry) { struct inode * inode = dentry->d_inode; struct ext2_dir_entry_2 * de; struct page * page; int err = -ENOENT; |
871a29315
|
265 |
dquot_initialize(dir); |
907f4554e
|
266 |
|
a9885444f
|
267 |
de = ext2_find_entry (dir, &dentry->d_name, &page); |
1da177e4c
|
268 269 270 271 272 273 274 275 |
if (!de) goto out; err = ext2_delete_entry (de, page); if (err) goto out; inode->i_ctime = dir->i_ctime; |
a513b035e
|
276 |
inode_dec_link_count(inode); |
1da177e4c
|
277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
err = 0; out: return err; } static int ext2_rmdir (struct inode * dir, struct dentry *dentry) { struct inode * inode = dentry->d_inode; int err = -ENOTEMPTY; if (ext2_empty_dir(inode)) { err = ext2_unlink(dir, dentry); if (!err) { inode->i_size = 0; |
a513b035e
|
291 292 |
inode_dec_link_count(inode); inode_dec_link_count(dir); |
1da177e4c
|
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
} } return err; } static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, struct inode * new_dir, struct dentry * new_dentry ) { struct inode * old_inode = old_dentry->d_inode; struct inode * new_inode = new_dentry->d_inode; struct page * dir_page = NULL; struct ext2_dir_entry_2 * dir_de = NULL; struct page * old_page; struct ext2_dir_entry_2 * old_de; int err = -ENOENT; |
871a29315
|
308 309 |
dquot_initialize(old_dir); dquot_initialize(new_dir); |
907f4554e
|
310 |
|
a9885444f
|
311 |
old_de = ext2_find_entry (old_dir, &old_dentry->d_name, &old_page); |
1da177e4c
|
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
if (!old_de) goto out; 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
|
331 |
new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page); |
1da177e4c
|
332 333 |
if (!new_de) goto out_dir; |
39fe7557b
|
334 |
ext2_set_link(new_dir, new_de, new_page, old_inode, 1); |
1da177e4c
|
335 336 |
new_inode->i_ctime = CURRENT_TIME_SEC; if (dir_de) |
9a53c3a78
|
337 |
drop_nlink(new_inode); |
a513b035e
|
338 |
inode_dec_link_count(new_inode); |
1da177e4c
|
339 340 341 342 343 344 |
} else { if (dir_de) { err = -EMLINK; if (new_dir->i_nlink >= EXT2_LINK_MAX) goto out_dir; } |
1da177e4c
|
345 |
err = ext2_add_link(new_dentry, old_inode); |
e8a80c6f7
|
346 |
if (err) |
1da177e4c
|
347 |
goto out_dir; |
1da177e4c
|
348 |
if (dir_de) |
a513b035e
|
349 |
inode_inc_link_count(new_dir); |
1da177e4c
|
350 351 352 353 354 |
} /* * Like most other Unix systems, set the ctime for inodes on a * rename. |
1da177e4c
|
355 356 |
*/ old_inode->i_ctime = CURRENT_TIME_SEC; |
e8a80c6f7
|
357 |
mark_inode_dirty(old_inode); |
1da177e4c
|
358 359 |
ext2_delete_entry (old_de, old_page); |
1da177e4c
|
360 361 |
if (dir_de) { |
39fe7557b
|
362 363 |
if (old_dir != new_dir) ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0); |
9de6886ec
|
364 365 366 367 |
else { kunmap(dir_page); page_cache_release(dir_page); } |
a513b035e
|
368 |
inode_dec_link_count(old_dir); |
1da177e4c
|
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
} return 0; out_dir: if (dir_de) { kunmap(dir_page); page_cache_release(dir_page); } out_old: kunmap(old_page); page_cache_release(old_page); out: return err; } |
754661f14
|
384 |
const struct inode_operations ext2_dir_inode_operations = { |
1da177e4c
|
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 |
.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 .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = ext2_listxattr, .removexattr = generic_removexattr, #endif .setattr = ext2_setattr, |
4e34e719e
|
401 |
.get_acl = ext2_get_acl, |
1da177e4c
|
402 |
}; |
754661f14
|
403 |
const struct inode_operations ext2_special_inode_operations = { |
1da177e4c
|
404 405 406 407 408 409 410 |
#ifdef CONFIG_EXT2_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = ext2_listxattr, .removexattr = generic_removexattr, #endif .setattr = ext2_setattr, |
4e34e719e
|
411 |
.get_acl = ext2_get_acl, |
1da177e4c
|
412 |
}; |