Commit 2e5c3672 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  cifs: make cifs_set_oplock_level() take a cifsInodeInfo pointer
  cifs: dereferencing first then checking
  cifs: trivial comment fix: tlink_tree is now a rbtree
  [CIFS] Cleanup unused variable build warning
  cifs: convert tlink_tree to a rbtree
  cifs: store pointer to master tlink in superblock (try #2)
  cifs: trivial doc fix: note setlease implemented
  CIFS: Add cifs_set_oplock_level
  FS: cifs, remove unneeded NULL tests
parents e0a70217 c6723628
...@@ -81,7 +81,7 @@ u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for ...@@ -81,7 +81,7 @@ u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for
v) mount check for unmatched uids v) mount check for unmatched uids
w) Add support for new vfs entry points for setlease and fallocate w) Add support for new vfs entry point for fallocate
x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of
processes can proceed better in parallel (on the server) processes can proceed better in parallel (on the server)
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* the GNU Lesser General Public License for more details. * the GNU Lesser General Public License for more details.
* *
*/ */
#include <linux/radix-tree.h> #include <linux/rbtree.h>
#ifndef _CIFS_FS_SB_H #ifndef _CIFS_FS_SB_H
#define _CIFS_FS_SB_H #define _CIFS_FS_SB_H
...@@ -42,9 +42,9 @@ ...@@ -42,9 +42,9 @@
#define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */ #define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */
struct cifs_sb_info { struct cifs_sb_info {
struct radix_tree_root tlink_tree; struct rb_root tlink_tree;
#define CIFS_TLINK_MASTER_TAG 0 /* is "master" (mount) tcon */
spinlock_t tlink_tree_lock; spinlock_t tlink_tree_lock;
struct tcon_link *master_tlink;
struct nls_table *local_nls; struct nls_table *local_nls;
unsigned int rsize; unsigned int rsize;
unsigned int wsize; unsigned int wsize;
......
...@@ -116,7 +116,7 @@ cifs_read_super(struct super_block *sb, void *data, ...@@ -116,7 +116,7 @@ cifs_read_super(struct super_block *sb, void *data,
return -ENOMEM; return -ENOMEM;
spin_lock_init(&cifs_sb->tlink_tree_lock); spin_lock_init(&cifs_sb->tlink_tree_lock);
INIT_RADIX_TREE(&cifs_sb->tlink_tree, GFP_KERNEL); cifs_sb->tlink_tree = RB_ROOT;
rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY); rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY);
if (rc) { if (rc) {
...@@ -321,8 +321,7 @@ cifs_alloc_inode(struct super_block *sb) ...@@ -321,8 +321,7 @@ cifs_alloc_inode(struct super_block *sb)
/* Until the file is open and we have gotten oplock /* Until the file is open and we have gotten oplock
info back from the server, can not assume caching of info back from the server, can not assume caching of
file data or metadata */ file data or metadata */
cifs_inode->clientCanCacheRead = false; cifs_set_oplock_level(cifs_inode, 0);
cifs_inode->clientCanCacheAll = false;
cifs_inode->delete_pending = false; cifs_inode->delete_pending = false;
cifs_inode->invalid_mapping = false; cifs_inode->invalid_mapping = false;
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
......
...@@ -336,7 +336,8 @@ struct cifsTconInfo { ...@@ -336,7 +336,8 @@ struct cifsTconInfo {
* "get" on the container. * "get" on the container.
*/ */
struct tcon_link { struct tcon_link {
unsigned long tl_index; struct rb_node tl_rbnode;
uid_t tl_uid;
unsigned long tl_flags; unsigned long tl_flags;
#define TCON_LINK_MASTER 0 #define TCON_LINK_MASTER 0
#define TCON_LINK_PENDING 1 #define TCON_LINK_PENDING 1
......
...@@ -104,6 +104,7 @@ extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); ...@@ -104,6 +104,7 @@ extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
extern u64 cifs_UnixTimeToNT(struct timespec); extern u64 cifs_UnixTimeToNT(struct timespec);
extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
int offset); int offset);
extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle, extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle,
struct file *file, struct tcon_link *tlink, struct file *file, struct tcon_link *tlink,
......
...@@ -116,6 +116,7 @@ struct smb_vol { ...@@ -116,6 +116,7 @@ struct smb_vol {
static int ipv4_connect(struct TCP_Server_Info *server); static int ipv4_connect(struct TCP_Server_Info *server);
static int ipv6_connect(struct TCP_Server_Info *server); static int ipv6_connect(struct TCP_Server_Info *server);
static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
static void cifs_prune_tlinks(struct work_struct *work); static void cifs_prune_tlinks(struct work_struct *work);
/* /*
...@@ -2900,24 +2901,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2900,24 +2901,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
goto mount_fail_check; goto mount_fail_check;
} }
tlink->tl_index = pSesInfo->linux_uid; tlink->tl_uid = pSesInfo->linux_uid;
tlink->tl_tcon = tcon; tlink->tl_tcon = tcon;
tlink->tl_time = jiffies; tlink->tl_time = jiffies;
set_bit(TCON_LINK_MASTER, &tlink->tl_flags); set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
rc = radix_tree_preload(GFP_KERNEL); cifs_sb->master_tlink = tlink;
if (rc == -ENOMEM) {
kfree(tlink);
goto mount_fail_check;
}
spin_lock(&cifs_sb->tlink_tree_lock); spin_lock(&cifs_sb->tlink_tree_lock);
radix_tree_insert(&cifs_sb->tlink_tree, pSesInfo->linux_uid, tlink); tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
radix_tree_tag_set(&cifs_sb->tlink_tree, pSesInfo->linux_uid,
CIFS_TLINK_MASTER_TAG);
spin_unlock(&cifs_sb->tlink_tree_lock); spin_unlock(&cifs_sb->tlink_tree_lock);
radix_tree_preload_end();
queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
TLINK_IDLE_EXPIRE); TLINK_IDLE_EXPIRE);
...@@ -3107,32 +3100,25 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3107,32 +3100,25 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
int int
cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
{ {
int i, ret; struct rb_root *root = &cifs_sb->tlink_tree;
struct rb_node *node;
struct tcon_link *tlink;
char *tmp; char *tmp;
struct tcon_link *tlink[8];
unsigned long index = 0;
cancel_delayed_work_sync(&cifs_sb->prune_tlinks); cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
do { spin_lock(&cifs_sb->tlink_tree_lock);
spin_lock(&cifs_sb->tlink_tree_lock); while ((node = rb_first(root))) {
ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree, tlink = rb_entry(node, struct tcon_link, tl_rbnode);
(void **)tlink, index, cifs_get_tlink(tlink);
ARRAY_SIZE(tlink)); clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
/* increment index for next pass */ rb_erase(node, root);
if (ret > 0)
index = tlink[ret - 1]->tl_index + 1;
for (i = 0; i < ret; i++) {
cifs_get_tlink(tlink[i]);
clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
radix_tree_delete(&cifs_sb->tlink_tree,
tlink[i]->tl_index);
}
spin_unlock(&cifs_sb->tlink_tree_lock);
for (i = 0; i < ret; i++) spin_unlock(&cifs_sb->tlink_tree_lock);
cifs_put_tlink(tlink[i]); cifs_put_tlink(tlink);
} while (ret != 0); spin_lock(&cifs_sb->tlink_tree_lock);
}
spin_unlock(&cifs_sb->tlink_tree_lock);
tmp = cifs_sb->prepath; tmp = cifs_sb->prepath;
cifs_sb->prepathlen = 0; cifs_sb->prepathlen = 0;
...@@ -3271,22 +3257,10 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) ...@@ -3271,22 +3257,10 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
return tcon; return tcon;
} }
static struct tcon_link * static inline struct tcon_link *
cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb) cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
{ {
struct tcon_link *tlink; return cifs_sb->master_tlink;
unsigned int ret;
spin_lock(&cifs_sb->tlink_tree_lock);
ret = radix_tree_gang_lookup_tag(&cifs_sb->tlink_tree, (void **)&tlink,
0, 1, CIFS_TLINK_MASTER_TAG);
spin_unlock(&cifs_sb->tlink_tree_lock);
/* the master tcon should always be present */
if (ret == 0)
BUG();
return tlink;
} }
struct cifsTconInfo * struct cifsTconInfo *
...@@ -3302,6 +3276,47 @@ cifs_sb_tcon_pending_wait(void *unused) ...@@ -3302,6 +3276,47 @@ cifs_sb_tcon_pending_wait(void *unused)
return signal_pending(current) ? -ERESTARTSYS : 0; return signal_pending(current) ? -ERESTARTSYS : 0;
} }
/* find and return a tlink with given uid */
static struct tcon_link *
tlink_rb_search(struct rb_root *root, uid_t uid)
{
struct rb_node *node = root->rb_node;
struct tcon_link *tlink;
while (node) {
tlink = rb_entry(node, struct tcon_link, tl_rbnode);
if (tlink->tl_uid > uid)
node = node->rb_left;
else if (tlink->tl_uid < uid)
node = node->rb_right;
else
return tlink;
}
return NULL;
}
/* insert a tcon_link into the tree */
static void
tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink)
{
struct rb_node **new = &(root->rb_node), *parent = NULL;
struct tcon_link *tlink;
while (*new) {
tlink = rb_entry(*new, struct tcon_link, tl_rbnode);
parent = *new;
if (tlink->tl_uid > new_tlink->tl_uid)
new = &((*new)->rb_left);
else
new = &((*new)->rb_right);
}
rb_link_node(&new_tlink->tl_rbnode, parent, new);
rb_insert_color(&new_tlink->tl_rbnode, root);
}
/* /*
* Find or construct an appropriate tcon given a cifs_sb and the fsuid of the * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
* current task. * current task.
...@@ -3309,7 +3324,7 @@ cifs_sb_tcon_pending_wait(void *unused) ...@@ -3309,7 +3324,7 @@ cifs_sb_tcon_pending_wait(void *unused)
* If the superblock doesn't refer to a multiuser mount, then just return * If the superblock doesn't refer to a multiuser mount, then just return
* the master tcon for the mount. * the master tcon for the mount.
* *
* First, search the radix tree for an existing tcon for this fsuid. If one * First, search the rbtree for an existing tcon for this fsuid. If one
* exists, then check to see if it's pending construction. If it is then wait * exists, then check to see if it's pending construction. If it is then wait
* for construction to complete. Once it's no longer pending, check to see if * for construction to complete. Once it's no longer pending, check to see if
* it failed and either return an error or retry construction, depending on * it failed and either return an error or retry construction, depending on
...@@ -3322,14 +3337,14 @@ struct tcon_link * ...@@ -3322,14 +3337,14 @@ struct tcon_link *
cifs_sb_tlink(struct cifs_sb_info *cifs_sb) cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
{ {
int ret; int ret;
unsigned long fsuid = (unsigned long) current_fsuid(); uid_t fsuid = current_fsuid();
struct tcon_link *tlink, *newtlink; struct tcon_link *tlink, *newtlink;
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
spin_lock(&cifs_sb->tlink_tree_lock); spin_lock(&cifs_sb->tlink_tree_lock);
tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid); tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
if (tlink) if (tlink)
cifs_get_tlink(tlink); cifs_get_tlink(tlink);
spin_unlock(&cifs_sb->tlink_tree_lock); spin_unlock(&cifs_sb->tlink_tree_lock);
...@@ -3338,36 +3353,24 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb) ...@@ -3338,36 +3353,24 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL); newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
if (newtlink == NULL) if (newtlink == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
newtlink->tl_index = fsuid; newtlink->tl_uid = fsuid;
newtlink->tl_tcon = ERR_PTR(-EACCES); newtlink->tl_tcon = ERR_PTR(-EACCES);
set_bit(TCON_LINK_PENDING, &newtlink->tl_flags); set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags); set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
cifs_get_tlink(newtlink); cifs_get_tlink(newtlink);
ret = radix_tree_preload(GFP_KERNEL);
if (ret != 0) {
kfree(newtlink);
return ERR_PTR(ret);
}
spin_lock(&cifs_sb->tlink_tree_lock); spin_lock(&cifs_sb->tlink_tree_lock);
/* was one inserted after previous search? */ /* was one inserted after previous search? */
tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid); tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
if (tlink) { if (tlink) {
cifs_get_tlink(tlink); cifs_get_tlink(tlink);
spin_unlock(&cifs_sb->tlink_tree_lock); spin_unlock(&cifs_sb->tlink_tree_lock);
radix_tree_preload_end();
kfree(newtlink); kfree(newtlink);
goto wait_for_construction; goto wait_for_construction;
} }
ret = radix_tree_insert(&cifs_sb->tlink_tree, fsuid, newtlink);
spin_unlock(&cifs_sb->tlink_tree_lock);
radix_tree_preload_end();
if (ret) {
kfree(newtlink);
return ERR_PTR(ret);
}
tlink = newtlink; tlink = newtlink;
tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
spin_unlock(&cifs_sb->tlink_tree_lock);
} else { } else {
wait_for_construction: wait_for_construction:
ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING, ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
...@@ -3413,39 +3416,39 @@ cifs_prune_tlinks(struct work_struct *work) ...@@ -3413,39 +3416,39 @@ cifs_prune_tlinks(struct work_struct *work)
{ {
struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info, struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
prune_tlinks.work); prune_tlinks.work);
struct tcon_link *tlink[8]; struct rb_root *root = &cifs_sb->tlink_tree;
unsigned long now = jiffies; struct rb_node *node = rb_first(root);
unsigned long index = 0; struct rb_node *tmp;
int i, ret; struct tcon_link *tlink;
do { /*
spin_lock(&cifs_sb->tlink_tree_lock); * Because we drop the spinlock in the loop in order to put the tlink
ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree, * it's not guarded against removal of links from the tree. The only
(void **)tlink, index, * places that remove entries from the tree are this function and
ARRAY_SIZE(tlink)); * umounts. Because this function is non-reentrant and is canceled
/* increment index for next pass */ * before umount can proceed, this is safe.
if (ret > 0) */
index = tlink[ret - 1]->tl_index + 1; spin_lock(&cifs_sb->tlink_tree_lock);
for (i = 0; i < ret; i++) { node = rb_first(root);
if (test_bit(TCON_LINK_MASTER, &tlink[i]->tl_flags) || while (node != NULL) {
atomic_read(&tlink[i]->tl_count) != 0 || tmp = node;
time_after(tlink[i]->tl_time + TLINK_IDLE_EXPIRE, node = rb_next(tmp);
now)) { tlink = rb_entry(tmp, struct tcon_link, tl_rbnode);
tlink[i] = NULL;
continue; if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) ||
} atomic_read(&tlink->tl_count) != 0 ||
cifs_get_tlink(tlink[i]); time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies))
clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags); continue;
radix_tree_delete(&cifs_sb->tlink_tree,
tlink[i]->tl_index);
}
spin_unlock(&cifs_sb->tlink_tree_lock);
for (i = 0; i < ret; i++) { cifs_get_tlink(tlink);
if (tlink[i] != NULL) clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
cifs_put_tlink(tlink[i]); rb_erase(tmp, root);
}
} while (ret != 0); spin_unlock(&cifs_sb->tlink_tree_lock);
cifs_put_tlink(tlink);
spin_lock(&cifs_sb->tlink_tree_lock);
}
spin_unlock(&cifs_sb->tlink_tree_lock);
queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
TLINK_IDLE_EXPIRE); TLINK_IDLE_EXPIRE);
......
...@@ -146,12 +146,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, ...@@ -146,12 +146,7 @@ static inline int cifs_open_inode_helper(struct inode *inode,
rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
xid, NULL); xid, NULL);
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { cifs_set_oplock_level(pCifsInode, oplock);
pCifsInode->clientCanCacheAll = true;
pCifsInode->clientCanCacheRead = true;
cFYI(1, "Exclusive Oplock granted on inode %p", inode);
} else if ((oplock & 0xF) == OPLOCK_READ)
pCifsInode->clientCanCacheRead = true;
return rc; return rc;
} }
...@@ -253,12 +248,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, ...@@ -253,12 +248,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList); list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
spin_unlock(&cifs_file_list_lock); spin_unlock(&cifs_file_list_lock);
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { cifs_set_oplock_level(pCifsInode, oplock);
pCifsInode->clientCanCacheAll = true;
pCifsInode->clientCanCacheRead = true;
cFYI(1, "Exclusive Oplock inode %p", inode);
} else if ((oplock & 0xF) == OPLOCK_READ)
pCifsInode->clientCanCacheRead = true;
file->private_data = pCifsFile; file->private_data = pCifsFile;
return pCifsFile; return pCifsFile;
...@@ -271,8 +261,9 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, ...@@ -271,8 +261,9 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
*/ */
void cifsFileInfo_put(struct cifsFileInfo *cifs_file) void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
{ {
struct inode *inode = cifs_file->dentry->d_inode;
struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink); struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
struct cifsInodeInfo *cifsi = CIFS_I(cifs_file->dentry->d_inode); struct cifsInodeInfo *cifsi = CIFS_I(inode);
struct cifsLockInfo *li, *tmp; struct cifsLockInfo *li, *tmp;
spin_lock(&cifs_file_list_lock); spin_lock(&cifs_file_list_lock);
...@@ -288,8 +279,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) ...@@ -288,8 +279,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
if (list_empty(&cifsi->openFileList)) { if (list_empty(&cifsi->openFileList)) {
cFYI(1, "closing last open instance for inode %p", cFYI(1, "closing last open instance for inode %p",
cifs_file->dentry->d_inode); cifs_file->dentry->d_inode);
cifsi->clientCanCacheRead = false; cifs_set_oplock_level(cifsi, 0);
cifsi->clientCanCacheAll = false;
} }
spin_unlock(&cifs_file_list_lock); spin_unlock(&cifs_file_list_lock);
...@@ -607,8 +597,6 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush) ...@@ -607,8 +597,6 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
rc = filemap_write_and_wait(inode->i_mapping); rc = filemap_write_and_wait(inode->i_mapping);
mapping_set_error(inode->i_mapping, rc); mapping_set_error(inode->i_mapping, rc);
pCifsInode->clientCanCacheAll = false;
pCifsInode->clientCanCacheRead = false;
if (tcon->unix_ext) if (tcon->unix_ext)
rc = cifs_get_inode_info_unix(&inode, rc = cifs_get_inode_info_unix(&inode,
full_path, inode->i_sb, xid); full_path, inode->i_sb, xid);
...@@ -622,18 +610,9 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush) ...@@ -622,18 +610,9 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
invalidate the current end of file on the server invalidate the current end of file on the server
we can not go to the server to get the new inod we can not go to the server to get the new inod
info */ info */
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = true; cifs_set_oplock_level(pCifsInode, oplock);
pCifsInode->clientCanCacheRead = true;
cFYI(1, "Exclusive Oplock granted on inode %p",
pCifsFile->dentry->d_inode);
} else if ((oplock & 0xF) == OPLOCK_READ) {
pCifsInode->clientCanCacheRead = true;
pCifsInode->clientCanCacheAll = false;
} else {
pCifsInode->clientCanCacheRead = false;
pCifsInode->clientCanCacheAll = false;
}
cifs_relock_file(pCifsFile); cifs_relock_file(pCifsFile);
reopen_error_exit: reopen_error_exit:
...@@ -775,12 +754,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -775,12 +754,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink); tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
if (file->private_data == NULL) {
rc = -EBADF;
FreeXid(xid);
return rc;
}
netfid = ((struct cifsFileInfo *)file->private_data)->netfid; netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
if ((tcon->ses->capabilities & CAP_UNIX) && if ((tcon->ses->capabilities & CAP_UNIX) &&
...@@ -956,6 +929,7 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, ...@@ -956,6 +929,7 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
ssize_t cifs_user_write(struct file *file, const char __user *write_data, ssize_t cifs_user_write(struct file *file, const char __user *write_data,
size_t write_size, loff_t *poffset) size_t write_size, loff_t *poffset)
{ {
struct inode *inode = file->f_path.dentry->d_inode;
int rc = 0; int rc = 0;
unsigned int bytes_written = 0; unsigned int bytes_written = 0;
unsigned int total_written; unsigned int total_written;
...@@ -963,7 +937,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -963,7 +937,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
int xid, long_op; int xid, long_op;
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode); struct cifsInodeInfo *cifsi = CIFS_I(inode);
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
...@@ -1029,21 +1003,17 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -1029,21 +1003,17 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
cifs_stats_bytes_written(pTcon, total_written); cifs_stats_bytes_written(pTcon, total_written);
/* since the write may have blocked check these pointers again */
if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
struct inode *inode = file->f_path.dentry->d_inode;
/* Do not update local mtime - server will set its actual value on write /* Do not update local mtime - server will set its actual value on write
* inode->i_ctime = inode->i_mtime = * inode->i_ctime = inode->i_mtime =
* current_fs_time(inode->i_sb);*/ * current_fs_time(inode->i_sb);*/
if (total_written > 0) { if (total_written > 0) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (*poffset > file->f_path.dentry->d_inode->i_size) if (*poffset > inode->i_size)
i_size_write(file->f_path.dentry->d_inode, i_size_write(inode, *poffset);
*poffset); spin_unlock(&inode->i_lock);
spin_unlock(&inode->i_lock);
}
mark_inode_dirty_sync(file->f_path.dentry->d_inode);
} }
mark_inode_dirty_sync(inode);
FreeXid(xid); FreeXid(xid);
return total_written; return total_written;
} }
...@@ -1178,7 +1148,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1178,7 +1148,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
bool fsuid_only) bool fsuid_only)
{ {
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); struct cifs_sb_info *cifs_sb;
bool any_available = false; bool any_available = false;
int rc; int rc;
...@@ -1192,6 +1162,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1192,6 +1162,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
return NULL; return NULL;
} }
cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
/* only filter by fsuid on multiuser mounts */ /* only filter by fsuid on multiuser mounts */
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
fsuid_only = false; fsuid_only = false;
......
...@@ -63,8 +63,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -63,8 +63,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
case FS_IOC_GETFLAGS: case FS_IOC_GETFLAGS:
if (CIFS_UNIX_EXTATTR_CAP & caps) { if (CIFS_UNIX_EXTATTR_CAP & caps) {
if (pSMBFile == NULL)
break;
rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
&ExtAttrBits, &ExtAttrMask); &ExtAttrBits, &ExtAttrMask);
if (rc == 0) if (rc == 0)
...@@ -80,8 +78,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -80,8 +78,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
rc = -EFAULT; rc = -EFAULT;
break; break;
} }
if (pSMBFile == NULL)
break;
/* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid, /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
extAttrBits, &ExtAttrMask);*/ extAttrBits, &ExtAttrMask);*/
} }
......
...@@ -569,10 +569,9 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) ...@@ -569,10 +569,9 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
cFYI(1, "file id match, oplock break"); cFYI(1, "file id match, oplock break");
pCifsInode = CIFS_I(netfile->dentry->d_inode); pCifsInode = CIFS_I(netfile->dentry->d_inode);
pCifsInode->clientCanCacheAll = false;
if (pSMB->OplockLevel == 0)
pCifsInode->clientCanCacheRead = false;
cifs_set_oplock_level(pCifsInode,
pSMB->OplockLevel);
/* /*
* cifs_oplock_break_put() can't be called * cifs_oplock_break_put() can't be called
* from here. Get reference after queueing * from here. Get reference after queueing
...@@ -722,3 +721,23 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) ...@@ -722,3 +721,23 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
cifs_sb_master_tcon(cifs_sb)->treeName); cifs_sb_master_tcon(cifs_sb)->treeName);
} }
} }
void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
{
oplock &= 0xF;
if (oplock == OPLOCK_EXCLUSIVE) {
cinode->clientCanCacheAll = true;
cinode->clientCanCacheRead = true;
cFYI(1, "Exclusive Oplock granted on inode %p",
&cinode->vfs_inode);
} else if (oplock == OPLOCK_READ) {
cinode->clientCanCacheAll = false;
cinode->clientCanCacheRead = true;
cFYI(1, "Level II Oplock granted on inode %p",
&cinode->vfs_inode);
} else {
cinode->clientCanCacheAll = false;
cinode->clientCanCacheRead = false;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment