summaryrefslogtreecommitdiffstats
path: root/fs/smbfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/smbfs/inode.c')
-rw-r--r--fs/smbfs/inode.c138
1 files changed, 95 insertions, 43 deletions
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index b21892863..1e72f59a1 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -55,12 +55,12 @@ static struct super_operations smb_sops =
unsigned long
smb_invent_inos(unsigned long n)
{
- static unsigned long ino = 1;
+ static unsigned long ino = 2;
if (ino + 2*n < ino)
{
/* wrap around */
- ino += n;
+ ino = 2;
}
ino += n;
return ino;
@@ -93,6 +93,7 @@ smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr)
memset(fattr, 0, sizeof(struct smb_fattr));
fattr->f_mode = inode->i_mode;
fattr->f_nlink = inode->i_nlink;
+ fattr->f_ino = inode->i_ino;
fattr->f_uid = inode->i_uid;
fattr->f_gid = inode->i_gid;
fattr->f_rdev = inode->i_rdev;
@@ -102,6 +103,15 @@ smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr)
fattr->f_atime = inode->i_atime;
fattr->f_blksize= inode->i_blksize;
fattr->f_blocks = inode->i_blocks;
+
+ fattr->attr = inode->u.smbfs_i.attr;
+ /*
+ * Keep the attributes in sync with the inode permissions.
+ */
+ if (fattr->f_mode & S_IWUSR)
+ fattr->attr &= ~aRONLY;
+ else
+ fattr->attr |= aRONLY;
}
static void
@@ -112,13 +122,22 @@ smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
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;
/*
+ * Don't change the size and mtime/atime fields
+ * if we're writing to the file.
+ */
+ if (!(inode->u.smbfs_i.cache_valid & SMB_F_LOCALWRITE))
+ {
+ inode->i_size = fattr->f_size;
+ inode->i_mtime = fattr->f_mtime;
+ inode->i_atime = fattr->f_atime;
+ }
+
+ inode->u.smbfs_i.attr = fattr->attr;
+ /*
* Update the "last time refreshed" field for revalidation.
*/
inode->u.smbfs_i.oldmtime = jiffies;
@@ -177,9 +196,9 @@ smb_revalidate_inode(struct inode *inode)
* If this is a file opened with write permissions,
* the inode will be up-to-date.
*/
- if (S_ISREG(inode->i_mode) && smb_is_open(inode)) {
- if (inode->u.smbfs_i.access == SMB_O_RDWR ||
- inode->u.smbfs_i.access == SMB_O_WRONLY)
+ if (S_ISREG(inode->i_mode) && smb_is_open(inode))
+ {
+ if (inode->u.smbfs_i.access != SMB_O_RDONLY)
goto out;
}
@@ -237,15 +256,7 @@ smb_refresh_inode(struct inode *inode)
goto out;
}
- /*
- * Kludge alert ... for some reason we can't get attributes
- * for the root directory, so just return success.
- */
- error = 0;
- if (IS_ROOT(dentry))
- goto out;
-
- error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
+ error = smb_proc_getattr(dentry, &fattr);
if (!error)
{
smb_renew_times(dentry);
@@ -261,12 +272,8 @@ smb_refresh_inode(struct inode *inode)
* Big trouble! The inode has become a new object,
* so any operations attempted on it are invalid.
*
- * Take a couple of steps to limit damage:
- * (1) Mark the inode as bad so that subsequent
- * lookup validations will fail.
- * (2) Clear i_nlink so the inode will be released
- * at iput() time. (Unhash it as well?)
- * We also invalidate the caches for good measure.
+ * To limit damage, mark the inode as bad so that
+ * subsequent lookup validations will fail.
*/
#ifdef SMBFS_PARANOIA
printk("smb_refresh_inode: %s/%s changed mode, %07o to %07o\n",
@@ -354,7 +361,7 @@ smb_put_super(struct super_block *sb)
}
if (server->conn_pid)
- kill_proc(server->conn_pid, SIGTERM, 0);
+ kill_proc(server->conn_pid, SIGTERM, 1);
kfree(server->mnt);
if (server->packet)
@@ -487,7 +494,8 @@ smb_notify_change(struct inode *inode, struct iattr *attr)
struct smb_sb_info *server = SMB_SERVER(inode);
struct dentry *dentry = inode->u.smbfs_i.dentry;
unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
- int error, refresh = 0;
+ int error, changed, refresh = 0;
+ struct smb_fattr fattr;
error = -EIO;
if (!dentry)
@@ -515,14 +523,14 @@ smb_notify_change(struct inode *inode, struct iattr *attr)
if ((attr->ia_valid & ATTR_SIZE) != 0)
{
- error = smb_open(dentry, O_WRONLY);
- if (error)
- goto out;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_notify_change: changing %s/%s, old size=%ld, new size=%ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(long) inode->i_size, (long) attr->ia_size);
#endif
+ error = smb_open(dentry, O_WRONLY);
+ if (error)
+ goto out;
error = smb_proc_trunc(server, inode->u.smbfs_i.fileid,
attr->ia_size);
if (error)
@@ -531,32 +539,76 @@ dentry->d_parent->d_name.name, dentry->d_name.name,
* We don't implement an i_op->truncate operation,
* so we have to update the page cache here.
*/
- if (attr->ia_size < inode->i_size) {
+ if (attr->ia_size < inode->i_size)
+ {
truncate_inode_pages(inode, attr->ia_size);
inode->i_size = attr->ia_size;
}
refresh = 1;
}
- if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
- {
- struct smb_fattr fattr;
-
- smb_get_inode_attr(inode, &fattr);
- if ((attr->ia_valid & ATTR_CTIME) != 0)
- fattr.f_ctime = attr->ia_ctime;
-
- if ((attr->ia_valid & ATTR_MTIME) != 0)
- fattr.f_mtime = attr->ia_mtime;
-
- if ((attr->ia_valid & ATTR_ATIME) != 0)
- fattr.f_atime = attr->ia_atime;
+ /*
+ * Initialize the fattr and check for changed fields.
+ * Note: CTIME under SMB is creation time rather than
+ * change time, so we don't attempt to change it.
+ */
+ smb_get_inode_attr(inode, &fattr);
- error = smb_proc_setattr(server, dentry, &fattr);
+ changed = 0;
+ if ((attr->ia_valid & ATTR_MTIME) != 0)
+ {
+ fattr.f_mtime = attr->ia_mtime;
+ changed = 1;
+ }
+ if ((attr->ia_valid & ATTR_ATIME) != 0)
+ {
+ fattr.f_atime = attr->ia_atime;
+ /* Earlier protocols don't have an access time */
+ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
+ changed = 1;
+ }
+ if (changed)
+ {
+ error = smb_proc_settime(dentry, &fattr);
if (error)
goto out;
refresh = 1;
}
+
+ /*
+ * Check for mode changes ... we're extremely limited in
+ * what can be set for SMB servers: just the read-only bit.
+ */
+ if ((attr->ia_valid & ATTR_MODE) != 0)
+ {
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_notify_change: %s/%s mode change, old=%x, new=%lx\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, fattr.f_mode,attr->ia_mode);
+#endif
+ changed = 0;
+ if (attr->ia_mode & S_IWUSR)
+ {
+ if (fattr.attr & aRONLY)
+ {
+ fattr.attr &= ~aRONLY;
+ changed = 1;
+ }
+ } else
+ {
+ if (!(fattr.attr & aRONLY))
+ {
+ fattr.attr |= aRONLY;
+ changed = 1;
+ }
+ }
+ if (changed)
+ {
+ error = smb_proc_setattr(dentry, &fattr);
+ if (error)
+ goto out;
+ refresh = 1;
+ }
+ }
error = 0;
out: