diff options
author | npiggin@suse.de <npiggin@suse.de> | 2010-05-26 11:05:33 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-05-27 22:15:33 -0400 |
commit | 7bb46a6734a7e1ad4beaecc11cae7ed3ff81d30f (patch) | |
tree | e575d9c55e2a6ccc645dcb3ae2564de458b428f2 /fs/attr.c | |
parent | 7000d3c424e5bb350e502a477fb0e1ed42f8b10e (diff) |
fs: introduce new truncate sequence
Introduce a new truncate calling sequence into fs/mm subsystems. Rather than
setattr > vmtruncate > truncate, have filesystems call their truncate sequence
from ->setattr if filesystem specific operations are required. vmtruncate is
deprecated, and truncate_pagecache and inode_newsize_ok helpers introduced
previously should be used.
simple_setattr is introduced for simple in-ram filesystems to implement
the new truncate sequence. Eventually all filesystems should be converted
to implement a setattr, and the default code in notify_change should go
away.
simple_setsize is also introduced to perform just the ATTR_SIZE portion
of simple_setattr (ie. changing i_size and trimming pagecache).
To implement the new truncate sequence:
- filesystem specific manipulations (eg freeing blocks) must be done in
the setattr method rather than ->truncate.
- vmtruncate can not be used by core code to trim blocks past i_size in
the event of write failure after allocation, so this must be performed
in the fs code.
- convert usage of helpers block_write_begin, nobh_write_begin,
cont_write_begin, and *blockdev_direct_IO* to use _newtrunc postfixed
variants. These avoid calling vmtruncate to trim blocks (see previous).
- inode_setattr should not be used. generic_setattr is a new function
to be used to copy simple attributes into the generic inode.
- make use of the better opportunity to handle errors with the new sequence.
Big problem with the previous calling sequence: the filesystem is not called
until i_size has already changed. This means it is not allowed to fail the
call, and also it does not know what the previous i_size was. Also, generic
code calling vmtruncate to truncate allocated blocks in case of error had
no good way to return a meaningful error (or, for example, atomically handle
block deallocation).
Cc: Christoph Hellwig <hch@lst.de>
Acked-by: Jan Kara <jack@suse.cz>
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/attr.c')
-rw-r--r-- | fs/attr.c | 50 |
1 files changed, 40 insertions, 10 deletions
@@ -67,14 +67,14 @@ EXPORT_SYMBOL(inode_change_ok); | |||
67 | * @offset: the new size to assign to the inode | 67 | * @offset: the new size to assign to the inode |
68 | * @Returns: 0 on success, -ve errno on failure | 68 | * @Returns: 0 on success, -ve errno on failure |
69 | * | 69 | * |
70 | * inode_newsize_ok must be called with i_mutex held. | ||
71 | * | ||
70 | * inode_newsize_ok will check filesystem limits and ulimits to check that the | 72 | * inode_newsize_ok will check filesystem limits and ulimits to check that the |
71 | * new inode size is within limits. inode_newsize_ok will also send SIGXFSZ | 73 | * new inode size is within limits. inode_newsize_ok will also send SIGXFSZ |
72 | * when necessary. Caller must not proceed with inode size change if failure is | 74 | * when necessary. Caller must not proceed with inode size change if failure is |
73 | * returned. @inode must be a file (not directory), with appropriate | 75 | * returned. @inode must be a file (not directory), with appropriate |
74 | * permissions to allow truncate (inode_newsize_ok does NOT check these | 76 | * permissions to allow truncate (inode_newsize_ok does NOT check these |
75 | * conditions). | 77 | * conditions). |
76 | * | ||
77 | * inode_newsize_ok must be called with i_mutex held. | ||
78 | */ | 78 | */ |
79 | int inode_newsize_ok(const struct inode *inode, loff_t offset) | 79 | int inode_newsize_ok(const struct inode *inode, loff_t offset) |
80 | { | 80 | { |
@@ -104,17 +104,25 @@ out_big: | |||
104 | } | 104 | } |
105 | EXPORT_SYMBOL(inode_newsize_ok); | 105 | EXPORT_SYMBOL(inode_newsize_ok); |
106 | 106 | ||
107 | int inode_setattr(struct inode * inode, struct iattr * attr) | 107 | /** |
108 | * generic_setattr - copy simple metadata updates into the generic inode | ||
109 | * @inode: the inode to be updated | ||
110 | * @attr: the new attributes | ||
111 | * | ||
112 | * generic_setattr must be called with i_mutex held. | ||
113 | * | ||
114 | * generic_setattr updates the inode's metadata with that specified | ||
115 | * in attr. Noticably missing is inode size update, which is more complex | ||
116 | * as it requires pagecache updates. See simple_setsize. | ||
117 | * | ||
118 | * The inode is not marked as dirty after this operation. The rationale is | ||
119 | * that for "simple" filesystems, the struct inode is the inode storage. | ||
120 | * The caller is free to mark the inode dirty afterwards if needed. | ||
121 | */ | ||
122 | void generic_setattr(struct inode *inode, const struct iattr *attr) | ||
108 | { | 123 | { |
109 | unsigned int ia_valid = attr->ia_valid; | 124 | unsigned int ia_valid = attr->ia_valid; |
110 | 125 | ||
111 | if (ia_valid & ATTR_SIZE && | ||
112 | attr->ia_size != i_size_read(inode)) { | ||
113 | int error = vmtruncate(inode, attr->ia_size); | ||
114 | if (error) | ||
115 | return error; | ||
116 | } | ||
117 | |||
118 | if (ia_valid & ATTR_UID) | 126 | if (ia_valid & ATTR_UID) |
119 | inode->i_uid = attr->ia_uid; | 127 | inode->i_uid = attr->ia_uid; |
120 | if (ia_valid & ATTR_GID) | 128 | if (ia_valid & ATTR_GID) |
@@ -135,6 +143,28 @@ int inode_setattr(struct inode * inode, struct iattr * attr) | |||
135 | mode &= ~S_ISGID; | 143 | mode &= ~S_ISGID; |
136 | inode->i_mode = mode; | 144 | inode->i_mode = mode; |
137 | } | 145 | } |
146 | } | ||
147 | EXPORT_SYMBOL(generic_setattr); | ||
148 | |||
149 | /* | ||
150 | * note this function is deprecated, the new truncate sequence should be | ||
151 | * used instead -- see eg. simple_setsize, generic_setattr. | ||
152 | */ | ||
153 | int inode_setattr(struct inode *inode, const struct iattr *attr) | ||
154 | { | ||
155 | unsigned int ia_valid = attr->ia_valid; | ||
156 | |||
157 | if (ia_valid & ATTR_SIZE && | ||
158 | attr->ia_size != i_size_read(inode)) { | ||
159 | int error; | ||
160 | |||
161 | error = vmtruncate(inode, attr->ia_size); | ||
162 | if (error) | ||
163 | return error; | ||
164 | } | ||
165 | |||
166 | generic_setattr(inode, attr); | ||
167 | |||
138 | mark_inode_dirty(inode); | 168 | mark_inode_dirty(inode); |
139 | 169 | ||
140 | return 0; | 170 | return 0; |