From: arnd@arndb.de
To: linux-fsdevel@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, hch@lst.de
Subject: [RFC 2/7] cramfs: create unique inode numbers
Date: Sat, 31 May 2008 17:20:15 +0200 [thread overview]
Message-ID: <20080531153510.692084580@arndb.de> (raw)
In-Reply-To: 20080531152013.031903990@arndb.de
[-- Attachment #1: 0002-cramfs-create-unique-inode-numbers.patch --]
[-- Type: text/plain, Size: 6942 bytes --]
This changes the inode number in cramfs to be based on
the location of the dentry instead of the file, in order
to make inodes unique.
This lets us change and unlink files in a later patch
without changing all other files that contain the same
data, and it fixes a user-visible bug with 'cp -a'
trying to hardlink empty directories when copying from
a cramfs source.
A slight disadvantage is that identical files no longer
share a common page cache, so the data has to be read
from disk for each file individually.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
fs/cramfs/inode.c | 100 +++++++++++++++++++++++------------------------------
1 files changed, 43 insertions(+), 57 deletions(-)
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 08f08f9..8aa04d7 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -33,80 +33,60 @@ static const struct address_space_operations cramfs_aops;
static DEFINE_MUTEX(read_mutex);
+#define OFFSET(x) ((unsigned long)(x)->i_private)
-/* These two macros may change in future, to provide better st_ino
- semantics. */
-#define CRAMINO(x) (((x)->offset && (x)->size)?(x)->offset<<2:1)
-#define OFFSET(x) ((x)->i_ino)
-
-
-static int cramfs_iget5_test(struct inode *inode, void *opaque)
+static struct inode *get_cramfs_inode(struct super_block *sb,
+ mode_t mode, dev_t dev)
{
- struct cramfs_inode *cramfs_inode = opaque;
-
- if (inode->i_ino != CRAMINO(cramfs_inode))
- return 0; /* does not match */
-
- if (inode->i_ino != 1)
- return 1;
+ struct inode *inode;
- /* all empty directories, char, block, pipe, and sock, share inode #1 */
-
- if ((inode->i_mode != cramfs_inode->mode) ||
- (inode->i_gid != cramfs_inode->gid) ||
- (inode->i_uid != cramfs_inode->uid))
- return 0; /* does not match */
-
- if ((S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) &&
- (inode->i_rdev != old_decode_dev(cramfs_inode->size)))
- return 0; /* does not match */
-
- return 1; /* matches */
-}
+ inode = new_inode(sb);
+ if (!inode)
+ return NULL;
-static int cramfs_iget5_set(struct inode *inode, void *opaque)
-{
- static struct timespec zerotime;
- struct cramfs_inode *cramfs_inode = opaque;
- inode->i_mode = cramfs_inode->mode;
- inode->i_uid = cramfs_inode->uid;
- inode->i_size = cramfs_inode->size;
- inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
- inode->i_gid = cramfs_inode->gid;
- /* Struct copy intentional */
- inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
- inode->i_ino = CRAMINO(cramfs_inode);
+ inode->i_mode = mode;
/* inode->i_nlink is left 1 - arguably wrong for directories,
but it's the best we can do without reading the directory
contents. 1 yields the right result in GNU find, even
without -noleaf option. */
- if (S_ISREG(inode->i_mode)) {
+ if (S_ISREG(mode)) {
inode->i_fop = &generic_ro_fops;
inode->i_data.a_ops = &cramfs_aops;
- } else if (S_ISDIR(inode->i_mode)) {
+ } else if (S_ISDIR(mode)) {
inode->i_op = &cramfs_dir_inode_operations;
inode->i_fop = &cramfs_directory_operations;
- } else if (S_ISLNK(inode->i_mode)) {
+ } else if (S_ISLNK(mode)) {
inode->i_op = &page_symlink_inode_operations;
inode->i_data.a_ops = &cramfs_aops;
} else {
inode->i_size = 0;
inode->i_blocks = 0;
- init_special_inode(inode, inode->i_mode,
- old_decode_dev(cramfs_inode->size));
+ init_special_inode(inode, mode, dev);
}
- return 0;
+ return inode;
}
-static struct inode *get_cramfs_inode(struct super_block *sb,
- struct cramfs_inode * cramfs_inode)
+static struct inode *get_cramfs_inode_ondisk(struct super_block *sb,
+ struct cramfs_inode * cramfs_inode,
+ ino_t ino, off_t offset)
{
- struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode),
- cramfs_iget5_test, cramfs_iget5_set,
- cramfs_inode);
- if (inode && (inode->i_state & I_NEW)) {
- unlock_new_inode(inode);
- }
+ static struct timespec zerotime;
+ struct inode *inode;
+
+ inode = get_cramfs_inode(sb, cramfs_inode->mode,
+ old_decode_dev(cramfs_inode->size));
+ if (!inode)
+ return NULL;
+
+ inode->i_ino = ino;
+ inode->i_uid = cramfs_inode->uid;
+ inode->i_size = cramfs_inode->size;
+ inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
+ inode->i_gid = cramfs_inode->gid;
+ /* Struct copy intentional */
+ inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
+ inode->i_private = (void *)offset;
+
return inode;
}
@@ -234,6 +214,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
int i;
struct cramfs_super super;
unsigned long root_offset;
+ unsigned long root_ino;
struct cramfs_sb_info *sbi;
struct inode *root;
@@ -252,6 +233,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
/* Read the first block and get the superblock from it */
memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));
mutex_unlock(&read_mutex);
+ root_ino = offsetof(struct cramfs_super, root);
/* Do sanity checks on the superblock */
if (super.magic != CRAMFS_MAGIC) {
@@ -266,6 +248,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
mutex_lock(&read_mutex);
memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super));
mutex_unlock(&read_mutex);
+ root_ino += 512;
if (super.magic != CRAMFS_MAGIC) {
if (super.magic == CRAMFS_MAGIC_WEND && !silent)
printk(KERN_ERR "cramfs: wrong endianess\n");
@@ -310,7 +293,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
/* Set it all up.. */
sb->s_op = &cramfs_ops;
- root = get_cramfs_inode(sb, &super.root);
+ root = get_cramfs_inode_ondisk(sb, &super.root, root_ino, root_offset);
if (!root)
goto out;
sb->s_root = d_alloc_root(root);
@@ -383,7 +366,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
*/
namelen = de->namelen << 2;
memcpy(buf, name, namelen);
- ino = CRAMINO(de);
+ ino = OFFSET(inode) + offset;
mode = de->mode;
mutex_unlock(&read_mutex);
nextoffset = offset + sizeof(*de) + namelen;
@@ -422,8 +405,10 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s
struct cramfs_inode *de;
char *name;
int namelen, retval;
+ ino_t ino;
- de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+CRAMFS_MAXPATHLEN);
+ ino = OFFSET(dir) + offset;
+ de = cramfs_read(dir->i_sb, ino, sizeof(*de)+CRAMFS_MAXPATHLEN);
name = (char *)(de+1);
/* Try to take advantage of sorted directories */
@@ -454,7 +439,8 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s
if (!retval) {
struct cramfs_inode entry = *de;
mutex_unlock(&read_mutex);
- d_add(dentry, get_cramfs_inode(dir->i_sb, &entry));
+ d_add(dentry, get_cramfs_inode_ondisk(dir->i_sb,
+ &entry, ino, entry.offset << 2));
return NULL;
}
/* else (retval < 0) */
--
1.5.4.3
--
next prev parent reply other threads:[~2008-05-31 15:38 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20080531152013.031903990@arndb.de>
2008-05-31 15:20 ` [RFC 1/7] cramfs: allow remount rw arnd
2008-05-31 15:20 ` arnd [this message]
2008-06-01 16:50 ` [RFC 2/7] cramfs: create unique inode numbers Jörn Engel
2008-06-01 21:24 ` Arnd Bergmann
2008-06-02 5:42 ` Jörn Engel
2008-05-31 15:20 ` [RFC 3/7] cramfs: allow unlinking of files arnd
2008-06-01 16:54 ` Jörn Engel
2008-06-01 21:28 ` Arnd Bergmann
2008-05-31 15:20 ` [RFC 4/7] cramfs: allow rmdir arnd
2008-05-31 15:20 ` [RFC 5/7] cramfs: allow writing to existing files arnd
2008-05-31 15:20 ` [RFC 6/7] cramfs: read directory entries from dcache arnd
2008-05-31 15:20 ` [RFC 7/7] cramfs: add missing inode operations arnd
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080531153510.692084580@arndb.de \
--to=arnd@arndb.de \
--cc=hch@lst.de \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox