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);
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;
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) {
}
}
mutex_unlock(&nlm_file_mutex);
- return 0;
+ return ret;
}
/*
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.
}
+ /*
+ * 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)
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.
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 = {
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);
}
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 = {
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);
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];
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)
{
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);
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 */
printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
goto err_unmap;
}
- dprintk("filename = %*s\n", len, (char *)p);
- p += XDR_QUADLEN(len);
- if (p + 1 > end)
+ xlen = XDR_QUADLEN(len);
+ if (end - p < xlen + 1)
goto short_pkt;
+ dprintk("filename = %*s\n", len, (char *)p);
+ p += xlen;
len = ntohl(*p++); /* bitmap length */
- p += len;
- if (p + 1 > end)
+ if (end - p < len + 1)
goto short_pkt;
+ p += len;
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))
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;
+ }
}
/*
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];
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);
}
count += base;
for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
SetPageError(*pages);
+ if (count != 0)
+ SetPageError(*pages);
}
/*
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 */
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);
#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)
/*
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);
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:
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);
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;
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;
}
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 */
rpc_close_pipes(dentry->d_inode);
simple_unlink(dir, dentry);
}
+ inode_dir_notify(dir, DN_DELETE);
dput(dentry);
} while (n);
goto repeat;
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) {
}
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;
}
}
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;
}