[PATCH] fuse: fix hang on SMP
[safe/jmp/linux-2.6] / fs / fuse / dir.c
index 417bcee..a8f65c1 100644 (file)
@@ -1,6 +1,6 @@
 /*
   FUSE: Filesystem in Userspace
-  Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>
+  Copyright (C) 2001-2006  Miklos Szeredi <miklos@szeredi.hu>
 
   This program can be distributed under the terms of the GNU GPL.
   See the file COPYING.
 #include <linux/sched.h>
 #include <linux/namei.h>
 
+#if BITS_PER_LONG >= 64
+static inline void fuse_dentry_settime(struct dentry *entry, u64 time)
+{
+       entry->d_time = time;
+}
+
+static inline u64 fuse_dentry_time(struct dentry *entry)
+{
+       return entry->d_time;
+}
+#else
+/*
+ * On 32 bit archs store the high 32 bits of time in d_fsdata
+ */
+static void fuse_dentry_settime(struct dentry *entry, u64 time)
+{
+       entry->d_time = time;
+       entry->d_fsdata = (void *) (unsigned long) (time >> 32);
+}
+
+static u64 fuse_dentry_time(struct dentry *entry)
+{
+       return (u64) entry->d_time +
+               ((u64) (unsigned long) entry->d_fsdata << 32);
+}
+#endif
+
 /*
  * FUSE caches dentries and attributes with separate timeout.  The
  * time in jiffies until the dentry/attributes are valid is stored in
 /*
  * Calculate the time in jiffies until a dentry/attributes are valid
  */
-static inline unsigned long time_to_jiffies(unsigned long sec,
-                                           unsigned long nsec)
+static u64 time_to_jiffies(unsigned long sec, unsigned long nsec)
 {
-       struct timespec ts = {sec, nsec};
-       return jiffies + timespec_to_jiffies(&ts);
+       if (sec || nsec) {
+               struct timespec ts = {sec, nsec};
+               return get_jiffies_64() + timespec_to_jiffies(&ts);
+       } else
+               return 0;
 }
 
 /*
@@ -36,7 +65,8 @@ static inline unsigned long time_to_jiffies(unsigned long sec,
  */
 static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
 {
-       entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec);
+       fuse_dentry_settime(entry,
+               time_to_jiffies(o->entry_valid, o->entry_valid_nsec));
        if (entry->d_inode)
                get_fuse_inode(entry->d_inode)->i_time =
                        time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
@@ -48,7 +78,7 @@ static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
  */
 void fuse_invalidate_attr(struct inode *inode)
 {
-       get_fuse_inode(inode)->i_time = jiffies - 1;
+       get_fuse_inode(inode)->i_time = 0;
 }
 
 /*
@@ -61,7 +91,7 @@ void fuse_invalidate_attr(struct inode *inode)
  */
 static void fuse_invalidate_entry_cache(struct dentry *entry)
 {
-       entry->d_time = jiffies - 1;
+       fuse_dentry_settime(entry, 0);
 }
 
 /*
@@ -80,7 +110,6 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
 {
        req->in.h.opcode = FUSE_LOOKUP;
        req->in.h.nodeid = get_node_id(dir);
-       req->inode = dir;
        req->in.numargs = 1;
        req->in.args[0].size = entry->d_name.len + 1;
        req->in.args[0].value = entry->d_name.name;
@@ -104,7 +133,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
 
        if (inode && is_bad_inode(inode))
                return 0;
-       else if (time_after(jiffies, entry->d_time)) {
+       else if (fuse_dentry_time(entry) < get_jiffies_64()) {
                int err;
                struct fuse_entry_out outarg;
                struct fuse_conn *fc;
@@ -112,17 +141,22 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
 
                /* Doesn't hurt to "reset" the validity timeout */
                fuse_invalidate_entry_cache(entry);
+
+               /* For negative dentries, always do a fresh lookup */
                if (!inode)
                        return 0;
 
                fc = get_fuse_conn(inode);
-               req = fuse_get_request(fc);
-               if (!req)
+               req = fuse_get_req(fc);
+               if (IS_ERR(req))
                        return 0;
 
                fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
                request_send(fc, req);
                err = req->out.h.error;
+               /* Zero nodeid is same as -ENOENT */
+               if (!err && !outarg.nodeid)
+                       err = -ENOENT;
                if (!err) {
                        struct fuse_inode *fi = get_fuse_inode(inode);
                        if (outarg.nodeid != get_node_id(inode)) {
@@ -157,7 +191,7 @@ static int dir_alias(struct inode *inode)
        return 0;
 }
 
-static inline int invalid_nodeid(u64 nodeid)
+static int invalid_nodeid(u64 nodeid)
 {
        return !nodeid || nodeid == FUSE_ROOT_ID;
 }
@@ -166,7 +200,7 @@ static struct dentry_operations fuse_dentry_operations = {
        .d_revalidate   = fuse_dentry_revalidate,
 };
 
-static inline int valid_mode(int m)
+static int valid_mode(int m)
 {
        return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
                S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
@@ -184,15 +218,16 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
        if (entry->d_name.len > FUSE_NAME_MAX)
                return ERR_PTR(-ENAMETOOLONG);
 
-       req = fuse_get_request(fc);
-       if (!req)
-               return ERR_PTR(-EINTR);
+       req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return ERR_PTR(PTR_ERR(req));
 
        fuse_lookup_init(req, dir, entry, &outarg);
        request_send(fc, req);
        err = req->out.h.error;
-       if (!err && ((outarg.nodeid && invalid_nodeid(outarg.nodeid)) ||
-                    !valid_mode(outarg.attr.mode)))
+       /* Zero nodeid is same as -ENOENT, but with valid timeout */
+       if (!err && outarg.nodeid &&
+           (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode)))
                err = -EIO;
        if (!err && outarg.nodeid) {
                inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
@@ -220,6 +255,20 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
 }
 
 /*
+ * Synchronous release for the case when something goes wrong in CREATE_OPEN
+ */
+static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
+                             u64 nodeid, int flags)
+{
+       struct fuse_req *req;
+
+       req = fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
+       req->force = 1;
+       request_send(fc, req);
+       fuse_put_request(fc, req);
+}
+
+/*
  * Atomic create+open operation
  *
  * If the filesystem doesn't support this, then fall back to separate
@@ -232,6 +281,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        struct inode *inode;
        struct fuse_conn *fc = get_fuse_conn(dir);
        struct fuse_req *req;
+       struct fuse_req *forget_req;
        struct fuse_open_in inarg;
        struct fuse_open_out outopen;
        struct fuse_entry_out outentry;
@@ -239,15 +289,19 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        struct file *file;
        int flags = nd->intent.open.flags - 1;
 
-       err = -ENOSYS;
        if (fc->no_create)
-               goto out;
+               return -ENOSYS;
 
-       err = -EINTR;
-       req = fuse_get_request(fc);
-       if (!req)
-               goto out;
+       forget_req = fuse_get_req(fc);
+       if (IS_ERR(forget_req))
+               return PTR_ERR(forget_req);
 
+       req = fuse_get_req(fc);
+       err = PTR_ERR(req);
+       if (IS_ERR(req))
+               goto out_put_forget_req;
+
+       err = -ENOMEM;
        ff = fuse_file_alloc();
        if (!ff)
                goto out_put_request;
@@ -258,7 +312,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        inarg.mode = mode;
        req->in.h.opcode = FUSE_CREATE;
        req->in.h.nodeid = get_node_id(dir);
-       req->inode = dir;
        req->in.numargs = 2;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -281,25 +334,23 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
                goto out_free_ff;
 
+       fuse_put_request(fc, req);
        inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
                          &outentry.attr);
-       err = -ENOMEM;
        if (!inode) {
                flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
                ff->fh = outopen.fh;
-               /* Special release, with inode = NULL, this will
-                  trigger a 'forget' request when the release is
-                  complete */
-               fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
-               goto out_put_request;
+               fuse_sync_release(fc, ff, outentry.nodeid, flags);
+               fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
+               return -ENOMEM;
        }
-       fuse_put_request(fc, req);
+       fuse_put_request(fc, forget_req);
        d_instantiate(entry, inode);
        fuse_change_timeout(entry, &outentry);
        file = lookup_instantiate_filp(nd, entry, generic_file_open);
        if (IS_ERR(file)) {
                ff->fh = outopen.fh;
-               fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
+               fuse_sync_release(fc, ff, outentry.nodeid, flags);
                return PTR_ERR(file);
        }
        fuse_finish_open(inode, file, ff, &outopen);
@@ -309,7 +360,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        fuse_file_free(ff);
  out_put_request:
        fuse_put_request(fc, req);
- out:
+ out_put_forget_req:
+       fuse_put_request(fc, forget_req);
        return err;
 }
 
@@ -325,7 +377,6 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
        int err;
 
        req->in.h.nodeid = get_node_id(dir);
-       req->inode = dir;
        req->out.numargs = 1;
        req->out.args[0].size = sizeof(outarg);
        req->out.args[0].value = &outarg;
@@ -370,9 +421,9 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
 {
        struct fuse_mknod_in inarg;
        struct fuse_conn *fc = get_fuse_conn(dir);
-       struct fuse_req *req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       struct fuse_req *req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.mode = mode;
@@ -402,9 +453,9 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
 {
        struct fuse_mkdir_in inarg;
        struct fuse_conn *fc = get_fuse_conn(dir);
-       struct fuse_req *req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       struct fuse_req *req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.mode = mode;
@@ -422,9 +473,9 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
 {
        struct fuse_conn *fc = get_fuse_conn(dir);
        unsigned len = strlen(link) + 1;
-       struct fuse_req *req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       struct fuse_req *req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        req->in.h.opcode = FUSE_SYMLINK;
        req->in.numargs = 2;
@@ -439,13 +490,12 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
 {
        int err;
        struct fuse_conn *fc = get_fuse_conn(dir);
-       struct fuse_req *req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       struct fuse_req *req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        req->in.h.opcode = FUSE_UNLINK;
        req->in.h.nodeid = get_node_id(dir);
-       req->inode = dir;
        req->in.numargs = 1;
        req->in.args[0].size = entry->d_name.len + 1;
        req->in.args[0].value = entry->d_name.name;
@@ -458,7 +508,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
                /* Set nlink to zero so the inode can be cleared, if
                    the inode does have more links this will be
                    discovered at the next lookup/getattr */
-               inode->i_nlink = 0;
+               clear_nlink(inode);
                fuse_invalidate_attr(inode);
                fuse_invalidate_attr(dir);
                fuse_invalidate_entry_cache(entry);
@@ -471,13 +521,12 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
 {
        int err;
        struct fuse_conn *fc = get_fuse_conn(dir);
-       struct fuse_req *req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       struct fuse_req *req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        req->in.h.opcode = FUSE_RMDIR;
        req->in.h.nodeid = get_node_id(dir);
-       req->inode = dir;
        req->in.numargs = 1;
        req->in.args[0].size = entry->d_name.len + 1;
        req->in.args[0].value = entry->d_name.name;
@@ -485,7 +534,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
        err = req->out.h.error;
        fuse_put_request(fc, req);
        if (!err) {
-               entry->d_inode->i_nlink = 0;
+               clear_nlink(entry->d_inode);
                fuse_invalidate_attr(dir);
                fuse_invalidate_entry_cache(entry);
        } else if (err == -EINTR)
@@ -499,16 +548,14 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
        int err;
        struct fuse_rename_in inarg;
        struct fuse_conn *fc = get_fuse_conn(olddir);
-       struct fuse_req *req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       struct fuse_req *req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.newdir = get_node_id(newdir);
        req->in.h.opcode = FUSE_RENAME;
        req->in.h.nodeid = get_node_id(olddir);
-       req->inode = olddir;
-       req->inode2 = newdir;
        req->in.numargs = 3;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -548,14 +595,13 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
        struct fuse_link_in inarg;
        struct inode *inode = entry->d_inode;
        struct fuse_conn *fc = get_fuse_conn(inode);
-       struct fuse_req *req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       struct fuse_req *req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.oldnodeid = get_node_id(inode);
        req->in.h.opcode = FUSE_LINK;
-       req->inode2 = inode;
        req->in.numargs = 2;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -578,13 +624,12 @@ int fuse_do_getattr(struct inode *inode)
        int err;
        struct fuse_attr_out arg;
        struct fuse_conn *fc = get_fuse_conn(inode);
-       struct fuse_req *req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       struct fuse_req *req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        req->in.h.opcode = FUSE_GETATTR;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->out.numargs = 1;
        req->out.args[0].size = sizeof(arg);
        req->out.args[0].value = &arg;
@@ -652,7 +697,7 @@ static int fuse_revalidate(struct dentry *entry)
        if (!fuse_allow_task(fc, current))
                return -EACCES;
        if (get_node_id(inode) != FUSE_ROOT_ID &&
-           time_before_eq(jiffies, fi->i_time))
+           fi->i_time >= get_jiffies_64())
                return 0;
 
        return fuse_do_getattr(inode);
@@ -668,15 +713,14 @@ static int fuse_access(struct inode *inode, int mask)
        if (fc->no_access)
                return 0;
 
-       req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.mask = mask;
        req->in.h.opcode = FUSE_ACCESS;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -732,7 +776,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
                if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
                        return -EACCES;
 
-               if (nd && (nd->flags & LOOKUP_ACCESS))
+               if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR)))
                        return fuse_access(inode, mask);
                return 0;
        }
@@ -763,13 +807,6 @@ static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
        return 0;
 }
 
-static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
-                                      struct inode *inode, loff_t pos,
-                                      size_t count)
-{
-       return fuse_send_read_common(req, file, inode, pos, count, 1);
-}
-
 static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
 {
        int err;
@@ -782,9 +819,9 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
        if (is_bad_inode(inode))
                return -EIO;
 
-       req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        page = alloc_page(GFP_KERNEL);
        if (!page) {
@@ -793,7 +830,9 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
        }
        req->num_pages = 1;
        req->pages[0] = page;
-       nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
+       fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
+       request_send(fc, req);
+       nbytes = req->out.args[0].size;
        err = req->out.h.error;
        fuse_put_request(fc, req);
        if (!err)
@@ -809,11 +848,11 @@ static char *read_link(struct dentry *dentry)
 {
        struct inode *inode = dentry->d_inode;
        struct fuse_conn *fc = get_fuse_conn(inode);
-       struct fuse_req *req = fuse_get_request(fc);
+       struct fuse_req *req = fuse_get_req(fc);
        char *link;
 
-       if (!req)
-               return ERR_PTR(-EINTR);
+       if (IS_ERR(req))
+               return ERR_PTR(PTR_ERR(req));
 
        link = (char *) __get_free_page(GFP_KERNEL);
        if (!link) {
@@ -822,7 +861,6 @@ static char *read_link(struct dentry *dentry)
        }
        req->in.h.opcode = FUSE_READLINK;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->out.argvar = 1;
        req->out.numargs = 1;
        req->out.args[0].size = PAGE_SIZE - 1;
@@ -897,14 +935,30 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
        }
 }
 
+static void fuse_vmtruncate(struct inode *inode, loff_t offset)
+{
+       struct fuse_conn *fc = get_fuse_conn(inode);
+       int need_trunc;
+
+       spin_lock(&fc->lock);
+       need_trunc = inode->i_size > offset;
+       i_size_write(inode, offset);
+       spin_unlock(&fc->lock);
+
+       if (need_trunc) {
+               struct address_space *mapping = inode->i_mapping;
+               unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+               truncate_inode_pages(mapping, offset);
+       }
+}
+
 /*
  * Set attributes, and at the same time refresh them.
  *
  * Truncation is slightly complicated, because the 'truncate' request
  * may fail, in which case we don't want to touch the mapping.
- * vmtruncate() doesn't allow for this case.  So do the rlimit
- * checking by hand and call vmtruncate() only after the file has
- * actually been truncated.
+ * vmtruncate() doesn't allow for this case, so do the rlimit checking
+ * and the actual truncation by hand.
  */
 static int fuse_setattr(struct dentry *entry, struct iattr *attr)
 {
@@ -933,15 +987,14 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
                }
        }
 
-       req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        memset(&inarg, 0, sizeof(inarg));
        iattr_to_fattr(attr, &inarg);
        req->in.h.opcode = FUSE_SETATTR;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -956,12 +1009,8 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
                        make_bad_inode(inode);
                        err = -EIO;
                } else {
-                       if (is_truncate) {
-                               loff_t origsize = i_size_read(inode);
-                               i_size_write(inode, outarg.attr.size);
-                               if (origsize > outarg.attr.size)
-                                       vmtruncate(inode, outarg.attr.size);
-                       }
+                       if (is_truncate)
+                               fuse_vmtruncate(inode, outarg.attr.size);
                        fuse_change_attributes(inode, &outarg.attr);
                        fi->i_time = time_to_jiffies(outarg.attr_valid,
                                                     outarg.attr_valid_nsec);
@@ -995,16 +1044,15 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
        if (fc->no_setxattr)
                return -EOPNOTSUPP;
 
-       req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.size = size;
        inarg.flags = flags;
        req->in.h.opcode = FUSE_SETXATTR;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 3;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -1035,15 +1083,14 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
        if (fc->no_getxattr)
                return -EOPNOTSUPP;
 
-       req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.size = size;
        req->in.h.opcode = FUSE_GETXATTR;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 2;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -1085,15 +1132,14 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
        if (fc->no_listxattr)
                return -EOPNOTSUPP;
 
-       req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.size = size;
        req->in.h.opcode = FUSE_LISTXATTR;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
@@ -1131,13 +1177,12 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
        if (fc->no_removexattr)
                return -EOPNOTSUPP;
 
-       req = fuse_get_request(fc);
-       if (!req)
-               return -EINTR;
+       req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
 
        req->in.h.opcode = FUSE_REMOVEXATTR;
        req->in.h.nodeid = get_node_id(inode);
-       req->inode = inode;
        req->in.numargs = 1;
        req->in.args[0].size = strlen(name) + 1;
        req->in.args[0].value = name;
@@ -1170,7 +1215,7 @@ static struct inode_operations fuse_dir_inode_operations = {
        .removexattr    = fuse_removexattr,
 };
 
-static struct file_operations fuse_dir_operations = {
+static const struct file_operations fuse_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = fuse_readdir,