linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-01  8:55 [PATCH] sparc32: wrong type of nlink_t Tomas Szepe
@ 2002-09-01  8:52 ` David S. Miller
  2002-09-01  9:44   ` Tomas Szepe
  0 siblings, 1 reply; 44+ messages in thread
From: David S. Miller @ 2002-09-01  8:52 UTC (permalink / raw)
  To: szepe; +Cc: marcelo, linux-kernel, aurora-sparc-devel

   From: Tomas Szepe <szepe@pinerecords.com>
   Date: Sun, 1 Sep 2002 10:55:24 +0200

   Against 2.4.20-pre5 - fix up the type of nlink_t. This makes jfs and
   reiserfs stop complaining about comparisons always turning up false
   due to limited range of data type.

If you change this, you change the types exported to userspace
which will break everything.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH] sparc32: wrong type of nlink_t
@ 2002-09-01  8:55 Tomas Szepe
  2002-09-01  8:52 ` David S. Miller
  0 siblings, 1 reply; 44+ messages in thread
From: Tomas Szepe @ 2002-09-01  8:55 UTC (permalink / raw)
  To: davem, marcelo, linux-kernel, aurora-sparc-devel

Against 2.4.20-pre5 - fix up the type of nlink_t. This makes jfs and
reiserfs stop complaining about comparisons always turning up false
due to limited range of data type.

T.

--- linux-2.4.19/include/asm-sparc/posix_types.h	2000-01-16 07:08:29.000000000 +0100
+++ linux-2.4.20-pre5/include/asm-sparc/posix_types.h	2002-09-01 10:41:35.000000000 +0200
@@ -21,7 +21,7 @@
 typedef unsigned long          __kernel_ino_t;
 typedef unsigned short         __kernel_mode_t;
 typedef unsigned short         __kernel_umode_t;
-typedef short                  __kernel_nlink_t;
+typedef unsigned short         __kernel_nlink_t;
 typedef long                   __kernel_daddr_t;
 typedef long                   __kernel_off_t;
 typedef char *                 __kernel_caddr_t;

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-01  8:52 ` David S. Miller
@ 2002-09-01  9:44   ` Tomas Szepe
  2002-09-04 20:18     ` Dave Kleikamp
  0 siblings, 1 reply; 44+ messages in thread
From: Tomas Szepe @ 2002-09-01  9:44 UTC (permalink / raw)
  To: David S. Miller
  Cc: marcelo, linux-kernel, aurora-sparc-devel, reiserfs-dev, linuxjfs

>    From: Tomas Szepe <szepe@pinerecords.com>
>    Date: Sun, 1 Sep 2002 10:55:24 +0200
> 
>    Against 2.4.20-pre5 - fix up the type of nlink_t. This makes jfs and
>    reiserfs stop complaining about comparisons always turning up false
>    due to limited range of data type.
> 
> If you change this, you change the types exported to userspace
> which will break everything.

Right.  Here's a corresponding reiserfs/jfs fix, then.  I've checked the
constants aren't used for anything else except nlink overflow alerts.

T.


diff -urN linux-2.4.20-pre5/fs/jfs/jfs_filsys.h linux-2.4.20-pre5.n/fs/jfs/jfs_filsys.h
--- linux-2.4.20-pre5/fs/jfs/jfs_filsys.h	2002-09-01 11:31:44.000000000 +0200
+++ linux-2.4.20-pre5.n/fs/jfs/jfs_filsys.h	2002-09-01 11:30:13.000000000 +0200
@@ -125,7 +125,8 @@
 #define MAXBLOCKSIZE		4096
 #define	MAXFILESIZE		((s64)1 << 52)
 
-#define JFS_LINK_MAX		65535	/* nlink_t is unsigned short */
+/* the shortest nlink_t there is is sparc's signed short */
+#define JFS_LINK_MAX		32767
 
 /* Minimum number of bytes supported for a JFS partition */
 #define MINJFS			(0x1000000)
diff -urN linux-2.4.20-pre5/include/linux/reiserfs_fs.h linux-2.4.20-pre5.n/include/linux/reiserfs_fs.h
--- linux-2.4.20-pre5/include/linux/reiserfs_fs.h	2002-09-01 11:31:45.000000000 +0200
+++ linux-2.4.20-pre5.n/include/linux/reiserfs_fs.h	2002-09-01 11:23:30.000000000 +0200
@@ -1185,10 +1185,12 @@
 #define MAX_B_NUM  MAX_UL_INT
 #define MAX_FC_NUM MAX_US_INT
 
-
-/* the purpose is to detect overflow of an unsigned short */
-#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
-
+/* the original purpose was to detect a possible overflow
+ * of an unsigned short nlink_t. However, there are archs
+ * that only provide a signed short nlink_t, so this will
+ * have to start ringing a wee bit earlier.
+ */
+#define REISERFS_LINK_MAX (0x7fff - 1000)
 
 /* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
 #define REISERFS_KERNEL_MEM		0	/* reiserfs kernel memory mode	*/

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-01  9:44   ` Tomas Szepe
@ 2002-09-04 20:18     ` Dave Kleikamp
  2002-09-04 20:29       ` [reiserfs-dev] " Chris Mason
                         ` (2 more replies)
  0 siblings, 3 replies; 44+ messages in thread
From: Dave Kleikamp @ 2002-09-04 20:18 UTC (permalink / raw)
  To: Tomas Szepe
  Cc: David S. Miller, marcelo, linux-kernel, aurora-sparc-devel,
	reiserfs-dev, linuxjfs

> >    Against 2.4.20-pre5 - fix up the type of nlink_t. This makes jfs and
> >    reiserfs stop complaining about comparisons always turning up false
> >    due to limited range of data type.
> >
> > If you change this, you change the types exported to userspace
> > which will break everything.
> 
> Right.  Here's a corresponding reiserfs/jfs fix, then.  I've checked the
> constants aren't used for anything else except nlink overflow alerts.

I don't like this fix.  I know 32767 is a lot of links, but I don't like
artificially lowering a limit like this just because one architecture
defines nlink_t incorrectly.  I'd rather get rid of the compiler warnings
with a cast in the few places the limit is checked, even though that is
a little bit ugly.

> diff -urN linux-2.4.20-pre5/fs/jfs/jfs_filsys.h linux-2.4.20-pre5.n/fs/jfs/jfs_filsys.h
> --- linux-2.4.20-pre5/fs/jfs/jfs_filsys.h	2002-09-01 11:31:44.000000000 +0200
> +++ linux-2.4.20-pre5.n/fs/jfs/jfs_filsys.h	2002-09-01 11:30:13.000000000 +0200
> @@ -125,7 +125,8 @@
>  #define MAXBLOCKSIZE		4096
>  #define	MAXFILESIZE		((s64)1 << 52)
> 
> -#define JFS_LINK_MAX		65535	/* nlink_t is unsigned short */
> +/* the shortest nlink_t there is is sparc's signed short */
> +#define JFS_LINK_MAX		32767
> 
>  /* Minimum number of bytes supported for a JFS partition */
>  #define MINJFS			(0x1000000)
> diff -urN linux-2.4.20-pre5/include/linux/reiserfs_fs.h linux-2.4.20-pre5.n/include/linux/reiserfs_fs.h
> --- linux-2.4.20-pre5/include/linux/reiserfs_fs.h	2002-09-01 11:31:45.000000000 +0200
> +++ linux-2.4.20-pre5.n/include/linux/reiserfs_fs.h	2002-09-01 11:23:30.000000000 +0200
> @@ -1185,10 +1185,12 @@
>  #define MAX_B_NUM  MAX_UL_INT
>  #define MAX_FC_NUM MAX_US_INT
> 
> -
> -/* the purpose is to detect overflow of an unsigned short */
> -#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
> -
> +/* the original purpose was to detect a possible overflow
> + * of an unsigned short nlink_t. However, there are archs
> + * that only provide a signed short nlink_t, so this will
> + * have to start ringing a wee bit earlier.
> + */
> +#define REISERFS_LINK_MAX (0x7fff - 1000)
> 
>  /* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
>  #define REISERFS_KERNEL_MEM		0	/* reiserfs kernel memory mode	*/

Thanks,
Shaggy

-- 
David Kleikamp
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-04 20:18     ` Dave Kleikamp
@ 2002-09-04 20:29       ` Chris Mason
  2002-09-04 23:34         ` David S. Miller
  2002-09-06  8:52         ` David Woodhouse
  2002-09-04 20:31       ` Hans Reiser
  2002-09-04 23:33       ` David S. Miller
  2 siblings, 2 replies; 44+ messages in thread
From: Chris Mason @ 2002-09-04 20:29 UTC (permalink / raw)
  To: Dave Kleikamp
  Cc: Tomas Szepe, David S. Miller, marcelo, linux-kernel,
	aurora-sparc-devel, reiserfs-dev, linuxjfs

On Wed, 2002-09-04 at 16:18, Dave Kleikamp wrote:
> > >    Against 2.4.20-pre5 - fix up the type of nlink_t. This makes jfs and
> > >    reiserfs stop complaining about comparisons always turning up false
> > >    due to limited range of data type.
> > >
> > > If you change this, you change the types exported to userspace
> > > which will break everything.
> > 
> > Right.  Here's a corresponding reiserfs/jfs fix, then.  I've checked the
> > constants aren't used for anything else except nlink overflow alerts.
> 
> I don't like this fix.  I know 32767 is a lot of links, but I don't like
> artificially lowering a limit like this just because one architecture
> defines nlink_t incorrectly.  I'd rather get rid of the compiler warnings
> with a cast in the few places the limit is checked, even though that is
> a little bit ugly.
> 

The patch will probably cause reiserfs problems as well, we've already
got people with > 32767 links on disk, going to a lower number will
confuse things.

-chris



^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-04 20:18     ` Dave Kleikamp
  2002-09-04 20:29       ` [reiserfs-dev] " Chris Mason
@ 2002-09-04 20:31       ` Hans Reiser
  2002-09-04 21:18         ` Tomas Szepe
  2002-09-04 23:35         ` David S. Miller
  2002-09-04 23:33       ` David S. Miller
  2 siblings, 2 replies; 44+ messages in thread
From: Hans Reiser @ 2002-09-04 20:31 UTC (permalink / raw)
  To: Dave Kleikamp
  Cc: Tomas Szepe, David S. Miller, marcelo, linux-kernel,
	aurora-sparc-devel, reiserfs-dev, linuxjfs, Oleg Drokin

Dave Kleikamp wrote:

>>>   Against 2.4.20-pre5 - fix up the type of nlink_t. This makes jfs and
>>>   reiserfs stop complaining about comparisons always turning up false
>>>   due to limited range of data type.
>>>
>>>If you change this, you change the types exported to userspace
>>>which will break everything.
>>>      
>>>
>>Right.  Here's a corresponding reiserfs/jfs fix, then.  I've checked the
>>constants aren't used for anything else except nlink overflow alerts.
>>    
>>
>
>I don't like this fix.  I know 32767 is a lot of links, but I don't like
>artificially lowering a limit like this just because one architecture
>defines nlink_t incorrectly.  I'd rather get rid of the compiler warnings
>with a cast in the few places the limit is checked, even though that is
>a little bit ugly.
>
>  
>
>>diff -urN linux-2.4.20-pre5/fs/jfs/jfs_filsys.h linux-2.4.20-pre5.n/fs/jfs/jfs_filsys.h
>>--- linux-2.4.20-pre5/fs/jfs/jfs_filsys.h	2002-09-01 11:31:44.000000000 +0200
>>+++ linux-2.4.20-pre5.n/fs/jfs/jfs_filsys.h	2002-09-01 11:30:13.000000000 +0200
>>@@ -125,7 +125,8 @@
>> #define MAXBLOCKSIZE		4096
>> #define	MAXFILESIZE		((s64)1 << 52)
>>
>>-#define JFS_LINK_MAX		65535	/* nlink_t is unsigned short */
>>+/* the shortest nlink_t there is is sparc's signed short */
>>+#define JFS_LINK_MAX		32767
>>
>> /* Minimum number of bytes supported for a JFS partition */
>> #define MINJFS			(0x1000000)
>>diff -urN linux-2.4.20-pre5/include/linux/reiserfs_fs.h linux-2.4.20-pre5.n/include/linux/reiserfs_fs.h
>>--- linux-2.4.20-pre5/include/linux/reiserfs_fs.h	2002-09-01 11:31:45.000000000 +0200
>>+++ linux-2.4.20-pre5.n/include/linux/reiserfs_fs.h	2002-09-01 11:23:30.000000000 +0200
>>@@ -1185,10 +1185,12 @@
>> #define MAX_B_NUM  MAX_UL_INT
>> #define MAX_FC_NUM MAX_US_INT
>>
>>-
>>-/* the purpose is to detect overflow of an unsigned short */
>>-#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
>>-
>>+/* the original purpose was to detect a possible overflow
>>+ * of an unsigned short nlink_t. However, there are archs
>>+ * that only provide a signed short nlink_t, so this will
>>+ * have to start ringing a wee bit earlier.
>>+ */
>>+#define REISERFS_LINK_MAX (0x7fff - 1000)
>>
>> /* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
>> #define REISERFS_KERNEL_MEM		0	/* reiserfs kernel memory mode	*/
>>    
>>
>
>Thanks,
>Shaggy
>
>  
>
I think you are sort of right.  You are right to dislike this patch for 
the reasons you state.  The proper fix should be to make the result of 
the limit computation be accurately architecture specific.   I wasn't 
paying enough attention --- hardcoding

0x7fff - 1000 

is ugly.  We need to find some appropriate #define to subtract 1000 from.

Green, please scan the code for the magic constant to compute from, and 
code something unless Dave or someone does it before you.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-04 20:31       ` Hans Reiser
@ 2002-09-04 21:18         ` Tomas Szepe
  2002-09-04 21:44           ` Thunder from the hill
  2002-09-04 23:35         ` David S. Miller
  1 sibling, 1 reply; 44+ messages in thread
From: Tomas Szepe @ 2002-09-04 21:18 UTC (permalink / raw)
  To: Hans Reiser
  Cc: Dave Kleikamp, David S. Miller, marcelo, linux-kernel,
	aurora-sparc-devel, reiserfs-dev, linuxjfs, Oleg Drokin

> >>>  Against 2.4.20-pre5 - fix up the type of nlink_t. This makes jfs and
> >>>  reiserfs stop complaining about comparisons always turning up false
> >>>  due to limited range of data type.
> >>>
> >>>If you change this, you change the types exported to userspace
> >>>which will break everything.
> >>>     
> >>>
> >>Right.  Here's a corresponding reiserfs/jfs fix, then.  I've checked the
> >>constants aren't used for anything else except nlink overflow alerts.
> >>   
> >>
> >
> >I don't like this fix.  I know 32767 is a lot of links, but I don't like
> >artificially lowering a limit like this just because one architecture
> >defines nlink_t incorrectly.  I'd rather get rid of the compiler warnings
> >with a cast in the few places the limit is checked, even though that is
> >a little bit ugly.
> >
> > 
> >
> >>diff -urN linux-2.4.20-pre5/fs/jfs/jfs_filsys.h 
> >>linux-2.4.20-pre5.n/fs/jfs/jfs_filsys.h
> >>--- linux-2.4.20-pre5/fs/jfs/jfs_filsys.h	2002-09-01 
> >>11:31:44.000000000 +0200
> >>+++ linux-2.4.20-pre5.n/fs/jfs/jfs_filsys.h	2002-09-01 
> >>11:30:13.000000000 +0200
> >>@@ -125,7 +125,8 @@
> >>#define MAXBLOCKSIZE		4096
> >>#define	MAXFILESIZE		((s64)1 << 52)
> >>
> >>-#define JFS_LINK_MAX		65535	/* nlink_t is unsigned short 
> >>*/
> >>+/* the shortest nlink_t there is is sparc's signed short */
> >>+#define JFS_LINK_MAX		32767
> >>
> >>/* Minimum number of bytes supported for a JFS partition */
> >>#define MINJFS			(0x1000000)
> >>diff -urN linux-2.4.20-pre5/include/linux/reiserfs_fs.h 
> >>linux-2.4.20-pre5.n/include/linux/reiserfs_fs.h
> >>--- linux-2.4.20-pre5/include/linux/reiserfs_fs.h	2002-09-01 
> >>11:31:45.000000000 +0200
> >>+++ linux-2.4.20-pre5.n/include/linux/reiserfs_fs.h	2002-09-01 
> >>11:23:30.000000000 +0200
> >>@@ -1185,10 +1185,12 @@
> >>#define MAX_B_NUM  MAX_UL_INT
> >>#define MAX_FC_NUM MAX_US_INT
> >>
> >>-
> >>-/* the purpose is to detect overflow of an unsigned short */
> >>-#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
> >>-
> >>+/* the original purpose was to detect a possible overflow
> >>+ * of an unsigned short nlink_t. However, there are archs
> >>+ * that only provide a signed short nlink_t, so this will
> >>+ * have to start ringing a wee bit earlier.
> >>+ */
> >>+#define REISERFS_LINK_MAX (0x7fff - 1000)
> >>
> >>/* The following defines are used in reiserfs_insert_item and 
> >>reiserfs_append_item  */
> >>#define REISERFS_KERNEL_MEM		0	/* reiserfs kernel memory 
> >>mode	*/
> >>   
> >>
> >
> >Thanks,
> >Shaggy
> >
> > 
> >
> I think you are sort of right.  You are right to dislike this patch for 
> the reasons you state.  The proper fix should be to make the result of 
> the limit computation be accurately architecture specific.   I wasn't 
> paying enough attention --- hardcoding
> 
> 0x7fff - 1000 
> 
> is ugly.  We need to find some appropriate #define to subtract 1000 from.
> 
> Green, please scan the code for the magic constant to compute from, and 
> code something unless Dave or someone does it before you.


All right, how about this? ->


typedef unsigned long long u64;

/* usable for char, short int, and int */
#define set_to_max(a) \
{ \
	u64 max = ((u64) 2 << (sizeof(a) * 8 - 1)) - 1; \
	a = max; if ((u64) a != max) a = max / 2; \
}


Tomas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-04 21:18         ` Tomas Szepe
@ 2002-09-04 21:44           ` Thunder from the hill
  2002-09-04 21:57             ` Thunder from the hill
  0 siblings, 1 reply; 44+ messages in thread
From: Thunder from the hill @ 2002-09-04 21:44 UTC (permalink / raw)
  To: Tomas Szepe
  Cc: Hans Reiser, Dave Kleikamp, David S. Miller, marcelo,
	linux-kernel, aurora-sparc-devel, reiserfs-dev, linuxjfs,
	Oleg Drokin

Hi,

On Wed, 4 Sep 2002, Tomas Szepe wrote:
> typedef unsigned long long u64;
> 
> /* usable for char, short int, and int */
> #define set_to_max(a) \
> { \
> 	u64 max = ((u64) 2 << (sizeof(a) * 8 - 1)) - 1; \
> 	a = max; if ((u64) a != max) a = max / 2; \
> }

To make it more secure, we should consider the following version:

typedef unsigned long long u64;

/* usable for char, short int, and int */
#define set_to_max(a) { \
        u64 __val_max = ((u64) 1 << (sizeof(a) * 8)) - 1; \
        a = __val_max; \
        if ((u64) a != __val_max) \
                a = __val_max / 2; \
}

So it's basically naming.

			Thunder
-- 
--./../...-/. -.--/---/..-/.-./..././.-../..-. .---/..-/.../- .-
--/../-./..-/-/./--..-- ../.----./.-../.-.. --./../...-/. -.--/---/..-
.- -/---/--/---/.-./.-./---/.--/.-.-.-
--./.-/-.../.-./.././.-../.-.-.-


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-04 21:44           ` Thunder from the hill
@ 2002-09-04 21:57             ` Thunder from the hill
  0 siblings, 0 replies; 44+ messages in thread
From: Thunder from the hill @ 2002-09-04 21:57 UTC (permalink / raw)
  To: Thunder from the hill
  Cc: Tomas Szepe, Hans Reiser, Dave Kleikamp, David S. Miller,
	marcelo, linux-kernel, aurora-sparc-devel, reiserfs-dev,
	linuxjfs, Oleg Drokin

Hi,

On Wed, 4 Sep 2002, Thunder from the hill wrote:
> On Wed, 4 Sep 2002, Tomas Szepe wrote:
> > typedef unsigned long long u64;
> > 
> > /* usable for char, short int, and int */
> > #define set_to_max(a) \
> > { \
> > 	u64 max = ((u64) 2 << (sizeof(a) * 8 - 1)) - 1; \
> > 	a = max; if ((u64) a != max) a = max / 2; \
> > }

This is the wholesale:

typedef unsigned long long u64;

/* usable for char, short int, and int */
#define set_to_max(a) do { \
        u64 __val_max = ((u64) 1 << (sizeof(a) * 8)) - 1; \
        a = __val_max; \
        if ((u64) a != __val_max) \
                a = __val_max / 2; \
} while(0)

#define set_to_min(a) do { \
        set_to_max(a); \
        a++; \
} while(0)

			Thunder
-- 
--./../...-/. -.--/---/..-/.-./..././.-../..-. .---/..-/.../- .-
--/../-./..-/-/./--..-- ../.----./.-../.-.. --./../...-/. -.--/---/..-
.- -/---/--/---/.-./.-./---/.--/.-.-.-
--./.-/-.../.-./.././.-../.-.-.-


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-04 20:18     ` Dave Kleikamp
  2002-09-04 20:29       ` [reiserfs-dev] " Chris Mason
  2002-09-04 20:31       ` Hans Reiser
@ 2002-09-04 23:33       ` David S. Miller
  2 siblings, 0 replies; 44+ messages in thread
From: David S. Miller @ 2002-09-04 23:33 UTC (permalink / raw)
  To: shaggy
  Cc: szepe, marcelo, linux-kernel, aurora-sparc-devel, reiserfs-dev, linuxjfs

   From: Dave Kleikamp <shaggy@austin.ibm.com>
   Date: Wed, 4 Sep 2002 15:18:05 -0500 (CDT)
   
   I don't like this fix.  I know 32767 is a lot of links, but I don't like
   artificially lowering a limit like this just because one architecture
   defines nlink_t incorrectly.  I'd rather get rid of the compiler warnings
   with a cast in the few places the limit is checked, even though that is
   a little bit ugly.

"incorrectly"?  There are no correct or incorrect values for any
of these types, which is why they are defined on a per-platform
basis.

If you impose different limits on different platforms, that means
that a jfs/reiserfs filesystem that works properly on one platform
may not function properly on another.

That is something I'd certainly deem "incorrect" :-)

Every other filesystem can be plugged into an arbitrary Linux platform
and be expected to work properly, don't make jfs/reiserfs an exception
to this.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-04 20:29       ` [reiserfs-dev] " Chris Mason
@ 2002-09-04 23:34         ` David S. Miller
  2002-09-06  8:52         ` David Woodhouse
  1 sibling, 0 replies; 44+ messages in thread
From: David S. Miller @ 2002-09-04 23:34 UTC (permalink / raw)
  To: mason
  Cc: shaggy, szepe, marcelo, linux-kernel, aurora-sparc-devel,
	reiserfs-dev, linuxjfs

   From: Chris Mason <mason@suse.com>
   Date: 04 Sep 2002 16:29:21 -0400
   
   The patch will probably cause reiserfs problems as well, we've already
   got people with > 32767 links on disk, going to a lower number will
   confuse things.
   
And that means you already have reiserfs partitions that cannot
be used on other Linux platforms.  That's pretty bad.

   

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-04 20:31       ` Hans Reiser
  2002-09-04 21:18         ` Tomas Szepe
@ 2002-09-04 23:35         ` David S. Miller
  2002-09-05  0:36           ` Hans Reiser
  1 sibling, 1 reply; 44+ messages in thread
From: David S. Miller @ 2002-09-04 23:35 UTC (permalink / raw)
  To: reiser
  Cc: shaggy, szepe, marcelo, linux-kernel, aurora-sparc-devel,
	reiserfs-dev, linuxjfs, green

   From: Hans Reiser <reiser@namesys.com>
   Date: Thu, 05 Sep 2002 00:31:36 +0400

   The proper fix should be to make the result of the limit
   computation be accurately architecture specific.

And then each and every Reiserfs partition is platform specific
and cannot be mounted onto another Linux platform.

Creating such a restriction is a grave error.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  0:36           ` Hans Reiser
@ 2002-09-05  0:32             ` David S. Miller
  2002-09-05  0:49             ` Chris Mason
  1 sibling, 0 replies; 44+ messages in thread
From: David S. Miller @ 2002-09-05  0:32 UTC (permalink / raw)
  To: reiser
  Cc: shaggy, szepe, marcelo, linux-kernel, aurora-sparc-devel,
	reiserfs-dev, linuxjfs, green

   From: Hans Reiser <reiser@namesys.com>
   Date: Thu, 05 Sep 2002 04:36:15 +0400

   And you would cripple the 99% usage to aid those users who move disk 
   drives physically over to a sparc box AND have more than 31k links to a 
   file?

This is not a sparc or a x86 or x86_64 or ia64 thing.

It's a global thing.

It's about being portable and clean and not installing unnecessary
restrictions.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-04 23:35         ` David S. Miller
@ 2002-09-05  0:36           ` Hans Reiser
  2002-09-05  0:32             ` David S. Miller
  2002-09-05  0:49             ` Chris Mason
  0 siblings, 2 replies; 44+ messages in thread
From: Hans Reiser @ 2002-09-05  0:36 UTC (permalink / raw)
  To: David S. Miller
  Cc: shaggy, szepe, marcelo, linux-kernel, aurora-sparc-devel,
	reiserfs-dev, linuxjfs, green

David S. Miller wrote:

>   From: Hans Reiser <reiser@namesys.com>
>   Date: Thu, 05 Sep 2002 00:31:36 +0400
>
>   The proper fix should be to make the result of the limit
>   computation be accurately architecture specific.
>
>And then each and every Reiserfs partition is platform specific
>and cannot be mounted onto another Linux platform.
>
>Creating such a restriction is a grave error.
>
>
>  
>
And you would cripple the 99% usage to aid those users who move disk 
drives physically over to a sparc box AND have more than 31k links to a 
file?

Or is there some usage pattern that I don't appreciate that makes it 
highly likely that people will swap disks into a sparc?  Maybe these hot 
plug ruggedized with plastic covers IDE disks that there was some press 
about being a substitute for DVDs a few months ago?

Frankly, I had doubts about our code that causes CPU order to not be 
used in the disk format, but I was persuaded that it was not a 
measurable performance loss to do it and said yes.

I recognize that you may see things from a perspective that I have not 
experienced, so please articulate on that if so.

Hans


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  0:36           ` Hans Reiser
  2002-09-05  0:32             ` David S. Miller
@ 2002-09-05  0:49             ` Chris Mason
  2002-09-05  5:40               ` Tomas Szepe
  1 sibling, 1 reply; 44+ messages in thread
From: Chris Mason @ 2002-09-05  0:49 UTC (permalink / raw)
  To: Hans Reiser
  Cc: David S. Miller, shaggy, szepe, marcelo, linux-kernel,
	aurora-sparc-devel, reiserfs-dev, linuxjfs, green

On Wed, 2002-09-04 at 20:36, Hans Reiser wrote:
> David S. Miller wrote:
> 
> >   From: Hans Reiser <reiser@namesys.com>
> >   Date: Thu, 05 Sep 2002 00:31:36 +0400
> >
> >   The proper fix should be to make the result of the limit
> >   computation be accurately architecture specific.
> >
> >And then each and every Reiserfs partition is platform specific
> >and cannot be mounted onto another Linux platform.
> >
> >Creating such a restriction is a grave error.
> >
> >
> >  
> >
> And you would cripple the 99% usage to aid those users who move disk 
> drives physically over to a sparc box AND have more than 31k links to a 
> file?

31k links to a file isn't really an issue, I really doubt anyone out
there is doing something like that.

31k links on a directory is a bigger problem, since each subdir is a
link.  The good news is that reiserfs already works around this by
setting the link count to 1 and doing other checks to make sure a
directory really is empty.

My point isn't that we should not change the link max, it is that
changing the link max is not sufficient.  Portability to sparc doesn't
matter one bit if it means breaking existing i386 users.  Our disk
format has link counts > 32k, so any reiserfs fixes for this need to
expect those larger values on disk and play nicely with them.

-chris



^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  5:40               ` Tomas Szepe
@ 2002-09-05  5:36                 ` David S. Miller
  2002-09-05  5:48                   ` Tomas Szepe
  2002-09-05  9:54                   ` Oleg Drokin
  0 siblings, 2 replies; 44+ messages in thread
From: David S. Miller @ 2002-09-05  5:36 UTC (permalink / raw)
  To: szepe
  Cc: mason, reiser, shaggy, marcelo, linux-kernel, aurora-sparc-devel,
	reiserfs-dev, linuxjfs, green

   From: Tomas Szepe <szepe@pinerecords.com>
   Date: Thu, 5 Sep 2002 07:40:08 +0200

   > Our disk format has link counts > 32k
   
   Does the internal reiserfs nlink value translate directly
   to what stat() puts in st_nlink?
   
It really doesn't matter.  Even if you have some huge value that can't
be represented in st_nlink, you can report to the user that st_nlink
is NLINK_MAX.

This is one possible solution to this whole problem.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  0:49             ` Chris Mason
@ 2002-09-05  5:40               ` Tomas Szepe
  2002-09-05  5:36                 ` David S. Miller
  0 siblings, 1 reply; 44+ messages in thread
From: Tomas Szepe @ 2002-09-05  5:40 UTC (permalink / raw)
  To: Chris Mason
  Cc: Hans Reiser, David S. Miller, shaggy, marcelo, linux-kernel,
	aurora-sparc-devel, reiserfs-dev, linuxjfs, green

> Our disk format has link counts > 32k

Does the internal reiserfs nlink value translate directly
to what stat() puts in st_nlink?

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  5:48                   ` Tomas Szepe
@ 2002-09-05  5:45                     ` David S. Miller
  2002-09-05  9:46                       ` Nikita Danilov
  2002-09-05  5:56                     ` Oleg Drokin
  1 sibling, 1 reply; 44+ messages in thread
From: David S. Miller @ 2002-09-05  5:45 UTC (permalink / raw)
  To: szepe
  Cc: mason, reiser, shaggy, marcelo, linux-kernel, aurora-sparc-devel,
	reiserfs-dev, linuxjfs, green

   From: Tomas Szepe <szepe@pinerecords.com>
   Date: Thu, 5 Sep 2002 07:48:58 +0200
   
   And a pretty straightforward one, too. Convert the internal reiserfs
   link stuff to an unsigned short, find NLINK_MAX using the code I posted
   last night (or maybe simply grab it from userspace includes) and add
   a check to your stat() code to return NLINK_MAX if necessary.
   
Whose stat() code?  These go straight to userspace via normal
syscalls.
   
It has to be done generically, in the VFS or reiserfs.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  5:36                 ` David S. Miller
@ 2002-09-05  5:48                   ` Tomas Szepe
  2002-09-05  5:45                     ` David S. Miller
  2002-09-05  5:56                     ` Oleg Drokin
  2002-09-05  9:54                   ` Oleg Drokin
  1 sibling, 2 replies; 44+ messages in thread
From: Tomas Szepe @ 2002-09-05  5:48 UTC (permalink / raw)
  To: David S. Miller
  Cc: mason, reiser, shaggy, marcelo, linux-kernel, aurora-sparc-devel,
	reiserfs-dev, linuxjfs, green

>    From: Tomas Szepe <szepe@pinerecords.com>
>    Date: Thu, 5 Sep 2002 07:40:08 +0200
> 
>    > Our disk format has link counts > 32k
>    
>    Does the internal reiserfs nlink value translate directly
>    to what stat() puts in st_nlink?
>    
> It really doesn't matter.  Even if you have some huge value that can't
> be represented in st_nlink, you can report to the user that st_nlink
> is NLINK_MAX.
> 
> This is one possible solution to this whole problem.

And a pretty straightforward one, too. Convert the internal reiserfs
link stuff to an unsigned short, find NLINK_MAX using the code I posted
last night (or maybe simply grab it from userspace includes) and add
a check to your stat() code to return NLINK_MAX if necessary.

T.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  5:56                     ` Oleg Drokin
@ 2002-09-05  5:52                       ` David S. Miller
  2002-09-05  6:07                         ` Oleg Drokin
  2002-09-05  5:59                       ` Tomas Szepe
  1 sibling, 1 reply; 44+ messages in thread
From: David S. Miller @ 2002-09-05  5:52 UTC (permalink / raw)
  To: green
  Cc: szepe, mason, reiser, shaggy, marcelo, linux-kernel,
	aurora-sparc-devel, reiserfs-dev, linuxjfs

   From: Oleg Drokin <green@namesys.com>
   Date: Thu, 5 Sep 2002 09:56:38 +0400
   
   On Thu, Sep 05, 2002 at 07:48:58AM +0200, Tomas Szepe wrote:
   > >    Does the internal reiserfs nlink value translate directly
   > >    to what stat() puts in st_nlink?
   > > It really doesn't matter.  Even if you have some huge value that can't
   > > be represented in st_nlink, you can report to the user that st_nlink
   > > is NLINK_MAX.
   > > This is one possible solution to this whole problem.
   >
   > And a pretty straightforward one, too. Convert the internal reiserfs
   > link stuff to an unsigned short, find NLINK_MAX using the code I posted
   
   Too bad it is 32bit nlink field in on disk format ;)
   
We're only talking about what the user is told is the
nlink value, not what you happen to compute and put/get
from disk.

Your nlink can be legitimately 128-bits if you want, it
still can be made to work :-)

   > last night (or maybe simply grab it from userspace includes) and add
   > a check to your stat() code to return NLINK_MAX if necessary.
   
   Ok, I think I will rework it to something sensible, because current code is
   somewhat a mess and corrupt correct nlink value on overflows. Hm.
   
Ok.

Franks a lot,
David S. Miller
davem@redhat.com

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  5:48                   ` Tomas Szepe
  2002-09-05  5:45                     ` David S. Miller
@ 2002-09-05  5:56                     ` Oleg Drokin
  2002-09-05  5:52                       ` David S. Miller
  2002-09-05  5:59                       ` Tomas Szepe
  1 sibling, 2 replies; 44+ messages in thread
From: Oleg Drokin @ 2002-09-05  5:56 UTC (permalink / raw)
  To: Tomas Szepe
  Cc: David S. Miller, mason, reiser, shaggy, marcelo, linux-kernel,
	aurora-sparc-devel, reiserfs-dev, linuxjfs

Hello!

On Thu, Sep 05, 2002 at 07:48:58AM +0200, Tomas Szepe wrote:
> >    Does the internal reiserfs nlink value translate directly
> >    to what stat() puts in st_nlink?
> > It really doesn't matter.  Even if you have some huge value that can't
> > be represented in st_nlink, you can report to the user that st_nlink
> > is NLINK_MAX.
> > This is one possible solution to this whole problem.
> And a pretty straightforward one, too. Convert the internal reiserfs
> link stuff to an unsigned short, find NLINK_MAX using the code I posted

Too bad it is 32bit nlink field in on disk format ;)

> last night (or maybe simply grab it from userspace includes) and add
> a check to your stat() code to return NLINK_MAX if necessary.

Ok, I think I will rework it to something sensible, because current code is
somewhat a mess and corrupt correct nlink value on overflows. Hm.

Bye,
    Oleg

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  5:56                     ` Oleg Drokin
  2002-09-05  5:52                       ` David S. Miller
@ 2002-09-05  5:59                       ` Tomas Szepe
  1 sibling, 0 replies; 44+ messages in thread
From: Tomas Szepe @ 2002-09-05  5:59 UTC (permalink / raw)
  To: Oleg Drokin
  Cc: David S. Miller, mason, reiser, shaggy, marcelo, linux-kernel,
	aurora-sparc-devel, reiserfs-dev, linuxjfs

> > >    Does the internal reiserfs nlink value translate directly
> > >    to what stat() puts in st_nlink?
> > > It really doesn't matter.  Even if you have some huge value that can't
> > > be represented in st_nlink, you can report to the user that st_nlink
> > > is NLINK_MAX.
> > > This is one possible solution to this whole problem.
> > And a pretty straightforward one, too. Convert the internal reiserfs
> > link stuff to an unsigned short, find NLINK_MAX using the code I posted
> 
> Too bad it is 32bit nlink field in on disk format ;)

Oh! What a confession. :)

> > last night (or maybe simply grab it from userspace includes) and add
> > a check to your stat() code to return NLINK_MAX if necessary.
> 
> Ok, I think I will rework it to something sensible, because current code is
> somewhat a mess and corrupt correct nlink value on overflows. Hm.

Good.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  5:52                       ` David S. Miller
@ 2002-09-05  6:07                         ` Oleg Drokin
  0 siblings, 0 replies; 44+ messages in thread
From: Oleg Drokin @ 2002-09-05  6:07 UTC (permalink / raw)
  To: David S. Miller
  Cc: szepe, mason, reiser, shaggy, marcelo, linux-kernel,
	reiserfs-dev, linuxjfs

Hello!

On Wed, Sep 04, 2002 at 10:52:34PM -0700, David S. Miller wrote:

>    > And a pretty straightforward one, too. Convert the internal reiserfs
>    > link stuff to an unsigned short, find NLINK_MAX using the code I posted
>    Too bad it is 32bit nlink field in on disk format ;)
> We're only talking about what the user is told is the
> nlink value, not what you happen to compute and put/get
> from disk.

Yes, I just parsed that suggestion above incorrectly ;)

> Your nlink can be legitimately 128-bits if you want, it
> still can be made to work :-)

Yes, I know. That's what I plan to do ;)

Bye,
    Oleg

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  5:45                     ` David S. Miller
@ 2002-09-05  9:46                       ` Nikita Danilov
  0 siblings, 0 replies; 44+ messages in thread
From: Nikita Danilov @ 2002-09-05  9:46 UTC (permalink / raw)
  To: David S. Miller
  Cc: szepe, mason, reiser, shaggy, marcelo, linux-kernel,
	aurora-sparc-devel, reiserfs-dev, linuxjfs, green

David S. Miller writes:
 >    From: Tomas Szepe <szepe@pinerecords.com>
 >    Date: Thu, 5 Sep 2002 07:48:58 +0200
 >    
 >    And a pretty straightforward one, too. Convert the internal reiserfs
 >    link stuff to an unsigned short, find NLINK_MAX using the code I posted
 >    last night (or maybe simply grab it from userspace includes) and add
 >    a check to your stat() code to return NLINK_MAX if necessary.
 >    
 > Whose stat() code?  These go straight to userspace via normal
 > syscalls.

In 2.5 is goes through ->getattr() method.

 >    
 > It has to be done generically, in the VFS or reiserfs.

Nikita.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  5:36                 ` David S. Miller
  2002-09-05  5:48                   ` Tomas Szepe
@ 2002-09-05  9:54                   ` Oleg Drokin
  2002-09-05 10:50                     ` David S. Miller
                                       ` (3 more replies)
  1 sibling, 4 replies; 44+ messages in thread
From: Oleg Drokin @ 2002-09-05  9:54 UTC (permalink / raw)
  To: David S. Miller
  Cc: szepe, mason, reiser, shaggy, marcelo, linux-kernel,
	reiserfs-dev, linuxjfs

Hello!

On Wed, Sep 04, 2002 at 10:36:51PM -0700, David S. Miller wrote:
>    > Our disk format has link counts > 32k
>    Does the internal reiserfs nlink value translate directly
>    to what stat() puts in st_nlink?
> It really doesn't matter.  Even if you have some huge value that can't
> be represented in st_nlink, you can report to the user that st_nlink
> is NLINK_MAX.

Ok, since I really like this approach, below is the patch (for 2.4) that
demonstrates my solution.
Also it correctly calculates maximal number given type may hold ( does not work
with unsigned long long, though) with my own way ;)

FS compatibility is still intact and older kernel will work.
If nobody will object against this code, then I'll implement something
similar for 2.5 too and we will fix reiserfsck to understand this correct
nlink accounting.
The only downside of this patch is that v3.5 filesystems won't allow to
create more than 64k-2 subdirs in a dir, like old code did, but this is
not an issue I think.  (already existent dirs should still work)

Bye,
    Oleg

===== fs/reiserfs/inode.c 1.35 vs edited =====
--- 1.35/fs/reiserfs/inode.c	Fri Aug  9 19:22:33 2002
+++ edited/fs/reiserfs/inode.c	Thu Sep  5 13:43:26 2002
@@ -891,7 +891,8 @@
 	set_inode_item_key_version (inode, KEY_FORMAT_3_5);
         set_inode_sd_version (inode, STAT_DATA_V1);
 	inode->i_mode  = sd_v1_mode(sd);
-	inode->i_nlink = sd_v1_nlink(sd);
+	inode->i_nlink = ( sd_v1_nlink(sd) > REISERFS_LINK_MAX ) ? REISERFS_LINK_MAX:sd_v1_nlink(sd);
+	inode->u.reiserfs_i.i_nlink_real = sd_v1_nlink(sd);
 	inode->i_uid   = sd_v1_uid(sd);
 	inode->i_gid   = sd_v1_gid(sd);
 	inode->i_size  = sd_v1_size(sd);
@@ -923,7 +924,8 @@
 	struct stat_data * sd = (struct stat_data *)B_I_PITEM (bh, ih);
 
 	inode->i_mode   = sd_v2_mode(sd);
-	inode->i_nlink  = sd_v2_nlink(sd);
+	inode->i_nlink  = (sd_v2_nlink(sd)>REISERFS_LINK_MAX)?REISERFS_LINK_MAX:sd_v2_nlink(sd);
+	inode->u.reiserfs_i.i_nlink_real = sd_v2_nlink(sd);
 	inode->i_uid    = sd_v2_uid(sd);
 	inode->i_size   = sd_v2_size(sd);
 	inode->i_gid    = sd_v2_gid(sd);
@@ -975,7 +977,7 @@
     __u16 flags;
 
     set_sd_v2_mode(sd_v2, inode->i_mode );
-    set_sd_v2_nlink(sd_v2, inode->i_nlink );
+    set_sd_v2_nlink(sd_v2, inode->u.reiserfs_i.i_nlink_real );
     set_sd_v2_uid(sd_v2, inode->i_uid );
     set_sd_v2_size(sd_v2, inode->i_size );
     set_sd_v2_gid(sd_v2, inode->i_gid );
@@ -1001,7 +1003,7 @@
     set_sd_v1_mode(sd_v1, inode->i_mode );
     set_sd_v1_uid(sd_v1, inode->i_uid );
     set_sd_v1_gid(sd_v1, inode->i_gid );
-    set_sd_v1_nlink(sd_v1, inode->i_nlink );
+    set_sd_v1_nlink(sd_v1, inode->u.reiserfs_i.i_nlink_real );
     set_sd_v1_size(sd_v1, inode->i_size );
     set_sd_v1_atime(sd_v1, inode->i_atime );
     set_sd_v1_ctime(sd_v1, inode->i_ctime );
@@ -1537,7 +1539,7 @@
 
     /* fill stat data */
     inode->i_mode = mode;
-    inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
+    inode->u.reiserfs_i.i_nlink_real = inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
     inode->i_uid = current->fsuid;
     if (dir->i_mode & S_ISGID) {
 	inode->i_gid = dir->i_gid;
===== fs/reiserfs/namei.c 1.24 vs edited =====
--- 1.24/fs/reiserfs/namei.c	Fri Aug  9 19:22:33 2002
+++ edited/fs/reiserfs/namei.c	Thu Sep  5 13:34:43 2002
@@ -8,8 +8,16 @@
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
 
-#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
-#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--;
+#define INC_INODE_NLINK(i) { if (i->i_nlink < REISERFS_LINK_MAX) i->i_nlink++; i->u.reiserfs_i.i_nlink_real++; }
+#define DEC_INODE_NLINK(i) {if ( --i->u.reiserfs_i.i_nlink_real < REISERFS_LINK_MAX) i->i_nlink--;}
+
+// v3.5 files have 16bit nlink_t, v3.6 files have 32bit nlink_t.
+#define CAN_INCREASE_NLINK(i) ( i->u.reiserfs_i.i_nlink_real < ((get_inode_item_key_version (inode) != KEY_FORMAT_3_5)?MAX_UL_INT:MAX_US_INT)) 
+
+// Compatibility stuff with old trick that allowed to have lots of subdirs in
+// one dir. Such dirs had 1 as their nlink count.
+#define INC_DIR_INODE_NLINK(i) { if (i->i_nlink != 1) INC_INODE_NLINK(i);}
+#define DEC_DIR_INODE_NLINK(i) { if (i->i_nlink != 1) DEC_INODE_NLINK(i);}
 
 // directory item contains array of entry headers. This performs
 // binary search through that array
@@ -518,7 +526,7 @@
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				inode, 1/*visible*/);
     if (retval) {
-	inode->i_nlink--;
+	DEC_INODE_NLINK(inode);
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
 	// FIXME: should we put iput here and have stat data deleted
@@ -569,7 +577,7 @@
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				 inode, 1/*visible*/);
     if (retval) {
-	inode->i_nlink--;
+	DEC_INODE_NLINK(inode);
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
 	journal_end(&th, dir->i_sb, jbegin_count) ;
@@ -613,7 +621,7 @@
 				dentry, inode, &retval);
     if (!inode) {
 	pop_journal_writer(windex) ;
-	dir->i_nlink-- ;
+	DEC_DIR_INODE_NLINK(dir);
 	journal_end(&th, dir->i_sb, jbegin_count) ;
 	return retval;
     }
@@ -627,7 +635,7 @@
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				inode, 1/*visible*/);
     if (retval) {
-	inode->i_nlink = 0;
+	inode->u.reiserfs_i.i_nlink_real = inode->i_nlink = 0;
 	DEC_DIR_INODE_NLINK(dir);
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
@@ -711,7 +719,7 @@
     if ( inode->i_nlink != 2 && inode->i_nlink != 1 )
 	printk ("reiserfs_rmdir: empty directory has nlink != 2 (%d)\n", inode->i_nlink);
 
-    inode->i_nlink = 0;
+    inode->u.reiserfs_i.i_nlink_real = inode->i_nlink = 0;
     inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
     reiserfs_update_sd (&th, inode);
 
@@ -780,14 +788,14 @@
     if (!inode->i_nlink) {
 	printk("reiserfs_unlink: deleting nonexistent file (%s:%lu), %d\n",
 	       kdevname(inode->i_dev), inode->i_ino, inode->i_nlink);
-	inode->i_nlink = 1;
+	inode->u.reiserfs_i.i_nlink_real = inode->i_nlink = 1;
     }
 
     retval = reiserfs_cut_from_item (&th, &path, &(de.de_entry_key), dir, NULL, 0);
     if (retval < 0)
 	goto end_unlink;
 
-    inode->i_nlink--;
+    DEC_INODE_NLINK(inode);
     inode->i_ctime = CURRENT_TIME;
     reiserfs_update_sd (&th, inode);
 
@@ -868,7 +876,7 @@
     retval = reiserfs_add_entry (&th, parent_dir, dentry->d_name.name, dentry->d_name.len, 
 				 inode, 1/*visible*/);
     if (retval) {
-	inode->i_nlink--;
+	DEC_INODE_NLINK(inode);
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
 	journal_end(&th, parent_dir->i_sb, jbegin_count) ;
@@ -896,7 +904,7 @@
     if (S_ISDIR(inode->i_mode))
 	return -EPERM;
   
-    if (inode->i_nlink >= REISERFS_LINK_MAX) {
+    if (CAN_INCREASE_NLINK(inode)) {
 	//FIXME: sd_nlink is 32 bit for new files
 	return -EMLINK;
     }
@@ -917,7 +925,7 @@
 	return retval;
     }
 
-    inode->i_nlink++;
+    INC_INODE_NLINK(inode);
     ctime = CURRENT_TIME;
     inode->i_ctime = ctime;
     reiserfs_update_sd (&th, inode);
@@ -1157,9 +1165,9 @@
     if (new_dentry_inode) {
 	// adjust link number of the victim
 	if (S_ISDIR(new_dentry_inode->i_mode)) {
-	    new_dentry_inode->i_nlink  = 0;
+	    new_dentry_inode->u.reiserfs_i.i_nlink_real = new_dentry_inode->i_nlink  = 0;
 	} else {
-	    new_dentry_inode->i_nlink--;
+	    DEC_INODE_NLINK(new_dentry_inode);
 	}
 	ctime = CURRENT_TIME;
 	new_dentry_inode->i_ctime = ctime;
===== include/linux/reiserfs_fs.h 1.22 vs edited =====
--- 1.22/include/linux/reiserfs_fs.h	Tue Aug 20 13:40:53 2002
+++ edited/include/linux/reiserfs_fs.h	Thu Sep  5 13:42:08 2002
@@ -1163,7 +1163,6 @@
 #define INODE_PKEY(inode) ((struct key *)((inode)->u.reiserfs_i.i_key))
 
 #define MAX_UL_INT 0xffffffff
-#define MAX_INT    0x7ffffff
 #define MAX_US_INT 0xffff
 
 // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
@@ -1186,8 +1185,9 @@
 #define MAX_FC_NUM MAX_US_INT
 
 
-/* the purpose is to detect overflow of an unsigned short */
-#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
+/* Find maximal number, that nlink_t can hold. GCC is able to calculate this
+   value at compile time, so do not worry about extra CPU overhead. */
+#define REISERFS_LINK_MAX ((((nlink_t) -1) > 0)?~0:((1u<<(sizeof(nlink_t)*8-1))-1))
 
 
 /* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
===== include/linux/reiserfs_fs_i.h 1.8 vs edited =====
--- 1.8/include/linux/reiserfs_fs_i.h	Fri Aug  9 19:22:34 2002
+++ edited/include/linux/reiserfs_fs_i.h	Thu Sep  5 13:41:01 2002
@@ -53,6 +53,8 @@
     ** flushed */
     unsigned long i_trans_id ;
     unsigned long i_trans_index ;
+    unsigned int i_nlink_real; /* We store real nlink number since field in
+				  struct inode is too short for us */
 };
 
 #endif

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  9:54                   ` Oleg Drokin
@ 2002-09-05 10:50                     ` David S. Miller
  2002-09-05 13:49                     ` Oleg Drokin
                                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 44+ messages in thread
From: David S. Miller @ 2002-09-05 10:50 UTC (permalink / raw)
  To: green
  Cc: szepe, mason, reiser, shaggy, marcelo, linux-kernel,
	reiserfs-dev, linuxjfs

   From: Oleg Drokin <green@namesys.com>
   Date: Thu, 5 Sep 2002 13:54:42 +0400
   
   Ok, since I really like this approach, below is the patch (for 2.4) that
   demonstrates my solution.

I like it.  Now we just need a JFS version, shouldn't bee too
hard :-)

Franks a lot,
David S. Miller
davem@redhat.com

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  9:54                   ` Oleg Drokin
  2002-09-05 10:50                     ` David S. Miller
@ 2002-09-05 13:49                     ` Oleg Drokin
  2002-09-05 13:57                       ` Oleg Drokin
  2002-09-05 14:03                       ` Chris Mason
  2002-09-05 16:09                     ` Dave Kleikamp
  2002-09-05 17:24                     ` Linus Torvalds
  3 siblings, 2 replies; 44+ messages in thread
From: Oleg Drokin @ 2002-09-05 13:49 UTC (permalink / raw)
  To: David S. Miller
  Cc: szepe, mason, reiser, shaggy, marcelo, linux-kernel,
	reiserfs-dev, linuxjfs

Hello!

On Thu, Sep 05, 2002 at 01:54:42PM +0400, Oleg Drokin wrote:

> Ok, since I really like this approach, below is the patch (for 2.4) that
> demonstrates my solution.
> Also it correctly calculates maximal number given type may hold ( does not work
> with unsigned long long, though) with my own way ;)

Version that actually works is now here ;)
Also I have added checks to reiserfs_mkdir and reiserfs_rename to not
overflow the counter. Still reiserfs only version of the patch.
Actually I think this very approach can be used for a lot of other filesystems
including ext2, where max nlink is defined to be 32000 only (I am not sure
how much space is there reserved on disk, though).

Chris, can you please take a look at it?

Bye,
    Oleg
===== fs/reiserfs/inode.c 1.35 vs edited =====
--- 1.35/fs/reiserfs/inode.c	Fri Aug  9 19:22:33 2002
+++ edited/fs/reiserfs/inode.c	Thu Sep  5 13:43:26 2002
@@ -891,7 +891,8 @@
 	set_inode_item_key_version (inode, KEY_FORMAT_3_5);
         set_inode_sd_version (inode, STAT_DATA_V1);
 	inode->i_mode  = sd_v1_mode(sd);
-	inode->i_nlink = sd_v1_nlink(sd);
+	inode->i_nlink = ( sd_v1_nlink(sd) > REISERFS_LINK_MAX ) ? REISERFS_LINK_MAX:sd_v1_nlink(sd);
+	inode->u.reiserfs_i.i_nlink_real = sd_v1_nlink(sd);
 	inode->i_uid   = sd_v1_uid(sd);
 	inode->i_gid   = sd_v1_gid(sd);
 	inode->i_size  = sd_v1_size(sd);
@@ -923,7 +924,8 @@
 	struct stat_data * sd = (struct stat_data *)B_I_PITEM (bh, ih);
 
 	inode->i_mode   = sd_v2_mode(sd);
-	inode->i_nlink  = sd_v2_nlink(sd);
+	inode->i_nlink  = (sd_v2_nlink(sd)>REISERFS_LINK_MAX)?REISERFS_LINK_MAX:sd_v2_nlink(sd);
+	inode->u.reiserfs_i.i_nlink_real = sd_v2_nlink(sd);
 	inode->i_uid    = sd_v2_uid(sd);
 	inode->i_size   = sd_v2_size(sd);
 	inode->i_gid    = sd_v2_gid(sd);
@@ -975,7 +977,7 @@
     __u16 flags;
 
     set_sd_v2_mode(sd_v2, inode->i_mode );
-    set_sd_v2_nlink(sd_v2, inode->i_nlink );
+    set_sd_v2_nlink(sd_v2, inode->u.reiserfs_i.i_nlink_real );
     set_sd_v2_uid(sd_v2, inode->i_uid );
     set_sd_v2_size(sd_v2, inode->i_size );
     set_sd_v2_gid(sd_v2, inode->i_gid );
@@ -1001,7 +1003,7 @@
     set_sd_v1_mode(sd_v1, inode->i_mode );
     set_sd_v1_uid(sd_v1, inode->i_uid );
     set_sd_v1_gid(sd_v1, inode->i_gid );
-    set_sd_v1_nlink(sd_v1, inode->i_nlink );
+    set_sd_v1_nlink(sd_v1, inode->u.reiserfs_i.i_nlink_real );
     set_sd_v1_size(sd_v1, inode->i_size );
     set_sd_v1_atime(sd_v1, inode->i_atime );
     set_sd_v1_ctime(sd_v1, inode->i_ctime );
@@ -1537,7 +1539,7 @@
 
     /* fill stat data */
     inode->i_mode = mode;
-    inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
+    inode->u.reiserfs_i.i_nlink_real = inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
     inode->i_uid = current->fsuid;
     if (dir->i_mode & S_ISGID) {
 	inode->i_gid = dir->i_gid;
===== fs/reiserfs/namei.c 1.24 vs edited =====
--- 1.24/fs/reiserfs/namei.c	Fri Aug  9 19:22:33 2002
+++ edited/fs/reiserfs/namei.c	Thu Sep  5 16:33:04 2002
@@ -8,8 +8,16 @@
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
 
-#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
-#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--;
+#define INC_INODE_NLINK(i) { if (i->i_nlink < REISERFS_LINK_MAX) i->i_nlink++; i->u.reiserfs_i.i_nlink_real++; }
+#define DEC_INODE_NLINK(i) {if ( --i->u.reiserfs_i.i_nlink_real < REISERFS_LINK_MAX) i->i_nlink--;}
+
+// v3.5 files have 16bit nlink_t, v3.6 files have 32bit nlink_t.
+#define CAN_INCREASE_NLINK(i) ( i->u.reiserfs_i.i_nlink_real < ((get_inode_sd_version (i) != KEY_FORMAT_3_5)?MAX_UL_INT:MAX_US_INT)) 
+
+// Compatibility stuff with old trick that allowed to have lots of subdirs in
+// one dir. Such dirs had 1 as their nlink count.
+#define INC_DIR_INODE_NLINK(i) { if (i->i_nlink != 1) INC_INODE_NLINK(i);}
+#define DEC_DIR_INODE_NLINK(i) { if (i->i_nlink != 1) DEC_INODE_NLINK(i);}
 
 // directory item contains array of entry headers. This performs
 // binary search through that array
@@ -518,7 +526,7 @@
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				inode, 1/*visible*/);
     if (retval) {
-	inode->i_nlink--;
+	DEC_INODE_NLINK(inode);
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
 	// FIXME: should we put iput here and have stat data deleted
@@ -569,7 +577,7 @@
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				 inode, 1/*visible*/);
     if (retval) {
-	inode->i_nlink--;
+	DEC_INODE_NLINK(inode);
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
 	journal_end(&th, dir->i_sb, jbegin_count) ;
@@ -592,6 +600,9 @@
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
+    if ( !CAN_INCREASE_NLINK(dir) )
+	return -EMLINK;
+
     if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
@@ -613,7 +624,7 @@
 				dentry, inode, &retval);
     if (!inode) {
 	pop_journal_writer(windex) ;
-	dir->i_nlink-- ;
+	DEC_DIR_INODE_NLINK(dir);
 	journal_end(&th, dir->i_sb, jbegin_count) ;
 	return retval;
     }
@@ -627,7 +638,7 @@
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				inode, 1/*visible*/);
     if (retval) {
-	inode->i_nlink = 0;
+	inode->u.reiserfs_i.i_nlink_real = inode->i_nlink = 0;
 	DEC_DIR_INODE_NLINK(dir);
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
@@ -711,7 +722,7 @@
     if ( inode->i_nlink != 2 && inode->i_nlink != 1 )
 	printk ("reiserfs_rmdir: empty directory has nlink != 2 (%d)\n", inode->i_nlink);
 
-    inode->i_nlink = 0;
+    inode->u.reiserfs_i.i_nlink_real = inode->i_nlink = 0;
     inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
     reiserfs_update_sd (&th, inode);
 
@@ -780,14 +791,14 @@
     if (!inode->i_nlink) {
 	printk("reiserfs_unlink: deleting nonexistent file (%s:%lu), %d\n",
 	       kdevname(inode->i_dev), inode->i_ino, inode->i_nlink);
-	inode->i_nlink = 1;
+	inode->u.reiserfs_i.i_nlink_real = inode->i_nlink = 1;
     }
 
     retval = reiserfs_cut_from_item (&th, &path, &(de.de_entry_key), dir, NULL, 0);
     if (retval < 0)
 	goto end_unlink;
 
-    inode->i_nlink--;
+    DEC_INODE_NLINK(inode);
     inode->i_ctime = CURRENT_TIME;
     reiserfs_update_sd (&th, inode);
 
@@ -868,7 +879,7 @@
     retval = reiserfs_add_entry (&th, parent_dir, dentry->d_name.name, dentry->d_name.len, 
 				 inode, 1/*visible*/);
     if (retval) {
-	inode->i_nlink--;
+	DEC_INODE_NLINK(inode);
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
 	journal_end(&th, parent_dir->i_sb, jbegin_count) ;
@@ -896,8 +907,7 @@
     if (S_ISDIR(inode->i_mode))
 	return -EPERM;
   
-    if (inode->i_nlink >= REISERFS_LINK_MAX) {
-	//FIXME: sd_nlink is 32 bit for new files
+    if (!CAN_INCREASE_NLINK(inode)) {
 	return -EMLINK;
     }
 
@@ -917,7 +927,7 @@
 	return retval;
     }
 
-    inode->i_nlink++;
+    INC_INODE_NLINK(inode);
     ctime = CURRENT_TIME;
     inode->i_ctime = ctime;
     reiserfs_update_sd (&th, inode);
@@ -1021,6 +1031,8 @@
 	// and that its new parent directory has not too many links
 	// already
 
+	if ( !CAN_INCREASE_NLINK(new_dir) )
+	    return -EMLINK;
 	if (new_dentry_inode) {
 	    if (!reiserfs_empty_dir(new_dentry_inode)) {
 		return -ENOTEMPTY;
@@ -1157,9 +1169,9 @@
     if (new_dentry_inode) {
 	// adjust link number of the victim
 	if (S_ISDIR(new_dentry_inode->i_mode)) {
-	    new_dentry_inode->i_nlink  = 0;
+	    new_dentry_inode->u.reiserfs_i.i_nlink_real = new_dentry_inode->i_nlink  = 0;
 	} else {
-	    new_dentry_inode->i_nlink--;
+	    DEC_INODE_NLINK(new_dentry_inode);
 	}
 	ctime = CURRENT_TIME;
 	new_dentry_inode->i_ctime = ctime;
===== include/linux/reiserfs_fs.h 1.22 vs edited =====
--- 1.22/include/linux/reiserfs_fs.h	Tue Aug 20 13:40:53 2002
+++ edited/include/linux/reiserfs_fs.h	Thu Sep  5 13:42:08 2002
@@ -1163,7 +1163,6 @@
 #define INODE_PKEY(inode) ((struct key *)((inode)->u.reiserfs_i.i_key))
 
 #define MAX_UL_INT 0xffffffff
-#define MAX_INT    0x7ffffff
 #define MAX_US_INT 0xffff
 
 // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
@@ -1186,8 +1185,9 @@
 #define MAX_FC_NUM MAX_US_INT
 
 
-/* the purpose is to detect overflow of an unsigned short */
-#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
+/* Find maximal number, that nlink_t can hold. GCC is able to calculate this
+   value at compile time, so do not worry about extra CPU overhead. */
+#define REISERFS_LINK_MAX ((((nlink_t) -1) > 0)?~0:((1u<<(sizeof(nlink_t)*8-1))-1))
 
 
 /* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
===== include/linux/reiserfs_fs_i.h 1.8 vs edited =====
--- 1.8/include/linux/reiserfs_fs_i.h	Fri Aug  9 19:22:34 2002
+++ edited/include/linux/reiserfs_fs_i.h	Thu Sep  5 13:41:01 2002
@@ -53,6 +53,8 @@
     ** flushed */
     unsigned long i_trans_id ;
     unsigned long i_trans_index ;
+    unsigned int i_nlink_real; /* We store real nlink number since field in
+				  struct inode is too short for us */
 };
 
 #endif

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05 13:49                     ` Oleg Drokin
@ 2002-09-05 13:57                       ` Oleg Drokin
  2002-09-05 14:03                       ` Chris Mason
  1 sibling, 0 replies; 44+ messages in thread
From: Oleg Drokin @ 2002-09-05 13:57 UTC (permalink / raw)
  To: mason; +Cc: szepe, linux-kernel, reiserfs-dev

Hello!

On Thu, Sep 05, 2002 at 05:49:02PM +0400, Oleg Drokin wrote:

> > Ok, since I really like this approach, below is the patch (for 2.4) that
> > demonstrates my solution.
> > Also it correctly calculates maximal number given type may hold ( does not work
> > with unsigned long long, though) with my own way ;)
> Version that actually works is now here ;)

Heh, diffed against wrong tree :(
Corrected diff is here.

Also I trimmed CC list since I afraid Marcelo, DaveM adn jfs people are not very
interested in this reiserfs only patch.

Bye,
    Oleg

===== fs/reiserfs/inode.c 1.35 vs edited =====
--- 1.35/fs/reiserfs/inode.c	Fri Aug  9 19:22:33 2002
+++ edited/fs/reiserfs/inode.c	Thu Sep  5 13:43:26 2002
@@ -891,7 +891,8 @@
 	set_inode_item_key_version (inode, KEY_FORMAT_3_5);
         set_inode_sd_version (inode, STAT_DATA_V1);
 	inode->i_mode  = sd_v1_mode(sd);
-	inode->i_nlink = sd_v1_nlink(sd);
+	inode->i_nlink = ( sd_v1_nlink(sd) > REISERFS_LINK_MAX ) ? REISERFS_LINK_MAX:sd_v1_nlink(sd);
+	inode->u.reiserfs_i.i_nlink_real = sd_v1_nlink(sd);
 	inode->i_uid   = sd_v1_uid(sd);
 	inode->i_gid   = sd_v1_gid(sd);
 	inode->i_size  = sd_v1_size(sd);
@@ -923,7 +924,8 @@
 	struct stat_data * sd = (struct stat_data *)B_I_PITEM (bh, ih);
 
 	inode->i_mode   = sd_v2_mode(sd);
-	inode->i_nlink  = sd_v2_nlink(sd);
+	inode->i_nlink  = (sd_v2_nlink(sd)>REISERFS_LINK_MAX)?REISERFS_LINK_MAX:sd_v2_nlink(sd);
+	inode->u.reiserfs_i.i_nlink_real = sd_v2_nlink(sd);
 	inode->i_uid    = sd_v2_uid(sd);
 	inode->i_size   = sd_v2_size(sd);
 	inode->i_gid    = sd_v2_gid(sd);
@@ -975,7 +977,7 @@
     __u16 flags;
 
     set_sd_v2_mode(sd_v2, inode->i_mode );
-    set_sd_v2_nlink(sd_v2, inode->i_nlink );
+    set_sd_v2_nlink(sd_v2, inode->u.reiserfs_i.i_nlink_real );
     set_sd_v2_uid(sd_v2, inode->i_uid );
     set_sd_v2_size(sd_v2, inode->i_size );
     set_sd_v2_gid(sd_v2, inode->i_gid );
@@ -1001,7 +1003,7 @@
     set_sd_v1_mode(sd_v1, inode->i_mode );
     set_sd_v1_uid(sd_v1, inode->i_uid );
     set_sd_v1_gid(sd_v1, inode->i_gid );
-    set_sd_v1_nlink(sd_v1, inode->i_nlink );
+    set_sd_v1_nlink(sd_v1, inode->u.reiserfs_i.i_nlink_real );
     set_sd_v1_size(sd_v1, inode->i_size );
     set_sd_v1_atime(sd_v1, inode->i_atime );
     set_sd_v1_ctime(sd_v1, inode->i_ctime );
@@ -1537,7 +1539,7 @@
 
     /* fill stat data */
     inode->i_mode = mode;
-    inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
+    inode->u.reiserfs_i.i_nlink_real = inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
     inode->i_uid = current->fsuid;
     if (dir->i_mode & S_ISGID) {
 	inode->i_gid = dir->i_gid;
===== fs/reiserfs/namei.c 1.24 vs edited =====
--- 1.24/fs/reiserfs/namei.c	Fri Aug  9 19:22:33 2002
+++ edited/fs/reiserfs/namei.c	Thu Sep  5 16:33:04 2002
@@ -8,8 +8,16 @@
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
 
-#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
-#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--;
+#define INC_INODE_NLINK(i) { if (i->i_nlink < REISERFS_LINK_MAX) i->i_nlink++; i->u.reiserfs_i.i_nlink_real++; }
+#define DEC_INODE_NLINK(i) {if ( --i->u.reiserfs_i.i_nlink_real < REISERFS_LINK_MAX) i->i_nlink--;}
+
+// v3.5 files have 16bit nlink_t, v3.6 files have 32bit nlink_t.
+#define CAN_INCREASE_NLINK(i) ( i->u.reiserfs_i.i_nlink_real < ((get_inode_sd_version (i) != KEY_FORMAT_3_5)?MAX_UL_INT:MAX_US_INT)) 
+
+// Compatibility stuff with old trick that allowed to have lots of subdirs in
+// one dir. Such dirs had 1 as their nlink count.
+#define INC_DIR_INODE_NLINK(i) { if (i->i_nlink != 1) INC_INODE_NLINK(i);}
+#define DEC_DIR_INODE_NLINK(i) { if (i->i_nlink != 1) DEC_INODE_NLINK(i);}
 
 // directory item contains array of entry headers. This performs
 // binary search through that array
@@ -518,7 +526,7 @@
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				inode, 1/*visible*/);
     if (retval) {
-	inode->i_nlink--;
+	DEC_INODE_NLINK(inode);
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
 	// FIXME: should we put iput here and have stat data deleted
@@ -569,7 +577,7 @@
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				 inode, 1/*visible*/);
     if (retval) {
-	inode->i_nlink--;
+	DEC_INODE_NLINK(inode);
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
 	journal_end(&th, dir->i_sb, jbegin_count) ;
@@ -592,6 +600,9 @@
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
+    if ( !CAN_INCREASE_NLINK(dir) )
+	return -EMLINK;
+
     if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
@@ -613,7 +624,7 @@
 				dentry, inode, &retval);
     if (!inode) {
 	pop_journal_writer(windex) ;
-	dir->i_nlink-- ;
+	DEC_DIR_INODE_NLINK(dir);
 	journal_end(&th, dir->i_sb, jbegin_count) ;
 	return retval;
     }
@@ -627,7 +638,7 @@
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				inode, 1/*visible*/);
     if (retval) {
-	inode->i_nlink = 0;
+	inode->u.reiserfs_i.i_nlink_real = inode->i_nlink = 0;
 	DEC_DIR_INODE_NLINK(dir);
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
@@ -711,7 +722,7 @@
     if ( inode->i_nlink != 2 && inode->i_nlink != 1 )
 	printk ("reiserfs_rmdir: empty directory has nlink != 2 (%d)\n", inode->i_nlink);
 
-    inode->i_nlink = 0;
+    inode->u.reiserfs_i.i_nlink_real = inode->i_nlink = 0;
     inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
     reiserfs_update_sd (&th, inode);
 
@@ -780,14 +791,14 @@
     if (!inode->i_nlink) {
 	printk("reiserfs_unlink: deleting nonexistent file (%s:%lu), %d\n",
 	       kdevname(inode->i_dev), inode->i_ino, inode->i_nlink);
-	inode->i_nlink = 1;
+	inode->u.reiserfs_i.i_nlink_real = inode->i_nlink = 1;
     }
 
     retval = reiserfs_cut_from_item (&th, &path, &(de.de_entry_key), dir, NULL, 0);
     if (retval < 0)
 	goto end_unlink;
 
-    inode->i_nlink--;
+    DEC_INODE_NLINK(inode);
     inode->i_ctime = CURRENT_TIME;
     reiserfs_update_sd (&th, inode);
 
@@ -868,7 +879,7 @@
     retval = reiserfs_add_entry (&th, parent_dir, dentry->d_name.name, dentry->d_name.len, 
 				 inode, 1/*visible*/);
     if (retval) {
-	inode->i_nlink--;
+	DEC_INODE_NLINK(inode);
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
 	journal_end(&th, parent_dir->i_sb, jbegin_count) ;
@@ -896,8 +907,7 @@
     if (S_ISDIR(inode->i_mode))
 	return -EPERM;
   
-    if (inode->i_nlink >= REISERFS_LINK_MAX) {
-	//FIXME: sd_nlink is 32 bit for new files
+    if (!CAN_INCREASE_NLINK(inode)) {
 	return -EMLINK;
     }
 
@@ -917,7 +927,7 @@
 	return retval;
     }
 
-    inode->i_nlink++;
+    INC_INODE_NLINK(inode);
     ctime = CURRENT_TIME;
     inode->i_ctime = ctime;
     reiserfs_update_sd (&th, inode);
@@ -1021,6 +1031,8 @@
 	// and that its new parent directory has not too many links
 	// already
 
+	if ( !CAN_INCREASE_NLINK(new_dir) )
+	    return -EMLINK;
 	if (new_dentry_inode) {
 	    if (!reiserfs_empty_dir(new_dentry_inode)) {
 		return -ENOTEMPTY;
@@ -1157,9 +1169,9 @@
     if (new_dentry_inode) {
 	// adjust link number of the victim
 	if (S_ISDIR(new_dentry_inode->i_mode)) {
-	    new_dentry_inode->i_nlink  = 0;
+	    new_dentry_inode->u.reiserfs_i.i_nlink_real = new_dentry_inode->i_nlink  = 0;
 	} else {
-	    new_dentry_inode->i_nlink--;
+	    DEC_INODE_NLINK(new_dentry_inode);
 	}
 	ctime = CURRENT_TIME;
 	new_dentry_inode->i_ctime = ctime;
===== include/linux/reiserfs_fs.h 1.22 vs edited =====
--- 1.22/include/linux/reiserfs_fs.h	Tue Aug 20 13:40:53 2002
+++ edited/include/linux/reiserfs_fs.h	Thu Sep  5 17:52:50 2002
@@ -1163,7 +1163,6 @@
 #define INODE_PKEY(inode) ((struct key *)((inode)->u.reiserfs_i.i_key))
 
 #define MAX_UL_INT 0xffffffff
-#define MAX_INT    0x7ffffff
 #define MAX_US_INT 0xffff
 
 // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
@@ -1186,8 +1185,9 @@
 #define MAX_FC_NUM MAX_US_INT
 
 
-/* the purpose is to detect overflow of an unsigned short */
-#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
+/* Find maximal number, that nlink_t can hold. GCC is able to calculate this
+   value at compile time, so do not worry about extra CPU overhead. */
+#define REISERFS_LINK_MAX (nlink_t)((((nlink_t) -1) > 0)?~0:((1u<<(sizeof(nlink_t)*8-1))-1))
 
 
 /* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
===== include/linux/reiserfs_fs_i.h 1.8 vs edited =====
--- 1.8/include/linux/reiserfs_fs_i.h	Fri Aug  9 19:22:34 2002
+++ edited/include/linux/reiserfs_fs_i.h	Thu Sep  5 13:41:01 2002
@@ -53,6 +53,8 @@
     ** flushed */
     unsigned long i_trans_id ;
     unsigned long i_trans_index ;
+    unsigned int i_nlink_real; /* We store real nlink number since field in
+				  struct inode is too short for us */
 };
 
 #endif

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05 13:49                     ` Oleg Drokin
  2002-09-05 13:57                       ` Oleg Drokin
@ 2002-09-05 14:03                       ` Chris Mason
  2002-09-05 14:17                         ` Oleg Drokin
  1 sibling, 1 reply; 44+ messages in thread
From: Chris Mason @ 2002-09-05 14:03 UTC (permalink / raw)
  To: Oleg Drokin
  Cc: David S. Miller, szepe, reiser, shaggy, marcelo, linux-kernel,
	reiserfs-dev, linuxjfs

On Thu, 2002-09-05 at 09:49, Oleg Drokin wrote:
> Hello!
> 
> On Thu, Sep 05, 2002 at 01:54:42PM +0400, Oleg Drokin wrote:
> 
> > Ok, since I really like this approach, below is the patch (for 2.4) that
> > demonstrates my solution.
> > Also it correctly calculates maximal number given type may hold ( does not work
> > with unsigned long long, though) with my own way ;)
> 
> Version that actually works is now here ;)
> Also I have added checks to reiserfs_mkdir and reiserfs_rename to not
> overflow the counter. Still reiserfs only version of the patch.
> Actually I think this very approach can be used for a lot of other filesystems
> including ext2, where max nlink is defined to be 32000 only (I am not sure
> how much space is there reserved on disk, though).
> 
> Chris, can you please take a look at it?

read the -noleaf description on the find man page to see why we need to
set the directory link count to 1 when we are lying to userspace about
the actual link count on directories. 

find isn't the only program that makes this assumption (it's just the
only one I can think of ;-)

Other than that the patch (the second one diffed against the correct
tree) looks sane.

-chris



^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05 14:03                       ` Chris Mason
@ 2002-09-05 14:17                         ` Oleg Drokin
  2002-09-05 16:45                           ` Chris Mason
  0 siblings, 1 reply; 44+ messages in thread
From: Oleg Drokin @ 2002-09-05 14:17 UTC (permalink / raw)
  To: Chris Mason; +Cc: szepe, linux-kernel, reiserfs-dev

Hello!

On Thu, Sep 05, 2002 at 10:03:44AM -0400, Chris Mason wrote:

> read the -noleaf description on the find man page to see why we need to
> set the directory link count to 1 when we are lying to userspace about
> the actual link count on directories. 

There is nothing about nlink == 1 means assume -noleaf, so it should not work
with old way too, right? Have anybody verified? ;)

Actually patch might be easily modified to represent i_nlink == 1 for
large directories, but still maintain correct on-disk nlink count.
(and show maximal possible nlink count for regular files. Hm,
I wonder if tar and stuff would break if met with file that have
67000 hardlinks ;) ).

> find isn't the only program that makes this assumption (it's just the
> only one I can think of ;-)

All of these programs are broken if there is no way to turn this feature off
then. ;)

> Other than that the patch (the second one diffed against the correct
> tree) looks sane.

Good.

Bye,
    Oleg

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  9:54                   ` Oleg Drokin
  2002-09-05 10:50                     ` David S. Miller
  2002-09-05 13:49                     ` Oleg Drokin
@ 2002-09-05 16:09                     ` Dave Kleikamp
  2002-09-05 16:13                       ` Oleg Drokin
  2002-09-05 17:24                     ` Linus Torvalds
  3 siblings, 1 reply; 44+ messages in thread
From: Dave Kleikamp @ 2002-09-05 16:09 UTC (permalink / raw)
  To: Oleg Drokin, David S. Miller
  Cc: szepe, mason, reiser, marcelo, linux-kernel, reiserfs-dev, linuxjfs

On Thursday 05 September 2002 04:54, Oleg Drokin wrote:

> +/* Find maximal number, that nlink_t can hold. GCC is able to
> calculate this +   value at compile time, so do not worry about extra
> CPU overhead. */ +#define REISERFS_LINK_MAX ((((nlink_t) -1) >> 0)?~0:((1u<<(sizeof(nlink_t)*8-1))-1))

Shouldn't this be:

#define REISERFS_LINK_MAX ((((nlink_t) -1) >> 0)?(nlink_t) ~0:((1u<<(sizeof(nlink_t)*8-1))-1))

if nlink_t is u16, ~0 would still be 0xffffffff (assuming 32 bits)
-- 
David Kleikamp
IBM Linux Technology Center


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05 16:09                     ` Dave Kleikamp
@ 2002-09-05 16:13                       ` Oleg Drokin
  2002-09-05 17:58                         ` Dave Kleikamp
  0 siblings, 1 reply; 44+ messages in thread
From: Oleg Drokin @ 2002-09-05 16:13 UTC (permalink / raw)
  To: Dave Kleikamp
  Cc: David S. Miller, szepe, mason, linux-kernel, reiserfs-dev, linuxjfs

Hello!

   I am sorry but yor mailer corrupted the message or something like that
   so I cannot understand what do you mean.

   Ah, I see now. My latest version of a patch does a cast 
   this way (yes, I noticed that problem).
#define REISERFS_LINK_MAX (nlink_t)((((nlink_t) -1) > 0)?~0:((1u<<(sizeof(nlink_t)*8-1))-1))

Bye,
    Oleg
On Thu, Sep 05, 2002 at 11:09:12AM -0500, Dave Kleikamp wrote:
> On Thursday 05 September 2002 04:54, Oleg Drokin wrote:
> 
> > +/* Find maximal number, that nlink_t can hold. GCC is able to
> > calculate this +   value at compile time, so do not worry about extra
> > CPU overhead. */ +#define REISERFS_LINK_MAX ((((nlink_t) -1) >> 0)?~0:((1u<<(sizeof(nlink_t)*8-1))-1))
> 
> Shouldn't this be:
> 
> #define REISERFS_LINK_MAX ((((nlink_t) -1) >> 0)?(nlink_t) ~0:((1u<<(sizeof(nlink_t)*8-1))-1))
> 
> if nlink_t is u16, ~0 would still be 0xffffffff (assuming 32 bits)
> -- 
> David Kleikamp
> IBM Linux Technology Center
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05 14:17                         ` Oleg Drokin
@ 2002-09-05 16:45                           ` Chris Mason
  2002-09-05 17:25                             ` Oleg Drokin
  0 siblings, 1 reply; 44+ messages in thread
From: Chris Mason @ 2002-09-05 16:45 UTC (permalink / raw)
  To: Oleg Drokin; +Cc: szepe, linux-kernel, reiserfs-dev

On Thu, 2002-09-05 at 10:17, Oleg Drokin wrote:
> Hello!
> 
> On Thu, Sep 05, 2002 at 10:03:44AM -0400, Chris Mason wrote:
> 
> > read the -noleaf description on the find man page to see why we need to
> > set the directory link count to 1 when we are lying to userspace about
> > the actual link count on directories. 
> 
> There is nothing about nlink == 1 means assume -noleaf, so it should not work
> with old way too, right? Have anybody verified? ;)

I remember that happening during the initial discussions for the link
patch.  1 was chosen as the best way to do it, since it was a flag to
various programs that the unix directory link convention was not being
followed.

> 
> Actually patch might be easily modified to represent i_nlink == 1 for
> large directories, but still maintain correct on-disk nlink count.

Right.

> (and show maximal possible nlink count for regular files. Hm,
> I wonder if tar and stuff would break if met with file that have
> 67000 hardlinks ;) ).

Certainly seems like it would on sparc at least ;-)

-chris



^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05  9:54                   ` Oleg Drokin
                                       ` (2 preceding siblings ...)
  2002-09-05 16:09                     ` Dave Kleikamp
@ 2002-09-05 17:24                     ` Linus Torvalds
  3 siblings, 0 replies; 44+ messages in thread
From: Linus Torvalds @ 2002-09-05 17:24 UTC (permalink / raw)
  To: linux-kernel

In article <20020905135442.A19682@namesys.com>,
Oleg Drokin  <green@namesys.com> wrote:
>
>Ok, since I really like this approach, below is the patch (for 2.4) that
>demonstrates my solution.

No, please just change i_nlink in <linux/fs.h> to be an "unsigned int"
instead.

The kernel internal VFS layers should not care about the fact that
nlink_t is of a limited type - the same way we internally can use larger
inode numbers than the old stat interfaces export. I'm already using a
32-bit i_nlink in my tree on 2.5.x for other reasons (/proc overflow
with hundreds of thousands of threads), we should internally be able to
handle them even if the external interfaces have problems.

(Besides, almost nobody in user space cares about i_nlink.  And as long
as the kernel internally doesn't care, if you actually have people with
nlink values in the >16-bit range, they can at least work around the few
problems they might have by using things like "-noleaf" for their find
commands. 

		Linus

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05 16:45                           ` Chris Mason
@ 2002-09-05 17:25                             ` Oleg Drokin
  2002-09-05 21:18                               ` jw schultz
  0 siblings, 1 reply; 44+ messages in thread
From: Oleg Drokin @ 2002-09-05 17:25 UTC (permalink / raw)
  To: Chris Mason; +Cc: szepe, linux-kernel, reiserfs-dev

Hello!

On Thu, Sep 05, 2002 at 12:45:34PM -0400, Chris Mason wrote:
> > > read the -noleaf description on the find man page to see why we need to
> > > set the directory link count to 1 when we are lying to userspace about
> > > the actual link count on directories. 
> > 
> > There is nothing about nlink == 1 means assume -noleaf, so it should not work
> > with old way too, right? Have anybody verified? ;)
> I remember that happening during the initial discussions for the link
> patch.  1 was chosen as the best way to do it, since it was a flag to
> various programs that the unix directory link convention was not being
> followed.
> > Actually patch might be easily modified to represent i_nlink == 1 for
> > large directories, but still maintain correct on-disk nlink count.
> Right.

Ok, I will come up with revised patch tomorrow and do 2.5 port (and
advise Vitaly about reiserfsck part)

Bye,
    Oleg

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05 16:13                       ` Oleg Drokin
@ 2002-09-05 17:58                         ` Dave Kleikamp
  2002-09-06 13:54                           ` Oleg Drokin
  0 siblings, 1 reply; 44+ messages in thread
From: Dave Kleikamp @ 2002-09-05 17:58 UTC (permalink / raw)
  To: Oleg Drokin
  Cc: David S. Miller, szepe, mason, linux-kernel, reiserfs-dev, linuxjfs

Here's the JFS patch.  When I first saw this thread I didn't expect that
the result would be increasing the max. number of links.  :^)

Note that I made JFS_LINK_MAX the maximum supported by JFS,
and VFS_LINK_MAX as the number limited by the size of nlink_t.
VFS_LINK_MAX could be moved to fs.h if other file systems are
to use it in the same way.

I borrowed reiserfs's *_INODE_NLINK macros, but made them inline functions.

(I don't usually send patches from kmail.  I hope it doesn't screw up the formatting.)

===== fs/jfs/jfs_filsys.h 1.1 vs edited =====
--- 1.1/fs/jfs/jfs_filsys.h	Fri May 31 08:19:24 2002
+++ edited/fs/jfs/jfs_filsys.h	Thu Sep  5 11:01:55 2002
@@ -125,7 +125,13 @@
 #define MAXBLOCKSIZE		4096
 #define	MAXFILESIZE		((s64)1 << 52)
 
-#define JFS_LINK_MAX		65535	/* nlink_t is unsigned short */
+/*
+ * The max link count in struct inode is limited to the size of nlink_t.
+ * The JFS inode uses an unsigned 32-bit int, so we can really go higher
+ */
+#define JFS_LINK_MAX	0xffffffff	/* real limit */
+#define VFS_LINK_MAX	((((nlink_t) -1) > 0) ? (nlink_t) ~0 : \
+			 ((1u << (sizeof (nlink_t) * 8 - 1)) -1))
 
 /* Minimum number of bytes supported for a JFS partition */
 #define MINJFS			(0x1000000)
===== fs/jfs/jfs_imap.c 1.6 vs edited =====
--- 1.6/fs/jfs/jfs_imap.c	Wed Sep  4 11:11:52 2002
+++ edited/fs/jfs/jfs_imap.c	Thu Sep  5 10:52:53 2002
@@ -3035,7 +3035,15 @@
 	jfs_ip->mode2 = le32_to_cpu(dip->di_mode);
 
 	ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff;
-	ip->i_nlink = le32_to_cpu(dip->di_nlink);
+
+	jfs_ip->nlink_real = le32_to_cpu(dip->di_nlink);
+	if (jfs_ip->nlink_real <= VFS_LINK_MAX)
+		ip->i_nlink = jfs_ip->nlink_real;
+	else if (S_ISDIR(ip->i_mode))
+		ip->i_nlink = 1;
+	else
+		ip->i_nlink = VFS_LINK_MAX;
+
 	ip->i_uid = le32_to_cpu(dip->di_uid);
 	ip->i_gid = le32_to_cpu(dip->di_gid);
 	ip->i_size = le64_to_cpu(dip->di_size);
@@ -3089,7 +3097,7 @@
 	dip->di_gen = cpu_to_le32(ip->i_generation);
 	dip->di_size = cpu_to_le64(ip->i_size);
 	dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks));
-	dip->di_nlink = cpu_to_le32(ip->i_nlink);
+	dip->di_nlink = cpu_to_le32(jfs_ip->nlink_real);
 	dip->di_uid = cpu_to_le32(ip->i_uid);
 	dip->di_gid = cpu_to_le32(ip->i_gid);
 	/*
===== fs/jfs/jfs_incore.h 1.5 vs edited =====
--- 1.5/fs/jfs/jfs_incore.h	Mon Sep  2 05:48:42 2002
+++ edited/fs/jfs/jfs_incore.h	Thu Sep  5 10:12:09 2002
@@ -38,6 +38,7 @@
 	struct inode *inode;	/* pointer back to fs-independent inode */
 	int	fileset;	/* fileset number (always 16)*/
 	uint	mode2;		/* jfs-specific mode		*/
+	uint	nlink_real;	/* i_nlink is too short		*/
 	pxd_t   ixpxd;		/* inode extent descriptor	*/
 	dxd_t	acl;		/* dxd describing acl	*/
 	dxd_t	ea;		/* dxd describing ea	*/
===== fs/jfs/namei.c 1.9 vs edited =====
--- 1.9/fs/jfs/namei.c	Mon Aug 26 14:07:42 2002
+++ edited/fs/jfs/namei.c	Thu Sep  5 11:11:57 2002
@@ -44,6 +44,34 @@
 s64 commitZeroLink(tid_t, struct inode *);
 
 /*
+ * i_nlink accounting
+ * Keep track of real link count, while keeping i_nlink, which may be too
+ * small to hold the real value, sane.
+ */
+static inline void INC_INODE_NLINK(struct inode *inode)
+{
+	if (++JFS_IP(inode)->nlink_real <= VFS_LINK_MAX)
+		inode->i_nlink = JFS_IP(inode)->nlink_real;
+}
+static inline void DEC_INODE_NLINK(struct inode *inode)
+{
+	if (--JFS_IP(inode)->nlink_real <= VFS_LINK_MAX)
+		inode->i_nlink = JFS_IP(inode)->nlink_real;
+}
+/*
+ * Due to an optimazation in the find command (and other cases?),
+ * set i_nlink to one if i_nlink can't be correct.
+ */
+static inline void INC_DIR_INODE_NLINK(struct inode *inode)
+{
+	if (++JFS_IP(inode)->nlink_real <= VFS_LINK_MAX)
+		inode->i_nlink = JFS_IP(inode)->nlink_real;
+	else
+		inode->i_nlink = 1;
+}
+#define DEC_DIR_INODE_NLINK DEC_INODE_NLINK
+
+/*
  * NAME:	jfs_create(dip, dentry, mode)
  *
  * FUNCTION:	create a regular file in the parent directory <dip>
@@ -142,7 +170,7 @@
 	up(&JFS_IP(dip)->commit_sem);
 	up(&JFS_IP(ip)->commit_sem);
 	if (rc) {
-		ip->i_nlink = 0;
+		ip->i_nlink = JFS_IP(ip)->nlink_real = 0;
 		iput(ip);
 	}
 
@@ -185,7 +213,7 @@
 	jFYI(1, ("jfs_mkdir: dip:0x%p name:%s\n", dip, dentry->d_name.name));
 
 	/* link count overflow on parent directory ? */
-	if (dip->i_nlink == JFS_LINK_MAX) {
+	if (JFS_IP(dip)->nlink_real == JFS_LINK_MAX) {
 		rc = EMLINK;
 		goto out1;
 	}
@@ -245,7 +273,7 @@
 		goto out3;
 	}
 
-	ip->i_nlink = 2;	/* for '.' */
+	ip->i_nlink = JFS_IP(ip)->nlink_real = 2;	/* for '.' */
 	ip->i_op = &jfs_dir_inode_operations;
 	ip->i_fop = &jfs_dir_operations;
 	ip->i_mapping->a_ops = &jfs_aops;
@@ -256,7 +284,7 @@
 	d_instantiate(dentry, ip);
 
 	/* update parent directory inode */
-	dip->i_nlink++;		/* for '..' from child directory */
+	INC_DIR_INODE_NLINK(dip);	/* for '..' from child directory */
 	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(dip);
 
@@ -267,7 +295,7 @@
 	up(&JFS_IP(dip)->commit_sem);
 	up(&JFS_IP(ip)->commit_sem);
 	if (rc) {
-		ip->i_nlink = 0;
+		ip->i_nlink = JFS_IP(ip)->nlink_real = 0;
 		iput(ip);
 	}
 
@@ -351,7 +379,7 @@
 	/* update parent directory's link count corresponding
 	 * to ".." entry of the target directory deleted
 	 */
-	dip->i_nlink--;
+	DEC_DIR_INODE_NLINK(dip);
 	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(dip);
 
@@ -373,7 +401,7 @@
 	JFS_IP(ip)->acl.flag = 0;
 
 	/* mark the target directory as deleted */
-	ip->i_nlink = 0;
+	ip->i_nlink = JFS_IP(ip)->nlink_real = 0;
 	mark_inode_dirty(ip);
 
 	rc = txCommit(tid, 2, &iplist[0], 0);
@@ -470,7 +498,7 @@
 	mark_inode_dirty(dip);
 
 	/* update target's inode */
-	ip->i_nlink--;
+	DEC_INODE_NLINK(ip);
 	mark_inode_dirty(ip);
 
 	/*
@@ -768,7 +796,7 @@
 	down(&JFS_IP(dir)->commit_sem);
 	down(&JFS_IP(ip)->commit_sem);
 
-	if (ip->i_nlink == JFS_LINK_MAX) {
+	if (JFS_IP(ip)->nlink_real == JFS_LINK_MAX) {
 		rc = EMLINK;
 		goto out;
 	}
@@ -790,7 +818,7 @@
 		goto out;
 
 	/* update object inode */
-	ip->i_nlink++;		/* for new link */
+	INC_INODE_NLINK(ip);
 	ip->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(dir);
 	atomic_inc(&ip->i_count);
@@ -1004,7 +1032,7 @@
 	up(&JFS_IP(dip)->commit_sem);
 	up(&JFS_IP(ip)->commit_sem);
 	if (rc) {
-		ip->i_nlink = 0;
+		ip->i_nlink = JFS_IP(ip)->nlink_real = 0;
 		iput(ip);
 	}
 
@@ -1091,7 +1119,7 @@
 				goto out3;
 			}
 		} else if ((new_dir != old_dir) &&
-			   (new_dir->i_nlink == JFS_LINK_MAX)) {
+			   (JFS_IP(new_dir)->nlink_real == JFS_LINK_MAX)) {
 			rc = EMLINK;
 			goto out3;
 		}
@@ -1118,9 +1146,9 @@
 			      old_ip->i_ino, JFS_RENAME);
 		if (rc)
 			goto out4;
-		new_ip->i_nlink--;
+		DEC_INODE_NLINK(new_ip);
 		if (S_ISDIR(new_ip->i_mode)) {
-			new_ip->i_nlink--;
+			DEC_DIR_INODE_NLINK(new_ip);
 			assert(new_ip->i_nlink == 0);
 			tblk = tid_to_tblock(tid);
 			tblk->xflag |= COMMIT_DELETE;
@@ -1162,7 +1190,7 @@
 			goto out4;
 		}
 		if (S_ISDIR(old_ip->i_mode))
-			new_dir->i_nlink++;
+			INC_DIR_INODE_NLINK(new_dir);
 	}
 	/*
 	 * Remove old directory entry
@@ -1178,7 +1206,7 @@
 		goto out4;
 	}
 	if (S_ISDIR(old_ip->i_mode)) {
-		old_dir->i_nlink--;
+		DEC_DIR_INODE_NLINK(old_dir);
 		if (old_dir != new_dir) {
 			/*
 			 * Change inode number of parent for moved directory
@@ -1351,7 +1379,7 @@
 	up(&JFS_IP(ip)->commit_sem);
 	up(&JFS_IP(dir)->commit_sem);
 	if (rc) {
-		ip->i_nlink = 0;
+		ip->i_nlink = JFS_IP(ip)->nlink_real = 0;
 		iput(ip);
 	}
 



^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05 17:25                             ` Oleg Drokin
@ 2002-09-05 21:18                               ` jw schultz
  2002-09-05 22:02                                 ` Ragnar Kjørstad
  0 siblings, 1 reply; 44+ messages in thread
From: jw schultz @ 2002-09-05 21:18 UTC (permalink / raw)
  To: linux-kernel

On Thu, Sep 05, 2002 at 09:25:45PM +0400, Oleg Drokin wrote:
> Hello!
> 
> On Thu, Sep 05, 2002 at 12:45:34PM -0400, Chris Mason wrote:
> > > > read the -noleaf description on the find man page to see why we need to
> > > > set the directory link count to 1 when we are lying to userspace about
> > > > the actual link count on directories. 
> > > 
> > > There is nothing about nlink == 1 means assume -noleaf, so it should not work
> > > with old way too, right? Have anybody verified? ;)
> > I remember that happening during the initial discussions for the link
> > patch.  1 was chosen as the best way to do it, since it was a flag to
> > various programs that the unix directory link convention was not being
> > followed.
> > > Actually patch might be easily modified to represent i_nlink == 1 for
> > > large directories, but still maintain correct on-disk nlink count.
> > Right.

I'm assuming for the moment that the discussion here is
about what to report to stat(2) and not how to deal with
internal overflow (which should produce an error).

So what you are suggesting is that 
<pseudocode>
	if (i.i_nlink > ST_NLINK_MAX)
		st.st_nlink = S_ISDIR(i.i_mode) ? 1 : ST_NLINK_MAX;
</pseudocode>

I don't know the rationale for st_nlink == 1 on directories
but it seems to me the thing to do is st_nlink == 0 on
overflow regardless of type.  This simplifies the logic and
eliminates the use a funky special value that gets in the
way of supporting growth.

An st_nlink value of 0 could only occur if you were doing an
fstat() on a deleted file so i doubt much would break on
this odd case.  Having said that no doubt someone will come
up with an example to prove me wrong :)

> Ok, I will come up with revised patch tomorrow and do 2.5 port (and
> advise Vitaly about reiserfsck part)

-- 
________________________________________________________________
	J.W. Schultz            Pegasystems Technologies
	email address:		jw@pegasys.ws

		Remember Cernan and Schmitt

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05 21:18                               ` jw schultz
@ 2002-09-05 22:02                                 ` Ragnar Kjørstad
  2002-09-05 22:57                                   ` jw schultz
  0 siblings, 1 reply; 44+ messages in thread
From: Ragnar Kjørstad @ 2002-09-05 22:02 UTC (permalink / raw)
  To: jw schultz, linux-kernel

On Thu, Sep 05, 2002 at 02:18:49PM -0700, jw schultz wrote:
> I'm assuming for the moment that the discussion here is
> about what to report to stat(2) and not how to deal with
> internal overflow (which should produce an error).
> 
> So what you are suggesting is that 
> <pseudocode>
> 	if (i.i_nlink > ST_NLINK_MAX)
> 		st.st_nlink = S_ISDIR(i.i_mode) ? 1 : ST_NLINK_MAX;
> </pseudocode>
> 
> I don't know the rationale for st_nlink == 1 on directories
> but it seems to me the thing to do is st_nlink == 0 on
> overflow regardless of type.  This simplifies the logic and
> eliminates the use a funky special value that gets in the
> way of supporting growth.

I believe nlink for directories and files are used differently, 
and thus may have to be handled differently as well.

Amongs other things nlink on directories are used when traversing 
directory-trees. If nlink=4 on a directory there must be 2
sub-directories, and you can stop looking once you've found the two.

By giving the incorrect nlink-number, applications using this
optimization will break.

Apperently some operatingsystems/filesystems (VMS?) report the special 
value of nlink=1 when the information is not available, and some
applications use this information to automaticly disable the
optimization. This is why reiserfs has returned nlink=1 for directories
with more than MAX_REISERFS_NLINK subdirectories.

Now, I've just checked the source of GNU find (v4.1.7) and it does _not_
recognize nlink=1 as a special value. (It works as long as there are
less than 2^32 subdirectories though, because it is looking for -1
subdirectories and it wraps)


I'm not sure exactly what nlink is used for in userspace for regular
files, so I don't know what value should be used when the real number 
doesn't fit in the interface.



(Of course new directories/hardlinks shouldn't be created at all once
the limit is exceeded, the above is only a workaround for people that
need it anyway :) )



-- 
Ragnar Kjørstad

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05 22:02                                 ` Ragnar Kjørstad
@ 2002-09-05 22:57                                   ` jw schultz
  2002-09-06  0:01                                     ` Ragnar Kjørstad
  0 siblings, 1 reply; 44+ messages in thread
From: jw schultz @ 2002-09-05 22:57 UTC (permalink / raw)
  To: linux-kernel

On Fri, Sep 06, 2002 at 12:02:49AM +0200, Ragnar Kjørstad wrote:
> On Thu, Sep 05, 2002 at 02:18:49PM -0700, jw schultz wrote:
> > I'm assuming for the moment that the discussion here is
> > about what to report to stat(2) and not how to deal with
> > internal overflow (which should produce an error).
> > 
> > So what you are suggesting is that 
> > <pseudocode>
> > 	if (i.i_nlink > ST_NLINK_MAX)
> > 		st.st_nlink = S_ISDIR(i.i_mode) ? 1 : ST_NLINK_MAX;
> > </pseudocode>
> > 
> > I don't know the rationale for st_nlink == 1 on directories
> > but it seems to me the thing to do is st_nlink == 0 on
> > overflow regardless of type.  This simplifies the logic and
> > eliminates the use a funky special value that gets in the
> > way of supporting growth.
> 
> I believe nlink for directories and files are used differently, 
> and thus may have to be handled differently as well.
> 
> Amongs other things nlink on directories are used when traversing 
> directory-trees. If nlink=4 on a directory there must be 2
> sub-directories, and you can stop looking once you've found the two.
> 
> By giving the incorrect nlink-number, applications using this
> optimization will break.
> 
> Apperently some operatingsystems/filesystems (VMS?) report the special 
> value of nlink=1 when the information is not available, and some
> applications use this information to automaticly disable the
> optimization. This is why reiserfs has returned nlink=1 for directories
> with more than MAX_REISERFS_NLINK subdirectories.
> 
> Now, I've just checked the source of GNU find (v4.1.7) and it does _not_
> recognize nlink=1 as a special value. (It works as long as there are
> less than 2^32 subdirectories though, because it is looking for -1
> subdirectories and it wraps)

So a value of 0 would have the same effect.
(0 - 2 == -2 vs 1 - 2 == -1) Yes?

> 
> 
> I'm not sure exactly what nlink is used for in userspace for regular
> files, so I don't know what value should be used when the real number 
> doesn't fit in the interface.

I know it is used for reporting purposes such as ls -l.  It
would also used by archiving tools like cpio, tar and rsync
to identify files that may be linked so that not every file
must be checked against every previous file.  A smart
archiving tool would track the link count and remove entries
that have all links found so any value that isn't recognized
as an overflow indicator would tend to break things.  I see
the value of 0 as indicating "link count unsupported".

> (Of course new directories/hardlinks shouldn't be created at all once
> the limit is exceeded, the above is only a workaround for people that
> need it anyway :) )

It should not fail just because the type specified for
st_nlink has overflowed.  It should fail only if the FS or
kernel internals overflow.  Internally the kernel is moving
to an unsigned int.  I looked it up a recently and each
filesystem has it's own idea of a maximum number of links
and most of them are not just arbitrary  but even strange
such as 32000 or 0x7FFF - 1000.

The stat structure has already been left behind on this.
Eventually (3.0?) it should be updated to reflect the
changed internals.  This update has to be delayed because it
will break binary compatability of oodles of code.  I, at
least, don't think this is worth creating yet another
version of stat(2).

-- 
________________________________________________________________
	J.W. Schultz            Pegasystems Technologies
	email address:		jw@pegasys.ws

		Remember Cernan and Schmitt

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05 22:57                                   ` jw schultz
@ 2002-09-06  0:01                                     ` Ragnar Kjørstad
  2002-09-06  1:41                                       ` jw schultz
  0 siblings, 1 reply; 44+ messages in thread
From: Ragnar Kjørstad @ 2002-09-06  0:01 UTC (permalink / raw)
  To: jw schultz, linux-kernel

On Thu, Sep 05, 2002 at 03:57:06PM -0700, jw schultz wrote:
> > Now, I've just checked the source of GNU find (v4.1.7) and it does _not_
> > recognize nlink=1 as a special value. (It works as long as there are
> > less than 2^32 subdirectories though, because it is looking for -1
> > subdirectories and it wraps)
> 
> So a value of 0 would have the same effect.
> (0 - 2 == -2 vs 1 - 2 == -1) Yes?

Yes, it will. For GNU find.

But the reasoning for using nlink==1 is that that's how "all non-unix
filesystems" behaved, so applications out there could potentially check
for it. 

> I know it is used for reporting purposes such as ls -l.  It
> would also used by archiving tools like cpio, tar and rsync
> to identify files that may be linked so that not every file
> must be checked against every previous file.  A smart
> archiving tool would track the link count and remove entries
> that have all links found so any value that isn't recognized
> as an overflow indicator would tend to break things.  I see
> the value of 0 as indicating "link count unsupported".

Hmm, yes. Values of 1 or NLINK_MAX would definitively confuse such
applications. But then again, so would a value of 0 unless they know
it's meaning.



-- 
Ragnar Kjørstad

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-06  0:01                                     ` Ragnar Kjørstad
@ 2002-09-06  1:41                                       ` jw schultz
  2002-09-06  2:29                                         ` Ragnar Kjørstad
  0 siblings, 1 reply; 44+ messages in thread
From: jw schultz @ 2002-09-06  1:41 UTC (permalink / raw)
  To: linux-kernel

On Fri, Sep 06, 2002 at 02:01:38AM +0200, Ragnar Kjørstad wrote:
> On Thu, Sep 05, 2002 at 03:57:06PM -0700, jw schultz wrote:
> > > Now, I've just checked the source of GNU find (v4.1.7) and it does _not_
> > > recognize nlink=1 as a special value. (It works as long as there are
> > > less than 2^32 subdirectories though, because it is looking for -1
> > > subdirectories and it wraps)
> > 
> > So a value of 0 would have the same effect.
> > (0 - 2 == -2 vs 1 - 2 == -1) Yes?
> 
> Yes, it will. For GNU find.
> 
> But the reasoning for using nlink==1 is that that's how "all non-unix
> filesystems" behaved, so applications out there could potentially check
> for it. 

But we aren't talking about filesystems with different ideas
about directory linking.  We are talking about directories
with an overflowed link-count.

> > I know it is used for reporting purposes such as ls -l.  It
> > would also used by archiving tools like cpio, tar and rsync
> > to identify files that may be linked so that not every file
> > must be checked against every previous file.  A smart
> > archiving tool would track the link count and remove entries
> > that have all links found so any value that isn't recognized
> > as an overflow indicator would tend to break things.  I see
> > the value of 0 as indicating "link count unsupported".
> 
> Hmm, yes. Values of 1 or NLINK_MAX would definitively confuse such
> applications. But then again, so would a value of 0 unless they know
> it's meaning.

The value of 1 can't be used for regular files because it
would mean the file doesn't need checking for other links.
Coding for NLINK_MAX would mean the apps would have to
adjust every time NLINK_MAX changed.  Yes, it could be done
through #define in stat.h.  It is a corner case right now
but these apps could know that

	1 == no other links
	>1 == known number of other links
	0 == unknown number of other links

And the code would work on other systems with different or
no overflow/limit.  So far as i know Linux is the only OS
that is allowing the creation of more links than 32767.
These apps are going to need to cope with this sooner or
later.  Allowing nlinks to overflow st_nlink is going to
break them.  Using 0 would mean that the application code to
handle this corner case would simply never get invoked on
other platforms without requiring build options.  Sure 1 is
a red flag for directories (if you can spot it) but any
value greater than 0 is potentially valid for files.

That is why i lean toward 0.  It is a clear indication that
the value is meaningless.  It also sticks out like a sore
thumb.  If i do an ls -l and see 0 i will know i've got a
reporting overflow without having to remember what the exact
limit is.  This way i can do a 'find -links 0' and spot
directories and files with more links than fit etc.  The
application code to cope with it won't break or require
special handling on other platforms.

So you see why i dislike NLINK_MAX and it just makes sens to me
to use the same for files and directories.  Filesystems that
don't support hardlinks have been stuffing 1 into st_nlink
for both file and directories (treating them identically).
I am essentially saying we should treat files and directories
the same on overflow.  We just shouldn't use some value that
in future could represent reality.  Hence 0.  So far i
haven't heard any reason why not.

NOTE: 
	Allowing the creation of links that exceed the capacity of
	stat(2) to report will break utilities.  There should be a
	system wide tunable that allows restricting link creation to
	a maximum number until the tools catch up.  This tunable
	would only affect link creation causing link(2) to set errno
	to EMLINK.  A mount option might be OK too.
	This limit should not affect pseudo filesystems like
	proc or driverfs.

-- 
________________________________________________________________
	J.W. Schultz            Pegasystems Technologies
	email address:		jw@pegasys.ws

		Remember Cernan and Schmitt

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-06  1:41                                       ` jw schultz
@ 2002-09-06  2:29                                         ` Ragnar Kjørstad
  0 siblings, 0 replies; 44+ messages in thread
From: Ragnar Kjørstad @ 2002-09-06  2:29 UTC (permalink / raw)
  To: jw schultz, linux-kernel

On Thu, Sep 05, 2002 at 06:41:22PM -0700, jw schultz wrote:
> > > So a value of 0 would have the same effect.
> > > (0 - 2 == -2 vs 1 - 2 == -1) Yes?
> > 
> > Yes, it will. For GNU find.
> > 
> > But the reasoning for using nlink==1 is that that's how "all non-unix
> > filesystems" behaved, so applications out there could potentially check
> > for it. 
> 
> But we aren't talking about filesystems with different ideas
> about directory linking.  We are talking about directories
> with an overflowed link-count.

No, but from an application's point of view they're the same. They're
both directories unable to report the number of subdirectories they
have. So, they should be handled the same. Either with nlink==1, or
nlink==0, but I think it will be difficult to migrate to the later if a
lot of existing software implement the first one.

> The value of 1 can't be used for regular files because it
> would mean the file doesn't need checking for other links.
> Coding for NLINK_MAX would mean the apps would have to
> adjust every time NLINK_MAX changed.  Yes, it could be done
> through #define in stat.h.  It is a corner case right now
> but these apps could know that
> 
> 	1 == no other links
> 	>1 == known number of other links
> 	0 == unknown number of other links

I agree.



-- 
Ragnar Kjørstad

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-04 20:29       ` [reiserfs-dev] " Chris Mason
  2002-09-04 23:34         ` David S. Miller
@ 2002-09-06  8:52         ` David Woodhouse
  1 sibling, 0 replies; 44+ messages in thread
From: David Woodhouse @ 2002-09-06  8:52 UTC (permalink / raw)
  To: David S. Miller
  Cc: mason, shaggy, szepe, marcelo, linux-kernel, aurora-sparc-devel,
	reiserfs-dev, linuxjfs


davem@redhat.com said:
> >    The patch will probably cause reiserfs problems as well, we've
> >    already got people with > 32767 links on disk, going to a lower
> >    number will confuse things.
> And that means you already have reiserfs partitions that cannot be
> used on other Linux platforms.  That's pretty bad. 

Surely a file system with > 32Ki links can be _used_ on sparc, you just 
can't return a correct value in st_nlink. For directories, you could 
perhaps set st_nlink to '1', which many things will interpret as
"don't know". For files, I'm not sure -- but even just setting it to 
min(32767, real_nlink) would suffice, surely? It's inaccurate but it's 
better than the idea that the file system just cannot be mounted.

Is there a requirement to stop allowing hard links (or subdirectories) 
to be made when nlink reaches the maximum representable to user space? 
Obviously you have to do it if you're keeping an nlink count on the 
medium and you'd overflow _that_, but should we return -EMLINK even if we 
could represent the new hard link on the file system?

--
dwmw2



^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
  2002-09-05 17:58                         ` Dave Kleikamp
@ 2002-09-06 13:54                           ` Oleg Drokin
  0 siblings, 0 replies; 44+ messages in thread
From: Oleg Drokin @ 2002-09-06 13:54 UTC (permalink / raw)
  To: Dave Kleikamp
  Cc: David S. Miller, szepe, mason, linux-kernel, reiserfs-dev, linuxjfs

Hello!

On Thu, Sep 05, 2002 at 12:58:27PM -0500, Dave Kleikamp wrote:
> Here's the JFS patch.  When I first saw this thread I didn't expect that
> the result would be increasing the max. number of links.  :^)
> Note that I made JFS_LINK_MAX the maximum supported by JFS,
> and VFS_LINK_MAX as the number limited by the size of nlink_t.
> VFS_LINK_MAX could be moved to fs.h if other file systems are
> to use it in the same way.
> I borrowed reiserfs's *_INODE_NLINK macros, but made them inline functions.
> (I don't usually send patches from kmail.  I hope it doesn't screw up the formatting.)

Actually Linus' suggestion to change type of struct inode.i_nlink field is
better because otherwise everybody will implement that "real nlink" stuff.
I hope Marcello will accept such a patch.
Here is it (both reiserfs and jfs bits).

Hm. jfs patch became really small ;)

Note I do not play this "if directory, then set nlink to 1" games.
As it was already explained it will only lead to find(1) and others still
count only (nlink_t) -1 links, so not all of the links will be counted, but
exactly the same amount as we present in st_nlink field on arches
that have unsigned nlink_t and probably none on those with signed nlink_t.

Patch is against 2.4.20-pre5.

Bye,
    Oleg

===== fs/stat.c 1.4 vs edited =====
--- 1.4/fs/stat.c	Tue Feb  5 10:45:18 2002
+++ edited/fs/stat.c	Fri Sep  6 17:35:02 2002
@@ -49,7 +49,7 @@
 	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
 	tmp.st_ino = inode->i_ino;
 	tmp.st_mode = inode->i_mode;
-	tmp.st_nlink = inode->i_nlink;
+	tmp.st_nlink = min_t(unsigned int, MAX_NLINK_T, inode->i_nlink);
 	SET_OLDSTAT_UID(tmp, inode->i_uid);
 	SET_OLDSTAT_GID(tmp, inode->i_gid);
 	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
@@ -75,7 +75,7 @@
 	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
 	tmp.st_ino = inode->i_ino;
 	tmp.st_mode = inode->i_mode;
-	tmp.st_nlink = inode->i_nlink;
+	tmp.st_nlink = min_t(unsigned int, MAX_NLINK_T, inode->i_nlink);
 	SET_STAT_UID(tmp, inode->i_uid);
 	SET_STAT_GID(tmp, inode->i_gid);
 	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
@@ -282,7 +282,7 @@
 	tmp.__st_ino = inode->i_ino;
 #endif
 	tmp.st_mode = inode->i_mode;
-	tmp.st_nlink = inode->i_nlink;
+	tmp.st_nlink = min_t(unsigned int, MAX_NLINK_T, inode->i_nlink);
 	tmp.st_uid = inode->i_uid;
 	tmp.st_gid = inode->i_gid;
 	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
===== fs/jfs/jfs_filsys.h 1.1 vs edited =====
--- 1.1/fs/jfs/jfs_filsys.h	Fri May 31 17:19:24 2002
+++ edited/fs/jfs/jfs_filsys.h	Fri Sep  6 17:33:32 2002
@@ -125,7 +125,11 @@
 #define MAXBLOCKSIZE		4096
 #define	MAXFILESIZE		((s64)1 << 52)
 
-#define JFS_LINK_MAX		65535	/* nlink_t is unsigned short */
+/*
+ * The max link count in struct inode is limited to the size of nlink_t.
+ * The JFS inode uses an unsigned 32-bit int, so we can really go higher
+ */
+#define JFS_LINK_MAX	0xffffffff	/* real limit */
 
 /* Minimum number of bytes supported for a JFS partition */
 #define MINJFS			(0x1000000)
===== fs/reiserfs/namei.c 1.24 vs edited =====
--- 1.24/fs/reiserfs/namei.c	Fri Aug  9 19:22:33 2002
+++ edited/fs/reiserfs/namei.c	Fri Sep  6 17:23:34 2002
@@ -8,8 +8,13 @@
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
 
-#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
-#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--;
+// v3.5 files have 16bit nlink_t, v3.6 files have 32bit nlink_t.
+#define CAN_INCREASE_NLINK(i) ( i->i_nlink < ((get_inode_sd_version (i) != KEY_FORMAT_3_5)?MAX_UL_INT:MAX_US_INT)) 
+
+// Compatibility stuff with old trick that allowed to have lots of subdirs in
+// one dir. Such dirs had 1 as their nlink count.
+#define INC_DIR_INODE_NLINK(i) { if (i->i_nlink != 1) i->i_nlink++;}
+#define DEC_DIR_INODE_NLINK(i) { if (i->i_nlink != 1) i->i_nlink--;}
 
 // directory item contains array of entry headers. This performs
 // binary search through that array
@@ -592,6 +597,9 @@
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
+    if ( !CAN_INCREASE_NLINK(dir) )
+	return -EMLINK;
+
     if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
@@ -613,7 +621,7 @@
 				dentry, inode, &retval);
     if (!inode) {
 	pop_journal_writer(windex) ;
-	dir->i_nlink-- ;
+	DEC_DIR_INODE_NLINK(dir);
 	journal_end(&th, dir->i_sb, jbegin_count) ;
 	return retval;
     }
@@ -896,8 +904,7 @@
     if (S_ISDIR(inode->i_mode))
 	return -EPERM;
   
-    if (inode->i_nlink >= REISERFS_LINK_MAX) {
-	//FIXME: sd_nlink is 32 bit for new files
+    if (!CAN_INCREASE_NLINK(inode)) {
 	return -EMLINK;
     }
 
@@ -1021,6 +1028,8 @@
 	// and that its new parent directory has not too many links
 	// already
 
+	if ( !CAN_INCREASE_NLINK(new_dir) )
+	    return -EMLINK;
 	if (new_dentry_inode) {
 	    if (!reiserfs_empty_dir(new_dentry_inode)) {
 		return -ENOTEMPTY;
===== include/linux/fs.h 1.68 vs edited =====
--- 1.68/include/linux/fs.h	Fri Aug 23 17:27:33 2002
+++ edited/include/linux/fs.h	Fri Sep  6 17:43:02 2002
@@ -442,7 +442,7 @@
 	atomic_t		i_count;
 	kdev_t			i_dev;
 	umode_t			i_mode;
-	nlink_t			i_nlink;
+	unsigned int		i_nlink;
 	uid_t			i_uid;
 	gid_t			i_gid;
 	kdev_t			i_rdev;
@@ -513,6 +513,11 @@
 		void				*generic_ip;
 	} u;
 };
+
+/* maximal nlink_t value possible. Used insead of very high i_nlink values
+   that some filesystems might allow to prevent user visible negative
+   nlink counts. */
+#define MAX_NLINK_T (nlink_t)((((nlink_t) -1) > 0)?~0:((1u<<(sizeof(nlink_t)*8-1))-1))
 
 struct fown_struct {
 	int pid;		/* pid or -pgrp where SIGIO should be sent */
===== include/linux/reiserfs_fs.h 1.22 vs edited =====
--- 1.22/include/linux/reiserfs_fs.h	Tue Aug 20 13:40:53 2002
+++ edited/include/linux/reiserfs_fs.h	Fri Sep  6 17:44:53 2002
@@ -1163,7 +1163,6 @@
 #define INODE_PKEY(inode) ((struct key *)((inode)->u.reiserfs_i.i_key))
 
 #define MAX_UL_INT 0xffffffff
-#define MAX_INT    0x7ffffff
 #define MAX_US_INT 0xffff
 
 // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
@@ -1184,10 +1183,6 @@
 
 #define MAX_B_NUM  MAX_UL_INT
 #define MAX_FC_NUM MAX_US_INT
-
-
-/* the purpose is to detect overflow of an unsigned short */
-#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
 
 
 /* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2002-09-06 13:50 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-09-01  8:55 [PATCH] sparc32: wrong type of nlink_t Tomas Szepe
2002-09-01  8:52 ` David S. Miller
2002-09-01  9:44   ` Tomas Szepe
2002-09-04 20:18     ` Dave Kleikamp
2002-09-04 20:29       ` [reiserfs-dev] " Chris Mason
2002-09-04 23:34         ` David S. Miller
2002-09-06  8:52         ` David Woodhouse
2002-09-04 20:31       ` Hans Reiser
2002-09-04 21:18         ` Tomas Szepe
2002-09-04 21:44           ` Thunder from the hill
2002-09-04 21:57             ` Thunder from the hill
2002-09-04 23:35         ` David S. Miller
2002-09-05  0:36           ` Hans Reiser
2002-09-05  0:32             ` David S. Miller
2002-09-05  0:49             ` Chris Mason
2002-09-05  5:40               ` Tomas Szepe
2002-09-05  5:36                 ` David S. Miller
2002-09-05  5:48                   ` Tomas Szepe
2002-09-05  5:45                     ` David S. Miller
2002-09-05  9:46                       ` Nikita Danilov
2002-09-05  5:56                     ` Oleg Drokin
2002-09-05  5:52                       ` David S. Miller
2002-09-05  6:07                         ` Oleg Drokin
2002-09-05  5:59                       ` Tomas Szepe
2002-09-05  9:54                   ` Oleg Drokin
2002-09-05 10:50                     ` David S. Miller
2002-09-05 13:49                     ` Oleg Drokin
2002-09-05 13:57                       ` Oleg Drokin
2002-09-05 14:03                       ` Chris Mason
2002-09-05 14:17                         ` Oleg Drokin
2002-09-05 16:45                           ` Chris Mason
2002-09-05 17:25                             ` Oleg Drokin
2002-09-05 21:18                               ` jw schultz
2002-09-05 22:02                                 ` Ragnar Kjørstad
2002-09-05 22:57                                   ` jw schultz
2002-09-06  0:01                                     ` Ragnar Kjørstad
2002-09-06  1:41                                       ` jw schultz
2002-09-06  2:29                                         ` Ragnar Kjørstad
2002-09-05 16:09                     ` Dave Kleikamp
2002-09-05 16:13                       ` Oleg Drokin
2002-09-05 17:58                         ` Dave Kleikamp
2002-09-06 13:54                           ` Oleg Drokin
2002-09-05 17:24                     ` Linus Torvalds
2002-09-04 23:33       ` David S. Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).