Skip to content

Commit

Permalink
[PATCH] r/o bind mounts: unlink: monitor i_nlink
Browse files Browse the repository at this point in the history
When a filesystem decrements i_nlink to zero, it means that a write must be
performed in order to drop the inode from the filesystem.

We're shortly going to have keep filesystems from being remounted r/o between
the time that this i_nlink decrement and that write occurs.

So, add a little helper function to do the decrements.  We'll tie into it in a
bit to note when i_nlink hits zero.

Signed-off-by: Dave Hansen <[email protected]>
Acked-by: Christoph Hellwig <[email protected]>
Cc: Al Viro <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
hansendc authored and Linus Torvalds committed Oct 1, 2006
1 parent aab520e commit 9a53c3a
Show file tree
Hide file tree
Showing 28 changed files with 83 additions and 93 deletions.
7 changes: 4 additions & 3 deletions drivers/usb/core/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ static int usbfs_unlink (struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
mutex_lock(&inode->i_mutex);
dentry->d_inode->i_nlink--;
drop_nlink(dentry->d_inode);
dput(dentry);
mutex_unlock(&inode->i_mutex);
d_delete(dentry);
Expand All @@ -347,10 +347,11 @@ static int usbfs_rmdir(struct inode *dir, struct dentry *dentry)
mutex_lock(&inode->i_mutex);
dentry_unhash(dentry);
if (usbfs_empty(dentry)) {
dentry->d_inode->i_nlink -= 2;
drop_nlink(dentry->d_inode);
drop_nlink(dentry->d_inode);
dput(dentry);
inode->i_flags |= S_DEAD;
dir->i_nlink--;
drop_nlink(dir);
error = 0;
}
mutex_unlock(&inode->i_mutex);
Expand Down
2 changes: 1 addition & 1 deletion fs/autofs/root.c
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry)

dentry->d_time = (unsigned long)(struct autofs_dir_ent *)NULL;
autofs_hash_delete(ent);
dir->i_nlink--;
drop_nlink(dir);
d_drop(dentry);
unlock_kernel();

Expand Down
2 changes: 1 addition & 1 deletion fs/autofs4/root.c
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
dentry->d_inode->i_nlink = 0;

if (dir->i_nlink)
dir->i_nlink--;
drop_nlink(dir);

return 0;
}
Expand Down
9 changes: 3 additions & 6 deletions fs/bfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,7 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode,

err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, inode->i_ino);
if (err) {
inode->i_nlink--;
mark_inode_dirty(inode);
inode_dec_link_count(inode);
iput(inode);
unlock_kernel();
return err;
Expand Down Expand Up @@ -196,9 +195,8 @@ static int bfs_unlink(struct inode * dir, struct dentry * dentry)
mark_buffer_dirty(bh);
dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(dir);
inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
mark_inode_dirty(inode);
inode_dec_link_count(inode);
error = 0;

out_brelse:
Expand Down Expand Up @@ -249,9 +247,8 @@ static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry,
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(old_dir);
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(new_inode);
inode_dec_link_count(new_inode);
}
mark_buffer_dirty(old_bh);
error = 0;
Expand Down
10 changes: 5 additions & 5 deletions fs/cifs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)

if (!rc) {
if (direntry->d_inode)
direntry->d_inode->i_nlink--;
drop_nlink(direntry->d_inode);
} else if (rc == -ENOENT) {
d_drop(direntry);
} else if (rc == -ETXTBSY) {
Expand All @@ -609,7 +609,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, pTcon, netfid);
if (direntry->d_inode)
direntry->d_inode->i_nlink--;
drop_nlink(direntry->d_inode);
}
} else if (rc == -EACCES) {
/* try only if r/o attribute set in local lookup data? */
Expand Down Expand Up @@ -663,7 +663,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc) {
if (direntry->d_inode)
direntry->d_inode->i_nlink--;
drop_nlink(direntry->d_inode);
} else if (rc == -ETXTBSY) {
int oplock = FALSE;
__u16 netfid;
Expand All @@ -684,7 +684,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, pTcon, netfid);
if (direntry->d_inode)
direntry->d_inode->i_nlink--;
drop_nlink(direntry->d_inode);
}
/* BB if rc = -ETXTBUSY goto the rename logic BB */
}
Expand Down Expand Up @@ -816,7 +816,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);

if (!rc) {
inode->i_nlink--;
drop_nlink(inode);
i_size_write(direntry->d_inode,0);
direntry->d_inode->i_nlink = 0;
}
Expand Down
4 changes: 2 additions & 2 deletions fs/coda/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ int coda_unlink(struct inode *dir, struct dentry *de)
}

coda_dir_changed(dir, 0);
de->d_inode->i_nlink--;
drop_nlink(de->d_inode);
unlock_kernel();

return 0;
Expand All @@ -394,7 +394,7 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
}

coda_dir_changed(dir, -1);
de->d_inode->i_nlink--;
drop_nlink(de->d_inode);
d_delete(de);
unlock_kernel();

Expand Down
2 changes: 1 addition & 1 deletion fs/ext2/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
ext2_set_link(new_dir, new_de, new_page, old_inode);
new_inode->i_ctime = CURRENT_TIME_SEC;
if (dir_de)
new_inode->i_nlink--;
drop_nlink(new_inode);
inode_dec_link_count(new_inode);
} else {
if (dir_de) {
Expand Down
14 changes: 7 additions & 7 deletions fs/ext3/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -1621,7 +1621,7 @@ static inline void ext3_inc_count(handle_t *handle, struct inode *inode)

static inline void ext3_dec_count(handle_t *handle, struct inode *inode)
{
inode->i_nlink--;
drop_nlink(inode);
}

static int ext3_add_nondir(handle_t *handle,
Expand Down Expand Up @@ -1743,7 +1743,7 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
dir_block = ext3_bread (handle, inode, 0, 1, &err);
if (!dir_block) {
inode->i_nlink--; /* is this nlink == 0? */
drop_nlink(inode); /* is this nlink == 0? */
ext3_mark_inode_dirty(handle, inode);
iput (inode);
goto out_stop;
Expand Down Expand Up @@ -2053,7 +2053,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry)
ext3_orphan_add(handle, inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
ext3_mark_inode_dirty(handle, inode);
dir->i_nlink--;
drop_nlink(dir);
ext3_update_dx_flag(dir);
ext3_mark_inode_dirty(handle, dir);

Expand Down Expand Up @@ -2104,7 +2104,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
ext3_update_dx_flag(dir);
ext3_mark_inode_dirty(handle, dir);
inode->i_nlink--;
drop_nlink(inode);
if (!inode->i_nlink)
ext3_orphan_add(handle, inode);
inode->i_ctime = dir->i_ctime;
Expand Down Expand Up @@ -2326,7 +2326,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
}

if (new_inode) {
new_inode->i_nlink--;
drop_nlink(new_inode);
new_inode->i_ctime = CURRENT_TIME_SEC;
}
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
Expand All @@ -2337,9 +2337,9 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata");
ext3_journal_dirty_metadata(handle, dir_bh);
old_dir->i_nlink--;
drop_nlink(old_dir);
if (new_inode) {
new_inode->i_nlink--;
drop_nlink(new_inode);
} else {
new_dir->i_nlink++;
ext3_update_dx_flag(new_dir);
Expand Down
2 changes: 1 addition & 1 deletion fs/hfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ static int hfs_unlink(struct inode *dir, struct dentry *dentry)
if (res)
return res;

inode->i_nlink--;
drop_nlink(inode);
hfs_delete_inode(inode);
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
Expand Down
2 changes: 1 addition & 1 deletion fs/hfsplus/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
return res;

if (inode->i_nlink > 0)
inode->i_nlink--;
drop_nlink(inode);
hfsplus_delete_inode(inode);
if (inode->i_ino != cnid && !inode->i_nlink) {
if (!atomic_read(&HFSPLUS_I(inode).opencnt)) {
Expand Down
6 changes: 3 additions & 3 deletions fs/hpfs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
unlock_kernel();
return -ENOSPC;
default:
inode->i_nlink--;
drop_nlink(inode);
err = 0;
}
goto out;
Expand Down Expand Up @@ -494,7 +494,7 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
err = -ENOSPC;
break;
default:
dir->i_nlink--;
drop_nlink(dir);
inode->i_nlink = 0;
err = 0;
}
Expand Down Expand Up @@ -636,7 +636,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
hpfs_i(i)->i_parent_dir = new_dir->i_ino;
if (S_ISDIR(i->i_mode)) {
new_dir->i_nlink++;
old_dir->i_nlink--;
drop_nlink(old_dir);
}
if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) {
fnode->up = new_dir->i_ino;
Expand Down
3 changes: 1 addition & 2 deletions fs/jffs/inode-v23.c
Original file line number Diff line number Diff line change
Expand Up @@ -1052,9 +1052,8 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type)

dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(dir);
inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
mark_inode_dirty(inode);
inode_dec_link_count(inode);

d_delete(dentry); /* This also frees the inode */

Expand Down
6 changes: 3 additions & 3 deletions fs/jffs2/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
}
ret = jffs2_unlink(dir_i, dentry);
if (!ret)
dir_i->i_nlink--;
drop_nlink(dir_i);
return ret;
}

Expand Down Expand Up @@ -823,7 +823,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,

if (victim_f) {
/* There was a victim. Kill it off nicely */
new_dentry->d_inode->i_nlink--;
drop_nlink(new_dentry->d_inode);
/* Don't oops if the victim was a dirent pointing to an
inode which didn't exist. */
if (victim_f->inocache) {
Expand Down Expand Up @@ -862,7 +862,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
}

if (S_ISDIR(old_dentry->d_inode->i_mode))
old_dir_i->i_nlink--;
drop_nlink(old_dir_i);

new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);

Expand Down
14 changes: 6 additions & 8 deletions fs/jfs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,9 +393,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
/* update parent directory's link count corresponding
* to ".." entry of the target directory deleted
*/
dip->i_nlink--;
dip->i_ctime = dip->i_mtime = CURRENT_TIME;
mark_inode_dirty(dip);
inode_dec_link_count(dip);

/*
* OS/2 could have created EA and/or ACL
Expand Down Expand Up @@ -515,8 +514,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
mark_inode_dirty(dip);

/* update target's inode */
ip->i_nlink--;
mark_inode_dirty(ip);
inode_dec_link_count(ip);

/*
* commit zero link count object
Expand Down Expand Up @@ -835,7 +833,7 @@ static int jfs_link(struct dentry *old_dentry,
rc = txCommit(tid, 2, &iplist[0], 0);

if (rc) {
ip->i_nlink--;
ip->i_nlink--; /* never instantiated */
iput(ip);
} else
d_instantiate(dentry, ip);
Expand Down Expand Up @@ -1155,9 +1153,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
old_ip->i_ino, JFS_RENAME);
if (rc)
goto out4;
new_ip->i_nlink--;
drop_nlink(new_ip);
if (S_ISDIR(new_ip->i_mode)) {
new_ip->i_nlink--;
drop_nlink(new_ip);
if (new_ip->i_nlink) {
mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
if (old_dir != new_dir)
Expand Down Expand Up @@ -1223,7 +1221,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out4;
}
if (S_ISDIR(old_ip->i_mode)) {
old_dir->i_nlink--;
drop_nlink(old_dir);
if (old_dir != new_dir) {
/*
* Change inode number of parent for moved directory
Expand Down
10 changes: 5 additions & 5 deletions fs/libfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ int simple_unlink(struct inode *dir, struct dentry *dentry)
struct inode *inode = dentry->d_inode;

inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
inode->i_nlink--;
drop_nlink(inode);
dput(dentry);
return 0;
}
Expand All @@ -285,9 +285,9 @@ int simple_rmdir(struct inode *dir, struct dentry *dentry)
if (!simple_empty(dentry))
return -ENOTEMPTY;

dentry->d_inode->i_nlink--;
drop_nlink(dentry->d_inode);
simple_unlink(dir, dentry);
dir->i_nlink--;
drop_nlink(dir);
return 0;
}

Expand All @@ -303,9 +303,9 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_dentry->d_inode) {
simple_unlink(new_dir, new_dentry);
if (they_are_dirs)
old_dir->i_nlink--;
drop_nlink(old_dir);
} else if (they_are_dirs) {
old_dir->i_nlink--;
drop_nlink(old_dir);
new_dir->i_nlink++;
}

Expand Down
2 changes: 1 addition & 1 deletion fs/minix/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
minix_set_link(new_de, new_page, old_inode);
new_inode->i_ctime = CURRENT_TIME_SEC;
if (dir_de)
new_inode->i_nlink--;
drop_nlink(new_inode);
inode_dec_link_count(new_inode);
} else {
if (dir_de) {
Expand Down
Loading

0 comments on commit 9a53c3a

Please sign in to comment.