1 Subject: VFS: new fsetattr() file operation
3 From: Miklos Szeredi <mszeredi@suse.cz>
5 Add a new file operation: f_op->fsetattr(), that is invoked by
6 ftruncate, fchmod, fchown and utimensat. Fall back to i_op->setattr()
9 For the reasons why we need this, see patch adding fgetattr().
11 ftruncate() already passed the open file to the filesystem via the
12 ia_file member of struct iattr. However it is cleaner to have a
13 separate file operation for this, so remove ia_file, ATTR_FILE and
14 convert existing users: fuse and AFS.
16 Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> ---
17 Signed-off-by: John Johansen <jjohansen@suse.de> ---
22 fs/afs/inode.c | 19 +++++++++++++++----
23 fs/afs/internal.h | 1 +
24 fs/attr.c | 19 +++++++++++++++----
25 fs/fuse/dir.c | 20 +++++++++-----------
26 fs/fuse/file.c | 7 +++++++
27 fs/fuse/fuse_i.h | 4 ++++
28 fs/open.c | 20 ++++++++------------
29 fs/utimes.c | 9 +++++----
30 include/linux/fs.h | 9 ++-------
31 11 files changed, 68 insertions(+), 42 deletions(-)
35 @@ -45,6 +45,7 @@ const struct file_operations afs_dir_fil
36 .release = afs_release,
37 .readdir = afs_readdir,
39 + .fsetattr = afs_fsetattr,
42 const struct inode_operations afs_dir_inode_operations = {
45 @@ -36,6 +36,7 @@ const struct file_operations afs_file_op
49 + .fsetattr = afs_fsetattr,
52 const struct inode_operations afs_file_inode_operations = {
55 @@ -358,7 +358,8 @@ void afs_clear_inode(struct inode *inode
57 * set the attributes of an inode
59 -int afs_setattr(struct dentry *dentry, struct iattr *attr)
60 +static int afs_do_setattr(struct dentry *dentry, struct iattr *attr,
63 struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
65 @@ -380,8 +381,8 @@ int afs_setattr(struct dentry *dentry, s
66 afs_writeback_all(vnode);
69 - if (attr->ia_valid & ATTR_FILE) {
70 - key = attr->ia_file->private_data;
72 + key = file->private_data;
74 key = afs_request_key(vnode->volume->cell);
76 @@ -391,10 +392,20 @@ int afs_setattr(struct dentry *dentry, s
79 ret = afs_vnode_setattr(vnode, key, attr);
80 - if (!(attr->ia_valid & ATTR_FILE))
89 +int afs_setattr(struct dentry *dentry, struct iattr *attr)
91 + return afs_do_setattr(dentry, attr, NULL);
94 +int afs_fsetattr(struct file *file, struct iattr *attr)
96 + return afs_do_setattr(file->f_path.dentry, attr, file);
98 --- a/fs/afs/internal.h
99 +++ b/fs/afs/internal.h
100 @@ -548,6 +548,7 @@ extern void afs_zap_data(struct afs_vnod
101 extern int afs_validate(struct afs_vnode *, struct key *);
102 extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
103 extern int afs_setattr(struct dentry *, struct iattr *);
104 +extern int afs_fsetattr(struct file *, struct iattr *);
105 extern void afs_clear_inode(struct inode *);
110 @@ -100,8 +100,8 @@ int inode_setattr(struct inode * inode,
112 EXPORT_SYMBOL(inode_setattr);
114 -int notify_change(struct dentry *dentry, struct vfsmount *mnt,
115 - struct iattr *attr)
116 +int fnotify_change(struct dentry *dentry, struct vfsmount *mnt,
117 + struct iattr *attr, struct file *file)
119 struct inode *inode = dentry->d_inode;
120 mode_t mode = inode->i_mode;
121 @@ -165,8 +165,12 @@ int notify_change(struct dentry *dentry,
123 if (inode->i_op && inode->i_op->setattr) {
124 error = security_inode_setattr(dentry, mnt, attr);
126 - error = inode->i_op->setattr(dentry, attr);
128 + if (file && file->f_op && file->f_op->fsetattr)
129 + error = file->f_op->fsetattr(file, attr);
131 + error = inode->i_op->setattr(dentry, attr);
134 error = inode_change_ok(inode, attr);
136 @@ -188,5 +192,12 @@ int notify_change(struct dentry *dentry,
140 +EXPORT_SYMBOL_GPL(fnotify_change);
142 +int notify_change(struct dentry *dentry, struct vfsmount *mnt,
143 + struct iattr *attr)
145 + return fnotify_change(dentry, mnt, attr, NULL);
148 EXPORT_SYMBOL(notify_change);
151 @@ -1105,21 +1105,22 @@ static int fuse_dir_fsync(struct file *f
152 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
155 -static bool update_mtime(unsigned ivalid)
156 +static bool update_mtime(unsigned ivalid, bool have_file)
158 /* Always update if mtime is explicitly set */
159 if (ivalid & ATTR_MTIME_SET)
162 /* If it's an open(O_TRUNC) or an ftruncate(), don't update */
163 - if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE)))
164 + if ((ivalid & ATTR_SIZE) && ((ivalid & ATTR_OPEN) || have_file))
167 /* In all other cases update */
171 -static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
172 +static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
175 unsigned ivalid = iattr->ia_valid;
177 @@ -1138,7 +1139,7 @@ static void iattr_to_fattr(struct iattr
178 if (!(ivalid & ATTR_ATIME_SET))
179 arg->valid |= FATTR_ATIME_NOW;
181 - if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) {
182 + if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, have_file)) {
183 arg->valid |= FATTR_MTIME;
184 arg->mtime = iattr->ia_mtime.tv_sec;
185 arg->mtimensec = iattr->ia_mtime.tv_nsec;
186 @@ -1199,8 +1200,8 @@ void fuse_release_nowrite(struct inode *
187 * vmtruncate() doesn't allow for this case, so do the rlimit checking
188 * and the actual truncation by hand.
190 -static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
192 +int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
195 struct inode *inode = entry->d_inode;
196 struct fuse_conn *fc = get_fuse_conn(inode);
197 @@ -1244,7 +1245,7 @@ static int fuse_do_setattr(struct dentry
199 memset(&inarg, 0, sizeof(inarg));
200 memset(&outarg, 0, sizeof(outarg));
201 - iattr_to_fattr(attr, &inarg);
202 + iattr_to_fattr(attr, &inarg, file != NULL);
204 struct fuse_file *ff = file->private_data;
205 inarg.valid |= FATTR_FH;
206 @@ -1314,10 +1315,7 @@ error:
208 static int fuse_setattr(struct dentry *entry, struct iattr *attr)
210 - if (attr->ia_valid & ATTR_FILE)
211 - return fuse_do_setattr(entry, attr, attr->ia_file);
213 - return fuse_do_setattr(entry, attr, NULL);
214 + return fuse_do_setattr(entry, attr, NULL);
217 static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
220 @@ -1467,6 +1467,11 @@ static loff_t fuse_file_llseek(struct fi
224 +static int fuse_fsetattr(struct file *file, struct iattr *attr)
226 + return fuse_do_setattr(file->f_path.dentry, attr, file);
229 static const struct file_operations fuse_file_operations = {
230 .llseek = fuse_file_llseek,
231 .read = do_sync_read,
232 @@ -1480,6 +1485,7 @@ static const struct file_operations fuse
234 .lock = fuse_file_lock,
235 .flock = fuse_file_flock,
236 + .fsetattr = fuse_fsetattr,
237 .splice_read = generic_file_splice_read,
240 @@ -1493,6 +1499,7 @@ static const struct file_operations fuse
242 .lock = fuse_file_lock,
243 .flock = fuse_file_flock,
244 + .fsetattr = fuse_fsetattr,
245 /* no mmap and splice_read */
248 --- a/fs/fuse/fuse_i.h
249 +++ b/fs/fuse/fuse_i.h
250 @@ -551,6 +551,10 @@ void fuse_truncate(struct address_space
252 int fuse_dev_init(void);
255 +int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
256 + struct file *file);
259 * Cleanup the client device
263 @@ -207,16 +207,12 @@ int do_truncate(struct dentry *dentry, s
265 newattrs.ia_size = length;
266 newattrs.ia_valid = ATTR_SIZE | time_attrs;
268 - newattrs.ia_file = filp;
269 - newattrs.ia_valid |= ATTR_FILE;
272 /* Remove suid/sgid on truncate too */
273 newattrs.ia_valid |= should_remove_suid(dentry);
275 mutex_lock(&dentry->d_inode->i_mutex);
276 - err = notify_change(dentry, mnt, &newattrs);
277 + err = fnotify_change(dentry, mnt, &newattrs, filp);
278 mutex_unlock(&dentry->d_inode->i_mutex);
281 @@ -625,7 +621,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd
282 mode = inode->i_mode;
283 newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
284 newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
285 - err = notify_change(dentry, file->f_path.mnt, &newattrs);
286 + err = fnotify_change(dentry, file->f_path.mnt, &newattrs, file);
287 mutex_unlock(&inode->i_mutex);
288 mnt_drop_write(file->f_path.mnt);
290 @@ -669,7 +665,7 @@ SYSCALL_DEFINE2(chmod, const char __user
293 static int chown_common(struct dentry * dentry, struct vfsmount *mnt,
294 - uid_t user, gid_t group)
295 + uid_t user, gid_t group, struct file *file)
297 struct inode *inode = dentry->d_inode;
299 @@ -688,7 +684,7 @@ static int chown_common(struct dentry *
301 ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
302 mutex_lock(&inode->i_mutex);
303 - error = notify_change(dentry, mnt, &newattrs);
304 + error = fnotify_change(dentry, mnt, &newattrs, file);
305 mutex_unlock(&inode->i_mutex);
308 @@ -705,7 +701,7 @@ SYSCALL_DEFINE3(chown, const char __user
309 error = mnt_want_write(path.mnt);
312 - error = chown_common(path.dentry, path.mnt, user, group);
313 + error = chown_common(path.dentry, path.mnt, user, group, NULL);
314 mnt_drop_write(path.mnt);
317 @@ -730,7 +726,7 @@ SYSCALL_DEFINE5(fchownat, int, dfd, cons
318 error = mnt_want_write(path.mnt);
321 - error = chown_common(path.dentry, path.mnt, user, group);
322 + error = chown_common(path.dentry, path.mnt, user, group, NULL);
323 mnt_drop_write(path.mnt);
326 @@ -749,7 +745,7 @@ SYSCALL_DEFINE3(lchown, const char __use
327 error = mnt_want_write(path.mnt);
330 - error = chown_common(path.dentry, path.mnt, user, group);
331 + error = chown_common(path.dentry, path.mnt, user, group, NULL);
332 mnt_drop_write(path.mnt);
335 @@ -772,7 +768,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd
337 dentry = file->f_path.dentry;
338 audit_inode(NULL, dentry);
339 - error = chown_common(dentry, file->f_path.mnt, user, group);
340 + error = chown_common(dentry, file->f_path.mnt, user, group, file);
341 mnt_drop_write(file->f_path.mnt);
346 @@ -48,7 +48,8 @@ static bool nsec_valid(long nsec)
347 return nsec >= 0 && nsec <= 999999999;
350 -static int utimes_common(struct path *path, struct timespec *times)
351 +static int utimes_common(struct path *path, struct timespec *times,
355 struct iattr newattrs;
356 @@ -102,7 +103,7 @@ static int utimes_common(struct path *pa
359 mutex_lock(&inode->i_mutex);
360 - error = notify_change(path->dentry, path->mnt, &newattrs);
361 + error = fnotify_change(path->dentry, path->mnt, &newattrs, f);
362 mutex_unlock(&inode->i_mutex);
364 mnt_drop_write_and_out:
365 @@ -149,7 +150,7 @@ long do_utimes(int dfd, char __user *fil
369 - error = utimes_common(&file->f_path, times);
370 + error = utimes_common(&file->f_path, times, file);
374 @@ -162,7 +163,7 @@ long do_utimes(int dfd, char __user *fil
378 - error = utimes_common(&path, times);
379 + error = utimes_common(&path, times, NULL);
383 --- a/include/linux/fs.h
384 +++ b/include/linux/fs.h
385 @@ -367,13 +367,6 @@ struct iattr {
386 struct timespec ia_atime;
387 struct timespec ia_mtime;
388 struct timespec ia_ctime;
391 - * Not an attribute, but an auxilary info for filesystems wanting to
392 - * implement an ftruncate() like method. NOTE: filesystem should
393 - * check for (ia_valid & ATTR_FILE), and not for (ia_file != NULL).
395 - struct file *ia_file;
399 @@ -1280,6 +1273,7 @@ struct file_operations {
400 #define HAVE_FOP_OPEN_EXEC
401 int (*open_exec) (struct inode *);
402 int (*setlease)(struct file *, long, struct file_lock **);
403 + int (*fsetattr)(struct file *, struct iattr *);
406 struct inode_operations {
407 @@ -1799,6 +1793,7 @@ extern int do_remount_sb(struct super_bl
408 extern sector_t bmap(struct inode *, sector_t);
410 extern int notify_change(struct dentry *, struct vfsmount *, struct iattr *);
411 +extern int fnotify_change(struct dentry *, struct vfsmount *, struct iattr *, struct file *);
412 extern int inode_permission(struct inode *, int);
413 extern int generic_permission(struct inode *, int,
414 int (*check_acl)(struct inode *, int));