int create_options;
const char *path;
struct cifs_fid *fid;
+ bool reconnect:1;
};
struct cifs_fid {
oparms.disposition = disposition;
oparms.path = full_path;
oparms.fid = fid;
+ oparms.reconnect = false;
rc = server->ops->open(xid, &oparms, oplock, buf);
if (rc) {
oparms.disposition = disposition;
oparms.path = full_path;
oparms.fid = fid;
+ oparms.reconnect = false;
rc = server->ops->open(xid, &oparms, oplock, buf);
int desired_access;
int disposition = FILE_OPEN;
int create_options = CREATE_NOT_DIR;
- struct cifs_fid fid;
struct cifs_open_parms oparms;
xid = get_xid();
rc = cifs_posix_open(full_path, NULL, inode->i_sb,
cifs_sb->mnt_file_mode /* ignored */,
- oflags, &oplock, &fid.netfid, xid);
+ oflags, &oplock, &cfile->fid.netfid, xid);
if (rc == 0) {
cifs_dbg(FYI, "posix reopen succeeded\n");
goto reopen_success;
create_options |= CREATE_OPEN_BACKUP_INTENT;
if (server->ops->get_lease_key)
- server->ops->get_lease_key(inode, &fid);
+ server->ops->get_lease_key(inode, &cfile->fid);
oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb;
oparms.create_options = create_options;
oparms.disposition = disposition;
oparms.path = full_path;
- oparms.fid = &fid;
+ oparms.fid = &cfile->fid;
+ oparms.reconnect = true;
/*
* Can not refresh inode by passing in file_info buf to be returned by
* to the server to get the new inode info.
*/
- server->ops->set_fid(cfile, &fid, oplock);
- cifs_relock_file(cfile);
+ server->ops->set_fid(cfile, &cfile->fid, oplock);
+ if (oparms.reconnect)
+ cifs_relock_file(cfile);
reopen_error_exit:
kfree(full_path);
if (!rc)
goto out;
+
/*
* Windows 7 server can delay breaking lease from read to None
* if we set a byte-range lock on a file - break it explicitly
oplock &= 0xFF;
if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
return;
- if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+ if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
+ oplock == SMB2_OPLOCK_LEVEL_BATCH) {
cinode->clientCanCacheAll = true;
cinode->clientCanCacheRead = true;
cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
oparms.disposition = create_disposition;
oparms.create_options = create_options;
oparms.fid = &fid;
+ oparms.reconnect = false;
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
if (rc) {
oparms.disposition = FILE_OPEN;
oparms.create_options = 0;
oparms.fid = &fid;
+ oparms.reconnect = false;
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
if (rc) {
oparms.disposition = FILE_OPEN;
oparms.create_options = 0;
oparms.fid = fid;
+ oparms.reconnect = false;
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
kfree(utf16_path);
oparms.disposition = FILE_OPEN;
oparms.create_options = 0;
oparms.fid = &fid;
+ oparms.reconnect = false;
rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL);
if (rc)
return NULL;
buf->ccontext.DataOffset = cpu_to_le16(offsetof
- (struct create_durable, Reserved));
+ (struct create_durable, Data));
buf->ccontext.DataLength = cpu_to_le32(16);
buf->ccontext.NameOffset = cpu_to_le16(offsetof
(struct create_durable, Name));
return buf;
}
+static struct create_durable *
+create_reconnect_durable_buf(struct cifs_fid *fid)
+{
+ struct create_durable *buf;
+
+ buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ buf->ccontext.DataOffset = cpu_to_le16(offsetof
+ (struct create_durable, Data));
+ buf->ccontext.DataLength = cpu_to_le32(16);
+ buf->ccontext.NameOffset = cpu_to_le16(offsetof
+ (struct create_durable, Name));
+ buf->ccontext.NameLength = cpu_to_le16(4);
+ buf->Data.Fid.PersistentFileId = fid->persistent_fid;
+ buf->Data.Fid.VolatileFileId = fid->volatile_fid;
+ buf->Name[0] = 'D';
+ buf->Name[1] = 'H';
+ buf->Name[2] = 'n';
+ buf->Name[3] = 'C';
+ return buf;
+}
+
static __u8
parse_lease_state(struct smb2_create_rsp *rsp)
{
}
static int
-add_durable_context(struct kvec *iov, unsigned int *num_iovec)
+add_durable_context(struct kvec *iov, unsigned int *num_iovec,
+ struct cifs_open_parms *oparms)
{
struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec;
- iov[num].iov_base = create_durable_buf();
+ if (oparms->reconnect) {
+ iov[num].iov_base = create_reconnect_durable_buf(oparms->fid);
+ /* indicate that we don't need to relock the file */
+ oparms->reconnect = false;
+ } else
+ iov[num].iov_base = create_durable_buf();
if (iov[num].iov_base == NULL)
return -ENOMEM;
iov[num].iov_len = sizeof(struct create_durable);
(struct create_context *)iov[num_iovecs-1].iov_base;
ccontext->Next = sizeof(struct create_lease);
}
- rc = add_durable_context(iov, &num_iovecs);
+ rc = add_durable_context(iov, &num_iovecs, oparms);
if (rc) {
cifs_small_buf_release(req);
kfree(copy_path);
struct create_durable {
struct create_context ccontext;
__u8 Name[8];
- __u8 Reserved[16];
+ union {
+ __u8 Reserved[16];
+ struct {
+ __u64 PersistentFileId;
+ __u64 VolatileFileId;
+ } Fid;
+ } Data;
} __packed;
/* this goes in the ioctl buffer when doing a copychunk request */