diff options
author | Jan Harkes <jaharkes@cs.cmu.edu> | 2007-07-19 04:48:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 13:04:48 -0400 |
commit | d728900cd5502927158db747c653007cf72e2e49 (patch) | |
tree | 34e641ec49e42265e01e0fe38be6bc54abfb11d0 | |
parent | 56ee3547940f895a2cf20f2ac462fbeaee55fa2a (diff) |
coda: fix nlink updates for directories
The Coda client sets the directory link count to 1 when it isn't sure how many
subdirectories we have. In this case we shouldn't change the link count in
the kernel when a subdirectory is created or removed.
Signed-off-by: Jan Harkes <jaharkes@cs.cmu.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/coda/dir.c | 106 |
1 files changed, 60 insertions, 46 deletions
diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 898a86dde8f5..56a3b76b91ca 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c | |||
@@ -173,12 +173,11 @@ int coda_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
173 | 173 | ||
174 | out: | 174 | out: |
175 | unlock_kernel(); | 175 | unlock_kernel(); |
176 | 176 | return error; | |
177 | return error; | ||
178 | } | 177 | } |
179 | 178 | ||
180 | 179 | ||
181 | static inline void coda_dir_changed(struct inode *dir, int link) | 180 | static inline void coda_dir_update_mtime(struct inode *dir) |
182 | { | 181 | { |
183 | #ifdef REQUERY_VENUS_FOR_MTIME | 182 | #ifdef REQUERY_VENUS_FOR_MTIME |
184 | /* invalidate the directory cnode's attributes so we refetch the | 183 | /* invalidate the directory cnode's attributes so we refetch the |
@@ -186,12 +185,27 @@ static inline void coda_dir_changed(struct inode *dir, int link) | |||
186 | coda_flag_inode(dir, C_VATTR); | 185 | coda_flag_inode(dir, C_VATTR); |
187 | #else | 186 | #else |
188 | /* optimistically we can also act as if our nose bleeds. The | 187 | /* optimistically we can also act as if our nose bleeds. The |
189 | * granularity of the mtime is coarse anyways so we might actually be | 188 | * granularity of the mtime is coarse anyways so we might actually be |
190 | * right most of the time. Note: we only do this for directories. */ | 189 | * right most of the time. Note: we only do this for directories. */ |
191 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; | 190 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; |
192 | #endif | 191 | #endif |
193 | if (link) | 192 | } |
194 | dir->i_nlink += link; | 193 | |
194 | /* we have to wrap inc_nlink/drop_nlink because sometimes userspace uses a | ||
195 | * trick to fool GNU find's optimizations. If we can't be sure of the link | ||
196 | * (because of volume mount points) we set i_nlink to 1 which forces find | ||
197 | * to consider every child as a possible directory. We should also never | ||
198 | * see an increment or decrement for deleted directories where i_nlink == 0 */ | ||
199 | static inline void coda_dir_inc_nlink(struct inode *dir) | ||
200 | { | ||
201 | if (dir->i_nlink >= 2) | ||
202 | inc_nlink(dir); | ||
203 | } | ||
204 | |||
205 | static inline void coda_dir_drop_nlink(struct inode *dir) | ||
206 | { | ||
207 | if (dir->i_nlink > 2) | ||
208 | drop_nlink(dir); | ||
195 | } | 209 | } |
196 | 210 | ||
197 | /* creation routines: create, mknod, mkdir, link, symlink */ | 211 | /* creation routines: create, mknod, mkdir, link, symlink */ |
@@ -229,10 +243,10 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode, struct na | |||
229 | } | 243 | } |
230 | 244 | ||
231 | /* invalidate the directory cnode's attributes */ | 245 | /* invalidate the directory cnode's attributes */ |
232 | coda_dir_changed(dir, 0); | 246 | coda_dir_update_mtime(dir); |
233 | unlock_kernel(); | 247 | unlock_kernel(); |
234 | d_instantiate(de, inode); | 248 | d_instantiate(de, inode); |
235 | return 0; | 249 | return 0; |
236 | } | 250 | } |
237 | 251 | ||
238 | static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) | 252 | static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) |
@@ -268,12 +282,13 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) | |||
268 | d_drop(de); | 282 | d_drop(de); |
269 | return PTR_ERR(inode); | 283 | return PTR_ERR(inode); |
270 | } | 284 | } |
271 | 285 | ||
272 | /* invalidate the directory cnode's attributes */ | 286 | /* invalidate the directory cnode's attributes */ |
273 | coda_dir_changed(dir, 1); | 287 | coda_dir_inc_nlink(dir); |
288 | coda_dir_update_mtime(dir); | ||
274 | unlock_kernel(); | 289 | unlock_kernel(); |
275 | d_instantiate(de, inode); | 290 | d_instantiate(de, inode); |
276 | return 0; | 291 | return 0; |
277 | } | 292 | } |
278 | 293 | ||
279 | /* try to make de an entry in dir_inodde linked to source_de */ | 294 | /* try to make de an entry in dir_inodde linked to source_de */ |
@@ -296,16 +311,16 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode, | |||
296 | error = venus_link(dir_inode->i_sb, coda_i2f(inode), | 311 | error = venus_link(dir_inode->i_sb, coda_i2f(inode), |
297 | coda_i2f(dir_inode), (const char *)name, len); | 312 | coda_i2f(dir_inode), (const char *)name, len); |
298 | 313 | ||
299 | if (error) { | 314 | if (error) { |
300 | d_drop(de); | 315 | d_drop(de); |
301 | goto out; | 316 | goto out; |
302 | } | 317 | } |
303 | 318 | ||
304 | coda_dir_changed(dir_inode, 0); | 319 | coda_dir_update_mtime(dir_inode); |
305 | atomic_inc(&inode->i_count); | 320 | atomic_inc(&inode->i_count); |
306 | d_instantiate(de, inode); | 321 | d_instantiate(de, inode); |
307 | inc_nlink(inode); | 322 | inc_nlink(inode); |
308 | 323 | ||
309 | out: | 324 | out: |
310 | unlock_kernel(); | 325 | unlock_kernel(); |
311 | return(error); | 326 | return(error); |
@@ -336,18 +351,18 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de, | |||
336 | 351 | ||
337 | /* | 352 | /* |
338 | * This entry is now negative. Since we do not create | 353 | * This entry is now negative. Since we do not create |
339 | * an inode for the entry we have to drop it. | 354 | * an inode for the entry we have to drop it. |
340 | */ | 355 | */ |
341 | d_drop(de); | 356 | d_drop(de); |
342 | error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len, | 357 | error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len, |
343 | symname, symlen); | 358 | symname, symlen); |
344 | 359 | ||
345 | /* mtime is no good anymore */ | 360 | /* mtime is no good anymore */ |
346 | if ( !error ) | 361 | if ( !error ) |
347 | coda_dir_changed(dir_inode, 0); | 362 | coda_dir_update_mtime(dir_inode); |
348 | 363 | ||
349 | unlock_kernel(); | 364 | unlock_kernel(); |
350 | return error; | 365 | return error; |
351 | } | 366 | } |
352 | 367 | ||
353 | /* destruction routines: unlink, rmdir */ | 368 | /* destruction routines: unlink, rmdir */ |
@@ -360,17 +375,16 @@ int coda_unlink(struct inode *dir, struct dentry *de) | |||
360 | lock_kernel(); | 375 | lock_kernel(); |
361 | coda_vfs_stat.unlink++; | 376 | coda_vfs_stat.unlink++; |
362 | 377 | ||
363 | error = venus_remove(dir->i_sb, coda_i2f(dir), name, len); | 378 | error = venus_remove(dir->i_sb, coda_i2f(dir), name, len); |
364 | if ( error ) { | 379 | if ( error ) { |
365 | unlock_kernel(); | 380 | unlock_kernel(); |
366 | return error; | 381 | return error; |
367 | } | 382 | } |
368 | 383 | ||
369 | coda_dir_changed(dir, 0); | 384 | coda_dir_update_mtime(dir); |
370 | drop_nlink(de->d_inode); | 385 | drop_nlink(de->d_inode); |
371 | unlock_kernel(); | 386 | unlock_kernel(); |
372 | 387 | return 0; | |
373 | return 0; | ||
374 | } | 388 | } |
375 | 389 | ||
376 | int coda_rmdir(struct inode *dir, struct dentry *de) | 390 | int coda_rmdir(struct inode *dir, struct dentry *de) |
@@ -388,49 +402,49 @@ int coda_rmdir(struct inode *dir, struct dentry *de) | |||
388 | } | 402 | } |
389 | error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len); | 403 | error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len); |
390 | 404 | ||
391 | if ( error ) { | 405 | if ( error ) { |
392 | unlock_kernel(); | 406 | unlock_kernel(); |
393 | return error; | 407 | return error; |
394 | } | 408 | } |
395 | 409 | ||
396 | coda_dir_changed(dir, -1); | 410 | coda_dir_drop_nlink(dir); |
411 | coda_dir_update_mtime(dir); | ||
397 | drop_nlink(de->d_inode); | 412 | drop_nlink(de->d_inode); |
398 | d_delete(de); | 413 | d_delete(de); |
399 | unlock_kernel(); | 414 | unlock_kernel(); |
400 | 415 | return 0; | |
401 | return 0; | ||
402 | } | 416 | } |
403 | 417 | ||
404 | /* rename */ | 418 | /* rename */ |
405 | static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, | 419 | static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, |
406 | struct inode *new_dir, struct dentry *new_dentry) | 420 | struct inode *new_dir, struct dentry *new_dentry) |
407 | { | 421 | { |
408 | const char *old_name = old_dentry->d_name.name; | 422 | const char *old_name = old_dentry->d_name.name; |
409 | const char *new_name = new_dentry->d_name.name; | 423 | const char *new_name = new_dentry->d_name.name; |
410 | int old_length = old_dentry->d_name.len; | 424 | int old_length = old_dentry->d_name.len; |
411 | int new_length = new_dentry->d_name.len; | 425 | int new_length = new_dentry->d_name.len; |
412 | int link_adjust = 0; | 426 | int error; |
413 | int error; | ||
414 | 427 | ||
415 | lock_kernel(); | 428 | lock_kernel(); |
416 | coda_vfs_stat.rename++; | 429 | coda_vfs_stat.rename++; |
417 | 430 | ||
418 | error = venus_rename(old_dir->i_sb, coda_i2f(old_dir), | 431 | error = venus_rename(old_dir->i_sb, coda_i2f(old_dir), |
419 | coda_i2f(new_dir), old_length, new_length, | 432 | coda_i2f(new_dir), old_length, new_length, |
420 | (const char *) old_name, (const char *)new_name); | 433 | (const char *) old_name, (const char *)new_name); |
421 | 434 | ||
422 | if ( !error ) { | 435 | if ( !error ) { |
423 | if ( new_dentry->d_inode ) { | 436 | if ( new_dentry->d_inode ) { |
424 | if ( S_ISDIR(new_dentry->d_inode->i_mode) ) | 437 | if ( S_ISDIR(new_dentry->d_inode->i_mode) ) { |
425 | link_adjust = 1; | 438 | coda_dir_drop_nlink(old_dir); |
426 | 439 | coda_dir_inc_nlink(new_dir); | |
427 | coda_dir_changed(old_dir, -link_adjust); | 440 | } |
428 | coda_dir_changed(new_dir, link_adjust); | 441 | coda_dir_update_mtime(old_dir); |
442 | coda_dir_update_mtime(new_dir); | ||
429 | coda_flag_inode(new_dentry->d_inode, C_VATTR); | 443 | coda_flag_inode(new_dentry->d_inode, C_VATTR); |
430 | } else { | 444 | } else { |
431 | coda_flag_inode(old_dir, C_VATTR); | 445 | coda_flag_inode(old_dir, C_VATTR); |
432 | coda_flag_inode(new_dir, C_VATTR); | 446 | coda_flag_inode(new_dir, C_VATTR); |
433 | } | 447 | } |
434 | } | 448 | } |
435 | unlock_kernel(); | 449 | unlock_kernel(); |
436 | 450 | ||