@@ -138,15 +138,15 @@ xfs_dir2_sf_getdents(
138
138
STATIC int
139
139
xfs_dir2_block_getdents (
140
140
struct xfs_da_args * args ,
141
- struct dir_context * ctx )
141
+ struct dir_context * ctx ,
142
+ unsigned int * lock_mode )
142
143
{
143
144
struct xfs_inode * dp = args -> dp ; /* incore directory inode */
144
145
struct xfs_buf * bp ; /* buffer for block */
145
146
int error ; /* error return value */
146
147
int wantoff ; /* starting block offset */
147
148
xfs_off_t cook ;
148
149
struct xfs_da_geometry * geo = args -> geo ;
149
- int lock_mode ;
150
150
unsigned int offset , next_offset ;
151
151
unsigned int end ;
152
152
@@ -156,12 +156,13 @@ xfs_dir2_block_getdents(
156
156
if (xfs_dir2_dataptr_to_db (geo , ctx -> pos ) > geo -> datablk )
157
157
return 0 ;
158
158
159
- lock_mode = xfs_ilock_data_map_shared (dp );
160
159
error = xfs_dir3_block_read (args -> trans , dp , & bp );
161
- xfs_iunlock (dp , lock_mode );
162
160
if (error )
163
161
return error ;
164
162
163
+ xfs_iunlock (dp , * lock_mode );
164
+ * lock_mode = 0 ;
165
+
165
166
/*
166
167
* Extract the byte offset we start at from the seek pointer.
167
168
* We'll skip entries before this.
@@ -344,7 +345,8 @@ STATIC int
344
345
xfs_dir2_leaf_getdents (
345
346
struct xfs_da_args * args ,
346
347
struct dir_context * ctx ,
347
- size_t bufsize )
348
+ size_t bufsize ,
349
+ unsigned int * lock_mode )
348
350
{
349
351
struct xfs_inode * dp = args -> dp ;
350
352
struct xfs_mount * mp = dp -> i_mount ;
@@ -356,7 +358,6 @@ xfs_dir2_leaf_getdents(
356
358
xfs_dir2_off_t curoff ; /* current overall offset */
357
359
int length ; /* temporary length value */
358
360
int byteoff ; /* offset in current block */
359
- int lock_mode ;
360
361
unsigned int offset = 0 ;
361
362
int error = 0 ; /* error return value */
362
363
@@ -390,13 +391,16 @@ xfs_dir2_leaf_getdents(
390
391
bp = NULL ;
391
392
}
392
393
393
- lock_mode = xfs_ilock_data_map_shared (dp );
394
+ if (* lock_mode == 0 )
395
+ * lock_mode = xfs_ilock_data_map_shared (dp );
394
396
error = xfs_dir2_leaf_readbuf (args , bufsize , & curoff ,
395
397
& rablk , & bp );
396
- xfs_iunlock (dp , lock_mode );
397
398
if (error || !bp )
398
399
break ;
399
400
401
+ xfs_iunlock (dp , * lock_mode );
402
+ * lock_mode = 0 ;
403
+
400
404
xfs_dir3_data_check (dp , bp );
401
405
/*
402
406
* Find our position in the block.
@@ -496,7 +500,7 @@ xfs_dir2_leaf_getdents(
496
500
*
497
501
* If supplied, the transaction collects locked dir buffers to avoid
498
502
* nested buffer deadlocks. This function does not dirty the
499
- * transaction. The caller should ensure that the inode is locked
503
+ * transaction. The caller must hold the IOLOCK (shared or exclusive)
500
504
* before calling this function.
501
505
*/
502
506
int
@@ -507,29 +511,40 @@ xfs_readdir(
507
511
size_t bufsize )
508
512
{
509
513
struct xfs_da_args args = { NULL };
510
- int rval ;
511
- int v ;
514
+ unsigned int lock_mode ;
515
+ int isblock ;
516
+ int error ;
512
517
513
518
trace_xfs_readdir (dp );
514
519
515
520
if (xfs_is_shutdown (dp -> i_mount ))
516
521
return - EIO ;
517
522
518
523
ASSERT (S_ISDIR (VFS_I (dp )-> i_mode ));
524
+ ASSERT (xfs_isilocked (dp , XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL ));
519
525
XFS_STATS_INC (dp -> i_mount , xs_dir_getdents );
520
526
521
527
args .dp = dp ;
522
528
args .geo = dp -> i_mount -> m_dir_geo ;
523
529
args .trans = tp ;
524
530
525
531
if (dp -> i_df .if_format == XFS_DINODE_FMT_LOCAL )
526
- rval = xfs_dir2_sf_getdents (& args , ctx );
527
- else if ((rval = xfs_dir2_isblock (& args , & v )))
528
- ;
529
- else if (v )
530
- rval = xfs_dir2_block_getdents (& args , ctx );
531
- else
532
- rval = xfs_dir2_leaf_getdents (& args , ctx , bufsize );
532
+ return xfs_dir2_sf_getdents (& args , ctx );
533
533
534
- return rval ;
534
+ lock_mode = xfs_ilock_data_map_shared (dp );
535
+ error = xfs_dir2_isblock (& args , & isblock );
536
+ if (error )
537
+ goto out_unlock ;
538
+
539
+ if (isblock ) {
540
+ error = xfs_dir2_block_getdents (& args , ctx , & lock_mode );
541
+ goto out_unlock ;
542
+ }
543
+
544
+ error = xfs_dir2_leaf_getdents (& args , ctx , bufsize , & lock_mode );
545
+
546
+ out_unlock :
547
+ if (lock_mode )
548
+ xfs_iunlock (dp , lock_mode );
549
+ return error ;
535
550
}
0 commit comments