1e5e5558eSMiklos Szeredi /*
2e5e5558eSMiklos Szeredi FUSE: Filesystem in Userspace
31729a16cSMiklos Szeredi Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
4e5e5558eSMiklos Szeredi
5e5e5558eSMiklos Szeredi This program can be distributed under the terms of the GNU GPL.
6e5e5558eSMiklos Szeredi See the file COPYING.
7e5e5558eSMiklos Szeredi */
8e5e5558eSMiklos Szeredi
9e5e5558eSMiklos Szeredi #include "fuse_i.h"
10e5e5558eSMiklos Szeredi
11e5e5558eSMiklos Szeredi #include <linux/pagemap.h>
12e5e5558eSMiklos Szeredi #include <linux/file.h>
13bf109c64SMax Reitz #include <linux/fs_context.h>
149ccf47b2SDave Marchevsky #include <linux/moduleparam.h>
15e5e5558eSMiklos Szeredi #include <linux/sched.h>
16e5e5558eSMiklos Szeredi #include <linux/namei.h>
1707e77dcaSMiklos Szeredi #include <linux/slab.h>
18703c7362SSeth Forshee #include <linux/xattr.h>
19261aaba7SMiklos Szeredi #include <linux/iversion.h>
2060bcc88aSSeth Forshee #include <linux/posix_acl.h>
213e2b6fdbSVivek Goyal #include <linux/security.h>
223e2b6fdbSVivek Goyal #include <linux/types.h>
233e2b6fdbSVivek Goyal #include <linux/kernel.h>
24e5e5558eSMiklos Szeredi
259ccf47b2SDave Marchevsky static bool __read_mostly allow_sys_admin_access;
269ccf47b2SDave Marchevsky module_param(allow_sys_admin_access, bool, 0644);
279ccf47b2SDave Marchevsky MODULE_PARM_DESC(allow_sys_admin_access,
289ccf47b2SDave Marchevsky "Allow users with CAP_SYS_ADMIN in initial userns to bypass allow_other access check");
299ccf47b2SDave Marchevsky
fuse_advise_use_readdirplus(struct inode * dir)304582a4abSFeng Shuo static void fuse_advise_use_readdirplus(struct inode *dir)
314582a4abSFeng Shuo {
324582a4abSFeng Shuo struct fuse_inode *fi = get_fuse_inode(dir);
334582a4abSFeng Shuo
344582a4abSFeng Shuo set_bit(FUSE_I_ADVISE_RDPLUS, &fi->state);
354582a4abSFeng Shuo }
364582a4abSFeng Shuo
3730c6a23dSKhazhismel Kumykov #if BITS_PER_LONG >= 64
__fuse_dentry_settime(struct dentry * entry,u64 time)3830c6a23dSKhazhismel Kumykov static inline void __fuse_dentry_settime(struct dentry *entry, u64 time)
3930c6a23dSKhazhismel Kumykov {
4030c6a23dSKhazhismel Kumykov entry->d_fsdata = (void *) time;
4130c6a23dSKhazhismel Kumykov }
4230c6a23dSKhazhismel Kumykov
fuse_dentry_time(const struct dentry * entry)4330c6a23dSKhazhismel Kumykov static inline u64 fuse_dentry_time(const struct dentry *entry)
4430c6a23dSKhazhismel Kumykov {
4530c6a23dSKhazhismel Kumykov return (u64)entry->d_fsdata;
4630c6a23dSKhazhismel Kumykov }
4730c6a23dSKhazhismel Kumykov
4830c6a23dSKhazhismel Kumykov #else
49f75fdf22SMiklos Szeredi union fuse_dentry {
50f75fdf22SMiklos Szeredi u64 time;
51f75fdf22SMiklos Szeredi struct rcu_head rcu;
52f75fdf22SMiklos Szeredi };
53f75fdf22SMiklos Szeredi
__fuse_dentry_settime(struct dentry * dentry,u64 time)5430c6a23dSKhazhismel Kumykov static inline void __fuse_dentry_settime(struct dentry *dentry, u64 time)
5530c6a23dSKhazhismel Kumykov {
5630c6a23dSKhazhismel Kumykov ((union fuse_dentry *) dentry->d_fsdata)->time = time;
5730c6a23dSKhazhismel Kumykov }
5830c6a23dSKhazhismel Kumykov
fuse_dentry_time(const struct dentry * entry)5930c6a23dSKhazhismel Kumykov static inline u64 fuse_dentry_time(const struct dentry *entry)
6030c6a23dSKhazhismel Kumykov {
6130c6a23dSKhazhismel Kumykov return ((union fuse_dentry *) entry->d_fsdata)->time;
6230c6a23dSKhazhismel Kumykov }
6330c6a23dSKhazhismel Kumykov #endif
6430c6a23dSKhazhismel Kumykov
fuse_dentry_settime(struct dentry * dentry,u64 time)658fab0106SMiklos Szeredi static void fuse_dentry_settime(struct dentry *dentry, u64 time)
660a0898cfSMiklos Szeredi {
678fab0106SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(dentry->d_sb);
688fab0106SMiklos Szeredi bool delete = !time && fc->delete_stale;
698fab0106SMiklos Szeredi /*
708fab0106SMiklos Szeredi * Mess with DCACHE_OP_DELETE because dput() will be faster without it.
718fab0106SMiklos Szeredi * Don't care about races, either way it's just an optimization
728fab0106SMiklos Szeredi */
738fab0106SMiklos Szeredi if ((!delete && (dentry->d_flags & DCACHE_OP_DELETE)) ||
748fab0106SMiklos Szeredi (delete && !(dentry->d_flags & DCACHE_OP_DELETE))) {
758fab0106SMiklos Szeredi spin_lock(&dentry->d_lock);
768fab0106SMiklos Szeredi if (!delete)
778fab0106SMiklos Szeredi dentry->d_flags &= ~DCACHE_OP_DELETE;
788fab0106SMiklos Szeredi else
798fab0106SMiklos Szeredi dentry->d_flags |= DCACHE_OP_DELETE;
808fab0106SMiklos Szeredi spin_unlock(&dentry->d_lock);
810a0898cfSMiklos Szeredi }
820a0898cfSMiklos Szeredi
8330c6a23dSKhazhismel Kumykov __fuse_dentry_settime(dentry, time);
840a0898cfSMiklos Szeredi }
850a0898cfSMiklos Szeredi
866f9f1180SMiklos Szeredi /*
876f9f1180SMiklos Szeredi * FUSE caches dentries and attributes with separate timeout. The
886f9f1180SMiklos Szeredi * time in jiffies until the dentry/attributes are valid is stored in
89f75fdf22SMiklos Szeredi * dentry->d_fsdata and fuse_inode->i_time respectively.
906f9f1180SMiklos Szeredi */
916f9f1180SMiklos Szeredi
926f9f1180SMiklos Szeredi /*
936f9f1180SMiklos Szeredi * Calculate the time in jiffies until a dentry/attributes are valid
946f9f1180SMiklos Szeredi */
fuse_time_to_jiffies(u64 sec,u32 nsec)959dc10a54SMiklos Szeredi u64 fuse_time_to_jiffies(u64 sec, u32 nsec)
96e5e5558eSMiklos Szeredi {
97685d16ddSMiklos Szeredi if (sec || nsec) {
98bcb6f6d2SMiklos Szeredi struct timespec64 ts = {
99bcb6f6d2SMiklos Szeredi sec,
10021067527SDavid Sheets min_t(u32, nsec, NSEC_PER_SEC - 1)
101bcb6f6d2SMiklos Szeredi };
102bcb6f6d2SMiklos Szeredi
103bcb6f6d2SMiklos Szeredi return get_jiffies_64() + timespec64_to_jiffies(&ts);
104685d16ddSMiklos Szeredi } else
1050a0898cfSMiklos Szeredi return 0;
106e5e5558eSMiklos Szeredi }
107e5e5558eSMiklos Szeredi
1086f9f1180SMiklos Szeredi /*
1096f9f1180SMiklos Szeredi * Set dentry and possibly attribute timeouts from the lookup/mk*
1106f9f1180SMiklos Szeredi * replies
1116f9f1180SMiklos Szeredi */
fuse_change_entry_timeout(struct dentry * entry,struct fuse_entry_out * o)112d123d8e1SMiklos Szeredi void fuse_change_entry_timeout(struct dentry *entry, struct fuse_entry_out *o)
1130aa7c699SMiklos Szeredi {
1140a0898cfSMiklos Szeredi fuse_dentry_settime(entry,
1159dc10a54SMiklos Szeredi fuse_time_to_jiffies(o->entry_valid, o->entry_valid_nsec));
1168cbdf1e6SMiklos Szeredi }
1178cbdf1e6SMiklos Szeredi
fuse_invalidate_attr_mask(struct inode * inode,u32 mask)118fa5eee57SMiklos Szeredi void fuse_invalidate_attr_mask(struct inode *inode, u32 mask)
1192f1e8196SMiklos Szeredi {
1202f1e8196SMiklos Szeredi set_mask_bits(&get_fuse_inode(inode)->inval_mask, 0, mask);
1212f1e8196SMiklos Szeredi }
1222f1e8196SMiklos Szeredi
1236f9f1180SMiklos Szeredi /*
1246f9f1180SMiklos Szeredi * Mark the attributes as stale, so that at the next call to
1256f9f1180SMiklos Szeredi * ->getattr() they will be fetched from userspace
1266f9f1180SMiklos Szeredi */
fuse_invalidate_attr(struct inode * inode)1278cbdf1e6SMiklos Szeredi void fuse_invalidate_attr(struct inode *inode)
1288cbdf1e6SMiklos Szeredi {
1292f1e8196SMiklos Szeredi fuse_invalidate_attr_mask(inode, STATX_BASIC_STATS);
1308cbdf1e6SMiklos Szeredi }
1318cbdf1e6SMiklos Szeredi
fuse_dir_changed(struct inode * dir)132261aaba7SMiklos Szeredi static void fuse_dir_changed(struct inode *dir)
133261aaba7SMiklos Szeredi {
134261aaba7SMiklos Szeredi fuse_invalidate_attr(dir);
135261aaba7SMiklos Szeredi inode_maybe_inc_iversion(dir, false);
136261aaba7SMiklos Szeredi }
137261aaba7SMiklos Szeredi
13806bbb761SRandy Dunlap /*
139451418fcSAndrew Gallagher * Mark the attributes as stale due to an atime change. Avoid the invalidate if
140451418fcSAndrew Gallagher * atime is not used.
141451418fcSAndrew Gallagher */
fuse_invalidate_atime(struct inode * inode)142451418fcSAndrew Gallagher void fuse_invalidate_atime(struct inode *inode)
143451418fcSAndrew Gallagher {
144451418fcSAndrew Gallagher if (!IS_RDONLY(inode))
1452f1e8196SMiklos Szeredi fuse_invalidate_attr_mask(inode, STATX_ATIME);
146451418fcSAndrew Gallagher }
147451418fcSAndrew Gallagher
1486f9f1180SMiklos Szeredi /*
1496f9f1180SMiklos Szeredi * Just mark the entry as stale, so that a next attempt to look it up
1506f9f1180SMiklos Szeredi * will result in a new lookup call to userspace
1516f9f1180SMiklos Szeredi *
1526f9f1180SMiklos Szeredi * This is called when a dentry is about to become negative and the
1536f9f1180SMiklos Szeredi * timeout is unknown (unlink, rmdir, rename and in some cases
1546f9f1180SMiklos Szeredi * lookup)
1556f9f1180SMiklos Szeredi */
fuse_invalidate_entry_cache(struct dentry * entry)156dbd561d2SMiklos Szeredi void fuse_invalidate_entry_cache(struct dentry *entry)
1578cbdf1e6SMiklos Szeredi {
1580a0898cfSMiklos Szeredi fuse_dentry_settime(entry, 0);
1598cbdf1e6SMiklos Szeredi }
1608cbdf1e6SMiklos Szeredi
1616f9f1180SMiklos Szeredi /*
1626f9f1180SMiklos Szeredi * Same as fuse_invalidate_entry_cache(), but also try to remove the
1636f9f1180SMiklos Szeredi * dentry from the hash
1646f9f1180SMiklos Szeredi */
fuse_invalidate_entry(struct dentry * entry)1658cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry)
1668cbdf1e6SMiklos Szeredi {
1678cbdf1e6SMiklos Szeredi d_invalidate(entry);
1688cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry);
1690aa7c699SMiklos Szeredi }
1700aa7c699SMiklos Szeredi
fuse_lookup_init(struct fuse_conn * fc,struct fuse_args * args,u64 nodeid,const struct qstr * name,struct fuse_entry_out * outarg)1717078187aSMiklos Szeredi static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args,
17213983d06SAl Viro u64 nodeid, const struct qstr *name,
173e5e5558eSMiklos Szeredi struct fuse_entry_out *outarg)
174e5e5558eSMiklos Szeredi {
1750e9663eeSMiklos Szeredi memset(outarg, 0, sizeof(struct fuse_entry_out));
176d5b48543SMiklos Szeredi args->opcode = FUSE_LOOKUP;
177d5b48543SMiklos Szeredi args->nodeid = nodeid;
178d5b48543SMiklos Szeredi args->in_numargs = 1;
179d5b48543SMiklos Szeredi args->in_args[0].size = name->len + 1;
180d5b48543SMiklos Szeredi args->in_args[0].value = name->name;
181d5b48543SMiklos Szeredi args->out_numargs = 1;
182d5b48543SMiklos Szeredi args->out_args[0].size = sizeof(struct fuse_entry_out);
183d5b48543SMiklos Szeredi args->out_args[0].value = outarg;
184e5e5558eSMiklos Szeredi }
185e5e5558eSMiklos Szeredi
1866f9f1180SMiklos Szeredi /*
1876f9f1180SMiklos Szeredi * Check whether the dentry is still valid
1886f9f1180SMiklos Szeredi *
1896f9f1180SMiklos Szeredi * If the entry validity timeout has expired and the dentry is
1906f9f1180SMiklos Szeredi * positive, try to redo the lookup. If the lookup results in a
1916f9f1180SMiklos Szeredi * different inode, then let the VFS invalidate the dentry and redo
1926f9f1180SMiklos Szeredi * the lookup once more. If the lookup results in the same inode,
1936f9f1180SMiklos Szeredi * then refresh the attributes, timeouts and mark the dentry valid.
1946f9f1180SMiklos Szeredi */
fuse_dentry_revalidate(struct dentry * entry,unsigned int flags)1950b728e19SAl Viro static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
196e5e5558eSMiklos Szeredi {
19734286d66SNick Piggin struct inode *inode;
19828420dadSMiklos Szeredi struct dentry *parent;
199fcee216bSMax Reitz struct fuse_mount *fm;
2006314efeeSMiklos Szeredi struct fuse_inode *fi;
201e2a6b952SMiklos Szeredi int ret;
2028cbdf1e6SMiklos Szeredi
2032b0143b5SDavid Howells inode = d_inode_rcu(entry);
2045d069dbeSMiklos Szeredi if (inode && fuse_is_bad(inode))
205e2a6b952SMiklos Szeredi goto invalid;
206154210ccSAnand Avati else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) ||
207ccc031e2SJiachen Zhang (flags & (LOOKUP_EXCL | LOOKUP_REVAL | LOOKUP_RENAME_TARGET))) {
208e5e5558eSMiklos Szeredi struct fuse_entry_out outarg;
2097078187aSMiklos Szeredi FUSE_ARGS(args);
21007e77dcaSMiklos Szeredi struct fuse_forget_link *forget;
2111fb69e78SMiklos Szeredi u64 attr_version;
2128cbdf1e6SMiklos Szeredi
21350322fe7SMiklos Szeredi /* For negative dentries, always do a fresh lookup */
2148cbdf1e6SMiklos Szeredi if (!inode)
215e2a6b952SMiklos Szeredi goto invalid;
2168cbdf1e6SMiklos Szeredi
217e2a6b952SMiklos Szeredi ret = -ECHILD;
2180b728e19SAl Viro if (flags & LOOKUP_RCU)
219e2a6b952SMiklos Szeredi goto out;
220e7c0a167SMiklos Szeredi
221fcee216bSMax Reitz fm = get_fuse_mount(inode);
222e5e5558eSMiklos Szeredi
22307e77dcaSMiklos Szeredi forget = fuse_alloc_forget();
224e2a6b952SMiklos Szeredi ret = -ENOMEM;
2257078187aSMiklos Szeredi if (!forget)
226e2a6b952SMiklos Szeredi goto out;
2272d51013eSMiklos Szeredi
228fcee216bSMax Reitz attr_version = fuse_get_attr_version(fm->fc);
2291fb69e78SMiklos Szeredi
230e956edd0SMiklos Szeredi parent = dget_parent(entry);
231fcee216bSMax Reitz fuse_lookup_init(fm->fc, &args, get_node_id(d_inode(parent)),
232c180eebeSMiklos Szeredi &entry->d_name, &outarg);
233fcee216bSMax Reitz ret = fuse_simple_request(fm, &args);
234e956edd0SMiklos Szeredi dput(parent);
23550322fe7SMiklos Szeredi /* Zero nodeid is same as -ENOENT */
2367078187aSMiklos Szeredi if (!ret && !outarg.nodeid)
2377078187aSMiklos Szeredi ret = -ENOENT;
2387078187aSMiklos Szeredi if (!ret) {
2396314efeeSMiklos Szeredi fi = get_fuse_inode(inode);
240bf109c64SMax Reitz if (outarg.nodeid != get_node_id(inode) ||
241bf109c64SMax Reitz (bool) IS_AUTOMOUNT(inode) != (bool) (outarg.attr.flags & FUSE_ATTR_SUBMOUNT)) {
242fcee216bSMax Reitz fuse_queue_forget(fm->fc, forget,
243fcee216bSMax Reitz outarg.nodeid, 1);
244e2a6b952SMiklos Szeredi goto invalid;
2459e6268dbSMiklos Szeredi }
246c9d8f5f0SKirill Tkhai spin_lock(&fi->lock);
2479e6268dbSMiklos Szeredi fi->nlookup++;
248c9d8f5f0SKirill Tkhai spin_unlock(&fi->lock);
2499e6268dbSMiklos Szeredi }
25007e77dcaSMiklos Szeredi kfree(forget);
251a9d1c4c6SMiklos Szeredi if (ret == -ENOMEM || ret == -EINTR)
2527078187aSMiklos Szeredi goto out;
253eb59bd17SMiklos Szeredi if (ret || fuse_invalid_attr(&outarg.attr) ||
25415db1683SAmir Goldstein fuse_stale_inode(inode, outarg.generation, &outarg.attr))
255e2a6b952SMiklos Szeredi goto invalid;
256e5e5558eSMiklos Szeredi
25760bcc88aSSeth Forshee forget_all_cached_acls(inode);
258972f4c46SMiklos Szeredi fuse_change_attributes(inode, &outarg.attr, NULL,
2599dc10a54SMiklos Szeredi ATTR_TIMEOUT(&outarg),
2601fb69e78SMiklos Szeredi attr_version);
2611fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg);
26228420dadSMiklos Szeredi } else if (inode) {
2636314efeeSMiklos Szeredi fi = get_fuse_inode(inode);
2646314efeeSMiklos Szeredi if (flags & LOOKUP_RCU) {
2656314efeeSMiklos Szeredi if (test_bit(FUSE_I_INIT_RDPLUS, &fi->state))
2666314efeeSMiklos Szeredi return -ECHILD;
2676314efeeSMiklos Szeredi } else if (test_and_clear_bit(FUSE_I_INIT_RDPLUS, &fi->state)) {
26828420dadSMiklos Szeredi parent = dget_parent(entry);
2692b0143b5SDavid Howells fuse_advise_use_readdirplus(d_inode(parent));
27028420dadSMiklos Szeredi dput(parent);
271e5e5558eSMiklos Szeredi }
27228420dadSMiklos Szeredi }
273e2a6b952SMiklos Szeredi ret = 1;
274e2a6b952SMiklos Szeredi out:
275e2a6b952SMiklos Szeredi return ret;
276e2a6b952SMiklos Szeredi
277e2a6b952SMiklos Szeredi invalid:
278e2a6b952SMiklos Szeredi ret = 0;
279e2a6b952SMiklos Szeredi goto out;
280e5e5558eSMiklos Szeredi }
281e5e5558eSMiklos Szeredi
28230c6a23dSKhazhismel Kumykov #if BITS_PER_LONG < 64
fuse_dentry_init(struct dentry * dentry)283f75fdf22SMiklos Szeredi static int fuse_dentry_init(struct dentry *dentry)
284f75fdf22SMiklos Szeredi {
285dc69e98cSKhazhismel Kumykov dentry->d_fsdata = kzalloc(sizeof(union fuse_dentry),
286dc69e98cSKhazhismel Kumykov GFP_KERNEL_ACCOUNT | __GFP_RECLAIMABLE);
287f75fdf22SMiklos Szeredi
288f75fdf22SMiklos Szeredi return dentry->d_fsdata ? 0 : -ENOMEM;
289f75fdf22SMiklos Szeredi }
fuse_dentry_release(struct dentry * dentry)290f75fdf22SMiklos Szeredi static void fuse_dentry_release(struct dentry *dentry)
291f75fdf22SMiklos Szeredi {
292f75fdf22SMiklos Szeredi union fuse_dentry *fd = dentry->d_fsdata;
293f75fdf22SMiklos Szeredi
294f75fdf22SMiklos Szeredi kfree_rcu(fd, rcu);
295f75fdf22SMiklos Szeredi }
29630c6a23dSKhazhismel Kumykov #endif
297f75fdf22SMiklos Szeredi
fuse_dentry_delete(const struct dentry * dentry)2988fab0106SMiklos Szeredi static int fuse_dentry_delete(const struct dentry *dentry)
2998fab0106SMiklos Szeredi {
3008fab0106SMiklos Szeredi return time_before64(fuse_dentry_time(dentry), get_jiffies_64());
3018fab0106SMiklos Szeredi }
3028fab0106SMiklos Szeredi
303bf109c64SMax Reitz /*
304bf109c64SMax Reitz * Create a fuse_mount object with a new superblock (with path->dentry
305bf109c64SMax Reitz * as the root), and return that mount so it can be auto-mounted on
306bf109c64SMax Reitz * @path.
307bf109c64SMax Reitz */
fuse_dentry_automount(struct path * path)308bf109c64SMax Reitz static struct vfsmount *fuse_dentry_automount(struct path *path)
309bf109c64SMax Reitz {
310bf109c64SMax Reitz struct fs_context *fsc;
311bf109c64SMax Reitz struct vfsmount *mnt;
312bf109c64SMax Reitz struct fuse_inode *mp_fi = get_fuse_inode(d_inode(path->dentry));
313bf109c64SMax Reitz
314bf109c64SMax Reitz fsc = fs_context_for_submount(path->mnt->mnt_sb->s_type, path->dentry);
31529e0e4dfSGreg Kurz if (IS_ERR(fsc))
31629e0e4dfSGreg Kurz return ERR_CAST(fsc);
317bf109c64SMax Reitz
318266eb3f2SGreg Kurz /* Pass the FUSE inode of the mount for fuse_get_tree_submount() */
319266eb3f2SGreg Kurz fsc->fs_private = mp_fi;
320266eb3f2SGreg Kurz
321bf109c64SMax Reitz /* Create the submount */
32229e0e4dfSGreg Kurz mnt = fc_mount(fsc);
32329e0e4dfSGreg Kurz if (!IS_ERR(mnt))
324bf109c64SMax Reitz mntget(mnt);
32529e0e4dfSGreg Kurz
326bf109c64SMax Reitz put_fs_context(fsc);
327bf109c64SMax Reitz return mnt;
328bf109c64SMax Reitz }
329bf109c64SMax Reitz
3304269590aSAl Viro const struct dentry_operations fuse_dentry_operations = {
331e5e5558eSMiklos Szeredi .d_revalidate = fuse_dentry_revalidate,
3328fab0106SMiklos Szeredi .d_delete = fuse_dentry_delete,
33330c6a23dSKhazhismel Kumykov #if BITS_PER_LONG < 64
334f75fdf22SMiklos Szeredi .d_init = fuse_dentry_init,
335f75fdf22SMiklos Szeredi .d_release = fuse_dentry_release,
33630c6a23dSKhazhismel Kumykov #endif
337bf109c64SMax Reitz .d_automount = fuse_dentry_automount,
338e5e5558eSMiklos Szeredi };
339e5e5558eSMiklos Szeredi
3400ce267ffSMiklos Szeredi const struct dentry_operations fuse_root_dentry_operations = {
34130c6a23dSKhazhismel Kumykov #if BITS_PER_LONG < 64
3420ce267ffSMiklos Szeredi .d_init = fuse_dentry_init,
3430ce267ffSMiklos Szeredi .d_release = fuse_dentry_release,
34430c6a23dSKhazhismel Kumykov #endif
3450ce267ffSMiklos Szeredi };
3460ce267ffSMiklos Szeredi
fuse_valid_type(int m)347a5bfffacSTimo Savola int fuse_valid_type(int m)
34839ee059aSMiklos Szeredi {
34939ee059aSMiklos Szeredi return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
35039ee059aSMiklos Szeredi S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
35139ee059aSMiklos Szeredi }
35239ee059aSMiklos Szeredi
fuse_valid_size(u64 size)353d3045530SMiklos Szeredi static bool fuse_valid_size(u64 size)
354d3045530SMiklos Szeredi {
355d3045530SMiklos Szeredi return size <= LLONG_MAX;
356d3045530SMiklos Szeredi }
357d3045530SMiklos Szeredi
fuse_invalid_attr(struct fuse_attr * attr)358eb59bd17SMiklos Szeredi bool fuse_invalid_attr(struct fuse_attr *attr)
359eb59bd17SMiklos Szeredi {
360d3045530SMiklos Szeredi return !fuse_valid_type(attr->mode) || !fuse_valid_size(attr->size);
361eb59bd17SMiklos Szeredi }
362eb59bd17SMiklos Szeredi
fuse_lookup_name(struct super_block * sb,u64 nodeid,const struct qstr * name,struct fuse_entry_out * outarg,struct inode ** inode)36313983d06SAl Viro int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name,
364c180eebeSMiklos Szeredi struct fuse_entry_out *outarg, struct inode **inode)
365c180eebeSMiklos Szeredi {
366fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount_super(sb);
3677078187aSMiklos Szeredi FUSE_ARGS(args);
36807e77dcaSMiklos Szeredi struct fuse_forget_link *forget;
369c180eebeSMiklos Szeredi u64 attr_version;
370c180eebeSMiklos Szeredi int err;
371c180eebeSMiklos Szeredi
372c180eebeSMiklos Szeredi *inode = NULL;
373c180eebeSMiklos Szeredi err = -ENAMETOOLONG;
374c180eebeSMiklos Szeredi if (name->len > FUSE_NAME_MAX)
375c180eebeSMiklos Szeredi goto out;
376c180eebeSMiklos Szeredi
377c180eebeSMiklos Szeredi
37807e77dcaSMiklos Szeredi forget = fuse_alloc_forget();
37907e77dcaSMiklos Szeredi err = -ENOMEM;
3807078187aSMiklos Szeredi if (!forget)
381c180eebeSMiklos Szeredi goto out;
382c180eebeSMiklos Szeredi
383fcee216bSMax Reitz attr_version = fuse_get_attr_version(fm->fc);
384c180eebeSMiklos Szeredi
385fcee216bSMax Reitz fuse_lookup_init(fm->fc, &args, nodeid, name, outarg);
386fcee216bSMax Reitz err = fuse_simple_request(fm, &args);
387c180eebeSMiklos Szeredi /* Zero nodeid is same as -ENOENT, but with valid timeout */
388c180eebeSMiklos Szeredi if (err || !outarg->nodeid)
389c180eebeSMiklos Szeredi goto out_put_forget;
390c180eebeSMiklos Szeredi
391c180eebeSMiklos Szeredi err = -EIO;
392eb59bd17SMiklos Szeredi if (fuse_invalid_attr(&outarg->attr))
393c180eebeSMiklos Szeredi goto out_put_forget;
394777ba189SMiklos Szeredi if (outarg->nodeid == FUSE_ROOT_ID && outarg->generation != 0) {
395777ba189SMiklos Szeredi pr_warn_once("root generation should be zero\n");
396777ba189SMiklos Szeredi outarg->generation = 0;
397777ba189SMiklos Szeredi }
398c180eebeSMiklos Szeredi
399c180eebeSMiklos Szeredi *inode = fuse_iget(sb, outarg->nodeid, outarg->generation,
4009dc10a54SMiklos Szeredi &outarg->attr, ATTR_TIMEOUT(outarg),
401c180eebeSMiklos Szeredi attr_version);
402c180eebeSMiklos Szeredi err = -ENOMEM;
403c180eebeSMiklos Szeredi if (!*inode) {
404fcee216bSMax Reitz fuse_queue_forget(fm->fc, forget, outarg->nodeid, 1);
405c180eebeSMiklos Szeredi goto out;
406c180eebeSMiklos Szeredi }
407c180eebeSMiklos Szeredi err = 0;
408c180eebeSMiklos Szeredi
409c180eebeSMiklos Szeredi out_put_forget:
41007e77dcaSMiklos Szeredi kfree(forget);
411c180eebeSMiklos Szeredi out:
412c180eebeSMiklos Szeredi return err;
413c180eebeSMiklos Szeredi }
414c180eebeSMiklos Szeredi
fuse_lookup(struct inode * dir,struct dentry * entry,unsigned int flags)4150aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
41600cd8dd3SAl Viro unsigned int flags)
417e5e5558eSMiklos Szeredi {
418e5e5558eSMiklos Szeredi int err;
419e5e5558eSMiklos Szeredi struct fuse_entry_out outarg;
420c180eebeSMiklos Szeredi struct inode *inode;
4210de6256dSMiklos Szeredi struct dentry *newent;
422c180eebeSMiklos Szeredi bool outarg_valid = true;
42363576c13SMiklos Szeredi bool locked;
424e5e5558eSMiklos Szeredi
4255d069dbeSMiklos Szeredi if (fuse_is_bad(dir))
4265d069dbeSMiklos Szeredi return ERR_PTR(-EIO);
4275d069dbeSMiklos Szeredi
42863576c13SMiklos Szeredi locked = fuse_lock_inode(dir);
429c180eebeSMiklos Szeredi err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
430c180eebeSMiklos Szeredi &outarg, &inode);
43163576c13SMiklos Szeredi fuse_unlock_inode(dir, locked);
432c180eebeSMiklos Szeredi if (err == -ENOENT) {
433c180eebeSMiklos Szeredi outarg_valid = false;
434c180eebeSMiklos Szeredi err = 0;
4352d51013eSMiklos Szeredi }
436c180eebeSMiklos Szeredi if (err)
437c180eebeSMiklos Szeredi goto out_err;
4382d51013eSMiklos Szeredi
439ee4e5271SMiklos Szeredi err = -EIO;
440c180eebeSMiklos Szeredi if (inode && get_node_id(inode) == FUSE_ROOT_ID)
441c180eebeSMiklos Szeredi goto out_iput;
442e5e5558eSMiklos Szeredi
44341d28bcaSAl Viro newent = d_splice_alias(inode, entry);
444c180eebeSMiklos Szeredi err = PTR_ERR(newent);
445c180eebeSMiklos Szeredi if (IS_ERR(newent))
4465835f339SMiklos Szeredi goto out_err;
447d2a85164SMiklos Szeredi
4480de6256dSMiklos Szeredi entry = newent ? newent : entry;
449c180eebeSMiklos Szeredi if (outarg_valid)
4501fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg);
4518cbdf1e6SMiklos Szeredi else
4528cbdf1e6SMiklos Szeredi fuse_invalidate_entry_cache(entry);
453c180eebeSMiklos Szeredi
4546c26f717SMiklos Szeredi if (inode)
4554582a4abSFeng Shuo fuse_advise_use_readdirplus(dir);
4560de6256dSMiklos Szeredi return newent;
457c180eebeSMiklos Szeredi
458c180eebeSMiklos Szeredi out_iput:
459c180eebeSMiklos Szeredi iput(inode);
460c180eebeSMiklos Szeredi out_err:
461c180eebeSMiklos Szeredi return ERR_PTR(err);
462e5e5558eSMiklos Szeredi }
463e5e5558eSMiklos Szeredi
get_security_context(struct dentry * entry,umode_t mode,struct fuse_in_arg * ext)4643e2b6fdbSVivek Goyal static int get_security_context(struct dentry *entry, umode_t mode,
46515d937d7SMiklos Szeredi struct fuse_in_arg *ext)
4663e2b6fdbSVivek Goyal {
4673e2b6fdbSVivek Goyal struct fuse_secctx *fctx;
4683e2b6fdbSVivek Goyal struct fuse_secctx_header *header;
4693e2b6fdbSVivek Goyal void *ctx = NULL, *ptr;
4703e2b6fdbSVivek Goyal u32 ctxlen, total_len = sizeof(*header);
4713e2b6fdbSVivek Goyal int err, nr_ctx = 0;
4723e2b6fdbSVivek Goyal const char *name;
4733e2b6fdbSVivek Goyal size_t namelen;
4743e2b6fdbSVivek Goyal
4753e2b6fdbSVivek Goyal err = security_dentry_init_security(entry, mode, &entry->d_name,
4763e2b6fdbSVivek Goyal &name, &ctx, &ctxlen);
4773e2b6fdbSVivek Goyal if (err) {
4783e2b6fdbSVivek Goyal if (err != -EOPNOTSUPP)
4793e2b6fdbSVivek Goyal goto out_err;
4803e2b6fdbSVivek Goyal /* No LSM is supporting this security hook. Ignore error */
4813e2b6fdbSVivek Goyal ctxlen = 0;
4823e2b6fdbSVivek Goyal ctx = NULL;
4833e2b6fdbSVivek Goyal }
4843e2b6fdbSVivek Goyal
4853e2b6fdbSVivek Goyal if (ctxlen) {
4863e2b6fdbSVivek Goyal nr_ctx = 1;
4873e2b6fdbSVivek Goyal namelen = strlen(name) + 1;
4883e2b6fdbSVivek Goyal err = -EIO;
4893e2b6fdbSVivek Goyal if (WARN_ON(namelen > XATTR_NAME_MAX + 1 || ctxlen > S32_MAX))
4903e2b6fdbSVivek Goyal goto out_err;
4913e2b6fdbSVivek Goyal total_len += FUSE_REC_ALIGN(sizeof(*fctx) + namelen + ctxlen);
4923e2b6fdbSVivek Goyal }
4933e2b6fdbSVivek Goyal
4943e2b6fdbSVivek Goyal err = -ENOMEM;
4953e2b6fdbSVivek Goyal header = ptr = kzalloc(total_len, GFP_KERNEL);
4963e2b6fdbSVivek Goyal if (!ptr)
4973e2b6fdbSVivek Goyal goto out_err;
4983e2b6fdbSVivek Goyal
4993e2b6fdbSVivek Goyal header->nr_secctx = nr_ctx;
5003e2b6fdbSVivek Goyal header->size = total_len;
5013e2b6fdbSVivek Goyal ptr += sizeof(*header);
5023e2b6fdbSVivek Goyal if (nr_ctx) {
5033e2b6fdbSVivek Goyal fctx = ptr;
5043e2b6fdbSVivek Goyal fctx->size = ctxlen;
5053e2b6fdbSVivek Goyal ptr += sizeof(*fctx);
5063e2b6fdbSVivek Goyal
5073e2b6fdbSVivek Goyal strcpy(ptr, name);
5083e2b6fdbSVivek Goyal ptr += namelen;
5093e2b6fdbSVivek Goyal
5103e2b6fdbSVivek Goyal memcpy(ptr, ctx, ctxlen);
5113e2b6fdbSVivek Goyal }
51215d937d7SMiklos Szeredi ext->size = total_len;
51315d937d7SMiklos Szeredi ext->value = header;
5143e2b6fdbSVivek Goyal err = 0;
5153e2b6fdbSVivek Goyal out_err:
5163e2b6fdbSVivek Goyal kfree(ctx);
5173e2b6fdbSVivek Goyal return err;
5183e2b6fdbSVivek Goyal }
5193e2b6fdbSVivek Goyal
extend_arg(struct fuse_in_arg * buf,u32 bytes)5208ed7cb3fSMiklos Szeredi static void *extend_arg(struct fuse_in_arg *buf, u32 bytes)
5218ed7cb3fSMiklos Szeredi {
5228ed7cb3fSMiklos Szeredi void *p;
5238ed7cb3fSMiklos Szeredi u32 newlen = buf->size + bytes;
5248ed7cb3fSMiklos Szeredi
5258ed7cb3fSMiklos Szeredi p = krealloc(buf->value, newlen, GFP_KERNEL);
5268ed7cb3fSMiklos Szeredi if (!p) {
5278ed7cb3fSMiklos Szeredi kfree(buf->value);
5288ed7cb3fSMiklos Szeredi buf->size = 0;
5298ed7cb3fSMiklos Szeredi buf->value = NULL;
5308ed7cb3fSMiklos Szeredi return NULL;
5318ed7cb3fSMiklos Szeredi }
5328ed7cb3fSMiklos Szeredi
5338ed7cb3fSMiklos Szeredi memset(p + buf->size, 0, bytes);
5348ed7cb3fSMiklos Szeredi buf->value = p;
5358ed7cb3fSMiklos Szeredi buf->size = newlen;
5368ed7cb3fSMiklos Szeredi
5378ed7cb3fSMiklos Szeredi return p + newlen - bytes;
5388ed7cb3fSMiklos Szeredi }
5398ed7cb3fSMiklos Szeredi
fuse_ext_size(size_t size)5408ed7cb3fSMiklos Szeredi static u32 fuse_ext_size(size_t size)
5418ed7cb3fSMiklos Szeredi {
5428ed7cb3fSMiklos Szeredi return FUSE_REC_ALIGN(sizeof(struct fuse_ext_header) + size);
5438ed7cb3fSMiklos Szeredi }
5448ed7cb3fSMiklos Szeredi
5458ed7cb3fSMiklos Szeredi /*
5468ed7cb3fSMiklos Szeredi * This adds just a single supplementary group that matches the parent's group.
5478ed7cb3fSMiklos Szeredi */
get_create_supp_group(struct inode * dir,struct fuse_in_arg * ext)5488ed7cb3fSMiklos Szeredi static int get_create_supp_group(struct inode *dir, struct fuse_in_arg *ext)
5498ed7cb3fSMiklos Szeredi {
5508ed7cb3fSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir);
5518ed7cb3fSMiklos Szeredi struct fuse_ext_header *xh;
5528ed7cb3fSMiklos Szeredi struct fuse_supp_groups *sg;
5538ed7cb3fSMiklos Szeredi kgid_t kgid = dir->i_gid;
5548ed7cb3fSMiklos Szeredi gid_t parent_gid = from_kgid(fc->user_ns, kgid);
5558ed7cb3fSMiklos Szeredi u32 sg_len = fuse_ext_size(sizeof(*sg) + sizeof(sg->groups[0]));
5568ed7cb3fSMiklos Szeredi
5578ed7cb3fSMiklos Szeredi if (parent_gid == (gid_t) -1 || gid_eq(kgid, current_fsgid()) ||
5588ed7cb3fSMiklos Szeredi !in_group_p(kgid))
5598ed7cb3fSMiklos Szeredi return 0;
5608ed7cb3fSMiklos Szeredi
5618ed7cb3fSMiklos Szeredi xh = extend_arg(ext, sg_len);
5628ed7cb3fSMiklos Szeredi if (!xh)
5638ed7cb3fSMiklos Szeredi return -ENOMEM;
5648ed7cb3fSMiklos Szeredi
5658ed7cb3fSMiklos Szeredi xh->size = sg_len;
5668ed7cb3fSMiklos Szeredi xh->type = FUSE_EXT_GROUPS;
5678ed7cb3fSMiklos Szeredi
5688ed7cb3fSMiklos Szeredi sg = (struct fuse_supp_groups *) &xh[1];
5698ed7cb3fSMiklos Szeredi sg->nr_groups = 1;
5708ed7cb3fSMiklos Szeredi sg->groups[0] = parent_gid;
5718ed7cb3fSMiklos Szeredi
5728ed7cb3fSMiklos Szeredi return 0;
5738ed7cb3fSMiklos Szeredi }
5748ed7cb3fSMiklos Szeredi
get_create_ext(struct fuse_args * args,struct inode * dir,struct dentry * dentry,umode_t mode)5758ed7cb3fSMiklos Szeredi static int get_create_ext(struct fuse_args *args,
5768ed7cb3fSMiklos Szeredi struct inode *dir, struct dentry *dentry,
57715d937d7SMiklos Szeredi umode_t mode)
57815d937d7SMiklos Szeredi {
57915d937d7SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn_super(dentry->d_sb);
58015d937d7SMiklos Szeredi struct fuse_in_arg ext = { .size = 0, .value = NULL };
58115d937d7SMiklos Szeredi int err = 0;
58215d937d7SMiklos Szeredi
58315d937d7SMiklos Szeredi if (fc->init_security)
58415d937d7SMiklos Szeredi err = get_security_context(dentry, mode, &ext);
5858ed7cb3fSMiklos Szeredi if (!err && fc->create_supp_group)
5868ed7cb3fSMiklos Szeredi err = get_create_supp_group(dir, &ext);
58715d937d7SMiklos Szeredi
58815d937d7SMiklos Szeredi if (!err && ext.size) {
58915d937d7SMiklos Szeredi WARN_ON(args->in_numargs >= ARRAY_SIZE(args->in_args));
59015d937d7SMiklos Szeredi args->is_ext = true;
59115d937d7SMiklos Szeredi args->ext_idx = args->in_numargs++;
59215d937d7SMiklos Szeredi args->in_args[args->ext_idx] = ext;
59315d937d7SMiklos Szeredi } else {
59415d937d7SMiklos Szeredi kfree(ext.value);
59515d937d7SMiklos Szeredi }
59615d937d7SMiklos Szeredi
59715d937d7SMiklos Szeredi return err;
59815d937d7SMiklos Szeredi }
59915d937d7SMiklos Szeredi
free_ext_value(struct fuse_args * args)60015d937d7SMiklos Szeredi static void free_ext_value(struct fuse_args *args)
60115d937d7SMiklos Szeredi {
60215d937d7SMiklos Szeredi if (args->is_ext)
60315d937d7SMiklos Szeredi kfree(args->in_args[args->ext_idx].value);
60415d937d7SMiklos Szeredi }
60515d937d7SMiklos Szeredi
6066f9f1180SMiklos Szeredi /*
6076f9f1180SMiklos Szeredi * Atomic create+open operation
6086f9f1180SMiklos Szeredi *
6096f9f1180SMiklos Szeredi * If the filesystem doesn't support this, then fall back to separate
6106f9f1180SMiklos Szeredi * 'mknod' + 'open' requests.
6116f9f1180SMiklos Szeredi */
fuse_create_open(struct inode * dir,struct dentry * entry,struct file * file,unsigned int flags,umode_t mode,u32 opcode)612d9585277SAl Viro static int fuse_create_open(struct inode *dir, struct dentry *entry,
61354d601cbSMiklos Szeredi struct file *file, unsigned int flags,
6147d375390SMiklos Szeredi umode_t mode, u32 opcode)
615fd72faacSMiklos Szeredi {
616fd72faacSMiklos Szeredi int err;
617fd72faacSMiklos Szeredi struct inode *inode;
618fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(dir);
6197078187aSMiklos Szeredi FUSE_ARGS(args);
62007e77dcaSMiklos Szeredi struct fuse_forget_link *forget;
621e0a43ddcSMiklos Szeredi struct fuse_create_in inarg;
622fd72faacSMiklos Szeredi struct fuse_open_out outopen;
623fd72faacSMiklos Szeredi struct fuse_entry_out outentry;
624ebf84d0cSKirill Tkhai struct fuse_inode *fi;
625fd72faacSMiklos Szeredi struct fuse_file *ff;
6262fdbb8ddSMiklos Szeredi bool trunc = flags & O_TRUNC;
627fd72faacSMiklos Szeredi
628af109bcaSMiklos Szeredi /* Userspace expects S_IFREG in create mode */
629af109bcaSMiklos Szeredi BUG_ON((mode & S_IFMT) != S_IFREG);
630af109bcaSMiklos Szeredi
63107e77dcaSMiklos Szeredi forget = fuse_alloc_forget();
632c8ccbe03SMiklos Szeredi err = -ENOMEM;
63307e77dcaSMiklos Szeredi if (!forget)
634c8ccbe03SMiklos Szeredi goto out_err;
63551eb01e7SMiklos Szeredi
636ce1d5a49SMiklos Szeredi err = -ENOMEM;
637fcee216bSMax Reitz ff = fuse_file_alloc(fm);
638fd72faacSMiklos Szeredi if (!ff)
6397078187aSMiklos Szeredi goto out_put_forget_req;
640fd72faacSMiklos Szeredi
641fcee216bSMax Reitz if (!fm->fc->dont_mask)
642e0a43ddcSMiklos Szeredi mode &= ~current_umask();
643e0a43ddcSMiklos Szeredi
644fd72faacSMiklos Szeredi flags &= ~O_NOCTTY;
645fd72faacSMiklos Szeredi memset(&inarg, 0, sizeof(inarg));
6460e9663eeSMiklos Szeredi memset(&outentry, 0, sizeof(outentry));
647fd72faacSMiklos Szeredi inarg.flags = flags;
648fd72faacSMiklos Szeredi inarg.mode = mode;
649e0a43ddcSMiklos Szeredi inarg.umask = current_umask();
650643a666aSVivek Goyal
6512fdbb8ddSMiklos Szeredi if (fm->fc->handle_killpriv_v2 && trunc &&
652643a666aSVivek Goyal !(flags & O_EXCL) && !capable(CAP_FSETID)) {
653643a666aSVivek Goyal inarg.open_flags |= FUSE_OPEN_KILL_SUIDGID;
654643a666aSVivek Goyal }
655643a666aSVivek Goyal
6567d375390SMiklos Szeredi args.opcode = opcode;
657d5b48543SMiklos Szeredi args.nodeid = get_node_id(dir);
658d5b48543SMiklos Szeredi args.in_numargs = 2;
659d5b48543SMiklos Szeredi args.in_args[0].size = sizeof(inarg);
660d5b48543SMiklos Szeredi args.in_args[0].value = &inarg;
661d5b48543SMiklos Szeredi args.in_args[1].size = entry->d_name.len + 1;
662d5b48543SMiklos Szeredi args.in_args[1].value = entry->d_name.name;
663d5b48543SMiklos Szeredi args.out_numargs = 2;
664d5b48543SMiklos Szeredi args.out_args[0].size = sizeof(outentry);
665d5b48543SMiklos Szeredi args.out_args[0].value = &outentry;
666d5b48543SMiklos Szeredi args.out_args[1].size = sizeof(outopen);
667d5b48543SMiklos Szeredi args.out_args[1].value = &outopen;
6683e2b6fdbSVivek Goyal
6698ed7cb3fSMiklos Szeredi err = get_create_ext(&args, dir, entry, mode);
6703e2b6fdbSVivek Goyal if (err)
671*f36df5ccSyangyun goto out_free_ff;
6723e2b6fdbSVivek Goyal
673fcee216bSMax Reitz err = fuse_simple_request(fm, &args);
67415d937d7SMiklos Szeredi free_ext_value(&args);
675c8ccbe03SMiklos Szeredi if (err)
676fd72faacSMiklos Szeredi goto out_free_ff;
677fd72faacSMiklos Szeredi
678fd72faacSMiklos Szeredi err = -EIO;
679eb59bd17SMiklos Szeredi if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid) ||
680eb59bd17SMiklos Szeredi fuse_invalid_attr(&outentry.attr))
681fd72faacSMiklos Szeredi goto out_free_ff;
682fd72faacSMiklos Szeredi
683c7b7143cSMiklos Szeredi ff->fh = outopen.fh;
684c7b7143cSMiklos Szeredi ff->nodeid = outentry.nodeid;
685c7b7143cSMiklos Szeredi ff->open_flags = outopen.open_flags;
686fd72faacSMiklos Szeredi inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
6879dc10a54SMiklos Szeredi &outentry.attr, ATTR_TIMEOUT(&outentry), 0);
688fd72faacSMiklos Szeredi if (!inode) {
689fd72faacSMiklos Szeredi flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
690ebf84d0cSKirill Tkhai fuse_sync_release(NULL, ff, flags);
691fcee216bSMax Reitz fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1);
692c8ccbe03SMiklos Szeredi err = -ENOMEM;
693c8ccbe03SMiklos Szeredi goto out_err;
694fd72faacSMiklos Szeredi }
69507e77dcaSMiklos Szeredi kfree(forget);
696fd72faacSMiklos Szeredi d_instantiate(entry, inode);
6971fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outentry);
698261aaba7SMiklos Szeredi fuse_dir_changed(dir);
699be12af3eSAl Viro err = finish_open(file, entry, generic_file_open);
70030d90494SAl Viro if (err) {
701ebf84d0cSKirill Tkhai fi = get_fuse_inode(inode);
702ebf84d0cSKirill Tkhai fuse_sync_release(fi, ff, flags);
703c8ccbe03SMiklos Szeredi } else {
704267d8444SMiklos Szeredi file->private_data = ff;
705c7b7143cSMiklos Szeredi fuse_finish_open(inode, file);
7062fdbb8ddSMiklos Szeredi if (fm->fc->atomic_o_trunc && trunc)
7072fdbb8ddSMiklos Szeredi truncate_pagecache(inode, 0);
7082fdbb8ddSMiklos Szeredi else if (!(ff->open_flags & FOPEN_KEEP_CACHE))
7092fdbb8ddSMiklos Szeredi invalidate_inode_pages2(inode->i_mapping);
710c8ccbe03SMiklos Szeredi }
711d9585277SAl Viro return err;
712fd72faacSMiklos Szeredi
713fd72faacSMiklos Szeredi out_free_ff:
714fd72faacSMiklos Szeredi fuse_file_free(ff);
71551eb01e7SMiklos Szeredi out_put_forget_req:
71607e77dcaSMiklos Szeredi kfree(forget);
717c8ccbe03SMiklos Szeredi out_err:
718d9585277SAl Viro return err;
719c8ccbe03SMiklos Szeredi }
720c8ccbe03SMiklos Szeredi
7215ebb29beSChristian Brauner static int fuse_mknod(struct mnt_idmap *, struct inode *, struct dentry *,
722549c7297SChristian Brauner umode_t, dev_t);
fuse_atomic_open(struct inode * dir,struct dentry * entry,struct file * file,unsigned flags,umode_t mode)723d9585277SAl Viro static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
72430d90494SAl Viro struct file *file, unsigned flags,
72544907d79SAl Viro umode_t mode)
726c8ccbe03SMiklos Szeredi {
727c8ccbe03SMiklos Szeredi int err;
728c8ccbe03SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir);
729c8ccbe03SMiklos Szeredi struct dentry *res = NULL;
730c8ccbe03SMiklos Szeredi
7315d069dbeSMiklos Szeredi if (fuse_is_bad(dir))
7325d069dbeSMiklos Szeredi return -EIO;
7335d069dbeSMiklos Szeredi
73400699ad8SAl Viro if (d_in_lookup(entry)) {
73500cd8dd3SAl Viro res = fuse_lookup(dir, entry, 0);
736c8ccbe03SMiklos Szeredi if (IS_ERR(res))
737d9585277SAl Viro return PTR_ERR(res);
738c8ccbe03SMiklos Szeredi
739c8ccbe03SMiklos Szeredi if (res)
740c8ccbe03SMiklos Szeredi entry = res;
741c8ccbe03SMiklos Szeredi }
742c8ccbe03SMiklos Szeredi
7432b0143b5SDavid Howells if (!(flags & O_CREAT) || d_really_is_positive(entry))
744c8ccbe03SMiklos Szeredi goto no_open;
745c8ccbe03SMiklos Szeredi
746c8ccbe03SMiklos Szeredi /* Only creates */
74773a09dd9SAl Viro file->f_mode |= FMODE_CREATED;
748c8ccbe03SMiklos Szeredi
749c8ccbe03SMiklos Szeredi if (fc->no_create)
750c8ccbe03SMiklos Szeredi goto mknod;
751c8ccbe03SMiklos Szeredi
7527d375390SMiklos Szeredi err = fuse_create_open(dir, entry, file, flags, mode, FUSE_CREATE);
753d9585277SAl Viro if (err == -ENOSYS) {
754c8ccbe03SMiklos Szeredi fc->no_create = 1;
755c8ccbe03SMiklos Szeredi goto mknod;
7567d875e66SJiachen Zhang } else if (err == -EEXIST)
7577d875e66SJiachen Zhang fuse_invalidate_entry(entry);
758c8ccbe03SMiklos Szeredi out_dput:
759c8ccbe03SMiklos Szeredi dput(res);
760d9585277SAl Viro return err;
761c8ccbe03SMiklos Szeredi
762c8ccbe03SMiklos Szeredi mknod:
7635ebb29beSChristian Brauner err = fuse_mknod(&nop_mnt_idmap, dir, entry, mode, 0);
764d9585277SAl Viro if (err)
765c8ccbe03SMiklos Szeredi goto out_dput;
766c8ccbe03SMiklos Szeredi no_open:
767e45198a6SAl Viro return finish_no_open(file, res);
768fd72faacSMiklos Szeredi }
769fd72faacSMiklos Szeredi
7706f9f1180SMiklos Szeredi /*
7716f9f1180SMiklos Szeredi * Code shared between mknod, mkdir, symlink and link
7726f9f1180SMiklos Szeredi */
create_new_entry(struct fuse_mount * fm,struct fuse_args * args,struct inode * dir,struct dentry * entry,umode_t mode)773fcee216bSMax Reitz static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
7749e6268dbSMiklos Szeredi struct inode *dir, struct dentry *entry,
775541af6a0SAl Viro umode_t mode)
7769e6268dbSMiklos Szeredi {
7779e6268dbSMiklos Szeredi struct fuse_entry_out outarg;
7789e6268dbSMiklos Szeredi struct inode *inode;
779c971e6a0SAl Viro struct dentry *d;
7809e6268dbSMiklos Szeredi int err;
78107e77dcaSMiklos Szeredi struct fuse_forget_link *forget;
7822d51013eSMiklos Szeredi
7835d069dbeSMiklos Szeredi if (fuse_is_bad(dir))
7845d069dbeSMiklos Szeredi return -EIO;
7855d069dbeSMiklos Szeredi
78607e77dcaSMiklos Szeredi forget = fuse_alloc_forget();
7877078187aSMiklos Szeredi if (!forget)
78807e77dcaSMiklos Szeredi return -ENOMEM;
7899e6268dbSMiklos Szeredi
7900e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg));
791d5b48543SMiklos Szeredi args->nodeid = get_node_id(dir);
792d5b48543SMiklos Szeredi args->out_numargs = 1;
793d5b48543SMiklos Szeredi args->out_args[0].size = sizeof(outarg);
794d5b48543SMiklos Szeredi args->out_args[0].value = &outarg;
7953e2b6fdbSVivek Goyal
79615d937d7SMiklos Szeredi if (args->opcode != FUSE_LINK) {
7978ed7cb3fSMiklos Szeredi err = get_create_ext(args, dir, entry, mode);
7983e2b6fdbSVivek Goyal if (err)
7993e2b6fdbSVivek Goyal goto out_put_forget_req;
8003e2b6fdbSVivek Goyal }
8013e2b6fdbSVivek Goyal
802fcee216bSMax Reitz err = fuse_simple_request(fm, args);
80315d937d7SMiklos Szeredi free_ext_value(args);
8042d51013eSMiklos Szeredi if (err)
8052d51013eSMiklos Szeredi goto out_put_forget_req;
8062d51013eSMiklos Szeredi
80739ee059aSMiklos Szeredi err = -EIO;
808eb59bd17SMiklos Szeredi if (invalid_nodeid(outarg.nodeid) || fuse_invalid_attr(&outarg.attr))
8092d51013eSMiklos Szeredi goto out_put_forget_req;
81039ee059aSMiklos Szeredi
81139ee059aSMiklos Szeredi if ((outarg.attr.mode ^ mode) & S_IFMT)
8122d51013eSMiklos Szeredi goto out_put_forget_req;
81339ee059aSMiklos Szeredi
8149e6268dbSMiklos Szeredi inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
8159dc10a54SMiklos Szeredi &outarg.attr, ATTR_TIMEOUT(&outarg), 0);
8169e6268dbSMiklos Szeredi if (!inode) {
817fcee216bSMax Reitz fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1);
8189e6268dbSMiklos Szeredi return -ENOMEM;
8199e6268dbSMiklos Szeredi }
82007e77dcaSMiklos Szeredi kfree(forget);
8219e6268dbSMiklos Szeredi
822c971e6a0SAl Viro d_drop(entry);
823c971e6a0SAl Viro d = d_splice_alias(inode, entry);
824c971e6a0SAl Viro if (IS_ERR(d))
825c971e6a0SAl Viro return PTR_ERR(d);
826d2a85164SMiklos Szeredi
827c971e6a0SAl Viro if (d) {
828c971e6a0SAl Viro fuse_change_entry_timeout(d, &outarg);
829c971e6a0SAl Viro dput(d);
830c971e6a0SAl Viro } else {
8311fb69e78SMiklos Szeredi fuse_change_entry_timeout(entry, &outarg);
832c971e6a0SAl Viro }
833261aaba7SMiklos Szeredi fuse_dir_changed(dir);
8349e6268dbSMiklos Szeredi return 0;
83539ee059aSMiklos Szeredi
8362d51013eSMiklos Szeredi out_put_forget_req:
8377d875e66SJiachen Zhang if (err == -EEXIST)
8387d875e66SJiachen Zhang fuse_invalidate_entry(entry);
83907e77dcaSMiklos Szeredi kfree(forget);
84039ee059aSMiklos Szeredi return err;
8419e6268dbSMiklos Szeredi }
8429e6268dbSMiklos Szeredi
fuse_mknod(struct mnt_idmap * idmap,struct inode * dir,struct dentry * entry,umode_t mode,dev_t rdev)8435ebb29beSChristian Brauner static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir,
844549c7297SChristian Brauner struct dentry *entry, umode_t mode, dev_t rdev)
8459e6268dbSMiklos Szeredi {
8469e6268dbSMiklos Szeredi struct fuse_mknod_in inarg;
847fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(dir);
8487078187aSMiklos Szeredi FUSE_ARGS(args);
8499e6268dbSMiklos Szeredi
850fcee216bSMax Reitz if (!fm->fc->dont_mask)
851e0a43ddcSMiklos Szeredi mode &= ~current_umask();
852e0a43ddcSMiklos Szeredi
8539e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg));
8549e6268dbSMiklos Szeredi inarg.mode = mode;
8559e6268dbSMiklos Szeredi inarg.rdev = new_encode_dev(rdev);
856e0a43ddcSMiklos Szeredi inarg.umask = current_umask();
857d5b48543SMiklos Szeredi args.opcode = FUSE_MKNOD;
858d5b48543SMiklos Szeredi args.in_numargs = 2;
859d5b48543SMiklos Szeredi args.in_args[0].size = sizeof(inarg);
860d5b48543SMiklos Szeredi args.in_args[0].value = &inarg;
861d5b48543SMiklos Szeredi args.in_args[1].size = entry->d_name.len + 1;
862d5b48543SMiklos Szeredi args.in_args[1].value = entry->d_name.name;
863fcee216bSMax Reitz return create_new_entry(fm, &args, dir, entry, mode);
8649e6268dbSMiklos Szeredi }
8659e6268dbSMiklos Szeredi
fuse_create(struct mnt_idmap * idmap,struct inode * dir,struct dentry * entry,umode_t mode,bool excl)8666c960e68SChristian Brauner static int fuse_create(struct mnt_idmap *idmap, struct inode *dir,
867549c7297SChristian Brauner struct dentry *entry, umode_t mode, bool excl)
8689e6268dbSMiklos Szeredi {
8695ebb29beSChristian Brauner return fuse_mknod(&nop_mnt_idmap, dir, entry, mode, 0);
8709e6268dbSMiklos Szeredi }
8719e6268dbSMiklos Szeredi
fuse_tmpfile(struct mnt_idmap * idmap,struct inode * dir,struct file * file,umode_t mode)872011e2b71SChristian Brauner static int fuse_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
8737d375390SMiklos Szeredi struct file *file, umode_t mode)
8747d375390SMiklos Szeredi {
8757d375390SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(dir);
8767d375390SMiklos Szeredi int err;
8777d375390SMiklos Szeredi
8787d375390SMiklos Szeredi if (fc->no_tmpfile)
8797d375390SMiklos Szeredi return -EOPNOTSUPP;
8807d375390SMiklos Szeredi
8817d375390SMiklos Szeredi err = fuse_create_open(dir, file->f_path.dentry, file, file->f_flags, mode, FUSE_TMPFILE);
8827d375390SMiklos Szeredi if (err == -ENOSYS) {
8837d375390SMiklos Szeredi fc->no_tmpfile = 1;
8847d375390SMiklos Szeredi err = -EOPNOTSUPP;
8857d375390SMiklos Szeredi }
8867d375390SMiklos Szeredi return err;
8877d375390SMiklos Szeredi }
8887d375390SMiklos Szeredi
fuse_mkdir(struct mnt_idmap * idmap,struct inode * dir,struct dentry * entry,umode_t mode)889c54bd91eSChristian Brauner static int fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir,
890549c7297SChristian Brauner struct dentry *entry, umode_t mode)
8919e6268dbSMiklos Szeredi {
8929e6268dbSMiklos Szeredi struct fuse_mkdir_in inarg;
893fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(dir);
8947078187aSMiklos Szeredi FUSE_ARGS(args);
8959e6268dbSMiklos Szeredi
896fcee216bSMax Reitz if (!fm->fc->dont_mask)
897e0a43ddcSMiklos Szeredi mode &= ~current_umask();
898e0a43ddcSMiklos Szeredi
8999e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg));
9009e6268dbSMiklos Szeredi inarg.mode = mode;
901e0a43ddcSMiklos Szeredi inarg.umask = current_umask();
902d5b48543SMiklos Szeredi args.opcode = FUSE_MKDIR;
903d5b48543SMiklos Szeredi args.in_numargs = 2;
904d5b48543SMiklos Szeredi args.in_args[0].size = sizeof(inarg);
905d5b48543SMiklos Szeredi args.in_args[0].value = &inarg;
906d5b48543SMiklos Szeredi args.in_args[1].size = entry->d_name.len + 1;
907d5b48543SMiklos Szeredi args.in_args[1].value = entry->d_name.name;
908fcee216bSMax Reitz return create_new_entry(fm, &args, dir, entry, S_IFDIR);
9099e6268dbSMiklos Szeredi }
9109e6268dbSMiklos Szeredi
fuse_symlink(struct mnt_idmap * idmap,struct inode * dir,struct dentry * entry,const char * link)9117a77db95SChristian Brauner static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir,
912549c7297SChristian Brauner struct dentry *entry, const char *link)
9139e6268dbSMiklos Szeredi {
914fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(dir);
9159e6268dbSMiklos Szeredi unsigned len = strlen(link) + 1;
9167078187aSMiklos Szeredi FUSE_ARGS(args);
9179e6268dbSMiklos Szeredi
918d5b48543SMiklos Szeredi args.opcode = FUSE_SYMLINK;
919d5b48543SMiklos Szeredi args.in_numargs = 2;
920d5b48543SMiklos Szeredi args.in_args[0].size = entry->d_name.len + 1;
921d5b48543SMiklos Szeredi args.in_args[0].value = entry->d_name.name;
922d5b48543SMiklos Szeredi args.in_args[1].size = len;
923d5b48543SMiklos Szeredi args.in_args[1].value = link;
924fcee216bSMax Reitz return create_new_entry(fm, &args, dir, entry, S_IFLNK);
9259e6268dbSMiklos Szeredi }
9269e6268dbSMiklos Szeredi
fuse_flush_time_update(struct inode * inode)9275c791fe1SMiklos Szeredi void fuse_flush_time_update(struct inode *inode)
9285c791fe1SMiklos Szeredi {
9295c791fe1SMiklos Szeredi int err = sync_inode_metadata(inode, 1);
9305c791fe1SMiklos Szeredi
9315c791fe1SMiklos Szeredi mapping_set_error(inode->i_mapping, err);
9325c791fe1SMiklos Szeredi }
9335c791fe1SMiklos Szeredi
fuse_update_ctime_in_cache(struct inode * inode)93497f044f6SMiklos Szeredi static void fuse_update_ctime_in_cache(struct inode *inode)
93531f3267bSMaxim Patlasov {
93631f3267bSMaxim Patlasov if (!IS_NOCMTIME(inode)) {
937ceb2d5e9SJeff Layton inode_set_ctime_current(inode);
93831f3267bSMaxim Patlasov mark_inode_dirty_sync(inode);
9395c791fe1SMiklos Szeredi fuse_flush_time_update(inode);
94031f3267bSMaxim Patlasov }
94131f3267bSMaxim Patlasov }
94231f3267bSMaxim Patlasov
fuse_update_ctime(struct inode * inode)94397f044f6SMiklos Szeredi void fuse_update_ctime(struct inode *inode)
94497f044f6SMiklos Szeredi {
945fa5eee57SMiklos Szeredi fuse_invalidate_attr_mask(inode, STATX_CTIME);
94697f044f6SMiklos Szeredi fuse_update_ctime_in_cache(inode);
94797f044f6SMiklos Szeredi }
94897f044f6SMiklos Szeredi
fuse_entry_unlinked(struct dentry * entry)949cefd1b83SMiklos Szeredi static void fuse_entry_unlinked(struct dentry *entry)
950cefd1b83SMiklos Szeredi {
951cefd1b83SMiklos Szeredi struct inode *inode = d_inode(entry);
952cefd1b83SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode);
953cefd1b83SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode);
954cefd1b83SMiklos Szeredi
955cefd1b83SMiklos Szeredi spin_lock(&fi->lock);
956cefd1b83SMiklos Szeredi fi->attr_version = atomic64_inc_return(&fc->attr_version);
957cefd1b83SMiklos Szeredi /*
958cefd1b83SMiklos Szeredi * If i_nlink == 0 then unlink doesn't make sense, yet this can
959cefd1b83SMiklos Szeredi * happen if userspace filesystem is careless. It would be
960cefd1b83SMiklos Szeredi * difficult to enforce correct nlink usage so just ignore this
961cefd1b83SMiklos Szeredi * condition here
962cefd1b83SMiklos Szeredi */
963cefd1b83SMiklos Szeredi if (S_ISDIR(inode->i_mode))
964cefd1b83SMiklos Szeredi clear_nlink(inode);
965cefd1b83SMiklos Szeredi else if (inode->i_nlink > 0)
966cefd1b83SMiklos Szeredi drop_nlink(inode);
967cefd1b83SMiklos Szeredi spin_unlock(&fi->lock);
968cefd1b83SMiklos Szeredi fuse_invalidate_entry_cache(entry);
969cefd1b83SMiklos Szeredi fuse_update_ctime(inode);
970cefd1b83SMiklos Szeredi }
971cefd1b83SMiklos Szeredi
fuse_unlink(struct inode * dir,struct dentry * entry)9729e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry)
9739e6268dbSMiklos Szeredi {
9749e6268dbSMiklos Szeredi int err;
975fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(dir);
9767078187aSMiklos Szeredi FUSE_ARGS(args);
9779e6268dbSMiklos Szeredi
9785d069dbeSMiklos Szeredi if (fuse_is_bad(dir))
9795d069dbeSMiklos Szeredi return -EIO;
9805d069dbeSMiklos Szeredi
981d5b48543SMiklos Szeredi args.opcode = FUSE_UNLINK;
982d5b48543SMiklos Szeredi args.nodeid = get_node_id(dir);
983d5b48543SMiklos Szeredi args.in_numargs = 1;
984d5b48543SMiklos Szeredi args.in_args[0].size = entry->d_name.len + 1;
985d5b48543SMiklos Szeredi args.in_args[0].value = entry->d_name.name;
986fcee216bSMax Reitz err = fuse_simple_request(fm, &args);
9879e6268dbSMiklos Szeredi if (!err) {
988261aaba7SMiklos Szeredi fuse_dir_changed(dir);
989cefd1b83SMiklos Szeredi fuse_entry_unlinked(entry);
9907d875e66SJiachen Zhang } else if (err == -EINTR || err == -ENOENT)
9919e6268dbSMiklos Szeredi fuse_invalidate_entry(entry);
9929e6268dbSMiklos Szeredi return err;
9939e6268dbSMiklos Szeredi }
9949e6268dbSMiklos Szeredi
fuse_rmdir(struct inode * dir,struct dentry * entry)9959e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry)
9969e6268dbSMiklos Szeredi {
9979e6268dbSMiklos Szeredi int err;
998fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(dir);
9997078187aSMiklos Szeredi FUSE_ARGS(args);
10009e6268dbSMiklos Szeredi
10015d069dbeSMiklos Szeredi if (fuse_is_bad(dir))
10025d069dbeSMiklos Szeredi return -EIO;
10035d069dbeSMiklos Szeredi
1004d5b48543SMiklos Szeredi args.opcode = FUSE_RMDIR;
1005d5b48543SMiklos Szeredi args.nodeid = get_node_id(dir);
1006d5b48543SMiklos Szeredi args.in_numargs = 1;
1007d5b48543SMiklos Szeredi args.in_args[0].size = entry->d_name.len + 1;
1008d5b48543SMiklos Szeredi args.in_args[0].value = entry->d_name.name;
1009fcee216bSMax Reitz err = fuse_simple_request(fm, &args);
10109e6268dbSMiklos Szeredi if (!err) {
1011261aaba7SMiklos Szeredi fuse_dir_changed(dir);
1012cefd1b83SMiklos Szeredi fuse_entry_unlinked(entry);
10137d875e66SJiachen Zhang } else if (err == -EINTR || err == -ENOENT)
10149e6268dbSMiklos Szeredi fuse_invalidate_entry(entry);
10159e6268dbSMiklos Szeredi return err;
10169e6268dbSMiklos Szeredi }
10179e6268dbSMiklos Szeredi
fuse_rename_common(struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent,unsigned int flags,int opcode,size_t argsize)10181560c974SMiklos Szeredi static int fuse_rename_common(struct inode *olddir, struct dentry *oldent,
10191560c974SMiklos Szeredi struct inode *newdir, struct dentry *newent,
10201560c974SMiklos Szeredi unsigned int flags, int opcode, size_t argsize)
10219e6268dbSMiklos Szeredi {
10229e6268dbSMiklos Szeredi int err;
10231560c974SMiklos Szeredi struct fuse_rename2_in inarg;
1024fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(olddir);
10257078187aSMiklos Szeredi FUSE_ARGS(args);
10269e6268dbSMiklos Szeredi
10271560c974SMiklos Szeredi memset(&inarg, 0, argsize);
10289e6268dbSMiklos Szeredi inarg.newdir = get_node_id(newdir);
10291560c974SMiklos Szeredi inarg.flags = flags;
1030d5b48543SMiklos Szeredi args.opcode = opcode;
1031d5b48543SMiklos Szeredi args.nodeid = get_node_id(olddir);
1032d5b48543SMiklos Szeredi args.in_numargs = 3;
1033d5b48543SMiklos Szeredi args.in_args[0].size = argsize;
1034d5b48543SMiklos Szeredi args.in_args[0].value = &inarg;
1035d5b48543SMiklos Szeredi args.in_args[1].size = oldent->d_name.len + 1;
1036d5b48543SMiklos Szeredi args.in_args[1].value = oldent->d_name.name;
1037d5b48543SMiklos Szeredi args.in_args[2].size = newent->d_name.len + 1;
1038d5b48543SMiklos Szeredi args.in_args[2].value = newent->d_name.name;
1039fcee216bSMax Reitz err = fuse_simple_request(fm, &args);
10409e6268dbSMiklos Szeredi if (!err) {
104108b63307SMiklos Szeredi /* ctime changes */
10422b0143b5SDavid Howells fuse_update_ctime(d_inode(oldent));
104308b63307SMiklos Szeredi
1044371e8fd0SMiklos Szeredi if (flags & RENAME_EXCHANGE)
10452b0143b5SDavid Howells fuse_update_ctime(d_inode(newent));
10461560c974SMiklos Szeredi
1047261aaba7SMiklos Szeredi fuse_dir_changed(olddir);
10489e6268dbSMiklos Szeredi if (olddir != newdir)
1049261aaba7SMiklos Szeredi fuse_dir_changed(newdir);
10508cbdf1e6SMiklos Szeredi
10518cbdf1e6SMiklos Szeredi /* newent will end up negative */
1052cefd1b83SMiklos Szeredi if (!(flags & RENAME_EXCHANGE) && d_really_is_positive(newent))
1053cefd1b83SMiklos Szeredi fuse_entry_unlinked(newent);
10547d875e66SJiachen Zhang } else if (err == -EINTR || err == -ENOENT) {
10559e6268dbSMiklos Szeredi /* If request was interrupted, DEITY only knows if the
10569e6268dbSMiklos Szeredi rename actually took place. If the invalidation
10579e6268dbSMiklos Szeredi fails (e.g. some process has CWD under the renamed
10589e6268dbSMiklos Szeredi directory), then there can be inconsistency between
10599e6268dbSMiklos Szeredi the dcache and the real filesystem. Tough luck. */
10609e6268dbSMiklos Szeredi fuse_invalidate_entry(oldent);
10612b0143b5SDavid Howells if (d_really_is_positive(newent))
10629e6268dbSMiklos Szeredi fuse_invalidate_entry(newent);
10639e6268dbSMiklos Szeredi }
10649e6268dbSMiklos Szeredi
10659e6268dbSMiklos Szeredi return err;
10669e6268dbSMiklos Szeredi }
10679e6268dbSMiklos Szeredi
fuse_rename2(struct mnt_idmap * idmap,struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent,unsigned int flags)1068e18275aeSChristian Brauner static int fuse_rename2(struct mnt_idmap *idmap, struct inode *olddir,
1069549c7297SChristian Brauner struct dentry *oldent, struct inode *newdir,
1070549c7297SChristian Brauner struct dentry *newent, unsigned int flags)
10711560c974SMiklos Szeredi {
10721560c974SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(olddir);
10731560c974SMiklos Szeredi int err;
10741560c974SMiklos Szeredi
10755d069dbeSMiklos Szeredi if (fuse_is_bad(olddir))
10765d069dbeSMiklos Szeredi return -EIO;
10775d069dbeSMiklos Szeredi
1078519525faSVivek Goyal if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
10791560c974SMiklos Szeredi return -EINVAL;
10801560c974SMiklos Szeredi
10814237ba43SMiklos Szeredi if (flags) {
10821560c974SMiklos Szeredi if (fc->no_rename2 || fc->minor < 23)
10831560c974SMiklos Szeredi return -EINVAL;
10841560c974SMiklos Szeredi
10851560c974SMiklos Szeredi err = fuse_rename_common(olddir, oldent, newdir, newent, flags,
10864237ba43SMiklos Szeredi FUSE_RENAME2,
10874237ba43SMiklos Szeredi sizeof(struct fuse_rename2_in));
10881560c974SMiklos Szeredi if (err == -ENOSYS) {
10891560c974SMiklos Szeredi fc->no_rename2 = 1;
10901560c974SMiklos Szeredi err = -EINVAL;
10911560c974SMiklos Szeredi }
10924237ba43SMiklos Szeredi } else {
10934237ba43SMiklos Szeredi err = fuse_rename_common(olddir, oldent, newdir, newent, 0,
10944237ba43SMiklos Szeredi FUSE_RENAME,
10954237ba43SMiklos Szeredi sizeof(struct fuse_rename_in));
10964237ba43SMiklos Szeredi }
10971560c974SMiklos Szeredi
10984237ba43SMiklos Szeredi return err;
10994237ba43SMiklos Szeredi }
11004237ba43SMiklos Szeredi
fuse_link(struct dentry * entry,struct inode * newdir,struct dentry * newent)11019e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir,
11029e6268dbSMiklos Szeredi struct dentry *newent)
11039e6268dbSMiklos Szeredi {
11049e6268dbSMiklos Szeredi int err;
11059e6268dbSMiklos Szeredi struct fuse_link_in inarg;
11062b0143b5SDavid Howells struct inode *inode = d_inode(entry);
1107fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode);
11087078187aSMiklos Szeredi FUSE_ARGS(args);
11099e6268dbSMiklos Szeredi
11109e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg));
11119e6268dbSMiklos Szeredi inarg.oldnodeid = get_node_id(inode);
1112d5b48543SMiklos Szeredi args.opcode = FUSE_LINK;
1113d5b48543SMiklos Szeredi args.in_numargs = 2;
1114d5b48543SMiklos Szeredi args.in_args[0].size = sizeof(inarg);
1115d5b48543SMiklos Szeredi args.in_args[0].value = &inarg;
1116d5b48543SMiklos Szeredi args.in_args[1].size = newent->d_name.len + 1;
1117d5b48543SMiklos Szeredi args.in_args[1].value = newent->d_name.name;
1118fcee216bSMax Reitz err = create_new_entry(fm, &args, newdir, newent, inode->i_mode);
111997f044f6SMiklos Szeredi if (!err)
112097f044f6SMiklos Szeredi fuse_update_ctime_in_cache(inode);
112197f044f6SMiklos Szeredi else if (err == -EINTR)
1122ac45d613SMiklos Szeredi fuse_invalidate_attr(inode);
112397f044f6SMiklos Szeredi
11249e6268dbSMiklos Szeredi return err;
11259e6268dbSMiklos Szeredi }
11269e6268dbSMiklos Szeredi
fuse_fillattr(struct inode * inode,struct fuse_attr * attr,struct kstat * stat)11271fb69e78SMiklos Szeredi static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
11281fb69e78SMiklos Szeredi struct kstat *stat)
11291fb69e78SMiklos Szeredi {
1130203627bbSMiklos Szeredi unsigned int blkbits;
11318373200bSPavel Emelyanov struct fuse_conn *fc = get_fuse_conn(inode);
11328373200bSPavel Emelyanov
11331fb69e78SMiklos Szeredi stat->dev = inode->i_sb->s_dev;
11341fb69e78SMiklos Szeredi stat->ino = attr->ino;
11351fb69e78SMiklos Szeredi stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
11361fb69e78SMiklos Szeredi stat->nlink = attr->nlink;
11378cb08329SEric W. Biederman stat->uid = make_kuid(fc->user_ns, attr->uid);
11388cb08329SEric W. Biederman stat->gid = make_kgid(fc->user_ns, attr->gid);
11391fb69e78SMiklos Szeredi stat->rdev = inode->i_rdev;
11401fb69e78SMiklos Szeredi stat->atime.tv_sec = attr->atime;
11411fb69e78SMiklos Szeredi stat->atime.tv_nsec = attr->atimensec;
11421fb69e78SMiklos Szeredi stat->mtime.tv_sec = attr->mtime;
11431fb69e78SMiklos Szeredi stat->mtime.tv_nsec = attr->mtimensec;
11441fb69e78SMiklos Szeredi stat->ctime.tv_sec = attr->ctime;
11451fb69e78SMiklos Szeredi stat->ctime.tv_nsec = attr->ctimensec;
11461fb69e78SMiklos Szeredi stat->size = attr->size;
11471fb69e78SMiklos Szeredi stat->blocks = attr->blocks;
1148203627bbSMiklos Szeredi
1149203627bbSMiklos Szeredi if (attr->blksize != 0)
1150203627bbSMiklos Szeredi blkbits = ilog2(attr->blksize);
1151203627bbSMiklos Szeredi else
1152203627bbSMiklos Szeredi blkbits = inode->i_sb->s_blocksize_bits;
1153203627bbSMiklos Szeredi
1154203627bbSMiklos Szeredi stat->blksize = 1 << blkbits;
11551fb69e78SMiklos Szeredi }
11561fb69e78SMiklos Szeredi
fuse_statx_to_attr(struct fuse_statx * sx,struct fuse_attr * attr)1157d3045530SMiklos Szeredi static void fuse_statx_to_attr(struct fuse_statx *sx, struct fuse_attr *attr)
1158d3045530SMiklos Szeredi {
1159d3045530SMiklos Szeredi memset(attr, 0, sizeof(*attr));
1160d3045530SMiklos Szeredi attr->ino = sx->ino;
1161d3045530SMiklos Szeredi attr->size = sx->size;
1162d3045530SMiklos Szeredi attr->blocks = sx->blocks;
1163d3045530SMiklos Szeredi attr->atime = sx->atime.tv_sec;
1164d3045530SMiklos Szeredi attr->mtime = sx->mtime.tv_sec;
1165d3045530SMiklos Szeredi attr->ctime = sx->ctime.tv_sec;
1166d3045530SMiklos Szeredi attr->atimensec = sx->atime.tv_nsec;
1167d3045530SMiklos Szeredi attr->mtimensec = sx->mtime.tv_nsec;
1168d3045530SMiklos Szeredi attr->ctimensec = sx->ctime.tv_nsec;
1169d3045530SMiklos Szeredi attr->mode = sx->mode;
1170d3045530SMiklos Szeredi attr->nlink = sx->nlink;
1171d3045530SMiklos Szeredi attr->uid = sx->uid;
1172d3045530SMiklos Szeredi attr->gid = sx->gid;
1173d3045530SMiklos Szeredi attr->rdev = new_encode_dev(MKDEV(sx->rdev_major, sx->rdev_minor));
1174d3045530SMiklos Szeredi attr->blksize = sx->blksize;
1175d3045530SMiklos Szeredi }
1176d3045530SMiklos Szeredi
fuse_do_statx(struct inode * inode,struct file * file,struct kstat * stat)1177d3045530SMiklos Szeredi static int fuse_do_statx(struct inode *inode, struct file *file,
1178d3045530SMiklos Szeredi struct kstat *stat)
1179d3045530SMiklos Szeredi {
1180d3045530SMiklos Szeredi int err;
1181d3045530SMiklos Szeredi struct fuse_attr attr;
1182d3045530SMiklos Szeredi struct fuse_statx *sx;
1183d3045530SMiklos Szeredi struct fuse_statx_in inarg;
1184d3045530SMiklos Szeredi struct fuse_statx_out outarg;
1185d3045530SMiklos Szeredi struct fuse_mount *fm = get_fuse_mount(inode);
1186d3045530SMiklos Szeredi u64 attr_version = fuse_get_attr_version(fm->fc);
1187d3045530SMiklos Szeredi FUSE_ARGS(args);
1188d3045530SMiklos Szeredi
1189d3045530SMiklos Szeredi memset(&inarg, 0, sizeof(inarg));
1190d3045530SMiklos Szeredi memset(&outarg, 0, sizeof(outarg));
1191d3045530SMiklos Szeredi /* Directories have separate file-handle space */
1192d3045530SMiklos Szeredi if (file && S_ISREG(inode->i_mode)) {
1193d3045530SMiklos Szeredi struct fuse_file *ff = file->private_data;
1194d3045530SMiklos Szeredi
1195d3045530SMiklos Szeredi inarg.getattr_flags |= FUSE_GETATTR_FH;
1196d3045530SMiklos Szeredi inarg.fh = ff->fh;
1197d3045530SMiklos Szeredi }
1198d3045530SMiklos Szeredi /* For now leave sync hints as the default, request all stats. */
1199d3045530SMiklos Szeredi inarg.sx_flags = 0;
1200d3045530SMiklos Szeredi inarg.sx_mask = STATX_BASIC_STATS | STATX_BTIME;
1201d3045530SMiklos Szeredi args.opcode = FUSE_STATX;
1202d3045530SMiklos Szeredi args.nodeid = get_node_id(inode);
1203d3045530SMiklos Szeredi args.in_numargs = 1;
1204d3045530SMiklos Szeredi args.in_args[0].size = sizeof(inarg);
1205d3045530SMiklos Szeredi args.in_args[0].value = &inarg;
1206d3045530SMiklos Szeredi args.out_numargs = 1;
1207d3045530SMiklos Szeredi args.out_args[0].size = sizeof(outarg);
1208d3045530SMiklos Szeredi args.out_args[0].value = &outarg;
1209d3045530SMiklos Szeredi err = fuse_simple_request(fm, &args);
1210d3045530SMiklos Szeredi if (err)
1211d3045530SMiklos Szeredi return err;
1212d3045530SMiklos Szeredi
1213d3045530SMiklos Szeredi sx = &outarg.stat;
1214d3045530SMiklos Szeredi if (((sx->mask & STATX_SIZE) && !fuse_valid_size(sx->size)) ||
1215d3045530SMiklos Szeredi ((sx->mask & STATX_TYPE) && (!fuse_valid_type(sx->mode) ||
1216d3045530SMiklos Szeredi inode_wrong_type(inode, sx->mode)))) {
12173d304dd6SMiklos Szeredi fuse_make_bad(inode);
1218d3045530SMiklos Szeredi return -EIO;
1219d3045530SMiklos Szeredi }
1220d3045530SMiklos Szeredi
1221d3045530SMiklos Szeredi fuse_statx_to_attr(&outarg.stat, &attr);
1222d3045530SMiklos Szeredi if ((sx->mask & STATX_BASIC_STATS) == STATX_BASIC_STATS) {
1223972f4c46SMiklos Szeredi fuse_change_attributes(inode, &attr, &outarg.stat,
1224972f4c46SMiklos Szeredi ATTR_TIMEOUT(&outarg), attr_version);
1225d3045530SMiklos Szeredi }
1226f73016b6SBernd Schubert
1227f73016b6SBernd Schubert if (stat) {
1228d3045530SMiklos Szeredi stat->result_mask = sx->mask & (STATX_BASIC_STATS | STATX_BTIME);
1229d3045530SMiklos Szeredi stat->btime.tv_sec = sx->btime.tv_sec;
1230d3045530SMiklos Szeredi stat->btime.tv_nsec = min_t(u32, sx->btime.tv_nsec, NSEC_PER_SEC - 1);
1231d3045530SMiklos Szeredi fuse_fillattr(inode, &attr, stat);
1232d3045530SMiklos Szeredi stat->result_mask |= STATX_TYPE;
1233f73016b6SBernd Schubert }
1234d3045530SMiklos Szeredi
1235d3045530SMiklos Szeredi return 0;
1236d3045530SMiklos Szeredi }
1237d3045530SMiklos Szeredi
fuse_do_getattr(struct inode * inode,struct kstat * stat,struct file * file)1238c79e322fSMiklos Szeredi static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
1239c79e322fSMiklos Szeredi struct file *file)
1240e5e5558eSMiklos Szeredi {
1241e5e5558eSMiklos Szeredi int err;
1242c79e322fSMiklos Szeredi struct fuse_getattr_in inarg;
1243c79e322fSMiklos Szeredi struct fuse_attr_out outarg;
1244fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode);
12457078187aSMiklos Szeredi FUSE_ARGS(args);
12461fb69e78SMiklos Szeredi u64 attr_version;
12471fb69e78SMiklos Szeredi
1248fcee216bSMax Reitz attr_version = fuse_get_attr_version(fm->fc);
12491fb69e78SMiklos Szeredi
1250c79e322fSMiklos Szeredi memset(&inarg, 0, sizeof(inarg));
12510e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg));
1252c79e322fSMiklos Szeredi /* Directories have separate file-handle space */
1253c79e322fSMiklos Szeredi if (file && S_ISREG(inode->i_mode)) {
1254c79e322fSMiklos Szeredi struct fuse_file *ff = file->private_data;
1255c79e322fSMiklos Szeredi
1256c79e322fSMiklos Szeredi inarg.getattr_flags |= FUSE_GETATTR_FH;
1257c79e322fSMiklos Szeredi inarg.fh = ff->fh;
1258c79e322fSMiklos Szeredi }
1259d5b48543SMiklos Szeredi args.opcode = FUSE_GETATTR;
1260d5b48543SMiklos Szeredi args.nodeid = get_node_id(inode);
1261d5b48543SMiklos Szeredi args.in_numargs = 1;
1262d5b48543SMiklos Szeredi args.in_args[0].size = sizeof(inarg);
1263d5b48543SMiklos Szeredi args.in_args[0].value = &inarg;
1264d5b48543SMiklos Szeredi args.out_numargs = 1;
1265d5b48543SMiklos Szeredi args.out_args[0].size = sizeof(outarg);
1266d5b48543SMiklos Szeredi args.out_args[0].value = &outarg;
1267fcee216bSMax Reitz err = fuse_simple_request(fm, &args);
1268e5e5558eSMiklos Szeredi if (!err) {
1269eb59bd17SMiklos Szeredi if (fuse_invalid_attr(&outarg.attr) ||
12706e3e2c43SAl Viro inode_wrong_type(inode, outarg.attr.mode)) {
12715d069dbeSMiklos Szeredi fuse_make_bad(inode);
1272e5e5558eSMiklos Szeredi err = -EIO;
1273e5e5558eSMiklos Szeredi } else {
1274972f4c46SMiklos Szeredi fuse_change_attributes(inode, &outarg.attr, NULL,
12759dc10a54SMiklos Szeredi ATTR_TIMEOUT(&outarg),
12761fb69e78SMiklos Szeredi attr_version);
12771fb69e78SMiklos Szeredi if (stat)
1278c79e322fSMiklos Szeredi fuse_fillattr(inode, &outarg.attr, stat);
1279e5e5558eSMiklos Szeredi }
1280e5e5558eSMiklos Szeredi }
1281e5e5558eSMiklos Szeredi return err;
1282e5e5558eSMiklos Szeredi }
1283e5e5558eSMiklos Szeredi
fuse_update_get_attr(struct inode * inode,struct file * file,struct kstat * stat,u32 request_mask,unsigned int flags)12845b97eeacSMiklos Szeredi static int fuse_update_get_attr(struct inode *inode, struct file *file,
12852f1e8196SMiklos Szeredi struct kstat *stat, u32 request_mask,
12862f1e8196SMiklos Szeredi unsigned int flags)
1287bcb4be80SMiklos Szeredi {
1288bcb4be80SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode);
1289d3045530SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode);
12905b97eeacSMiklos Szeredi int err = 0;
1291bf5c1898SMiklos Szeredi bool sync;
1292ec855375SMiklos Szeredi u32 inval_mask = READ_ONCE(fi->inval_mask);
1293ec855375SMiklos Szeredi u32 cache_mask = fuse_get_cache_mask(inode);
1294bcb4be80SMiklos Szeredi
1295d3045530SMiklos Szeredi
1296d3045530SMiklos Szeredi /* FUSE only supports basic stats and possibly btime */
1297d3045530SMiklos Szeredi request_mask &= STATX_BASIC_STATS | STATX_BTIME;
1298d3045530SMiklos Szeredi retry:
1299d3045530SMiklos Szeredi if (fc->no_statx)
13008d8f9c4bSMiklos Szeredi request_mask &= STATX_BASIC_STATS;
13018d8f9c4bSMiklos Szeredi
13028d8f9c4bSMiklos Szeredi if (!request_mask)
13038d8f9c4bSMiklos Szeredi sync = false;
13048d8f9c4bSMiklos Szeredi else if (flags & AT_STATX_FORCE_SYNC)
1305bf5c1898SMiklos Szeredi sync = true;
1306bf5c1898SMiklos Szeredi else if (flags & AT_STATX_DONT_SYNC)
1307bf5c1898SMiklos Szeredi sync = false;
1308ec855375SMiklos Szeredi else if (request_mask & inval_mask & ~cache_mask)
13092f1e8196SMiklos Szeredi sync = true;
1310bf5c1898SMiklos Szeredi else
1311bf5c1898SMiklos Szeredi sync = time_before64(fi->i_time, get_jiffies_64());
1312bf5c1898SMiklos Szeredi
1313bf5c1898SMiklos Szeredi if (sync) {
131460bcc88aSSeth Forshee forget_all_cached_acls(inode);
1315d3045530SMiklos Szeredi /* Try statx if BTIME is requested */
1316d3045530SMiklos Szeredi if (!fc->no_statx && (request_mask & ~STATX_BASIC_STATS)) {
1317d3045530SMiklos Szeredi err = fuse_do_statx(inode, file, stat);
1318d3045530SMiklos Szeredi if (err == -ENOSYS) {
1319d3045530SMiklos Szeredi fc->no_statx = 1;
1320885d4c31SDanny Lin err = 0;
1321d3045530SMiklos Szeredi goto retry;
1322d3045530SMiklos Szeredi }
1323d3045530SMiklos Szeredi } else {
1324bcb4be80SMiklos Szeredi err = fuse_do_getattr(inode, stat, file);
1325d3045530SMiklos Szeredi }
13265b97eeacSMiklos Szeredi } else if (stat) {
13270d72b928SJeff Layton generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
1328bcb4be80SMiklos Szeredi stat->mode = fi->orig_i_mode;
132945c72cd7SPavel Shilovsky stat->ino = fi->orig_ino;
1330972f4c46SMiklos Szeredi if (test_bit(FUSE_I_BTIME, &fi->state)) {
1331972f4c46SMiklos Szeredi stat->btime = fi->i_btime;
1332972f4c46SMiklos Szeredi stat->result_mask |= STATX_BTIME;
1333972f4c46SMiklos Szeredi }
1334bcb4be80SMiklos Szeredi }
1335bcb4be80SMiklos Szeredi
1336bcb4be80SMiklos Szeredi return err;
1337bcb4be80SMiklos Szeredi }
1338bcb4be80SMiklos Szeredi
fuse_update_attributes(struct inode * inode,struct file * file,u32 mask)1339c6c745b8SMiklos Szeredi int fuse_update_attributes(struct inode *inode, struct file *file, u32 mask)
13405b97eeacSMiklos Szeredi {
1341c6c745b8SMiklos Szeredi return fuse_update_get_attr(inode, file, NULL, mask, 0);
13425b97eeacSMiklos Szeredi }
13435b97eeacSMiklos Szeredi
fuse_reverse_inval_entry(struct fuse_conn * fc,u64 parent_nodeid,u64 child_nodeid,struct qstr * name,u32 flags)1344fcee216bSMax Reitz int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
13454f8d3702SMiklos Szeredi u64 child_nodeid, struct qstr *name, u32 flags)
13463b463ae0SJohn Muir {
13473b463ae0SJohn Muir int err = -ENOTDIR;
13483b463ae0SJohn Muir struct inode *parent;
13493b463ae0SJohn Muir struct dentry *dir;
13503b463ae0SJohn Muir struct dentry *entry;
13513b463ae0SJohn Muir
1352fcee216bSMax Reitz parent = fuse_ilookup(fc, parent_nodeid, NULL);
13533b463ae0SJohn Muir if (!parent)
13543b463ae0SJohn Muir return -ENOENT;
13553b463ae0SJohn Muir
1356bda9a719SMiklos Szeredi inode_lock_nested(parent, I_MUTEX_PARENT);
13573b463ae0SJohn Muir if (!S_ISDIR(parent->i_mode))
13583b463ae0SJohn Muir goto unlock;
13593b463ae0SJohn Muir
13603b463ae0SJohn Muir err = -ENOENT;
13613b463ae0SJohn Muir dir = d_find_alias(parent);
13623b463ae0SJohn Muir if (!dir)
13633b463ae0SJohn Muir goto unlock;
13643b463ae0SJohn Muir
13658387ff25SLinus Torvalds name->hash = full_name_hash(dir, name->name, name->len);
13663b463ae0SJohn Muir entry = d_lookup(dir, name);
13673b463ae0SJohn Muir dput(dir);
13683b463ae0SJohn Muir if (!entry)
13693b463ae0SJohn Muir goto unlock;
13703b463ae0SJohn Muir
1371261aaba7SMiklos Szeredi fuse_dir_changed(parent);
13724f8d3702SMiklos Szeredi if (!(flags & FUSE_EXPIRE_ONLY))
13734f8d3702SMiklos Szeredi d_invalidate(entry);
13744f8d3702SMiklos Szeredi fuse_invalidate_entry_cache(entry);
1375451d0f59SJohn Muir
13762b0143b5SDavid Howells if (child_nodeid != 0 && d_really_is_positive(entry)) {
13775955102cSAl Viro inode_lock(d_inode(entry));
13782b0143b5SDavid Howells if (get_node_id(d_inode(entry)) != child_nodeid) {
1379451d0f59SJohn Muir err = -ENOENT;
1380451d0f59SJohn Muir goto badentry;
1381451d0f59SJohn Muir }
1382451d0f59SJohn Muir if (d_mountpoint(entry)) {
1383451d0f59SJohn Muir err = -EBUSY;
1384451d0f59SJohn Muir goto badentry;
1385451d0f59SJohn Muir }
1386e36cb0b8SDavid Howells if (d_is_dir(entry)) {
1387451d0f59SJohn Muir shrink_dcache_parent(entry);
1388451d0f59SJohn Muir if (!simple_empty(entry)) {
1389451d0f59SJohn Muir err = -ENOTEMPTY;
1390451d0f59SJohn Muir goto badentry;
1391451d0f59SJohn Muir }
13922b0143b5SDavid Howells d_inode(entry)->i_flags |= S_DEAD;
1393451d0f59SJohn Muir }
1394451d0f59SJohn Muir dont_mount(entry);
13952b0143b5SDavid Howells clear_nlink(d_inode(entry));
13963b463ae0SJohn Muir err = 0;
1397451d0f59SJohn Muir badentry:
13985955102cSAl Viro inode_unlock(d_inode(entry));
1399451d0f59SJohn Muir if (!err)
1400451d0f59SJohn Muir d_delete(entry);
1401451d0f59SJohn Muir } else {
1402451d0f59SJohn Muir err = 0;
1403451d0f59SJohn Muir }
1404451d0f59SJohn Muir dput(entry);
14053b463ae0SJohn Muir
14063b463ae0SJohn Muir unlock:
14075955102cSAl Viro inode_unlock(parent);
14083b463ae0SJohn Muir iput(parent);
14093b463ae0SJohn Muir return err;
14103b463ae0SJohn Muir }
14113b463ae0SJohn Muir
fuse_permissible_uidgid(struct fuse_conn * fc)1412b1387777SDave Marchevsky static inline bool fuse_permissible_uidgid(struct fuse_conn *fc)
1413b1387777SDave Marchevsky {
1414b1387777SDave Marchevsky const struct cred *cred = current_cred();
1415b1387777SDave Marchevsky
1416b1387777SDave Marchevsky return (uid_eq(cred->euid, fc->user_id) &&
1417b1387777SDave Marchevsky uid_eq(cred->suid, fc->user_id) &&
1418b1387777SDave Marchevsky uid_eq(cred->uid, fc->user_id) &&
1419b1387777SDave Marchevsky gid_eq(cred->egid, fc->group_id) &&
1420b1387777SDave Marchevsky gid_eq(cred->sgid, fc->group_id) &&
1421b1387777SDave Marchevsky gid_eq(cred->gid, fc->group_id));
1422b1387777SDave Marchevsky }
1423b1387777SDave Marchevsky
142487729a55SMiklos Szeredi /*
142587729a55SMiklos Szeredi * Calling into a user-controlled filesystem gives the filesystem
1426c2132c1bSAnatol Pomozov * daemon ptrace-like capabilities over the current process. This
142787729a55SMiklos Szeredi * means, that the filesystem daemon is able to record the exact
142887729a55SMiklos Szeredi * filesystem operations performed, and can also control the behavior
142987729a55SMiklos Szeredi * of the requester process in otherwise impossible ways. For example
143087729a55SMiklos Szeredi * it can delay the operation for arbitrary length of time allowing
143187729a55SMiklos Szeredi * DoS against the requester.
143287729a55SMiklos Szeredi *
143387729a55SMiklos Szeredi * For this reason only those processes can call into the filesystem,
143487729a55SMiklos Szeredi * for which the owner of the mount has ptrace privilege. This
143587729a55SMiklos Szeredi * excludes processes started by other users, suid or sgid processes.
143687729a55SMiklos Szeredi */
fuse_allow_current_process(struct fuse_conn * fc)1437b1387777SDave Marchevsky bool fuse_allow_current_process(struct fuse_conn *fc)
143887729a55SMiklos Szeredi {
1439b1387777SDave Marchevsky bool allow;
14409ccf47b2SDave Marchevsky
144129433a29SMiklos Szeredi if (fc->allow_other)
1442b1387777SDave Marchevsky allow = current_in_userns(fc->user_ns);
1443b1387777SDave Marchevsky else
1444b1387777SDave Marchevsky allow = fuse_permissible_uidgid(fc);
144587729a55SMiklos Szeredi
1446b1387777SDave Marchevsky if (!allow && allow_sys_admin_access && capable(CAP_SYS_ADMIN))
1447b1387777SDave Marchevsky allow = true;
144887729a55SMiklos Szeredi
1449b1387777SDave Marchevsky return allow;
145087729a55SMiklos Szeredi }
145187729a55SMiklos Szeredi
fuse_access(struct inode * inode,int mask)145231d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask)
145331d40d74SMiklos Szeredi {
1454fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode);
14557078187aSMiklos Szeredi FUSE_ARGS(args);
145631d40d74SMiklos Szeredi struct fuse_access_in inarg;
145731d40d74SMiklos Szeredi int err;
145831d40d74SMiklos Szeredi
1459698fa1d1SMiklos Szeredi BUG_ON(mask & MAY_NOT_BLOCK);
1460698fa1d1SMiklos Szeredi
1461fcee216bSMax Reitz if (fm->fc->no_access)
146231d40d74SMiklos Szeredi return 0;
146331d40d74SMiklos Szeredi
146431d40d74SMiklos Szeredi memset(&inarg, 0, sizeof(inarg));
1465e6305c43SAl Viro inarg.mask = mask & (MAY_READ | MAY_WRITE | MAY_EXEC);
1466d5b48543SMiklos Szeredi args.opcode = FUSE_ACCESS;
1467d5b48543SMiklos Szeredi args.nodeid = get_node_id(inode);
1468d5b48543SMiklos Szeredi args.in_numargs = 1;
1469d5b48543SMiklos Szeredi args.in_args[0].size = sizeof(inarg);
1470d5b48543SMiklos Szeredi args.in_args[0].value = &inarg;
1471fcee216bSMax Reitz err = fuse_simple_request(fm, &args);
147231d40d74SMiklos Szeredi if (err == -ENOSYS) {
1473fcee216bSMax Reitz fm->fc->no_access = 1;
147431d40d74SMiklos Szeredi err = 0;
147531d40d74SMiklos Szeredi }
147631d40d74SMiklos Szeredi return err;
147731d40d74SMiklos Szeredi }
147831d40d74SMiklos Szeredi
fuse_perm_getattr(struct inode * inode,int mask)147910556cb2SAl Viro static int fuse_perm_getattr(struct inode *inode, int mask)
148019690ddbSMiklos Szeredi {
148110556cb2SAl Viro if (mask & MAY_NOT_BLOCK)
148219690ddbSMiklos Szeredi return -ECHILD;
148319690ddbSMiklos Szeredi
148460bcc88aSSeth Forshee forget_all_cached_acls(inode);
148519690ddbSMiklos Szeredi return fuse_do_getattr(inode, NULL, NULL);
148619690ddbSMiklos Szeredi }
148719690ddbSMiklos Szeredi
14886f9f1180SMiklos Szeredi /*
14896f9f1180SMiklos Szeredi * Check permission. The two basic access models of FUSE are:
14906f9f1180SMiklos Szeredi *
14916f9f1180SMiklos Szeredi * 1) Local access checking ('default_permissions' mount option) based
14926f9f1180SMiklos Szeredi * on file mode. This is the plain old disk filesystem permission
14936f9f1180SMiklos Szeredi * modell.
14946f9f1180SMiklos Szeredi *
14956f9f1180SMiklos Szeredi * 2) "Remote" access checking, where server is responsible for
14966f9f1180SMiklos Szeredi * checking permission in each inode operation. An exception to this
14976f9f1180SMiklos Szeredi * is if ->permission() was invoked from sys_access() in which case an
14986f9f1180SMiklos Szeredi * access request is sent. Execute permission is still checked
14996f9f1180SMiklos Szeredi * locally based on file mode.
15006f9f1180SMiklos Szeredi */
fuse_permission(struct mnt_idmap * idmap,struct inode * inode,int mask)15014609e1f1SChristian Brauner static int fuse_permission(struct mnt_idmap *idmap,
1502549c7297SChristian Brauner struct inode *inode, int mask)
1503e5e5558eSMiklos Szeredi {
1504e5e5558eSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode);
1505244f6385SMiklos Szeredi bool refreshed = false;
1506244f6385SMiklos Szeredi int err = 0;
1507e5e5558eSMiklos Szeredi
15085d069dbeSMiklos Szeredi if (fuse_is_bad(inode))
15095d069dbeSMiklos Szeredi return -EIO;
15105d069dbeSMiklos Szeredi
1511c2132c1bSAnatol Pomozov if (!fuse_allow_current_process(fc))
1512e5e5558eSMiklos Szeredi return -EACCES;
1513244f6385SMiklos Szeredi
1514244f6385SMiklos Szeredi /*
1515e8e96157SMiklos Szeredi * If attributes are needed, refresh them before proceeding
1516244f6385SMiklos Szeredi */
151729433a29SMiklos Szeredi if (fc->default_permissions ||
1518e8e96157SMiklos Szeredi ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) {
151919690ddbSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode);
1520d233c7ddSMiklos Szeredi u32 perm_mask = STATX_MODE | STATX_UID | STATX_GID;
152119690ddbSMiklos Szeredi
1522d233c7ddSMiklos Szeredi if (perm_mask & READ_ONCE(fi->inval_mask) ||
1523d233c7ddSMiklos Szeredi time_before64(fi->i_time, get_jiffies_64())) {
152419690ddbSMiklos Szeredi refreshed = true;
152519690ddbSMiklos Szeredi
152610556cb2SAl Viro err = fuse_perm_getattr(inode, mask);
1527244f6385SMiklos Szeredi if (err)
1528244f6385SMiklos Szeredi return err;
15291fb69e78SMiklos Szeredi }
153019690ddbSMiklos Szeredi }
1531244f6385SMiklos Szeredi
153229433a29SMiklos Szeredi if (fc->default_permissions) {
15334609e1f1SChristian Brauner err = generic_permission(&nop_mnt_idmap, inode, mask);
15341e9a4ed9SMiklos Szeredi
15351e9a4ed9SMiklos Szeredi /* If permission is denied, try to refresh file
15361e9a4ed9SMiklos Szeredi attributes. This is also needed, because the root
15371e9a4ed9SMiklos Szeredi node will at first have no permissions */
1538244f6385SMiklos Szeredi if (err == -EACCES && !refreshed) {
153910556cb2SAl Viro err = fuse_perm_getattr(inode, mask);
15401e9a4ed9SMiklos Szeredi if (!err)
15414609e1f1SChristian Brauner err = generic_permission(&nop_mnt_idmap,
154247291baaSChristian Brauner inode, mask);
15431e9a4ed9SMiklos Szeredi }
15441e9a4ed9SMiklos Szeredi
15456f9f1180SMiklos Szeredi /* Note: the opposite of the above test does not
15466f9f1180SMiklos Szeredi exist. So if permissions are revoked this won't be
15476f9f1180SMiklos Szeredi noticed immediately, only after the attribute
15486f9f1180SMiklos Szeredi timeout has expired */
15499cfcac81SEric Paris } else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
1550e8e96157SMiklos Szeredi err = fuse_access(inode, mask);
1551e8e96157SMiklos Szeredi } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
1552e8e96157SMiklos Szeredi if (!(inode->i_mode & S_IXUGO)) {
1553e8e96157SMiklos Szeredi if (refreshed)
1554e5e5558eSMiklos Szeredi return -EACCES;
155531d40d74SMiklos Szeredi
155610556cb2SAl Viro err = fuse_perm_getattr(inode, mask);
1557e8e96157SMiklos Szeredi if (!err && !(inode->i_mode & S_IXUGO))
1558e8e96157SMiklos Szeredi return -EACCES;
1559e8e96157SMiklos Szeredi }
1560e5e5558eSMiklos Szeredi }
1561244f6385SMiklos Szeredi return err;
1562e5e5558eSMiklos Szeredi }
1563e5e5558eSMiklos Szeredi
fuse_readlink_page(struct inode * inode,struct page * page)15645571f1e6SDan Schatzberg static int fuse_readlink_page(struct inode *inode, struct page *page)
1565e5e5558eSMiklos Szeredi {
1566fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode);
15674c29afecSMiklos Szeredi struct fuse_page_desc desc = { .length = PAGE_SIZE - 1 };
15684c29afecSMiklos Szeredi struct fuse_args_pages ap = {
15694c29afecSMiklos Szeredi .num_pages = 1,
15704c29afecSMiklos Szeredi .pages = &page,
15714c29afecSMiklos Szeredi .descs = &desc,
15724c29afecSMiklos Szeredi };
15734c29afecSMiklos Szeredi char *link;
15744c29afecSMiklos Szeredi ssize_t res;
1575e5e5558eSMiklos Szeredi
15764c29afecSMiklos Szeredi ap.args.opcode = FUSE_READLINK;
15774c29afecSMiklos Szeredi ap.args.nodeid = get_node_id(inode);
15784c29afecSMiklos Szeredi ap.args.out_pages = true;
15794c29afecSMiklos Szeredi ap.args.out_argvar = true;
15804c29afecSMiklos Szeredi ap.args.page_zeroing = true;
15814c29afecSMiklos Szeredi ap.args.out_numargs = 1;
15824c29afecSMiklos Szeredi ap.args.out_args[0].size = desc.length;
1583fcee216bSMax Reitz res = fuse_simple_request(fm, &ap.args);
15846b255391SAl Viro
1585451418fcSAndrew Gallagher fuse_invalidate_atime(inode);
15865571f1e6SDan Schatzberg
15874c29afecSMiklos Szeredi if (res < 0)
15884c29afecSMiklos Szeredi return res;
15894c29afecSMiklos Szeredi
15904c29afecSMiklos Szeredi if (WARN_ON(res >= PAGE_SIZE))
15914c29afecSMiklos Szeredi return -EIO;
15924c29afecSMiklos Szeredi
15934c29afecSMiklos Szeredi link = page_address(page);
15944c29afecSMiklos Szeredi link[res] = '\0';
15954c29afecSMiklos Szeredi
15964c29afecSMiklos Szeredi return 0;
15975571f1e6SDan Schatzberg }
15985571f1e6SDan Schatzberg
fuse_get_link(struct dentry * dentry,struct inode * inode,struct delayed_call * callback)15995571f1e6SDan Schatzberg static const char *fuse_get_link(struct dentry *dentry, struct inode *inode,
16005571f1e6SDan Schatzberg struct delayed_call *callback)
16015571f1e6SDan Schatzberg {
16025571f1e6SDan Schatzberg struct fuse_conn *fc = get_fuse_conn(inode);
16035571f1e6SDan Schatzberg struct page *page;
16045571f1e6SDan Schatzberg int err;
16055571f1e6SDan Schatzberg
16065571f1e6SDan Schatzberg err = -EIO;
16075d069dbeSMiklos Szeredi if (fuse_is_bad(inode))
16085571f1e6SDan Schatzberg goto out_err;
16095571f1e6SDan Schatzberg
16105571f1e6SDan Schatzberg if (fc->cache_symlinks)
16115571f1e6SDan Schatzberg return page_get_link(dentry, inode, callback);
16125571f1e6SDan Schatzberg
16135571f1e6SDan Schatzberg err = -ECHILD;
16145571f1e6SDan Schatzberg if (!dentry)
16155571f1e6SDan Schatzberg goto out_err;
16165571f1e6SDan Schatzberg
16175571f1e6SDan Schatzberg page = alloc_page(GFP_KERNEL);
16185571f1e6SDan Schatzberg err = -ENOMEM;
16195571f1e6SDan Schatzberg if (!page)
16205571f1e6SDan Schatzberg goto out_err;
16215571f1e6SDan Schatzberg
16225571f1e6SDan Schatzberg err = fuse_readlink_page(inode, page);
16235571f1e6SDan Schatzberg if (err) {
16245571f1e6SDan Schatzberg __free_page(page);
16255571f1e6SDan Schatzberg goto out_err;
16265571f1e6SDan Schatzberg }
16275571f1e6SDan Schatzberg
16285571f1e6SDan Schatzberg set_delayed_call(callback, page_put_link, page);
16295571f1e6SDan Schatzberg
16305571f1e6SDan Schatzberg return page_address(page);
16315571f1e6SDan Schatzberg
16325571f1e6SDan Schatzberg out_err:
16335571f1e6SDan Schatzberg return ERR_PTR(err);
1634e5e5558eSMiklos Szeredi }
1635e5e5558eSMiklos Szeredi
fuse_dir_open(struct inode * inode,struct file * file)1636e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file)
1637e5e5558eSMiklos Szeredi {
163891fe96b4SMiklos Szeredi return fuse_open_common(inode, file, true);
1639e5e5558eSMiklos Szeredi }
1640e5e5558eSMiklos Szeredi
fuse_dir_release(struct inode * inode,struct file * file)1641e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file)
1642e5e5558eSMiklos Szeredi {
16432e64ff15SChad Austin fuse_release_common(file, true);
16448b0797a4SMiklos Szeredi
16458b0797a4SMiklos Szeredi return 0;
1646e5e5558eSMiklos Szeredi }
1647e5e5558eSMiklos Szeredi
fuse_dir_fsync(struct file * file,loff_t start,loff_t end,int datasync)164802c24a82SJosef Bacik static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end,
164902c24a82SJosef Bacik int datasync)
165082547981SMiklos Szeredi {
1651a9c2d1e8SMiklos Szeredi struct inode *inode = file->f_mapping->host;
1652a9c2d1e8SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode);
1653a9c2d1e8SMiklos Szeredi int err;
1654a9c2d1e8SMiklos Szeredi
16555d069dbeSMiklos Szeredi if (fuse_is_bad(inode))
1656a9c2d1e8SMiklos Szeredi return -EIO;
1657a9c2d1e8SMiklos Szeredi
1658a9c2d1e8SMiklos Szeredi if (fc->no_fsyncdir)
1659a9c2d1e8SMiklos Szeredi return 0;
1660a9c2d1e8SMiklos Szeredi
1661a9c2d1e8SMiklos Szeredi inode_lock(inode);
1662a9c2d1e8SMiklos Szeredi err = fuse_fsync_common(file, start, end, datasync, FUSE_FSYNCDIR);
1663a9c2d1e8SMiklos Szeredi if (err == -ENOSYS) {
1664a9c2d1e8SMiklos Szeredi fc->no_fsyncdir = 1;
1665a9c2d1e8SMiklos Szeredi err = 0;
1666a9c2d1e8SMiklos Szeredi }
1667a9c2d1e8SMiklos Szeredi inode_unlock(inode);
1668a9c2d1e8SMiklos Szeredi
1669a9c2d1e8SMiklos Szeredi return err;
167082547981SMiklos Szeredi }
167182547981SMiklos Szeredi
fuse_dir_ioctl(struct file * file,unsigned int cmd,unsigned long arg)1672b18da0c5SMiklos Szeredi static long fuse_dir_ioctl(struct file *file, unsigned int cmd,
1673b18da0c5SMiklos Szeredi unsigned long arg)
1674b18da0c5SMiklos Szeredi {
1675b18da0c5SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host);
1676b18da0c5SMiklos Szeredi
1677b18da0c5SMiklos Szeredi /* FUSE_IOCTL_DIR only supported for API version >= 7.18 */
1678b18da0c5SMiklos Szeredi if (fc->minor < 18)
1679b18da0c5SMiklos Szeredi return -ENOTTY;
1680b18da0c5SMiklos Szeredi
1681b18da0c5SMiklos Szeredi return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_DIR);
1682b18da0c5SMiklos Szeredi }
1683b18da0c5SMiklos Szeredi
fuse_dir_compat_ioctl(struct file * file,unsigned int cmd,unsigned long arg)1684b18da0c5SMiklos Szeredi static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd,
1685b18da0c5SMiklos Szeredi unsigned long arg)
1686b18da0c5SMiklos Szeredi {
1687b18da0c5SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host);
1688b18da0c5SMiklos Szeredi
1689b18da0c5SMiklos Szeredi if (fc->minor < 18)
1690b18da0c5SMiklos Szeredi return -ENOTTY;
1691b18da0c5SMiklos Szeredi
1692b18da0c5SMiklos Szeredi return fuse_ioctl_common(file, cmd, arg,
1693b18da0c5SMiklos Szeredi FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR);
1694b18da0c5SMiklos Szeredi }
1695b18da0c5SMiklos Szeredi
update_mtime(unsigned ivalid,bool trust_local_mtime)1696b0aa7606SMaxim Patlasov static bool update_mtime(unsigned ivalid, bool trust_local_mtime)
169717637cbaSMiklos Szeredi {
169817637cbaSMiklos Szeredi /* Always update if mtime is explicitly set */
169917637cbaSMiklos Szeredi if (ivalid & ATTR_MTIME_SET)
170017637cbaSMiklos Szeredi return true;
170117637cbaSMiklos Szeredi
1702b0aa7606SMaxim Patlasov /* Or if kernel i_mtime is the official one */
1703b0aa7606SMaxim Patlasov if (trust_local_mtime)
1704b0aa7606SMaxim Patlasov return true;
1705b0aa7606SMaxim Patlasov
170617637cbaSMiklos Szeredi /* If it's an open(O_TRUNC) or an ftruncate(), don't update */
170717637cbaSMiklos Szeredi if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE)))
170817637cbaSMiklos Szeredi return false;
170917637cbaSMiklos Szeredi
171017637cbaSMiklos Szeredi /* In all other cases update */
171117637cbaSMiklos Szeredi return true;
171217637cbaSMiklos Szeredi }
171317637cbaSMiklos Szeredi
iattr_to_fattr(struct fuse_conn * fc,struct iattr * iattr,struct fuse_setattr_in * arg,bool trust_local_cmtime)17148cb08329SEric W. Biederman static void iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr,
17158cb08329SEric W. Biederman struct fuse_setattr_in *arg, bool trust_local_cmtime)
17169e6268dbSMiklos Szeredi {
17179e6268dbSMiklos Szeredi unsigned ivalid = iattr->ia_valid;
17189e6268dbSMiklos Szeredi
17199e6268dbSMiklos Szeredi if (ivalid & ATTR_MODE)
1720befc649cSMiklos Szeredi arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
17219e6268dbSMiklos Szeredi if (ivalid & ATTR_UID)
17228cb08329SEric W. Biederman arg->valid |= FATTR_UID, arg->uid = from_kuid(fc->user_ns, iattr->ia_uid);
17239e6268dbSMiklos Szeredi if (ivalid & ATTR_GID)
17248cb08329SEric W. Biederman arg->valid |= FATTR_GID, arg->gid = from_kgid(fc->user_ns, iattr->ia_gid);
17259e6268dbSMiklos Szeredi if (ivalid & ATTR_SIZE)
1726befc649cSMiklos Szeredi arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
172717637cbaSMiklos Szeredi if (ivalid & ATTR_ATIME) {
172817637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME;
1729befc649cSMiklos Szeredi arg->atime = iattr->ia_atime.tv_sec;
173017637cbaSMiklos Szeredi arg->atimensec = iattr->ia_atime.tv_nsec;
173117637cbaSMiklos Szeredi if (!(ivalid & ATTR_ATIME_SET))
173217637cbaSMiklos Szeredi arg->valid |= FATTR_ATIME_NOW;
173317637cbaSMiklos Szeredi }
17343ad22c62SMaxim Patlasov if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_cmtime)) {
173517637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME;
1736befc649cSMiklos Szeredi arg->mtime = iattr->ia_mtime.tv_sec;
173717637cbaSMiklos Szeredi arg->mtimensec = iattr->ia_mtime.tv_nsec;
17383ad22c62SMaxim Patlasov if (!(ivalid & ATTR_MTIME_SET) && !trust_local_cmtime)
173917637cbaSMiklos Szeredi arg->valid |= FATTR_MTIME_NOW;
17409e6268dbSMiklos Szeredi }
17413ad22c62SMaxim Patlasov if ((ivalid & ATTR_CTIME) && trust_local_cmtime) {
17423ad22c62SMaxim Patlasov arg->valid |= FATTR_CTIME;
17433ad22c62SMaxim Patlasov arg->ctime = iattr->ia_ctime.tv_sec;
17443ad22c62SMaxim Patlasov arg->ctimensec = iattr->ia_ctime.tv_nsec;
17453ad22c62SMaxim Patlasov }
17469e6268dbSMiklos Szeredi }
17479e6268dbSMiklos Szeredi
17486f9f1180SMiklos Szeredi /*
17493be5a52bSMiklos Szeredi * Prevent concurrent writepages on inode
17503be5a52bSMiklos Szeredi *
17513be5a52bSMiklos Szeredi * This is done by adding a negative bias to the inode write counter
17523be5a52bSMiklos Szeredi * and waiting for all pending writes to finish.
17533be5a52bSMiklos Szeredi */
fuse_set_nowrite(struct inode * inode)17543be5a52bSMiklos Szeredi void fuse_set_nowrite(struct inode *inode)
17553be5a52bSMiklos Szeredi {
17563be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode);
17573be5a52bSMiklos Szeredi
17585955102cSAl Viro BUG_ON(!inode_is_locked(inode));
17593be5a52bSMiklos Szeredi
1760f15ecfefSKirill Tkhai spin_lock(&fi->lock);
17613be5a52bSMiklos Szeredi BUG_ON(fi->writectr < 0);
17623be5a52bSMiklos Szeredi fi->writectr += FUSE_NOWRITE;
1763f15ecfefSKirill Tkhai spin_unlock(&fi->lock);
17643be5a52bSMiklos Szeredi wait_event(fi->page_waitq, fi->writectr == FUSE_NOWRITE);
17653be5a52bSMiklos Szeredi }
17663be5a52bSMiklos Szeredi
17673be5a52bSMiklos Szeredi /*
17683be5a52bSMiklos Szeredi * Allow writepages on inode
17693be5a52bSMiklos Szeredi *
17703be5a52bSMiklos Szeredi * Remove the bias from the writecounter and send any queued
17713be5a52bSMiklos Szeredi * writepages.
17723be5a52bSMiklos Szeredi */
__fuse_release_nowrite(struct inode * inode)17733be5a52bSMiklos Szeredi static void __fuse_release_nowrite(struct inode *inode)
17743be5a52bSMiklos Szeredi {
17753be5a52bSMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode);
17763be5a52bSMiklos Szeredi
17773be5a52bSMiklos Szeredi BUG_ON(fi->writectr != FUSE_NOWRITE);
17783be5a52bSMiklos Szeredi fi->writectr = 0;
17793be5a52bSMiklos Szeredi fuse_flush_writepages(inode);
17803be5a52bSMiklos Szeredi }
17813be5a52bSMiklos Szeredi
fuse_release_nowrite(struct inode * inode)17823be5a52bSMiklos Szeredi void fuse_release_nowrite(struct inode *inode)
17833be5a52bSMiklos Szeredi {
1784f15ecfefSKirill Tkhai struct fuse_inode *fi = get_fuse_inode(inode);
17853be5a52bSMiklos Szeredi
1786f15ecfefSKirill Tkhai spin_lock(&fi->lock);
17873be5a52bSMiklos Szeredi __fuse_release_nowrite(inode);
1788f15ecfefSKirill Tkhai spin_unlock(&fi->lock);
17893be5a52bSMiklos Szeredi }
17903be5a52bSMiklos Szeredi
fuse_setattr_fill(struct fuse_conn * fc,struct fuse_args * args,struct inode * inode,struct fuse_setattr_in * inarg_p,struct fuse_attr_out * outarg_p)17917078187aSMiklos Szeredi static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_args *args,
1792b0aa7606SMaxim Patlasov struct inode *inode,
1793b0aa7606SMaxim Patlasov struct fuse_setattr_in *inarg_p,
1794b0aa7606SMaxim Patlasov struct fuse_attr_out *outarg_p)
1795b0aa7606SMaxim Patlasov {
1796d5b48543SMiklos Szeredi args->opcode = FUSE_SETATTR;
1797d5b48543SMiklos Szeredi args->nodeid = get_node_id(inode);
1798d5b48543SMiklos Szeredi args->in_numargs = 1;
1799d5b48543SMiklos Szeredi args->in_args[0].size = sizeof(*inarg_p);
1800d5b48543SMiklos Szeredi args->in_args[0].value = inarg_p;
1801d5b48543SMiklos Szeredi args->out_numargs = 1;
1802d5b48543SMiklos Szeredi args->out_args[0].size = sizeof(*outarg_p);
1803d5b48543SMiklos Szeredi args->out_args[0].value = outarg_p;
1804b0aa7606SMaxim Patlasov }
1805b0aa7606SMaxim Patlasov
1806b0aa7606SMaxim Patlasov /*
1807b0aa7606SMaxim Patlasov * Flush inode->i_mtime to the server
1808b0aa7606SMaxim Patlasov */
fuse_flush_times(struct inode * inode,struct fuse_file * ff)1809ab9e13f7SMaxim Patlasov int fuse_flush_times(struct inode *inode, struct fuse_file *ff)
1810b0aa7606SMaxim Patlasov {
1811fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode);
18127078187aSMiklos Szeredi FUSE_ARGS(args);
1813b0aa7606SMaxim Patlasov struct fuse_setattr_in inarg;
1814b0aa7606SMaxim Patlasov struct fuse_attr_out outarg;
1815b0aa7606SMaxim Patlasov
1816b0aa7606SMaxim Patlasov memset(&inarg, 0, sizeof(inarg));
1817b0aa7606SMaxim Patlasov memset(&outarg, 0, sizeof(outarg));
1818b0aa7606SMaxim Patlasov
1819ab9e13f7SMaxim Patlasov inarg.valid = FATTR_MTIME;
1820b0aa7606SMaxim Patlasov inarg.mtime = inode->i_mtime.tv_sec;
1821b0aa7606SMaxim Patlasov inarg.mtimensec = inode->i_mtime.tv_nsec;
1822fcee216bSMax Reitz if (fm->fc->minor >= 23) {
1823ab9e13f7SMaxim Patlasov inarg.valid |= FATTR_CTIME;
1824ceb2d5e9SJeff Layton inarg.ctime = inode_get_ctime(inode).tv_sec;
1825ceb2d5e9SJeff Layton inarg.ctimensec = inode_get_ctime(inode).tv_nsec;
1826ab9e13f7SMaxim Patlasov }
18271e18bda8SMiklos Szeredi if (ff) {
18281e18bda8SMiklos Szeredi inarg.valid |= FATTR_FH;
18291e18bda8SMiklos Szeredi inarg.fh = ff->fh;
18301e18bda8SMiklos Szeredi }
1831fcee216bSMax Reitz fuse_setattr_fill(fm->fc, &args, inode, &inarg, &outarg);
1832b0aa7606SMaxim Patlasov
1833fcee216bSMax Reitz return fuse_simple_request(fm, &args);
1834b0aa7606SMaxim Patlasov }
1835b0aa7606SMaxim Patlasov
18363be5a52bSMiklos Szeredi /*
18376f9f1180SMiklos Szeredi * Set attributes, and at the same time refresh them.
18386f9f1180SMiklos Szeredi *
18396f9f1180SMiklos Szeredi * Truncation is slightly complicated, because the 'truncate' request
18406f9f1180SMiklos Szeredi * may fail, in which case we don't want to touch the mapping.
18419ffbb916SMiklos Szeredi * vmtruncate() doesn't allow for this case, so do the rlimit checking
18429ffbb916SMiklos Szeredi * and the actual truncation by hand.
18436f9f1180SMiklos Szeredi */
fuse_do_setattr(struct dentry * dentry,struct iattr * attr,struct file * file)184462490330SJan Kara int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
184549d4914fSMiklos Szeredi struct file *file)
18469e6268dbSMiklos Szeredi {
184762490330SJan Kara struct inode *inode = d_inode(dentry);
1848fcee216bSMax Reitz struct fuse_mount *fm = get_fuse_mount(inode);
1849fcee216bSMax Reitz struct fuse_conn *fc = fm->fc;
185006a7c3c2SMaxim Patlasov struct fuse_inode *fi = get_fuse_inode(inode);
18518bcbbe9cSJan Kara struct address_space *mapping = inode->i_mapping;
18527078187aSMiklos Szeredi FUSE_ARGS(args);
18539e6268dbSMiklos Szeredi struct fuse_setattr_in inarg;
18549e6268dbSMiklos Szeredi struct fuse_attr_out outarg;
18553be5a52bSMiklos Szeredi bool is_truncate = false;
1856c15016b7SMiklos Szeredi bool is_wb = fc->writeback_cache && S_ISREG(inode->i_mode);
18573be5a52bSMiklos Szeredi loff_t oldsize;
18589e6268dbSMiklos Szeredi int err;
1859c15016b7SMiklos Szeredi bool trust_local_cmtime = is_wb;
18606ae330caSVivek Goyal bool fault_blocked = false;
18619e6268dbSMiklos Szeredi
186229433a29SMiklos Szeredi if (!fc->default_permissions)
1863db78b877SChristoph Hellwig attr->ia_valid |= ATTR_FORCE;
1864db78b877SChristoph Hellwig
1865c1632a0fSChristian Brauner err = setattr_prepare(&nop_mnt_idmap, dentry, attr);
18661e9a4ed9SMiklos Szeredi if (err)
18671e9a4ed9SMiklos Szeredi return err;
18681e9a4ed9SMiklos Szeredi
18696ae330caSVivek Goyal if (attr->ia_valid & ATTR_SIZE) {
18706ae330caSVivek Goyal if (WARN_ON(!S_ISREG(inode->i_mode)))
18716ae330caSVivek Goyal return -EIO;
18726ae330caSVivek Goyal is_truncate = true;
18736ae330caSVivek Goyal }
18746ae330caSVivek Goyal
18756ae330caSVivek Goyal if (FUSE_IS_DAX(inode) && is_truncate) {
18768bcbbe9cSJan Kara filemap_invalidate_lock(mapping);
18776ae330caSVivek Goyal fault_blocked = true;
18786ae330caSVivek Goyal err = fuse_dax_break_layouts(inode, 0, 0);
18796ae330caSVivek Goyal if (err) {
18808bcbbe9cSJan Kara filemap_invalidate_unlock(mapping);
18816ae330caSVivek Goyal return err;
18826ae330caSVivek Goyal }
18836ae330caSVivek Goyal }
18846ae330caSVivek Goyal
18858d56adddSMiklos Szeredi if (attr->ia_valid & ATTR_OPEN) {
1886df0e91d4SMiklos Szeredi /* This is coming from open(..., ... | O_TRUNC); */
1887df0e91d4SMiklos Szeredi WARN_ON(!(attr->ia_valid & ATTR_SIZE));
1888df0e91d4SMiklos Szeredi WARN_ON(attr->ia_size != 0);
1889df0e91d4SMiklos Szeredi if (fc->atomic_o_trunc) {
1890df0e91d4SMiklos Szeredi /*
1891df0e91d4SMiklos Szeredi * No need to send request to userspace, since actual
1892df0e91d4SMiklos Szeredi * truncation has already been done by OPEN. But still
1893df0e91d4SMiklos Szeredi * need to truncate page cache.
1894df0e91d4SMiklos Szeredi */
1895df0e91d4SMiklos Szeredi i_size_write(inode, 0);
1896df0e91d4SMiklos Szeredi truncate_pagecache(inode, 0);
18976ae330caSVivek Goyal goto out;
1898df0e91d4SMiklos Szeredi }
18998d56adddSMiklos Szeredi file = NULL;
19008d56adddSMiklos Szeredi }
19016ff958edSMiklos Szeredi
1902b24e7598SMiklos Szeredi /* Flush dirty data/metadata before non-truncate SETATTR */
1903c15016b7SMiklos Szeredi if (is_wb &&
1904b24e7598SMiklos Szeredi attr->ia_valid &
1905b24e7598SMiklos Szeredi (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_MTIME_SET |
1906b24e7598SMiklos Szeredi ATTR_TIMES_SET)) {
1907b24e7598SMiklos Szeredi err = write_inode_now(inode, true);
1908b24e7598SMiklos Szeredi if (err)
1909b24e7598SMiklos Szeredi return err;
1910b24e7598SMiklos Szeredi
1911b24e7598SMiklos Szeredi fuse_set_nowrite(inode);
1912b24e7598SMiklos Szeredi fuse_release_nowrite(inode);
1913b24e7598SMiklos Szeredi }
1914b24e7598SMiklos Szeredi
191506a7c3c2SMaxim Patlasov if (is_truncate) {
19163be5a52bSMiklos Szeredi fuse_set_nowrite(inode);
191706a7c3c2SMaxim Patlasov set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
19183ad22c62SMaxim Patlasov if (trust_local_cmtime && attr->ia_size != inode->i_size)
19193ad22c62SMaxim Patlasov attr->ia_valid |= ATTR_MTIME | ATTR_CTIME;
192006a7c3c2SMaxim Patlasov }
19213be5a52bSMiklos Szeredi
19229e6268dbSMiklos Szeredi memset(&inarg, 0, sizeof(inarg));
19230e9663eeSMiklos Szeredi memset(&outarg, 0, sizeof(outarg));
19248cb08329SEric W. Biederman iattr_to_fattr(fc, attr, &inarg, trust_local_cmtime);
192549d4914fSMiklos Szeredi if (file) {
192649d4914fSMiklos Szeredi struct fuse_file *ff = file->private_data;
192749d4914fSMiklos Szeredi inarg.valid |= FATTR_FH;
192849d4914fSMiklos Szeredi inarg.fh = ff->fh;
192949d4914fSMiklos Szeredi }
193031792161SVivek Goyal
193131792161SVivek Goyal /* Kill suid/sgid for non-directory chown unconditionally */
193231792161SVivek Goyal if (fc->handle_killpriv_v2 && !S_ISDIR(inode->i_mode) &&
193331792161SVivek Goyal attr->ia_valid & (ATTR_UID | ATTR_GID))
193431792161SVivek Goyal inarg.valid |= FATTR_KILL_SUIDGID;
193531792161SVivek Goyal
1936f3332114SMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) {
1937f3332114SMiklos Szeredi /* For mandatory locking in truncate */
1938f3332114SMiklos Szeredi inarg.valid |= FATTR_LOCKOWNER;
1939f3332114SMiklos Szeredi inarg.lock_owner = fuse_lock_owner_id(fc, current->files);
194031792161SVivek Goyal
194131792161SVivek Goyal /* Kill suid/sgid for truncate only if no CAP_FSETID */
194231792161SVivek Goyal if (fc->handle_killpriv_v2 && !capable(CAP_FSETID))
194331792161SVivek Goyal inarg.valid |= FATTR_KILL_SUIDGID;
1944f3332114SMiklos Szeredi }
19457078187aSMiklos Szeredi fuse_setattr_fill(fc, &args, inode, &inarg, &outarg);
1946fcee216bSMax Reitz err = fuse_simple_request(fm, &args);
1947e00d2c2dSMiklos Szeredi if (err) {
1948e00d2c2dSMiklos Szeredi if (err == -EINTR)
1949e00d2c2dSMiklos Szeredi fuse_invalidate_attr(inode);
19503be5a52bSMiklos Szeredi goto error;
1951e00d2c2dSMiklos Szeredi }
1952e00d2c2dSMiklos Szeredi
1953eb59bd17SMiklos Szeredi if (fuse_invalid_attr(&outarg.attr) ||
19546e3e2c43SAl Viro inode_wrong_type(inode, outarg.attr.mode)) {
19555d069dbeSMiklos Szeredi fuse_make_bad(inode);
19563be5a52bSMiklos Szeredi err = -EIO;
19573be5a52bSMiklos Szeredi goto error;
19589e6268dbSMiklos Szeredi }
19599e6268dbSMiklos Szeredi
1960f15ecfefSKirill Tkhai spin_lock(&fi->lock);
1961b0aa7606SMaxim Patlasov /* the kernel maintains i_mtime locally */
19623ad22c62SMaxim Patlasov if (trust_local_cmtime) {
19633ad22c62SMaxim Patlasov if (attr->ia_valid & ATTR_MTIME)
1964b0aa7606SMaxim Patlasov inode->i_mtime = attr->ia_mtime;
19653ad22c62SMaxim Patlasov if (attr->ia_valid & ATTR_CTIME)
1966ceb2d5e9SJeff Layton inode_set_ctime_to_ts(inode, attr->ia_ctime);
19671e18bda8SMiklos Szeredi /* FIXME: clear I_DIRTY_SYNC? */
1968b0aa7606SMaxim Patlasov }
1969b0aa7606SMaxim Patlasov
1970972f4c46SMiklos Szeredi fuse_change_attributes_common(inode, &outarg.attr, NULL,
19719dc10a54SMiklos Szeredi ATTR_TIMEOUT(&outarg),
19724b52f059SMiklos Szeredi fuse_get_cache_mask(inode));
19733be5a52bSMiklos Szeredi oldsize = inode->i_size;
19748373200bSPavel Emelyanov /* see the comment in fuse_change_attributes() */
1975c15016b7SMiklos Szeredi if (!is_wb || is_truncate)
19763be5a52bSMiklos Szeredi i_size_write(inode, outarg.attr.size);
19773be5a52bSMiklos Szeredi
19783be5a52bSMiklos Szeredi if (is_truncate) {
1979f15ecfefSKirill Tkhai /* NOTE: this may release/reacquire fi->lock */
19803be5a52bSMiklos Szeredi __fuse_release_nowrite(inode);
19813be5a52bSMiklos Szeredi }
1982f15ecfefSKirill Tkhai spin_unlock(&fi->lock);
19833be5a52bSMiklos Szeredi
19843be5a52bSMiklos Szeredi /*
19853be5a52bSMiklos Szeredi * Only call invalidate_inode_pages2() after removing
19862bf06b8eSMatthew Wilcox (Oracle) * FUSE_NOWRITE, otherwise fuse_launder_folio() would deadlock.
19873be5a52bSMiklos Szeredi */
19888373200bSPavel Emelyanov if ((is_truncate || !is_wb) &&
19898373200bSPavel Emelyanov S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) {
19907caef267SKirill A. Shutemov truncate_pagecache(inode, outarg.attr.size);
19918bcbbe9cSJan Kara invalidate_inode_pages2(mapping);
19923be5a52bSMiklos Szeredi }
19933be5a52bSMiklos Szeredi
199406a7c3c2SMaxim Patlasov clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
19956ae330caSVivek Goyal out:
19966ae330caSVivek Goyal if (fault_blocked)
19978bcbbe9cSJan Kara filemap_invalidate_unlock(mapping);
19986ae330caSVivek Goyal
1999e00d2c2dSMiklos Szeredi return 0;
20003be5a52bSMiklos Szeredi
20013be5a52bSMiklos Szeredi error:
20023be5a52bSMiklos Szeredi if (is_truncate)
20033be5a52bSMiklos Szeredi fuse_release_nowrite(inode);
20043be5a52bSMiklos Szeredi
200506a7c3c2SMaxim Patlasov clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
20066ae330caSVivek Goyal
20076ae330caSVivek Goyal if (fault_blocked)
20088bcbbe9cSJan Kara filemap_invalidate_unlock(mapping);
20093be5a52bSMiklos Szeredi return err;
20109e6268dbSMiklos Szeredi }
20119e6268dbSMiklos Szeredi
fuse_setattr(struct mnt_idmap * idmap,struct dentry * entry,struct iattr * attr)2012c1632a0fSChristian Brauner static int fuse_setattr(struct mnt_idmap *idmap, struct dentry *entry,
2013549c7297SChristian Brauner struct iattr *attr)
201449d4914fSMiklos Szeredi {
20152b0143b5SDavid Howells struct inode *inode = d_inode(entry);
20165e940c1dSMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode);
2017a09f99edSMiklos Szeredi struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL;
20185e2b8828SMiklos Szeredi int ret;
2019efb9fa9eSMaxim Patlasov
20205d069dbeSMiklos Szeredi if (fuse_is_bad(inode))
20215d069dbeSMiklos Szeredi return -EIO;
20225d069dbeSMiklos Szeredi
2023efb9fa9eSMaxim Patlasov if (!fuse_allow_current_process(get_fuse_conn(inode)))
2024efb9fa9eSMaxim Patlasov return -EACCES;
2025efb9fa9eSMaxim Patlasov
2026a09f99edSMiklos Szeredi if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) {
2027a09f99edSMiklos Szeredi attr->ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID |
2028a09f99edSMiklos Szeredi ATTR_MODE);
20295e940c1dSMiklos Szeredi
2030a09f99edSMiklos Szeredi /*
20315e940c1dSMiklos Szeredi * The only sane way to reliably kill suid/sgid is to do it in
20325e940c1dSMiklos Szeredi * the userspace filesystem
20335e940c1dSMiklos Szeredi *
20345e940c1dSMiklos Szeredi * This should be done on write(), truncate() and chown().
20355e940c1dSMiklos Szeredi */
20368981bdfdSVivek Goyal if (!fc->handle_killpriv && !fc->handle_killpriv_v2) {
20375e940c1dSMiklos Szeredi /*
20385e940c1dSMiklos Szeredi * ia_mode calculation may have used stale i_mode.
20395e940c1dSMiklos Szeredi * Refresh and recalculate.
2040a09f99edSMiklos Szeredi */
2041a09f99edSMiklos Szeredi ret = fuse_do_getattr(inode, NULL, file);
2042a09f99edSMiklos Szeredi if (ret)
2043a09f99edSMiklos Szeredi return ret;
2044a09f99edSMiklos Szeredi
2045a09f99edSMiklos Szeredi attr->ia_mode = inode->i_mode;
2046c01638f5SMiklos Szeredi if (inode->i_mode & S_ISUID) {
2047a09f99edSMiklos Szeredi attr->ia_valid |= ATTR_MODE;
2048a09f99edSMiklos Szeredi attr->ia_mode &= ~S_ISUID;
2049a09f99edSMiklos Szeredi }
2050c01638f5SMiklos Szeredi if ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
2051a09f99edSMiklos Szeredi attr->ia_valid |= ATTR_MODE;
2052a09f99edSMiklos Szeredi attr->ia_mode &= ~S_ISGID;
2053a09f99edSMiklos Szeredi }
2054a09f99edSMiklos Szeredi }
20555e940c1dSMiklos Szeredi }
2056a09f99edSMiklos Szeredi if (!attr->ia_valid)
2057a09f99edSMiklos Szeredi return 0;
2058a09f99edSMiklos Szeredi
2059abb5a14fSLinus Torvalds ret = fuse_do_setattr(entry, attr, file);
20605e2b8828SMiklos Szeredi if (!ret) {
206160bcc88aSSeth Forshee /*
206260bcc88aSSeth Forshee * If filesystem supports acls it may have updated acl xattrs in
206360bcc88aSSeth Forshee * the filesystem, so forget cached acls for the inode.
206460bcc88aSSeth Forshee */
206560bcc88aSSeth Forshee if (fc->posix_acl)
206660bcc88aSSeth Forshee forget_all_cached_acls(inode);
206760bcc88aSSeth Forshee
20685e2b8828SMiklos Szeredi /* Directory mode changed, may need to revalidate access */
20695e2b8828SMiklos Szeredi if (d_is_dir(entry) && (attr->ia_valid & ATTR_MODE))
20705e2b8828SMiklos Szeredi fuse_invalidate_entry_cache(entry);
20715e2b8828SMiklos Szeredi }
20725e2b8828SMiklos Szeredi return ret;
207349d4914fSMiklos Szeredi }
207449d4914fSMiklos Szeredi
fuse_getattr(struct mnt_idmap * idmap,const struct path * path,struct kstat * stat,u32 request_mask,unsigned int flags)2075b74d24f7SChristian Brauner static int fuse_getattr(struct mnt_idmap *idmap,
2076549c7297SChristian Brauner const struct path *path, struct kstat *stat,
2077a528d35eSDavid Howells u32 request_mask, unsigned int flags)
2078e5e5558eSMiklos Szeredi {
2079a528d35eSDavid Howells struct inode *inode = d_inode(path->dentry);
2080244f6385SMiklos Szeredi struct fuse_conn *fc = get_fuse_conn(inode);
2081244f6385SMiklos Szeredi
20825d069dbeSMiklos Szeredi if (fuse_is_bad(inode))
20835d069dbeSMiklos Szeredi return -EIO;
20845d069dbeSMiklos Szeredi
20855157da2cSMiklos Szeredi if (!fuse_allow_current_process(fc)) {
20865157da2cSMiklos Szeredi if (!request_mask) {
20875157da2cSMiklos Szeredi /*
20885157da2cSMiklos Szeredi * If user explicitly requested *nothing* then don't
20895157da2cSMiklos Szeredi * error out, but return st_dev only.
20905157da2cSMiklos Szeredi */
20915157da2cSMiklos Szeredi stat->result_mask = 0;
20925157da2cSMiklos Szeredi stat->dev = inode->i_sb->s_dev;
20935157da2cSMiklos Szeredi return 0;
20945157da2cSMiklos Szeredi }
2095244f6385SMiklos Szeredi return -EACCES;
20965157da2cSMiklos Szeredi }
2097244f6385SMiklos Szeredi
20982f1e8196SMiklos Szeredi return fuse_update_get_attr(inode, NULL, stat, request_mask, flags);
2099e5e5558eSMiklos Szeredi }
2100e5e5558eSMiklos Szeredi
2101754661f1SArjan van de Ven static const struct inode_operations fuse_dir_inode_operations = {
2102e5e5558eSMiklos Szeredi .lookup = fuse_lookup,
21039e6268dbSMiklos Szeredi .mkdir = fuse_mkdir,
21049e6268dbSMiklos Szeredi .symlink = fuse_symlink,
21059e6268dbSMiklos Szeredi .unlink = fuse_unlink,
21069e6268dbSMiklos Szeredi .rmdir = fuse_rmdir,
21072773bf00SMiklos Szeredi .rename = fuse_rename2,
21089e6268dbSMiklos Szeredi .link = fuse_link,
21099e6268dbSMiklos Szeredi .setattr = fuse_setattr,
21109e6268dbSMiklos Szeredi .create = fuse_create,
2111c8ccbe03SMiklos Szeredi .atomic_open = fuse_atomic_open,
21127d375390SMiklos Szeredi .tmpfile = fuse_tmpfile,
21139e6268dbSMiklos Szeredi .mknod = fuse_mknod,
2114e5e5558eSMiklos Szeredi .permission = fuse_permission,
2115e5e5558eSMiklos Szeredi .getattr = fuse_getattr,
211692a8780eSMiklos Szeredi .listxattr = fuse_listxattr,
2117facd6105SChristian Brauner .get_inode_acl = fuse_get_inode_acl,
2118facd6105SChristian Brauner .get_acl = fuse_get_acl,
211960bcc88aSSeth Forshee .set_acl = fuse_set_acl,
212072227eacSMiklos Szeredi .fileattr_get = fuse_fileattr_get,
212172227eacSMiklos Szeredi .fileattr_set = fuse_fileattr_set,
2122e5e5558eSMiklos Szeredi };
2123e5e5558eSMiklos Szeredi
21244b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = {
2125b6aeadedSMiklos Szeredi .llseek = generic_file_llseek,
2126e5e5558eSMiklos Szeredi .read = generic_read_dir,
2127d9b3dbdcSAl Viro .iterate_shared = fuse_readdir,
2128e5e5558eSMiklos Szeredi .open = fuse_dir_open,
2129e5e5558eSMiklos Szeredi .release = fuse_dir_release,
213082547981SMiklos Szeredi .fsync = fuse_dir_fsync,
2131b18da0c5SMiklos Szeredi .unlocked_ioctl = fuse_dir_ioctl,
2132b18da0c5SMiklos Szeredi .compat_ioctl = fuse_dir_compat_ioctl,
2133e5e5558eSMiklos Szeredi };
2134e5e5558eSMiklos Szeredi
2135754661f1SArjan van de Ven static const struct inode_operations fuse_common_inode_operations = {
21369e6268dbSMiklos Szeredi .setattr = fuse_setattr,
2137e5e5558eSMiklos Szeredi .permission = fuse_permission,
2138e5e5558eSMiklos Szeredi .getattr = fuse_getattr,
213992a8780eSMiklos Szeredi .listxattr = fuse_listxattr,
2140facd6105SChristian Brauner .get_inode_acl = fuse_get_inode_acl,
2141facd6105SChristian Brauner .get_acl = fuse_get_acl,
214260bcc88aSSeth Forshee .set_acl = fuse_set_acl,
214372227eacSMiklos Szeredi .fileattr_get = fuse_fileattr_get,
214472227eacSMiklos Szeredi .fileattr_set = fuse_fileattr_set,
2145e5e5558eSMiklos Szeredi };
2146e5e5558eSMiklos Szeredi
2147754661f1SArjan van de Ven static const struct inode_operations fuse_symlink_inode_operations = {
21489e6268dbSMiklos Szeredi .setattr = fuse_setattr,
21496b255391SAl Viro .get_link = fuse_get_link,
2150e5e5558eSMiklos Szeredi .getattr = fuse_getattr,
215192a8780eSMiklos Szeredi .listxattr = fuse_listxattr,
2152e5e5558eSMiklos Szeredi };
2153e5e5558eSMiklos Szeredi
fuse_init_common(struct inode * inode)2154e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode)
2155e5e5558eSMiklos Szeredi {
2156e5e5558eSMiklos Szeredi inode->i_op = &fuse_common_inode_operations;
2157e5e5558eSMiklos Szeredi }
2158e5e5558eSMiklos Szeredi
fuse_init_dir(struct inode * inode)2159e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode)
2160e5e5558eSMiklos Szeredi {
2161ab2257e9SMiklos Szeredi struct fuse_inode *fi = get_fuse_inode(inode);
2162ab2257e9SMiklos Szeredi
2163e5e5558eSMiklos Szeredi inode->i_op = &fuse_dir_inode_operations;
2164e5e5558eSMiklos Szeredi inode->i_fop = &fuse_dir_operations;
2165ab2257e9SMiklos Szeredi
2166ab2257e9SMiklos Szeredi spin_lock_init(&fi->rdc.lock);
2167ab2257e9SMiklos Szeredi fi->rdc.cached = false;
2168ab2257e9SMiklos Szeredi fi->rdc.size = 0;
2169ab2257e9SMiklos Szeredi fi->rdc.pos = 0;
2170ab2257e9SMiklos Szeredi fi->rdc.version = 0;
2171e5e5558eSMiklos Szeredi }
2172e5e5558eSMiklos Szeredi
fuse_symlink_read_folio(struct file * null,struct folio * folio)21735efd00e4SMatthew Wilcox (Oracle) static int fuse_symlink_read_folio(struct file *null, struct folio *folio)
21745571f1e6SDan Schatzberg {
21755efd00e4SMatthew Wilcox (Oracle) int err = fuse_readlink_page(folio->mapping->host, &folio->page);
21765571f1e6SDan Schatzberg
21775571f1e6SDan Schatzberg if (!err)
21785efd00e4SMatthew Wilcox (Oracle) folio_mark_uptodate(folio);
21795571f1e6SDan Schatzberg
21805efd00e4SMatthew Wilcox (Oracle) folio_unlock(folio);
21815571f1e6SDan Schatzberg
21825571f1e6SDan Schatzberg return err;
21835571f1e6SDan Schatzberg }
21845571f1e6SDan Schatzberg
21855571f1e6SDan Schatzberg static const struct address_space_operations fuse_symlink_aops = {
21865efd00e4SMatthew Wilcox (Oracle) .read_folio = fuse_symlink_read_folio,
21875571f1e6SDan Schatzberg };
21885571f1e6SDan Schatzberg
fuse_init_symlink(struct inode * inode)2189e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode)
2190e5e5558eSMiklos Szeredi {
2191e5e5558eSMiklos Szeredi inode->i_op = &fuse_symlink_inode_operations;
21925571f1e6SDan Schatzberg inode->i_data.a_ops = &fuse_symlink_aops;
21935571f1e6SDan Schatzberg inode_nohighmem(inode);
2194e5e5558eSMiklos Szeredi }
2195