From e16695b67ed7af63e8c1498720ff2e173bc0e017 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH] --- yaml --- r: 95018 b: refs/heads/master c: 9fc7c63a1d6e9920038ced782390a54888ed70a6 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/edac/pasemi_edac.c | 1 - trunk/fs/jbd2/commit.c | 16 -- trunk/fs/jbd2/transaction.c | 13 ++ trunk/fs/xfs/Kconfig | 13 -- trunk/fs/xfs/linux-2.6/mrlock.h | 60 +++--- trunk/fs/xfs/linux-2.6/xfs_buf.c | 2 +- trunk/fs/xfs/linux-2.6/xfs_export.c | 2 +- trunk/fs/xfs/linux-2.6/xfs_file.c | 75 ++++++++ trunk/fs/xfs/linux-2.6/xfs_ioctl.c | 8 +- trunk/fs/xfs/linux-2.6/xfs_iops.c | 3 +- trunk/fs/xfs/linux-2.6/xfs_linux.h | 1 + trunk/fs/xfs/linux-2.6/xfs_lrw.c | 21 +- trunk/fs/xfs/linux-2.6/xfs_lrw.h | 1 + trunk/fs/xfs/linux-2.6/xfs_super.c | 2 +- trunk/fs/xfs/linux-2.6/xfs_vnode.h | 24 +++ trunk/fs/xfs/quota/xfs_dquot.c | 4 +- trunk/fs/xfs/quota/xfs_qm.c | 27 +-- trunk/fs/xfs/quota/xfs_qm_syscalls.c | 6 + trunk/fs/xfs/quota/xfs_quota_priv.h | 5 + trunk/fs/xfs/quota/xfs_trans_dquot.c | 2 +- trunk/fs/xfs/xfs.h | 2 +- trunk/fs/xfs/xfs_acl.c | 53 ++++-- trunk/fs/xfs/xfs_attr.c | 93 ++++----- trunk/fs/xfs/xfs_attr.h | 6 +- trunk/fs/xfs/xfs_bmap.c | 1 + trunk/fs/xfs/xfs_dfrag.c | 4 +- trunk/fs/xfs/xfs_fsops.c | 8 +- trunk/fs/xfs/xfs_ialloc.c | 10 - trunk/fs/xfs/xfs_iget.c | 140 +++++++------- trunk/fs/xfs/xfs_inode.c | 25 +-- trunk/fs/xfs/xfs_inode.h | 16 +- trunk/fs/xfs/xfs_inode_item.c | 12 +- trunk/fs/xfs/xfs_iomap.c | 19 +- trunk/fs/xfs/xfs_itable.c | 6 + trunk/fs/xfs/xfs_mount.c | 83 ++++---- trunk/fs/xfs/xfs_mount.h | 7 +- trunk/fs/xfs/xfs_rename.c | 252 +++++++++++++++++++----- trunk/fs/xfs/xfs_trans_inode.c | 12 +- trunk/fs/xfs/xfs_utils.c | 45 ++++- trunk/fs/xfs/xfs_utils.h | 2 + trunk/fs/xfs/xfs_vfsops.c | 1 - trunk/fs/xfs/xfs_vnodeops.c | 274 +++++++++++++++++++++++---- trunk/fs/xfs/xfs_vnodeops.h | 8 +- 44 files changed, 953 insertions(+), 414 deletions(-) diff --git a/[refs] b/[refs] index 6140531fae15..dad6ba2b2b50 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: c15a2434ed4868cad99278ac4d4ae4de9de62e02 +refs/heads/master: 9fc7c63a1d6e9920038ced782390a54888ed70a6 diff --git a/trunk/drivers/edac/pasemi_edac.c b/trunk/drivers/edac/pasemi_edac.c index 8e6b91bd2e99..3fd65a563848 100644 --- a/trunk/drivers/edac/pasemi_edac.c +++ b/trunk/drivers/edac/pasemi_edac.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "edac_core.h" #define MODULE_NAME "pasemi_edac" diff --git a/trunk/fs/jbd2/commit.c b/trunk/fs/jbd2/commit.c index a8173081f831..988fbec1143c 100644 --- a/trunk/fs/jbd2/commit.c +++ b/trunk/fs/jbd2/commit.c @@ -519,22 +519,6 @@ void jbd2_journal_commit_transaction(journal_t *journal) jbd_debug (3, "JBD: commit phase 2\n"); - /* - * First, drop modified flag: all accesses to the buffers - * will be tracked for a new trasaction only -bzzz - */ - spin_lock(&journal->j_list_lock); - if (commit_transaction->t_buffers) { - new_jh = jh = commit_transaction->t_buffers->b_tnext; - do { - J_ASSERT_JH(new_jh, new_jh->b_modified == 1 || - new_jh->b_modified == 0); - new_jh->b_modified = 0; - new_jh = new_jh->b_tnext; - } while (new_jh != jh); - } - spin_unlock(&journal->j_list_lock); - /* * Now start flushing things to disk, in the order they appear * on the transaction lists. Data blocks go first. diff --git a/trunk/fs/jbd2/transaction.c b/trunk/fs/jbd2/transaction.c index b9b0b6f899b9..9dc71a6b62e6 100644 --- a/trunk/fs/jbd2/transaction.c +++ b/trunk/fs/jbd2/transaction.c @@ -617,6 +617,12 @@ do_get_write_access(handle_t *handle, struct journal_head *jh, jh->b_next_transaction == transaction) goto done; + /* + * this is the first time this transaction is touching this buffer, + * reset the modified flag + */ + jh->b_modified = 0; + /* * If there is already a copy-out version of this buffer, then we don't * need to make another one @@ -829,9 +835,16 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) if (jh->b_transaction == NULL) { jh->b_transaction = transaction; + + /* first access by this transaction */ + jh->b_modified = 0; + JBUFFER_TRACE(jh, "file as BJ_Reserved"); __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved); } else if (jh->b_transaction == journal->j_committing_transaction) { + /* first access by this transaction */ + jh->b_modified = 0; + JBUFFER_TRACE(jh, "set next transaction"); jh->b_next_transaction = transaction; } diff --git a/trunk/fs/xfs/Kconfig b/trunk/fs/xfs/Kconfig index 3f53dd101f99..524021ff5436 100644 --- a/trunk/fs/xfs/Kconfig +++ b/trunk/fs/xfs/Kconfig @@ -64,16 +64,3 @@ config XFS_RT See the xfs man page in section 5 for additional information. If unsure, say N. - -config XFS_DEBUG - bool "XFS Debugging support (EXPERIMENTAL)" - depends on XFS_FS && EXPERIMENTAL - help - Say Y here to get an XFS build with many debugging features, - including ASSERT checks, function wrappers around macros, - and extra sanity-checking functions in various code paths. - - Note that the resulting code will be HUGE and SLOW, and probably - not useful unless you are debugging a particular problem. - - Say N unless you are an XFS developer, or you play one on TV. diff --git a/trunk/fs/xfs/linux-2.6/mrlock.h b/trunk/fs/xfs/linux-2.6/mrlock.h index ff6a19873e5c..c110bb002665 100644 --- a/trunk/fs/xfs/linux-2.6/mrlock.h +++ b/trunk/fs/xfs/linux-2.6/mrlock.h @@ -20,24 +20,29 @@ #include +enum { MR_NONE, MR_ACCESS, MR_UPDATE }; + typedef struct { struct rw_semaphore mr_lock; -#ifdef DEBUG int mr_writer; -#endif } mrlock_t; -#ifdef DEBUG #define mrinit(mrp, name) \ do { (mrp)->mr_writer = 0; init_rwsem(&(mrp)->mr_lock); } while (0) -#else -#define mrinit(mrp, name) \ - do { init_rwsem(&(mrp)->mr_lock); } while (0) -#endif - #define mrlock_init(mrp, t,n,s) mrinit(mrp, n) #define mrfree(mrp) do { } while (0) +static inline void mraccess(mrlock_t *mrp) +{ + down_read(&mrp->mr_lock); +} + +static inline void mrupdate(mrlock_t *mrp) +{ + down_write(&mrp->mr_lock); + mrp->mr_writer = 1; +} + static inline void mraccess_nested(mrlock_t *mrp, int subclass) { down_read_nested(&mrp->mr_lock, subclass); @@ -46,11 +51,10 @@ static inline void mraccess_nested(mrlock_t *mrp, int subclass) static inline void mrupdate_nested(mrlock_t *mrp, int subclass) { down_write_nested(&mrp->mr_lock, subclass); -#ifdef DEBUG mrp->mr_writer = 1; -#endif } + static inline int mrtryaccess(mrlock_t *mrp) { return down_read_trylock(&mrp->mr_lock); @@ -60,31 +64,39 @@ static inline int mrtryupdate(mrlock_t *mrp) { if (!down_write_trylock(&mrp->mr_lock)) return 0; -#ifdef DEBUG mrp->mr_writer = 1; -#endif return 1; } -static inline void mrunlock_excl(mrlock_t *mrp) +static inline void mrunlock(mrlock_t *mrp) { -#ifdef DEBUG - mrp->mr_writer = 0; -#endif - up_write(&mrp->mr_lock); -} - -static inline void mrunlock_shared(mrlock_t *mrp) -{ - up_read(&mrp->mr_lock); + if (mrp->mr_writer) { + mrp->mr_writer = 0; + up_write(&mrp->mr_lock); + } else { + up_read(&mrp->mr_lock); + } } static inline void mrdemote(mrlock_t *mrp) { -#ifdef DEBUG mrp->mr_writer = 0; -#endif downgrade_write(&mrp->mr_lock); } +#ifdef DEBUG +/* + * Debug-only routine, without some platform-specific asm code, we can + * now only answer requests regarding whether we hold the lock for write + * (reader state is outside our visibility, we only track writer state). + * Note: means !ismrlocked would give false positives, so don't do that. + */ +static inline int ismrlocked(mrlock_t *mrp, int type) +{ + if (mrp && type == MR_UPDATE) + return mrp->mr_writer; + return 1; +} +#endif + #endif /* __XFS_SUPPORT_MRLOCK_H__ */ diff --git a/trunk/fs/xfs/linux-2.6/xfs_buf.c b/trunk/fs/xfs/linux-2.6/xfs_buf.c index 5105015a75ad..52f6846101d5 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_buf.c +++ b/trunk/fs/xfs/linux-2.6/xfs_buf.c @@ -886,7 +886,7 @@ int xfs_buf_lock_value( xfs_buf_t *bp) { - return bp->b_sema.count; + return atomic_read(&bp->b_sema.count); } #endif diff --git a/trunk/fs/xfs/linux-2.6/xfs_export.c b/trunk/fs/xfs/linux-2.6/xfs_export.c index c672b3238b14..265f0168ab76 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_export.c +++ b/trunk/fs/xfs/linux-2.6/xfs_export.c @@ -133,7 +133,7 @@ xfs_nfs_get_inode( if (!ip) return ERR_PTR(-EIO); - if (ip->i_d.di_gen != generation) { + if (!ip->i_d.di_mode || ip->i_d.di_gen != generation) { xfs_iput_new(ip, XFS_ILOCK_SHARED); return ERR_PTR(-ENOENT); } diff --git a/trunk/fs/xfs/linux-2.6/xfs_file.c b/trunk/fs/xfs/linux-2.6/xfs_file.c index 65e78c13d4ae..05905246434d 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_file.c +++ b/trunk/fs/xfs/linux-2.6/xfs_file.c @@ -43,6 +43,9 @@ #include static struct vm_operations_struct xfs_file_vm_ops; +#ifdef CONFIG_XFS_DMAPI +static struct vm_operations_struct xfs_dmapi_file_vm_ops; +#endif STATIC_INLINE ssize_t __xfs_file_read( @@ -199,6 +202,22 @@ xfs_file_fsync( (xfs_off_t)0, (xfs_off_t)-1); } +#ifdef CONFIG_XFS_DMAPI +STATIC int +xfs_vm_fault( + struct vm_area_struct *vma, + struct vm_fault *vmf) +{ + struct inode *inode = vma->vm_file->f_path.dentry->d_inode; + bhv_vnode_t *vp = vn_from_inode(inode); + + ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI); + if (XFS_SEND_MMAP(XFS_VFSTOM(vp->v_vfsp), vma, 0)) + return VM_FAULT_SIGBUS; + return filemap_fault(vma, vmf); +} +#endif /* CONFIG_XFS_DMAPI */ + /* * Unfortunately we can't just use the clean and simple readdir implementation * below, because nfs might call back into ->lookup from the filldir callback @@ -367,6 +386,11 @@ xfs_file_mmap( vma->vm_ops = &xfs_file_vm_ops; vma->vm_flags |= VM_CAN_NONLINEAR; +#ifdef CONFIG_XFS_DMAPI + if (XFS_M(filp->f_path.dentry->d_inode->i_sb)->m_flags & XFS_MOUNT_DMAPI) + vma->vm_ops = &xfs_dmapi_file_vm_ops; +#endif /* CONFIG_XFS_DMAPI */ + file_accessed(filp); return 0; } @@ -413,6 +437,47 @@ xfs_file_ioctl_invis( return error; } +#ifdef CONFIG_XFS_DMAPI +#ifdef HAVE_VMOP_MPROTECT +STATIC int +xfs_vm_mprotect( + struct vm_area_struct *vma, + unsigned int newflags) +{ + struct inode *inode = vma->vm_file->f_path.dentry->d_inode; + struct xfs_mount *mp = XFS_M(inode->i_sb); + int error = 0; + + if (mp->m_flags & XFS_MOUNT_DMAPI) { + if ((vma->vm_flags & VM_MAYSHARE) && + (newflags & VM_WRITE) && !(vma->vm_flags & VM_WRITE)) + error = XFS_SEND_MMAP(mp, vma, VM_WRITE); + } + return error; +} +#endif /* HAVE_VMOP_MPROTECT */ +#endif /* CONFIG_XFS_DMAPI */ + +#ifdef HAVE_FOP_OPEN_EXEC +/* If the user is attempting to execute a file that is offline then + * we have to trigger a DMAPI READ event before the file is marked as busy + * otherwise the invisible I/O will not be able to write to the file to bring + * it back online. + */ +STATIC int +xfs_file_open_exec( + struct inode *inode) +{ + struct xfs_mount *mp = XFS_M(inode->i_sb); + struct xfs_inode *ip = XFS_I(inode); + + if (unlikely(mp->m_flags & XFS_MOUNT_DMAPI) && + DM_EVENT_ENABLED(ip, DM_EVENT_READ)) + return -XFS_SEND_DATA(mp, DM_EVENT_READ, ip, 0, 0, 0, NULL); + return 0; +} +#endif /* HAVE_FOP_OPEN_EXEC */ + /* * mmap()d file has taken write protection fault and is being made * writable. We can set the page state up correctly for a writable @@ -481,3 +546,13 @@ static struct vm_operations_struct xfs_file_vm_ops = { .fault = filemap_fault, .page_mkwrite = xfs_vm_page_mkwrite, }; + +#ifdef CONFIG_XFS_DMAPI +static struct vm_operations_struct xfs_dmapi_file_vm_ops = { + .fault = xfs_vm_fault, + .page_mkwrite = xfs_vm_page_mkwrite, +#ifdef HAVE_VMOP_MPROTECT + .mprotect = xfs_vm_mprotect, +#endif +}; +#endif /* CONFIG_XFS_DMAPI */ diff --git a/trunk/fs/xfs/linux-2.6/xfs_ioctl.c b/trunk/fs/xfs/linux-2.6/xfs_ioctl.c index a42ba9d71156..4ddb86b73c6b 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/trunk/fs/xfs/linux-2.6/xfs_ioctl.c @@ -238,7 +238,7 @@ xfs_vget_fsop_handlereq( return error; if (ip == NULL) return XFS_ERROR(EIO); - if (ip->i_d.di_gen != igen) { + if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) { xfs_iput_new(ip, XFS_ILOCK_SHARED); return XFS_ERROR(ENOENT); } @@ -505,14 +505,14 @@ xfs_attrmulti_attr_get( { char *kbuf; int error = EFAULT; - + if (*len > XATTR_SIZE_MAX) return EINVAL; kbuf = kmalloc(*len, GFP_KERNEL); if (!kbuf) return ENOMEM; - error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags); + error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags, NULL); if (error) goto out_kfree; @@ -546,7 +546,7 @@ xfs_attrmulti_attr_set( if (copy_from_user(kbuf, ubuf, len)) goto out_kfree; - + error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags); out_kfree: diff --git a/trunk/fs/xfs/linux-2.6/xfs_iops.c b/trunk/fs/xfs/linux-2.6/xfs_iops.c index 2bf287ef5489..a1237dad6430 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_iops.c +++ b/trunk/fs/xfs/linux-2.6/xfs_iops.c @@ -511,8 +511,7 @@ xfs_vn_rename( xfs_dentry_to_name(&nname, ndentry); error = xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode), - XFS_I(ndir), &nname, new_inode ? - XFS_I(new_inode) : NULL); + XFS_I(ndir), &nname); if (likely(!error)) { if (new_inode) xfs_validate_fields(new_inode); diff --git a/trunk/fs/xfs/linux-2.6/xfs_linux.h b/trunk/fs/xfs/linux-2.6/xfs_linux.h index 1bc9f600365f..e5143323e71f 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_linux.h +++ b/trunk/fs/xfs/linux-2.6/xfs_linux.h @@ -99,6 +99,7 @@ /* * Feature macros (disable/enable) */ +#define HAVE_SPLICE /* a splice(2) exists in 2.6, but not in 2.4 */ #ifdef CONFIG_SMP #define HAVE_PERCPU_SB /* per cpu superblock counters are a 2.6 feature */ #else diff --git a/trunk/fs/xfs/linux-2.6/xfs_lrw.c b/trunk/fs/xfs/linux-2.6/xfs_lrw.c index 5e3b57516ec7..1ebd8004469c 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_lrw.c +++ b/trunk/fs/xfs/linux-2.6/xfs_lrw.c @@ -394,7 +394,7 @@ xfs_zero_last_block( int error = 0; xfs_bmbt_irec_t imap; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0); zero_offset = XFS_B_FSB_OFFSET(mp, isize); if (zero_offset == 0) { @@ -425,14 +425,14 @@ xfs_zero_last_block( * out sync. We need to drop the ilock while we do this so we * don't deadlock when the buffer cache calls back to us. */ - xfs_iunlock(ip, XFS_ILOCK_EXCL); + xfs_iunlock(ip, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD); zero_len = mp->m_sb.sb_blocksize - zero_offset; if (isize + zero_len > offset) zero_len = offset - isize; error = xfs_iozero(ip, isize, zero_len); - xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_ilock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); ASSERT(error >= 0); return error; } @@ -465,7 +465,8 @@ xfs_zero_eof( int error = 0; xfs_bmbt_irec_t imap; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); ASSERT(offset > isize); /* @@ -474,7 +475,8 @@ xfs_zero_eof( */ error = xfs_zero_last_block(ip, offset, isize); if (error) { - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); return error; } @@ -505,7 +507,8 @@ xfs_zero_eof( error = xfs_bmapi(NULL, ip, start_zero_fsb, zero_count_fsb, 0, NULL, 0, &imap, &nimaps, NULL, NULL); if (error) { - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); return error; } ASSERT(nimaps > 0); @@ -529,7 +532,7 @@ xfs_zero_eof( * Drop the inode lock while we're doing the I/O. * We'll still have the iolock to protect us. */ - xfs_iunlock(ip, XFS_ILOCK_EXCL); + xfs_iunlock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); zero_off = XFS_FSB_TO_B(mp, start_zero_fsb); zero_len = XFS_FSB_TO_B(mp, imap.br_blockcount); @@ -545,13 +548,13 @@ xfs_zero_eof( start_zero_fsb = imap.br_startoff + imap.br_blockcount; ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); - xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_ilock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); } return 0; out_lock: - xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_ilock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); ASSERT(error >= 0); return error; } diff --git a/trunk/fs/xfs/linux-2.6/xfs_lrw.h b/trunk/fs/xfs/linux-2.6/xfs_lrw.h index e6be37dbd0e9..e1d498b4ba7a 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_lrw.h +++ b/trunk/fs/xfs/linux-2.6/xfs_lrw.h @@ -50,6 +50,7 @@ struct xfs_iomap; #define XFS_INVAL_CACHED 18 #define XFS_DIORD_ENTER 19 #define XFS_DIOWR_ENTER 20 +#define XFS_SENDFILE_ENTER 21 #define XFS_WRITEPAGE_ENTER 22 #define XFS_RELEASEPAGE_ENTER 23 #define XFS_INVALIDPAGE_ENTER 24 diff --git a/trunk/fs/xfs/linux-2.6/xfs_super.c b/trunk/fs/xfs/linux-2.6/xfs_super.c index 742b2c7852c1..865eb708aa95 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_super.c +++ b/trunk/fs/xfs/linux-2.6/xfs_super.c @@ -1181,7 +1181,7 @@ xfs_fs_statfs( statp->f_fsid.val[0] = (u32)id; statp->f_fsid.val[1] = (u32)(id >> 32); - xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT); + xfs_icsb_sync_counters_flags(mp, XFS_ICSB_LAZY_COUNT); spin_lock(&mp->m_sb_lock); statp->f_bsize = sbp->sb_blocksize; diff --git a/trunk/fs/xfs/linux-2.6/xfs_vnode.h b/trunk/fs/xfs/linux-2.6/xfs_vnode.h index 9d73cb5c0fc7..8b4d63ce8694 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_vnode.h +++ b/trunk/fs/xfs/linux-2.6/xfs_vnode.h @@ -25,6 +25,12 @@ struct attrlist_cursor_kern; typedef struct inode bhv_vnode_t; +#define VN_ISLNK(vp) S_ISLNK((vp)->i_mode) +#define VN_ISREG(vp) S_ISREG((vp)->i_mode) +#define VN_ISDIR(vp) S_ISDIR((vp)->i_mode) +#define VN_ISCHR(vp) S_ISCHR((vp)->i_mode) +#define VN_ISBLK(vp) S_ISBLK((vp)->i_mode) + /* * Vnode to Linux inode mapping. */ @@ -145,6 +151,24 @@ typedef struct bhv_vattr { XFS_AT_TYPE|XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|\ XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_GENCOUNT) +/* + * Modes. + */ +#define VSUID S_ISUID /* set user id on execution */ +#define VSGID S_ISGID /* set group id on execution */ +#define VSVTX S_ISVTX /* save swapped text even after use */ +#define VREAD S_IRUSR /* read, write, execute permissions */ +#define VWRITE S_IWUSR +#define VEXEC S_IXUSR + +#define MODEMASK S_IALLUGO /* mode bits plus permission bits */ + +/* + * Check whether mandatory file locking is enabled. + */ +#define MANDLOCK(vp, mode) \ + (VN_ISREG(vp) && ((mode) & (VSGID|(VEXEC>>3))) == VSGID) + extern void vn_init(void); extern int vn_revalidate(bhv_vnode_t *); diff --git a/trunk/fs/xfs/quota/xfs_dquot.c b/trunk/fs/xfs/quota/xfs_dquot.c index 85df3288efd5..631ebb31b295 100644 --- a/trunk/fs/xfs/quota/xfs_dquot.c +++ b/trunk/fs/xfs/quota/xfs_dquot.c @@ -933,7 +933,7 @@ xfs_qm_dqget( type == XFS_DQ_PROJ || type == XFS_DQ_GROUP); if (ip) { - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); if (type == XFS_DQ_USER) ASSERT(ip->i_udquot == NULL); else @@ -1088,7 +1088,7 @@ xfs_qm_dqget( xfs_qm_mplist_unlock(mp); XFS_DQ_HASH_UNLOCK(h); dqret: - ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT((ip == NULL) || XFS_ISLOCKED_INODE_EXCL(ip)); xfs_dqtrace_entry(dqp, "DQGET DONE"); *O_dqpp = dqp; return (0); diff --git a/trunk/fs/xfs/quota/xfs_qm.c b/trunk/fs/xfs/quota/xfs_qm.c index d31cce1165c5..40ea56409561 100644 --- a/trunk/fs/xfs/quota/xfs_qm.c +++ b/trunk/fs/xfs/quota/xfs_qm.c @@ -670,7 +670,7 @@ xfs_qm_dqattach_one( xfs_dquot_t *dqp; int error; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); error = 0; /* * See if we already have it in the inode itself. IO_idqpp is @@ -874,7 +874,7 @@ xfs_qm_dqattach( return 0; ASSERT((flags & XFS_QMOPT_ILOCKED) == 0 || - xfs_isilocked(ip, XFS_ILOCK_EXCL)); + XFS_ISLOCKED_INODE_EXCL(ip)); if (! (flags & XFS_QMOPT_ILOCKED)) xfs_ilock(ip, XFS_ILOCK_EXCL); @@ -888,8 +888,7 @@ xfs_qm_dqattach( goto done; nquotas++; } - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); if (XFS_IS_OQUOTA_ON(mp)) { error = XFS_IS_GQUOTA_ON(mp) ? xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP, @@ -914,7 +913,7 @@ xfs_qm_dqattach( * This WON'T, in general, result in a thrash. */ if (nquotas == 2) { - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); ASSERT(ip->i_udquot); ASSERT(ip->i_gdquot); @@ -957,7 +956,7 @@ xfs_qm_dqattach( #ifdef QUOTADEBUG else - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); #endif return error; } @@ -1292,7 +1291,7 @@ xfs_qm_dqget_noattach( xfs_mount_t *mp; xfs_dquot_t *udqp, *gdqp; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); mp = ip->i_mount; udqp = NULL; gdqp = NULL; @@ -1393,7 +1392,7 @@ xfs_qm_qino_alloc( * Keep an extra reference to this quota inode. This inode is * locked exclusively and joined to the transaction already. */ - ASSERT(xfs_isilocked(*ip, XFS_ILOCK_EXCL)); + ASSERT(XFS_ISLOCKED_INODE_EXCL(*ip)); VN_HOLD(XFS_ITOV((*ip))); /* @@ -1738,6 +1737,12 @@ xfs_qm_dqusage_adjust( return error; } + if (ip->i_d.di_mode == 0) { + xfs_iput_new(ip, XFS_ILOCK_EXCL); + *res = BULKSTAT_RV_NOTHING; + return XFS_ERROR(ENOENT); + } + /* * Obtain the locked dquots. In case of an error (eg. allocation * fails for ENOSPC), we return the negative of the error number @@ -2558,7 +2563,7 @@ xfs_qm_vop_chown( uint bfield = XFS_IS_REALTIME_INODE(ip) ? XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount)); /* old dquot */ @@ -2602,7 +2607,7 @@ xfs_qm_vop_chown_reserve( uint delblks, blkflags, prjflags = 0; xfs_dquot_t *unresudq, *unresgdq, *delblksudq, *delblksgdq; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); + ASSERT(XFS_ISLOCKED_INODE(ip)); mp = ip->i_mount; ASSERT(XFS_IS_QUOTA_RUNNING(mp)); @@ -2712,7 +2717,7 @@ xfs_qm_vop_dqattach_and_dqmod_newinode( if (!XFS_IS_QUOTA_ON(tp->t_mountp)) return; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp)); if (udqp) { diff --git a/trunk/fs/xfs/quota/xfs_qm_syscalls.c b/trunk/fs/xfs/quota/xfs_qm_syscalls.c index 768a3b27d2b6..8342823dbdc3 100644 --- a/trunk/fs/xfs/quota/xfs_qm_syscalls.c +++ b/trunk/fs/xfs/quota/xfs_qm_syscalls.c @@ -1366,6 +1366,12 @@ xfs_qm_internalqcheck_adjust( return (error); } + if (ip->i_d.di_mode == 0) { + xfs_iput_new(ip, lock_flags); + *res = BULKSTAT_RV_NOTHING; + return XFS_ERROR(ENOENT); + } + /* * This inode can have blocks after eof which can get released * when we send it to inactive. Since we don't check the dquot diff --git a/trunk/fs/xfs/quota/xfs_quota_priv.h b/trunk/fs/xfs/quota/xfs_quota_priv.h index 5e4a40b1c565..a8b85e2be9d5 100644 --- a/trunk/fs/xfs/quota/xfs_quota_priv.h +++ b/trunk/fs/xfs/quota/xfs_quota_priv.h @@ -27,6 +27,11 @@ /* Number of dquots that fit in to a dquot block */ #define XFS_QM_DQPERBLK(mp) ((mp)->m_quotainfo->qi_dqperchunk) +#define XFS_ISLOCKED_INODE(ip) (ismrlocked(&(ip)->i_lock, \ + MR_UPDATE | MR_ACCESS) != 0) +#define XFS_ISLOCKED_INODE_EXCL(ip) (ismrlocked(&(ip)->i_lock, \ + MR_UPDATE) != 0) + #define XFS_DQ_IS_ADDEDTO_TRX(t, d) ((d)->q_transp == (t)) #define XFS_QI_MPLRECLAIMS(mp) ((mp)->m_quotainfo->qi_dqreclaims) diff --git a/trunk/fs/xfs/quota/xfs_trans_dquot.c b/trunk/fs/xfs/quota/xfs_trans_dquot.c index 99611381e740..f441f836ca8b 100644 --- a/trunk/fs/xfs/quota/xfs_trans_dquot.c +++ b/trunk/fs/xfs/quota/xfs_trans_dquot.c @@ -834,7 +834,7 @@ xfs_trans_reserve_quota_nblks( ASSERT(ip->i_ino != mp->m_sb.sb_uquotino); ASSERT(ip->i_ino != mp->m_sb.sb_gquotino); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount)); ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) == XFS_TRANS_DQ_RES_RTBLKS || diff --git a/trunk/fs/xfs/xfs.h b/trunk/fs/xfs/xfs.h index 540e4c989825..765aaf65e2d3 100644 --- a/trunk/fs/xfs/xfs.h +++ b/trunk/fs/xfs/xfs.h @@ -22,7 +22,7 @@ #define STATIC #define DEBUG 1 #define XFS_BUF_LOCK_TRACKING 1 -/* #define QUOTADEBUG 1 */ +#define QUOTADEBUG 1 #endif #ifdef CONFIG_XFS_TRACE diff --git a/trunk/fs/xfs/xfs_acl.c b/trunk/fs/xfs/xfs_acl.c index ebee3a4f703a..8e130b9720ae 100644 --- a/trunk/fs/xfs/xfs_acl.c +++ b/trunk/fs/xfs/xfs_acl.c @@ -72,7 +72,7 @@ xfs_acl_vhasacl_default( { int error; - if (!S_ISDIR(vp->i_mode)) + if (!VN_ISDIR(vp)) return 0; xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error); return (error == 0); @@ -238,8 +238,15 @@ xfs_acl_vget( error = EINVAL; goto out; } - if (kind == _ACL_TYPE_ACCESS) - xfs_acl_sync_mode(xfs_vtoi(vp)->i_d.di_mode, xfs_acl); + if (kind == _ACL_TYPE_ACCESS) { + bhv_vattr_t va; + + va.va_mask = XFS_AT_MODE; + error = xfs_getattr(xfs_vtoi(vp), &va, 0); + if (error) + goto out; + xfs_acl_sync_mode(va.va_mode, xfs_acl); + } error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size); } out: @@ -334,15 +341,14 @@ xfs_acl_iaccess( { xfs_acl_t *acl; int rval; - struct xfs_name acl_name = {SGI_ACL_FILE, SGI_ACL_FILE_SIZE}; if (!(_ACL_ALLOC(acl))) return -1; /* If the file has no ACL return -1. */ rval = sizeof(xfs_acl_t); - if (xfs_attr_fetch(ip, &acl_name, (char *)acl, &rval, - ATTR_ROOT | ATTR_KERNACCESS)) { + if (xfs_attr_fetch(ip, SGI_ACL_FILE, SGI_ACL_FILE_SIZE, + (char *)acl, &rval, ATTR_ROOT | ATTR_KERNACCESS, cr)) { _ACL_FREE(acl); return -1; } @@ -367,15 +373,23 @@ xfs_acl_allow_set( bhv_vnode_t *vp, int kind) { + xfs_inode_t *ip = xfs_vtoi(vp); + bhv_vattr_t va; + int error; + if (vp->i_flags & (S_IMMUTABLE|S_APPEND)) return EPERM; - if (kind == _ACL_TYPE_DEFAULT && !S_ISDIR(vp->i_mode)) + if (kind == _ACL_TYPE_DEFAULT && !VN_ISDIR(vp)) return ENOTDIR; if (vp->i_sb->s_flags & MS_RDONLY) return EROFS; - if (xfs_vtoi(vp)->i_d.di_uid != current->fsuid && !capable(CAP_FOWNER)) + va.va_mask = XFS_AT_UID; + error = xfs_getattr(ip, &va, 0); + if (error) + return error; + if (va.va_uid != current->fsuid && !capable(CAP_FOWNER)) return EPERM; - return 0; + return error; } /* @@ -580,7 +594,7 @@ xfs_acl_get_attr( *error = xfs_attr_get(xfs_vtoi(vp), kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE : SGI_ACL_DEFAULT, - (char *)aclp, &len, flags); + (char *)aclp, &len, flags, sys_cred); if (*error || (flags & ATTR_KERNOVAL)) return; xfs_acl_get_endian(aclp); @@ -629,6 +643,7 @@ xfs_acl_vtoacl( xfs_acl_t *access_acl, xfs_acl_t *default_acl) { + bhv_vattr_t va; int error = 0; if (access_acl) { @@ -637,10 +652,16 @@ xfs_acl_vtoacl( * be obtained for some reason, invalidate the access ACL. */ xfs_acl_get_attr(vp, access_acl, _ACL_TYPE_ACCESS, 0, &error); + if (!error) { + /* Got the ACL, need the mode... */ + va.va_mask = XFS_AT_MODE; + error = xfs_getattr(xfs_vtoi(vp), &va, 0); + } + if (error) access_acl->acl_cnt = XFS_ACL_NOT_PRESENT; else /* We have a good ACL and the file mode, synchronize. */ - xfs_acl_sync_mode(xfs_vtoi(vp)->i_d.di_mode, access_acl); + xfs_acl_sync_mode(va.va_mode, access_acl); } if (default_acl) { @@ -698,7 +719,7 @@ xfs_acl_inherit( * If the new file is a directory, its default ACL is a copy of * the containing directory's default ACL. */ - if (S_ISDIR(vp->i_mode)) + if (VN_ISDIR(vp)) xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error); if (!error && !basicperms) xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error); @@ -723,7 +744,7 @@ xfs_acl_setmode( bhv_vattr_t va; xfs_acl_entry_t *ap; xfs_acl_entry_t *gap = NULL; - int i, nomask = 1; + int i, error, nomask = 1; *basicperms = 1; @@ -735,7 +756,11 @@ xfs_acl_setmode( * mode. The m:: bits take precedence over the g:: bits. */ va.va_mask = XFS_AT_MODE; - va.va_mode = xfs_vtoi(vp)->i_d.di_mode; + error = xfs_getattr(xfs_vtoi(vp), &va, 0); + if (error) + return error; + + va.va_mask = XFS_AT_MODE; va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); ap = acl->acl_entry; for (i = 0; i < acl->acl_cnt; ++i) { diff --git a/trunk/fs/xfs/xfs_attr.c b/trunk/fs/xfs/xfs_attr.c index df151a859186..36d781ee5fcc 100644 --- a/trunk/fs/xfs/xfs_attr.c +++ b/trunk/fs/xfs/xfs_attr.c @@ -101,28 +101,14 @@ STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args); ktrace_t *xfs_attr_trace_buf; #endif -STATIC int -xfs_attr_name_to_xname( - struct xfs_name *xname, - const char *aname) -{ - if (!aname) - return EINVAL; - xname->name = aname; - xname->len = strlen(aname); - if (xname->len >= MAXNAMELEN) - return EFAULT; /* match IRIX behaviour */ - - return 0; -} /*======================================================================== * Overall external interface routines. *========================================================================*/ int -xfs_attr_fetch(xfs_inode_t *ip, struct xfs_name *name, - char *value, int *valuelenp, int flags) +xfs_attr_fetch(xfs_inode_t *ip, const char *name, int namelen, + char *value, int *valuelenp, int flags, struct cred *cred) { xfs_da_args_t args; int error; @@ -136,8 +122,8 @@ xfs_attr_fetch(xfs_inode_t *ip, struct xfs_name *name, * Fill in the arg structure for this request. */ memset((char *)&args, 0, sizeof(args)); - args.name = name->name; - args.namelen = name->len; + args.name = name; + args.namelen = namelen; args.value = value; args.valuelen = *valuelenp; args.flags = flags; @@ -176,29 +162,31 @@ xfs_attr_get( const char *name, char *value, int *valuelenp, - int flags) + int flags, + cred_t *cred) { - int error; - struct xfs_name xname; + int error, namelen; XFS_STATS_INC(xs_attr_get); + if (!name) + return(EINVAL); + namelen = strlen(name); + if (namelen >= MAXNAMELEN) + return(EFAULT); /* match IRIX behaviour */ + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) return(EIO); - error = xfs_attr_name_to_xname(&xname, name); - if (error) - return error; - xfs_ilock(ip, XFS_ILOCK_SHARED); - error = xfs_attr_fetch(ip, &xname, value, valuelenp, flags); + error = xfs_attr_fetch(ip, name, namelen, value, valuelenp, flags, cred); xfs_iunlock(ip, XFS_ILOCK_SHARED); return(error); } -STATIC int -xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, - char *value, int valuelen, int flags) +int +xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, + char *value, int valuelen, int flags) { xfs_da_args_t args; xfs_fsblock_t firstblock; @@ -221,7 +209,7 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, */ if (XFS_IFORK_Q(dp) == 0) { int sf_size = sizeof(xfs_attr_sf_hdr_t) + - XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen); + XFS_ATTR_SF_ENTSIZE_BYNAME(namelen, valuelen); if ((error = xfs_bmap_add_attrfork(dp, sf_size, rsvd))) return(error); @@ -231,8 +219,8 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, * Fill in the arg structure for this request. */ memset((char *)&args, 0, sizeof(args)); - args.name = name->name; - args.namelen = name->len; + args.name = name; + args.namelen = namelen; args.value = value; args.valuelen = valuelen; args.flags = flags; @@ -248,7 +236,7 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, * Determine space new attribute will use, and if it would be * "local" or "remote" (note: local != inline). */ - size = xfs_attr_leaf_newentsize(name->len, valuelen, + size = xfs_attr_leaf_newentsize(namelen, valuelen, mp->m_sb.sb_blocksize, &local); nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); @@ -441,27 +429,26 @@ xfs_attr_set( int valuelen, int flags) { - int error; - struct xfs_name xname; + int namelen; + + namelen = strlen(name); + if (namelen >= MAXNAMELEN) + return EFAULT; /* match IRIX behaviour */ XFS_STATS_INC(xs_attr_set); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return (EIO); - error = xfs_attr_name_to_xname(&xname, name); - if (error) - return error; - - return xfs_attr_set_int(dp, &xname, value, valuelen, flags); + return xfs_attr_set_int(dp, name, namelen, value, valuelen, flags); } /* * Generic handler routine to remove a name from an attribute list. * Transitions attribute list from Btree to shortform as necessary. */ -STATIC int -xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags) +int +xfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags) { xfs_da_args_t args; xfs_fsblock_t firstblock; @@ -473,8 +460,8 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags) * Fill in the arg structure for this request. */ memset((char *)&args, 0, sizeof(args)); - args.name = name->name; - args.namelen = name->len; + args.name = name; + args.namelen = namelen; args.flags = flags; args.hashval = xfs_da_hashname(args.name, args.namelen); args.dp = dp; @@ -588,18 +575,17 @@ xfs_attr_remove( const char *name, int flags) { - int error; - struct xfs_name xname; + int namelen; + + namelen = strlen(name); + if (namelen >= MAXNAMELEN) + return EFAULT; /* match IRIX behaviour */ XFS_STATS_INC(xs_attr_remove); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return (EIO); - error = xfs_attr_name_to_xname(&xname, name); - if (error) - return error; - xfs_ilock(dp, XFS_ILOCK_SHARED); if (XFS_IFORK_Q(dp) == 0 || (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && @@ -609,10 +595,10 @@ xfs_attr_remove( } xfs_iunlock(dp, XFS_ILOCK_SHARED); - return xfs_attr_remove_int(dp, &xname, flags); + return xfs_attr_remove_int(dp, name, namelen, flags); } -STATIC int +int /* error */ xfs_attr_list_int(xfs_attr_list_context_t *context) { int error; @@ -2536,7 +2522,8 @@ attr_generic_get( { int error, asize = size; - error = xfs_attr_get(xfs_vtoi(vp), name, data, &asize, xflags); + error = xfs_attr_get(xfs_vtoi(vp), name, data, + &asize, xflags, NULL); if (!error) return asize; return -error; diff --git a/trunk/fs/xfs/xfs_attr.h b/trunk/fs/xfs/xfs_attr.h index 6cfc9384fe35..786eba3121c4 100644 --- a/trunk/fs/xfs/xfs_attr.h +++ b/trunk/fs/xfs/xfs_attr.h @@ -158,10 +158,14 @@ struct xfs_da_args; /* * Overall external interface routines. */ +int xfs_attr_set_int(struct xfs_inode *, const char *, int, char *, int, int); +int xfs_attr_remove_int(struct xfs_inode *, const char *, int, int); +int xfs_attr_list_int(struct xfs_attr_list_context *); int xfs_attr_inactive(struct xfs_inode *dp); int xfs_attr_shortform_getvalue(struct xfs_da_args *); -int xfs_attr_fetch(struct xfs_inode *, struct xfs_name *, char *, int *, int); +int xfs_attr_fetch(struct xfs_inode *, const char *, int, + char *, int *, int, struct cred *); int xfs_attr_rmtval_get(struct xfs_da_args *args); #endif /* __XFS_ATTR_H__ */ diff --git a/trunk/fs/xfs/xfs_bmap.c b/trunk/fs/xfs/xfs_bmap.c index 53c259f5a5af..eb198c01c35d 100644 --- a/trunk/fs/xfs/xfs_bmap.c +++ b/trunk/fs/xfs/xfs_bmap.c @@ -4074,6 +4074,7 @@ xfs_bmap_add_attrfork( error2: xfs_bmap_cancel(&flist); error1: + ASSERT(ismrlocked(&ip->i_lock,MR_UPDATE)); xfs_iunlock(ip, XFS_ILOCK_EXCL); error0: xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); diff --git a/trunk/fs/xfs/xfs_dfrag.c b/trunk/fs/xfs/xfs_dfrag.c index 5f3647cb9885..3f53fad356a3 100644 --- a/trunk/fs/xfs/xfs_dfrag.c +++ b/trunk/fs/xfs/xfs_dfrag.c @@ -162,7 +162,7 @@ xfs_swap_extents( ips[1] = ip; } - xfs_lock_inodes(ips, 2, lock_flags); + xfs_lock_inodes(ips, 2, 0, lock_flags); locked = 1; /* Verify that both files have the same format */ @@ -265,7 +265,7 @@ xfs_swap_extents( locked = 0; goto error0; } - xfs_lock_inodes(ips, 2, XFS_ILOCK_EXCL); + xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); /* * Count the number of extended attribute blocks diff --git a/trunk/fs/xfs/xfs_fsops.c b/trunk/fs/xfs/xfs_fsops.c index 381ebda4f7bc..d3a0f538d6a6 100644 --- a/trunk/fs/xfs/xfs_fsops.c +++ b/trunk/fs/xfs/xfs_fsops.c @@ -462,7 +462,7 @@ xfs_fs_counts( xfs_mount_t *mp, xfs_fsop_counts_t *cnt) { - xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT); + xfs_icsb_sync_counters_flags(mp, XFS_ICSB_LAZY_COUNT); spin_lock(&mp->m_sb_lock); cnt->freedata = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); cnt->freertx = mp->m_sb.sb_frextents; @@ -524,7 +524,7 @@ xfs_reserve_blocks( */ retry: spin_lock(&mp->m_sb_lock); - xfs_icsb_sync_counters_locked(mp, 0); + xfs_icsb_sync_counters_flags(mp, XFS_ICSB_SB_LOCKED); /* * If our previous reservation was larger than the current value, @@ -552,8 +552,11 @@ xfs_reserve_blocks( mp->m_resblks += free; mp->m_resblks_avail += free; fdblks_delta = -free; + mp->m_sb.sb_fdblocks = XFS_ALLOC_SET_ASIDE(mp); } else { fdblks_delta = -delta; + mp->m_sb.sb_fdblocks = + lcounter + XFS_ALLOC_SET_ASIDE(mp); mp->m_resblks = request; mp->m_resblks_avail += delta; } @@ -584,6 +587,7 @@ xfs_reserve_blocks( if (error == ENOSPC) goto retry; } + return 0; } diff --git a/trunk/fs/xfs/xfs_ialloc.c b/trunk/fs/xfs/xfs_ialloc.c index aad8c5da38af..a64dfbd565a5 100644 --- a/trunk/fs/xfs/xfs_ialloc.c +++ b/trunk/fs/xfs/xfs_ialloc.c @@ -147,7 +147,6 @@ xfs_ialloc_ag_alloc( int version; /* inode version number to use */ int isaligned = 0; /* inode allocation at stripe unit */ /* boundary */ - unsigned int gen; args.tp = tp; args.mp = tp->t_mountp; @@ -291,14 +290,6 @@ xfs_ialloc_ag_alloc( else version = XFS_DINODE_VERSION_1; - /* - * Seed the new inode cluster with a random generation number. This - * prevents short-term reuse of generation numbers if a chunk is - * freed and then immediately reallocated. We use random numbers - * rather than a linear progression to prevent the next generation - * number from being easily guessable. - */ - gen = random32(); for (j = 0; j < nbufs; j++) { /* * Get the block. @@ -318,7 +309,6 @@ xfs_ialloc_ag_alloc( free = XFS_MAKE_IPTR(args.mp, fbuf, i); free->di_core.di_magic = cpu_to_be16(XFS_DINODE_MAGIC); free->di_core.di_version = version; - free->di_core.di_gen = cpu_to_be32(gen); free->di_next_unlinked = cpu_to_be32(NULLAGINO); xfs_ialloc_log_di(tp, fbuf, i, XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED); diff --git a/trunk/fs/xfs/xfs_iget.c b/trunk/fs/xfs/xfs_iget.c index b07604b94d9f..e657c5128460 100644 --- a/trunk/fs/xfs/xfs_iget.c +++ b/trunk/fs/xfs/xfs_iget.c @@ -593,9 +593,8 @@ xfs_iunlock_map_shared( * XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL */ void -xfs_ilock( - xfs_inode_t *ip, - uint lock_flags) +xfs_ilock(xfs_inode_t *ip, + uint lock_flags) { /* * You can't set both SHARED and EXCL for the same lock, @@ -608,16 +607,16 @@ xfs_ilock( (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0); - if (lock_flags & XFS_IOLOCK_EXCL) + if (lock_flags & XFS_IOLOCK_EXCL) { mrupdate_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags)); - else if (lock_flags & XFS_IOLOCK_SHARED) + } else if (lock_flags & XFS_IOLOCK_SHARED) { mraccess_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags)); - - if (lock_flags & XFS_ILOCK_EXCL) + } + if (lock_flags & XFS_ILOCK_EXCL) { mrupdate_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags)); - else if (lock_flags & XFS_ILOCK_SHARED) + } else if (lock_flags & XFS_ILOCK_SHARED) { mraccess_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags)); - + } xfs_ilock_trace(ip, 1, lock_flags, (inst_t *)__return_address); } @@ -632,12 +631,15 @@ xfs_ilock( * lock_flags -- this parameter indicates the inode's locks to be * to be locked. See the comment for xfs_ilock() for a list * of valid values. + * */ int -xfs_ilock_nowait( - xfs_inode_t *ip, - uint lock_flags) +xfs_ilock_nowait(xfs_inode_t *ip, + uint lock_flags) { + int iolocked; + int ilocked; + /* * You can't set both SHARED and EXCL for the same lock, * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, @@ -649,30 +651,37 @@ xfs_ilock_nowait( (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0); + iolocked = 0; if (lock_flags & XFS_IOLOCK_EXCL) { - if (!mrtryupdate(&ip->i_iolock)) - goto out; + iolocked = mrtryupdate(&ip->i_iolock); + if (!iolocked) { + return 0; + } } else if (lock_flags & XFS_IOLOCK_SHARED) { - if (!mrtryaccess(&ip->i_iolock)) - goto out; + iolocked = mrtryaccess(&ip->i_iolock); + if (!iolocked) { + return 0; + } } if (lock_flags & XFS_ILOCK_EXCL) { - if (!mrtryupdate(&ip->i_lock)) - goto out_undo_iolock; + ilocked = mrtryupdate(&ip->i_lock); + if (!ilocked) { + if (iolocked) { + mrunlock(&ip->i_iolock); + } + return 0; + } } else if (lock_flags & XFS_ILOCK_SHARED) { - if (!mrtryaccess(&ip->i_lock)) - goto out_undo_iolock; + ilocked = mrtryaccess(&ip->i_lock); + if (!ilocked) { + if (iolocked) { + mrunlock(&ip->i_iolock); + } + return 0; + } } xfs_ilock_trace(ip, 2, lock_flags, (inst_t *)__return_address); return 1; - - out_undo_iolock: - if (lock_flags & XFS_IOLOCK_EXCL) - mrunlock_excl(&ip->i_iolock); - else if (lock_flags & XFS_IOLOCK_SHARED) - mrunlock_shared(&ip->i_iolock); - out: - return 0; } /* @@ -688,9 +697,8 @@ xfs_ilock_nowait( * */ void -xfs_iunlock( - xfs_inode_t *ip, - uint lock_flags) +xfs_iunlock(xfs_inode_t *ip, + uint lock_flags) { /* * You can't set both SHARED and EXCL for the same lock, @@ -705,25 +713,31 @@ xfs_iunlock( XFS_LOCK_DEP_MASK)) == 0); ASSERT(lock_flags != 0); - if (lock_flags & XFS_IOLOCK_EXCL) - mrunlock_excl(&ip->i_iolock); - else if (lock_flags & XFS_IOLOCK_SHARED) - mrunlock_shared(&ip->i_iolock); + if (lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) { + ASSERT(!(lock_flags & XFS_IOLOCK_SHARED) || + (ismrlocked(&ip->i_iolock, MR_ACCESS))); + ASSERT(!(lock_flags & XFS_IOLOCK_EXCL) || + (ismrlocked(&ip->i_iolock, MR_UPDATE))); + mrunlock(&ip->i_iolock); + } - if (lock_flags & XFS_ILOCK_EXCL) - mrunlock_excl(&ip->i_lock); - else if (lock_flags & XFS_ILOCK_SHARED) - mrunlock_shared(&ip->i_lock); + if (lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) { + ASSERT(!(lock_flags & XFS_ILOCK_SHARED) || + (ismrlocked(&ip->i_lock, MR_ACCESS))); + ASSERT(!(lock_flags & XFS_ILOCK_EXCL) || + (ismrlocked(&ip->i_lock, MR_UPDATE))); + mrunlock(&ip->i_lock); - if ((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) && - !(lock_flags & XFS_IUNLOCK_NONOTIFY) && ip->i_itemp) { /* * Let the AIL know that this item has been unlocked in case * it is in the AIL and anyone is waiting on it. Don't do * this if the caller has asked us not to. */ - xfs_trans_unlocked_item(ip->i_mount, - (xfs_log_item_t*)(ip->i_itemp)); + if (!(lock_flags & XFS_IUNLOCK_NONOTIFY) && + ip->i_itemp != NULL) { + xfs_trans_unlocked_item(ip->i_mount, + (xfs_log_item_t*)(ip->i_itemp)); + } } xfs_ilock_trace(ip, 3, lock_flags, (inst_t *)__return_address); } @@ -733,47 +747,21 @@ xfs_iunlock( * if it is being demoted. */ void -xfs_ilock_demote( - xfs_inode_t *ip, - uint lock_flags) +xfs_ilock_demote(xfs_inode_t *ip, + uint lock_flags) { ASSERT(lock_flags & (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)); ASSERT((lock_flags & ~(XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)) == 0); - if (lock_flags & XFS_ILOCK_EXCL) + if (lock_flags & XFS_ILOCK_EXCL) { + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); mrdemote(&ip->i_lock); - if (lock_flags & XFS_IOLOCK_EXCL) - mrdemote(&ip->i_iolock); -} - -#ifdef DEBUG -/* - * Debug-only routine, without additional rw_semaphore APIs, we can - * now only answer requests regarding whether we hold the lock for write - * (reader state is outside our visibility, we only track writer state). - * - * Note: this means !xfs_isilocked would give false positives, so don't do that. - */ -int -xfs_isilocked( - xfs_inode_t *ip, - uint lock_flags) -{ - if ((lock_flags & (XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)) == - XFS_ILOCK_EXCL) { - if (!ip->i_lock.mr_writer) - return 0; } - - if ((lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) == - XFS_IOLOCK_EXCL) { - if (!ip->i_iolock.mr_writer) - return 0; + if (lock_flags & XFS_IOLOCK_EXCL) { + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); + mrdemote(&ip->i_iolock); } - - return 1; } -#endif /* * The following three routines simply manage the i_flock diff --git a/trunk/fs/xfs/xfs_inode.c b/trunk/fs/xfs/xfs_inode.c index cf0bb9c1d621..ca12acb90394 100644 --- a/trunk/fs/xfs/xfs_inode.c +++ b/trunk/fs/xfs/xfs_inode.c @@ -1291,7 +1291,7 @@ xfs_file_last_byte( xfs_fileoff_t size_last_block; int error; - ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)); + ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE | MR_ACCESS)); mp = ip->i_mount; /* @@ -1402,7 +1402,7 @@ xfs_itruncate_start( bhv_vnode_t *vp; int error = 0; - ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0); ASSERT((new_size == 0) || (new_size <= ip->i_size)); ASSERT((flags == XFS_ITRUNC_DEFINITE) || (flags == XFS_ITRUNC_MAYBE)); @@ -1528,7 +1528,8 @@ xfs_itruncate_finish( xfs_bmap_free_t free_list; int error; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0); ASSERT((new_size == 0) || (new_size <= ip->i_size)); ASSERT(*tp != NULL); ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); @@ -1779,7 +1780,8 @@ xfs_igrow_start( xfs_fsize_t new_size, cred_t *credp) { - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); + ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0); + ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0); ASSERT(new_size > ip->i_size); /* @@ -1807,7 +1809,8 @@ xfs_igrow_finish( xfs_fsize_t new_size, int change_flag) { - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); + ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0); + ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0); ASSERT(ip->i_transp == tp); ASSERT(new_size > ip->i_size); @@ -2284,7 +2287,7 @@ xfs_ifree( xfs_dinode_t *dip; xfs_buf_t *ibp; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); ASSERT(ip->i_transp == tp); ASSERT(ip->i_d.di_nlink == 0); ASSERT(ip->i_d.di_nextents == 0); @@ -2743,7 +2746,7 @@ void xfs_ipin( xfs_inode_t *ip) { - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); atomic_inc(&ip->i_pincount); } @@ -2776,7 +2779,7 @@ __xfs_iunpin_wait( { xfs_inode_log_item_t *iip = ip->i_itemp; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE | MR_ACCESS)); if (atomic_read(&ip->i_pincount) == 0) return; @@ -2826,7 +2829,7 @@ xfs_iextents_copy( xfs_fsblock_t start_block; ifp = XFS_IFORK_PTR(ip, whichfork); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); ASSERT(ifp->if_bytes > 0); nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); @@ -3129,7 +3132,7 @@ xfs_iflush( XFS_STATS_INC(xs_iflush_count); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); ASSERT(issemalocked(&(ip->i_flock))); ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || ip->i_d.di_nextents > ip->i_df.if_ext_max); @@ -3294,7 +3297,7 @@ xfs_iflush_int( int first; #endif - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); ASSERT(issemalocked(&(ip->i_flock))); ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || ip->i_d.di_nextents > ip->i_df.if_ext_max); diff --git a/trunk/fs/xfs/xfs_inode.h b/trunk/fs/xfs/xfs_inode.h index 0a999fee4f03..93c37697a72c 100644 --- a/trunk/fs/xfs/xfs_inode.h +++ b/trunk/fs/xfs/xfs_inode.h @@ -386,9 +386,20 @@ xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned short flags) #define XFS_ILOCK_EXCL (1<<2) #define XFS_ILOCK_SHARED (1<<3) #define XFS_IUNLOCK_NONOTIFY (1<<4) +/* #define XFS_IOLOCK_NESTED (1<<5) */ +#define XFS_EXTENT_TOKEN_RD (1<<6) +#define XFS_SIZE_TOKEN_RD (1<<7) +#define XFS_EXTSIZE_RD (XFS_EXTENT_TOKEN_RD|XFS_SIZE_TOKEN_RD) +#define XFS_WILLLEND (1<<8) /* Always acquire tokens for lending */ +#define XFS_EXTENT_TOKEN_WR (XFS_EXTENT_TOKEN_RD | XFS_WILLLEND) +#define XFS_SIZE_TOKEN_WR (XFS_SIZE_TOKEN_RD | XFS_WILLLEND) +#define XFS_EXTSIZE_WR (XFS_EXTSIZE_RD | XFS_WILLLEND) +/* TODO:XFS_SIZE_TOKEN_WANT (1<<9) */ #define XFS_LOCK_MASK (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED \ - | XFS_ILOCK_EXCL | XFS_ILOCK_SHARED) + | XFS_ILOCK_EXCL | XFS_ILOCK_SHARED \ + | XFS_EXTENT_TOKEN_RD | XFS_SIZE_TOKEN_RD \ + | XFS_WILLLEND) /* * Flags for lockdep annotations. @@ -472,7 +483,6 @@ void xfs_ilock(xfs_inode_t *, uint); int xfs_ilock_nowait(xfs_inode_t *, uint); void xfs_iunlock(xfs_inode_t *, uint); void xfs_ilock_demote(xfs_inode_t *, uint); -int xfs_isilocked(xfs_inode_t *, uint); void xfs_iflock(xfs_inode_t *); int xfs_iflock_nowait(xfs_inode_t *); uint xfs_ilock_map_shared(xfs_inode_t *); @@ -524,7 +534,7 @@ int xfs_iflush(xfs_inode_t *, uint); void xfs_iflush_all(struct xfs_mount *); void xfs_ichgtime(xfs_inode_t *, int); xfs_fsize_t xfs_file_last_byte(xfs_inode_t *); -void xfs_lock_inodes(xfs_inode_t **, int, uint); +void xfs_lock_inodes(xfs_inode_t **, int, int, uint); void xfs_synchronize_atime(xfs_inode_t *); void xfs_mark_inode_dirty_sync(xfs_inode_t *); diff --git a/trunk/fs/xfs/xfs_inode_item.c b/trunk/fs/xfs/xfs_inode_item.c index 167b33f15772..93b5db453ea2 100644 --- a/trunk/fs/xfs/xfs_inode_item.c +++ b/trunk/fs/xfs/xfs_inode_item.c @@ -547,7 +547,7 @@ STATIC void xfs_inode_item_pin( xfs_inode_log_item_t *iip) { - ASSERT(xfs_isilocked(iip->ili_inode, XFS_ILOCK_EXCL)); + ASSERT(ismrlocked(&(iip->ili_inode->i_lock), MR_UPDATE)); xfs_ipin(iip->ili_inode); } @@ -664,13 +664,13 @@ xfs_inode_item_unlock( ASSERT(iip != NULL); ASSERT(iip->ili_inode->i_itemp != NULL); - ASSERT(xfs_isilocked(iip->ili_inode, XFS_ILOCK_EXCL)); + ASSERT(ismrlocked(&(iip->ili_inode->i_lock), MR_UPDATE)); ASSERT((!(iip->ili_inode->i_itemp->ili_flags & XFS_ILI_IOLOCKED_EXCL)) || - xfs_isilocked(iip->ili_inode, XFS_IOLOCK_EXCL)); + ismrlocked(&(iip->ili_inode->i_iolock), MR_UPDATE)); ASSERT((!(iip->ili_inode->i_itemp->ili_flags & XFS_ILI_IOLOCKED_SHARED)) || - xfs_isilocked(iip->ili_inode, XFS_IOLOCK_SHARED)); + ismrlocked(&(iip->ili_inode->i_iolock), MR_ACCESS)); /* * Clear the transaction pointer in the inode. */ @@ -769,7 +769,7 @@ xfs_inode_item_pushbuf( ip = iip->ili_inode; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED)); + ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS)); /* * The ili_pushbuf_flag keeps others from @@ -857,7 +857,7 @@ xfs_inode_item_push( ip = iip->ili_inode; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED)); + ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS)); ASSERT(issemalocked(&(ip->i_flock))); /* * Since we were able to lock the inode's flush lock and diff --git a/trunk/fs/xfs/xfs_iomap.c b/trunk/fs/xfs/xfs_iomap.c index 7edcde691d1a..fb3cf1191419 100644 --- a/trunk/fs/xfs/xfs_iomap.c +++ b/trunk/fs/xfs/xfs_iomap.c @@ -196,14 +196,14 @@ xfs_iomap( break; case BMAPI_WRITE: xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, ip, offset, count); - lockmode = XFS_ILOCK_EXCL; + lockmode = XFS_ILOCK_EXCL|XFS_EXTSIZE_WR; if (flags & BMAPI_IGNSTATE) bmapi_flags |= XFS_BMAPI_IGSTATE|XFS_BMAPI_ENTIRE; xfs_ilock(ip, lockmode); break; case BMAPI_ALLOCATE: xfs_iomap_enter_trace(XFS_IOMAP_ALLOC_ENTER, ip, offset, count); - lockmode = XFS_ILOCK_SHARED; + lockmode = XFS_ILOCK_SHARED|XFS_EXTSIZE_RD; bmapi_flags = XFS_BMAPI_ENTIRE; /* Attempt non-blocking lock */ @@ -523,7 +523,8 @@ xfs_iomap_write_direct( goto error_out; } - if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip))) { + if (unlikely(!imap.br_startblock && + !(XFS_IS_REALTIME_INODE(ip)))) { error = xfs_cmn_err_fsblock_zero(ip, &imap); goto error_out; } @@ -623,7 +624,7 @@ xfs_iomap_write_delay( int prealloc, fsynced = 0; int error; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0); /* * Make sure that the dquots are there. This doesn't hold @@ -685,7 +686,8 @@ xfs_iomap_write_delay( goto retry; } - if (!(imap[0].br_startblock || XFS_IS_REALTIME_INODE(ip))) + if (unlikely(!imap[0].br_startblock && + !(XFS_IS_REALTIME_INODE(ip)))) return xfs_cmn_err_fsblock_zero(ip, &imap[0]); *ret_imap = imap[0]; @@ -836,9 +838,9 @@ xfs_iomap_write_allocate( * See if we were able to allocate an extent that * covers at least part of the callers request */ - if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip))) + if (unlikely(!imap.br_startblock && + XFS_IS_REALTIME_INODE(ip))) return xfs_cmn_err_fsblock_zero(ip, &imap); - if ((offset_fsb >= imap.br_startoff) && (offset_fsb < (imap.br_startoff + imap.br_blockcount))) { @@ -932,7 +934,8 @@ xfs_iomap_write_unwritten( if (error) return XFS_ERROR(error); - if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip))) + if (unlikely(!imap.br_startblock && + !(XFS_IS_REALTIME_INODE(ip)))) return xfs_cmn_err_fsblock_zero(ip, &imap); if ((numblks_fsb = imap.br_blockcount) == 0) { diff --git a/trunk/fs/xfs/xfs_itable.c b/trunk/fs/xfs/xfs_itable.c index 419de15aeb43..eb85bdedad0c 100644 --- a/trunk/fs/xfs/xfs_itable.c +++ b/trunk/fs/xfs/xfs_itable.c @@ -71,6 +71,11 @@ xfs_bulkstat_one_iget( ASSERT(ip != NULL); ASSERT(ip->i_blkno != (xfs_daddr_t)0); + if (ip->i_d.di_mode == 0) { + *stat = BULKSTAT_RV_NOTHING; + error = XFS_ERROR(ENOENT); + goto out_iput; + } vp = XFS_ITOV(ip); dic = &ip->i_d; @@ -119,6 +124,7 @@ xfs_bulkstat_one_iget( break; } + out_iput: xfs_iput(ip, XFS_ILOCK_SHARED); return error; } diff --git a/trunk/fs/xfs/xfs_mount.c b/trunk/fs/xfs/xfs_mount.c index da3988453b71..2fec452afbcc 100644 --- a/trunk/fs/xfs/xfs_mount.c +++ b/trunk/fs/xfs/xfs_mount.c @@ -54,9 +54,8 @@ STATIC void xfs_unmountfs_wait(xfs_mount_t *); #ifdef HAVE_PERCPU_SB STATIC void xfs_icsb_destroy_counters(xfs_mount_t *); STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, - int); -STATIC void xfs_icsb_balance_counter_locked(xfs_mount_t *, xfs_sb_field_t, - int); + int, int); +STATIC void xfs_icsb_sync_counters(xfs_mount_t *); STATIC int xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t, int64_t, int); STATIC void xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t); @@ -64,8 +63,8 @@ STATIC void xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t); #else #define xfs_icsb_destroy_counters(mp) do { } while (0) -#define xfs_icsb_balance_counter(mp, a, b) do { } while (0) -#define xfs_icsb_balance_counter_locked(mp, a, b) do { } while (0) +#define xfs_icsb_balance_counter(mp, a, b, c) do { } while (0) +#define xfs_icsb_sync_counters(mp) do { } while (0) #define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0) #endif @@ -1401,7 +1400,7 @@ xfs_log_sbcount( if (!xfs_fs_writable(mp)) return 0; - xfs_icsb_sync_counters(mp, 0); + xfs_icsb_sync_counters(mp); /* * we don't need to do this if we are updating the superblock @@ -2027,9 +2026,9 @@ xfs_icsb_cpu_notify( case CPU_ONLINE: case CPU_ONLINE_FROZEN: xfs_icsb_lock(mp); - xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0); - xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0); - xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0, 0); xfs_icsb_unlock(mp); break; case CPU_DEAD: @@ -2049,9 +2048,12 @@ xfs_icsb_cpu_notify( memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); - xfs_icsb_balance_counter_locked(mp, XFS_SBS_ICOUNT, 0); - xfs_icsb_balance_counter_locked(mp, XFS_SBS_IFREE, 0); - xfs_icsb_balance_counter_locked(mp, XFS_SBS_FDBLOCKS, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, + XFS_ICSB_SB_LOCKED, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, + XFS_ICSB_SB_LOCKED, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, + XFS_ICSB_SB_LOCKED, 0); spin_unlock(&mp->m_sb_lock); xfs_icsb_unlock(mp); break; @@ -2103,9 +2105,9 @@ xfs_icsb_reinit_counters( * initial balance kicks us off correctly */ mp->m_icsb_counters = -1; - xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0); - xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0); - xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0, 0); xfs_icsb_unlock(mp); } @@ -2221,7 +2223,7 @@ xfs_icsb_disable_counter( if (!test_and_set_bit(field, &mp->m_icsb_counters)) { /* drain back to superblock */ - xfs_icsb_count(mp, &cnt, XFS_ICSB_LAZY_COUNT); + xfs_icsb_count(mp, &cnt, XFS_ICSB_SB_LOCKED|XFS_ICSB_LAZY_COUNT); switch(field) { case XFS_SBS_ICOUNT: mp->m_sb.sb_icount = cnt.icsb_icount; @@ -2276,33 +2278,38 @@ xfs_icsb_enable_counter( } void -xfs_icsb_sync_counters_locked( +xfs_icsb_sync_counters_flags( xfs_mount_t *mp, int flags) { xfs_icsb_cnts_t cnt; + /* Pass 1: lock all counters */ + if ((flags & XFS_ICSB_SB_LOCKED) == 0) + spin_lock(&mp->m_sb_lock); + xfs_icsb_count(mp, &cnt, flags); + /* Step 3: update mp->m_sb fields */ if (!xfs_icsb_counter_disabled(mp, XFS_SBS_ICOUNT)) mp->m_sb.sb_icount = cnt.icsb_icount; if (!xfs_icsb_counter_disabled(mp, XFS_SBS_IFREE)) mp->m_sb.sb_ifree = cnt.icsb_ifree; if (!xfs_icsb_counter_disabled(mp, XFS_SBS_FDBLOCKS)) mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks; + + if ((flags & XFS_ICSB_SB_LOCKED) == 0) + spin_unlock(&mp->m_sb_lock); } /* * Accurate update of per-cpu counters to incore superblock */ -void +STATIC void xfs_icsb_sync_counters( - xfs_mount_t *mp, - int flags) + xfs_mount_t *mp) { - spin_lock(&mp->m_sb_lock); - xfs_icsb_sync_counters_locked(mp, flags); - spin_unlock(&mp->m_sb_lock); + xfs_icsb_sync_counters_flags(mp, 0); } /* @@ -2325,15 +2332,19 @@ xfs_icsb_sync_counters( #define XFS_ICSB_FDBLK_CNTR_REENABLE(mp) \ (uint64_t)(512 + XFS_ALLOC_SET_ASIDE(mp)) STATIC void -xfs_icsb_balance_counter_locked( +xfs_icsb_balance_counter( xfs_mount_t *mp, xfs_sb_field_t field, + int flags, int min_per_cpu) { uint64_t count, resid; int weight = num_online_cpus(); uint64_t min = (uint64_t)min_per_cpu; + if (!(flags & XFS_ICSB_SB_LOCKED)) + spin_lock(&mp->m_sb_lock); + /* disable counter and sync counter */ xfs_icsb_disable_counter(mp, field); @@ -2343,19 +2354,19 @@ xfs_icsb_balance_counter_locked( count = mp->m_sb.sb_icount; resid = do_div(count, weight); if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE)) - return; + goto out; break; case XFS_SBS_IFREE: count = mp->m_sb.sb_ifree; resid = do_div(count, weight); if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE)) - return; + goto out; break; case XFS_SBS_FDBLOCKS: count = mp->m_sb.sb_fdblocks; resid = do_div(count, weight); if (count < max(min, XFS_ICSB_FDBLK_CNTR_REENABLE(mp))) - return; + goto out; break; default: BUG(); @@ -2364,17 +2375,9 @@ xfs_icsb_balance_counter_locked( } xfs_icsb_enable_counter(mp, field, count, resid); -} - -STATIC void -xfs_icsb_balance_counter( - xfs_mount_t *mp, - xfs_sb_field_t fields, - int min_per_cpu) -{ - spin_lock(&mp->m_sb_lock); - xfs_icsb_balance_counter_locked(mp, fields, min_per_cpu); - spin_unlock(&mp->m_sb_lock); +out: + if (!(flags & XFS_ICSB_SB_LOCKED)) + spin_unlock(&mp->m_sb_lock); } STATIC int @@ -2481,7 +2484,7 @@ xfs_icsb_modify_counters( * we are done. */ if (ret != ENOSPC) - xfs_icsb_balance_counter(mp, field, 0); + xfs_icsb_balance_counter(mp, field, 0, 0); xfs_icsb_unlock(mp); return ret; @@ -2505,7 +2508,7 @@ xfs_icsb_modify_counters( * will either succeed through the fast path or slow path without * another balance operation being required. */ - xfs_icsb_balance_counter(mp, field, delta); + xfs_icsb_balance_counter(mp, field, 0, delta); xfs_icsb_unlock(mp); goto again; } diff --git a/trunk/fs/xfs/xfs_mount.h b/trunk/fs/xfs/xfs_mount.h index 63e0693a358a..1ed575110ff0 100644 --- a/trunk/fs/xfs/xfs_mount.h +++ b/trunk/fs/xfs/xfs_mount.h @@ -206,18 +206,17 @@ typedef struct xfs_icsb_cnts { #define XFS_ICSB_FLAG_LOCK (1 << 0) /* counter lock bit */ +#define XFS_ICSB_SB_LOCKED (1 << 0) /* sb already locked */ #define XFS_ICSB_LAZY_COUNT (1 << 1) /* accuracy not needed */ extern int xfs_icsb_init_counters(struct xfs_mount *); extern void xfs_icsb_reinit_counters(struct xfs_mount *); -extern void xfs_icsb_sync_counters(struct xfs_mount *, int); -extern void xfs_icsb_sync_counters_locked(struct xfs_mount *, int); +extern void xfs_icsb_sync_counters_flags(struct xfs_mount *, int); #else #define xfs_icsb_init_counters(mp) (0) #define xfs_icsb_reinit_counters(mp) do { } while (0) -#define xfs_icsb_sync_counters(mp, flags) do { } while (0) -#define xfs_icsb_sync_counters_locked(mp, flags) do { } while (0) +#define xfs_icsb_sync_counters_flags(mp, flags) do { } while (0) #endif typedef struct xfs_ail { diff --git a/trunk/fs/xfs/xfs_rename.c b/trunk/fs/xfs/xfs_rename.c index d8063e1ad298..ee371890d85d 100644 --- a/trunk/fs/xfs/xfs_rename.c +++ b/trunk/fs/xfs/xfs_rename.c @@ -55,32 +55,85 @@ xfs_rename_unlock4( xfs_iunlock(i_tab[0], lock_mode); for (i = 1; i < 4; i++) { - if (i_tab[i] == NULL) + if (i_tab[i] == NULL) { break; - + } /* * Watch out for duplicate entries in the table. */ - if (i_tab[i] != i_tab[i-1]) + if (i_tab[i] != i_tab[i-1]) { xfs_iunlock(i_tab[i], lock_mode); + } } } +#ifdef DEBUG +int xfs_rename_skip, xfs_rename_nskip; +#endif + /* - * Enter all inodes for a rename transaction into a sorted array. + * The following routine will acquire the locks required for a rename + * operation. The code understands the semantics of renames and will + * validate that name1 exists under dp1 & that name2 may or may not + * exist under dp2. + * + * We are renaming dp1/name1 to dp2/name2. + * + * Return ENOENT if dp1 does not exist, other lookup errors, or 0 for success. */ -STATIC void -xfs_sort_for_rename( +STATIC int +xfs_lock_for_rename( xfs_inode_t *dp1, /* in: old (source) directory inode */ xfs_inode_t *dp2, /* in: new (target) directory inode */ xfs_inode_t *ip1, /* in: inode of old entry */ - xfs_inode_t *ip2, /* in: inode of new entry, if it + struct xfs_name *name2, /* in: new entry name */ + xfs_inode_t **ipp2, /* out: inode of new entry, if it already exists, NULL otherwise. */ xfs_inode_t **i_tab,/* out: array of inode returned, sorted */ int *num_inodes) /* out: number of inodes in array */ { + xfs_inode_t *ip2 = NULL; xfs_inode_t *temp; + xfs_ino_t inum1, inum2; + int error; int i, j; + uint lock_mode; + int diff_dirs = (dp1 != dp2); + + /* + * First, find out the current inums of the entries so that we + * can determine the initial locking order. We'll have to + * sanity check stuff after all the locks have been acquired + * to see if we still have the right inodes, directories, etc. + */ + lock_mode = xfs_ilock_map_shared(dp1); + IHOLD(ip1); + xfs_itrace_ref(ip1); + + inum1 = ip1->i_ino; + + /* + * Unlock dp1 and lock dp2 if they are different. + */ + if (diff_dirs) { + xfs_iunlock_map_shared(dp1, lock_mode); + lock_mode = xfs_ilock_map_shared(dp2); + } + + error = xfs_dir_lookup_int(dp2, lock_mode, name2, &inum2, &ip2); + if (error == ENOENT) { /* target does not need to exist. */ + inum2 = 0; + } else if (error) { + /* + * If dp2 and dp1 are the same, the next line unlocks dp1. + * Got it? + */ + xfs_iunlock_map_shared(dp2, lock_mode); + IRELE (ip1); + return error; + } else { + xfs_itrace_ref(ip2); + } /* * i_tab contains a list of pointers to inodes. We initialize @@ -92,20 +145,21 @@ xfs_sort_for_rename( i_tab[0] = dp1; i_tab[1] = dp2; i_tab[2] = ip1; - if (ip2) { - *num_inodes = 4; - i_tab[3] = ip2; - } else { + if (inum2 == 0) { *num_inodes = 3; i_tab[3] = NULL; + } else { + *num_inodes = 4; + i_tab[3] = ip2; } + *ipp2 = i_tab[3]; /* * Sort the elements via bubble sort. (Remember, there are at * most 4 elements to sort, so this is adequate.) */ - for (i = 0; i < *num_inodes; i++) { - for (j = 1; j < *num_inodes; j++) { + for (i=0; i < *num_inodes; i++) { + for (j=1; j < *num_inodes; j++) { if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) { temp = i_tab[j]; i_tab[j] = i_tab[j-1]; @@ -113,6 +167,30 @@ xfs_sort_for_rename( } } } + + /* + * We have dp2 locked. If it isn't first, unlock it. + * If it is first, tell xfs_lock_inodes so it can skip it + * when locking. if dp1 == dp2, xfs_lock_inodes will skip both + * since they are equal. xfs_lock_inodes needs all these inodes + * so that it can unlock and retry if there might be a dead-lock + * potential with the log. + */ + + if (i_tab[0] == dp2 && lock_mode == XFS_ILOCK_SHARED) { +#ifdef DEBUG + xfs_rename_skip++; +#endif + xfs_lock_inodes(i_tab, *num_inodes, 1, XFS_ILOCK_SHARED); + } else { +#ifdef DEBUG + xfs_rename_nskip++; +#endif + xfs_iunlock_map_shared(dp2, lock_mode); + xfs_lock_inodes(i_tab, *num_inodes, 0, XFS_ILOCK_SHARED); + } + + return 0; } /* @@ -124,10 +202,10 @@ xfs_rename( struct xfs_name *src_name, xfs_inode_t *src_ip, xfs_inode_t *target_dp, - struct xfs_name *target_name, - xfs_inode_t *target_ip) + struct xfs_name *target_name) { - xfs_trans_t *tp = NULL; + xfs_trans_t *tp; + xfs_inode_t *target_ip; xfs_mount_t *mp = src_dp->i_mount; int new_parent; /* moving to a new dir */ int src_is_directory; /* src_name is a directory */ @@ -137,7 +215,9 @@ xfs_rename( int cancel_flags; int committed; xfs_inode_t *inodes[4]; + int target_ip_dropped = 0; /* dropped target_ip link? */ int spaceres; + int target_link_zero = 0; int num_inodes; xfs_itrace_entry(src_dp); @@ -150,27 +230,64 @@ xfs_rename( target_dp, DM_RIGHT_NULL, src_name->name, target_name->name, 0, 0, 0); - if (error) + if (error) { return error; + } } /* Return through std_return after this point. */ - new_parent = (src_dp != target_dp); - src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR); + /* + * Lock all the participating inodes. Depending upon whether + * the target_name exists in the target directory, and + * whether the target directory is the same as the source + * directory, we can lock from 2 to 4 inodes. + * xfs_lock_for_rename() will return ENOENT if src_name + * does not exist in the source directory. + */ + tp = NULL; + error = xfs_lock_for_rename(src_dp, target_dp, src_ip, target_name, + &target_ip, inodes, &num_inodes); + if (error) { + /* + * We have nothing locked, no inode references, and + * no transaction, so just get out. + */ + goto std_return; + } + + ASSERT(src_ip != NULL); - if (src_is_directory) { + if ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR) { /* * Check for link count overflow on target_dp */ - if (target_ip == NULL && new_parent && + if (target_ip == NULL && (src_dp != target_dp) && target_dp->i_d.di_nlink >= XFS_MAXLINK) { error = XFS_ERROR(EMLINK); - goto std_return; + xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); + goto rele_return; } } - xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, - inodes, &num_inodes); + /* + * If we are using project inheritance, we only allow renames + * into our tree when the project IDs are the same; else the + * tree quota mechanism would be circumvented. + */ + if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && + (target_dp->i_d.di_projid != src_ip->i_d.di_projid))) { + error = XFS_ERROR(EXDEV); + xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); + goto rele_return; + } + + new_parent = (src_dp != target_dp); + src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR); + + /* + * Drop the locks on our inodes so that we can start the transaction. + */ + xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); XFS_BMAP_INIT(&free_list, &first_block); tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME); @@ -185,7 +302,7 @@ xfs_rename( } if (error) { xfs_trans_cancel(tp, 0); - goto std_return; + goto rele_return; } /* @@ -193,29 +310,13 @@ xfs_rename( */ if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) { xfs_trans_cancel(tp, cancel_flags); - goto std_return; + goto rele_return; } /* - * Lock all the participating inodes. Depending upon whether - * the target_name exists in the target directory, and - * whether the target directory is the same as the source - * directory, we can lock from 2 to 4 inodes. - */ - xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL); - - /* - * If we are using project inheritance, we only allow renames - * into our tree when the project IDs are the same; else the - * tree quota mechanism would be circumvented. + * Reacquire the inode locks we dropped above. */ - if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && - (target_dp->i_d.di_projid != src_ip->i_d.di_projid))) { - error = XFS_ERROR(EXDEV); - xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); - xfs_trans_cancel(tp, cancel_flags); - goto std_return; - } + xfs_lock_inodes(inodes, num_inodes, 0, XFS_ILOCK_EXCL); /* * Join all the inodes to the transaction. From this point on, @@ -227,17 +328,17 @@ xfs_rename( */ IHOLD(src_dp); xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL); - if (new_parent) { IHOLD(target_dp); xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL); } - - IHOLD(src_ip); - xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL); - - if (target_ip) { - IHOLD(target_ip); + if ((src_ip != src_dp) && (src_ip != target_dp)) { + xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL); + } + if ((target_ip != NULL) && + (target_ip != src_ip) && + (target_ip != src_dp) && + (target_ip != target_dp)) { xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL); } @@ -311,6 +412,7 @@ xfs_rename( error = xfs_droplink(tp, target_ip); if (error) goto abort_return; + target_ip_dropped = 1; if (src_is_directory) { /* @@ -320,6 +422,10 @@ xfs_rename( if (error) goto abort_return; } + + /* Do this test while we still hold the locks */ + target_link_zero = (target_ip)->i_d.di_nlink==0; + } /* target_ip != NULL */ /* @@ -385,6 +491,15 @@ xfs_rename( xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE); } + /* + * If there was a target inode, take an extra reference on + * it here so that it doesn't go to xfs_inactive() from + * within the commit. + */ + if (target_ip != NULL) { + IHOLD(target_ip); + } + /* * If this is a synchronous mount, make sure that the * rename transaction goes to disk before returning to @@ -394,11 +509,30 @@ xfs_rename( xfs_trans_set_sync(tp); } + /* + * Take refs. for vop_link_removed calls below. No need to worry + * about directory refs. because the caller holds them. + * + * Do holds before the xfs_bmap_finish since it might rele them down + * to zero. + */ + + if (target_ip_dropped) + IHOLD(target_ip); + IHOLD(src_ip); + error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) { xfs_bmap_cancel(&free_list); xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT)); + if (target_ip != NULL) { + IRELE(target_ip); + } + if (target_ip_dropped) { + IRELE(target_ip); + } + IRELE(src_ip); goto std_return; } @@ -407,6 +541,15 @@ xfs_rename( * the vnode references. */ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); + if (target_ip != NULL) + IRELE(target_ip); + /* + * Let interposed file systems know about removed links. + */ + if (target_ip_dropped) + IRELE(target_ip); + + IRELE(src_ip); /* Fall through to std_return with error = 0 or errno from * xfs_trans_commit */ @@ -428,4 +571,11 @@ xfs_rename( xfs_bmap_cancel(&free_list); xfs_trans_cancel(tp, cancel_flags); goto std_return; + + rele_return: + IRELE(src_ip); + if (target_ip != NULL) { + IRELE(target_ip); + } + goto std_return; } diff --git a/trunk/fs/xfs/xfs_trans_inode.c b/trunk/fs/xfs/xfs_trans_inode.c index 4c70bf5e9985..b8db1d5cde5a 100644 --- a/trunk/fs/xfs/xfs_trans_inode.c +++ b/trunk/fs/xfs/xfs_trans_inode.c @@ -111,13 +111,13 @@ xfs_trans_iget( */ ASSERT(ip->i_itemp != NULL); ASSERT(lock_flags & XFS_ILOCK_EXCL); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) || - xfs_isilocked(ip, XFS_IOLOCK_EXCL)); + ismrlocked(&ip->i_iolock, MR_UPDATE)); ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) || (ip->i_itemp->ili_flags & XFS_ILI_IOLOCKED_EXCL)); ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) || - xfs_isilocked(ip, XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)); + ismrlocked(&ip->i_iolock, (MR_UPDATE | MR_ACCESS))); ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) || (ip->i_itemp->ili_flags & XFS_ILI_IOLOCKED_ANY)); @@ -185,7 +185,7 @@ xfs_trans_ijoin( xfs_inode_log_item_t *iip; ASSERT(ip->i_transp == NULL); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); ASSERT(lock_flags & XFS_ILOCK_EXCL); if (ip->i_itemp == NULL) xfs_inode_item_init(ip, ip->i_mount); @@ -232,7 +232,7 @@ xfs_trans_ihold( { ASSERT(ip->i_transp == tp); ASSERT(ip->i_itemp != NULL); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); ip->i_itemp->ili_flags |= XFS_ILI_HOLD; } @@ -257,7 +257,7 @@ xfs_trans_log_inode( ASSERT(ip->i_transp == tp); ASSERT(ip->i_itemp != NULL); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(ip->i_itemp)); ASSERT(lidp != NULL); diff --git a/trunk/fs/xfs/xfs_utils.c b/trunk/fs/xfs/xfs_utils.c index 98e5f110ba5f..2b8dc7e40772 100644 --- a/trunk/fs/xfs/xfs_utils.c +++ b/trunk/fs/xfs/xfs_utils.c @@ -41,6 +41,49 @@ #include "xfs_utils.h" +int +xfs_dir_lookup_int( + xfs_inode_t *dp, + uint lock_mode, + struct xfs_name *name, + xfs_ino_t *inum, + xfs_inode_t **ipp) +{ + int error; + + xfs_itrace_entry(dp); + + error = xfs_dir_lookup(NULL, dp, name, inum); + if (!error) { + /* + * Unlock the directory. We do this because we can't + * hold the directory lock while doing the vn_get() + * in xfs_iget(). Doing so could cause us to hold + * a lock while waiting for the inode to finish + * being inactive while it's waiting for a log + * reservation in the inactive routine. + */ + xfs_iunlock(dp, lock_mode); + error = xfs_iget(dp->i_mount, NULL, *inum, 0, 0, ipp, 0); + xfs_ilock(dp, lock_mode); + + if (error) { + *ipp = NULL; + } else if ((*ipp)->i_d.di_mode == 0) { + /* + * The inode has been freed. Something is + * wrong so just get out of here. + */ + xfs_iunlock(dp, lock_mode); + xfs_iput_new(*ipp, 0); + *ipp = NULL; + xfs_ilock(dp, lock_mode); + error = XFS_ERROR(ENOENT); + } + } + return error; +} + /* * Allocates a new inode from disk and return a pointer to the * incore copy. This routine will internally commit the current @@ -267,7 +310,7 @@ xfs_bump_ino_vers2( { xfs_mount_t *mp; - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE)); ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1); ip->i_d.di_version = XFS_DINODE_VERSION_2; diff --git a/trunk/fs/xfs/xfs_utils.h b/trunk/fs/xfs/xfs_utils.h index f316cb85d8e2..175b126d2cab 100644 --- a/trunk/fs/xfs/xfs_utils.h +++ b/trunk/fs/xfs/xfs_utils.h @@ -21,6 +21,8 @@ #define IRELE(ip) VN_RELE(XFS_ITOV(ip)) #define IHOLD(ip) VN_HOLD(XFS_ITOV(ip)) +extern int xfs_dir_lookup_int(xfs_inode_t *, uint, struct xfs_name *, + xfs_ino_t *, xfs_inode_t **); extern int xfs_truncate_file(xfs_mount_t *, xfs_inode_t *); extern int xfs_dir_ialloc(xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t, xfs_dev_t, cred_t *, prid_t, int, diff --git a/trunk/fs/xfs/xfs_vfsops.c b/trunk/fs/xfs/xfs_vfsops.c index 30bacd8bb0e5..fc48158fe479 100644 --- a/trunk/fs/xfs/xfs_vfsops.c +++ b/trunk/fs/xfs/xfs_vfsops.c @@ -186,7 +186,6 @@ xfs_cleanup(void) kmem_zone_destroy(xfs_efi_zone); kmem_zone_destroy(xfs_ifork_zone); kmem_zone_destroy(xfs_ili_zone); - kmem_zone_destroy(xfs_log_ticket_zone); } /* diff --git a/trunk/fs/xfs/xfs_vnodeops.c b/trunk/fs/xfs/xfs_vnodeops.c index 70702a60b4bb..6650601c64f7 100644 --- a/trunk/fs/xfs/xfs_vnodeops.c +++ b/trunk/fs/xfs/xfs_vnodeops.c @@ -75,6 +75,132 @@ xfs_open( return 0; } +/* + * xfs_getattr + */ +int +xfs_getattr( + xfs_inode_t *ip, + bhv_vattr_t *vap, + int flags) +{ + bhv_vnode_t *vp = XFS_ITOV(ip); + xfs_mount_t *mp = ip->i_mount; + + xfs_itrace_entry(ip); + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + if (!(flags & ATTR_LAZY)) + xfs_ilock(ip, XFS_ILOCK_SHARED); + + vap->va_size = XFS_ISIZE(ip); + if (vap->va_mask == XFS_AT_SIZE) + goto all_done; + + vap->va_nblocks = + XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); + vap->va_nodeid = ip->i_ino; +#if XFS_BIG_INUMS + vap->va_nodeid += mp->m_inoadd; +#endif + vap->va_nlink = ip->i_d.di_nlink; + + /* + * Quick exit for non-stat callers + */ + if ((vap->va_mask & + ~(XFS_AT_SIZE|XFS_AT_FSID|XFS_AT_NODEID| + XFS_AT_NLINK|XFS_AT_BLKSIZE)) == 0) + goto all_done; + + /* + * Copy from in-core inode. + */ + vap->va_mode = ip->i_d.di_mode; + vap->va_uid = ip->i_d.di_uid; + vap->va_gid = ip->i_d.di_gid; + vap->va_projid = ip->i_d.di_projid; + + /* + * Check vnode type block/char vs. everything else. + */ + switch (ip->i_d.di_mode & S_IFMT) { + case S_IFBLK: + case S_IFCHR: + vap->va_rdev = ip->i_df.if_u2.if_rdev; + vap->va_blocksize = BLKDEV_IOSIZE; + break; + default: + vap->va_rdev = 0; + + if (!(XFS_IS_REALTIME_INODE(ip))) { + vap->va_blocksize = xfs_preferred_iosize(mp); + } else { + + /* + * If the file blocks are being allocated from a + * realtime partition, then return the inode's + * realtime extent size or the realtime volume's + * extent size. + */ + vap->va_blocksize = + xfs_get_extsz_hint(ip) << mp->m_sb.sb_blocklog; + } + break; + } + + vn_atime_to_timespec(vp, &vap->va_atime); + vap->va_mtime.tv_sec = ip->i_d.di_mtime.t_sec; + vap->va_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; + vap->va_ctime.tv_sec = ip->i_d.di_ctime.t_sec; + vap->va_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; + + /* + * Exit for stat callers. See if any of the rest of the fields + * to be filled in are needed. + */ + if ((vap->va_mask & + (XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS| + XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0) + goto all_done; + + /* + * Convert di_flags to xflags. + */ + vap->va_xflags = xfs_ip2xflags(ip); + + /* + * Exit for inode revalidate. See if any of the rest of + * the fields to be filled in are needed. + */ + if ((vap->va_mask & + (XFS_AT_EXTSIZE|XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS| + XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0) + goto all_done; + + vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog; + vap->va_nextents = + (ip->i_df.if_flags & XFS_IFEXTENTS) ? + ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) : + ip->i_d.di_nextents; + if (ip->i_afp) + vap->va_anextents = + (ip->i_afp->if_flags & XFS_IFEXTENTS) ? + ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) : + ip->i_d.di_anextents; + else + vap->va_anextents = 0; + vap->va_gen = ip->i_d.di_gen; + + all_done: + if (!(flags & ATTR_LAZY)) + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return 0; +} + + /* * xfs_setattr */ @@ -85,6 +211,7 @@ xfs_setattr( int flags, cred_t *credp) { + bhv_vnode_t *vp = XFS_ITOV(ip); xfs_mount_t *mp = ip->i_mount; xfs_trans_t *tp; int mask; @@ -95,6 +222,7 @@ xfs_setattr( gid_t gid=0, igid=0; int timeflags = 0; xfs_prid_t projid=0, iprojid=0; + int mandlock_before, mandlock_after; struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; int file_owner; int need_iolock = 1; @@ -255,7 +383,7 @@ xfs_setattr( m |= S_ISGID; #if 0 /* Linux allows this, Irix doesn't. */ - if ((vap->va_mode & S_ISVTX) && !S_ISDIR(ip->i_d.di_mode)) + if ((vap->va_mode & S_ISVTX) && !VN_ISDIR(vp)) m |= S_ISVTX; #endif if (m && !capable(CAP_FSETID)) @@ -333,10 +461,10 @@ xfs_setattr( goto error_return; } - if (S_ISDIR(ip->i_d.di_mode)) { + if (VN_ISDIR(vp)) { code = XFS_ERROR(EISDIR); goto error_return; - } else if (!S_ISREG(ip->i_d.di_mode)) { + } else if (!VN_ISREG(vp)) { code = XFS_ERROR(EINVAL); goto error_return; } @@ -498,6 +626,9 @@ xfs_setattr( xfs_trans_ihold(tp, ip); } + /* determine whether mandatory locking mode changes */ + mandlock_before = MANDLOCK(vp, ip->i_d.di_mode); + /* * Truncate file. Must have write permission and not be a directory. */ @@ -727,6 +858,13 @@ xfs_setattr( code = xfs_trans_commit(tp, commit_flags); } + /* + * If the (regular) file's mandatory locking mode changed, then + * notify the vnode. We do this under the inode lock to prevent + * racing calls to vop_vnode_change. + */ + mandlock_after = MANDLOCK(vp, ip->i_d.di_mode); + xfs_iunlock(ip, lock_flags); /* @@ -1305,7 +1443,7 @@ xfs_inactive_attrs( int error; xfs_mount_t *mp; - ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); tp = *tpp; mp = ip->i_mount; ASSERT(ip->i_d.di_forkoff != 0); @@ -1353,7 +1491,7 @@ xfs_release( xfs_mount_t *mp = ip->i_mount; int error; - if (!S_ISREG(ip->i_d.di_mode) || (ip->i_d.di_mode == 0)) + if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0)) return 0; /* If this is a read-only mount, don't do this (would generate I/O) */ @@ -1636,7 +1774,8 @@ xfs_lookup( struct xfs_name *name, xfs_inode_t **ipp) { - xfs_ino_t inum; + xfs_inode_t *ip; + xfs_ino_t e_inum; int error; uint lock_mode; @@ -1646,21 +1785,12 @@ xfs_lookup( return XFS_ERROR(EIO); lock_mode = xfs_ilock_map_shared(dp); - error = xfs_dir_lookup(NULL, dp, name, &inum); + error = xfs_dir_lookup_int(dp, lock_mode, name, &e_inum, &ip); + if (!error) { + *ipp = ip; + xfs_itrace_ref(ip); + } xfs_iunlock_map_shared(dp, lock_mode); - - if (error) - goto out; - - error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp, 0); - if (error) - goto out; - - xfs_itrace_ref(*ipp); - return 0; - - out: - *ipp = NULL; return error; } @@ -1776,7 +1906,7 @@ xfs_create( * It is locked (and joined to the transaction). */ - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE)); /* * Now we join the directory inode to the transaction. We do not do it @@ -1982,7 +2112,7 @@ xfs_lock_dir_and_entry( ips[0] = ip; ips[1] = dp; - xfs_lock_inodes(ips, 2, XFS_ILOCK_EXCL); + xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); } /* else e_inum == dp->i_ino */ /* This can happen if we're asked to lock /x/.. @@ -2030,6 +2160,7 @@ void xfs_lock_inodes( xfs_inode_t **ips, int inodes, + int first_locked, uint lock_mode) { int attempts = 0, i, j, try_lock; @@ -2037,8 +2168,13 @@ xfs_lock_inodes( ASSERT(ips && (inodes >= 2)); /* we need at least two */ - try_lock = 0; - i = 0; + if (first_locked) { + try_lock = 1; + i = 1; + } else { + try_lock = 0; + i = 0; + } again: for (; i < inodes; i++) { @@ -2162,14 +2298,29 @@ xfs_remove( return error; } + /* + * We need to get a reference to ip before we get our log + * reservation. The reason for this is that we cannot call + * xfs_iget for an inode for which we do not have a reference + * once we've acquired a log reservation. This is because the + * inode we are trying to get might be in xfs_inactive going + * for a log reservation. Since we'll have to wait for the + * inactive code to complete before returning from xfs_iget, + * we need to make sure that we don't have log space reserved + * when we call xfs_iget. Instead we get an unlocked reference + * to the inode before getting our log reservation. + */ + IHOLD(ip); + xfs_itrace_entry(ip); xfs_itrace_ref(ip); error = XFS_QM_DQATTACH(mp, dp, 0); - if (!error) + if (!error && dp != ip) error = XFS_QM_DQATTACH(mp, ip, 0); if (error) { REMOVE_DEBUG_TRACE(__LINE__); + IRELE(ip); goto std_return; } @@ -2196,6 +2347,7 @@ xfs_remove( ASSERT(error != ENOSPC); REMOVE_DEBUG_TRACE(__LINE__); xfs_trans_cancel(tp, 0); + IRELE(ip); return error; } @@ -2203,6 +2355,7 @@ xfs_remove( if (error) { REMOVE_DEBUG_TRACE(__LINE__); xfs_trans_cancel(tp, cancel_flags); + IRELE(ip); goto std_return; } @@ -2210,18 +2363,23 @@ xfs_remove( * At this point, we've gotten both the directory and the entry * inodes locked. */ - IHOLD(ip); xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); - - IHOLD(dp); - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + if (dp != ip) { + /* + * Increment vnode ref count only in this case since + * there's an extra vnode reference in the case where + * dp == ip. + */ + IHOLD(dp); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + } /* * Entry must exist since we did a lookup in xfs_lock_dir_and_entry. */ XFS_BMAP_INIT(&free_list, &first_block); error = xfs_dir_removename(tp, dp, name, ip->i_ino, - &first_block, &free_list, resblks); + &first_block, &free_list, 0); if (error) { ASSERT(error != ENOENT); REMOVE_DEBUG_TRACE(__LINE__); @@ -2243,6 +2401,12 @@ xfs_remove( */ link_zero = (ip)->i_d.di_nlink==0; + /* + * Take an extra ref on the inode so that it doesn't + * go to xfs_inactive() from within the commit. + */ + IHOLD(ip); + /* * If this is a synchronous mount, make sure that the * remove transaction goes to disk before returning to @@ -2259,8 +2423,10 @@ xfs_remove( } error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); - if (error) + if (error) { + IRELE(ip); goto std_return; + } /* * If we are using filestreams, kill the stream association. @@ -2272,6 +2438,7 @@ xfs_remove( xfs_filestream_deassociate(ip); xfs_itrace_exit(ip); + IRELE(ip); /* Fall through to std_return with error = 0 */ std_return: @@ -2300,6 +2467,8 @@ xfs_remove( cancel_flags |= XFS_TRANS_ABORT; xfs_trans_cancel(tp, cancel_flags); + IRELE(ip); + goto std_return; } @@ -2367,7 +2536,7 @@ xfs_link( ips[1] = sip; } - xfs_lock_inodes(ips, 2, XFS_ILOCK_EXCL); + xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); /* * Increment vnode ref counts since xfs_trans_commit & @@ -2671,6 +2840,7 @@ xfs_rmdir( struct xfs_name *name, xfs_inode_t *cdp) { + bhv_vnode_t *dir_vp = XFS_ITOV(dp); xfs_mount_t *mp = dp->i_mount; xfs_trans_t *tp; int error; @@ -2695,13 +2865,28 @@ xfs_rmdir( return XFS_ERROR(error); } + /* + * We need to get a reference to cdp before we get our log + * reservation. The reason for this is that we cannot call + * xfs_iget for an inode for which we do not have a reference + * once we've acquired a log reservation. This is because the + * inode we are trying to get might be in xfs_inactive going + * for a log reservation. Since we'll have to wait for the + * inactive code to complete before returning from xfs_iget, + * we need to make sure that we don't have log space reserved + * when we call xfs_iget. Instead we get an unlocked reference + * to the inode before getting our log reservation. + */ + IHOLD(cdp); + /* * Get the dquots for the inodes. */ error = XFS_QM_DQATTACH(mp, dp, 0); - if (!error) + if (!error && dp != cdp) error = XFS_QM_DQATTACH(mp, cdp, 0); if (error) { + IRELE(cdp); REMOVE_DEBUG_TRACE(__LINE__); goto std_return; } @@ -2728,6 +2913,7 @@ xfs_rmdir( if (error) { ASSERT(error != ENOSPC); cancel_flags = 0; + IRELE(cdp); goto error_return; } XFS_BMAP_INIT(&free_list, &first_block); @@ -2741,13 +2927,21 @@ xfs_rmdir( error = xfs_lock_dir_and_entry(dp, cdp); if (error) { xfs_trans_cancel(tp, cancel_flags); + IRELE(cdp); goto std_return; } - IHOLD(dp); xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); + if (dp != cdp) { + /* + * Only increment the parent directory vnode count if + * we didn't bump it in looking up cdp. The only time + * we don't bump it is when we're looking up ".". + */ + VN_HOLD(dir_vp); + } - IHOLD(cdp); + xfs_itrace_ref(cdp); xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL); ASSERT(cdp->i_d.di_nlink >= 2); @@ -2800,6 +2994,12 @@ xfs_rmdir( /* Determine these before committing transaction */ last_cdp_link = (cdp)->i_d.di_nlink==0; + /* + * Take an extra ref on the child vnode so that it + * does not go to xfs_inactive() from within the commit. + */ + IHOLD(cdp); + /* * If this is a synchronous mount, make sure that the * rmdir transaction goes to disk before returning to @@ -2814,15 +3014,19 @@ xfs_rmdir( xfs_bmap_cancel(&free_list); xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT)); + IRELE(cdp); goto std_return; } error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); if (error) { + IRELE(cdp); goto std_return; } + IRELE(cdp); + /* Fall through to std_return with error = 0 or the errno * from xfs_trans_commit. */ std_return: diff --git a/trunk/fs/xfs/xfs_vnodeops.h b/trunk/fs/xfs/xfs_vnodeops.h index 8abe8f186e20..24c53923dc2c 100644 --- a/trunk/fs/xfs/xfs_vnodeops.h +++ b/trunk/fs/xfs/xfs_vnodeops.h @@ -15,6 +15,7 @@ struct xfs_iomap; int xfs_open(struct xfs_inode *ip); +int xfs_getattr(struct xfs_inode *ip, struct bhv_vattr *vap, int flags); int xfs_setattr(struct xfs_inode *ip, struct bhv_vattr *vap, int flags, struct cred *credp); int xfs_readlink(struct xfs_inode *ip, char *link); @@ -47,9 +48,9 @@ int xfs_change_file_space(struct xfs_inode *ip, int cmd, struct cred *credp, int attr_flags); int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name, struct xfs_inode *src_ip, struct xfs_inode *target_dp, - struct xfs_name *target_name, struct xfs_inode *target_ip); + struct xfs_name *target_name); int xfs_attr_get(struct xfs_inode *ip, const char *name, char *value, - int *valuelenp, int flags); + int *valuelenp, int flags, cred_t *cred); int xfs_attr_set(struct xfs_inode *dp, const char *name, char *value, int valuelen, int flags); int xfs_attr_remove(struct xfs_inode *dp, const char *name, int flags); @@ -60,6 +61,9 @@ int xfs_ioctl(struct xfs_inode *ip, struct file *filp, ssize_t xfs_read(struct xfs_inode *ip, struct kiocb *iocb, const struct iovec *iovp, unsigned int segs, loff_t *offset, int ioflags); +ssize_t xfs_sendfile(struct xfs_inode *ip, struct file *filp, + loff_t *offset, int ioflags, size_t count, + read_actor_t actor, void *target); ssize_t xfs_splice_read(struct xfs_inode *ip, struct file *infilp, loff_t *ppos, struct pipe_inode_info *pipe, size_t count, int flags, int ioflags);