xfs
[Top] [All Lists]

Re: dm_write_invis() blocking problem

To: Mike Montour <mmontour@xxxxxxxxxx>
Subject: Re: dm_write_invis() blocking problem
From: Dean Roehrich <roehrich@xxxxxxxxxxxxxxxxxxxxxx>
Date: Wed, 11 Feb 2004 12:37:00 -0600
Cc: linux-xfs@xxxxxxxxxxx
Sender: linux-xfs-bounce@xxxxxxxxxxx
>From:  Mike Montour <mmontour@xxxxxxxxxx>

>I am developing an application using XFS/DMAPI on Linux 2.4.
>
>My application registers for DM_EVENT_READ and DM_EVENT_WRITE events
>on a file, then calls dm_punch_hole() on that file. The event handlers
>use dm_write_invis() to re-populate the file data on demand (including
>re-populating all of the original file data before allowing the
>first write operation to continue).
>
>This works fine for READ events. However, whenever I get a WRITE
>event, the call to dm_write_invis() blocks my program. If I kill
>(ctrl-C) the application that triggered the WRITE event, then the
>dm_write_invis() call returns successfully and my program continues.


Hmm, I guess I'd better dust off my email folders once in a while.  Sorry to
respond so late.

I'm currently testing the following patch, which should alleviate the hang.
The problem is that a thread was able to get into the dmapi queues while
holding a resource (i_sem, in this case).

Dean


===========================================================================
dmapi/dmapi_xfs.c
===========================================================================

--- /usr/tmp/TmpDir.4852600-0/dmapi/dmapi_xfs.c_1.28    Wed Feb  4 16:21:21 2004
+++ dmapi/dmapi_xfs.c   Wed Feb  4 15:38:34 2004
@@ -136,6 +136,7 @@
        bhv_desc_t      *bdp;
        xfs_inode_t     *ip;
        uint16_t        dmstate;
+       struct inode    *inode = LINVFS_GET_IP(vp);
 
        XFS_BHV_LOOKUP(vp, bdp);
        ip = XFS_BHVTOI(bdp);
@@ -143,8 +144,24 @@
                dmstate = ip->i_iocore.io_dmstate;
                if (locktype)
                        xfs_rwunlock(bdp, *locktype);
+
+               if (flags & DM_FLAGS_ISEM)
+                       up(&inode->i_sem);
+#ifdef DM_FLAGS_IALLOCSEM
+               else if (flags & DM_FLAGS_IALLOCSEM)
+                       do_up_read(&inode->i_alloc_sem);
+#endif
+
                error = dm_send_data_event(event, vp, DM_RIGHT_NULL,
                                offset, length, flags);
+
+               if (flags & DM_FLAGS_ISEM)
+                       down(&inode->i_sem);
+#ifdef DM_FLAGS_IALLOCSEM
+               else if (flags & DM_FLAGS_IALLOCSEM)
+                       do_down_read(&inode->i_alloc_sem);
+#endif
+
                if (locktype)
                        xfs_rwlock(bdp, *locktype);
        } while (!error && (ip->i_iocore.io_dmstate != dmstate));

===========================================================================
linux-2.4/xfs_lrw.c
===========================================================================

--- /usr/tmp/TmpDir.4852600-0/linux-2.4/xfs_lrw.c_1.211 Wed Feb  4 16:21:21 2004
+++ linux-2.4/xfs_lrw.c Wed Feb  4 15:11:19 2004
@@ -311,9 +311,10 @@
            !(ioflags & IO_INVIS)) {
                int error;
                vrwlock_t locktype = VRWLOCK_READ;
+               int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG(ioflags);
 
                error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), 
*offset, size,
-                                     FILP_DELAY_FLAG(file), &locktype);
+                                     dmflags, &locktype);
                if (error) {
                        if (!(ioflags & IO_ISLOCKED))
                                xfs_iunlock(ip, XFS_IOLOCK_SHARED);
@@ -649,11 +650,12 @@
        if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
            !(ioflags & IO_INVIS) && !eventsent)) {
                loff_t          savedsize = *offset;
+               int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG(ioflags);
 
                xfs_iunlock(xip, XFS_ILOCK_EXCL);
                error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, vp,
                                      *offset, size,
-                                     FILP_DELAY_FLAG(file), &locktype);
+                                     dmflags, &locktype);
                if (error) {
                        if (iolock) xfs_iunlock(xip, iolock);
                        return -error;

===========================================================================
linux-2.6/xfs_lrw.c
===========================================================================

--- /usr/tmp/TmpDir.4852600-0/linux-2.6/xfs_lrw.c_1.202 Wed Feb  4 16:21:21 2004
+++ linux-2.6/xfs_lrw.c Wed Feb  4 15:11:19 2004
@@ -738,11 +738,12 @@
        if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
            !(ioflags & IO_INVIS) && !eventsent)) {
                loff_t          savedsize = *offset;
+               int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG(ioflags);
 
                xfs_iunlock(xip, XFS_ILOCK_EXCL);
                error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, vp,
                                      *offset, size,
-                                     FILP_DELAY_FLAG(file), &locktype);
+                                     dmflags, &locktype);
                if (error) {
                        if (iolock) xfs_iunlock(xip, iolock);
                        return -error;

===========================================================================
xfs_dmapi.h
===========================================================================

--- /usr/tmp/TmpDir.4852600-0/xfs_dmapi.h_1.43  Wed Feb  4 16:21:21 2004
+++ xfs_dmapi.h Wed Feb  4 16:15:03 2004
@@ -165,6 +165,24 @@
 
 #define DM_FLAGS_NDELAY                0x001   /* return EAGAIN after 
dm_pending() */
 #define DM_FLAGS_UNWANTED      0x002   /* event not in fsys dm_eventset_t */
+#define DM_FLAGS_ISEM          0x004   /* thread holds i_sem */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)
+/* i_alloc_sem was added in 2.4.22-pre1 */
+#define DM_FLAGS_IALLOCSEM     0x010   /* thread holds i_alloc_sem */
+#endif
+#endif
+
+/*
+ *     Based on IO_ISDIRECT, decide which i_ flag is set.
+ */
+#ifdef DM_FLAGS_IALLOCSEM
+#define DM_SEM_FLAG(ioflags) (((ioflags) & IO_ISDIRECT) ? \
+                             DM_FLAGS_IALLOCSEM : DM_FLAGS_ISEM)
+#else
+#define DM_SEM_FLAG(ioflags) (((ioflags) & IO_ISDIRECT) ? \
+                             0 : DM_FLAGS_ISEM)
+#endif
 
 /*
  *     Macros to turn caller specified delay/block flags into


<Prev in Thread] Current Thread [Next in Thread>