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
This commit is contained in:
commit
2e5c36722d
|
@ -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 @@
|
||||||
* 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 @@
|
||||||
#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,
|
||||||
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)
|
||||||
/* 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 {
|
||||||
* "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);
|
||||||
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 {
|
||||||
|
|
||||||
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 @@ remote_path_check:
|
||||||
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,
|
||||||
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 @@ out:
|
||||||
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)
|
||||||
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)
|
||||||
* 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 *
|
||||||
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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because we drop the spinlock in the loop in order to put the tlink
|
||||||
|
* it's not guarded against removal of links from the tree. The only
|
||||||
|
* places that remove entries from the tree are this function and
|
||||||
|
* umounts. Because this function is non-reentrant and is canceled
|
||||||
|
* before umount can proceed, this is safe.
|
||||||
|
*/
|
||||||
|
spin_lock(&cifs_sb->tlink_tree_lock);
|
||||||
|
node = rb_first(root);
|
||||||
|
while (node != NULL) {
|
||||||
|
tmp = node;
|
||||||
|
node = rb_next(tmp);
|
||||||
|
tlink = rb_entry(tmp, struct tcon_link, tl_rbnode);
|
||||||
|
|
||||||
|
if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) ||
|
||||||
|
atomic_read(&tlink->tl_count) != 0 ||
|
||||||
|
time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cifs_get_tlink(tlink);
|
||||||
|
clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
|
||||||
|
rb_erase(tmp, root);
|
||||||
|
|
||||||
do {
|
|
||||||
spin_lock(&cifs_sb->tlink_tree_lock);
|
|
||||||
ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
|
|
||||||
(void **)tlink, index,
|
|
||||||
ARRAY_SIZE(tlink));
|
|
||||||
/* increment index for next pass */
|
|
||||||
if (ret > 0)
|
|
||||||
index = tlink[ret - 1]->tl_index + 1;
|
|
||||||
for (i = 0; i < ret; i++) {
|
|
||||||
if (test_bit(TCON_LINK_MASTER, &tlink[i]->tl_flags) ||
|
|
||||||
atomic_read(&tlink[i]->tl_count) != 0 ||
|
|
||||||
time_after(tlink[i]->tl_time + TLINK_IDLE_EXPIRE,
|
|
||||||
now)) {
|
|
||||||
tlink[i] = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
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);
|
spin_unlock(&cifs_sb->tlink_tree_lock);
|
||||||
|
cifs_put_tlink(tlink);
|
||||||
for (i = 0; i < ret; i++) {
|
spin_lock(&cifs_sb->tlink_tree_lock);
|
||||||
if (tlink[i] != NULL)
|
}
|
||||||
cifs_put_tlink(tlink[i]);
|
spin_unlock(&cifs_sb->tlink_tree_lock);
|
||||||
}
|
|
||||||
} while (ret != 0);
|
|
||||||
|
|
||||||
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 @@ client_can_cache:
|
||||||
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,
|
||||||
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,
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
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 @@ reopen_success:
|
||||||
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 @@ reopen_success:
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
#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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue