aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/ops_inode.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2011-05-09 11:42:37 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2011-05-09 11:42:37 -0400
commit855d23ce2665c56437bd88fa6a0d45b6713bd194 (patch)
tree0678f8d0e93dfafd783bf9782f457bc7235b2128 /fs/gfs2/ops_inode.c
parent2baee03fb916563d7cc597e5460e4cb938815c52 (diff)
GFS2: Make gfs2_dir_del update link count when required
When we remove an entry from a directory, we can save ourselves some trouble if we know the type of the entry in question, since if it is itself a directory, we can update the link count of the parent at the same time as removing the directory entry. In addition this patch also merges the rmdir and unlink code which was almost identical anyway. This eliminates the calls to remove the . and .. directory entries on each rmdir (not needed since the directory will be deallocated, anyway) which was the only thing preventing passing the dentry to gfs2_dir_del(). The passing of the dentry rather than just the name allows us to figure out the type of the entry which is being removed, and thus adjust the link count when required. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/ops_inode.c')
-rw-r--r--fs/gfs2/ops_inode.c221
1 files changed, 66 insertions, 155 deletions
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index acb6f69b02e..765da06c8f5 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -312,11 +312,52 @@ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
312} 312}
313 313
314/** 314/**
315 * gfs2_unlink - Unlink a file 315 * gfs2_unlink_inode - Removes an inode from its parent dir and unlinks it
316 * @dir: The inode of the directory containing the file to unlink 316 * @dip: The parent directory
317 * @name: The name of the entry in the parent directory
318 * @bh: The inode buffer for the inode to be removed
319 * @inode: The inode to be removed
320 *
321 * Called with all the locks and in a transaction. This will only be
322 * called for a directory after it has been checked to ensure it is empty.
323 *
324 * Returns: 0 on success, or an error
325 */
326
327static int gfs2_unlink_inode(struct gfs2_inode *dip,
328 const struct dentry *dentry,
329 struct buffer_head *bh)
330{
331 struct inode *inode = dentry->d_inode;
332 struct gfs2_inode *ip = GFS2_I(inode);
333 int error;
334
335 error = gfs2_dir_del(dip, dentry);
336 if (error)
337 return error;
338
339 ip->i_entries = 0;
340 inode->i_ctime = CURRENT_TIME;
341 if (S_ISDIR(inode->i_mode))
342 clear_nlink(inode);
343 else
344 drop_nlink(inode);
345 gfs2_trans_add_bh(ip->i_gl, bh, 1);
346 gfs2_dinode_out(ip, bh->b_data);
347 mark_inode_dirty(inode);
348 if (inode->i_nlink == 0)
349 gfs2_unlink_di(inode);
350 return 0;
351}
352
353
354/**
355 * gfs2_unlink - Unlink an inode (this does rmdir as well)
356 * @dir: The inode of the directory containing the inode to unlink
317 * @dentry: The file itself 357 * @dentry: The file itself
318 * 358 *
319 * Unlink a file. Call gfs2_unlinki() 359 * This routine uses the type of the inode as a flag to figure out
360 * whether this is an unlink or an rmdir.
320 * 361 *
321 * Returns: errno 362 * Returns: errno
322 */ 363 */
@@ -325,7 +366,9 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
325{ 366{
326 struct gfs2_inode *dip = GFS2_I(dir); 367 struct gfs2_inode *dip = GFS2_I(dir);
327 struct gfs2_sbd *sdp = GFS2_SB(dir); 368 struct gfs2_sbd *sdp = GFS2_SB(dir);
328 struct gfs2_inode *ip = GFS2_I(dentry->d_inode); 369 struct inode *inode = dentry->d_inode;
370 struct gfs2_inode *ip = GFS2_I(inode);
371 struct buffer_head *bh;
329 struct gfs2_holder ghs[3]; 372 struct gfs2_holder ghs[3];
330 struct gfs2_rgrpd *rgd; 373 struct gfs2_rgrpd *rgd;
331 struct gfs2_holder ri_gh; 374 struct gfs2_holder ri_gh;
@@ -351,9 +394,15 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
351 goto out_child; 394 goto out_child;
352 395
353 error = -ENOENT; 396 error = -ENOENT;
354 if (ip->i_inode.i_nlink == 0) 397 if (inode->i_nlink == 0)
355 goto out_rgrp; 398 goto out_rgrp;
356 399
400 if (S_ISDIR(inode->i_mode)) {
401 error = -ENOTEMPTY;
402 if (ip->i_entries > 2 || inode->i_nlink > 2)
403 goto out_rgrp;
404 }
405
357 error = gfs2_glock_nq(ghs + 2); /* rgrp */ 406 error = gfs2_glock_nq(ghs + 2); /* rgrp */
358 if (error) 407 if (error)
359 goto out_rgrp; 408 goto out_rgrp;
@@ -362,15 +411,16 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
362 if (error) 411 if (error)
363 goto out_gunlock; 412 goto out_gunlock;
364 413
365 error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); 414 error = gfs2_trans_begin(sdp, 2*RES_DINODE + 3*RES_LEAF + RES_RG_BIT, 0);
366 if (error) 415 if (error)
367 goto out_gunlock; 416 goto out_gunlock;
368 417
369 error = gfs2_dir_del(dip, &dentry->d_name); 418 error = gfs2_meta_inode_buffer(ip, &bh);
370 if (error) 419 if (error)
371 goto out_end_trans; 420 goto out_end_trans;
372 421
373 error = gfs2_change_nlink(ip, -1); 422 error = gfs2_unlink_inode(dip, dentry, bh);
423 brelse(bh);
374 424
375out_end_trans: 425out_end_trans:
376 gfs2_trans_end(sdp); 426 gfs2_trans_end(sdp);
@@ -522,138 +572,6 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
522} 572}
523 573
524/** 574/**
525 * gfs2_rmdiri - Remove a directory
526 * @dip: The parent directory of the directory to be removed
527 * @name: The name of the directory to be removed
528 * @ip: The GFS2 inode of the directory to be removed
529 *
530 * Assumes Glocks on dip and ip are held
531 *
532 * Returns: errno
533 */
534
535static int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
536 struct gfs2_inode *ip)
537{
538 int error;
539
540 if (ip->i_entries != 2) {
541 if (gfs2_consist_inode(ip))
542 gfs2_dinode_print(ip);
543 return -EIO;
544 }
545
546 error = gfs2_dir_del(dip, name);
547 if (error)
548 return error;
549
550 error = gfs2_change_nlink(dip, -1);
551 if (error)
552 return error;
553
554 error = gfs2_dir_del(ip, &gfs2_qdot);
555 if (error)
556 return error;
557
558 error = gfs2_dir_del(ip, &gfs2_qdotdot);
559 if (error)
560 return error;
561
562 /* It looks odd, but it really should be done twice */
563 error = gfs2_change_nlink(ip, -1);
564 if (error)
565 return error;
566
567 error = gfs2_change_nlink(ip, -1);
568 if (error)
569 return error;
570
571 return error;
572}
573
574/**
575 * gfs2_rmdir - Remove a directory
576 * @dir: The parent directory of the directory to be removed
577 * @dentry: The dentry of the directory to remove
578 *
579 * Remove a directory. Call gfs2_rmdiri()
580 *
581 * Returns: errno
582 */
583
584static int gfs2_rmdir(struct inode *dir, struct dentry *dentry)
585{
586 struct gfs2_inode *dip = GFS2_I(dir);
587 struct gfs2_sbd *sdp = GFS2_SB(dir);
588 struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
589 struct gfs2_holder ghs[3];
590 struct gfs2_rgrpd *rgd;
591 struct gfs2_holder ri_gh;
592 int error;
593
594 error = gfs2_rindex_hold(sdp, &ri_gh);
595 if (error)
596 return error;
597 gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
598 gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
599
600 rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
601 gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
602
603 error = gfs2_glock_nq(ghs); /* parent */
604 if (error)
605 goto out_parent;
606
607 error = gfs2_glock_nq(ghs + 1); /* child */
608 if (error)
609 goto out_child;
610
611 error = -ENOENT;
612 if (ip->i_inode.i_nlink == 0)
613 goto out_rgrp;
614
615 error = gfs2_glock_nq(ghs + 2); /* rgrp */
616 if (error)
617 goto out_rgrp;
618
619 error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
620 if (error)
621 goto out_gunlock;
622
623 if (ip->i_entries < 2) {
624 if (gfs2_consist_inode(ip))
625 gfs2_dinode_print(ip);
626 error = -EIO;
627 goto out_gunlock;
628 }
629 if (ip->i_entries > 2) {
630 error = -ENOTEMPTY;
631 goto out_gunlock;
632 }
633
634 error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF + RES_RG_BIT, 0);
635 if (error)
636 goto out_gunlock;
637
638 error = gfs2_rmdiri(dip, &dentry->d_name, ip);
639
640 gfs2_trans_end(sdp);
641
642out_gunlock:
643 gfs2_glock_dq(ghs + 2);
644out_rgrp:
645 gfs2_holder_uninit(ghs + 2);
646 gfs2_glock_dq(ghs + 1);
647out_child:
648 gfs2_holder_uninit(ghs + 1);
649 gfs2_glock_dq(ghs);
650out_parent:
651 gfs2_holder_uninit(ghs);
652 gfs2_glock_dq_uninit(&ri_gh);
653 return error;
654}
655
656/**
657 * gfs2_mknod - Make a special file 575 * gfs2_mknod - Make a special file
658 * @dir: The directory in which the special file will reside 576 * @dir: The directory in which the special file will reside
659 * @dentry: The dentry of the special file 577 * @dentry: The dentry of the special file
@@ -930,25 +848,18 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
930 /* Remove the target file, if it exists */ 848 /* Remove the target file, if it exists */
931 849
932 if (nip) { 850 if (nip) {
933 if (S_ISDIR(nip->i_inode.i_mode)) 851 struct buffer_head *bh;
934 error = gfs2_rmdiri(ndip, &ndentry->d_name, nip); 852 error = gfs2_meta_inode_buffer(nip, &bh);
935 else {
936 error = gfs2_dir_del(ndip, &ndentry->d_name);
937 if (error)
938 goto out_end_trans;
939 error = gfs2_change_nlink(nip, -1);
940 }
941 if (error) 853 if (error)
942 goto out_end_trans; 854 goto out_end_trans;
855 error = gfs2_unlink_inode(ndip, ndentry, bh);
856 brelse(bh);
943 } 857 }
944 858
945 if (dir_rename) { 859 if (dir_rename) {
946 error = gfs2_change_nlink(ndip, +1); 860 error = gfs2_change_nlink(ndip, +1);
947 if (error) 861 if (error)
948 goto out_end_trans; 862 goto out_end_trans;
949 error = gfs2_change_nlink(odip, -1);
950 if (error)
951 goto out_end_trans;
952 863
953 error = gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR); 864 error = gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR);
954 if (error) 865 if (error)
@@ -964,7 +875,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
964 brelse(dibh); 875 brelse(dibh);
965 } 876 }
966 877
967 error = gfs2_dir_del(odip, &odentry->d_name); 878 error = gfs2_dir_del(odip, odentry);
968 if (error) 879 if (error)
969 goto out_end_trans; 880 goto out_end_trans;
970 881
@@ -1347,7 +1258,7 @@ const struct inode_operations gfs2_dir_iops = {
1347 .unlink = gfs2_unlink, 1258 .unlink = gfs2_unlink,
1348 .symlink = gfs2_symlink, 1259 .symlink = gfs2_symlink,
1349 .mkdir = gfs2_mkdir, 1260 .mkdir = gfs2_mkdir,
1350 .rmdir = gfs2_rmdir, 1261 .rmdir = gfs2_unlink,
1351 .mknod = gfs2_mknod, 1262 .mknod = gfs2_mknod,
1352 .rename = gfs2_rename, 1263 .rename = gfs2_rename,
1353 .permission = gfs2_permission, 1264 .permission = gfs2_permission,