diff options
-rw-r--r-- | drivers/block/drbd/drbd_debugfs.c | 58 |
1 files changed, 54 insertions, 4 deletions
diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c index d393aee37da6..51c64ec7bbc1 100644 --- a/drivers/block/drbd/drbd_debugfs.c +++ b/drivers/block/drbd/drbd_debugfs.c | |||
@@ -177,8 +177,8 @@ static int in_flight_summary_show(struct seq_file *m, void *pos) | |||
177 | connection = first_connection(resource); | 177 | connection = first_connection(resource); |
178 | /* This does not happen, actually. | 178 | /* This does not happen, actually. |
179 | * But be robust and prepare for future code changes. */ | 179 | * But be robust and prepare for future code changes. */ |
180 | if (!connection) | 180 | if (!connection || !kref_get_unless_zero(&connection->kref)) |
181 | return 0; | 181 | return -ESTALE; |
182 | 182 | ||
183 | seq_puts(m, "oldest application requests\n"); | 183 | seq_puts(m, "oldest application requests\n"); |
184 | seq_print_resource_transfer_log_summary(m, resource, connection, jif); | 184 | seq_print_resource_transfer_log_summary(m, resource, connection, jif); |
@@ -187,12 +187,62 @@ static int in_flight_summary_show(struct seq_file *m, void *pos) | |||
187 | jif = jiffies - jif; | 187 | jif = jiffies - jif; |
188 | if (jif) | 188 | if (jif) |
189 | seq_printf(m, "generated in %d ms\n", jiffies_to_msecs(jif)); | 189 | seq_printf(m, "generated in %d ms\n", jiffies_to_msecs(jif)); |
190 | kref_put(&connection->kref, drbd_destroy_connection); | ||
190 | return 0; | 191 | return 0; |
191 | } | 192 | } |
192 | 193 | ||
194 | /* simple_positive(file->f_dentry) respectively debugfs_positive(), | ||
195 | * but neither is "reachable" from here. | ||
196 | * So we have our own inline version of it above. :-( */ | ||
197 | static inline int debugfs_positive(struct dentry *dentry) | ||
198 | { | ||
199 | return dentry->d_inode && !d_unhashed(dentry); | ||
200 | } | ||
201 | |||
202 | /* make sure at *open* time that the respective object won't go away. */ | ||
203 | static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, void *), | ||
204 | void *data, struct kref *kref, | ||
205 | void (*release)(struct kref *)) | ||
206 | { | ||
207 | struct dentry *parent; | ||
208 | int ret = -ESTALE; | ||
209 | |||
210 | /* Are we still linked, | ||
211 | * or has debugfs_remove() already been called? */ | ||
212 | parent = file->f_dentry->d_parent; | ||
213 | /* not sure if this can happen: */ | ||
214 | if (!parent || !parent->d_inode) | ||
215 | goto out; | ||
216 | /* serialize with d_delete() */ | ||
217 | mutex_lock(&parent->d_inode->i_mutex); | ||
218 | if (!debugfs_positive(file->f_dentry)) | ||
219 | goto out_unlock; | ||
220 | /* Make sure the object is still alive */ | ||
221 | if (kref_get_unless_zero(kref)) | ||
222 | ret = 0; | ||
223 | out_unlock: | ||
224 | mutex_unlock(&parent->d_inode->i_mutex); | ||
225 | if (!ret) { | ||
226 | ret = single_open(file, show, data); | ||
227 | if (ret) | ||
228 | kref_put(kref, release); | ||
229 | } | ||
230 | out: | ||
231 | return ret; | ||
232 | } | ||
233 | |||
193 | static int in_flight_summary_open(struct inode *inode, struct file *file) | 234 | static int in_flight_summary_open(struct inode *inode, struct file *file) |
194 | { | 235 | { |
195 | return single_open(file, in_flight_summary_show, inode->i_private); | 236 | struct drbd_resource *resource = inode->i_private; |
237 | return drbd_single_open(file, in_flight_summary_show, resource, | ||
238 | &resource->kref, drbd_destroy_resource); | ||
239 | } | ||
240 | |||
241 | static int in_flight_summary_release(struct inode *inode, struct file *file) | ||
242 | { | ||
243 | struct drbd_resource *resource = inode->i_private; | ||
244 | kref_put(&resource->kref, drbd_destroy_resource); | ||
245 | return single_release(inode, file); | ||
196 | } | 246 | } |
197 | 247 | ||
198 | static const struct file_operations in_flight_summary_fops = { | 248 | static const struct file_operations in_flight_summary_fops = { |
@@ -200,7 +250,7 @@ static const struct file_operations in_flight_summary_fops = { | |||
200 | .open = in_flight_summary_open, | 250 | .open = in_flight_summary_open, |
201 | .read = seq_read, | 251 | .read = seq_read, |
202 | .llseek = seq_lseek, | 252 | .llseek = seq_lseek, |
203 | .release = single_release, | 253 | .release = in_flight_summary_release, |
204 | }; | 254 | }; |
205 | 255 | ||
206 | void drbd_debugfs_resource_add(struct drbd_resource *resource) | 256 | void drbd_debugfs_resource_add(struct drbd_resource *resource) |