lkml.org 
[lkml]   [2002]   [Sep]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: [reiserfs-dev] Re: [PATCH] sparc32: wrong type of nlink_t
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
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
\
 
 \ /
  Last update: 2005-03-22 13:28    [W:2.412 / U:0.144 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site