Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cbf2822a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6

Pull CIFS fixes from Steve French:
 "Small fix from Jeff for writepages leak, and some fixes for ACLs and
  xattrs when SMB2 enabled.

  Am expecting another fix from Jeff and at least one more fix (for
  mounting SMB2 with cifsacl) in the next week"

* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
  [CIFS] clean up page array when uncached write send fails
  cifs: use a flexarray in cifs_writedata
  retrieving CIFS ACLs when mounted with SMB2 fails dropping session
  Add protocol specific operation for CIFS xattrs
parents b28a960c 4a5c80d7
Loading
Loading
Loading
Loading
+24 −4
Original line number Diff line number Diff line
@@ -1043,15 +1043,30 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
	__u32 secdesclen = 0;
	struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
	struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
	struct cifs_tcon *tcon;

	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	tcon = tlink_tcon(tlink);

	cifs_dbg(NOISY, "set ACL from mode for %s\n", path);

	/* Get the security descriptor */
	pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);

	if (tcon->ses->server->ops->get_acl == NULL) {
		cifs_put_tlink(tlink);
		return -EOPNOTSUPP;
	}

	pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
						&secdesclen);
	if (IS_ERR(pntsd)) {
		rc = PTR_ERR(pntsd);
		cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
		goto out;
		cifs_put_tlink(tlink);
		return rc;
	}

	/*
@@ -1064,6 +1079,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
	pnntsd = kmalloc(secdesclen, GFP_KERNEL);
	if (!pnntsd) {
		kfree(pntsd);
		cifs_put_tlink(tlink);
		return -ENOMEM;
	}

@@ -1072,14 +1088,18 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,

	cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);

	if (tcon->ses->server->ops->set_acl == NULL)
		rc = -EOPNOTSUPP;

	if (!rc) {
		/* Set the security descriptor */
		rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
		rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
						     path, aclflag);
		cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
	}
	cifs_put_tlink(tlink);

	kfree(pnntsd);
	kfree(pntsd);
out:
	return rc;
}
+7 −2
Original line number Diff line number Diff line
@@ -323,7 +323,8 @@ struct smb_version_operations {
	/* async read from the server */
	int (*async_readv)(struct cifs_readdata *);
	/* async write to the server */
	int (*async_writev)(struct cifs_writedata *);
	int (*async_writev)(struct cifs_writedata *,
			    void (*release)(struct kref *));
	/* sync read from the server */
	int (*sync_read)(const unsigned int, struct cifsFileInfo *,
			 struct cifs_io_parms *, unsigned int *, char **,
@@ -395,6 +396,10 @@ struct smb_version_operations {
	int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
			const char *, const void *, const __u16,
			const struct nls_table *, int);
	struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *,
			const char *, u32 *);
	int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
			int);
};

struct smb_version_values {
@@ -1064,7 +1069,7 @@ struct cifs_writedata {
	unsigned int			pagesz;
	unsigned int			tailsz;
	unsigned int			nr_pages;
	struct page			*pages[1];
	struct page			*pages[];
};

/*
+2 −1
Original line number Diff line number Diff line
@@ -488,7 +488,8 @@ void cifs_readdata_release(struct kref *refcount);
int cifs_async_readv(struct cifs_readdata *rdata);
int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);

int cifs_async_writev(struct cifs_writedata *wdata);
int cifs_async_writev(struct cifs_writedata *wdata,
		      void (*release)(struct kref *kref));
void cifs_writev_complete(struct work_struct *work);
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
						work_func_t complete);
+5 −10
Original line number Diff line number Diff line
@@ -1910,7 +1910,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)

	do {
		server = tlink_tcon(wdata->cfile->tlink)->ses->server;
		rc = server->ops->async_writev(wdata);
		rc = server->ops->async_writev(wdata, cifs_writedata_release);
	} while (rc == -EAGAIN);

	for (i = 0; i < wdata->nr_pages; i++) {
@@ -1962,15 +1962,9 @@ cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
{
	struct cifs_writedata *wdata;

	/* this would overflow */
	if (nr_pages == 0) {
		cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
		return NULL;
	}

	/* writedata + number of page pointers */
	wdata = kzalloc(sizeof(*wdata) +
			sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
			sizeof(struct page *) * nr_pages, GFP_NOFS);
	if (wdata != NULL) {
		kref_init(&wdata->refcount);
		INIT_LIST_HEAD(&wdata->list);
@@ -2031,7 +2025,8 @@ cifs_writev_callback(struct mid_q_entry *mid)

/* cifs_async_writev - send an async write, and set up mid to handle result */
int
cifs_async_writev(struct cifs_writedata *wdata)
cifs_async_writev(struct cifs_writedata *wdata,
		  void (*release)(struct kref *kref))
{
	int rc = -EACCES;
	WRITE_REQ *smb = NULL;
@@ -2105,7 +2100,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
	if (rc == 0)
		cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
	else
		kref_put(&wdata->refcount, cifs_writedata_release);
		kref_put(&wdata->refcount, release);

async_writev_out:
	cifs_small_buf_release(smb);
+20 −11
Original line number Diff line number Diff line
@@ -2043,7 +2043,8 @@ retry:
			}
			wdata->pid = wdata->cfile->pid;
			server = tlink_tcon(wdata->cfile->tlink)->ses->server;
			rc = server->ops->async_writev(wdata);
			rc = server->ops->async_writev(wdata,
							cifs_writedata_release);
		} while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);

		for (i = 0; i < nr_pages; ++i)
@@ -2331,9 +2332,20 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
}

static void
cifs_uncached_writev_complete(struct work_struct *work)
cifs_uncached_writedata_release(struct kref *refcount)
{
	int i;
	struct cifs_writedata *wdata = container_of(refcount,
					struct cifs_writedata, refcount);

	for (i = 0; i < wdata->nr_pages; i++)
		put_page(wdata->pages[i]);
	cifs_writedata_release(refcount);
}

static void
cifs_uncached_writev_complete(struct work_struct *work)
{
	struct cifs_writedata *wdata = container_of(work,
					struct cifs_writedata, work);
	struct inode *inode = wdata->cfile->dentry->d_inode;
@@ -2347,12 +2359,7 @@ cifs_uncached_writev_complete(struct work_struct *work)

	complete(&wdata->done);

	if (wdata->result != -EAGAIN) {
		for (i = 0; i < wdata->nr_pages; i++)
			put_page(wdata->pages[i]);
	}

	kref_put(&wdata->refcount, cifs_writedata_release);
	kref_put(&wdata->refcount, cifs_uncached_writedata_release);
}

/* attempt to send write to server, retry on any -EAGAIN errors */
@@ -2370,7 +2377,8 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata)
			if (rc != 0)
				continue;
		}
		rc = server->ops->async_writev(wdata);
		rc = server->ops->async_writev(wdata,
					       cifs_uncached_writedata_release);
	} while (rc == -EAGAIN);

	return rc;
@@ -2454,7 +2462,8 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
		wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
		rc = cifs_uncached_retry_writev(wdata);
		if (rc) {
			kref_put(&wdata->refcount, cifs_writedata_release);
			kref_put(&wdata->refcount,
				 cifs_uncached_writedata_release);
			break;
		}

@@ -2496,7 +2505,7 @@ restart_loop:
			}
		}
		list_del_init(&wdata->list);
		kref_put(&wdata->refcount, cifs_writedata_release);
		kref_put(&wdata->refcount, cifs_uncached_writedata_release);
	}

	if (total_written > 0)
Loading