Commit ce71ec36 authored by Dave Hansen's avatar Dave Hansen Committed by Linus Torvalds

[PATCH] r/o bind mounts: monitor zeroing of i_nlink

Some filesystems, instead of simply decrementing i_nlink, simply zero it
during an unlink operation.  We need to catch these in addition to the
decrement operations.
Signed-off-by: default avatarDave Hansen <haveblue@us.ibm.com>
Acked-by: default avatarChristoph Hellwig <hch@lst.de>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 17ff7856
...@@ -638,7 +638,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) ...@@ -638,7 +638,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
dput(ino->dentry); dput(ino->dentry);
dentry->d_inode->i_size = 0; dentry->d_inode->i_size = 0;
dentry->d_inode->i_nlink = 0; clear_nlink(dentry->d_inode);
dir->i_mtime = CURRENT_TIME; dir->i_mtime = CURRENT_TIME;
...@@ -673,7 +673,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -673,7 +673,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
} }
dput(ino->dentry); dput(ino->dentry);
dentry->d_inode->i_size = 0; dentry->d_inode->i_size = 0;
dentry->d_inode->i_nlink = 0; clear_nlink(dentry->d_inode);
if (dir->i_nlink) if (dir->i_nlink)
drop_nlink(dir); drop_nlink(dir);
......
...@@ -818,7 +818,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) ...@@ -818,7 +818,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
if (!rc) { if (!rc) {
drop_nlink(inode); drop_nlink(inode);
i_size_write(direntry->d_inode,0); i_size_write(direntry->d_inode,0);
direntry->d_inode->i_nlink = 0; clear_nlink(direntry->d_inode);
} }
cifsInode = CIFS_I(direntry->d_inode); cifsInode = CIFS_I(direntry->d_inode);
......
...@@ -2045,7 +2045,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) ...@@ -2045,7 +2045,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry)
"empty directory has nlink!=2 (%d)", "empty directory has nlink!=2 (%d)",
inode->i_nlink); inode->i_nlink);
inode->i_version++; inode->i_version++;
inode->i_nlink = 0; clear_nlink(inode);
/* There's no need to set i_disksize: the fact that i_nlink is /* There's no need to set i_disksize: the fact that i_nlink is
* zero will ensure that the right thing happens during any * zero will ensure that the right thing happens during any
* recovery. */ * recovery. */
......
...@@ -508,7 +508,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) ...@@ -508,7 +508,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
/* Set nlink to zero so the inode can be cleared, if /* Set nlink to zero so the inode can be cleared, if
the inode does have more links this will be the inode does have more links this will be
discovered at the next lookup/getattr */ discovered at the next lookup/getattr */
inode->i_nlink = 0; clear_nlink(inode);
fuse_invalidate_attr(inode); fuse_invalidate_attr(inode);
fuse_invalidate_attr(dir); fuse_invalidate_attr(dir);
fuse_invalidate_entry_cache(entry); fuse_invalidate_entry_cache(entry);
...@@ -534,7 +534,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) ...@@ -534,7 +534,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
if (!err) { if (!err) {
entry->d_inode->i_nlink = 0; clear_nlink(entry->d_inode);
fuse_invalidate_attr(dir); fuse_invalidate_attr(dir);
fuse_invalidate_entry_cache(entry); fuse_invalidate_entry_cache(entry);
} else if (err == -EINTR) } else if (err == -EINTR)
......
...@@ -273,7 +273,7 @@ static int hfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -273,7 +273,7 @@ static int hfs_rmdir(struct inode *dir, struct dentry *dentry)
res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name); res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
if (res) if (res)
return res; return res;
inode->i_nlink = 0; clear_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC; inode->i_ctime = CURRENT_TIME_SEC;
hfs_delete_inode(inode); hfs_delete_inode(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
......
...@@ -348,7 +348,7 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) ...@@ -348,7 +348,7 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
} else } else
inode->i_flags |= S_DEAD; inode->i_flags |= S_DEAD;
} else } else
inode->i_nlink = 0; clear_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC; inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode); mark_inode_dirty(inode);
...@@ -387,7 +387,7 @@ static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -387,7 +387,7 @@ static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name);
if (res) if (res)
return res; return res;
inode->i_nlink = 0; clear_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC; inode->i_ctime = CURRENT_TIME_SEC;
hfsplus_delete_inode(inode); hfsplus_delete_inode(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
......
...@@ -495,7 +495,7 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -495,7 +495,7 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
break; break;
default: default:
drop_nlink(dir); drop_nlink(dir);
inode->i_nlink = 0; clear_nlink(inode);
err = 0; err = 0;
} }
goto out; goto out;
...@@ -590,7 +590,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -590,7 +590,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
int r; int r;
if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) { if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) {
if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, (char *)new_name, new_len, NULL, &qbh1))) { if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, (char *)new_name, new_len, NULL, &qbh1))) {
new_inode->i_nlink = 0; clear_nlink(new_inode);
copy_de(nde, &de); copy_de(nde, &de);
memcpy(nde->name, new_name, new_len); memcpy(nde->name, new_name, new_len);
hpfs_mark_4buffers_dirty(&qbh1); hpfs_mark_4buffers_dirty(&qbh1);
......
...@@ -414,7 +414,7 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) ...@@ -414,7 +414,7 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
JFS_IP(ip)->acl.flag = 0; JFS_IP(ip)->acl.flag = 0;
/* mark the target directory as deleted */ /* mark the target directory as deleted */
ip->i_nlink = 0; clear_nlink(ip);
mark_inode_dirty(ip); mark_inode_dirty(ip);
rc = txCommit(tid, 2, &iplist[0], 0); rc = txCommit(tid, 2, &iplist[0], 0);
......
...@@ -345,7 +345,7 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -345,7 +345,7 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
goto out; goto out;
drop_nlink(dir); drop_nlink(dir);
inode->i_nlink = 0; clear_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC; inode->i_ctime = CURRENT_TIME_SEC;
fat_detach(inode); fat_detach(inode);
out: out:
...@@ -430,7 +430,7 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry) ...@@ -430,7 +430,7 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry)
err = fat_remove_entries(dir, &sinfo); /* and releases bh */ err = fat_remove_entries(dir, &sinfo); /* and releases bh */
if (err) if (err)
goto out; goto out;
inode->i_nlink = 0; clear_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC; inode->i_ctime = CURRENT_TIME_SEC;
fat_detach(inode); fat_detach(inode);
out: out:
......
...@@ -1286,7 +1286,7 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1286,7 +1286,7 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
/* Ensure the VFS deletes this inode */ /* Ensure the VFS deletes this inode */
if (error == 0 && dentry->d_inode != NULL) if (error == 0 && dentry->d_inode != NULL)
dentry->d_inode->i_nlink = 0; clear_nlink(dentry->d_inode);
nfs_end_data_update(dir); nfs_end_data_update(dir);
unlock_kernel(); unlock_kernel();
......
...@@ -186,7 +186,7 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -186,7 +186,7 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry)
memset(de->di_fname, 0, sizeof de->di_fname); memset(de->di_fname, 0, sizeof de->di_fname);
de->di_mode = 0; de->di_mode = 0;
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
inode->i_nlink = 0; clear_nlink(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
inode_dec_link_count(dir); inode_dec_link_count(dir);
......
...@@ -913,7 +913,7 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -913,7 +913,7 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry)
reiserfs_warning(inode->i_sb, "%s: empty directory has nlink " reiserfs_warning(inode->i_sb, "%s: empty directory has nlink "
"!= 2 (%d)", __FUNCTION__, inode->i_nlink); "!= 2 (%d)", __FUNCTION__, inode->i_nlink);
inode->i_nlink = 0; clear_nlink(inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
reiserfs_update_sd(&th, inode); reiserfs_update_sd(&th, inode);
...@@ -1473,7 +1473,7 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1473,7 +1473,7 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_dentry_inode) { if (new_dentry_inode) {
// adjust link number of the victim // adjust link number of the victim
if (S_ISDIR(new_dentry_inode->i_mode)) { if (S_ISDIR(new_dentry_inode->i_mode)) {
new_dentry_inode->i_nlink = 0; clear_nlink(new_dentry_inode);
} else { } else {
drop_nlink(new_dentry_inode); drop_nlink(new_dentry_inode);
} }
......
...@@ -876,7 +876,7 @@ static int udf_rmdir(struct inode * dir, struct dentry * dentry) ...@@ -876,7 +876,7 @@ static int udf_rmdir(struct inode * dir, struct dentry * dentry)
udf_warning(inode->i_sb, "udf_rmdir", udf_warning(inode->i_sb, "udf_rmdir",
"empty directory has nlink != 2 (%d)", "empty directory has nlink != 2 (%d)",
inode->i_nlink); inode->i_nlink);
inode->i_nlink = 0; clear_nlink(inode);
inode->i_size = 0; inode->i_size = 0;
inode_dec_link_count(inode); inode_dec_link_count(inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb); inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
......
...@@ -784,7 +784,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -784,7 +784,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
goto out; goto out;
drop_nlink(dir); drop_nlink(dir);
inode->i_nlink = 0; clear_nlink(inode);
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode); fat_detach(inode);
out: out:
...@@ -808,7 +808,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry) ...@@ -808,7 +808,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry)
err = fat_remove_entries(dir, &sinfo); /* and releases bh */ err = fat_remove_entries(dir, &sinfo); /* and releases bh */
if (err) if (err)
goto out; goto out;
inode->i_nlink = 0; clear_nlink(inode);
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode); fat_detach(inode);
out: out:
......
...@@ -1235,6 +1235,11 @@ static inline void drop_nlink(struct inode *inode) ...@@ -1235,6 +1235,11 @@ static inline void drop_nlink(struct inode *inode)
inode->i_nlink--; inode->i_nlink--;
} }
static inline void clear_nlink(struct inode *inode)
{
inode->i_nlink = 0;
}
static inline void inode_dec_link_count(struct inode *inode) static inline void inode_dec_link_count(struct inode *inode)
{ {
drop_nlink(inode); drop_nlink(inode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment