forked from Minki/linux
Merge branch 'fixes' of git://git.linux-nfs.org/pub/linux/nfs-2.6
This commit is contained in:
commit
62250b3bb5
@ -486,8 +486,6 @@ struct file *open_exec(const char *name)
|
||||
if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
|
||||
S_ISREG(inode->i_mode)) {
|
||||
int err = vfs_permission(&nd, MAY_EXEC);
|
||||
if (!err && !(inode->i_mode & 0111))
|
||||
err = -EACCES;
|
||||
file = ERR_PTR(err);
|
||||
if (!err) {
|
||||
file = nameidata_to_filp(&nd, O_RDONLY);
|
||||
@ -922,12 +920,6 @@ int prepare_binprm(struct linux_binprm *bprm)
|
||||
int retval;
|
||||
|
||||
mode = inode->i_mode;
|
||||
/*
|
||||
* Check execute perms again - if the caller has CAP_DAC_OVERRIDE,
|
||||
* generic_permission lets a non-executable through
|
||||
*/
|
||||
if (!(mode & 0111)) /* with at least _one_ execute bit set */
|
||||
return -EACCES;
|
||||
if (bprm->file->f_op == NULL)
|
||||
return -EACCES;
|
||||
|
||||
|
@ -237,19 +237,22 @@ static int
|
||||
nlm_traverse_files(struct nlm_host *host, int action)
|
||||
{
|
||||
struct nlm_file *file, **fp;
|
||||
int i;
|
||||
int i, ret = 0;
|
||||
|
||||
mutex_lock(&nlm_file_mutex);
|
||||
for (i = 0; i < FILE_NRHASH; i++) {
|
||||
fp = nlm_files + i;
|
||||
while ((file = *fp) != NULL) {
|
||||
file->f_count++;
|
||||
mutex_unlock(&nlm_file_mutex);
|
||||
|
||||
/* Traverse locks, blocks and shares of this file
|
||||
* and update file->f_locks count */
|
||||
if (nlm_inspect_file(host, file, action)) {
|
||||
mutex_unlock(&nlm_file_mutex);
|
||||
return 1;
|
||||
}
|
||||
if (nlm_inspect_file(host, file, action))
|
||||
ret = 1;
|
||||
|
||||
mutex_lock(&nlm_file_mutex);
|
||||
file->f_count--;
|
||||
/* No more references to this file. Let go of it. */
|
||||
if (!file->f_blocks && !file->f_locks
|
||||
&& !file->f_shares && !file->f_count) {
|
||||
@ -262,7 +265,7 @@ nlm_traverse_files(struct nlm_host *host, int action)
|
||||
}
|
||||
}
|
||||
mutex_unlock(&nlm_file_mutex);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
11
fs/namei.c
11
fs/namei.c
@ -227,10 +227,10 @@ int generic_permission(struct inode *inode, int mask,
|
||||
|
||||
int permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
{
|
||||
umode_t mode = inode->i_mode;
|
||||
int retval, submask;
|
||||
|
||||
if (mask & MAY_WRITE) {
|
||||
umode_t mode = inode->i_mode;
|
||||
|
||||
/*
|
||||
* Nobody gets write access to a read-only fs.
|
||||
@ -247,6 +247,13 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MAY_EXEC on regular files requires special handling: We override
|
||||
* filesystem execute permissions if the mode bits aren't set.
|
||||
*/
|
||||
if ((mask & MAY_EXEC) && S_ISREG(mode) && !(mode & S_IXUGO))
|
||||
return -EACCES;
|
||||
|
||||
/* Ordinary permission routines do not understand MAY_APPEND. */
|
||||
submask = mask & ~MAY_APPEND;
|
||||
if (inode->i_op && inode->i_op->permission)
|
||||
@ -1767,6 +1774,8 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir)
|
||||
if (nd->last_type != LAST_NORM)
|
||||
goto fail;
|
||||
nd->flags &= ~LOOKUP_PARENT;
|
||||
nd->flags |= LOOKUP_CREATE;
|
||||
nd->intent.open.flags = O_EXCL;
|
||||
|
||||
/*
|
||||
* Do the final lookup.
|
||||
|
@ -312,7 +312,13 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset)
|
||||
|
||||
static int nfs_release_page(struct page *page, gfp_t gfp)
|
||||
{
|
||||
return !nfs_wb_page(page->mapping->host, page);
|
||||
if (gfp & __GFP_FS)
|
||||
return !nfs_wb_page(page->mapping->host, page);
|
||||
else
|
||||
/*
|
||||
* Avoid deadlock on nfs_wait_on_request().
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct address_space_operations nfs_file_aops = {
|
||||
|
@ -130,9 +130,7 @@ nfs_idmap_delete(struct nfs4_client *clp)
|
||||
|
||||
if (!idmap)
|
||||
return;
|
||||
dput(idmap->idmap_dentry);
|
||||
idmap->idmap_dentry = NULL;
|
||||
rpc_unlink(idmap->idmap_path);
|
||||
rpc_unlink(idmap->idmap_dentry);
|
||||
clp->cl_idmap = NULL;
|
||||
kfree(idmap);
|
||||
}
|
||||
|
@ -2668,7 +2668,7 @@ out:
|
||||
nfs4_set_cached_acl(inode, acl);
|
||||
}
|
||||
|
||||
static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
|
||||
static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
|
||||
{
|
||||
struct page *pages[NFS4ACL_MAXPAGES];
|
||||
struct nfs_getaclargs args = {
|
||||
@ -2721,6 +2721,19 @@ out_free:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
ssize_t ret;
|
||||
do {
|
||||
ret = __nfs4_get_acl_uncached(inode, buf, buflen);
|
||||
if (ret >= 0)
|
||||
break;
|
||||
ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception);
|
||||
} while (exception.retry);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
@ -2737,7 +2750,7 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
|
||||
return nfs4_get_acl_uncached(inode, buf, buflen);
|
||||
}
|
||||
|
||||
static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
|
||||
static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
struct page *pages[NFS4ACL_MAXPAGES];
|
||||
@ -2763,6 +2776,18 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
int err;
|
||||
do {
|
||||
err = nfs4_handle_exception(NFS_SERVER(inode),
|
||||
__nfs4_proc_set_acl(inode, buf, buflen),
|
||||
&exception);
|
||||
} while (exception.retry);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
|
||||
{
|
||||
|
@ -3355,7 +3355,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
|
||||
struct kvec *iov = rcvbuf->head;
|
||||
unsigned int nr, pglen = rcvbuf->page_len;
|
||||
uint32_t *end, *entry, *p, *kaddr;
|
||||
uint32_t len, attrlen;
|
||||
uint32_t len, attrlen, xlen;
|
||||
int hdrlen, recvd, status;
|
||||
|
||||
status = decode_op_hdr(xdr, OP_READDIR);
|
||||
@ -3377,10 +3377,10 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
|
||||
|
||||
BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
|
||||
kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0);
|
||||
end = (uint32_t *) ((char *)p + pglen + readdir->pgbase);
|
||||
end = p + ((pglen + readdir->pgbase) >> 2);
|
||||
entry = p;
|
||||
for (nr = 0; *p++; nr++) {
|
||||
if (p + 3 > end)
|
||||
if (end - p < 3)
|
||||
goto short_pkt;
|
||||
dprintk("cookie = %Lu, ", *((unsigned long long *)p));
|
||||
p += 2; /* cookie */
|
||||
@ -3389,18 +3389,19 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
|
||||
printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
|
||||
goto err_unmap;
|
||||
}
|
||||
xlen = XDR_QUADLEN(len);
|
||||
if (end - p < xlen + 1)
|
||||
goto short_pkt;
|
||||
dprintk("filename = %*s\n", len, (char *)p);
|
||||
p += XDR_QUADLEN(len);
|
||||
if (p + 1 > end)
|
||||
goto short_pkt;
|
||||
p += xlen;
|
||||
len = ntohl(*p++); /* bitmap length */
|
||||
if (end - p < len + 1)
|
||||
goto short_pkt;
|
||||
p += len;
|
||||
if (p + 1 > end)
|
||||
goto short_pkt;
|
||||
attrlen = XDR_QUADLEN(ntohl(*p++));
|
||||
p += attrlen; /* attributes */
|
||||
if (p + 2 > end)
|
||||
if (end - p < attrlen + 2)
|
||||
goto short_pkt;
|
||||
p += attrlen; /* attributes */
|
||||
entry = p;
|
||||
}
|
||||
if (!nr && (entry[0] != 0 || entry[1] == 0))
|
||||
|
@ -116,10 +116,17 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data)
|
||||
pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
|
||||
base &= ~PAGE_CACHE_MASK;
|
||||
pglen = PAGE_CACHE_SIZE - base;
|
||||
if (pglen < remainder)
|
||||
for (;;) {
|
||||
if (remainder <= pglen) {
|
||||
memclear_highpage_flush(*pages, base, remainder);
|
||||
break;
|
||||
}
|
||||
memclear_highpage_flush(*pages, base, pglen);
|
||||
else
|
||||
memclear_highpage_flush(*pages, base, remainder);
|
||||
pages++;
|
||||
remainder -= pglen;
|
||||
pglen = PAGE_CACHE_SIZE;
|
||||
base = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -476,6 +483,8 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
|
||||
unsigned int base = data->args.pgbase;
|
||||
struct page **pages;
|
||||
|
||||
if (data->res.eof)
|
||||
count = data->args.count;
|
||||
if (unlikely(count == 0))
|
||||
return;
|
||||
pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
|
||||
@ -483,11 +492,7 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
|
||||
count += base;
|
||||
for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
|
||||
SetPageUptodate(*pages);
|
||||
/*
|
||||
* Was this an eof or a short read? If the latter, don't mark the page
|
||||
* as uptodate yet.
|
||||
*/
|
||||
if (count > 0 && (data->res.eof || data->args.count == data->res.count))
|
||||
if (count != 0)
|
||||
SetPageUptodate(*pages);
|
||||
}
|
||||
|
||||
@ -502,6 +507,8 @@ static void nfs_readpage_set_pages_error(struct nfs_read_data *data)
|
||||
count += base;
|
||||
for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
|
||||
SetPageError(*pages);
|
||||
if (count != 0)
|
||||
SetPageError(*pages);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -659,7 +659,7 @@ struct nfs4_rename_res {
|
||||
struct nfs4_setclientid {
|
||||
const nfs4_verifier * sc_verifier; /* request */
|
||||
unsigned int sc_name_len;
|
||||
char sc_name[32]; /* request */
|
||||
char sc_name[48]; /* request */
|
||||
u32 sc_prog; /* request */
|
||||
unsigned int sc_netid_len;
|
||||
char sc_netid[4]; /* request */
|
||||
|
@ -42,9 +42,9 @@ RPC_I(struct inode *inode)
|
||||
extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
|
||||
|
||||
extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
|
||||
extern int rpc_rmdir(char *);
|
||||
extern int rpc_rmdir(struct dentry *);
|
||||
extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags);
|
||||
extern int rpc_unlink(char *);
|
||||
extern int rpc_unlink(struct dentry *);
|
||||
extern struct vfsmount *rpc_get_mount(void);
|
||||
extern void rpc_put_mount(void);
|
||||
|
||||
|
@ -37,7 +37,7 @@ extern unsigned int xprt_max_resvport;
|
||||
|
||||
#define RPC_MIN_RESVPORT (1U)
|
||||
#define RPC_MAX_RESVPORT (65535U)
|
||||
#define RPC_DEF_MIN_RESVPORT (650U)
|
||||
#define RPC_DEF_MIN_RESVPORT (665U)
|
||||
#define RPC_DEF_MAX_RESVPORT (1023U)
|
||||
|
||||
/*
|
||||
|
@ -718,8 +718,7 @@ gss_destroy(struct rpc_auth *auth)
|
||||
auth, auth->au_flavor);
|
||||
|
||||
gss_auth = container_of(auth, struct gss_auth, rpc_auth);
|
||||
rpc_unlink(gss_auth->path);
|
||||
dput(gss_auth->dentry);
|
||||
rpc_unlink(gss_auth->dentry);
|
||||
gss_auth->dentry = NULL;
|
||||
gss_mech_put(gss_auth->mech);
|
||||
|
||||
|
@ -183,8 +183,7 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname,
|
||||
|
||||
out_no_auth:
|
||||
if (!IS_ERR(clnt->cl_dentry)) {
|
||||
rpc_rmdir(clnt->cl_pathname);
|
||||
dput(clnt->cl_dentry);
|
||||
rpc_rmdir(clnt->cl_dentry);
|
||||
rpc_put_mount();
|
||||
}
|
||||
out_no_path:
|
||||
@ -251,10 +250,8 @@ rpc_clone_client(struct rpc_clnt *clnt)
|
||||
new->cl_autobind = 0;
|
||||
new->cl_oneshot = 0;
|
||||
new->cl_dead = 0;
|
||||
if (!IS_ERR(new->cl_dentry)) {
|
||||
if (!IS_ERR(new->cl_dentry))
|
||||
dget(new->cl_dentry);
|
||||
rpc_get_mount();
|
||||
}
|
||||
rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
|
||||
if (new->cl_auth)
|
||||
atomic_inc(&new->cl_auth->au_count);
|
||||
@ -317,11 +314,15 @@ rpc_destroy_client(struct rpc_clnt *clnt)
|
||||
clnt->cl_auth = NULL;
|
||||
}
|
||||
if (clnt->cl_parent != clnt) {
|
||||
if (!IS_ERR(clnt->cl_dentry))
|
||||
dput(clnt->cl_dentry);
|
||||
rpc_destroy_client(clnt->cl_parent);
|
||||
goto out_free;
|
||||
}
|
||||
if (clnt->cl_pathname[0])
|
||||
rpc_rmdir(clnt->cl_pathname);
|
||||
if (!IS_ERR(clnt->cl_dentry)) {
|
||||
rpc_rmdir(clnt->cl_dentry);
|
||||
rpc_put_mount();
|
||||
}
|
||||
if (clnt->cl_xprt) {
|
||||
xprt_destroy(clnt->cl_xprt);
|
||||
clnt->cl_xprt = NULL;
|
||||
@ -331,10 +332,6 @@ rpc_destroy_client(struct rpc_clnt *clnt)
|
||||
out_free:
|
||||
rpc_free_iostats(clnt->cl_metrics);
|
||||
clnt->cl_metrics = NULL;
|
||||
if (!IS_ERR(clnt->cl_dentry)) {
|
||||
dput(clnt->cl_dentry);
|
||||
rpc_put_mount();
|
||||
}
|
||||
kfree(clnt);
|
||||
return 0;
|
||||
}
|
||||
@ -1184,6 +1181,17 @@ call_verify(struct rpc_task *task)
|
||||
u32 *p = iov->iov_base, n;
|
||||
int error = -EACCES;
|
||||
|
||||
if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) {
|
||||
/* RFC-1014 says that the representation of XDR data must be a
|
||||
* multiple of four bytes
|
||||
* - if it isn't pointer subtraction in the NFS client may give
|
||||
* undefined results
|
||||
*/
|
||||
printk(KERN_WARNING
|
||||
"call_verify: XDR representation not a multiple of"
|
||||
" 4 bytes: 0x%x\n", task->tk_rqstp->rq_rcv_buf.len);
|
||||
goto out_eio;
|
||||
}
|
||||
if ((len -= 3) < 0)
|
||||
goto out_overflow;
|
||||
p += 1; /* skip XID */
|
||||
|
@ -539,6 +539,7 @@ repeat:
|
||||
rpc_close_pipes(dentry->d_inode);
|
||||
simple_unlink(dir, dentry);
|
||||
}
|
||||
inode_dir_notify(dir, DN_DELETE);
|
||||
dput(dentry);
|
||||
} while (n);
|
||||
goto repeat;
|
||||
@ -610,8 +611,8 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
int error;
|
||||
|
||||
shrink_dcache_parent(dentry);
|
||||
if (dentry->d_inode)
|
||||
rpc_close_pipes(dentry->d_inode);
|
||||
if (d_unhashed(dentry))
|
||||
return 0;
|
||||
if ((error = simple_rmdir(dir, dentry)) != 0)
|
||||
return error;
|
||||
if (!error) {
|
||||
@ -684,28 +685,20 @@ err_dput:
|
||||
}
|
||||
|
||||
int
|
||||
rpc_rmdir(char *path)
|
||||
rpc_rmdir(struct dentry *dentry)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct dentry *dentry;
|
||||
struct dentry *parent;
|
||||
struct inode *dir;
|
||||
int error;
|
||||
|
||||
if ((error = rpc_lookup_parent(path, &nd)) != 0)
|
||||
return error;
|
||||
dir = nd.dentry->d_inode;
|
||||
parent = dget_parent(dentry);
|
||||
dir = parent->d_inode;
|
||||
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
|
||||
if (IS_ERR(dentry)) {
|
||||
error = PTR_ERR(dentry);
|
||||
goto out_release;
|
||||
}
|
||||
rpc_depopulate(dentry);
|
||||
error = __rpc_rmdir(dir, dentry);
|
||||
dput(dentry);
|
||||
out_release:
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
rpc_release_path(&nd);
|
||||
dput(parent);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -746,32 +739,26 @@ err_dput:
|
||||
}
|
||||
|
||||
int
|
||||
rpc_unlink(char *path)
|
||||
rpc_unlink(struct dentry *dentry)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct dentry *dentry;
|
||||
struct dentry *parent;
|
||||
struct inode *dir;
|
||||
int error;
|
||||
int error = 0;
|
||||
|
||||
if ((error = rpc_lookup_parent(path, &nd)) != 0)
|
||||
return error;
|
||||
dir = nd.dentry->d_inode;
|
||||
parent = dget_parent(dentry);
|
||||
dir = parent->d_inode;
|
||||
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
|
||||
dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
|
||||
if (IS_ERR(dentry)) {
|
||||
error = PTR_ERR(dentry);
|
||||
goto out_release;
|
||||
}
|
||||
d_drop(dentry);
|
||||
if (dentry->d_inode) {
|
||||
rpc_close_pipes(dentry->d_inode);
|
||||
error = simple_unlink(dir, dentry);
|
||||
if (!d_unhashed(dentry)) {
|
||||
d_drop(dentry);
|
||||
if (dentry->d_inode) {
|
||||
rpc_close_pipes(dentry->d_inode);
|
||||
error = simple_unlink(dir, dentry);
|
||||
}
|
||||
inode_dir_notify(dir, DN_DELETE);
|
||||
}
|
||||
dput(dentry);
|
||||
inode_dir_notify(dir, DN_DELETE);
|
||||
out_release:
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
rpc_release_path(&nd);
|
||||
dput(parent);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user