|
@@ -169,16 +169,20 @@ posix_open_ret:
|
|
|
|
|
|
static int
|
|
static int
|
|
cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
|
|
cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
|
|
- struct cifs_tcon *tcon, unsigned int f_flags, __u32 *poplock,
|
|
|
|
- __u16 *pnetfid, unsigned int xid)
|
|
|
|
|
|
+ struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock,
|
|
|
|
+ struct cifs_fid *fid, unsigned int xid)
|
|
{
|
|
{
|
|
int rc;
|
|
int rc;
|
|
- int desiredAccess;
|
|
|
|
|
|
+ int desired_access;
|
|
int disposition;
|
|
int disposition;
|
|
int create_options = CREATE_NOT_DIR;
|
|
int create_options = CREATE_NOT_DIR;
|
|
FILE_ALL_INFO *buf;
|
|
FILE_ALL_INFO *buf;
|
|
|
|
+ struct TCP_Server_Info *server = tcon->ses->server;
|
|
|
|
+
|
|
|
|
+ if (!server->ops->open)
|
|
|
|
+ return -ENOSYS;
|
|
|
|
|
|
- desiredAccess = cifs_convert_flags(f_flags);
|
|
|
|
|
|
+ desired_access = cifs_convert_flags(f_flags);
|
|
|
|
|
|
/*********************************************************************
|
|
/*********************************************************************
|
|
* open flag mapping table:
|
|
* open flag mapping table:
|
|
@@ -215,16 +219,9 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
|
|
if (backup_cred(cifs_sb))
|
|
if (backup_cred(cifs_sb))
|
|
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
|
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
|
|
|
|
|
- if (tcon->ses->capabilities & CAP_NT_SMBS)
|
|
|
|
- rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
|
|
|
|
- desiredAccess, create_options, pnetfid, poplock, buf,
|
|
|
|
- cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
|
|
|
|
- & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
|
|
- else
|
|
|
|
- rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
|
|
|
|
- desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
|
|
|
|
- cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
|
|
|
|
- & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
|
|
|
|
+ rc = server->ops->open(xid, tcon, full_path, disposition,
|
|
|
|
+ desired_access, create_options, fid, oplock, buf,
|
|
|
|
+ cifs_sb);
|
|
|
|
|
|
if (rc)
|
|
if (rc)
|
|
goto out;
|
|
goto out;
|
|
@@ -234,7 +231,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
|
|
xid);
|
|
xid);
|
|
else
|
|
else
|
|
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, pnetfid);
|
|
|
|
|
|
+ xid, &fid->netfid);
|
|
|
|
|
|
out:
|
|
out:
|
|
kfree(buf);
|
|
kfree(buf);
|
|
@@ -242,48 +239,62 @@ out:
|
|
}
|
|
}
|
|
|
|
|
|
struct cifsFileInfo *
|
|
struct cifsFileInfo *
|
|
-cifs_new_fileinfo(__u16 fileHandle, struct file *file,
|
|
|
|
|
|
+cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
|
|
struct tcon_link *tlink, __u32 oplock)
|
|
struct tcon_link *tlink, __u32 oplock)
|
|
{
|
|
{
|
|
struct dentry *dentry = file->f_path.dentry;
|
|
struct dentry *dentry = file->f_path.dentry;
|
|
struct inode *inode = dentry->d_inode;
|
|
struct inode *inode = dentry->d_inode;
|
|
- struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
|
|
|
|
- struct cifsFileInfo *pCifsFile;
|
|
|
|
-
|
|
|
|
- pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
|
|
|
- if (pCifsFile == NULL)
|
|
|
|
- return pCifsFile;
|
|
|
|
-
|
|
|
|
- pCifsFile->count = 1;
|
|
|
|
- pCifsFile->netfid = fileHandle;
|
|
|
|
- pCifsFile->pid = current->tgid;
|
|
|
|
- pCifsFile->uid = current_fsuid();
|
|
|
|
- pCifsFile->dentry = dget(dentry);
|
|
|
|
- pCifsFile->f_flags = file->f_flags;
|
|
|
|
- pCifsFile->invalidHandle = false;
|
|
|
|
- pCifsFile->tlink = cifs_get_tlink(tlink);
|
|
|
|
- mutex_init(&pCifsFile->fh_mutex);
|
|
|
|
- INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
|
|
|
|
- INIT_LIST_HEAD(&pCifsFile->llist);
|
|
|
|
|
|
+ struct cifsInodeInfo *cinode = CIFS_I(inode);
|
|
|
|
+ struct cifsFileInfo *cfile;
|
|
|
|
+ struct cifs_fid_locks *fdlocks;
|
|
|
|
+ struct cifs_tcon *tcon = tlink_tcon(tlink);
|
|
|
|
+
|
|
|
|
+ cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
|
|
|
+ if (cfile == NULL)
|
|
|
|
+ return cfile;
|
|
|
|
+
|
|
|
|
+ fdlocks = kzalloc(sizeof(struct cifs_fid_locks), GFP_KERNEL);
|
|
|
|
+ if (!fdlocks) {
|
|
|
|
+ kfree(cfile);
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ INIT_LIST_HEAD(&fdlocks->locks);
|
|
|
|
+ fdlocks->cfile = cfile;
|
|
|
|
+ cfile->llist = fdlocks;
|
|
|
|
+ down_write(&cinode->lock_sem);
|
|
|
|
+ list_add(&fdlocks->llist, &cinode->llist);
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
|
|
+
|
|
|
|
+ cfile->count = 1;
|
|
|
|
+ cfile->pid = current->tgid;
|
|
|
|
+ cfile->uid = current_fsuid();
|
|
|
|
+ cfile->dentry = dget(dentry);
|
|
|
|
+ cfile->f_flags = file->f_flags;
|
|
|
|
+ cfile->invalidHandle = false;
|
|
|
|
+ cfile->tlink = cifs_get_tlink(tlink);
|
|
|
|
+ INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
|
|
|
|
+ mutex_init(&cfile->fh_mutex);
|
|
|
|
|
|
spin_lock(&cifs_file_list_lock);
|
|
spin_lock(&cifs_file_list_lock);
|
|
- list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
|
|
|
|
|
|
+ if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE)
|
|
|
|
+ oplock = fid->pending_open->oplock;
|
|
|
|
+ list_del(&fid->pending_open->olist);
|
|
|
|
+
|
|
|
|
+ tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock);
|
|
|
|
+
|
|
|
|
+ list_add(&cfile->tlist, &tcon->openFileList);
|
|
/* if readable file instance put first in list*/
|
|
/* if readable file instance put first in list*/
|
|
if (file->f_mode & FMODE_READ)
|
|
if (file->f_mode & FMODE_READ)
|
|
- list_add(&pCifsFile->flist, &pCifsInode->openFileList);
|
|
|
|
|
|
+ list_add(&cfile->flist, &cinode->openFileList);
|
|
else
|
|
else
|
|
- list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
|
|
|
|
|
|
+ list_add_tail(&cfile->flist, &cinode->openFileList);
|
|
spin_unlock(&cifs_file_list_lock);
|
|
spin_unlock(&cifs_file_list_lock);
|
|
|
|
|
|
- cifs_set_oplock_level(pCifsInode, oplock);
|
|
|
|
- pCifsInode->can_cache_brlcks = pCifsInode->clientCanCacheAll;
|
|
|
|
-
|
|
|
|
- file->private_data = pCifsFile;
|
|
|
|
- return pCifsFile;
|
|
|
|
|
|
+ file->private_data = cfile;
|
|
|
|
+ return cfile;
|
|
}
|
|
}
|
|
|
|
|
|
-static void cifs_del_lock_waiters(struct cifsLockInfo *lock);
|
|
|
|
-
|
|
|
|
struct cifsFileInfo *
|
|
struct cifsFileInfo *
|
|
cifsFileInfo_get(struct cifsFileInfo *cifs_file)
|
|
cifsFileInfo_get(struct cifsFileInfo *cifs_file)
|
|
{
|
|
{
|
|
@@ -302,9 +313,12 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
|
{
|
|
{
|
|
struct inode *inode = cifs_file->dentry->d_inode;
|
|
struct inode *inode = cifs_file->dentry->d_inode;
|
|
struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
|
|
struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
|
|
|
|
+ struct TCP_Server_Info *server = tcon->ses->server;
|
|
struct cifsInodeInfo *cifsi = CIFS_I(inode);
|
|
struct cifsInodeInfo *cifsi = CIFS_I(inode);
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
struct cifsLockInfo *li, *tmp;
|
|
struct cifsLockInfo *li, *tmp;
|
|
|
|
+ struct cifs_fid fid;
|
|
|
|
+ struct cifs_pending_open open;
|
|
|
|
|
|
spin_lock(&cifs_file_list_lock);
|
|
spin_lock(&cifs_file_list_lock);
|
|
if (--cifs_file->count > 0) {
|
|
if (--cifs_file->count > 0) {
|
|
@@ -312,6 +326,12 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (server->ops->get_lease_key)
|
|
|
|
+ server->ops->get_lease_key(inode, &fid);
|
|
|
|
+
|
|
|
|
+ /* store open in pending opens to make sure we don't miss lease break */
|
|
|
|
+ cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open);
|
|
|
|
+
|
|
/* remove it from the lists */
|
|
/* remove it from the lists */
|
|
list_del(&cifs_file->flist);
|
|
list_del(&cifs_file->flist);
|
|
list_del(&cifs_file->tlist);
|
|
list_del(&cifs_file->tlist);
|
|
@@ -319,13 +339,13 @@ 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);
|
|
-
|
|
|
|
- /* in strict cache mode we need invalidate mapping on the last
|
|
|
|
- close because it may cause a error when we open this file
|
|
|
|
- again and get at least level II oplock */
|
|
|
|
|
|
+ /*
|
|
|
|
+ * In strict cache mode we need invalidate mapping on the last
|
|
|
|
+ * close because it may cause a error when we open this file
|
|
|
|
+ * again and get at least level II oplock.
|
|
|
|
+ */
|
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
|
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
|
|
CIFS_I(inode)->invalid_mapping = true;
|
|
CIFS_I(inode)->invalid_mapping = true;
|
|
-
|
|
|
|
cifs_set_oplock_level(cifsi, 0);
|
|
cifs_set_oplock_level(cifsi, 0);
|
|
}
|
|
}
|
|
spin_unlock(&cifs_file_list_lock);
|
|
spin_unlock(&cifs_file_list_lock);
|
|
@@ -333,23 +353,30 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
|
cancel_work_sync(&cifs_file->oplock_break);
|
|
cancel_work_sync(&cifs_file->oplock_break);
|
|
|
|
|
|
if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
|
|
if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
|
|
|
|
+ struct TCP_Server_Info *server = tcon->ses->server;
|
|
unsigned int xid;
|
|
unsigned int xid;
|
|
- int rc;
|
|
|
|
|
|
+
|
|
xid = get_xid();
|
|
xid = get_xid();
|
|
- rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
|
|
|
|
- free_xid(xid);
|
|
|
|
|
|
+ if (server->ops->close)
|
|
|
|
+ server->ops->close(xid, tcon, &cifs_file->fid);
|
|
|
|
+ _free_xid(xid);
|
|
}
|
|
}
|
|
|
|
|
|
- /* Delete any outstanding lock records. We'll lose them when the file
|
|
|
|
|
|
+ cifs_del_pending_open(&open);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Delete any outstanding lock records. We'll lose them when the file
|
|
* is closed anyway.
|
|
* is closed anyway.
|
|
*/
|
|
*/
|
|
- mutex_lock(&cifsi->lock_mutex);
|
|
|
|
- list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) {
|
|
|
|
|
|
+ down_write(&cifsi->lock_sem);
|
|
|
|
+ list_for_each_entry_safe(li, tmp, &cifs_file->llist->locks, llist) {
|
|
list_del(&li->llist);
|
|
list_del(&li->llist);
|
|
cifs_del_lock_waiters(li);
|
|
cifs_del_lock_waiters(li);
|
|
kfree(li);
|
|
kfree(li);
|
|
}
|
|
}
|
|
- mutex_unlock(&cifsi->lock_mutex);
|
|
|
|
|
|
+ list_del(&cifs_file->llist->llist);
|
|
|
|
+ kfree(cifs_file->llist);
|
|
|
|
+ up_write(&cifsi->lock_sem);
|
|
|
|
|
|
cifs_put_tlink(cifs_file->tlink);
|
|
cifs_put_tlink(cifs_file->tlink);
|
|
dput(cifs_file->dentry);
|
|
dput(cifs_file->dentry);
|
|
@@ -357,17 +384,20 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
|
}
|
|
}
|
|
|
|
|
|
int cifs_open(struct inode *inode, struct file *file)
|
|
int cifs_open(struct inode *inode, struct file *file)
|
|
|
|
+
|
|
{
|
|
{
|
|
int rc = -EACCES;
|
|
int rc = -EACCES;
|
|
unsigned int xid;
|
|
unsigned int xid;
|
|
__u32 oplock;
|
|
__u32 oplock;
|
|
struct cifs_sb_info *cifs_sb;
|
|
struct cifs_sb_info *cifs_sb;
|
|
|
|
+ struct TCP_Server_Info *server;
|
|
struct cifs_tcon *tcon;
|
|
struct cifs_tcon *tcon;
|
|
struct tcon_link *tlink;
|
|
struct tcon_link *tlink;
|
|
- struct cifsFileInfo *pCifsFile = NULL;
|
|
|
|
|
|
+ struct cifsFileInfo *cfile = NULL;
|
|
char *full_path = NULL;
|
|
char *full_path = NULL;
|
|
bool posix_open_ok = false;
|
|
bool posix_open_ok = false;
|
|
- __u16 netfid;
|
|
|
|
|
|
+ struct cifs_fid fid;
|
|
|
|
+ struct cifs_pending_open open;
|
|
|
|
|
|
xid = get_xid();
|
|
xid = get_xid();
|
|
|
|
|
|
@@ -378,6 +408,7 @@ int cifs_open(struct inode *inode, struct file *file)
|
|
return PTR_ERR(tlink);
|
|
return PTR_ERR(tlink);
|
|
}
|
|
}
|
|
tcon = tlink_tcon(tlink);
|
|
tcon = tlink_tcon(tlink);
|
|
|
|
+ server = tcon->ses->server;
|
|
|
|
|
|
full_path = build_path_from_dentry(file->f_path.dentry);
|
|
full_path = build_path_from_dentry(file->f_path.dentry);
|
|
if (full_path == NULL) {
|
|
if (full_path == NULL) {
|
|
@@ -388,7 +419,7 @@ int cifs_open(struct inode *inode, struct file *file)
|
|
cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
|
|
cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
|
|
inode, file->f_flags, full_path);
|
|
inode, file->f_flags, full_path);
|
|
|
|
|
|
- if (tcon->ses->server->oplocks)
|
|
|
|
|
|
+ if (server->oplocks)
|
|
oplock = REQ_OPLOCK;
|
|
oplock = REQ_OPLOCK;
|
|
else
|
|
else
|
|
oplock = 0;
|
|
oplock = 0;
|
|
@@ -399,7 +430,7 @@ int cifs_open(struct inode *inode, struct file *file)
|
|
/* can not refresh inode info since size could be stale */
|
|
/* can not refresh inode info since size could be stale */
|
|
rc = cifs_posix_open(full_path, &inode, inode->i_sb,
|
|
rc = cifs_posix_open(full_path, &inode, inode->i_sb,
|
|
cifs_sb->mnt_file_mode /* ignored */,
|
|
cifs_sb->mnt_file_mode /* ignored */,
|
|
- file->f_flags, &oplock, &netfid, xid);
|
|
|
|
|
|
+ file->f_flags, &oplock, &fid.netfid, xid);
|
|
if (rc == 0) {
|
|
if (rc == 0) {
|
|
cFYI(1, "posix open succeeded");
|
|
cFYI(1, "posix open succeeded");
|
|
posix_open_ok = true;
|
|
posix_open_ok = true;
|
|
@@ -415,20 +446,34 @@ int cifs_open(struct inode *inode, struct file *file)
|
|
} else if ((rc != -EIO) && (rc != -EREMOTE) &&
|
|
} else if ((rc != -EIO) && (rc != -EREMOTE) &&
|
|
(rc != -EOPNOTSUPP)) /* path not found or net err */
|
|
(rc != -EOPNOTSUPP)) /* path not found or net err */
|
|
goto out;
|
|
goto out;
|
|
- /* else fallthrough to retry open the old way on network i/o
|
|
|
|
- or DFS errors */
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Else fallthrough to retry open the old way on network i/o
|
|
|
|
+ * or DFS errors.
|
|
|
|
+ */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (server->ops->get_lease_key)
|
|
|
|
+ server->ops->get_lease_key(inode, &fid);
|
|
|
|
+
|
|
|
|
+ cifs_add_pending_open(&fid, tlink, &open);
|
|
|
|
+
|
|
if (!posix_open_ok) {
|
|
if (!posix_open_ok) {
|
|
|
|
+ if (server->ops->get_lease_key)
|
|
|
|
+ server->ops->get_lease_key(inode, &fid);
|
|
|
|
+
|
|
rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
|
|
rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
|
|
- file->f_flags, &oplock, &netfid, xid);
|
|
|
|
- if (rc)
|
|
|
|
|
|
+ file->f_flags, &oplock, &fid, xid);
|
|
|
|
+ if (rc) {
|
|
|
|
+ cifs_del_pending_open(&open);
|
|
goto out;
|
|
goto out;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
|
|
|
|
- if (pCifsFile == NULL) {
|
|
|
|
- CIFSSMBClose(xid, tcon, netfid);
|
|
|
|
|
|
+ cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
|
|
|
|
+ if (cfile == NULL) {
|
|
|
|
+ if (server->ops->close)
|
|
|
|
+ server->ops->close(xid, tcon, &fid);
|
|
|
|
+ cifs_del_pending_open(&open);
|
|
rc = -ENOMEM;
|
|
rc = -ENOMEM;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
@@ -436,8 +481,10 @@ int cifs_open(struct inode *inode, struct file *file)
|
|
cifs_fscache_set_inode_cookie(inode, file);
|
|
cifs_fscache_set_inode_cookie(inode, file);
|
|
|
|
|
|
if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
|
|
if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
|
|
- /* time to set mode which we can not set earlier due to
|
|
|
|
- problems creating new read-only files */
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Time to set mode which we can not set earlier due to
|
|
|
|
+ * problems creating new read-only files.
|
|
|
|
+ */
|
|
struct cifs_unix_set_info_args args = {
|
|
struct cifs_unix_set_info_args args = {
|
|
.mode = inode->i_mode,
|
|
.mode = inode->i_mode,
|
|
.uid = NO_CHANGE_64,
|
|
.uid = NO_CHANGE_64,
|
|
@@ -447,8 +494,8 @@ int cifs_open(struct inode *inode, struct file *file)
|
|
.mtime = NO_CHANGE_64,
|
|
.mtime = NO_CHANGE_64,
|
|
.device = 0,
|
|
.device = 0,
|
|
};
|
|
};
|
|
- CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid,
|
|
|
|
- pCifsFile->pid);
|
|
|
|
|
|
+ CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid.netfid,
|
|
|
|
+ cfile->pid);
|
|
}
|
|
}
|
|
|
|
|
|
out:
|
|
out:
|
|
@@ -458,59 +505,66 @@ out:
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
-/* Try to reacquire byte range locks that were released when session */
|
|
|
|
-/* to server was lost */
|
|
|
|
|
|
+/*
|
|
|
|
+ * Try to reacquire byte range locks that were released when session
|
|
|
|
+ * to server was lost
|
|
|
|
+ */
|
|
static int cifs_relock_file(struct cifsFileInfo *cifsFile)
|
|
static int cifs_relock_file(struct cifsFileInfo *cifsFile)
|
|
{
|
|
{
|
|
int rc = 0;
|
|
int rc = 0;
|
|
|
|
|
|
-/* BB list all locks open on this file and relock */
|
|
|
|
|
|
+ /* BB list all locks open on this file and relock */
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
-static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
|
|
|
|
|
|
+static int
|
|
|
|
+cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
|
|
{
|
|
{
|
|
int rc = -EACCES;
|
|
int rc = -EACCES;
|
|
unsigned int xid;
|
|
unsigned int xid;
|
|
__u32 oplock;
|
|
__u32 oplock;
|
|
struct cifs_sb_info *cifs_sb;
|
|
struct cifs_sb_info *cifs_sb;
|
|
struct cifs_tcon *tcon;
|
|
struct cifs_tcon *tcon;
|
|
- struct cifsInodeInfo *pCifsInode;
|
|
|
|
|
|
+ struct TCP_Server_Info *server;
|
|
|
|
+ struct cifsInodeInfo *cinode;
|
|
struct inode *inode;
|
|
struct inode *inode;
|
|
char *full_path = NULL;
|
|
char *full_path = NULL;
|
|
- int desiredAccess;
|
|
|
|
|
|
+ int desired_access;
|
|
int disposition = FILE_OPEN;
|
|
int disposition = FILE_OPEN;
|
|
int create_options = CREATE_NOT_DIR;
|
|
int create_options = CREATE_NOT_DIR;
|
|
- __u16 netfid;
|
|
|
|
|
|
+ struct cifs_fid fid;
|
|
|
|
|
|
xid = get_xid();
|
|
xid = get_xid();
|
|
- mutex_lock(&pCifsFile->fh_mutex);
|
|
|
|
- if (!pCifsFile->invalidHandle) {
|
|
|
|
- mutex_unlock(&pCifsFile->fh_mutex);
|
|
|
|
|
|
+ mutex_lock(&cfile->fh_mutex);
|
|
|
|
+ if (!cfile->invalidHandle) {
|
|
|
|
+ mutex_unlock(&cfile->fh_mutex);
|
|
rc = 0;
|
|
rc = 0;
|
|
free_xid(xid);
|
|
free_xid(xid);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
- inode = pCifsFile->dentry->d_inode;
|
|
|
|
|
|
+ inode = cfile->dentry->d_inode;
|
|
cifs_sb = CIFS_SB(inode->i_sb);
|
|
cifs_sb = CIFS_SB(inode->i_sb);
|
|
- tcon = tlink_tcon(pCifsFile->tlink);
|
|
|
|
|
|
+ tcon = tlink_tcon(cfile->tlink);
|
|
|
|
+ server = tcon->ses->server;
|
|
|
|
|
|
-/* can not grab rename sem here because various ops, including
|
|
|
|
- those that already have the rename sem can end up causing writepage
|
|
|
|
- to get called and if the server was down that means we end up here,
|
|
|
|
- and we can never tell if the caller already has the rename_sem */
|
|
|
|
- full_path = build_path_from_dentry(pCifsFile->dentry);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Can not grab rename sem here because various ops, including those
|
|
|
|
+ * that already have the rename sem can end up causing writepage to get
|
|
|
|
+ * called and if the server was down that means we end up here, and we
|
|
|
|
+ * can never tell if the caller already has the rename_sem.
|
|
|
|
+ */
|
|
|
|
+ full_path = build_path_from_dentry(cfile->dentry);
|
|
if (full_path == NULL) {
|
|
if (full_path == NULL) {
|
|
rc = -ENOMEM;
|
|
rc = -ENOMEM;
|
|
- mutex_unlock(&pCifsFile->fh_mutex);
|
|
|
|
|
|
+ mutex_unlock(&cfile->fh_mutex);
|
|
free_xid(xid);
|
|
free_xid(xid);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
- cFYI(1, "inode = 0x%p file flags 0x%x for %s",
|
|
|
|
- inode, pCifsFile->f_flags, full_path);
|
|
|
|
|
|
+ cFYI(1, "inode = 0x%p file flags 0x%x for %s", inode, cfile->f_flags,
|
|
|
|
+ full_path);
|
|
|
|
|
|
if (tcon->ses->server->oplocks)
|
|
if (tcon->ses->server->oplocks)
|
|
oplock = REQ_OPLOCK;
|
|
oplock = REQ_OPLOCK;
|
|
@@ -524,69 +578,72 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
|
|
* O_CREAT, O_EXCL and O_TRUNC already had their effect on the
|
|
* O_CREAT, O_EXCL and O_TRUNC already had their effect on the
|
|
* original open. Must mask them off for a reopen.
|
|
* original open. Must mask them off for a reopen.
|
|
*/
|
|
*/
|
|
- unsigned int oflags = pCifsFile->f_flags &
|
|
|
|
|
|
+ unsigned int oflags = cfile->f_flags &
|
|
~(O_CREAT | O_EXCL | O_TRUNC);
|
|
~(O_CREAT | O_EXCL | O_TRUNC);
|
|
|
|
|
|
rc = cifs_posix_open(full_path, NULL, inode->i_sb,
|
|
rc = cifs_posix_open(full_path, NULL, inode->i_sb,
|
|
- cifs_sb->mnt_file_mode /* ignored */,
|
|
|
|
- oflags, &oplock, &netfid, xid);
|
|
|
|
|
|
+ cifs_sb->mnt_file_mode /* ignored */,
|
|
|
|
+ oflags, &oplock, &fid.netfid, xid);
|
|
if (rc == 0) {
|
|
if (rc == 0) {
|
|
cFYI(1, "posix reopen succeeded");
|
|
cFYI(1, "posix reopen succeeded");
|
|
goto reopen_success;
|
|
goto reopen_success;
|
|
}
|
|
}
|
|
- /* fallthrough to retry open the old way on errors, especially
|
|
|
|
- in the reconnect path it is important to retry hard */
|
|
|
|
|
|
+ /*
|
|
|
|
+ * fallthrough to retry open the old way on errors, especially
|
|
|
|
+ * in the reconnect path it is important to retry hard
|
|
|
|
+ */
|
|
}
|
|
}
|
|
|
|
|
|
- desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
|
|
|
|
|
|
+ desired_access = cifs_convert_flags(cfile->f_flags);
|
|
|
|
|
|
if (backup_cred(cifs_sb))
|
|
if (backup_cred(cifs_sb))
|
|
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
|
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
|
|
|
|
|
- /* Can not refresh inode by passing in file_info buf to be returned
|
|
|
|
- by SMBOpen and then calling get_inode_info with returned buf
|
|
|
|
- since file might have write behind data that needs to be flushed
|
|
|
|
- and server version of file size can be stale. If we knew for sure
|
|
|
|
- that inode was not dirty locally we could do this */
|
|
|
|
|
|
+ if (server->ops->get_lease_key)
|
|
|
|
+ server->ops->get_lease_key(inode, &fid);
|
|
|
|
|
|
- rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
|
|
|
|
- create_options, &netfid, &oplock, NULL,
|
|
|
|
- cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
|
|
|
- CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Can not refresh inode by passing in file_info buf to be returned by
|
|
|
|
+ * CIFSSMBOpen and then calling get_inode_info with returned buf since
|
|
|
|
+ * file might have write behind data that needs to be flushed and server
|
|
|
|
+ * version of file size can be stale. If we knew for sure that inode was
|
|
|
|
+ * not dirty locally we could do this.
|
|
|
|
+ */
|
|
|
|
+ rc = server->ops->open(xid, tcon, full_path, disposition,
|
|
|
|
+ desired_access, create_options, &fid, &oplock,
|
|
|
|
+ NULL, cifs_sb);
|
|
if (rc) {
|
|
if (rc) {
|
|
- mutex_unlock(&pCifsFile->fh_mutex);
|
|
|
|
- cFYI(1, "cifs_open returned 0x%x", rc);
|
|
|
|
|
|
+ mutex_unlock(&cfile->fh_mutex);
|
|
|
|
+ cFYI(1, "cifs_reopen returned 0x%x", rc);
|
|
cFYI(1, "oplock: %d", oplock);
|
|
cFYI(1, "oplock: %d", oplock);
|
|
goto reopen_error_exit;
|
|
goto reopen_error_exit;
|
|
}
|
|
}
|
|
|
|
|
|
reopen_success:
|
|
reopen_success:
|
|
- pCifsFile->netfid = netfid;
|
|
|
|
- pCifsFile->invalidHandle = false;
|
|
|
|
- mutex_unlock(&pCifsFile->fh_mutex);
|
|
|
|
- pCifsInode = CIFS_I(inode);
|
|
|
|
|
|
+ cfile->invalidHandle = false;
|
|
|
|
+ mutex_unlock(&cfile->fh_mutex);
|
|
|
|
+ cinode = CIFS_I(inode);
|
|
|
|
|
|
if (can_flush) {
|
|
if (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);
|
|
|
|
|
|
if (tcon->unix_ext)
|
|
if (tcon->unix_ext)
|
|
- rc = cifs_get_inode_info_unix(&inode,
|
|
|
|
- full_path, inode->i_sb, xid);
|
|
|
|
|
|
+ rc = cifs_get_inode_info_unix(&inode, full_path,
|
|
|
|
+ inode->i_sb, xid);
|
|
else
|
|
else
|
|
- rc = cifs_get_inode_info(&inode,
|
|
|
|
- full_path, NULL, inode->i_sb,
|
|
|
|
- xid, NULL);
|
|
|
|
- } /* else we are writing out data to server already
|
|
|
|
- and could deadlock if we tried to flush data, and
|
|
|
|
- since we do not know if we have data that would
|
|
|
|
- invalidate the current end of file on the server
|
|
|
|
- we can not go to the server to get the new inod
|
|
|
|
- info */
|
|
|
|
-
|
|
|
|
- cifs_set_oplock_level(pCifsInode, oplock);
|
|
|
|
|
|
+ rc = cifs_get_inode_info(&inode, full_path, NULL,
|
|
|
|
+ inode->i_sb, xid, NULL);
|
|
|
|
+ }
|
|
|
|
+ /*
|
|
|
|
+ * Else we are writing out data to server already and could deadlock if
|
|
|
|
+ * we tried to flush data, and since we do not know if we have data that
|
|
|
|
+ * would invalidate the current end of file on the server we can not go
|
|
|
|
+ * to the server to get the new inode info.
|
|
|
|
+ */
|
|
|
|
|
|
- cifs_relock_file(pCifsFile);
|
|
|
|
|
|
+ server->ops->set_fid(cfile, &fid, oplock);
|
|
|
|
+ cifs_relock_file(cfile);
|
|
|
|
|
|
reopen_error_exit:
|
|
reopen_error_exit:
|
|
kfree(full_path);
|
|
kfree(full_path);
|
|
@@ -609,42 +666,48 @@ int cifs_closedir(struct inode *inode, struct file *file)
|
|
{
|
|
{
|
|
int rc = 0;
|
|
int rc = 0;
|
|
unsigned int xid;
|
|
unsigned int xid;
|
|
- struct cifsFileInfo *pCFileStruct = file->private_data;
|
|
|
|
- char *ptmp;
|
|
|
|
|
|
+ struct cifsFileInfo *cfile = file->private_data;
|
|
|
|
+ struct cifs_tcon *tcon;
|
|
|
|
+ struct TCP_Server_Info *server;
|
|
|
|
+ char *buf;
|
|
|
|
|
|
cFYI(1, "Closedir inode = 0x%p", inode);
|
|
cFYI(1, "Closedir inode = 0x%p", inode);
|
|
|
|
|
|
|
|
+ if (cfile == NULL)
|
|
|
|
+ return rc;
|
|
|
|
+
|
|
xid = get_xid();
|
|
xid = get_xid();
|
|
|
|
+ tcon = tlink_tcon(cfile->tlink);
|
|
|
|
+ server = tcon->ses->server;
|
|
|
|
|
|
- if (pCFileStruct) {
|
|
|
|
- struct cifs_tcon *pTcon = tlink_tcon(pCFileStruct->tlink);
|
|
|
|
|
|
+ cFYI(1, "Freeing private data in close dir");
|
|
|
|
+ spin_lock(&cifs_file_list_lock);
|
|
|
|
+ if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
|
|
|
|
+ cfile->invalidHandle = true;
|
|
|
|
+ spin_unlock(&cifs_file_list_lock);
|
|
|
|
+ if (server->ops->close_dir)
|
|
|
|
+ rc = server->ops->close_dir(xid, tcon, &cfile->fid);
|
|
|
|
+ else
|
|
|
|
+ rc = -ENOSYS;
|
|
|
|
+ cFYI(1, "Closing uncompleted readdir with rc %d", rc);
|
|
|
|
+ /* not much we can do if it fails anyway, ignore rc */
|
|
|
|
+ rc = 0;
|
|
|
|
+ } else
|
|
|
|
+ spin_unlock(&cifs_file_list_lock);
|
|
|
|
|
|
- cFYI(1, "Freeing private data in close dir");
|
|
|
|
- spin_lock(&cifs_file_list_lock);
|
|
|
|
- if (!pCFileStruct->srch_inf.endOfSearch &&
|
|
|
|
- !pCFileStruct->invalidHandle) {
|
|
|
|
- pCFileStruct->invalidHandle = true;
|
|
|
|
- spin_unlock(&cifs_file_list_lock);
|
|
|
|
- rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
|
|
|
|
- cFYI(1, "Closing uncompleted readdir with rc %d",
|
|
|
|
- rc);
|
|
|
|
- /* not much we can do if it fails anyway, ignore rc */
|
|
|
|
- rc = 0;
|
|
|
|
- } else
|
|
|
|
- spin_unlock(&cifs_file_list_lock);
|
|
|
|
- ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
|
|
|
|
- if (ptmp) {
|
|
|
|
- cFYI(1, "closedir free smb buf in srch struct");
|
|
|
|
- pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
|
|
|
|
- if (pCFileStruct->srch_inf.smallBuf)
|
|
|
|
- cifs_small_buf_release(ptmp);
|
|
|
|
- else
|
|
|
|
- cifs_buf_release(ptmp);
|
|
|
|
- }
|
|
|
|
- cifs_put_tlink(pCFileStruct->tlink);
|
|
|
|
- kfree(file->private_data);
|
|
|
|
- file->private_data = NULL;
|
|
|
|
|
|
+ buf = cfile->srch_inf.ntwrk_buf_start;
|
|
|
|
+ if (buf) {
|
|
|
|
+ cFYI(1, "closedir free smb buf in srch struct");
|
|
|
|
+ cfile->srch_inf.ntwrk_buf_start = NULL;
|
|
|
|
+ if (cfile->srch_inf.smallBuf)
|
|
|
|
+ cifs_small_buf_release(buf);
|
|
|
|
+ else
|
|
|
|
+ cifs_buf_release(buf);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ cifs_put_tlink(cfile->tlink);
|
|
|
|
+ kfree(file->private_data);
|
|
|
|
+ file->private_data = NULL;
|
|
/* BB can we lock the filestruct while this is going on? */
|
|
/* BB can we lock the filestruct while this is going on? */
|
|
free_xid(xid);
|
|
free_xid(xid);
|
|
return rc;
|
|
return rc;
|
|
@@ -666,7 +729,7 @@ cifs_lock_init(__u64 offset, __u64 length, __u8 type)
|
|
return lock;
|
|
return lock;
|
|
}
|
|
}
|
|
|
|
|
|
-static void
|
|
|
|
|
|
+void
|
|
cifs_del_lock_waiters(struct cifsLockInfo *lock)
|
|
cifs_del_lock_waiters(struct cifsLockInfo *lock)
|
|
{
|
|
{
|
|
struct cifsLockInfo *li, *tmp;
|
|
struct cifsLockInfo *li, *tmp;
|
|
@@ -677,45 +740,47 @@ cifs_del_lock_waiters(struct cifsLockInfo *lock)
|
|
}
|
|
}
|
|
|
|
|
|
static bool
|
|
static bool
|
|
-cifs_find_fid_lock_conflict(struct cifsFileInfo *cfile, __u64 offset,
|
|
|
|
- __u64 length, __u8 type, struct cifsFileInfo *cur,
|
|
|
|
- struct cifsLockInfo **conf_lock)
|
|
|
|
|
|
+cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset,
|
|
|
|
+ __u64 length, __u8 type, struct cifsFileInfo *cfile,
|
|
|
|
+ struct cifsLockInfo **conf_lock, bool rw_check)
|
|
{
|
|
{
|
|
struct cifsLockInfo *li;
|
|
struct cifsLockInfo *li;
|
|
|
|
+ struct cifsFileInfo *cur_cfile = fdlocks->cfile;
|
|
struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
|
|
struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
|
|
|
|
|
|
- list_for_each_entry(li, &cfile->llist, llist) {
|
|
|
|
|
|
+ list_for_each_entry(li, &fdlocks->locks, llist) {
|
|
if (offset + length <= li->offset ||
|
|
if (offset + length <= li->offset ||
|
|
offset >= li->offset + li->length)
|
|
offset >= li->offset + li->length)
|
|
continue;
|
|
continue;
|
|
- else if ((type & server->vals->shared_lock_type) &&
|
|
|
|
- ((server->ops->compare_fids(cur, cfile) &&
|
|
|
|
- current->tgid == li->pid) || type == li->type))
|
|
|
|
|
|
+ if (rw_check && server->ops->compare_fids(cfile, cur_cfile) &&
|
|
|
|
+ current->tgid == li->pid)
|
|
continue;
|
|
continue;
|
|
- else {
|
|
|
|
|
|
+ if ((type & server->vals->shared_lock_type) &&
|
|
|
|
+ ((server->ops->compare_fids(cfile, cur_cfile) &&
|
|
|
|
+ current->tgid == li->pid) || type == li->type))
|
|
|
|
+ continue;
|
|
|
|
+ if (conf_lock)
|
|
*conf_lock = li;
|
|
*conf_lock = li;
|
|
- return true;
|
|
|
|
- }
|
|
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
-static bool
|
|
|
|
|
|
+bool
|
|
cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
|
|
cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
|
|
- __u8 type, struct cifsLockInfo **conf_lock)
|
|
|
|
|
|
+ __u8 type, struct cifsLockInfo **conf_lock,
|
|
|
|
+ bool rw_check)
|
|
{
|
|
{
|
|
bool rc = false;
|
|
bool rc = false;
|
|
- struct cifsFileInfo *fid, *tmp;
|
|
|
|
|
|
+ struct cifs_fid_locks *cur;
|
|
struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
|
|
struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
|
|
|
|
|
|
- spin_lock(&cifs_file_list_lock);
|
|
|
|
- list_for_each_entry_safe(fid, tmp, &cinode->openFileList, flist) {
|
|
|
|
- rc = cifs_find_fid_lock_conflict(fid, offset, length, type,
|
|
|
|
- cfile, conf_lock);
|
|
|
|
|
|
+ list_for_each_entry(cur, &cinode->llist, llist) {
|
|
|
|
+ rc = cifs_find_fid_lock_conflict(cur, offset, length, type,
|
|
|
|
+ cfile, conf_lock, rw_check);
|
|
if (rc)
|
|
if (rc)
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
- spin_unlock(&cifs_file_list_lock);
|
|
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
@@ -737,10 +802,10 @@ cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
|
|
struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
|
|
struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
|
|
bool exist;
|
|
bool exist;
|
|
|
|
|
|
- mutex_lock(&cinode->lock_mutex);
|
|
|
|
|
|
+ down_read(&cinode->lock_sem);
|
|
|
|
|
|
exist = cifs_find_lock_conflict(cfile, offset, length, type,
|
|
exist = cifs_find_lock_conflict(cfile, offset, length, type,
|
|
- &conf_lock);
|
|
|
|
|
|
+ &conf_lock, false);
|
|
if (exist) {
|
|
if (exist) {
|
|
flock->fl_start = conf_lock->offset;
|
|
flock->fl_start = conf_lock->offset;
|
|
flock->fl_end = conf_lock->offset + conf_lock->length - 1;
|
|
flock->fl_end = conf_lock->offset + conf_lock->length - 1;
|
|
@@ -754,7 +819,7 @@ cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length,
|
|
else
|
|
else
|
|
flock->fl_type = F_UNLCK;
|
|
flock->fl_type = F_UNLCK;
|
|
|
|
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_read(&cinode->lock_sem);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -762,9 +827,9 @@ static void
|
|
cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock)
|
|
cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock)
|
|
{
|
|
{
|
|
struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
|
|
struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
|
|
- mutex_lock(&cinode->lock_mutex);
|
|
|
|
- list_add_tail(&lock->llist, &cfile->llist);
|
|
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ down_write(&cinode->lock_sem);
|
|
|
|
+ list_add_tail(&lock->llist, &cfile->llist->locks);
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -784,13 +849,13 @@ cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock,
|
|
|
|
|
|
try_again:
|
|
try_again:
|
|
exist = false;
|
|
exist = false;
|
|
- mutex_lock(&cinode->lock_mutex);
|
|
|
|
|
|
+ down_write(&cinode->lock_sem);
|
|
|
|
|
|
exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length,
|
|
exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length,
|
|
- lock->type, &conf_lock);
|
|
|
|
|
|
+ lock->type, &conf_lock, false);
|
|
if (!exist && cinode->can_cache_brlcks) {
|
|
if (!exist && cinode->can_cache_brlcks) {
|
|
- list_add_tail(&lock->llist, &cfile->llist);
|
|
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ list_add_tail(&lock->llist, &cfile->llist->locks);
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -800,17 +865,17 @@ try_again:
|
|
rc = -EACCES;
|
|
rc = -EACCES;
|
|
else {
|
|
else {
|
|
list_add_tail(&lock->blist, &conf_lock->blist);
|
|
list_add_tail(&lock->blist, &conf_lock->blist);
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
rc = wait_event_interruptible(lock->block_q,
|
|
rc = wait_event_interruptible(lock->block_q,
|
|
(lock->blist.prev == &lock->blist) &&
|
|
(lock->blist.prev == &lock->blist) &&
|
|
(lock->blist.next == &lock->blist));
|
|
(lock->blist.next == &lock->blist));
|
|
if (!rc)
|
|
if (!rc)
|
|
goto try_again;
|
|
goto try_again;
|
|
- mutex_lock(&cinode->lock_mutex);
|
|
|
|
|
|
+ down_write(&cinode->lock_sem);
|
|
list_del_init(&lock->blist);
|
|
list_del_init(&lock->blist);
|
|
}
|
|
}
|
|
|
|
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -831,7 +896,7 @@ cifs_posix_lock_test(struct file *file, struct file_lock *flock)
|
|
if ((flock->fl_flags & FL_POSIX) == 0)
|
|
if ((flock->fl_flags & FL_POSIX) == 0)
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
- mutex_lock(&cinode->lock_mutex);
|
|
|
|
|
|
+ down_read(&cinode->lock_sem);
|
|
posix_test_lock(file, flock);
|
|
posix_test_lock(file, flock);
|
|
|
|
|
|
if (flock->fl_type == F_UNLCK && !cinode->can_cache_brlcks) {
|
|
if (flock->fl_type == F_UNLCK && !cinode->can_cache_brlcks) {
|
|
@@ -839,7 +904,7 @@ cifs_posix_lock_test(struct file *file, struct file_lock *flock)
|
|
rc = 1;
|
|
rc = 1;
|
|
}
|
|
}
|
|
|
|
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_read(&cinode->lock_sem);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -859,14 +924,14 @@ cifs_posix_lock_set(struct file *file, struct file_lock *flock)
|
|
return rc;
|
|
return rc;
|
|
|
|
|
|
try_again:
|
|
try_again:
|
|
- mutex_lock(&cinode->lock_mutex);
|
|
|
|
|
|
+ down_write(&cinode->lock_sem);
|
|
if (!cinode->can_cache_brlcks) {
|
|
if (!cinode->can_cache_brlcks) {
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
rc = posix_lock_file(file, flock, NULL);
|
|
rc = posix_lock_file(file, flock, NULL);
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
if (rc == FILE_LOCK_DEFERRED) {
|
|
if (rc == FILE_LOCK_DEFERRED) {
|
|
rc = wait_event_interruptible(flock->fl_wait, !flock->fl_next);
|
|
rc = wait_event_interruptible(flock->fl_wait, !flock->fl_next);
|
|
if (!rc)
|
|
if (!rc)
|
|
@@ -876,7 +941,7 @@ try_again:
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
-static int
|
|
|
|
|
|
+int
|
|
cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
|
|
cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
|
|
{
|
|
{
|
|
unsigned int xid;
|
|
unsigned int xid;
|
|
@@ -893,9 +958,10 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
|
|
xid = get_xid();
|
|
xid = get_xid();
|
|
tcon = tlink_tcon(cfile->tlink);
|
|
tcon = tlink_tcon(cfile->tlink);
|
|
|
|
|
|
- mutex_lock(&cinode->lock_mutex);
|
|
|
|
|
|
+ /* we are going to update can_cache_brlcks here - need a write access */
|
|
|
|
+ down_write(&cinode->lock_sem);
|
|
if (!cinode->can_cache_brlcks) {
|
|
if (!cinode->can_cache_brlcks) {
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
free_xid(xid);
|
|
free_xid(xid);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
@@ -906,7 +972,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
|
|
*/
|
|
*/
|
|
max_buf = tcon->ses->server->maxBuf;
|
|
max_buf = tcon->ses->server->maxBuf;
|
|
if (!max_buf) {
|
|
if (!max_buf) {
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
free_xid(xid);
|
|
free_xid(xid);
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
@@ -915,7 +981,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
|
|
sizeof(LOCKING_ANDX_RANGE);
|
|
sizeof(LOCKING_ANDX_RANGE);
|
|
buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
|
|
buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
|
|
if (!buf) {
|
|
if (!buf) {
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
free_xid(xid);
|
|
free_xid(xid);
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
@@ -923,7 +989,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
|
|
for (i = 0; i < 2; i++) {
|
|
for (i = 0; i < 2; i++) {
|
|
cur = buf;
|
|
cur = buf;
|
|
num = 0;
|
|
num = 0;
|
|
- list_for_each_entry_safe(li, tmp, &cfile->llist, llist) {
|
|
|
|
|
|
+ list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) {
|
|
if (li->type != types[i])
|
|
if (li->type != types[i])
|
|
continue;
|
|
continue;
|
|
cur->Pid = cpu_to_le16(li->pid);
|
|
cur->Pid = cpu_to_le16(li->pid);
|
|
@@ -932,7 +998,8 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
|
|
cur->OffsetLow = cpu_to_le32((u32)li->offset);
|
|
cur->OffsetLow = cpu_to_le32((u32)li->offset);
|
|
cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32));
|
|
cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32));
|
|
if (++num == max_num) {
|
|
if (++num == max_num) {
|
|
- stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
|
|
|
|
|
|
+ stored_rc = cifs_lockv(xid, tcon,
|
|
|
|
+ cfile->fid.netfid,
|
|
(__u8)li->type, 0, num,
|
|
(__u8)li->type, 0, num,
|
|
buf);
|
|
buf);
|
|
if (stored_rc)
|
|
if (stored_rc)
|
|
@@ -944,7 +1011,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
|
|
}
|
|
}
|
|
|
|
|
|
if (num) {
|
|
if (num) {
|
|
- stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
|
|
|
|
|
|
+ stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid,
|
|
(__u8)types[i], 0, num, buf);
|
|
(__u8)types[i], 0, num, buf);
|
|
if (stored_rc)
|
|
if (stored_rc)
|
|
rc = stored_rc;
|
|
rc = stored_rc;
|
|
@@ -952,7 +1019,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
|
|
}
|
|
}
|
|
|
|
|
|
cinode->can_cache_brlcks = false;
|
|
cinode->can_cache_brlcks = false;
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
|
|
|
|
kfree(buf);
|
|
kfree(buf);
|
|
free_xid(xid);
|
|
free_xid(xid);
|
|
@@ -987,9 +1054,10 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
|
|
|
|
|
|
xid = get_xid();
|
|
xid = get_xid();
|
|
|
|
|
|
- mutex_lock(&cinode->lock_mutex);
|
|
|
|
|
|
+ /* we are going to update can_cache_brlcks here - need a write access */
|
|
|
|
+ down_write(&cinode->lock_sem);
|
|
if (!cinode->can_cache_brlcks) {
|
|
if (!cinode->can_cache_brlcks) {
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
free_xid(xid);
|
|
free_xid(xid);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
@@ -1005,7 +1073,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
|
|
|
|
|
|
/*
|
|
/*
|
|
* Allocating count locks is enough because no FL_POSIX locks can be
|
|
* Allocating count locks is enough because no FL_POSIX locks can be
|
|
- * added to the list while we are holding cinode->lock_mutex that
|
|
|
|
|
|
+ * added to the list while we are holding cinode->lock_sem that
|
|
* protects locking operations of this inode.
|
|
* protects locking operations of this inode.
|
|
*/
|
|
*/
|
|
for (; i < count; i++) {
|
|
for (; i < count; i++) {
|
|
@@ -1038,7 +1106,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
|
|
type = CIFS_WRLCK;
|
|
type = CIFS_WRLCK;
|
|
lck = list_entry(el, struct lock_to_push, llist);
|
|
lck = list_entry(el, struct lock_to_push, llist);
|
|
lck->pid = flock->fl_pid;
|
|
lck->pid = flock->fl_pid;
|
|
- lck->netfid = cfile->netfid;
|
|
|
|
|
|
+ lck->netfid = cfile->fid.netfid;
|
|
lck->length = length;
|
|
lck->length = length;
|
|
lck->type = type;
|
|
lck->type = type;
|
|
lck->offset = flock->fl_start;
|
|
lck->offset = flock->fl_start;
|
|
@@ -1060,7 +1128,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
|
|
|
|
|
|
out:
|
|
out:
|
|
cinode->can_cache_brlcks = false;
|
|
cinode->can_cache_brlcks = false;
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
|
|
|
|
free_xid(xid);
|
|
free_xid(xid);
|
|
return rc;
|
|
return rc;
|
|
@@ -1083,7 +1151,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
|
|
((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
|
|
((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
|
|
return cifs_push_posix_locks(cfile);
|
|
return cifs_push_posix_locks(cfile);
|
|
|
|
|
|
- return cifs_push_mandatory_locks(cfile);
|
|
|
|
|
|
+ return tcon->ses->server->ops->push_mand_locks(cfile);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
@@ -1104,7 +1172,8 @@ cifs_read_flock(struct file_lock *flock, __u32 *type, int *lock, int *unlock,
|
|
if (flock->fl_flags & FL_LEASE)
|
|
if (flock->fl_flags & FL_LEASE)
|
|
cFYI(1, "Lease on file - not implemented yet");
|
|
cFYI(1, "Lease on file - not implemented yet");
|
|
if (flock->fl_flags &
|
|
if (flock->fl_flags &
|
|
- (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
|
|
|
|
|
|
+ (~(FL_POSIX | FL_FLOCK | FL_SLEEP |
|
|
|
|
+ FL_ACCESS | FL_LEASE | FL_CLOSE)))
|
|
cFYI(1, "Unknown lock flags 0x%x", flock->fl_flags);
|
|
cFYI(1, "Unknown lock flags 0x%x", flock->fl_flags);
|
|
|
|
|
|
*type = server->vals->large_lock_type;
|
|
*type = server->vals->large_lock_type;
|
|
@@ -1133,15 +1202,6 @@ cifs_read_flock(struct file_lock *flock, __u32 *type, int *lock, int *unlock,
|
|
cFYI(1, "Unknown type of lock");
|
|
cFYI(1, "Unknown type of lock");
|
|
}
|
|
}
|
|
|
|
|
|
-static int
|
|
|
|
-cifs_mandatory_lock(unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
|
|
|
|
- __u64 length, __u32 type, int lock, int unlock, bool wait)
|
|
|
|
-{
|
|
|
|
- return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->netfid,
|
|
|
|
- current->tgid, length, offset, unlock, lock,
|
|
|
|
- (__u8)type, wait, 0);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int
|
|
static int
|
|
cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
|
|
cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
|
|
bool wait_flag, bool posix_lck, unsigned int xid)
|
|
bool wait_flag, bool posix_lck, unsigned int xid)
|
|
@@ -1151,7 +1211,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
|
|
struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
|
|
struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
|
|
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
|
|
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
|
|
struct TCP_Server_Info *server = tcon->ses->server;
|
|
struct TCP_Server_Info *server = tcon->ses->server;
|
|
- __u16 netfid = cfile->netfid;
|
|
|
|
|
|
+ __u16 netfid = cfile->fid.netfid;
|
|
|
|
|
|
if (posix_lck) {
|
|
if (posix_lck) {
|
|
int posix_lock_type;
|
|
int posix_lock_type;
|
|
@@ -1175,11 +1235,11 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
|
|
return rc;
|
|
return rc;
|
|
|
|
|
|
/* BB we could chain these into one lock request BB */
|
|
/* BB we could chain these into one lock request BB */
|
|
- rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length, type,
|
|
|
|
- 1, 0, false);
|
|
|
|
|
|
+ rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, type,
|
|
|
|
+ 1, 0, false);
|
|
if (rc == 0) {
|
|
if (rc == 0) {
|
|
- rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length,
|
|
|
|
- type, 0, 1, false);
|
|
|
|
|
|
+ rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
|
|
|
|
+ type, 0, 1, false);
|
|
flock->fl_type = F_UNLCK;
|
|
flock->fl_type = F_UNLCK;
|
|
if (rc != 0)
|
|
if (rc != 0)
|
|
cERROR(1, "Error unlocking previously locked "
|
|
cERROR(1, "Error unlocking previously locked "
|
|
@@ -1192,13 +1252,14 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length,
|
|
|
|
- type | server->vals->shared_lock_type, 1, 0,
|
|
|
|
- false);
|
|
|
|
|
|
+ type &= ~server->vals->exclusive_lock_type;
|
|
|
|
+
|
|
|
|
+ rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
|
|
|
|
+ type | server->vals->shared_lock_type,
|
|
|
|
+ 1, 0, false);
|
|
if (rc == 0) {
|
|
if (rc == 0) {
|
|
- rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length,
|
|
|
|
- type | server->vals->shared_lock_type,
|
|
|
|
- 0, 1, false);
|
|
|
|
|
|
+ rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
|
|
|
|
+ type | server->vals->shared_lock_type, 0, 1, false);
|
|
flock->fl_type = F_RDLCK;
|
|
flock->fl_type = F_RDLCK;
|
|
if (rc != 0)
|
|
if (rc != 0)
|
|
cERROR(1, "Error unlocking previously locked "
|
|
cERROR(1, "Error unlocking previously locked "
|
|
@@ -1209,7 +1270,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static void
|
|
|
|
|
|
+void
|
|
cifs_move_llist(struct list_head *source, struct list_head *dest)
|
|
cifs_move_llist(struct list_head *source, struct list_head *dest)
|
|
{
|
|
{
|
|
struct list_head *li, *tmp;
|
|
struct list_head *li, *tmp;
|
|
@@ -1217,7 +1278,7 @@ cifs_move_llist(struct list_head *source, struct list_head *dest)
|
|
list_move(li, dest);
|
|
list_move(li, dest);
|
|
}
|
|
}
|
|
|
|
|
|
-static void
|
|
|
|
|
|
+void
|
|
cifs_free_llist(struct list_head *llist)
|
|
cifs_free_llist(struct list_head *llist)
|
|
{
|
|
{
|
|
struct cifsLockInfo *li, *tmp;
|
|
struct cifsLockInfo *li, *tmp;
|
|
@@ -1228,7 +1289,7 @@ cifs_free_llist(struct list_head *llist)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static int
|
|
|
|
|
|
+int
|
|
cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
|
|
cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
|
|
unsigned int xid)
|
|
unsigned int xid)
|
|
{
|
|
{
|
|
@@ -1260,11 +1321,11 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
|
|
if (!buf)
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
- mutex_lock(&cinode->lock_mutex);
|
|
|
|
|
|
+ down_write(&cinode->lock_sem);
|
|
for (i = 0; i < 2; i++) {
|
|
for (i = 0; i < 2; i++) {
|
|
cur = buf;
|
|
cur = buf;
|
|
num = 0;
|
|
num = 0;
|
|
- list_for_each_entry_safe(li, tmp, &cfile->llist, llist) {
|
|
|
|
|
|
+ list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) {
|
|
if (flock->fl_start > li->offset ||
|
|
if (flock->fl_start > li->offset ||
|
|
(flock->fl_start + length) <
|
|
(flock->fl_start + length) <
|
|
(li->offset + li->length))
|
|
(li->offset + li->length))
|
|
@@ -1295,7 +1356,8 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
|
|
*/
|
|
*/
|
|
list_move(&li->llist, &tmp_llist);
|
|
list_move(&li->llist, &tmp_llist);
|
|
if (++num == max_num) {
|
|
if (++num == max_num) {
|
|
- stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
|
|
|
|
|
|
+ stored_rc = cifs_lockv(xid, tcon,
|
|
|
|
+ cfile->fid.netfid,
|
|
li->type, num, 0, buf);
|
|
li->type, num, 0, buf);
|
|
if (stored_rc) {
|
|
if (stored_rc) {
|
|
/*
|
|
/*
|
|
@@ -1304,7 +1366,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
|
|
* list to the head of the file's list.
|
|
* list to the head of the file's list.
|
|
*/
|
|
*/
|
|
cifs_move_llist(&tmp_llist,
|
|
cifs_move_llist(&tmp_llist,
|
|
- &cfile->llist);
|
|
|
|
|
|
+ &cfile->llist->locks);
|
|
rc = stored_rc;
|
|
rc = stored_rc;
|
|
} else
|
|
} else
|
|
/*
|
|
/*
|
|
@@ -1318,23 +1380,24 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
|
|
cur++;
|
|
cur++;
|
|
}
|
|
}
|
|
if (num) {
|
|
if (num) {
|
|
- stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
|
|
|
|
|
|
+ stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid,
|
|
types[i], num, 0, buf);
|
|
types[i], num, 0, buf);
|
|
if (stored_rc) {
|
|
if (stored_rc) {
|
|
- cifs_move_llist(&tmp_llist, &cfile->llist);
|
|
|
|
|
|
+ cifs_move_llist(&tmp_llist,
|
|
|
|
+ &cfile->llist->locks);
|
|
rc = stored_rc;
|
|
rc = stored_rc;
|
|
} else
|
|
} else
|
|
cifs_free_llist(&tmp_llist);
|
|
cifs_free_llist(&tmp_llist);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- mutex_unlock(&cinode->lock_mutex);
|
|
|
|
|
|
+ up_write(&cinode->lock_sem);
|
|
kfree(buf);
|
|
kfree(buf);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
static int
|
|
-cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
|
|
|
|
|
|
+cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
|
|
bool wait_flag, bool posix_lck, int lock, int unlock,
|
|
bool wait_flag, bool posix_lck, int lock, int unlock,
|
|
unsigned int xid)
|
|
unsigned int xid)
|
|
{
|
|
{
|
|
@@ -1343,7 +1406,6 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
|
|
struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
|
|
struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
|
|
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
|
|
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
|
|
struct TCP_Server_Info *server = tcon->ses->server;
|
|
struct TCP_Server_Info *server = tcon->ses->server;
|
|
- __u16 netfid = cfile->netfid;
|
|
|
|
|
|
|
|
if (posix_lck) {
|
|
if (posix_lck) {
|
|
int posix_lock_type;
|
|
int posix_lock_type;
|
|
@@ -1360,9 +1422,9 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
|
|
if (unlock == 1)
|
|
if (unlock == 1)
|
|
posix_lock_type = CIFS_UNLCK;
|
|
posix_lock_type = CIFS_UNLCK;
|
|
|
|
|
|
- rc = CIFSSMBPosixLock(xid, tcon, netfid, current->tgid,
|
|
|
|
- flock->fl_start, length, NULL,
|
|
|
|
- posix_lock_type, wait_flag);
|
|
|
|
|
|
+ rc = CIFSSMBPosixLock(xid, tcon, cfile->fid.netfid,
|
|
|
|
+ current->tgid, flock->fl_start, length,
|
|
|
|
+ NULL, posix_lock_type, wait_flag);
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1379,8 +1441,8 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
|
|
if (rc <= 0)
|
|
if (rc <= 0)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length,
|
|
|
|
- type, 1, 0, wait_flag);
|
|
|
|
|
|
+ rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
|
|
|
|
+ type, 1, 0, wait_flag);
|
|
if (rc) {
|
|
if (rc) {
|
|
kfree(lock);
|
|
kfree(lock);
|
|
goto out;
|
|
goto out;
|
|
@@ -1388,7 +1450,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
|
|
|
|
|
|
cifs_lock_add(cfile, lock);
|
|
cifs_lock_add(cfile, lock);
|
|
} else if (unlock)
|
|
} else if (unlock)
|
|
- rc = cifs_unlock_range(cfile, flock, xid);
|
|
|
|
|
|
+ rc = server->ops->mand_unlock_range(cfile, flock, xid);
|
|
|
|
|
|
out:
|
|
out:
|
|
if (flock->fl_flags & FL_POSIX)
|
|
if (flock->fl_flags & FL_POSIX)
|
|
@@ -1423,7 +1485,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
|
|
tcon->ses->server);
|
|
tcon->ses->server);
|
|
|
|
|
|
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
|
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
|
- netfid = cfile->netfid;
|
|
|
|
|
|
+ netfid = cfile->fid.netfid;
|
|
cinode = CIFS_I(file->f_path.dentry->d_inode);
|
|
cinode = CIFS_I(file->f_path.dentry->d_inode);
|
|
|
|
|
|
if (cap_unix(tcon->ses) &&
|
|
if (cap_unix(tcon->ses) &&
|
|
@@ -1469,15 +1531,16 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
|
|
cifsi->server_eof = end_of_write;
|
|
cifsi->server_eof = end_of_write;
|
|
}
|
|
}
|
|
|
|
|
|
-static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
|
|
|
|
- const char *write_data, size_t write_size,
|
|
|
|
- loff_t *poffset)
|
|
|
|
|
|
+static ssize_t
|
|
|
|
+cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data,
|
|
|
|
+ size_t write_size, loff_t *offset)
|
|
{
|
|
{
|
|
int rc = 0;
|
|
int rc = 0;
|
|
unsigned int bytes_written = 0;
|
|
unsigned int bytes_written = 0;
|
|
unsigned int total_written;
|
|
unsigned int total_written;
|
|
struct cifs_sb_info *cifs_sb;
|
|
struct cifs_sb_info *cifs_sb;
|
|
- struct cifs_tcon *pTcon;
|
|
|
|
|
|
+ struct cifs_tcon *tcon;
|
|
|
|
+ struct TCP_Server_Info *server;
|
|
unsigned int xid;
|
|
unsigned int xid;
|
|
struct dentry *dentry = open_file->dentry;
|
|
struct dentry *dentry = open_file->dentry;
|
|
struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
|
|
struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
|
|
@@ -1486,9 +1549,13 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
|
|
cifs_sb = CIFS_SB(dentry->d_sb);
|
|
cifs_sb = CIFS_SB(dentry->d_sb);
|
|
|
|
|
|
cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
|
|
cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
|
|
- *poffset, dentry->d_name.name);
|
|
|
|
|
|
+ *offset, dentry->d_name.name);
|
|
|
|
|
|
- pTcon = tlink_tcon(open_file->tlink);
|
|
|
|
|
|
+ tcon = tlink_tcon(open_file->tlink);
|
|
|
|
+ server = tcon->ses->server;
|
|
|
|
+
|
|
|
|
+ if (!server->ops->sync_write)
|
|
|
|
+ return -ENOSYS;
|
|
|
|
|
|
xid = get_xid();
|
|
xid = get_xid();
|
|
|
|
|
|
@@ -1514,13 +1581,12 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
|
|
/* iov[0] is reserved for smb header */
|
|
/* iov[0] is reserved for smb header */
|
|
iov[1].iov_base = (char *)write_data + total_written;
|
|
iov[1].iov_base = (char *)write_data + total_written;
|
|
iov[1].iov_len = len;
|
|
iov[1].iov_len = len;
|
|
- io_parms.netfid = open_file->netfid;
|
|
|
|
io_parms.pid = pid;
|
|
io_parms.pid = pid;
|
|
- io_parms.tcon = pTcon;
|
|
|
|
- io_parms.offset = *poffset;
|
|
|
|
|
|
+ io_parms.tcon = tcon;
|
|
|
|
+ io_parms.offset = *offset;
|
|
io_parms.length = len;
|
|
io_parms.length = len;
|
|
- rc = CIFSSMBWrite2(xid, &io_parms, &bytes_written, iov,
|
|
|
|
- 1, 0);
|
|
|
|
|
|
+ rc = server->ops->sync_write(xid, open_file, &io_parms,
|
|
|
|
+ &bytes_written, iov, 1);
|
|
}
|
|
}
|
|
if (rc || (bytes_written == 0)) {
|
|
if (rc || (bytes_written == 0)) {
|
|
if (total_written)
|
|
if (total_written)
|
|
@@ -1531,18 +1597,18 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
spin_lock(&dentry->d_inode->i_lock);
|
|
spin_lock(&dentry->d_inode->i_lock);
|
|
- cifs_update_eof(cifsi, *poffset, bytes_written);
|
|
|
|
|
|
+ cifs_update_eof(cifsi, *offset, bytes_written);
|
|
spin_unlock(&dentry->d_inode->i_lock);
|
|
spin_unlock(&dentry->d_inode->i_lock);
|
|
- *poffset += bytes_written;
|
|
|
|
|
|
+ *offset += bytes_written;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- cifs_stats_bytes_written(pTcon, total_written);
|
|
|
|
|
|
+ cifs_stats_bytes_written(tcon, total_written);
|
|
|
|
|
|
if (total_written > 0) {
|
|
if (total_written > 0) {
|
|
spin_lock(&dentry->d_inode->i_lock);
|
|
spin_lock(&dentry->d_inode->i_lock);
|
|
- if (*poffset > dentry->d_inode->i_size)
|
|
|
|
- i_size_write(dentry->d_inode, *poffset);
|
|
|
|
|
|
+ if (*offset > dentry->d_inode->i_size)
|
|
|
|
+ i_size_write(dentry->d_inode, *offset);
|
|
spin_unlock(&dentry->d_inode->i_lock);
|
|
spin_unlock(&dentry->d_inode->i_lock);
|
|
}
|
|
}
|
|
mark_inode_dirty_sync(dentry->d_inode);
|
|
mark_inode_dirty_sync(dentry->d_inode);
|
|
@@ -1718,27 +1784,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * Marshal up the iov array, reserving the first one for the header. Also,
|
|
|
|
- * set wdata->bytes.
|
|
|
|
- */
|
|
|
|
-static void
|
|
|
|
-cifs_writepages_marshal_iov(struct kvec *iov, struct cifs_writedata *wdata)
|
|
|
|
-{
|
|
|
|
- int i;
|
|
|
|
- struct inode *inode = wdata->cfile->dentry->d_inode;
|
|
|
|
- loff_t size = i_size_read(inode);
|
|
|
|
-
|
|
|
|
- /* marshal up the pages into iov array */
|
|
|
|
- wdata->bytes = 0;
|
|
|
|
- for (i = 0; i < wdata->nr_pages; i++) {
|
|
|
|
- iov[i + 1].iov_len = min(size - page_offset(wdata->pages[i]),
|
|
|
|
- (loff_t)PAGE_CACHE_SIZE);
|
|
|
|
- iov[i + 1].iov_base = kmap(wdata->pages[i]);
|
|
|
|
- wdata->bytes += iov[i + 1].iov_len;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int cifs_writepages(struct address_space *mapping,
|
|
static int cifs_writepages(struct address_space *mapping,
|
|
struct writeback_control *wbc)
|
|
struct writeback_control *wbc)
|
|
{
|
|
{
|
|
@@ -1746,8 +1791,10 @@ static int cifs_writepages(struct address_space *mapping,
|
|
bool done = false, scanned = false, range_whole = false;
|
|
bool done = false, scanned = false, range_whole = false;
|
|
pgoff_t end, index;
|
|
pgoff_t end, index;
|
|
struct cifs_writedata *wdata;
|
|
struct cifs_writedata *wdata;
|
|
|
|
+ struct TCP_Server_Info *server;
|
|
struct page *page;
|
|
struct page *page;
|
|
int rc = 0;
|
|
int rc = 0;
|
|
|
|
+ loff_t isize = i_size_read(mapping->host);
|
|
|
|
|
|
/*
|
|
/*
|
|
* If wsize is smaller than the page cache size, default to writing
|
|
* If wsize is smaller than the page cache size, default to writing
|
|
@@ -1852,7 +1899,7 @@ retry:
|
|
*/
|
|
*/
|
|
set_page_writeback(page);
|
|
set_page_writeback(page);
|
|
|
|
|
|
- if (page_offset(page) >= mapping->host->i_size) {
|
|
|
|
|
|
+ if (page_offset(page) >= isize) {
|
|
done = true;
|
|
done = true;
|
|
unlock_page(page);
|
|
unlock_page(page);
|
|
end_page_writeback(page);
|
|
end_page_writeback(page);
|
|
@@ -1883,7 +1930,12 @@ retry:
|
|
wdata->sync_mode = wbc->sync_mode;
|
|
wdata->sync_mode = wbc->sync_mode;
|
|
wdata->nr_pages = nr_pages;
|
|
wdata->nr_pages = nr_pages;
|
|
wdata->offset = page_offset(wdata->pages[0]);
|
|
wdata->offset = page_offset(wdata->pages[0]);
|
|
- wdata->marshal_iov = cifs_writepages_marshal_iov;
|
|
|
|
|
|
+ wdata->pagesz = PAGE_CACHE_SIZE;
|
|
|
|
+ wdata->tailsz =
|
|
|
|
+ min(isize - page_offset(wdata->pages[nr_pages - 1]),
|
|
|
|
+ (loff_t)PAGE_CACHE_SIZE);
|
|
|
|
+ wdata->bytes = ((nr_pages - 1) * PAGE_CACHE_SIZE) +
|
|
|
|
+ wdata->tailsz;
|
|
|
|
|
|
do {
|
|
do {
|
|
if (wdata->cfile != NULL)
|
|
if (wdata->cfile != NULL)
|
|
@@ -1896,7 +1948,8 @@ retry:
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
wdata->pid = wdata->cfile->pid;
|
|
wdata->pid = wdata->cfile->pid;
|
|
- rc = cifs_async_writev(wdata);
|
|
|
|
|
|
+ server = tlink_tcon(wdata->cfile->tlink)->ses->server;
|
|
|
|
+ rc = server->ops->async_writev(wdata);
|
|
} while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
|
|
} while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
|
|
|
|
|
|
for (i = 0; i < nr_pages; ++i)
|
|
for (i = 0; i < nr_pages; ++i)
|
|
@@ -2054,6 +2107,7 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
|
|
unsigned int xid;
|
|
unsigned int xid;
|
|
int rc = 0;
|
|
int rc = 0;
|
|
struct cifs_tcon *tcon;
|
|
struct cifs_tcon *tcon;
|
|
|
|
+ struct TCP_Server_Info *server;
|
|
struct cifsFileInfo *smbfile = file->private_data;
|
|
struct cifsFileInfo *smbfile = file->private_data;
|
|
struct inode *inode = file->f_path.dentry->d_inode;
|
|
struct inode *inode = file->f_path.dentry->d_inode;
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
@@ -2077,8 +2131,13 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
|
|
}
|
|
}
|
|
|
|
|
|
tcon = tlink_tcon(smbfile->tlink);
|
|
tcon = tlink_tcon(smbfile->tlink);
|
|
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
|
|
|
|
- rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
|
|
|
|
|
|
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
|
|
|
|
+ server = tcon->ses->server;
|
|
|
|
+ if (server->ops->flush)
|
|
|
|
+ rc = server->ops->flush(xid, tcon, &smbfile->fid);
|
|
|
|
+ else
|
|
|
|
+ rc = -ENOSYS;
|
|
|
|
+ }
|
|
|
|
|
|
free_xid(xid);
|
|
free_xid(xid);
|
|
mutex_unlock(&inode->i_mutex);
|
|
mutex_unlock(&inode->i_mutex);
|
|
@@ -2090,6 +2149,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
|
unsigned int xid;
|
|
unsigned int xid;
|
|
int rc = 0;
|
|
int rc = 0;
|
|
struct cifs_tcon *tcon;
|
|
struct cifs_tcon *tcon;
|
|
|
|
+ struct TCP_Server_Info *server;
|
|
struct cifsFileInfo *smbfile = file->private_data;
|
|
struct cifsFileInfo *smbfile = file->private_data;
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
|
struct inode *inode = file->f_mapping->host;
|
|
struct inode *inode = file->f_mapping->host;
|
|
@@ -2105,8 +2165,13 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
|
file->f_path.dentry->d_name.name, datasync);
|
|
file->f_path.dentry->d_name.name, datasync);
|
|
|
|
|
|
tcon = tlink_tcon(smbfile->tlink);
|
|
tcon = tlink_tcon(smbfile->tlink);
|
|
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
|
|
|
|
- rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
|
|
|
|
|
|
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
|
|
|
|
+ server = tcon->ses->server;
|
|
|
|
+ if (server->ops->flush)
|
|
|
|
+ rc = server->ops->flush(xid, tcon, &smbfile->fid);
|
|
|
|
+ else
|
|
|
|
+ rc = -ENOSYS;
|
|
|
|
+ }
|
|
|
|
|
|
free_xid(xid);
|
|
free_xid(xid);
|
|
mutex_unlock(&inode->i_mutex);
|
|
mutex_unlock(&inode->i_mutex);
|
|
@@ -2171,20 +2236,6 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
|
|
return num_pages;
|
|
return num_pages;
|
|
}
|
|
}
|
|
|
|
|
|
-static void
|
|
|
|
-cifs_uncached_marshal_iov(struct kvec *iov, struct cifs_writedata *wdata)
|
|
|
|
-{
|
|
|
|
- int i;
|
|
|
|
- size_t bytes = wdata->bytes;
|
|
|
|
-
|
|
|
|
- /* marshal up the pages into iov array */
|
|
|
|
- for (i = 0; i < wdata->nr_pages; i++) {
|
|
|
|
- iov[i + 1].iov_len = min_t(size_t, bytes, PAGE_SIZE);
|
|
|
|
- iov[i + 1].iov_base = kmap(wdata->pages[i]);
|
|
|
|
- bytes -= iov[i + 1].iov_len;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void
|
|
static void
|
|
cifs_uncached_writev_complete(struct work_struct *work)
|
|
cifs_uncached_writev_complete(struct work_struct *work)
|
|
{
|
|
{
|
|
@@ -2215,6 +2266,9 @@ static int
|
|
cifs_uncached_retry_writev(struct cifs_writedata *wdata)
|
|
cifs_uncached_retry_writev(struct cifs_writedata *wdata)
|
|
{
|
|
{
|
|
int rc;
|
|
int rc;
|
|
|
|
+ struct TCP_Server_Info *server;
|
|
|
|
+
|
|
|
|
+ server = tlink_tcon(wdata->cfile->tlink)->ses->server;
|
|
|
|
|
|
do {
|
|
do {
|
|
if (wdata->cfile->invalidHandle) {
|
|
if (wdata->cfile->invalidHandle) {
|
|
@@ -2222,7 +2276,7 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata)
|
|
if (rc != 0)
|
|
if (rc != 0)
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
- rc = cifs_async_writev(wdata);
|
|
|
|
|
|
+ rc = server->ops->async_writev(wdata);
|
|
} while (rc == -EAGAIN);
|
|
} while (rc == -EAGAIN);
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
@@ -2257,6 +2311,10 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
|
|
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
|
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
|
open_file = file->private_data;
|
|
open_file = file->private_data;
|
|
tcon = tlink_tcon(open_file->tlink);
|
|
tcon = tlink_tcon(open_file->tlink);
|
|
|
|
+
|
|
|
|
+ if (!tcon->ses->server->ops->async_writev)
|
|
|
|
+ return -ENOSYS;
|
|
|
|
+
|
|
offset = *poffset;
|
|
offset = *poffset;
|
|
|
|
|
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
|
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
|
|
@@ -2298,7 +2356,8 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
|
|
wdata->cfile = cifsFileInfo_get(open_file);
|
|
wdata->cfile = cifsFileInfo_get(open_file);
|
|
wdata->pid = pid;
|
|
wdata->pid = pid;
|
|
wdata->bytes = cur_len;
|
|
wdata->bytes = cur_len;
|
|
- wdata->marshal_iov = cifs_uncached_marshal_iov;
|
|
|
|
|
|
+ wdata->pagesz = PAGE_SIZE;
|
|
|
|
+ wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
|
|
rc = cifs_uncached_retry_writev(wdata);
|
|
rc = cifs_uncached_retry_writev(wdata);
|
|
if (rc) {
|
|
if (rc) {
|
|
kref_put(&wdata->refcount, cifs_writedata_release);
|
|
kref_put(&wdata->refcount, cifs_writedata_release);
|
|
@@ -2376,40 +2435,110 @@ ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
|
|
return written;
|
|
return written;
|
|
}
|
|
}
|
|
|
|
|
|
-ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
|
|
|
|
- unsigned long nr_segs, loff_t pos)
|
|
|
|
|
|
+static ssize_t
|
|
|
|
+cifs_writev(struct kiocb *iocb, const struct iovec *iov,
|
|
|
|
+ unsigned long nr_segs, loff_t pos)
|
|
{
|
|
{
|
|
- struct inode *inode;
|
|
|
|
|
|
+ struct file *file = iocb->ki_filp;
|
|
|
|
+ struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
|
|
|
|
+ struct inode *inode = file->f_mapping->host;
|
|
|
|
+ struct cifsInodeInfo *cinode = CIFS_I(inode);
|
|
|
|
+ struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
|
|
|
|
+ ssize_t rc = -EACCES;
|
|
|
|
|
|
- inode = iocb->ki_filp->f_path.dentry->d_inode;
|
|
|
|
|
|
+ BUG_ON(iocb->ki_pos != pos);
|
|
|
|
|
|
- if (CIFS_I(inode)->clientCanCacheAll)
|
|
|
|
- return generic_file_aio_write(iocb, iov, nr_segs, pos);
|
|
|
|
|
|
+ sb_start_write(inode->i_sb);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * We need to hold the sem to be sure nobody modifies lock list
|
|
|
|
+ * with a brlock that prevents writing.
|
|
|
|
+ */
|
|
|
|
+ down_read(&cinode->lock_sem);
|
|
|
|
+ if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs),
|
|
|
|
+ server->vals->exclusive_lock_type, NULL,
|
|
|
|
+ true)) {
|
|
|
|
+ mutex_lock(&inode->i_mutex);
|
|
|
|
+ rc = __generic_file_aio_write(iocb, iov, nr_segs,
|
|
|
|
+ &iocb->ki_pos);
|
|
|
|
+ mutex_unlock(&inode->i_mutex);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (rc > 0 || rc == -EIOCBQUEUED) {
|
|
|
|
+ ssize_t err;
|
|
|
|
+
|
|
|
|
+ err = generic_write_sync(file, pos, rc);
|
|
|
|
+ if (err < 0 && rc > 0)
|
|
|
|
+ rc = err;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ up_read(&cinode->lock_sem);
|
|
|
|
+ sb_end_write(inode->i_sb);
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+ssize_t
|
|
|
|
+cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
|
|
|
|
+ unsigned long nr_segs, loff_t pos)
|
|
|
|
+{
|
|
|
|
+ struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
|
|
|
|
+ struct cifsInodeInfo *cinode = CIFS_I(inode);
|
|
|
|
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
|
|
+ struct cifsFileInfo *cfile = (struct cifsFileInfo *)
|
|
|
|
+ iocb->ki_filp->private_data;
|
|
|
|
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
|
|
|
|
|
|
|
|
+#ifdef CONFIG_CIFS_SMB2
|
|
/*
|
|
/*
|
|
- * In strict cache mode we need to write the data to the server exactly
|
|
|
|
- * from the pos to pos+len-1 rather than flush all affected pages
|
|
|
|
- * because it may cause a error with mandatory locks on these pages but
|
|
|
|
- * not on the region from pos to ppos+len-1.
|
|
|
|
|
|
+ * If we have an oplock for read and want to write a data to the file
|
|
|
|
+ * we need to store it in the page cache and then push it to the server
|
|
|
|
+ * to be sure the next read will get a valid data.
|
|
*/
|
|
*/
|
|
|
|
+ if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead) {
|
|
|
|
+ ssize_t written;
|
|
|
|
+ int rc;
|
|
|
|
|
|
- return cifs_user_writev(iocb, iov, nr_segs, pos);
|
|
|
|
|
|
+ written = generic_file_aio_write(iocb, iov, nr_segs, pos);
|
|
|
|
+ rc = filemap_fdatawrite(inode->i_mapping);
|
|
|
|
+ if (rc)
|
|
|
|
+ return (ssize_t)rc;
|
|
|
|
+
|
|
|
|
+ return written;
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * For non-oplocked files in strict cache mode we need to write the data
|
|
|
|
+ * to the server exactly from the pos to pos+len-1 rather than flush all
|
|
|
|
+ * affected pages because it may cause a error with mandatory locks on
|
|
|
|
+ * these pages but not on the region from pos to ppos+len-1.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ if (!cinode->clientCanCacheAll)
|
|
|
|
+ return cifs_user_writev(iocb, iov, nr_segs, pos);
|
|
|
|
+
|
|
|
|
+ if (cap_unix(tcon->ses) &&
|
|
|
|
+ (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
|
|
|
|
+ ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
|
|
|
|
+ return generic_file_aio_write(iocb, iov, nr_segs, pos);
|
|
|
|
+
|
|
|
|
+ return cifs_writev(iocb, iov, nr_segs, pos);
|
|
}
|
|
}
|
|
|
|
|
|
static struct cifs_readdata *
|
|
static struct cifs_readdata *
|
|
-cifs_readdata_alloc(unsigned int nr_vecs, work_func_t complete)
|
|
|
|
|
|
+cifs_readdata_alloc(unsigned int nr_pages, work_func_t complete)
|
|
{
|
|
{
|
|
struct cifs_readdata *rdata;
|
|
struct cifs_readdata *rdata;
|
|
|
|
|
|
- rdata = kzalloc(sizeof(*rdata) +
|
|
|
|
- sizeof(struct kvec) * nr_vecs, GFP_KERNEL);
|
|
|
|
|
|
+ rdata = kzalloc(sizeof(*rdata) + (sizeof(struct page *) * nr_pages),
|
|
|
|
+ GFP_KERNEL);
|
|
if (rdata != NULL) {
|
|
if (rdata != NULL) {
|
|
kref_init(&rdata->refcount);
|
|
kref_init(&rdata->refcount);
|
|
INIT_LIST_HEAD(&rdata->list);
|
|
INIT_LIST_HEAD(&rdata->list);
|
|
init_completion(&rdata->done);
|
|
init_completion(&rdata->done);
|
|
INIT_WORK(&rdata->work, complete);
|
|
INIT_WORK(&rdata->work, complete);
|
|
- INIT_LIST_HEAD(&rdata->pages);
|
|
|
|
}
|
|
}
|
|
|
|
+
|
|
return rdata;
|
|
return rdata;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2426,25 +2555,25 @@ cifs_readdata_release(struct kref *refcount)
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
static int
|
|
-cifs_read_allocate_pages(struct list_head *list, unsigned int npages)
|
|
|
|
|
|
+cifs_read_allocate_pages(struct cifs_readdata *rdata, unsigned int nr_pages)
|
|
{
|
|
{
|
|
int rc = 0;
|
|
int rc = 0;
|
|
- struct page *page, *tpage;
|
|
|
|
|
|
+ struct page *page;
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
- for (i = 0; i < npages; i++) {
|
|
|
|
|
|
+ for (i = 0; i < nr_pages; i++) {
|
|
page = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
|
|
page = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
|
|
if (!page) {
|
|
if (!page) {
|
|
rc = -ENOMEM;
|
|
rc = -ENOMEM;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
- list_add(&page->lru, list);
|
|
|
|
|
|
+ rdata->pages[i] = page;
|
|
}
|
|
}
|
|
|
|
|
|
if (rc) {
|
|
if (rc) {
|
|
- list_for_each_entry_safe(page, tpage, list, lru) {
|
|
|
|
- list_del(&page->lru);
|
|
|
|
- put_page(page);
|
|
|
|
|
|
+ for (i = 0; i < nr_pages; i++) {
|
|
|
|
+ put_page(rdata->pages[i]);
|
|
|
|
+ rdata->pages[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return rc;
|
|
return rc;
|
|
@@ -2453,13 +2582,13 @@ cifs_read_allocate_pages(struct list_head *list, unsigned int npages)
|
|
static void
|
|
static void
|
|
cifs_uncached_readdata_release(struct kref *refcount)
|
|
cifs_uncached_readdata_release(struct kref *refcount)
|
|
{
|
|
{
|
|
- struct page *page, *tpage;
|
|
|
|
struct cifs_readdata *rdata = container_of(refcount,
|
|
struct cifs_readdata *rdata = container_of(refcount,
|
|
struct cifs_readdata, refcount);
|
|
struct cifs_readdata, refcount);
|
|
|
|
+ unsigned int i;
|
|
|
|
|
|
- list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
|
|
|
|
- list_del(&page->lru);
|
|
|
|
- put_page(page);
|
|
|
|
|
|
+ for (i = 0; i < rdata->nr_pages; i++) {
|
|
|
|
+ put_page(rdata->pages[i]);
|
|
|
|
+ rdata->pages[i] = NULL;
|
|
}
|
|
}
|
|
cifs_readdata_release(refcount);
|
|
cifs_readdata_release(refcount);
|
|
}
|
|
}
|
|
@@ -2468,6 +2597,9 @@ static int
|
|
cifs_retry_async_readv(struct cifs_readdata *rdata)
|
|
cifs_retry_async_readv(struct cifs_readdata *rdata)
|
|
{
|
|
{
|
|
int rc;
|
|
int rc;
|
|
|
|
+ struct TCP_Server_Info *server;
|
|
|
|
+
|
|
|
|
+ server = tlink_tcon(rdata->cfile->tlink)->ses->server;
|
|
|
|
|
|
do {
|
|
do {
|
|
if (rdata->cfile->invalidHandle) {
|
|
if (rdata->cfile->invalidHandle) {
|
|
@@ -2475,7 +2607,7 @@ cifs_retry_async_readv(struct cifs_readdata *rdata)
|
|
if (rc != 0)
|
|
if (rc != 0)
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
- rc = cifs_async_readv(rdata);
|
|
|
|
|
|
+ rc = server->ops->async_readv(rdata);
|
|
} while (rc == -EAGAIN);
|
|
} while (rc == -EAGAIN);
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
@@ -2500,17 +2632,18 @@ cifs_readdata_to_iov(struct cifs_readdata *rdata, const struct iovec *iov,
|
|
int rc = 0;
|
|
int rc = 0;
|
|
struct iov_iter ii;
|
|
struct iov_iter ii;
|
|
size_t pos = rdata->offset - offset;
|
|
size_t pos = rdata->offset - offset;
|
|
- struct page *page, *tpage;
|
|
|
|
ssize_t remaining = rdata->bytes;
|
|
ssize_t remaining = rdata->bytes;
|
|
unsigned char *pdata;
|
|
unsigned char *pdata;
|
|
|
|
+ unsigned int i;
|
|
|
|
|
|
/* set up iov_iter and advance to the correct offset */
|
|
/* set up iov_iter and advance to the correct offset */
|
|
iov_iter_init(&ii, iov, nr_segs, iov_length(iov, nr_segs), 0);
|
|
iov_iter_init(&ii, iov, nr_segs, iov_length(iov, nr_segs), 0);
|
|
iov_iter_advance(&ii, pos);
|
|
iov_iter_advance(&ii, pos);
|
|
|
|
|
|
*copied = 0;
|
|
*copied = 0;
|
|
- list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
|
|
|
|
|
|
+ for (i = 0; i < rdata->nr_pages; i++) {
|
|
ssize_t copy;
|
|
ssize_t copy;
|
|
|
|
+ struct page *page = rdata->pages[i];
|
|
|
|
|
|
/* copy a whole page or whatever's left */
|
|
/* copy a whole page or whatever's left */
|
|
copy = min_t(ssize_t, remaining, PAGE_SIZE);
|
|
copy = min_t(ssize_t, remaining, PAGE_SIZE);
|
|
@@ -2530,9 +2663,6 @@ cifs_readdata_to_iov(struct cifs_readdata *rdata, const struct iovec *iov,
|
|
iov_iter_advance(&ii, copy);
|
|
iov_iter_advance(&ii, copy);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- list_del(&page->lru);
|
|
|
|
- put_page(page);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
@@ -2544,59 +2674,56 @@ cifs_uncached_readv_complete(struct work_struct *work)
|
|
struct cifs_readdata *rdata = container_of(work,
|
|
struct cifs_readdata *rdata = container_of(work,
|
|
struct cifs_readdata, work);
|
|
struct cifs_readdata, work);
|
|
|
|
|
|
- /* if the result is non-zero then the pages weren't kmapped */
|
|
|
|
- if (rdata->result == 0) {
|
|
|
|
- struct page *page;
|
|
|
|
-
|
|
|
|
- list_for_each_entry(page, &rdata->pages, lru)
|
|
|
|
- kunmap(page);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
complete(&rdata->done);
|
|
complete(&rdata->done);
|
|
kref_put(&rdata->refcount, cifs_uncached_readdata_release);
|
|
kref_put(&rdata->refcount, cifs_uncached_readdata_release);
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
static int
|
|
-cifs_uncached_read_marshal_iov(struct cifs_readdata *rdata,
|
|
|
|
- unsigned int remaining)
|
|
|
|
|
|
+cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
|
|
|
|
+ struct cifs_readdata *rdata, unsigned int len)
|
|
{
|
|
{
|
|
- int len = 0;
|
|
|
|
- struct page *page, *tpage;
|
|
|
|
|
|
+ int total_read = 0, result = 0;
|
|
|
|
+ unsigned int i;
|
|
|
|
+ unsigned int nr_pages = rdata->nr_pages;
|
|
|
|
+ struct kvec iov;
|
|
|
|
+
|
|
|
|
+ rdata->tailsz = PAGE_SIZE;
|
|
|
|
+ for (i = 0; i < nr_pages; i++) {
|
|
|
|
+ struct page *page = rdata->pages[i];
|
|
|
|
|
|
- rdata->nr_iov = 1;
|
|
|
|
- list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
|
|
|
|
- if (remaining >= PAGE_SIZE) {
|
|
|
|
|
|
+ if (len >= PAGE_SIZE) {
|
|
/* enough data to fill the page */
|
|
/* enough data to fill the page */
|
|
- rdata->iov[rdata->nr_iov].iov_base = kmap(page);
|
|
|
|
- rdata->iov[rdata->nr_iov].iov_len = PAGE_SIZE;
|
|
|
|
- cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
|
|
|
|
- rdata->nr_iov, page->index,
|
|
|
|
- rdata->iov[rdata->nr_iov].iov_base,
|
|
|
|
- rdata->iov[rdata->nr_iov].iov_len);
|
|
|
|
- ++rdata->nr_iov;
|
|
|
|
- len += PAGE_SIZE;
|
|
|
|
- remaining -= PAGE_SIZE;
|
|
|
|
- } else if (remaining > 0) {
|
|
|
|
|
|
+ iov.iov_base = kmap(page);
|
|
|
|
+ iov.iov_len = PAGE_SIZE;
|
|
|
|
+ cFYI(1, "%u: iov_base=%p iov_len=%zu",
|
|
|
|
+ i, iov.iov_base, iov.iov_len);
|
|
|
|
+ len -= PAGE_SIZE;
|
|
|
|
+ } else if (len > 0) {
|
|
/* enough for partial page, fill and zero the rest */
|
|
/* enough for partial page, fill and zero the rest */
|
|
- rdata->iov[rdata->nr_iov].iov_base = kmap(page);
|
|
|
|
- rdata->iov[rdata->nr_iov].iov_len = remaining;
|
|
|
|
- cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
|
|
|
|
- rdata->nr_iov, page->index,
|
|
|
|
- rdata->iov[rdata->nr_iov].iov_base,
|
|
|
|
- rdata->iov[rdata->nr_iov].iov_len);
|
|
|
|
- memset(rdata->iov[rdata->nr_iov].iov_base + remaining,
|
|
|
|
- '\0', PAGE_SIZE - remaining);
|
|
|
|
- ++rdata->nr_iov;
|
|
|
|
- len += remaining;
|
|
|
|
- remaining = 0;
|
|
|
|
|
|
+ iov.iov_base = kmap(page);
|
|
|
|
+ iov.iov_len = len;
|
|
|
|
+ cFYI(1, "%u: iov_base=%p iov_len=%zu",
|
|
|
|
+ i, iov.iov_base, iov.iov_len);
|
|
|
|
+ memset(iov.iov_base + len, '\0', PAGE_SIZE - len);
|
|
|
|
+ rdata->tailsz = len;
|
|
|
|
+ len = 0;
|
|
} else {
|
|
} else {
|
|
/* no need to hold page hostage */
|
|
/* no need to hold page hostage */
|
|
- list_del(&page->lru);
|
|
|
|
|
|
+ rdata->pages[i] = NULL;
|
|
|
|
+ rdata->nr_pages--;
|
|
put_page(page);
|
|
put_page(page);
|
|
|
|
+ continue;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ result = cifs_readv_from_socket(server, &iov, 1, iov.iov_len);
|
|
|
|
+ kunmap(page);
|
|
|
|
+ if (result < 0)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ total_read += result;
|
|
}
|
|
}
|
|
|
|
|
|
- return len;
|
|
|
|
|
|
+ return total_read > 0 ? total_read : result;
|
|
}
|
|
}
|
|
|
|
|
|
static ssize_t
|
|
static ssize_t
|
|
@@ -2627,6 +2754,9 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
|
|
open_file = file->private_data;
|
|
open_file = file->private_data;
|
|
tcon = tlink_tcon(open_file->tlink);
|
|
tcon = tlink_tcon(open_file->tlink);
|
|
|
|
|
|
|
|
+ if (!tcon->ses->server->ops->async_readv)
|
|
|
|
+ return -ENOSYS;
|
|
|
|
+
|
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
|
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
|
|
pid = open_file->pid;
|
|
pid = open_file->pid;
|
|
else
|
|
else
|
|
@@ -2647,15 +2777,17 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
|
|
- rc = cifs_read_allocate_pages(&rdata->pages, npages);
|
|
|
|
|
|
+ rc = cifs_read_allocate_pages(rdata, npages);
|
|
if (rc)
|
|
if (rc)
|
|
goto error;
|
|
goto error;
|
|
|
|
|
|
rdata->cfile = cifsFileInfo_get(open_file);
|
|
rdata->cfile = cifsFileInfo_get(open_file);
|
|
|
|
+ rdata->nr_pages = npages;
|
|
rdata->offset = offset;
|
|
rdata->offset = offset;
|
|
rdata->bytes = cur_len;
|
|
rdata->bytes = cur_len;
|
|
rdata->pid = pid;
|
|
rdata->pid = pid;
|
|
- rdata->marshal_iov = cifs_uncached_read_marshal_iov;
|
|
|
|
|
|
+ rdata->pagesz = PAGE_SIZE;
|
|
|
|
+ rdata->read_into_pages = cifs_uncached_read_into_pages;
|
|
|
|
|
|
rc = cifs_retry_async_readv(rdata);
|
|
rc = cifs_retry_async_readv(rdata);
|
|
error:
|
|
error:
|
|
@@ -2706,6 +2838,10 @@ restart_loop:
|
|
cifs_stats_bytes_read(tcon, total_read);
|
|
cifs_stats_bytes_read(tcon, total_read);
|
|
*poffset += total_read;
|
|
*poffset += total_read;
|
|
|
|
|
|
|
|
+ /* mask nodata case */
|
|
|
|
+ if (rc == -ENODATA)
|
|
|
|
+ rc = 0;
|
|
|
|
+
|
|
return total_read ? total_read : rc;
|
|
return total_read ? total_read : rc;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2721,15 +2857,17 @@ ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov,
|
|
return read;
|
|
return read;
|
|
}
|
|
}
|
|
|
|
|
|
-ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
|
|
|
|
- unsigned long nr_segs, loff_t pos)
|
|
|
|
|
|
+ssize_t
|
|
|
|
+cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
|
|
|
|
+ unsigned long nr_segs, loff_t pos)
|
|
{
|
|
{
|
|
- struct inode *inode;
|
|
|
|
-
|
|
|
|
- inode = iocb->ki_filp->f_path.dentry->d_inode;
|
|
|
|
-
|
|
|
|
- if (CIFS_I(inode)->clientCanCacheRead)
|
|
|
|
- return generic_file_aio_read(iocb, iov, nr_segs, pos);
|
|
|
|
|
|
+ struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
|
|
|
|
+ struct cifsInodeInfo *cinode = CIFS_I(inode);
|
|
|
|
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
|
|
+ struct cifsFileInfo *cfile = (struct cifsFileInfo *)
|
|
|
|
+ iocb->ki_filp->private_data;
|
|
|
|
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
|
|
|
|
+ int rc = -EACCES;
|
|
|
|
|
|
/*
|
|
/*
|
|
* In strict cache mode we need to read from the server all the time
|
|
* In strict cache mode we need to read from the server all the time
|
|
@@ -2739,12 +2877,29 @@ ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
|
|
* on pages affected by this read but not on the region from pos to
|
|
* on pages affected by this read but not on the region from pos to
|
|
* pos+len-1.
|
|
* pos+len-1.
|
|
*/
|
|
*/
|
|
|
|
+ if (!cinode->clientCanCacheRead)
|
|
|
|
+ return cifs_user_readv(iocb, iov, nr_segs, pos);
|
|
|
|
+
|
|
|
|
+ if (cap_unix(tcon->ses) &&
|
|
|
|
+ (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
|
|
|
|
+ ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
|
|
|
|
+ return generic_file_aio_read(iocb, iov, nr_segs, pos);
|
|
|
|
|
|
- return cifs_user_readv(iocb, iov, nr_segs, pos);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * We need to hold the sem to be sure nobody modifies lock list
|
|
|
|
+ * with a brlock that prevents reading.
|
|
|
|
+ */
|
|
|
|
+ down_read(&cinode->lock_sem);
|
|
|
|
+ if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs),
|
|
|
|
+ tcon->ses->server->vals->shared_lock_type,
|
|
|
|
+ NULL, true))
|
|
|
|
+ rc = generic_file_aio_read(iocb, iov, nr_segs, pos);
|
|
|
|
+ up_read(&cinode->lock_sem);
|
|
|
|
+ return rc;
|
|
}
|
|
}
|
|
|
|
|
|
-static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
|
|
|
|
- loff_t *poffset)
|
|
|
|
|
|
+static ssize_t
|
|
|
|
+cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset)
|
|
{
|
|
{
|
|
int rc = -EACCES;
|
|
int rc = -EACCES;
|
|
unsigned int bytes_read = 0;
|
|
unsigned int bytes_read = 0;
|
|
@@ -2753,8 +2908,9 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
|
|
unsigned int rsize;
|
|
unsigned int rsize;
|
|
struct cifs_sb_info *cifs_sb;
|
|
struct cifs_sb_info *cifs_sb;
|
|
struct cifs_tcon *tcon;
|
|
struct cifs_tcon *tcon;
|
|
|
|
+ struct TCP_Server_Info *server;
|
|
unsigned int xid;
|
|
unsigned int xid;
|
|
- char *current_offset;
|
|
|
|
|
|
+ char *cur_offset;
|
|
struct cifsFileInfo *open_file;
|
|
struct cifsFileInfo *open_file;
|
|
struct cifs_io_parms io_parms;
|
|
struct cifs_io_parms io_parms;
|
|
int buf_type = CIFS_NO_BUFFER;
|
|
int buf_type = CIFS_NO_BUFFER;
|
|
@@ -2773,6 +2929,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
|
|
}
|
|
}
|
|
open_file = file->private_data;
|
|
open_file = file->private_data;
|
|
tcon = tlink_tcon(open_file->tlink);
|
|
tcon = tlink_tcon(open_file->tlink);
|
|
|
|
+ server = tcon->ses->server;
|
|
|
|
+
|
|
|
|
+ if (!server->ops->sync_read) {
|
|
|
|
+ free_xid(xid);
|
|
|
|
+ return -ENOSYS;
|
|
|
|
+ }
|
|
|
|
|
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
|
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
|
|
pid = open_file->pid;
|
|
pid = open_file->pid;
|
|
@@ -2782,9 +2944,8 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
|
|
if ((file->f_flags & O_ACCMODE) == O_WRONLY)
|
|
if ((file->f_flags & O_ACCMODE) == O_WRONLY)
|
|
cFYI(1, "attempting read on write only file instance");
|
|
cFYI(1, "attempting read on write only file instance");
|
|
|
|
|
|
- for (total_read = 0, current_offset = read_data;
|
|
|
|
- read_size > total_read;
|
|
|
|
- total_read += bytes_read, current_offset += bytes_read) {
|
|
|
|
|
|
+ for (total_read = 0, cur_offset = read_data; read_size > total_read;
|
|
|
|
+ total_read += bytes_read, cur_offset += bytes_read) {
|
|
current_read_size = min_t(uint, read_size - total_read, rsize);
|
|
current_read_size = min_t(uint, read_size - total_read, rsize);
|
|
/*
|
|
/*
|
|
* For windows me and 9x we do not want to request more than it
|
|
* For windows me and 9x we do not want to request more than it
|
|
@@ -2802,13 +2963,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
|
|
if (rc != 0)
|
|
if (rc != 0)
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
- io_parms.netfid = open_file->netfid;
|
|
|
|
io_parms.pid = pid;
|
|
io_parms.pid = pid;
|
|
io_parms.tcon = tcon;
|
|
io_parms.tcon = tcon;
|
|
- io_parms.offset = *poffset;
|
|
|
|
|
|
+ io_parms.offset = *offset;
|
|
io_parms.length = current_read_size;
|
|
io_parms.length = current_read_size;
|
|
- rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
|
|
|
|
- ¤t_offset, &buf_type);
|
|
|
|
|
|
+ rc = server->ops->sync_read(xid, open_file, &io_parms,
|
|
|
|
+ &bytes_read, &cur_offset,
|
|
|
|
+ &buf_type);
|
|
}
|
|
}
|
|
if (rc || (bytes_read == 0)) {
|
|
if (rc || (bytes_read == 0)) {
|
|
if (total_read) {
|
|
if (total_read) {
|
|
@@ -2819,7 +2980,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
cifs_stats_bytes_read(tcon, total_read);
|
|
cifs_stats_bytes_read(tcon, total_read);
|
|
- *poffset += bytes_read;
|
|
|
|
|
|
+ *offset += bytes_read;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
free_xid(xid);
|
|
free_xid(xid);
|
|
@@ -2885,16 +3046,16 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
|
static void
|
|
static void
|
|
cifs_readv_complete(struct work_struct *work)
|
|
cifs_readv_complete(struct work_struct *work)
|
|
{
|
|
{
|
|
|
|
+ unsigned int i;
|
|
struct cifs_readdata *rdata = container_of(work,
|
|
struct cifs_readdata *rdata = container_of(work,
|
|
struct cifs_readdata, work);
|
|
struct cifs_readdata, work);
|
|
- struct page *page, *tpage;
|
|
|
|
|
|
|
|
- list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
|
|
|
|
- list_del(&page->lru);
|
|
|
|
|
|
+ for (i = 0; i < rdata->nr_pages; i++) {
|
|
|
|
+ struct page *page = rdata->pages[i];
|
|
|
|
+
|
|
lru_cache_add_file(page);
|
|
lru_cache_add_file(page);
|
|
|
|
|
|
if (rdata->result == 0) {
|
|
if (rdata->result == 0) {
|
|
- kunmap(page);
|
|
|
|
flush_dcache_page(page);
|
|
flush_dcache_page(page);
|
|
SetPageUptodate(page);
|
|
SetPageUptodate(page);
|
|
}
|
|
}
|
|
@@ -2905,49 +3066,48 @@ cifs_readv_complete(struct work_struct *work)
|
|
cifs_readpage_to_fscache(rdata->mapping->host, page);
|
|
cifs_readpage_to_fscache(rdata->mapping->host, page);
|
|
|
|
|
|
page_cache_release(page);
|
|
page_cache_release(page);
|
|
|
|
+ rdata->pages[i] = NULL;
|
|
}
|
|
}
|
|
kref_put(&rdata->refcount, cifs_readdata_release);
|
|
kref_put(&rdata->refcount, cifs_readdata_release);
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
static int
|
|
-cifs_readpages_marshal_iov(struct cifs_readdata *rdata, unsigned int remaining)
|
|
|
|
|
|
+cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
|
|
|
|
+ struct cifs_readdata *rdata, unsigned int len)
|
|
{
|
|
{
|
|
- int len = 0;
|
|
|
|
- struct page *page, *tpage;
|
|
|
|
|
|
+ int total_read = 0, result = 0;
|
|
|
|
+ unsigned int i;
|
|
u64 eof;
|
|
u64 eof;
|
|
pgoff_t eof_index;
|
|
pgoff_t eof_index;
|
|
|
|
+ unsigned int nr_pages = rdata->nr_pages;
|
|
|
|
+ struct kvec iov;
|
|
|
|
|
|
/* determine the eof that the server (probably) has */
|
|
/* determine the eof that the server (probably) has */
|
|
eof = CIFS_I(rdata->mapping->host)->server_eof;
|
|
eof = CIFS_I(rdata->mapping->host)->server_eof;
|
|
eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0;
|
|
eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0;
|
|
cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index);
|
|
cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index);
|
|
|
|
|
|
- rdata->nr_iov = 1;
|
|
|
|
- list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
|
|
|
|
- if (remaining >= PAGE_CACHE_SIZE) {
|
|
|
|
|
|
+ rdata->tailsz = PAGE_CACHE_SIZE;
|
|
|
|
+ for (i = 0; i < nr_pages; i++) {
|
|
|
|
+ struct page *page = rdata->pages[i];
|
|
|
|
+
|
|
|
|
+ if (len >= PAGE_CACHE_SIZE) {
|
|
/* enough data to fill the page */
|
|
/* enough data to fill the page */
|
|
- rdata->iov[rdata->nr_iov].iov_base = kmap(page);
|
|
|
|
- rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE;
|
|
|
|
|
|
+ iov.iov_base = kmap(page);
|
|
|
|
+ iov.iov_len = PAGE_CACHE_SIZE;
|
|
cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
|
|
cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
|
|
- rdata->nr_iov, page->index,
|
|
|
|
- rdata->iov[rdata->nr_iov].iov_base,
|
|
|
|
- rdata->iov[rdata->nr_iov].iov_len);
|
|
|
|
- ++rdata->nr_iov;
|
|
|
|
- len += PAGE_CACHE_SIZE;
|
|
|
|
- remaining -= PAGE_CACHE_SIZE;
|
|
|
|
- } else if (remaining > 0) {
|
|
|
|
|
|
+ i, page->index, iov.iov_base, iov.iov_len);
|
|
|
|
+ len -= PAGE_CACHE_SIZE;
|
|
|
|
+ } else if (len > 0) {
|
|
/* enough for partial page, fill and zero the rest */
|
|
/* enough for partial page, fill and zero the rest */
|
|
- rdata->iov[rdata->nr_iov].iov_base = kmap(page);
|
|
|
|
- rdata->iov[rdata->nr_iov].iov_len = remaining;
|
|
|
|
|
|
+ iov.iov_base = kmap(page);
|
|
|
|
+ iov.iov_len = len;
|
|
cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
|
|
cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
|
|
- rdata->nr_iov, page->index,
|
|
|
|
- rdata->iov[rdata->nr_iov].iov_base,
|
|
|
|
- rdata->iov[rdata->nr_iov].iov_len);
|
|
|
|
- memset(rdata->iov[rdata->nr_iov].iov_base + remaining,
|
|
|
|
- '\0', PAGE_CACHE_SIZE - remaining);
|
|
|
|
- ++rdata->nr_iov;
|
|
|
|
- len += remaining;
|
|
|
|
- remaining = 0;
|
|
|
|
|
|
+ i, page->index, iov.iov_base, iov.iov_len);
|
|
|
|
+ memset(iov.iov_base + len,
|
|
|
|
+ '\0', PAGE_CACHE_SIZE - len);
|
|
|
|
+ rdata->tailsz = len;
|
|
|
|
+ len = 0;
|
|
} else if (page->index > eof_index) {
|
|
} else if (page->index > eof_index) {
|
|
/*
|
|
/*
|
|
* The VFS will not try to do readahead past the
|
|
* The VFS will not try to do readahead past the
|
|
@@ -2958,22 +3118,33 @@ cifs_readpages_marshal_iov(struct cifs_readdata *rdata, unsigned int remaining)
|
|
* fill them until the writes are flushed.
|
|
* fill them until the writes are flushed.
|
|
*/
|
|
*/
|
|
zero_user(page, 0, PAGE_CACHE_SIZE);
|
|
zero_user(page, 0, PAGE_CACHE_SIZE);
|
|
- list_del(&page->lru);
|
|
|
|
lru_cache_add_file(page);
|
|
lru_cache_add_file(page);
|
|
flush_dcache_page(page);
|
|
flush_dcache_page(page);
|
|
SetPageUptodate(page);
|
|
SetPageUptodate(page);
|
|
unlock_page(page);
|
|
unlock_page(page);
|
|
page_cache_release(page);
|
|
page_cache_release(page);
|
|
|
|
+ rdata->pages[i] = NULL;
|
|
|
|
+ rdata->nr_pages--;
|
|
|
|
+ continue;
|
|
} else {
|
|
} else {
|
|
/* no need to hold page hostage */
|
|
/* no need to hold page hostage */
|
|
- list_del(&page->lru);
|
|
|
|
lru_cache_add_file(page);
|
|
lru_cache_add_file(page);
|
|
unlock_page(page);
|
|
unlock_page(page);
|
|
page_cache_release(page);
|
|
page_cache_release(page);
|
|
|
|
+ rdata->pages[i] = NULL;
|
|
|
|
+ rdata->nr_pages--;
|
|
|
|
+ continue;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ result = cifs_readv_from_socket(server, &iov, 1, iov.iov_len);
|
|
|
|
+ kunmap(page);
|
|
|
|
+ if (result < 0)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ total_read += result;
|
|
}
|
|
}
|
|
|
|
|
|
- return len;
|
|
|
|
|
|
+ return total_read > 0 ? total_read : result;
|
|
}
|
|
}
|
|
|
|
|
|
static int cifs_readpages(struct file *file, struct address_space *mapping,
|
|
static int cifs_readpages(struct file *file, struct address_space *mapping,
|
|
@@ -3027,6 +3198,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
|
|
* the rdata->pages, then we want them in increasing order.
|
|
* the rdata->pages, then we want them in increasing order.
|
|
*/
|
|
*/
|
|
while (!list_empty(page_list)) {
|
|
while (!list_empty(page_list)) {
|
|
|
|
+ unsigned int i;
|
|
unsigned int bytes = PAGE_CACHE_SIZE;
|
|
unsigned int bytes = PAGE_CACHE_SIZE;
|
|
unsigned int expected_index;
|
|
unsigned int expected_index;
|
|
unsigned int nr_pages = 1;
|
|
unsigned int nr_pages = 1;
|
|
@@ -3096,14 +3268,18 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
|
|
rdata->offset = offset;
|
|
rdata->offset = offset;
|
|
rdata->bytes = bytes;
|
|
rdata->bytes = bytes;
|
|
rdata->pid = pid;
|
|
rdata->pid = pid;
|
|
- rdata->marshal_iov = cifs_readpages_marshal_iov;
|
|
|
|
- list_splice_init(&tmplist, &rdata->pages);
|
|
|
|
|
|
+ rdata->pagesz = PAGE_CACHE_SIZE;
|
|
|
|
+ rdata->read_into_pages = cifs_readpages_read_into_pages;
|
|
|
|
+
|
|
|
|
+ list_for_each_entry_safe(page, tpage, &tmplist, lru) {
|
|
|
|
+ list_del(&page->lru);
|
|
|
|
+ rdata->pages[rdata->nr_pages++] = page;
|
|
|
|
+ }
|
|
|
|
|
|
rc = cifs_retry_async_readv(rdata);
|
|
rc = cifs_retry_async_readv(rdata);
|
|
if (rc != 0) {
|
|
if (rc != 0) {
|
|
- list_for_each_entry_safe(page, tpage, &rdata->pages,
|
|
|
|
- lru) {
|
|
|
|
- list_del(&page->lru);
|
|
|
|
|
|
+ for (i = 0; i < rdata->nr_pages; i++) {
|
|
|
|
+ page = rdata->pages[i];
|
|
lru_cache_add_file(page);
|
|
lru_cache_add_file(page);
|
|
unlock_page(page);
|
|
unlock_page(page);
|
|
page_cache_release(page);
|
|
page_cache_release(page);
|
|
@@ -3347,6 +3523,7 @@ void cifs_oplock_break(struct work_struct *work)
|
|
oplock_break);
|
|
oplock_break);
|
|
struct inode *inode = cfile->dentry->d_inode;
|
|
struct inode *inode = cfile->dentry->d_inode;
|
|
struct cifsInodeInfo *cinode = CIFS_I(inode);
|
|
struct cifsInodeInfo *cinode = CIFS_I(inode);
|
|
|
|
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
|
|
int rc = 0;
|
|
int rc = 0;
|
|
|
|
|
|
if (inode && S_ISREG(inode->i_mode)) {
|
|
if (inode && S_ISREG(inode->i_mode)) {
|
|
@@ -3374,10 +3551,8 @@ void cifs_oplock_break(struct work_struct *work)
|
|
* disconnected since oplock already released by the server
|
|
* disconnected since oplock already released by the server
|
|
*/
|
|
*/
|
|
if (!cfile->oplock_break_cancelled) {
|
|
if (!cfile->oplock_break_cancelled) {
|
|
- rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid,
|
|
|
|
- current->tgid, 0, 0, 0, 0,
|
|
|
|
- LOCKING_ANDX_OPLOCK_RELEASE, false,
|
|
|
|
- cinode->clientCanCacheRead ? 1 : 0);
|
|
|
|
|
|
+ rc = tcon->ses->server->ops->oplock_response(tcon, &cfile->fid,
|
|
|
|
+ cinode);
|
|
cFYI(1, "Oplock release rc = %d", rc);
|
|
cFYI(1, "Oplock release rc = %d", rc);
|
|
}
|
|
}
|
|
}
|
|
}
|