patch-2.1.56 linux/fs/smbfs/inode.c
Next file: linux/fs/smbfs/proc.c
Previous file: linux/fs/smbfs/file.c
Back to the patch index
Back to the overall index
- Lines: 369
- Date:
Sun Sep 14 15:14:56 1997
- Orig file:
v2.1.55/linux/fs/smbfs/inode.c
- Orig date:
Wed Sep 3 20:52:43 1997
diff -u --recursive --new-file v2.1.55/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
@@ -26,6 +26,9 @@
#include <asm/system.h>
#include <asm/uaccess.h>
+#define SB_of(server) ((struct super_block *) ((char *)(server) - \
+ (unsigned long)(&((struct super_block *)0)->u.smbfs_sb)))
+
extern int close_fp(struct file *filp);
static void smb_put_inode(struct inode *);
@@ -82,6 +85,23 @@
}
static void
+smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
+{
+ inode->i_dev = inode->i_sb->s_dev;
+ inode->i_mode = fattr->f_mode;
+ inode->i_nlink = fattr->f_nlink;
+ inode->i_uid = fattr->f_uid;
+ inode->i_gid = fattr->f_gid;
+ inode->i_rdev = fattr->f_rdev;
+ inode->i_size = fattr->f_size;
+ inode->i_mtime = fattr->f_mtime;
+ inode->i_ctime = fattr->f_ctime;
+ inode->i_atime = fattr->f_atime;
+ inode->i_blksize= fattr->f_blksize;
+ inode->i_blocks = fattr->f_blocks;
+}
+
+static void
smb_read_inode(struct inode *inode)
{
pr_debug("smb_iget: %p\n", read_fattr);
@@ -92,18 +112,8 @@
printk("smb_read_inode called from invalid point\n");
return;
}
- inode->i_mode = read_fattr->f_mode;
- inode->i_nlink = read_fattr->f_nlink;
- inode->i_uid = read_fattr->f_uid;
- inode->i_gid = read_fattr->f_gid;
- inode->i_rdev = read_fattr->f_rdev;
- inode->i_size = read_fattr->f_size;
- inode->i_mtime = read_fattr->f_mtime;
- inode->i_ctime = read_fattr->f_ctime;
- inode->i_atime = read_fattr->f_atime;
- inode->i_blksize = read_fattr->f_blksize;
- inode->i_blocks = read_fattr->f_blocks;
+ smb_set_inode_attr(inode, read_fattr);
memset(&(inode->u.smbfs_i), 0, sizeof(inode->u.smbfs_i));
if (S_ISREG(inode->i_mode))
@@ -114,39 +124,112 @@
inode->i_op = NULL;
}
+/*
+ * This is called if the connection has gone bad ...
+ * try to kill off all the current inodes.
+ */
void
smb_invalidate_inodes(struct smb_sb_info *server)
{
printk("smb_invalidate_inodes\n");
+ shrink_dcache(); /* should shrink only this sb */
+ invalidate_inodes(SB_of(server));
}
int
-smb_revalidate_inode(struct inode *i)
+smb_revalidate_inode(struct inode *ino)
{
+ struct dentry * dentry = ino->u.smbfs_i.dentry;
+ int error = 0;
+
pr_debug("smb_revalidate_inode\n");
- return 0;
+ if (!ino)
+ goto bad_no_inode;
+ dentry = ino->u.smbfs_i.dentry;
+#if 0
+ if (dentry)
+ {
+ printk("smb_revalidate: checking %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ }
+#endif
+out:
+ return error;
+
+bad_no_inode:
+ printk("smb_revalidate: no inode!\n");
+ error = -EINVAL;
+ goto out;
}
int
-smb_refresh_inode(struct inode *i)
+smb_refresh_inode(struct inode *ino)
{
+ struct dentry * dentry = ino->u.smbfs_i.dentry;
+ struct smb_fattr fattr;
+ int error;
+
pr_debug("smb_refresh_inode\n");
- return 0;
+ error = -EIO;
+ if (!dentry) {
+ printk("smb_refresh_inode: no dentry, can't refresh\n");
+ goto out;
+ }
+
+ /* N.B. Should check for changes of important fields! cf. NFS */
+ error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
+ if (!error)
+ {
+ smb_set_inode_attr(ino, &fattr);
+ }
+out:
+ return error;
}
+/*
+ * This routine is called for every iput().
+ */
static void
smb_put_inode(struct inode *ino)
{
+ struct dentry * dentry;
pr_debug("smb_put_inode: count = %d\n", ino->i_count);
- if (smb_close(ino))
- printk("smbfs: could not close inode\n");
+ if (ino->i_count > 1) {
+ /*
+ * Check whether the dentry still holds this inode.
+ * This looks scary, but should work ... d_inode is
+ * cleared before iput() in the dcache.
+ */
+ dentry = (struct dentry *) ino->u.smbfs_i.dentry;
+ if (dentry && dentry->d_inode != ino) {
+ ino->u.smbfs_i.dentry = NULL;
+#if 1
+printk("smb_put_inode: cleared dentry for %s/%s (%ld), count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, ino->i_ino, ino->i_count);
+#endif
+ }
+ } else {
+ /*
+ * Last use ... clear i_nlink to force
+ * smb_delete_inode to be called.
+ */
+ ino->i_nlink = 0;
+ }
}
+/*
+ * This routine is called when i_nlink == 0 and i_count goes to 0.
+ * All blocking cleanup operations need to go here to avoid races.
+ */
static void
-smb_delete_inode(struct inode *i)
+smb_delete_inode(struct inode *ino)
{
pr_debug("smb_delete_inode\n");
+ if (smb_close(ino))
+ printk("smb_delete_inode: could not close inode %ld\n",
+ ino->i_ino);
+ clear_inode(ino);
}
static void
@@ -181,33 +264,20 @@
struct smb_fattr root;
kdev_t dev = sb->s_dev;
unsigned char *packet;
+ struct inode *root_inode;
+ struct dentry *dentry;
MOD_INC_USE_COUNT;
- if (!data) {
- printk("smb_read_super: missing data argument\n");
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
- }
+ if (!data)
+ goto out_no_data;
if (data->version != SMB_MOUNT_VERSION)
- {
- printk(KERN_ERR "smb_read_super: wrong data argument."
- " Recompile smbmount.\n");
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
- }
+ goto out_wrong_data;
packet = smb_vmalloc(SMB_INITIAL_PACKET_SIZE);
if (!packet)
- {
- pr_debug("smb_read_super: could not alloc packet\n");
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
- }
+ goto out_no_mem;
lock_super(sb);
@@ -222,7 +292,7 @@
sb->u.smbfs_sb.conn_pid = 0;
sb->u.smbfs_sb.packet = packet;
sb->u.smbfs_sb.packet_size = SMB_INITIAL_PACKET_SIZE;
- sb->u.smbfs_sb.generation = 1;
+ sb->u.smbfs_sb.generation = 0;
sb->u.smbfs_sb.m = *data;
sb->u.smbfs_sb.m.file_mode = (sb->u.smbfs_sb.m.file_mode &
@@ -232,18 +302,38 @@
smb_init_root_dirent(&(sb->u.smbfs_sb), &root);
+ sb->s_root = NULL;
unlock_super(sb);
- sb->s_root = d_alloc_root(smb_iget(sb, &root), NULL);
- if (!sb->s_root)
- {
- sb->s_dev = 0;
- printk(KERN_ERR "smb_read_super: get root inode failed\n");
- smb_vfree(sb->u.smbfs_sb.packet);
- MOD_DEC_USE_COUNT;
- return NULL;
- }
+ root_inode = smb_iget(sb, &root);
+ if (!root_inode)
+ goto out_no_root;
+ dentry = d_alloc_root(root_inode, NULL);
+ if (!dentry)
+ goto out_no_root;
+ root_inode->u.smbfs_i.dentry = dentry;
+ sb->s_root = dentry;
return sb;
+
+out_no_data:
+ printk("smb_read_super: missing data argument\n");
+ goto out;
+out_wrong_data:
+ printk(KERN_ERR "smb_read_super: wrong data argument."
+ " Recompile smbmount.\n");
+ goto out;
+out_no_mem:
+ pr_debug("smb_read_super: could not alloc packet\n");
+ goto out;
+out_no_root:
+ sb->s_dev = 0; /* iput() might block */
+ printk(KERN_ERR "smb_read_super: get root inode failed\n");
+ iput(root_inode);
+ smb_vfree(packet);
+out:
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+ return NULL;
}
static int
@@ -265,32 +355,46 @@
int
smb_notify_change(struct inode *inode, struct iattr *attr)
{
- int error = 0;
+ struct dentry *dentry = inode->u.smbfs_i.dentry;
+ int error;
+
+ error = -EIO;
+ if (!dentry)
+ {
+ printk("smb_notify_change: no dentry for inode!\n");
+ goto out;
+ }
if ((error = inode_change_ok(inode, attr)) < 0)
- return error;
+ goto out;
+ error = -EPERM;
if (((attr->ia_valid & ATTR_UID) &&
(attr->ia_uid != SMB_SERVER(inode)->m.uid)))
- return -EPERM;
+ goto out;
if (((attr->ia_valid & ATTR_GID) &&
(attr->ia_uid != SMB_SERVER(inode)->m.gid)))
- return -EPERM;
+ goto out;
if (((attr->ia_valid & ATTR_MODE) &&
(attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
- return -EPERM;
+ goto out;
+
+ /*
+ * Assume success and invalidate the parent's dir cache
+ */
+ smb_invalid_dir_cache(dentry->d_parent->d_inode);
if ((attr->ia_valid & ATTR_SIZE) != 0)
{
- if ((error = smb_open(inode, O_WRONLY)) < 0)
- goto fail;
+ if ((error = smb_open(dentry, O_WRONLY)) < 0)
+ goto out;
if ((error = smb_proc_trunc(SMB_SERVER(inode),
inode->u.smbfs_i.fileid,
attr->ia_size)) < 0)
- goto fail;
+ goto out;
}
if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
{
@@ -300,36 +404,30 @@
fattr.attr = 0;
fattr.f_size = inode->i_size;
fattr.f_blksize = inode->i_blksize;
+ fattr.f_ctime = inode->i_ctime;
+ fattr.f_mtime = inode->i_mtime;
+ fattr.f_atime = inode->i_atime;
if ((attr->ia_valid & ATTR_CTIME) != 0)
fattr.f_ctime = attr->ia_ctime;
- else
- fattr.f_ctime = inode->i_ctime;
if ((attr->ia_valid & ATTR_MTIME) != 0)
fattr.f_mtime = attr->ia_mtime;
- else
- fattr.f_mtime = inode->i_mtime;
if ((attr->ia_valid & ATTR_ATIME) != 0)
fattr.f_atime = attr->ia_atime;
- else
- fattr.f_atime = inode->i_atime;
- if ((error = smb_proc_setattr(SMB_SERVER(inode),
- inode, &fattr)) >= 0)
+ error = smb_proc_setattr(SMB_SERVER(inode), dentry, &fattr);
+ if (error >= 0)
{
inode->i_ctime = fattr.f_ctime;
inode->i_mtime = fattr.f_mtime;
inode->i_atime = fattr.f_atime;
}
}
- fail:
-/* smb_invalid_dir_cache(smb_info_ino(SMB_INOP(inode)->dir));*/
-
+out:
return error;
}
-
#ifdef DEBUG_SMB_MALLOC
int smb_malloced;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov