aboutsummaryrefslogtreecommitdiffstats
path: root/fs/coda/dir.c
diff options
context:
space:
mode:
authorJan Harkes <jaharkes@cs.cmu.edu>2007-07-19 04:48:43 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-19 13:04:48 -0400
commitd728900cd5502927158db747c653007cf72e2e49 (patch)
tree34e641ec49e42265e01e0fe38be6bc54abfb11d0 /fs/coda/dir.c
parent56ee3547940f895a2cf20f2ac462fbeaee55fa2a (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>
Diffstat (limited to 'fs/coda/dir.c')
-rw-r--r--fs/coda/dir.c106
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
181static inline void coda_dir_changed(struct inode *dir, int link) 180static 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 */
199static inline void coda_dir_inc_nlink(struct inode *dir)
200{
201 if (dir->i_nlink >= 2)
202 inc_nlink(dir);
203}
204
205static 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
238static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) 252static 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
309out: 324out:
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
376int coda_rmdir(struct inode *dir, struct dentry *de) 390int 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 */
405static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, 419static 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