[EMAIL PROTECTED] (Martin Jacobs) writes:

> Hi Wolfgang,
> 
> > Hi Martin!
> > 
> > Trying to kill the keyboard, [EMAIL PROTECTED] produced:
> > > has anybody seen something like this?
> > 
> > > Module         Pages    Used by
> > > zftape            21            -1610612737
> > > ftape             34    [zftape]        0 
> > > ....

This is 0x9fffffff

/* magic marker for modules inserted from kerneld, to be auto-reaped */
#define MOD_AUTOCLEAN 0x40000000 /* big enough, but no sign problems... */
#define MOD_VISITED   0x20000000 /* Thanks Jacques! */

So it is simply "-1", after the kernel has cleared the MOD_AUTOCLEAN
and MOD_VISITED bits.

> > 
> > > What may be the reason for this abnormal usage count? Any
> > 
> > A bug.  Which version, exactly, are you using?
> 
> insmod reports version 2.1.85. Kernel is 2.0.33, everything
> out of a S.u.S.E. distribution 5.2 and ftape-4.02
> (4.03-pre-2) from the net.
> 
> My observation is that this happens if I load ftape and
> zftape manually and let kerneld load ftape-internal. Really
> strange. 
> 
> Another strange thing happens if I load all three modules
> manually, then do an ftmt status command and after this an
> ftformat --verify-only. Then after a moment zftape gets
> (autoclean) and some moments later kerneld unloads this
> module. Then ftformat comes in to real trouble and I have to
> reboot the machine.

The two problems are related. The point is that the kernel stores some
flags in the same location where it stores the module use count. As
negative numbers are represented using the 2-complement, small
negative numbers are bit fields with almost all bits set to
1. E.g. "-1" is 0xffffffff. Therefore the kernel thinks it can
autoclean the module. Older kernels wouldn't do this, but I think
2.0.36 only checks for the use count being >= 0 instead of == 0 which
would explain the strange behavior.

/* magic marker for modules inserted from kerneld, to be auto-reaped */
#define MOD_AUTOCLEAN 0x40000000 /* big enough, but no sign problems... */
#define MOD_VISITED   0x20000000 /* Thanks Jacques! */



After reviewing ftape/zftape/zftape-init.c I still don't understand
what is going wrong.

zftape_open() initially increments the use count, and decrements it
before exiting if something went wrong. This should work just fine.

Then, if zftape_open() succeeds, it checks whether the ftape driver is
"dirty", in which case a previous zftape_close() did not decrement the
use count to prevent the zftape module from being reaped by the
kernel.

This opens a door for that bug: if the zft_dirty() returns "1" when it
is called for the first time, then it will result in a negative use
count.

However, I don't know why this should be the case. So, if you don't
mind, please do the following changes to the code and report back
what happens:

in ftape/zftape/zftape-init.c, function zft_open():

#if defined(MODULE) && LINUX_VERSION_CODE < KERNEL_VER(2,1,18)
        if (!zft_dirty(zftape)) {
                MOD_DEC_USE_COUNT; /* unlock module in memory */
        }
#endif

Please change this to 

#if defined(MODULE) && LINUX_VERSION_CODE < KERNEL_VER(2,1,18)
        if (!zft_dirty(zftape)) {
                TRACE(ft_t_warn, "Unlocking module because tape was dirty");
                MOD_DEC_USE_COUNT; /* unlock module in memory */
                if (!MOD_IN_USE) {
                        TRACE(ft_t_err,
                              "Error, use count is zero after "__FUNCTION__);
                        MOD_INC_USE_COUNT;
                }
        }
#endif

This should a) inform us if the problem is located here, b) prevent
your modules from being locked forever, so it should spare you a
reboot during testing.

This alone doesn't suffice, I also need information why zft_dirty()
should report the wrong thing.

So, please replace zft_dirty() in ftape/zftape/zftape-ctl.c by the
following version:

int zft_dirty(zftape_info_t *zftape)
{
        ftape_info_t *ftape = zftape->ftape;
        TRACE_FUN(ft_t_any);

        if (!ftape || !ftape->formatted || zftape->offline) { 
                /* cannot be dirty if not formatted or offline */
                TRACE_EXIT 0;
        }
        if (zftape->blk_sz != CONFIG_ZFT_DFLT_BLK_SZ) {
                TRACE(ft_t_info, "Block size has changed %d/%d",
                      zftape->blk_sz, CONFIG_ZFT_DFLT_BLK_SZ);
                /* blocksize changed, must lock */
                TRACE_EXIT 1;
        }
        if (!zft_tape_at_lbot(zftape, &zftape->pos)) {
                TRACE(ft_t_info, "Tape not at bot");
                /* somewhere inside a volume, lock tape */
                TRACE_EXIT 1;
        }
        if (zftape->volume_table_changed || zftape->header_changed) {
                if ( !(ftape->write_protected || zftape->old_ftape)) {
                        TRACE(ft_t_info, "header segments dirty");
                }
                /* header segments dirty if tape not write protected */
                TRACE_EXIT !(ftape->write_protected || zftape->old_ftape);
        }
        return 0;
}

Reply via email to