In message <h4n8aj$fi...@ger.gmane.org>, "pas...@pabr.org" writes: > Bart van der Meulen wrote: > >> [<c0120b14>] do_page_fault+0x224/0x5c0 > >> [<c04bc302>] error_code+0x72/0x78 > >> [<c019f07a>] notify_change+0x2da/0x310 > >> [<c0188b37>] do_truncate+0x67/0x90 > >> [<c0188cb5>] do_sys_ftruncate+0x155/0x170 > >> [<c0188ceb>] sys_ftruncate64+0x1b/0x20 > >> [<c0105412>] sysenter_past_esp+0x5f/0x85 > > This might be related to my unlink+ftruncate bug, which > is easily reproducible: > https://bugzilla.filesystems.org/show_bug.cgi?id=633 > > > Can somebody give me some pointers on how to debug the problem further? > > strace the application to confirm that it calls unlink > and then ftruncate on the same file descriptor. > > Pascal
I love easily reproducible oopses. :-) Please try the patch below, which is also available from here: https://bugzilla.fsl.cs.sunysb.edu/attachment.cgi?id=235 The fix adds special handling to unlinked but open inodes, on which the user tries to setattr. Special handling is needed because this inode no longer has a name in the namespace (i.e., no dentry). Cheers, Erez. ############################################################################## Unionfs: handle an open-unlink-ftruncate sequence If someone calls open(), then unlink(), then ftruncate() on a file (rare, but possible), then it's possible for unionfs to get an unlinked inode which doesn't have an inode->i_sb and its inode->i_ino is zero. Don't oops in that case. Signed-off-by: Erez Zadok <e...@cs.sunysb.edu> diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c index 7e86273..bd5a3b3 100644 --- a/fs/unionfs/inode.c +++ b/fs/unionfs/inode.c @@ -835,7 +835,7 @@ static int unionfs_permission(struct inode *inode, int mask) if (err && err != -EACCES && err != EPERM && bindex > 0) { umode_t mode = lower_inode->i_mode; if ((is_robranch_super(inode->i_sb, bindex) || - IS_RDONLY(lower_inode)) && + __is_rdonly(lower_inode)) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) err = 0; if (IS_COPYUP_ERR(err)) @@ -930,7 +930,7 @@ static int unionfs_setattr(struct dentry *dentry, struct iattr *ia) /* copyup if the file is on a read only branch */ if (is_robranch_super(dentry->d_sb, bstart) - || IS_RDONLY(lower_inode)) { + || __is_rdonly(lower_inode)) { /* check if we have a branch to copy up to */ if (bstart <= 0) { err = -EACCES; @@ -977,14 +977,20 @@ static int unionfs_setattr(struct dentry *dentry, struct iattr *ia) } /* notify the (possibly copied-up) lower inode */ - mutex_lock(&lower_inode->i_mutex); + /* + * Note: we use lower_dentry->d_inode, because lower_inode may be + * unlinked (no inode->i_sb and i_ino==0. This happens if someone + * tries to open(), unlink(), then ftruncate() a file. + */ + mutex_lock(&lower_dentry->d_inode->i_mutex); err = notify_change(lower_dentry, ia); - mutex_unlock(&lower_inode->i_mutex); + mutex_unlock(&lower_dentry->d_inode->i_mutex); if (err) goto out; /* get attributes from the first lower inode */ - unionfs_copy_attr_all(inode, lower_inode); + if (ibstart(inode) >= 0) + unionfs_copy_attr_all(inode, lower_inode); /* * unionfs_copy_attr_all will copy the lower times to our inode if * the lower ones are newer (useful for cache coherency). However, diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h index 1b2b86f..9663506 100644 --- a/fs/unionfs/union.h +++ b/fs/unionfs/union.h @@ -485,6 +485,15 @@ static inline int set_branchperms(struct super_block *sb, int index, int perms) return perms; } +/* check if readonly lower inode, but possibly unlinked (no inode->i_sb) */ +static inline int __is_rdonly(const struct inode *inode) +{ + /* if unlinked, can't be readonly (?) */ + if (!inode->i_sb) + return 0; + return IS_RDONLY(inode); + +} /* Is this file on a read-only branch? */ static inline int is_robranch_super(const struct super_block *sb, int index) { _______________________________________________ unionfs mailing list: http://unionfs.filesystems.org/ unionfs@mail.fsl.cs.sunysb.edu http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs